Merge branch 'master' into v2.1
[luajit-2.0.git] / src / vm_mips64.dasc
blob859c0aee84825b213349dad9cefcb3f11192d062
1 |// Low-level VM code for MIPS64 CPUs.
2 |// Bytecode interpreter, fast functions and helper functions.
3 |// Copyright (C) 2005-2025 Mike Pall. See Copyright Notice in luajit.h
4 |//
5 |// Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com.
6 |// Sponsored by Cisco Systems, Inc.
8 |.arch mips64
9 |.section code_op, code_sub
11 |.actionlist build_actionlist
12 |.globals GLOB_
13 |.globalnames globnames
14 |.externnames extnames
16 |// Note: The ragged indentation of the instructions is intentional.
17 |//       The starting columns indicate data dependencies.
19 |//-----------------------------------------------------------------------
21 |// Fixed register assignments for the interpreter.
22 |// Don't use: r0 = 0, r26/r27 = reserved, r28 = gp, r29 = sp, r31 = ra
24 |.macro .FPU, a, b
25 |.if FPU
26 |  a, b
27 |.endif
28 |.endmacro
30 |// The following must be C callee-save (but BASE is often refetched).
31 |.define BASE,          r16     // Base of current Lua stack frame.
32 |.define KBASE,         r17     // Constants of current Lua function.
33 |.define PC,            r18     // Next PC.
34 |.define DISPATCH,      r19     // Opcode dispatch table.
35 |.define LREG,          r20     // Register holding lua_State (also in SAVE_L).
36 |.define MULTRES,       r21     // Size of multi-result: (nresults+1)*8.
38 |.define JGL,           r30     // On-trace: global_State + 32768.
40 |// Constants for type-comparisons, stores and conversions. C callee-save.
41 |.define TISNIL,        r30
42 |.define TISNUM,        r22
43 |.if FPU
44 |.define TOBIT,         f30     // 2^52 + 2^51.
45 |.endif
47 |// The following temporaries are not saved across C calls, except for RA.
48 |.define RA,            r23     // Callee-save.
49 |.define RB,            r8
50 |.define RC,            r9
51 |.define RD,            r10
52 |.define INS,           r11
54 |.define AT,            r1      // Assembler temporary.
55 |.define TMP0,          r12
56 |.define TMP1,          r13
57 |.define TMP2,          r14
58 |.define TMP3,          r15
60 |// MIPS n64 calling convention.
61 |.define CFUNCADDR,     r25
62 |.define CARG1,         r4
63 |.define CARG2,         r5
64 |.define CARG3,         r6
65 |.define CARG4,         r7
66 |.define CARG5,         r8
67 |.define CARG6,         r9
68 |.define CARG7,         r10
69 |.define CARG8,         r11
71 |.define CRET1,         r2
72 |.define CRET2,         r3
74 |.if FPU
75 |.define FARG1,         f12
76 |.define FARG2,         f13
77 |.define FARG3,         f14
78 |.define FARG4,         f15
79 |.define FARG5,         f16
80 |.define FARG6,         f17
81 |.define FARG7,         f18
82 |.define FARG8,         f19
84 |.define FRET1,         f0
85 |.define FRET2,         f2
87 |.define FTMP0,         f20
88 |.define FTMP1,         f21
89 |.define FTMP2,         f22
90 |.endif
92 |// Stack layout while in interpreter. Must match with lj_frame.h.
93 |.if FPU                // MIPS64 hard-float.
95 |.define CFRAME_SPACE,  192     // Delta for sp.
97 |//----- 16 byte aligned, <-- sp entering interpreter
98 |.define SAVE_ERRF,     188(sp) // 32 bit values.
99 |.define SAVE_NRES,     184(sp)
100 |.define SAVE_CFRAME,   176(sp) // 64 bit values.
101 |.define SAVE_L,        168(sp)
102 |.define SAVE_PC,       160(sp)
103 |//----- 16 byte aligned
104 |.define SAVE_GPR_,     80      // .. 80+10*8: 64 bit GPR saves.
105 |.define SAVE_FPR_,     16      // .. 16+8*8: 64 bit FPR saves.
107 |.else                  // MIPS64 soft-float
109 |.define CFRAME_SPACE,  128     // Delta for sp.
111 |//----- 16 byte aligned, <-- sp entering interpreter
112 |.define SAVE_ERRF,     124(sp) // 32 bit values.
113 |.define SAVE_NRES,     120(sp)
114 |.define SAVE_CFRAME,   112(sp) // 64 bit values.
115 |.define SAVE_L,        104(sp)
116 |.define SAVE_PC,       96(sp)
117 |//----- 16 byte aligned
118 |.define SAVE_GPR_,     16      // .. 16+10*8: 64 bit GPR saves.
120 |.endif
122 |.define TMPX,          8(sp)   // Unused by interpreter, temp for JIT code.
123 |.define TMPD,          0(sp)
124 |//----- 16 byte aligned
126 |.define TMPD_OFS,      0
128 |.define SAVE_MULTRES,  TMPD
130 |//-----------------------------------------------------------------------
132 |.macro saveregs
133 |  daddiu sp, sp, -CFRAME_SPACE
134 |  sd ra, SAVE_GPR_+9*8(sp)
135 |  sd r30, SAVE_GPR_+8*8(sp)
136 |   .FPU sdc1 f31, SAVE_FPR_+7*8(sp)
137 |  sd r23, SAVE_GPR_+7*8(sp)
138 |   .FPU sdc1 f30, SAVE_FPR_+6*8(sp)
139 |  sd r22, SAVE_GPR_+6*8(sp)
140 |   .FPU sdc1 f29, SAVE_FPR_+5*8(sp)
141 |  sd r21, SAVE_GPR_+5*8(sp)
142 |   .FPU sdc1 f28, SAVE_FPR_+4*8(sp)
143 |  sd r20, SAVE_GPR_+4*8(sp)
144 |   .FPU sdc1 f27, SAVE_FPR_+3*8(sp)
145 |  sd r19, SAVE_GPR_+3*8(sp)
146 |   .FPU sdc1 f26, SAVE_FPR_+2*8(sp)
147 |  sd r18, SAVE_GPR_+2*8(sp)
148 |   .FPU sdc1 f25, SAVE_FPR_+1*8(sp)
149 |  sd r17, SAVE_GPR_+1*8(sp)
150 |   .FPU sdc1 f24, SAVE_FPR_+0*8(sp)
151 |  sd r16, SAVE_GPR_+0*8(sp)
152 |.endmacro
154 |.macro restoreregs_ret
155 |  ld ra, SAVE_GPR_+9*8(sp)
156 |  ld r30, SAVE_GPR_+8*8(sp)
157 |  ld r23, SAVE_GPR_+7*8(sp)
158 |   .FPU ldc1 f31, SAVE_FPR_+7*8(sp)
159 |  ld r22, SAVE_GPR_+6*8(sp)
160 |   .FPU ldc1 f30, SAVE_FPR_+6*8(sp)
161 |  ld r21, SAVE_GPR_+5*8(sp)
162 |   .FPU ldc1 f29, SAVE_FPR_+5*8(sp)
163 |  ld r20, SAVE_GPR_+4*8(sp)
164 |   .FPU ldc1 f28, SAVE_FPR_+4*8(sp)
165 |  ld r19, SAVE_GPR_+3*8(sp)
166 |   .FPU ldc1 f27, SAVE_FPR_+3*8(sp)
167 |  ld r18, SAVE_GPR_+2*8(sp)
168 |   .FPU ldc1 f26, SAVE_FPR_+2*8(sp)
169 |  ld r17, SAVE_GPR_+1*8(sp)
170 |   .FPU ldc1 f25, SAVE_FPR_+1*8(sp)
171 |  ld r16, SAVE_GPR_+0*8(sp)
172 |   .FPU ldc1 f24, SAVE_FPR_+0*8(sp)
173 |  jr ra
174 |  daddiu sp, sp, CFRAME_SPACE
175 |.endmacro
177 |// Type definitions. Some of these are only used for documentation.
178 |.type L,               lua_State,      LREG
179 |.type GL,              global_State
180 |.type TVALUE,          TValue
181 |.type GCOBJ,           GCobj
182 |.type STR,             GCstr
183 |.type TAB,             GCtab
184 |.type LFUNC,           GCfuncL
185 |.type CFUNC,           GCfuncC
186 |.type PROTO,           GCproto
187 |.type UPVAL,           GCupval
188 |.type NODE,            Node
189 |.type NARGS8,          int
190 |.type TRACE,           GCtrace
191 |.type SBUF,            SBuf
193 |//-----------------------------------------------------------------------
195 |// Trap for not-yet-implemented parts.
196 |.macro NYI; .long 0xec1cf0f0; .endmacro
198 |// Macros to mark delay slots.
199 |.macro ., a; a; .endmacro
200 |.macro ., a,b; a,b; .endmacro
201 |.macro ., a,b,c; a,b,c; .endmacro
202 |.macro ., a,b,c,d; a,b,c,d; .endmacro
204 |.define FRAME_PC,      -8
205 |.define FRAME_FUNC,    -16
207 |//-----------------------------------------------------------------------
209 |// Endian-specific defines.
210 |.if ENDIAN_LE
211 |.define HI,            4
212 |.define LO,            0
213 |.define OFS_RD,        2
214 |.define OFS_RA,        1
215 |.define OFS_OP,        0
216 |.else
217 |.define HI,            0
218 |.define LO,            4
219 |.define OFS_RD,        0
220 |.define OFS_RA,        2
221 |.define OFS_OP,        3
222 |.endif
224 |// Instruction decode.
225 |.macro decode_OP1, dst, ins; andi dst, ins, 0xff; .endmacro
226 |.macro decode_OP8a, dst, ins; andi dst, ins, 0xff; .endmacro
227 |.macro decode_OP8b, dst; sll dst, dst, 3; .endmacro
228 |.macro decode_RC8a, dst, ins; srl dst, ins, 13; .endmacro
229 |.macro decode_RC8b, dst; andi dst, dst, 0x7f8; .endmacro
230 |.macro decode_RD4b, dst; sll dst, dst, 2; .endmacro
231 |.macro decode_RA8a, dst, ins; srl dst, ins, 5; .endmacro
232 |.macro decode_RA8b, dst; andi dst, dst, 0x7f8; .endmacro
233 |.macro decode_RB8a, dst, ins; srl dst, ins, 21; .endmacro
234 |.macro decode_RB8b, dst; andi dst, dst, 0x7f8; .endmacro
235 |.macro decode_RD8a, dst, ins; srl dst, ins, 16; .endmacro
236 |.macro decode_RD8b, dst; sll dst, dst, 3; .endmacro
237 |.macro decode_RDtoRC8, dst, src; andi dst, src, 0x7f8; .endmacro
239 |// Instruction fetch.
240 |.macro ins_NEXT1
241 |  lw INS, 0(PC)
242 |   daddiu PC, PC, 4
243 |.endmacro
244 |// Instruction decode+dispatch.
245 |.macro ins_NEXT2
246 |  decode_OP8a TMP1, INS
247 |  decode_OP8b TMP1
248 |  daddu TMP0, DISPATCH, TMP1
249 |   decode_RD8a RD, INS
250 |  ld AT, 0(TMP0)
251 |   decode_RA8a RA, INS
252 |   decode_RD8b RD
253 |  jr AT
254 |   decode_RA8b RA
255 |.endmacro
256 |.macro ins_NEXT
257 |  ins_NEXT1
258 |  ins_NEXT2
259 |.endmacro
261 |// Instruction footer.
262 |.if 1
263 |  // Replicated dispatch. Less unpredictable branches, but higher I-Cache use.
264 |  .define ins_next, ins_NEXT
265 |  .define ins_next_, ins_NEXT
266 |  .define ins_next1, ins_NEXT1
267 |  .define ins_next2, ins_NEXT2
268 |.else
269 |  // Common dispatch. Lower I-Cache use, only one (very) unpredictable branch.
270 |  // Affects only certain kinds of benchmarks (and only with -j off).
271 |  .macro ins_next
272 |    b ->ins_next
273 |  .endmacro
274 |  .macro ins_next1
275 |  .endmacro
276 |  .macro ins_next2
277 |    b ->ins_next
278 |  .endmacro
279 |  .macro ins_next_
280 |  ->ins_next:
281 |    ins_NEXT
282 |  .endmacro
283 |.endif
285 |// Call decode and dispatch.
286 |.macro ins_callt
287 |  // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC
288 |  ld PC, LFUNC:RB->pc
289 |  lw INS, 0(PC)
290 |   daddiu PC, PC, 4
291 |  decode_OP8a TMP1, INS
292 |   decode_RA8a RA, INS
293 |  decode_OP8b TMP1
294 |   decode_RA8b RA
295 |  daddu TMP0, DISPATCH, TMP1
296 |  ld TMP0, 0(TMP0)
297 |  jr TMP0
298 |   daddu RA, RA, BASE
299 |.endmacro
301 |.macro ins_call
302 |  // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, PC = caller PC
303 |  sd PC, FRAME_PC(BASE)
304 |  ins_callt
305 |.endmacro
307 |//-----------------------------------------------------------------------
309 |.macro branch_RD
310 |  srl TMP0, RD, 1
311 |  lui AT, (-(BCBIAS_J*4 >> 16) & 65535)
312 |  addu TMP0, TMP0, AT
313 |  daddu PC, PC, TMP0
314 |.endmacro
316 |// Assumes DISPATCH is relative to GL.
317 #define DISPATCH_GL(field)      (GG_DISP2G + (int)offsetof(global_State, field))
318 #define DISPATCH_J(field)       (GG_DISP2J + (int)offsetof(jit_State, field))
319 #define GG_DISP2GOT             (GG_OFS(got) - GG_OFS(dispatch))
320 #define DISPATCH_GOT(name)      (GG_DISP2GOT + sizeof(void*)*LJ_GOT_##name)
322 #define PC2PROTO(field)  ((int)offsetof(GCproto, field)-(int)sizeof(GCproto))
324 |.macro load_got, func
325 |  ld CFUNCADDR, DISPATCH_GOT(func)(DISPATCH)
326 |.endmacro
327 |// Much faster. Sadly, there's no easy way to force the required code layout.
328 |// .macro call_intern, func; bal extern func; .endmacro
329 |.macro call_intern, func; jalr CFUNCADDR; .endmacro
330 |.macro call_extern; jalr CFUNCADDR; .endmacro
331 |.macro jmp_extern; jr CFUNCADDR; .endmacro
333 |.macro hotcheck, delta, target
334 |  dsrl TMP1, PC, 1
335 |  andi TMP1, TMP1, 126
336 |  daddu TMP1, TMP1, DISPATCH
337 |  lhu TMP2, GG_DISP2HOT(TMP1)
338 |  addiu TMP2, TMP2, -delta
339 |  bltz TMP2, target
340 |.  sh TMP2, GG_DISP2HOT(TMP1)
341 |.endmacro
343 |.macro hotloop
344 |  hotcheck HOTCOUNT_LOOP, ->vm_hotloop
345 |.endmacro
347 |.macro hotcall
348 |  hotcheck HOTCOUNT_CALL, ->vm_hotcall
349 |.endmacro
351 |// Set current VM state. Uses TMP0.
352 |.macro li_vmstate, st; li TMP0, ~LJ_VMST_..st; .endmacro
353 |.macro st_vmstate; sw TMP0, DISPATCH_GL(vmstate)(DISPATCH); .endmacro
355 |// Move table write barrier back. Overwrites mark and tmp.
356 |.macro barrierback, tab, mark, tmp, target
357 |  ld tmp, DISPATCH_GL(gc.grayagain)(DISPATCH)
358 |   andi mark, mark, ~LJ_GC_BLACK & 255         // black2gray(tab)
359 |  sd tab, DISPATCH_GL(gc.grayagain)(DISPATCH)
360 |   sb mark, tab->marked
361 |  b target
362 |.  sd tmp, tab->gclist
363 |.endmacro
365 |// Clear type tag. Isolate lowest 14+32+1=47 bits of reg.
366 |.macro cleartp, reg; dextm reg, reg, 0, 14; .endmacro
367 |.macro cleartp, dst, reg; dextm dst, reg, 0, 14; .endmacro
369 |// Set type tag: Merge 17 type bits into bits [15+32=47, 31+32+1=64) of dst.
370 |.macro settp, dst, tp; dinsu dst, tp, 15, 31; .endmacro
372 |// Extract (negative) type tag.
373 |.macro gettp, dst, src; dsra dst, src, 47; .endmacro
375 |// Macros to check the TValue type and extract the GCobj. Branch on failure.
376 |.macro checktp, reg, tp, target
377 |  gettp AT, reg
378 |  daddiu AT, AT, tp
379 |  bnez AT, target
380 |.  cleartp reg
381 |.endmacro
382 |.macro checktp, dst, reg, tp, target
383 |  gettp AT, reg
384 |  daddiu AT, AT, tp
385 |  bnez AT, target
386 |.  cleartp dst, reg
387 |.endmacro
388 |.macro checkstr, reg, target; checktp reg, -LJ_TSTR, target; .endmacro
389 |.macro checktab, reg, target; checktp reg, -LJ_TTAB, target; .endmacro
390 |.macro checkfunc, reg, target; checktp reg, -LJ_TFUNC, target; .endmacro
391 |.macro checkint, reg, target   // Caveat: has delay slot!
392 |  gettp AT, reg
393 |  bne AT, TISNUM, target
394 |.endmacro
395 |.macro checknum, reg, target   // Caveat: has delay slot!
396 |  gettp AT, reg
397 |  sltiu AT, AT, LJ_TISNUM
398 |  beqz AT, target
399 |.endmacro
401 |.macro mov_false, reg
402 |  lu reg, 0x8000
403 |  dsll reg, reg, 32
404 |  not reg, reg
405 |.endmacro
406 |.macro mov_true, reg
407 |  li reg, 0x0001
408 |  dsll reg, reg, 48
409 |  not reg, reg
410 |.endmacro
412 |//-----------------------------------------------------------------------
414 /* Generate subroutines used by opcodes and other parts of the VM. */
415 /* The .code_sub section should be last to help static branch prediction. */
416 static void build_subroutines(BuildCtx *ctx)
418   |.code_sub
419   |
420   |//-----------------------------------------------------------------------
421   |//-- Return handling ----------------------------------------------------
422   |//-----------------------------------------------------------------------
423   |
424   |->vm_returnp:
425   |  // See vm_return. Also: TMP2 = previous base.
426   |  andi AT, PC, FRAME_P
427   |  beqz AT, ->cont_dispatch
428   |
429   |  // Return from pcall or xpcall fast func.
430   |.  mov_true TMP1
431   |  ld PC, FRAME_PC(TMP2)              // Fetch PC of previous frame.
432   |  move BASE, TMP2                    // Restore caller base.
433   |  // Prepending may overwrite the pcall frame, so do it at the end.
434   |   sd TMP1, -8(RA)                   // Prepend true to results.
435   |   daddiu RA, RA, -8
436   |
437   |->vm_returnc:
438   |   addiu RD, RD, 8                   // RD = (nresults+1)*8.
439   |  andi TMP0, PC, FRAME_TYPE
440   |   beqz RD, ->vm_unwind_c_eh
441   |.   li CRET1, LUA_YIELD
442   |  beqz TMP0, ->BC_RET_Z              // Handle regular return to Lua.
443   |.  move MULTRES, RD
444   |
445   |->vm_return:
446   |  // BASE = base, RA = resultptr, RD/MULTRES = (nresults+1)*8, PC = return
447   |  // TMP0 = PC & FRAME_TYPE
448   |   li TMP2, -8
449   |  xori AT, TMP0, FRAME_C
450   |   and TMP2, PC, TMP2
451   |  bnez AT, ->vm_returnp
452   |   dsubu TMP2, BASE, TMP2            // TMP2 = previous base.
453   |
454   |  addiu TMP1, RD, -8
455   |   sd TMP2, L->base
456   |    li_vmstate C
457   |   lw TMP2, SAVE_NRES
458   |   daddiu BASE, BASE, -16
459   |    st_vmstate
460   |  beqz TMP1, >2
461   |.   sll TMP2, TMP2, 3
462   |1:
463   |  addiu TMP1, TMP1, -8
464   |   ld CRET1, 0(RA)
465   |    daddiu RA, RA, 8
466   |   sd CRET1, 0(BASE)
467   |  bnez TMP1, <1
468   |.  daddiu BASE, BASE, 8
469   |
470   |2:
471   |  bne TMP2, RD, >6
472   |3:
473   |.  sd BASE, L->top                   // Store new top.
474   |
475   |->vm_leave_cp:
476   |  ld TMP0, SAVE_CFRAME               // Restore previous C frame.
477   |   move CRET1, r0                    // Ok return status for vm_pcall.
478   |  sd TMP0, L->cframe
479   |
480   |->vm_leave_unw:
481   |  restoreregs_ret
482   |
483   |6:
484   |  ld TMP1, L->maxstack
485   |  slt AT, TMP2, RD
486   |  bnez AT, >7                        // Less results wanted?
487   |  // More results wanted. Check stack size and fill up results with nil.
488   |.  slt AT, BASE, TMP1
489   |  beqz AT, >8
490   |.  nop
491   |  sd TISNIL, 0(BASE)
492   |  addiu RD, RD, 8
493   |  b <2
494   |.  daddiu BASE, BASE, 8
495   |
496   |7:  // Less results wanted.
497   |  subu TMP0, RD, TMP2
498   |  dsubu TMP0, BASE, TMP0             // Either keep top or shrink it.
499   |.if MIPSR6
500   |  selnez TMP0, TMP0, TMP2            // LUA_MULTRET+1 case?
501   |  seleqz BASE, BASE, TMP2
502   |  b <3
503   |.  or BASE, BASE, TMP0
504   |.else
505   |  b <3
506   |.  movn BASE, TMP0, TMP2             // LUA_MULTRET+1 case?
507   |.endif
508   |
509   |8:  // Corner case: need to grow stack for filling up results.
510   |  // This can happen if:
511   |  // - A C function grows the stack (a lot).
512   |  // - The GC shrinks the stack in between.
513   |  // - A return back from a lua_call() with (high) nresults adjustment.
514   |  load_got lj_state_growstack
515   |   move MULTRES, RD
516   |  srl CARG2, TMP2, 3
517   |  call_intern lj_state_growstack     // (lua_State *L, int n)
518   |.  move CARG1, L
519   |    lw TMP2, SAVE_NRES
520   |  ld BASE, L->top                    // Need the (realloced) L->top in BASE.
521   |   move RD, MULTRES
522   |  b <2
523   |.   sll TMP2, TMP2, 3
524   |
525   |->vm_unwind_c:                       // Unwind C stack, return from vm_pcall.
526   |  // (void *cframe, int errcode)
527   |  move sp, CARG1
528   |  move CRET1, CARG2
529   |->vm_unwind_c_eh:                    // Landing pad for external unwinder.
530   |  ld L, SAVE_L
531   |   li TMP0, ~LJ_VMST_C
532   |  ld GL:TMP1, L->glref
533   |  b ->vm_leave_unw
534   |.  sw TMP0, GL:TMP1->vmstate
535   |
536   |->vm_unwind_ff:                      // Unwind C stack, return from ff pcall.
537   |  // (void *cframe)
538   |  li AT, -4
539   |  and sp, CARG1, AT
540   |->vm_unwind_ff_eh:                   // Landing pad for external unwinder.
541   |  ld L, SAVE_L
542   |     .FPU lui TMP3, 0x59c0           // TOBIT = 2^52 + 2^51 (float).
543   |     li TISNIL, LJ_TNIL
544   |    li TISNUM, LJ_TISNUM
545   |  ld BASE, L->base
546   |   ld DISPATCH, L->glref             // Setup pointer to dispatch table.
547   |     .FPU mtc1 TMP3, TOBIT
548   |  mov_false TMP1
549   |    li_vmstate INTERP
550   |  ld PC, FRAME_PC(BASE)              // Fetch PC of previous frame.
551   |     .FPU cvt.d.s TOBIT, TOBIT
552   |  daddiu RA, BASE, -8                // Results start at BASE-8.
553   |   daddiu DISPATCH, DISPATCH, GG_G2DISP
554   |  sd TMP1, 0(RA)                     // Prepend false to error message.
555   |    st_vmstate
556   |  b ->vm_returnc
557   |.  li RD, 16                         // 2 results: false + error message.
558   |
559   |->vm_unwind_stub:                    // Jump to exit stub from unwinder.
560   |  jr CARG1
561   |.  move ra, CARG2
562   |
563   |//-----------------------------------------------------------------------
564   |//-- Grow stack for calls -----------------------------------------------
565   |//-----------------------------------------------------------------------
566   |
567   |->vm_growstack_c:                    // Grow stack for C function.
568   |  b >2
569   |.  li CARG2, LUA_MINSTACK
570   |
571   |->vm_growstack_l:                    // Grow stack for Lua function.
572   |  // BASE = new base, RA = BASE+framesize*8, RC = nargs*8, PC = first PC
573   |  daddu RC, BASE, RC
574   |   dsubu RA, RA, BASE
575   |  sd BASE, L->base
576   |   daddiu PC, PC, 4                  // Must point after first instruction.
577   |  sd RC, L->top
578   |   srl CARG2, RA, 3
579   |2:
580   |  // L->base = new base, L->top = top
581   |  load_got lj_state_growstack
582   |   sd PC, SAVE_PC
583   |  call_intern lj_state_growstack     // (lua_State *L, int n)
584   |.  move CARG1, L
585   |  ld BASE, L->base
586   |  ld RC, L->top
587   |  ld LFUNC:RB, FRAME_FUNC(BASE)
588   |  dsubu RC, RC, BASE
589   |  cleartp LFUNC:RB
590   |  // BASE = new base, RB = LFUNC/CFUNC, RC = nargs*8, FRAME_PC(BASE) = PC
591   |  ins_callt                          // Just retry the call.
592   |
593   |//-----------------------------------------------------------------------
594   |//-- Entry points into the assembler VM ---------------------------------
595   |//-----------------------------------------------------------------------
596   |
597   |->vm_resume:                         // Setup C frame and resume thread.
598   |  // (lua_State *L, TValue *base, int nres1 = 0, ptrdiff_t ef = 0)
599   |  saveregs
600   |  move L, CARG1
601   |    ld DISPATCH, L->glref            // Setup pointer to dispatch table.
602   |  move BASE, CARG2
603   |    lbu TMP1, L->status
604   |   sd L, SAVE_L
605   |  li PC, FRAME_CP
606   |  daddiu TMP0, sp, CFRAME_RESUME
607   |    daddiu DISPATCH, DISPATCH, GG_G2DISP
608   |   sw r0, SAVE_NRES
609   |   sw r0, SAVE_ERRF
610   |   sd CARG1, SAVE_PC                 // Any value outside of bytecode is ok.
611   |   sd r0, SAVE_CFRAME
612   |    beqz TMP1, >3
613   |. sd TMP0, L->cframe
614   |
615   |  // Resume after yield (like a return).
616   |  sd L, DISPATCH_GL(cur_L)(DISPATCH)
617   |  move RA, BASE
618   |   ld BASE, L->base
619   |   ld TMP1, L->top
620   |  ld PC, FRAME_PC(BASE)
621   |     .FPU  lui TMP3, 0x59c0          // TOBIT = 2^52 + 2^51 (float).
622   |   dsubu RD, TMP1, BASE
623   |     .FPU  mtc1 TMP3, TOBIT
624   |    sb r0, L->status
625   |     .FPU  cvt.d.s TOBIT, TOBIT
626   |    li_vmstate INTERP
627   |   daddiu RD, RD, 8
628   |    st_vmstate
629   |   move MULTRES, RD
630   |  andi TMP0, PC, FRAME_TYPE
631   |    li TISNIL, LJ_TNIL
632   |  beqz TMP0, ->BC_RET_Z
633   |.    li TISNUM, LJ_TISNUM
634   |  b ->vm_return
635   |.  nop
636   |
637   |->vm_pcall:                          // Setup protected C frame and enter VM.
638   |  // (lua_State *L, TValue *base, int nres1, ptrdiff_t ef)
639   |  saveregs
640   |  sw CARG4, SAVE_ERRF
641   |  b >1
642   |.  li PC, FRAME_CP
643   |
644   |->vm_call:                           // Setup C frame and enter VM.
645   |  // (lua_State *L, TValue *base, int nres1)
646   |  saveregs
647   |  li PC, FRAME_C
648   |
649   |1:  // Entry point for vm_pcall above (PC = ftype).
650   |  ld TMP1, L:CARG1->cframe
651   |    move L, CARG1
652   |   sw CARG3, SAVE_NRES
653   |    ld DISPATCH, L->glref            // Setup pointer to dispatch table.
654   |   sd CARG1, SAVE_L
655   |     move BASE, CARG2
656   |    daddiu DISPATCH, DISPATCH, GG_G2DISP
657   |   sd CARG1, SAVE_PC                 // Any value outside of bytecode is ok.
658   |  sd TMP1, SAVE_CFRAME
659   |  sd sp, L->cframe                   // Add our C frame to cframe chain.
660   |
661   |3:  // Entry point for vm_cpcall/vm_resume (BASE = base, PC = ftype).
662   |  sd L, DISPATCH_GL(cur_L)(DISPATCH)
663   |  ld TMP2, L->base                   // TMP2 = old base (used in vmeta_call).
664   |     .FPU lui TMP3, 0x59c0           // TOBIT = 2^52 + 2^51 (float).
665   |   ld TMP1, L->top
666   |     .FPU mtc1 TMP3, TOBIT
667   |  daddu PC, PC, BASE
668   |   dsubu NARGS8:RC, TMP1, BASE
669   |     li TISNUM, LJ_TISNUM
670   |  dsubu PC, PC, TMP2                 // PC = frame delta + frame type
671   |     .FPU cvt.d.s TOBIT, TOBIT
672   |    li_vmstate INTERP
673   |     li TISNIL, LJ_TNIL
674   |    st_vmstate
675   |
676   |->vm_call_dispatch:
677   |  // TMP2 = old base, BASE = new base, RC = nargs*8, PC = caller PC
678   |  ld LFUNC:RB, FRAME_FUNC(BASE)
679   |  checkfunc LFUNC:RB, ->vmeta_call
680   |
681   |->vm_call_dispatch_f:
682   |  ins_call
683   |  // BASE = new base, RB = func, RC = nargs*8, PC = caller PC
684   |
685   |->vm_cpcall:                         // Setup protected C frame, call C.
686   |  // (lua_State *L, lua_CFunction func, void *ud, lua_CPFunction cp)
687   |  saveregs
688   |  move L, CARG1
689   |   ld TMP0, L:CARG1->stack
690   |  sd CARG1, SAVE_L
691   |   ld TMP1, L->top
692   |     ld DISPATCH, L->glref           // Setup pointer to dispatch table.
693   |  sd CARG1, SAVE_PC                  // Any value outside of bytecode is ok.
694   |   dsubu TMP0, TMP0, TMP1            // Compute -savestack(L, L->top).
695   |    ld TMP1, L->cframe
696   |     daddiu DISPATCH, DISPATCH, GG_G2DISP
697   |   sw TMP0, SAVE_NRES                // Neg. delta means cframe w/o frame.
698   |  sw r0, SAVE_ERRF                   // No error function.
699   |    sd TMP1, SAVE_CFRAME
700   |    sd sp, L->cframe                 // Add our C frame to cframe chain.
701   |     sd L, DISPATCH_GL(cur_L)(DISPATCH)
702   |  jalr CARG4                 // (lua_State *L, lua_CFunction func, void *ud)
703   |.  move CFUNCADDR, CARG4
704   |  move BASE, CRET1
705   |  bnez CRET1, <3                     // Else continue with the call.
706   |.  li PC, FRAME_CP
707   |  b ->vm_leave_cp                    // No base? Just remove C frame.
708   |.  nop
709   |
710   |//-----------------------------------------------------------------------
711   |//-- Metamethod handling ------------------------------------------------
712   |//-----------------------------------------------------------------------
713   |
714   |// The lj_meta_* functions (except for lj_meta_cat) don't reallocate the
715   |// stack, so BASE doesn't need to be reloaded across these calls.
716   |
717   |//-- Continuation dispatch ----------------------------------------------
718   |
719   |->cont_dispatch:
720   |  // BASE = meta base, RA = resultptr, RD = (nresults+1)*8
721   |  ld TMP0, -32(BASE)                 // Continuation.
722   |   move RB, BASE
723   |   move BASE, TMP2                   // Restore caller BASE.
724   |    ld LFUNC:TMP1, FRAME_FUNC(TMP2)
725   |.if FFI
726   |  sltiu AT, TMP0, 2
727   |.endif
728   |     ld PC, -24(RB)                  // Restore PC from [cont|PC].
729   |    cleartp LFUNC:TMP1
730   |   daddu TMP2, RA, RD
731   |.if FFI
732   |  bnez AT, >1
733   |.endif
734   |.  sd TISNIL, -8(TMP2)               // Ensure one valid arg.
735   |    ld TMP1, LFUNC:TMP1->pc
736   |  // BASE = base, RA = resultptr, RB = meta base
737   |  jr TMP0                            // Jump to continuation.
738   |.  ld KBASE, PC2PROTO(k)(TMP1)
739   |
740   |.if FFI
741   |1:
742   |  bnez TMP0, ->cont_ffi_callback     // cont = 1: return from FFI callback.
743   |  // cont = 0: tailcall from C function.
744   |.  daddiu TMP1, RB, -32
745   |  b ->vm_call_tail
746   |.  dsubu RC, TMP1, BASE
747   |.endif
748   |
749   |->cont_cat:                          // RA = resultptr, RB = meta base
750   |  lw INS, -4(PC)
751   |   daddiu CARG2, RB, -32
752   |  ld CRET1, 0(RA)
753   |  decode_RB8a MULTRES, INS
754   |   decode_RA8a RA, INS
755   |  decode_RB8b MULTRES
756   |   decode_RA8b RA
757   |  daddu TMP1, BASE, MULTRES
758   |   sd BASE, L->base
759   |   dsubu CARG3, CARG2, TMP1
760   |  bne TMP1, CARG2, ->BC_CAT_Z
761   |.  sd CRET1, 0(CARG2)
762   |  daddu RA, BASE, RA
763   |  b ->cont_nop
764   |.  sd CRET1, 0(RA)
765   |
766   |//-- Table indexing metamethods -----------------------------------------
767   |
768   |->vmeta_tgets1:
769   |  daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv)
770   |  li TMP0, LJ_TSTR
771   |  settp STR:RC, TMP0
772   |  b >1
773   |.  sd STR:RC, 0(CARG3)
774   |
775   |->vmeta_tgets:
776   |  daddiu CARG2, DISPATCH, DISPATCH_GL(tmptv)
777   |  li TMP0, LJ_TTAB
778   |   li TMP1, LJ_TSTR
779   |  settp TAB:RB, TMP0
780   |   daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv2)
781   |  sd TAB:RB, 0(CARG2)
782   |   settp STR:RC, TMP1
783   |  b >1
784   |.  sd STR:RC, 0(CARG3)
785   |
786   |->vmeta_tgetb:                       // TMP0 = index
787   |  daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv)
788   |  settp TMP0, TISNUM
789   |  sd TMP0, 0(CARG3)
790   |
791   |->vmeta_tgetv:
792   |1:
793   |  load_got lj_meta_tget
794   |  sd BASE, L->base
795   |  sd PC, SAVE_PC
796   |  call_intern lj_meta_tget           // (lua_State *L, TValue *o, TValue *k)
797   |.  move CARG1, L
798   |  // Returns TValue * (finished) or NULL (metamethod).
799   |  beqz CRET1, >3
800   |.  daddiu TMP1, BASE, -FRAME_CONT
801   |  ld CARG1, 0(CRET1)
802   |  ins_next1
803   |  sd CARG1, 0(RA)
804   |  ins_next2
805   |
806   |3:  // Call __index metamethod.
807   |  // BASE = base, L->top = new base, stack = cont/func/t/k
808   |  ld BASE, L->top
809   |  sd PC, -24(BASE)                   // [cont|PC]
810   |   dsubu PC, BASE, TMP1
811   |  ld LFUNC:RB, FRAME_FUNC(BASE)      // Guaranteed to be a function here.
812   |  cleartp LFUNC:RB
813   |  b ->vm_call_dispatch_f
814   |.  li NARGS8:RC, 16                  // 2 args for func(t, k).
815   |
816   |->vmeta_tgetr:
817   |  load_got lj_tab_getinth
818   |  call_intern lj_tab_getinth         // (GCtab *t, int32_t key)
819   |.  nop
820   |  // Returns cTValue * or NULL.
821   |  beqz CRET1, ->BC_TGETR_Z
822   |.  move CARG2, TISNIL
823   |  b ->BC_TGETR_Z
824   |.  ld CARG2, 0(CRET1)
825   |
826   |//-----------------------------------------------------------------------
827   |
828   |->vmeta_tsets1:
829   |  daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv)
830   |  li TMP0, LJ_TSTR
831   |  settp STR:RC, TMP0
832   |  b >1
833   |.  sd STR:RC, 0(CARG3)
834   |
835   |->vmeta_tsets:
836   |  daddiu CARG2, DISPATCH, DISPATCH_GL(tmptv)
837   |  li TMP0, LJ_TTAB
838   |   li TMP1, LJ_TSTR
839   |  settp TAB:RB, TMP0
840   |   daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv2)
841   |  sd TAB:RB, 0(CARG2)
842   |   settp STR:RC, TMP1
843   |  b >1
844   |.  sd STR:RC, 0(CARG3)
845   |
846   |->vmeta_tsetb:                       // TMP0 = index
847   |  daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv)
848   |  settp TMP0, TISNUM
849   |  sd TMP0, 0(CARG3)
850   |
851   |->vmeta_tsetv:
852   |1:
853   |  load_got lj_meta_tset
854   |  sd BASE, L->base
855   |  sd PC, SAVE_PC
856   |  call_intern lj_meta_tset           // (lua_State *L, TValue *o, TValue *k)
857   |.  move CARG1, L
858   |  // Returns TValue * (finished) or NULL (metamethod).
859   |  beqz CRET1, >3
860   |.  ld CARG1, 0(RA)
861   |  // NOBARRIER: lj_meta_tset ensures the table is not black.
862   |  ins_next1
863   |  sd CARG1, 0(CRET1)
864   |  ins_next2
865   |
866   |3:  // Call __newindex metamethod.
867   |  // BASE = base, L->top = new base, stack = cont/func/t/k/(v)
868   |  daddiu TMP1, BASE, -FRAME_CONT
869   |  ld BASE, L->top
870   |  sd PC, -24(BASE)                   // [cont|PC]
871   |   dsubu PC, BASE, TMP1
872   |  ld LFUNC:RB, FRAME_FUNC(BASE)      // Guaranteed to be a function here.
873   |  cleartp LFUNC:RB
874   |  sd CARG1, 16(BASE)                 // Copy value to third argument.
875   |  b ->vm_call_dispatch_f
876   |.  li NARGS8:RC, 24                  // 3 args for func(t, k, v)
877   |
878   |->vmeta_tsetr:
879   |  load_got lj_tab_setinth
880   |  sd BASE, L->base
881   |  sd PC, SAVE_PC
882   |  call_intern lj_tab_setinth // (lua_State *L, GCtab *t, int32_t key)
883   |.  move CARG1, L
884   |  // Returns TValue *.
885   |  b ->BC_TSETR_Z
886   |.  nop
887   |
888   |//-- Comparison metamethods ---------------------------------------------
889   |
890   |->vmeta_comp:
891   |  // RA/RD point to o1/o2.
892   |  move CARG2, RA
893   |  move CARG3, RD
894   |  load_got lj_meta_comp
895   |  daddiu PC, PC, -4
896   |  sd BASE, L->base
897   |  sd PC, SAVE_PC
898   |  decode_OP1 CARG4, INS
899   |  call_intern lj_meta_comp   // (lua_State *L, TValue *o1, *o2, int op)
900   |.  move CARG1, L
901   |  // Returns 0/1 or TValue * (metamethod).
902   |3:
903   |  sltiu AT, CRET1, 2
904   |  beqz AT, ->vmeta_binop
905   |   negu TMP2, CRET1
906   |4:
907   |  lhu RD, OFS_RD(PC)
908   |   daddiu PC, PC, 4
909   |   lui TMP1, (-(BCBIAS_J*4 >> 16) & 65535)
910   |  sll RD, RD, 2
911   |  addu RD, RD, TMP1
912   |  and RD, RD, TMP2
913   |  daddu PC, PC, RD
914   |->cont_nop:
915   |  ins_next
916   |
917   |->cont_ra:                           // RA = resultptr
918   |  lbu TMP1, -4+OFS_RA(PC)
919   |   ld CRET1, 0(RA)
920   |  sll TMP1, TMP1, 3
921   |  daddu TMP1, BASE, TMP1
922   |  b ->cont_nop
923   |.   sd CRET1, 0(TMP1)
924   |
925   |->cont_condt:                        // RA = resultptr
926   |  ld TMP0, 0(RA)
927   |  gettp TMP0, TMP0
928   |  sltiu AT, TMP0, LJ_TISTRUECOND
929   |  b <4
930   |.  negu TMP2, AT                     // Branch if result is true.
931   |
932   |->cont_condf:                        // RA = resultptr
933   |  ld TMP0, 0(RA)
934   |  gettp TMP0, TMP0
935   |  sltiu AT, TMP0, LJ_TISTRUECOND
936   |  b <4
937   |.  addiu TMP2, AT, -1                // Branch if result is false.
938   |
939   |->vmeta_equal:
940   |  // CARG1/CARG2 point to o1/o2. TMP0 is set to 0/1.
941   |  load_got lj_meta_equal
942   |   cleartp LFUNC:CARG3, CARG2
943   |  cleartp LFUNC:CARG2, CARG1
944   |    move CARG4, TMP0
945   |  daddiu PC, PC, -4
946   |   sd BASE, L->base
947   |   sd PC, SAVE_PC
948   |  call_intern lj_meta_equal  // (lua_State *L, GCobj *o1, *o2, int ne)
949   |.  move CARG1, L
950   |  // Returns 0/1 or TValue * (metamethod).
951   |  b <3
952   |.  nop
953   |
954   |->vmeta_equal_cd:
955   |.if FFI
956   |  load_got lj_meta_equal_cd
957   |  move CARG2, INS
958   |  daddiu PC, PC, -4
959   |   sd BASE, L->base
960   |   sd PC, SAVE_PC
961   |  call_intern lj_meta_equal_cd       // (lua_State *L, BCIns op)
962   |.  move CARG1, L
963   |  // Returns 0/1 or TValue * (metamethod).
964   |  b <3
965   |.  nop
966   |.endif
967   |
968   |->vmeta_istype:
969   |  load_got lj_meta_istype
970   |  daddiu PC, PC, -4
971   |   sd BASE, L->base
972   |   srl CARG2, RA, 3
973   |   srl CARG3, RD, 3
974   |  sd PC, SAVE_PC
975   |  call_intern lj_meta_istype // (lua_State *L, BCReg ra, BCReg tp)
976   |.  move CARG1, L
977   |  b ->cont_nop
978   |.  nop
979   |
980   |//-- Arithmetic metamethods ---------------------------------------------
981   |
982   |->vmeta_unm:
983   |  move RC, RB
984   |
985   |->vmeta_arith:
986   |  load_got lj_meta_arith
987   |   sd BASE, L->base
988   |  move CARG2, RA
989   |   sd PC, SAVE_PC
990   |  move CARG3, RB
991   |  move CARG4, RC
992   |  decode_OP1 CARG5, INS      // CARG5 == RB.
993   |  call_intern lj_meta_arith  // (lua_State *L, TValue *ra,*rb,*rc, BCReg op)
994   |.  move CARG1, L
995   |  // Returns NULL (finished) or TValue * (metamethod).
996   |  beqz CRET1, ->cont_nop
997   |.  nop
998   |
999   |  // Call metamethod for binary op.
1000   |->vmeta_binop:
1001   |  // BASE = old base, CRET1 = new base, stack = cont/func/o1/o2
1002   |  dsubu TMP1, CRET1, BASE
1003   |   sd PC, -24(CRET1)                 // [cont|PC]
1004   |   move TMP2, BASE
1005   |  daddiu PC, TMP1, FRAME_CONT
1006   |   move BASE, CRET1
1007   |  b ->vm_call_dispatch
1008   |.  li NARGS8:RC, 16                  // 2 args for func(o1, o2).
1009   |
1010   |->vmeta_len:
1011   |  // CARG2 already set by BC_LEN.
1012 #if LJ_52
1013   |  move MULTRES, CARG1
1014 #endif
1015   |  load_got lj_meta_len
1016   |   sd BASE, L->base
1017   |   sd PC, SAVE_PC
1018   |  call_intern lj_meta_len            // (lua_State *L, TValue *o)
1019   |.  move CARG1, L
1020   |  // Returns NULL (retry) or TValue * (metamethod base).
1021 #if LJ_52
1022   |  bnez CRET1, ->vmeta_binop          // Binop call for compatibility.
1023   |.  nop
1024   |  b ->BC_LEN_Z
1025   |.  move CARG1, MULTRES
1026 #else
1027   |  b ->vmeta_binop                    // Binop call for compatibility.
1028   |.  nop
1029 #endif
1030   |
1031   |//-- Call metamethod ----------------------------------------------------
1032   |
1033   |->vmeta_call:                        // Resolve and call __call metamethod.
1034   |  // TMP2 = old base, BASE = new base, RC = nargs*8
1035   |  load_got lj_meta_call
1036   |   sd TMP2, L->base                  // This is the callers base!
1037   |  daddiu CARG2, BASE, -16
1038   |   sd PC, SAVE_PC
1039   |  daddu CARG3, BASE, RC
1040   |   move MULTRES, NARGS8:RC
1041   |  call_intern lj_meta_call   // (lua_State *L, TValue *func, TValue *top)
1042   |.  move CARG1, L
1043   |  ld LFUNC:RB, FRAME_FUNC(BASE)      // Guaranteed to be a function here.
1044   |   daddiu NARGS8:RC, MULTRES, 8      // Got one more argument now.
1045   |  cleartp LFUNC:RB
1046   |  ins_call
1047   |
1048   |->vmeta_callt:                       // Resolve __call for BC_CALLT.
1049   |  // BASE = old base, RA = new base, RC = nargs*8
1050   |  load_got lj_meta_call
1051   |   sd BASE, L->base
1052   |  daddiu CARG2, RA, -16
1053   |   sd PC, SAVE_PC
1054   |  daddu CARG3, RA, RC
1055   |   move MULTRES, NARGS8:RC
1056   |  call_intern lj_meta_call           // (lua_State *L, TValue *func, TValue *top)
1057   |.  move CARG1, L
1058   |   ld RB, FRAME_FUNC(RA)             // Guaranteed to be a function here.
1059   |  ld TMP1, FRAME_PC(BASE)
1060   |  daddiu NARGS8:RC, MULTRES, 8       // Got one more argument now.
1061   |  b ->BC_CALLT_Z
1062   |.  cleartp LFUNC:CARG3, RB
1063   |
1064   |//-- Argument coercion for 'for' statement ------------------------------
1065   |
1066   |->vmeta_for:
1067   |  load_got lj_meta_for
1068   |   sd BASE, L->base
1069   |  move CARG2, RA
1070   |   sd PC, SAVE_PC
1071   |  move MULTRES, INS
1072   |  call_intern lj_meta_for    // (lua_State *L, TValue *base)
1073   |.  move CARG1, L
1074   |.if JIT
1075   |  decode_OP1 TMP0, MULTRES
1076   |  li AT, BC_JFORI
1077   |.endif
1078   |  decode_RA8a RA, MULTRES
1079   |   decode_RD8a RD, MULTRES
1080   |  decode_RA8b RA
1081   |.if JIT
1082   |  beq TMP0, AT, =>BC_JFORI
1083   |.  decode_RD8b RD
1084   |  b =>BC_FORI
1085   |.  nop
1086   |.else
1087   |  b =>BC_FORI
1088   |.  decode_RD8b RD
1089   |.endif
1090   |
1091   |//-----------------------------------------------------------------------
1092   |//-- Fast functions -----------------------------------------------------
1093   |//-----------------------------------------------------------------------
1094   |
1095   |.macro .ffunc, name
1096   |->ff_ .. name:
1097   |.endmacro
1098   |
1099   |.macro .ffunc_1, name
1100   |->ff_ .. name:
1101   |  beqz NARGS8:RC, ->fff_fallback
1102   |.  ld CARG1, 0(BASE)
1103   |.endmacro
1104   |
1105   |.macro .ffunc_2, name
1106   |->ff_ .. name:
1107   |  sltiu AT, NARGS8:RC, 16
1108   |  ld CARG1, 0(BASE)
1109   |  bnez AT, ->fff_fallback
1110   |.  ld CARG2, 8(BASE)
1111   |.endmacro
1112   |
1113   |.macro .ffunc_n, name        // Caveat: has delay slot!
1114   |->ff_ .. name:
1115   |  ld CARG1, 0(BASE)
1116   |  beqz NARGS8:RC, ->fff_fallback
1117   |  // Either ldc1 or the 1st instruction of checknum is in the delay slot.
1118   |  .FPU ldc1 FARG1, 0(BASE)
1119   |  checknum CARG1, ->fff_fallback
1120   |.endmacro
1121   |
1122   |.macro .ffunc_nn, name       // Caveat: has delay slot!
1123   |->ff_ .. name:
1124   |  ld CARG1, 0(BASE)
1125   |    sltiu AT, NARGS8:RC, 16
1126   |   ld CARG2, 8(BASE)
1127   |  bnez AT, ->fff_fallback
1128   |.  gettp TMP0, CARG1
1129   |   gettp TMP1, CARG2
1130   |  sltiu TMP0, TMP0, LJ_TISNUM
1131   |   sltiu TMP1, TMP1, LJ_TISNUM
1132   |  .FPU ldc1 FARG1, 0(BASE)
1133   |  and TMP0, TMP0, TMP1
1134   |   .FPU ldc1 FARG2, 8(BASE)
1135   |  beqz TMP0, ->fff_fallback
1136   |.endmacro
1137   |
1138   |// Inlined GC threshold check. Caveat: uses TMP0 and TMP1 and has delay slot!
1139   |// MIPSR6: no delay slot, but a forbidden slot.
1140   |.macro ffgccheck
1141   |  ld TMP0, DISPATCH_GL(gc.total)(DISPATCH)
1142   |  ld TMP1, DISPATCH_GL(gc.threshold)(DISPATCH)
1143   |  dsubu AT, TMP0, TMP1
1144   |.if MIPSR6
1145   |  bgezalc AT, ->fff_gcstep
1146   |.else
1147   |  bgezal AT, ->fff_gcstep
1148   |.endif
1149   |.endmacro
1150   |
1151   |//-- Base library: checks -----------------------------------------------
1152   |.ffunc_1 assert
1153   |  gettp AT, CARG1
1154   |  sltiu AT, AT, LJ_TISTRUECOND
1155   |  beqz AT, ->fff_fallback
1156   |.  daddiu RA, BASE, -16
1157   |  ld PC, FRAME_PC(BASE)
1158   |  addiu RD, NARGS8:RC, 8             // Compute (nresults+1)*8.
1159   |  daddu TMP2, RA, RD
1160   |  daddiu TMP1, BASE, 8
1161   |  beq BASE, TMP2, ->fff_res          // Done if exactly 1 argument.
1162   |.  sd CARG1, 0(RA)
1163   |1:
1164   |  ld CRET1, 0(TMP1)
1165   |  sd CRET1, -16(TMP1)
1166   |  bne TMP1, TMP2, <1
1167   |.  daddiu TMP1, TMP1, 8
1168   |  b ->fff_res
1169   |.  nop
1170   |
1171   |.ffunc_1 type
1172   |  gettp TMP0, CARG1
1173   |  sltu TMP1, TISNUM, TMP0
1174   |  not TMP2, TMP0
1175   |  li TMP3, ~LJ_TISNUM
1176   |.if MIPSR6
1177   |  selnez TMP2, TMP2, TMP1
1178   |  seleqz TMP3, TMP3, TMP1
1179   |  or TMP2, TMP2, TMP3
1180   |.else
1181   |  movz TMP2, TMP3, TMP1
1182   |.endif
1183   |  dsll TMP2, TMP2, 3
1184   |  daddu TMP2, CFUNC:RB, TMP2
1185   |  b ->fff_restv
1186   |.  ld CARG1, CFUNC:TMP2->upvalue
1187   |
1188   |//-- Base library: getters and setters ---------------------------------
1189   |
1190   |.ffunc_1 getmetatable
1191   |  gettp TMP2, CARG1
1192   |  daddiu TMP0, TMP2, -LJ_TTAB
1193   |  daddiu TMP1, TMP2, -LJ_TUDATA
1194   |.if MIPSR6
1195   |  selnez TMP0, TMP1, TMP0
1196   |.else
1197   |  movn TMP0, TMP1, TMP0
1198   |.endif
1199   |  bnez TMP0, >6
1200   |.  cleartp TAB:CARG1
1201   |1:  // Field metatable must be at same offset for GCtab and GCudata!
1202   |  ld TAB:RB, TAB:CARG1->metatable
1203   |2:
1204   |  ld STR:RC, DISPATCH_GL(gcroot[GCROOT_MMNAME+MM_metatable])(DISPATCH)
1205   |  beqz TAB:RB, ->fff_restv
1206   |.  li CARG1, LJ_TNIL
1207   |  lw TMP0, TAB:RB->hmask
1208   |   lw TMP1, STR:RC->sid
1209   |    ld NODE:TMP2, TAB:RB->node
1210   |  and TMP1, TMP1, TMP0               // idx = str->sid & tab->hmask
1211   |  dsll TMP0, TMP1, 5
1212   |  dsll TMP1, TMP1, 3
1213   |  dsubu TMP1, TMP0, TMP1
1214   |  daddu NODE:TMP2, NODE:TMP2, TMP1   // node = tab->node + (idx*32-idx*8)
1215   |  li CARG4, LJ_TSTR
1216   |  settp STR:RC, CARG4                // Tagged key to look for.
1217   |3:  // Rearranged logic, because we expect _not_ to find the key.
1218   |  ld TMP0, NODE:TMP2->key
1219   |   ld CARG1, NODE:TMP2->val
1220   |    ld NODE:TMP2, NODE:TMP2->next
1221   |  beq RC, TMP0, >5
1222   |.  li AT, LJ_TTAB
1223   |  bnez NODE:TMP2, <3
1224   |.  nop
1225   |4:
1226   |  move CARG1, RB
1227   |  b ->fff_restv                      // Not found, keep default result.
1228   |.  settp CARG1, AT
1229   |5:
1230   |  bne CARG1, TISNIL, ->fff_restv
1231   |.  nop
1232   |  b <4                               // Ditto for nil value.
1233   |.  nop
1234   |
1235   |6:
1236   |  sltiu AT, TMP2, LJ_TISNUM
1237   |.if MIPSR6
1238   |  selnez TMP0, TISNUM, AT
1239   |  seleqz AT, TMP2, AT
1240   |  or TMP2, TMP0, AT
1241   |.else
1242   |  movn TMP2, TISNUM, AT
1243   |.endif
1244   |  dsll TMP2, TMP2, 3
1245   |   dsubu TMP0, DISPATCH, TMP2
1246   |  b <2
1247   |.  ld TAB:RB, DISPATCH_GL(gcroot[GCROOT_BASEMT])-8(TMP0)
1248   |
1249   |.ffunc_2 setmetatable
1250   |  // Fast path: no mt for table yet and not clearing the mt.
1251   |  checktp TMP1, CARG1, -LJ_TTAB, ->fff_fallback
1252   |  gettp TMP3, CARG2
1253   |   ld TAB:TMP0, TAB:TMP1->metatable
1254   |   lbu TMP2, TAB:TMP1->marked
1255   |  daddiu AT, TMP3, -LJ_TTAB
1256   |   cleartp TAB:CARG2
1257   |  or AT, AT, TAB:TMP0
1258   |  bnez AT, ->fff_fallback
1259   |.  andi AT, TMP2, LJ_GC_BLACK        // isblack(table)
1260   |  beqz AT, ->fff_restv
1261   |.  sd TAB:CARG2, TAB:TMP1->metatable
1262   |  barrierback TAB:TMP1, TMP2, TMP0, ->fff_restv
1263   |
1264   |.ffunc rawget
1265   |  ld CARG2, 0(BASE)
1266   |  sltiu AT, NARGS8:RC, 16
1267   |  load_got lj_tab_get
1268   |  gettp TMP0, CARG2
1269   |   cleartp CARG2
1270   |  daddiu TMP0, TMP0, -LJ_TTAB
1271   |  or AT, AT, TMP0
1272   |  bnez AT, ->fff_fallback
1273   |.  daddiu CARG3, BASE, 8
1274   |  call_intern lj_tab_get     // (lua_State *L, GCtab *t, cTValue *key)
1275   |.  move CARG1, L
1276   |  b ->fff_restv
1277   |.  ld CARG1, 0(CRET1)
1278   |
1279   |//-- Base library: conversions ------------------------------------------
1280   |
1281   |.ffunc tonumber
1282   |  // Only handles the number case inline (without a base argument).
1283   |  ld CARG1, 0(BASE)
1284   |  xori AT, NARGS8:RC, 8              // Exactly one number argument.
1285   |  gettp TMP1, CARG1
1286   |  sltu TMP0, TISNUM, TMP1
1287   |  or AT, AT, TMP0
1288   |  bnez AT, ->fff_fallback
1289   |.  nop
1290   |  b ->fff_restv
1291   |.  nop
1292   |
1293   |.ffunc_1 tostring
1294   |  // Only handles the string or number case inline.
1295   |  gettp TMP0, CARG1
1296   |  daddiu AT, TMP0, -LJ_TSTR
1297   |  // A __tostring method in the string base metatable is ignored.
1298   |  beqz AT, ->fff_restv       // String key?
1299   |  // Handle numbers inline, unless a number base metatable is present.
1300   |.  ld TMP1, DISPATCH_GL(gcroot[GCROOT_BASEMT_NUM])(DISPATCH)
1301   |  sltu TMP0, TISNUM, TMP0
1302   |  or TMP0, TMP0, TMP1
1303   |  bnez TMP0, ->fff_fallback
1304   |.  sd BASE, L->base                  // Add frame since C call can throw.
1305   |.if MIPSR6
1306   |  sd PC, SAVE_PC                     // Redundant (but a defined value).
1307   |  ffgccheck
1308   |.else
1309   |  ffgccheck
1310   |.  sd PC, SAVE_PC                    // Redundant (but a defined value).
1311   |.endif
1312   |  load_got lj_strfmt_number
1313   |  move CARG1, L
1314   |  call_intern lj_strfmt_number       // (lua_State *L, cTValue *o)
1315   |.  move CARG2, BASE
1316   |  // Returns GCstr *.
1317   |  li AT, LJ_TSTR
1318   |  settp CRET1, AT
1319   |  b ->fff_restv
1320   |.  move CARG1, CRET1
1321   |
1322   |//-- Base library: iterators -------------------------------------------
1323   |
1324   |.ffunc_1 next
1325   |  checktp CARG1, -LJ_TTAB, ->fff_fallback
1326   |  daddu TMP2, BASE, NARGS8:RC
1327   |  sd TISNIL, 0(TMP2)                 // Set missing 2nd arg to nil.
1328   |  load_got lj_tab_next
1329   |  ld PC, FRAME_PC(BASE)
1330   |  daddiu CARG2, BASE, 8
1331   |  call_intern lj_tab_next            // (GCtab *t, cTValue *key, TValue *o)
1332   |.  daddiu CARG3, BASE, -16
1333   |  // Returns 1=found, 0=end, -1=error.
1334   |   daddiu RA, BASE, -16
1335   |  bgtz CRET1, ->fff_res              // Found key/value.
1336   |.  li RD, (2+1)*8
1337   |  beqz CRET1, ->fff_restv            // End of traversal: return nil.
1338   |.  move CARG1, TISNIL
1339   |   ld CFUNC:RB, FRAME_FUNC(BASE)
1340   |   cleartp CFUNC:RB
1341   |  b ->fff_fallback                   // Invalid key.
1342   |.  li RC, 2*8
1343   |
1344   |.ffunc_1 pairs
1345   |  checktp TAB:TMP1, CARG1, -LJ_TTAB, ->fff_fallback
1346   |  ld PC, FRAME_PC(BASE)
1347 #if LJ_52
1348   |  ld TAB:TMP2, TAB:TMP1->metatable
1349   |  ld TMP0, CFUNC:RB->upvalue[0]
1350   |  bnez TAB:TMP2, ->fff_fallback
1351 #else
1352   |  ld TMP0, CFUNC:RB->upvalue[0]
1353 #endif
1354   |.  daddiu RA, BASE, -16
1355   |  sd TISNIL, 0(BASE)
1356   |   sd CARG1, -8(BASE)
1357   |    sd TMP0, 0(RA)
1358   |  b ->fff_res
1359   |.  li RD, (3+1)*8
1360   |
1361   |.ffunc_2 ipairs_aux
1362   |  checktab CARG1, ->fff_fallback
1363   |   checkint CARG2, ->fff_fallback
1364   |.  lw TMP0, TAB:CARG1->asize
1365   |   ld TMP1, TAB:CARG1->array
1366   |    ld PC, FRAME_PC(BASE)
1367   |  sextw TMP2, CARG2
1368   |  addiu TMP2, TMP2, 1
1369   |  sltu AT, TMP2, TMP0
1370   |    daddiu RA, BASE, -16
1371   |   zextw TMP0, TMP2
1372   |   settp TMP0, TISNUM
1373   |  beqz AT, >2                        // Not in array part?
1374   |.  sd TMP0, 0(RA)
1375   |  dsll TMP3, TMP2, 3
1376   |  daddu TMP3, TMP1, TMP3
1377   |  ld TMP1, 0(TMP3)
1378   |1:
1379   |  beq TMP1, TISNIL, ->fff_res        // End of iteration, return 0 results.
1380   |.  li RD, (0+1)*8
1381   |  sd TMP1, -8(BASE)
1382   |  b ->fff_res
1383   |.  li RD, (2+1)*8
1384   |2:  // Check for empty hash part first. Otherwise call C function.
1385   |  lw TMP0, TAB:CARG1->hmask
1386   |  load_got lj_tab_getinth
1387   |  beqz TMP0, ->fff_res
1388   |.  li RD, (0+1)*8
1389   |  call_intern lj_tab_getinth         // (GCtab *t, int32_t key)
1390   |.  move CARG2, TMP2
1391   |  // Returns cTValue * or NULL.
1392   |  beqz CRET1, ->fff_res
1393   |.  li RD, (0+1)*8
1394   |  b <1
1395   |.  ld TMP1, 0(CRET1)
1396   |
1397   |.ffunc_1 ipairs
1398   |  checktp TAB:TMP1, CARG1, -LJ_TTAB, ->fff_fallback
1399   |  ld PC, FRAME_PC(BASE)
1400 #if LJ_52
1401   |  ld TAB:TMP2, TAB:TMP1->metatable
1402   |  ld CFUNC:TMP0, CFUNC:RB->upvalue[0]
1403   |  bnez TAB:TMP2, ->fff_fallback
1404 #else
1405   |  ld TMP0, CFUNC:RB->upvalue[0]
1406 #endif
1407   |  daddiu RA, BASE, -16
1408   |  dsll AT, TISNUM, 47
1409   |  sd CARG1, -8(BASE)
1410   |   sd AT, 0(BASE)
1411   |    sd CFUNC:TMP0, 0(RA)
1412   |  b ->fff_res
1413   |.  li RD, (3+1)*8
1414   |
1415   |//-- Base library: catch errors ----------------------------------------
1416   |
1417   |.ffunc pcall
1418   |  ld TMP1, L->maxstack
1419   |  daddu TMP2, BASE, NARGS8:RC
1420   |  sltu AT, TMP1, TMP2
1421   |  bnez AT, ->fff_fallback
1422   |.  lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
1423   |  daddiu NARGS8:TMP0, NARGS8:RC, -8
1424   |  bltz NARGS8:TMP0, ->fff_fallback
1425   |.   move TMP2, BASE
1426   |  move NARGS8:RC, NARGS8:TMP0
1427   |   daddiu BASE, BASE, 16
1428   |  // Remember active hook before pcall.
1429   |  srl TMP3, TMP3, HOOK_ACTIVE_SHIFT
1430   |  andi TMP3, TMP3, 1
1431   |  daddiu PC, TMP3, 16+FRAME_PCALL
1432   |  beqz NARGS8:RC, ->vm_call_dispatch
1433   |1:
1434   |.  daddu TMP0, BASE, NARGS8:RC
1435   |2:
1436   |  ld TMP1, -16(TMP0)
1437   |  sd TMP1, -8(TMP0)
1438   |  daddiu TMP0, TMP0, -8
1439   |  bne TMP0, BASE, <2
1440   |.  nop
1441   |  b ->vm_call_dispatch
1442   |.  nop
1443   |
1444   |.ffunc xpcall
1445   |  ld TMP1, L->maxstack
1446   |  daddu TMP2, BASE, NARGS8:RC
1447   |  sltu AT, TMP1, TMP2
1448   |  bnez AT, ->fff_fallback
1449   |.  ld CARG1, 0(BASE)
1450   |  daddiu NARGS8:TMP0, NARGS8:RC, -16
1451   |   ld CARG2, 8(BASE)
1452   |    bltz NARGS8:TMP0, ->fff_fallback
1453   |.    lbu TMP1, DISPATCH_GL(hookmask)(DISPATCH)
1454   |  gettp AT, CARG2
1455   |  daddiu AT, AT, -LJ_TFUNC
1456   |  bnez AT, ->fff_fallback            // Traceback must be a function.
1457   |.   move TMP2, BASE
1458   |  move NARGS8:RC, NARGS8:TMP0
1459   |   daddiu BASE, BASE, 24
1460   |  // Remember active hook before pcall.
1461   |  srl TMP3, TMP3, HOOK_ACTIVE_SHIFT
1462   |   sd CARG2, 0(TMP2)                 // Swap function and traceback.
1463   |  andi TMP3, TMP3, 1
1464   |   sd CARG1, 8(TMP2)
1465   |  beqz NARGS8:RC, ->vm_call_dispatch
1466   |.  daddiu PC, TMP3, 24+FRAME_PCALL
1467   |  b <1
1468   |.  nop
1469   |
1470   |//-- Coroutine library --------------------------------------------------
1471   |
1472   |.macro coroutine_resume_wrap, resume
1473   |.if resume
1474   |.ffunc_1 coroutine_resume
1475   |  checktp CARG1, CARG1, -LJ_TTHREAD, ->fff_fallback
1476   |.else
1477   |.ffunc coroutine_wrap_aux
1478   |  ld L:CARG1, CFUNC:RB->upvalue[0].gcr
1479   |  cleartp L:CARG1
1480   |.endif
1481   |  lbu TMP0, L:CARG1->status
1482   |   ld TMP1, L:CARG1->cframe
1483   |    ld CARG2, L:CARG1->top
1484   |    ld TMP2, L:CARG1->base
1485   |  addiu AT, TMP0, -LUA_YIELD
1486   |    daddu CARG3, CARG2, TMP0
1487   |   daddiu TMP3, CARG2, 8
1488   |.if MIPSR6
1489   |  seleqz CARG2, CARG2, AT
1490   |  selnez TMP3, TMP3, AT
1491   |  bgtz AT, ->fff_fallback            // st > LUA_YIELD?
1492   |.  or CARG2, TMP3, CARG2
1493   |.else
1494   |  bgtz AT, ->fff_fallback            // st > LUA_YIELD?
1495   |.  movn CARG2, TMP3, AT
1496   |.endif
1497   |   xor TMP2, TMP2, CARG3
1498   |  bnez TMP1, ->fff_fallback          // cframe != 0?
1499   |.  or AT, TMP2, TMP0
1500   |  ld TMP0, L:CARG1->maxstack
1501   |  beqz AT, ->fff_fallback            // base == top && st == 0?
1502   |.  ld PC, FRAME_PC(BASE)
1503   |  daddu TMP2, CARG2, NARGS8:RC
1504   |  sltu AT, TMP0, TMP2
1505   |  bnez AT, ->fff_fallback            // Stack overflow?
1506   |.  sd PC, SAVE_PC
1507   |   sd BASE, L->base
1508   |1:
1509   |.if resume
1510   |  daddiu BASE, BASE, 8               // Keep resumed thread in stack for GC.
1511   |  daddiu NARGS8:RC, NARGS8:RC, -8
1512   |  daddiu TMP2, TMP2, -8
1513   |.endif
1514   |  sd TMP2, L:CARG1->top
1515   |  daddu TMP1, BASE, NARGS8:RC
1516   |  move CARG3, CARG2
1517   |  sd BASE, L->top
1518   |2:  // Move args to coroutine.
1519   |   ld CRET1, 0(BASE)
1520   |  sltu AT, BASE, TMP1
1521   |  beqz AT, >3
1522   |.  daddiu BASE, BASE, 8
1523   |   sd CRET1, 0(CARG3)
1524   |  b <2
1525   |.  daddiu CARG3, CARG3, 8
1526   |3:
1527   |  bal ->vm_resume                    // (lua_State *L, TValue *base, 0, 0)
1528   |.  move L:RA, L:CARG1
1529   |  // Returns thread status.
1530   |4:
1531   |  ld TMP2, L:RA->base
1532   |   sltiu AT, CRET1, LUA_YIELD+1
1533   |  ld TMP3, L:RA->top
1534   |    li_vmstate INTERP
1535   |  ld BASE, L->base
1536   |    sd L, DISPATCH_GL(cur_L)(DISPATCH)
1537   |    st_vmstate
1538   |   beqz AT, >8
1539   |. dsubu RD, TMP3, TMP2
1540   |   ld TMP0, L->maxstack
1541   |  beqz RD, >6                        // No results?
1542   |.  daddu TMP1, BASE, RD
1543   |  sltu AT, TMP0, TMP1
1544   |  bnez AT, >9                        // Need to grow stack?
1545   |.  daddu TMP3, TMP2, RD
1546   |  sd TMP2, L:RA->top                 // Clear coroutine stack.
1547   |  move TMP1, BASE
1548   |5:  // Move results from coroutine.
1549   |   ld CRET1, 0(TMP2)
1550   |  daddiu TMP2, TMP2, 8
1551   |  sltu AT, TMP2, TMP3
1552   |   sd CRET1, 0(TMP1)
1553   |  bnez AT, <5
1554   |.  daddiu TMP1, TMP1, 8
1555   |6:
1556   |  andi TMP0, PC, FRAME_TYPE
1557   |.if resume
1558   |  mov_true TMP1
1559   |   daddiu RA, BASE, -8
1560   |  sd TMP1, -8(BASE)                  // Prepend true to results.
1561   |  daddiu RD, RD, 16
1562   |.else
1563   |  move RA, BASE
1564   |  daddiu RD, RD, 8
1565   |.endif
1566   |7:
1567   |  sd PC, SAVE_PC
1568   |  beqz TMP0, ->BC_RET_Z
1569   |.  move MULTRES, RD
1570   |  b ->vm_return
1571   |.  nop
1572   |
1573   |8:  // Coroutine returned with error (at co->top-1).
1574   |.if resume
1575   |  daddiu TMP3, TMP3, -8
1576   |   mov_false TMP1
1577   |  ld CRET1, 0(TMP3)
1578   |   sd TMP3, L:RA->top                // Remove error from coroutine stack.
1579   |    li RD, (2+1)*8
1580   |   sd TMP1, -8(BASE)                 // Prepend false to results.
1581   |    daddiu RA, BASE, -8
1582   |  sd CRET1, 0(BASE)                  // Copy error message.
1583   |  b <7
1584   |.  andi TMP0, PC, FRAME_TYPE
1585   |.else
1586   |  load_got lj_ffh_coroutine_wrap_err
1587   |  move CARG2, L:RA
1588   |  call_intern lj_ffh_coroutine_wrap_err  // (lua_State *L, lua_State *co)
1589   |.  move CARG1, L
1590   |.endif
1591   |
1592   |9:  // Handle stack expansion on return from yield.
1593   |  load_got lj_state_growstack
1594   |  srl CARG2, RD, 3
1595   |  call_intern lj_state_growstack     // (lua_State *L, int n)
1596   |.  move CARG1, L
1597   |  b <4
1598   |.  li CRET1, 0
1599   |.endmacro
1600   |
1601   |  coroutine_resume_wrap 1            // coroutine.resume
1602   |  coroutine_resume_wrap 0            // coroutine.wrap
1603   |
1604   |.ffunc coroutine_yield
1605   |  ld TMP0, L->cframe
1606   |   daddu TMP1, BASE, NARGS8:RC
1607   |   sd BASE, L->base
1608   |  andi TMP0, TMP0, CFRAME_RESUME
1609   |   sd TMP1, L->top
1610   |  beqz TMP0, ->fff_fallback
1611   |.   li CRET1, LUA_YIELD
1612   |  sd r0, L->cframe
1613   |  b ->vm_leave_unw
1614   |.   sb CRET1, L->status
1615   |
1616   |//-- Math library -------------------------------------------------------
1617   |
1618   |.ffunc_1 math_abs
1619   |  gettp CARG2, CARG1
1620   |  daddiu AT, CARG2, -LJ_TISNUM
1621   |  bnez AT, >1
1622   |.  sextw TMP1, CARG1
1623   |  sra TMP0, TMP1, 31                 // Extract sign.
1624   |  xor TMP1, TMP1, TMP0
1625   |  dsubu CARG1, TMP1, TMP0
1626   |  dsll TMP3, CARG1, 32
1627   |  bgez TMP3, ->fff_restv
1628   |.  settp CARG1, TISNUM
1629   |  li CARG1, 0x41e0                   // 2^31 as a double.
1630   |  b ->fff_restv
1631   |.  dsll CARG1, CARG1, 48
1632   |1:
1633   |  sltiu AT, CARG2, LJ_TISNUM
1634   |  beqz AT, ->fff_fallback
1635   |.  dextm CARG1, CARG1, 0, 30
1636   |// fallthrough
1637   |
1638   |->fff_restv:
1639   |  // CARG1 = TValue result.
1640   |  ld PC, FRAME_PC(BASE)
1641   |  daddiu RA, BASE, -16
1642   |   sd CARG1, -16(BASE)
1643   |->fff_res1:
1644   |  // RA = results, PC = return.
1645   |  li RD, (1+1)*8
1646   |->fff_res:
1647   |  // RA = results, RD = (nresults+1)*8, PC = return.
1648   |  andi TMP0, PC, FRAME_TYPE
1649   |  bnez TMP0, ->vm_return
1650   |.  move MULTRES, RD
1651   |  lw INS, -4(PC)
1652   |  decode_RB8a RB, INS
1653   |  decode_RB8b RB
1654   |5:
1655   |  sltu AT, RD, RB
1656   |  bnez AT, >6                        // More results expected?
1657   |.  decode_RA8a TMP0, INS
1658   |  decode_RA8b TMP0
1659   |  ins_next1
1660   |  // Adjust BASE. KBASE is assumed to be set for the calling frame.
1661   |   dsubu BASE, RA, TMP0
1662   |  ins_next2
1663   |
1664   |6:  // Fill up results with nil.
1665   |  daddu TMP1, RA, RD
1666   |   daddiu RD, RD, 8
1667   |  b <5
1668   |.  sd TISNIL, -8(TMP1)
1669   |
1670   |.macro math_extern, func
1671   |  .ffunc_n math_ .. func
1672   |  load_got func
1673   |  call_extern
1674   |.  nop
1675   |  b ->fff_resn
1676   |.  nop
1677   |.endmacro
1678   |
1679   |.macro math_extern2, func
1680   |  .ffunc_nn math_ .. func
1681   |.  load_got func
1682   |  call_extern
1683   |.  nop
1684   |  b ->fff_resn
1685   |.  nop
1686   |.endmacro
1687   |
1688   |// TODO: Return integer type if result is integer (own sf implementation).
1689   |.macro math_round, func
1690   |->ff_math_ .. func:
1691   |  ld CARG1, 0(BASE)
1692   |  beqz NARGS8:RC, ->fff_fallback
1693   |.  gettp TMP0, CARG1
1694   |  beq TMP0, TISNUM, ->fff_restv
1695   |.  sltu AT, TMP0, TISNUM
1696   |  beqz AT, ->fff_fallback
1697   |.if FPU
1698   |.  ldc1 FARG1, 0(BASE)
1699   |  bal ->vm_ .. func
1700   |.  nop
1701   |.else
1702   |.  load_got func
1703   |  call_extern
1704   |.  nop
1705   |.endif
1706   |  b ->fff_resn
1707   |.  nop
1708   |.endmacro
1709   |
1710   |  math_round floor
1711   |  math_round ceil
1712   |
1713   |.ffunc math_log
1714   |  li AT, 8
1715   |  bne NARGS8:RC, AT, ->fff_fallback  // Exactly 1 argument.
1716   |.  ld CARG1, 0(BASE)
1717   |  checknum CARG1, ->fff_fallback
1718   |.  load_got log
1719   |.if FPU
1720   |  call_extern
1721   |.  ldc1 FARG1, 0(BASE)
1722   |.else
1723   |  call_extern
1724   |.  nop
1725   |.endif
1726   |  b ->fff_resn
1727   |.  nop
1728   |
1729   |  math_extern log10
1730   |  math_extern exp
1731   |  math_extern sin
1732   |  math_extern cos
1733   |  math_extern tan
1734   |  math_extern asin
1735   |  math_extern acos
1736   |  math_extern atan
1737   |  math_extern sinh
1738   |  math_extern cosh
1739   |  math_extern tanh
1740   |  math_extern2 pow
1741   |  math_extern2 atan2
1742   |  math_extern2 fmod
1743   |
1744   |.if FPU
1745   |.ffunc_n math_sqrt
1746   |.  sqrt.d FRET1, FARG1
1747   |// fallthrough to ->fff_resn
1748   |.else
1749   |  math_extern sqrt
1750   |.endif
1751   |
1752   |->fff_resn:
1753   |  ld PC, FRAME_PC(BASE)
1754   |  daddiu RA, BASE, -16
1755   |  b ->fff_res1
1756   |.if FPU
1757   |.  sdc1 FRET1, 0(RA)
1758   |.else
1759   |.  sd CRET1, 0(RA)
1760   |.endif
1761   |
1762   |
1763   |.ffunc_2 math_ldexp
1764   |  checknum CARG1, ->fff_fallback
1765   |  checkint CARG2, ->fff_fallback
1766   |.  load_got ldexp
1767   |  .FPU ldc1 FARG1, 0(BASE)
1768   |  call_extern
1769   |.  lw CARG2, 8+LO(BASE)
1770   |  b ->fff_resn
1771   |.  nop
1772   |
1773   |.ffunc_n math_frexp
1774   |  load_got frexp
1775   |   ld PC, FRAME_PC(BASE)
1776   |  call_extern
1777   |.  daddiu CARG2, DISPATCH, DISPATCH_GL(tmptv)
1778   |   lw TMP1, DISPATCH_GL(tmptv)(DISPATCH)
1779   |  daddiu RA, BASE, -16
1780   |.if FPU
1781   |   mtc1 TMP1, FARG2
1782   |  sdc1 FRET1, 0(RA)
1783   |   cvt.d.w FARG2, FARG2
1784   |   sdc1 FARG2, 8(RA)
1785   |.else
1786   |  sd CRET1, 0(RA)
1787   |  zextw TMP1, TMP1
1788   |  settp TMP1, TISNUM
1789   |  sd TMP1, 8(RA)
1790   |.endif
1791   |  b ->fff_res
1792   |.  li RD, (2+1)*8
1793   |
1794   |.ffunc_n math_modf
1795   |  load_got modf
1796   |   ld PC, FRAME_PC(BASE)
1797   |  call_extern
1798   |.  daddiu CARG2, BASE, -16
1799   |  daddiu RA, BASE, -16
1800   |.if FPU
1801   |  sdc1 FRET1, -8(BASE)
1802   |.else
1803   |  sd CRET1, -8(BASE)
1804   |.endif
1805   |  b ->fff_res
1806   |.  li RD, (2+1)*8
1807   |
1808   |.macro math_minmax, name, intins, intinsc, fpins
1809   |  .ffunc_1 name
1810   |  daddu TMP3, BASE, NARGS8:RC
1811   |  checkint CARG1, >5
1812   |.  daddiu TMP2, BASE, 8
1813   |1:  // Handle integers.
1814   |  beq TMP2, TMP3, ->fff_restv
1815   |.  ld CARG2, 0(TMP2)
1816   |  checkint CARG2, >3
1817   |.  sextw CARG1, CARG1
1818   |  lw CARG2, LO(TMP2)
1819   |.  slt AT, CARG1, CARG2
1820   |.if MIPSR6
1821   |  intins TMP1, CARG2, AT
1822   |  intinsc CARG1, CARG1, AT
1823   |  or CARG1, CARG1, TMP1
1824   |.else
1825   |  intins CARG1, CARG2, AT
1826   |.endif
1827   |  daddiu TMP2, TMP2, 8
1828   |  zextw CARG1, CARG1
1829   |  b <1
1830   |.  settp CARG1, TISNUM
1831   |
1832   |3:  // Convert intermediate result to number and continue with number loop.
1833   |  checknum CARG2, ->fff_fallback
1834   |.if FPU
1835   |.  mtc1 CARG1, FRET1
1836   |  cvt.d.w FRET1, FRET1
1837   |  b >7
1838   |.  ldc1 FARG1, 0(TMP2)
1839   |.else
1840   |.  nop
1841   |  bal ->vm_sfi2d_1
1842   |.  nop
1843   |  b >7
1844   |.  nop
1845   |.endif
1846   |
1847   |5:
1848   |  .FPU ldc1 FRET1, 0(BASE)
1849   |  checknum CARG1, ->fff_fallback
1850   |6:  // Handle numbers.
1851   |.  ld CARG2, 0(TMP2)
1852   |  beq TMP2, TMP3, ->fff_resn
1853   |.if FPU
1854   |  ldc1 FARG1, 0(TMP2)
1855   |.else
1856   |  move CRET1, CARG1
1857   |.endif
1858   |  checknum CARG2, >8
1859   |.  nop
1860   |7:
1861   |.if FPU
1862   |.if MIPSR6
1863   |  fpins FRET1, FRET1, FARG1
1864   |.else
1865   |.if fpins  // ismax
1866   |  c.olt.d FARG1, FRET1
1867   |.else
1868   |  c.olt.d FRET1, FARG1
1869   |.endif
1870   |  movf.d FRET1, FARG1
1871   |.endif
1872   |.else
1873   |.if fpins  // ismax
1874   |  bal ->vm_sfcmpogt
1875   |.else
1876   |  bal ->vm_sfcmpolt
1877   |.endif
1878   |.  nop
1879   |.if MIPSR6
1880   |  seleqz AT, CARG2, CRET1
1881   |  selnez CARG1, CARG1, CRET1
1882   |  or CARG1, CARG1, AT
1883   |.else
1884   |  movz CARG1, CARG2, CRET1
1885   |.endif
1886   |.endif
1887   |  b <6
1888   |.  daddiu TMP2, TMP2, 8
1889   |
1890   |8:  // Convert integer to number and continue with number loop.
1891   |  checkint CARG2, ->fff_fallback
1892   |.if FPU
1893   |.  lwc1 FARG1, LO(TMP2)
1894   |  b <7
1895   |.  cvt.d.w FARG1, FARG1
1896   |.else
1897   |.  lw CARG2, LO(TMP2)
1898   |  bal ->vm_sfi2d_2
1899   |.  nop
1900   |  b <7
1901   |.  nop
1902   |.endif
1903   |
1904   |.endmacro
1905   |
1906   |.if MIPSR6
1907   |  math_minmax math_min, seleqz, selnez, min.d
1908   |  math_minmax math_max, selnez, seleqz, max.d
1909   |.else
1910   |  math_minmax math_min, movz, _, 0
1911   |  math_minmax math_max, movn, _, 1
1912   |.endif
1913   |
1914   |//-- String library -----------------------------------------------------
1915   |
1916   |.ffunc string_byte                   // Only handle the 1-arg case here.
1917   |  ld CARG1, 0(BASE)
1918   |  gettp TMP0, CARG1
1919   |  xori AT, NARGS8:RC, 8
1920   |  daddiu TMP0, TMP0, -LJ_TSTR
1921   |  or AT, AT, TMP0
1922   |  bnez AT, ->fff_fallback            // Need exactly 1 string argument.
1923   |.  cleartp STR:CARG1
1924   |  lw TMP0, STR:CARG1->len
1925   |    daddiu RA, BASE, -16
1926   |    ld PC, FRAME_PC(BASE)
1927   |  sltu RD, r0, TMP0
1928   |   lbu TMP1, STR:CARG1[1]            // Access is always ok (NUL at end).
1929   |  addiu RD, RD, 1
1930   |  sll RD, RD, 3                      // RD = ((str->len != 0)+1)*8
1931   |  settp TMP1, TISNUM
1932   |  b ->fff_res
1933   |.  sd TMP1, 0(RA)
1934   |
1935   |.ffunc string_char                   // Only handle the 1-arg case here.
1936   |  ffgccheck
1937   |.if not MIPSR6
1938   |.  nop
1939   |.endif
1940   |  ld CARG1, 0(BASE)
1941   |  gettp TMP0, CARG1
1942   |  xori AT, NARGS8:RC, 8              // Exactly 1 argument.
1943   |  daddiu TMP0, TMP0, -LJ_TISNUM      // Integer.
1944   |  li TMP1, 255
1945   |   sextw CARG1, CARG1
1946   |  or AT, AT, TMP0
1947   |   sltu TMP1, TMP1, CARG1            // !(255 < n).
1948   |   or AT, AT, TMP1
1949   |  bnez AT, ->fff_fallback
1950   |.  li CARG3, 1
1951   |  daddiu CARG2, sp, TMPD_OFS
1952   |  sb CARG1, TMPD
1953   |->fff_newstr:
1954   |  load_got lj_str_new
1955   |   sd BASE, L->base
1956   |   sd PC, SAVE_PC
1957   |  call_intern lj_str_new             // (lua_State *L, char *str, size_t l)
1958   |.  move CARG1, L
1959   |  // Returns GCstr *.
1960   |  ld BASE, L->base
1961   |->fff_resstr:
1962   |  li AT, LJ_TSTR
1963   |  settp CRET1, AT
1964   |  b ->fff_restv
1965   |.  move CARG1, CRET1
1966   |
1967   |.ffunc string_sub
1968   |  ffgccheck
1969   |.if not MIPSR6
1970   |.  nop
1971   |.endif
1972   |  addiu AT, NARGS8:RC, -16
1973   |  ld TMP0, 0(BASE)
1974   |  bltz AT, ->fff_fallback
1975   |.  gettp TMP3, TMP0
1976   |  cleartp STR:CARG1, TMP0
1977   |  ld CARG2, 8(BASE)
1978   |  beqz AT, >1
1979   |.  li CARG4, -1
1980   |  ld CARG3, 16(BASE)
1981   |  checkint CARG3, ->fff_fallback
1982   |.  sextw CARG4, CARG3
1983   |1:
1984   |  checkint CARG2, ->fff_fallback
1985   |.  li AT, LJ_TSTR
1986   |  bne TMP3, AT, ->fff_fallback
1987   |.  sextw CARG3, CARG2
1988   |  lw CARG2, STR:CARG1->len
1989   |  // STR:CARG1 = str, CARG2 = str->len, CARG3 = start, CARG4 = end
1990   |  slt AT, CARG4, r0
1991   |  addiu TMP0, CARG2, 1
1992   |  addu TMP1, CARG4, TMP0
1993   |   slt TMP3, CARG3, r0
1994   |.if MIPSR6
1995   |  seleqz CARG4, CARG4, AT
1996   |  selnez TMP1, TMP1, AT
1997   |  or CARG4, TMP1, CARG4              // if (end < 0) end += len+1
1998   |.else
1999   |  movn CARG4, TMP1, AT               // if (end < 0) end += len+1
2000   |.endif
2001   |   addu TMP1, CARG3, TMP0
2002   |.if MIPSR6
2003   |   selnez TMP1, TMP1, TMP3
2004   |   seleqz CARG3, CARG3, TMP3
2005   |   or CARG3, TMP1, CARG3             // if (start < 0) start += len+1
2006   |   li TMP2, 1
2007   |  slt AT, CARG4, r0
2008   |   slt TMP3, r0, CARG3
2009   |  seleqz CARG4, CARG4, AT            // if (end < 0) end = 0
2010   |   selnez CARG3, CARG3, TMP3
2011   |   seleqz TMP2, TMP2, TMP3
2012   |   or CARG3, TMP2, CARG3             // if (start < 1) start = 1
2013   |  slt AT, CARG2, CARG4
2014   |  seleqz CARG4, CARG4, AT
2015   |  selnez CARG2, CARG2, AT
2016   |  or CARG4, CARG2, CARG4             // if (end > len) end = len
2017   |.else
2018   |   movn CARG3, TMP1, TMP3            // if (start < 0) start += len+1
2019   |   li TMP2, 1
2020   |  slt AT, CARG4, r0
2021   |   slt TMP3, r0, CARG3
2022   |  movn CARG4, r0, AT                 // if (end < 0) end = 0
2023   |   movz CARG3, TMP2, TMP3            // if (start < 1) start = 1
2024   |  slt AT, CARG2, CARG4
2025   |  movn CARG4, CARG2, AT              // if (end > len) end = len
2026   |.endif
2027   |   daddu CARG2, STR:CARG1, CARG3
2028   |  subu CARG3, CARG4, CARG3           // len = end - start
2029   |   daddiu CARG2, CARG2, sizeof(GCstr)-1
2030   |  bgez CARG3, ->fff_newstr
2031   |.  addiu CARG3, CARG3, 1             // len++
2032   |->fff_emptystr:  // Return empty string.
2033   |  li AT, LJ_TSTR
2034   |  daddiu STR:CARG1, DISPATCH, DISPATCH_GL(strempty)
2035   |  b ->fff_restv
2036   |.  settp CARG1, AT
2037   |
2038   |.macro ffstring_op, name
2039   |  .ffunc string_ .. name
2040   |  ffgccheck
2041   |.  nop
2042   |  beqz NARGS8:RC, ->fff_fallback
2043   |.  ld CARG2, 0(BASE)
2044   |  checkstr STR:CARG2, ->fff_fallback
2045   |  daddiu SBUF:CARG1, DISPATCH, DISPATCH_GL(tmpbuf)
2046   |  load_got lj_buf_putstr_ .. name
2047   |  ld TMP0, SBUF:CARG1->b
2048   |   sd L, SBUF:CARG1->L
2049   |   sd BASE, L->base
2050   |  sd TMP0, SBUF:CARG1->w
2051   |  call_intern extern lj_buf_putstr_ .. name
2052   |.  sd PC, SAVE_PC
2053   |  load_got lj_buf_tostr
2054   |  call_intern lj_buf_tostr
2055   |.  move SBUF:CARG1, SBUF:CRET1
2056   |  b ->fff_resstr
2057   |.  ld BASE, L->base
2058   |.endmacro
2059   |
2060   |ffstring_op reverse
2061   |ffstring_op lower
2062   |ffstring_op upper
2063   |
2064   |//-- Bit library --------------------------------------------------------
2065   |
2066   |->vm_tobit_fb:
2067   |  beqz TMP1, ->fff_fallback
2068   |.if FPU
2069   |.  ldc1 FARG1, 0(BASE)
2070   |  add.d FARG1, FARG1, TOBIT
2071   |  mfc1 CRET1, FARG1
2072   |  jr ra
2073   |.  zextw CRET1, CRET1
2074   |.else
2075   |// FP number to bit conversion for soft-float.
2076   |->vm_tobit:
2077   |  dsll TMP0, CARG1, 1
2078   |  li CARG3, 1076
2079   |  dsrl AT, TMP0, 53
2080   |  dsubu CARG3, CARG3, AT
2081   |  sltiu AT, CARG3, 54
2082   |  beqz AT, >1
2083   |.  dextm TMP0, TMP0, 0, 20
2084   |  dinsu TMP0, AT, 21, 21
2085   |  slt AT, CARG1, r0
2086   |  dsrlv CRET1, TMP0, CARG3
2087   |  dsubu TMP0, r0, CRET1
2088   |.if MIPSR6
2089   |  selnez TMP0, TMP0, AT
2090   |  seleqz CRET1, CRET1, AT
2091   |  or CRET1, CRET1, TMP0
2092   |.else
2093   |  movn CRET1, TMP0, AT
2094   |.endif
2095   |  jr ra
2096   |.  zextw CRET1, CRET1
2097   |1:
2098   |  jr ra
2099   |.  move CRET1, r0
2100   |
2101   |// FP number to int conversion with a check for soft-float.
2102   |// Modifies CARG1, CRET1, CRET2, TMP0, AT.
2103   |->vm_tointg:
2104   |.if JIT
2105   |  dsll CRET2, CARG1, 1
2106   |  beqz CRET2, >2
2107   |.  li TMP0, 1076
2108   |  dsrl AT, CRET2, 53
2109   |  dsubu TMP0, TMP0, AT
2110   |  sltiu AT, TMP0, 54
2111   |  beqz AT, >1
2112   |.  dextm CRET2, CRET2, 0, 20
2113   |  dinsu CRET2, AT, 21, 21
2114   |  slt AT, CARG1, r0
2115   |  dsrlv CRET1, CRET2, TMP0
2116   |  dsubu CARG1, r0, CRET1
2117   |.if MIPSR6
2118   |  seleqz CRET1, CRET1, AT
2119   |  selnez CARG1, CARG1, AT
2120   |  or CRET1, CRET1, CARG1
2121   |.else
2122   |  movn CRET1, CARG1, AT
2123   |.endif
2124   |  li CARG1, 64
2125   |  subu TMP0, CARG1, TMP0
2126   |  dsllv CRET2, CRET2, TMP0   // Integer check.
2127   |  sextw AT, CRET1
2128   |  xor AT, CRET1, AT          // Range check.
2129   |.if MIPSR6
2130   |  seleqz AT, AT, CRET2
2131   |  selnez CRET2, CRET2, CRET2
2132   |  jr ra
2133   |.  or CRET2, AT, CRET2
2134   |.else
2135   |  jr ra
2136   |.  movz CRET2, AT, CRET2
2137   |.endif
2138   |1:
2139   |  jr ra
2140   |.  li CRET2, 1
2141   |2:
2142   |  jr ra
2143   |.  move CRET1, r0
2144   |.endif
2145   |.endif
2146   |
2147   |.macro .ffunc_bit, name
2148   |  .ffunc_1 bit_..name
2149   |  gettp TMP0, CARG1
2150   |  beq TMP0, TISNUM, >6
2151   |.  zextw CRET1, CARG1
2152   |  bal ->vm_tobit_fb
2153   |.  sltiu TMP1, TMP0, LJ_TISNUM
2154   |6:
2155   |.endmacro
2156   |
2157   |.macro .ffunc_bit_op, name, bins
2158   |  .ffunc_bit name
2159   |  daddiu TMP2, BASE, 8
2160   |  daddu TMP3, BASE, NARGS8:RC
2161   |1:
2162   |  beq TMP2, TMP3, ->fff_resi
2163   |.  ld CARG1, 0(TMP2)
2164   |  gettp TMP0, CARG1
2165   |.if FPU
2166   |  bne TMP0, TISNUM, >2
2167   |.  daddiu TMP2, TMP2, 8
2168   |  zextw CARG1, CARG1
2169   |  b <1
2170   |.  bins CRET1, CRET1, CARG1
2171   |2:
2172   |   ldc1 FARG1, -8(TMP2)
2173   |  sltiu AT, TMP0, LJ_TISNUM
2174   |  beqz AT, ->fff_fallback
2175   |.  add.d FARG1, FARG1, TOBIT
2176   |  mfc1 CARG1, FARG1
2177   |  zextw CARG1, CARG1
2178   |  b <1
2179   |.  bins CRET1, CRET1, CARG1
2180   |.else
2181   |  beq TMP0, TISNUM, >2
2182   |.  move CRET2, CRET1
2183   |  bal ->vm_tobit_fb
2184   |.  sltiu TMP1, TMP0, LJ_TISNUM
2185   |  move CARG1, CRET2
2186   |2:
2187   |  zextw CARG1, CARG1
2188   |  bins CRET1, CRET1, CARG1
2189   |  b <1
2190   |.  daddiu TMP2, TMP2, 8
2191   |.endif
2192   |.endmacro
2193   |
2194   |.ffunc_bit_op band, and
2195   |.ffunc_bit_op bor, or
2196   |.ffunc_bit_op bxor, xor
2197   |
2198   |.ffunc_bit bswap
2199   |  dsrl TMP0, CRET1, 8
2200   |   dsrl TMP1, CRET1, 24
2201   |  andi TMP2, TMP0, 0xff00
2202   |   dins TMP1, CRET1, 24, 31
2203   |  dins TMP2, TMP0, 16, 23
2204   |  b ->fff_resi
2205   |.  or CRET1, TMP1, TMP2
2206   |
2207   |.ffunc_bit bnot
2208   |  not CRET1, CRET1
2209   |  b ->fff_resi
2210   |.  zextw CRET1, CRET1
2211   |
2212   |.macro .ffunc_bit_sh, name, shins, shmod
2213   |  .ffunc_2 bit_..name
2214   |  gettp TMP0, CARG1
2215   |  beq TMP0, TISNUM, >1
2216   |.  nop
2217   |  bal ->vm_tobit_fb
2218   |.  sltiu TMP1, TMP0, LJ_TISNUM
2219   |  move CARG1, CRET1
2220   |1:
2221   |  gettp TMP0, CARG2
2222   |  bne TMP0, TISNUM, ->fff_fallback
2223   |.  zextw CARG2, CARG2
2224   |  sextw CARG1, CARG1
2225   |.if shmod == 1
2226   |  negu CARG2, CARG2
2227   |.endif
2228   |  shins CRET1, CARG1, CARG2
2229   |  b ->fff_resi
2230   |.  zextw CRET1, CRET1
2231   |.endmacro
2232   |
2233   |.ffunc_bit_sh lshift, sllv, 0
2234   |.ffunc_bit_sh rshift, srlv, 0
2235   |.ffunc_bit_sh arshift, srav, 0
2236   |.ffunc_bit_sh rol, rotrv, 1
2237   |.ffunc_bit_sh ror, rotrv, 0
2238   |
2239   |.ffunc_bit tobit
2240   |->fff_resi:
2241   |  ld PC, FRAME_PC(BASE)
2242   |  daddiu RA, BASE, -16
2243   |  settp CRET1, TISNUM
2244   |  b ->fff_res1
2245   |.  sd CRET1, -16(BASE)
2246   |
2247   |//-----------------------------------------------------------------------
2248   |->fff_fallback:                      // Call fast function fallback handler.
2249   |  // BASE = new base, RB = CFUNC, RC = nargs*8
2250   |  ld TMP3, CFUNC:RB->f
2251   |    daddu TMP1, BASE, NARGS8:RC
2252   |   ld PC, FRAME_PC(BASE)             // Fallback may overwrite PC.
2253   |    daddiu TMP0, TMP1, 8*LUA_MINSTACK
2254   |     ld TMP2, L->maxstack
2255   |   sd PC, SAVE_PC                    // Redundant (but a defined value).
2256   |  sltu AT, TMP2, TMP0
2257   |     sd BASE, L->base
2258   |    sd TMP1, L->top
2259   |  bnez AT, >5                        // Need to grow stack.
2260   |.  move CFUNCADDR, TMP3
2261   |  jalr TMP3                          // (lua_State *L)
2262   |.  move CARG1, L
2263   |  // Either throws an error, or recovers and returns -1, 0 or nresults+1.
2264   |  ld BASE, L->base
2265   |   sll RD, CRET1, 3
2266   |  bgtz CRET1, ->fff_res              // Returned nresults+1?
2267   |.  daddiu RA, BASE, -16
2268   |1:  // Returned 0 or -1: retry fast path.
2269   |   ld LFUNC:RB, FRAME_FUNC(BASE)
2270   |  ld TMP0, L->top
2271   |   cleartp LFUNC:RB
2272   |  bnez CRET1, ->vm_call_tail         // Returned -1?
2273   |.  dsubu NARGS8:RC, TMP0, BASE
2274   |  ins_callt                          // Returned 0: retry fast path.
2275   |
2276   |// Reconstruct previous base for vmeta_call during tailcall.
2277   |->vm_call_tail:
2278   |  andi TMP0, PC, FRAME_TYPE
2279   |   li AT, -4
2280   |  bnez TMP0, >3
2281   |.  and TMP1, PC, AT
2282   |  lbu TMP1, OFS_RA(PC)
2283   |  sll TMP1, TMP1, 3
2284   |  addiu TMP1, TMP1, 16
2285   |3:
2286   |  b ->vm_call_dispatch               // Resolve again for tailcall.
2287   |.  dsubu TMP2, BASE, TMP1
2288   |
2289   |5:  // Grow stack for fallback handler.
2290   |  load_got lj_state_growstack
2291   |  li CARG2, LUA_MINSTACK
2292   |  call_intern lj_state_growstack     // (lua_State *L, int n)
2293   |.  move CARG1, L
2294   |  ld BASE, L->base
2295   |  b <1
2296   |.  li CRET1, 0                       // Force retry.
2297   |
2298   |->fff_gcstep:                        // Call GC step function.
2299   |  // BASE = new base, RC = nargs*8
2300   |  move MULTRES, ra
2301   |  load_got lj_gc_step
2302   |   sd BASE, L->base
2303   |  daddu TMP0, BASE, NARGS8:RC
2304   |   sd PC, SAVE_PC                    // Redundant (but a defined value).
2305   |  sd TMP0, L->top
2306   |  call_intern lj_gc_step             // (lua_State *L)
2307   |.  move CARG1, L
2308   |   ld BASE, L->base
2309   |  move ra, MULTRES
2310   |    ld TMP0, L->top
2311   |  ld CFUNC:RB, FRAME_FUNC(BASE)
2312   |  cleartp CFUNC:RB
2313   |  jr ra
2314   |.  dsubu NARGS8:RC, TMP0, BASE
2315   |
2316   |//-----------------------------------------------------------------------
2317   |//-- Special dispatch targets -------------------------------------------
2318   |//-----------------------------------------------------------------------
2319   |
2320   |->vm_record:                         // Dispatch target for recording phase.
2321   |.if JIT
2322   |  lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
2323   |  andi AT, TMP3, HOOK_VMEVENT        // No recording while in vmevent.
2324   |  bnez AT, >5
2325   |  // Decrement the hookcount for consistency, but always do the call.
2326   |.  lw TMP2, DISPATCH_GL(hookcount)(DISPATCH)
2327   |  andi AT, TMP3, HOOK_ACTIVE
2328   |  bnez AT, >1
2329   |.  addiu TMP2, TMP2, -1
2330   |  andi AT, TMP3, LUA_MASKLINE|LUA_MASKCOUNT
2331   |  beqz AT, >1
2332   |.  nop
2333   |  b >1
2334   |.  sw TMP2, DISPATCH_GL(hookcount)(DISPATCH)
2335   |.endif
2336   |
2337   |->vm_rethook:                        // Dispatch target for return hooks.
2338   |  lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
2339   |  andi AT, TMP3, HOOK_ACTIVE         // Hook already active?
2340   |  beqz AT, >1
2341   |5:  // Re-dispatch to static ins.
2342   |.  ld AT, GG_DISP2STATIC(TMP0)       // Assumes TMP0 holds DISPATCH+OP*4.
2343   |  jr AT
2344   |.  nop
2345   |
2346   |->vm_inshook:                        // Dispatch target for instr/line hooks.
2347   |  lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
2348   |  lw TMP2, DISPATCH_GL(hookcount)(DISPATCH)
2349   |  andi AT, TMP3, HOOK_ACTIVE         // Hook already active?
2350   |  bnez AT, <5
2351   |.  andi AT, TMP3, LUA_MASKLINE|LUA_MASKCOUNT
2352   |  beqz AT, <5
2353   |.  addiu TMP2, TMP2, -1
2354   |  beqz TMP2, >1
2355   |.  sw TMP2, DISPATCH_GL(hookcount)(DISPATCH)
2356   |  andi AT, TMP3, LUA_MASKLINE
2357   |  beqz AT, <5
2358   |1:
2359   |.  load_got lj_dispatch_ins
2360   |   sw MULTRES, SAVE_MULTRES
2361   |  move CARG2, PC
2362   |   sd BASE, L->base
2363   |  // SAVE_PC must hold the _previous_ PC. The callee updates it with PC.
2364   |  call_intern lj_dispatch_ins        // (lua_State *L, const BCIns *pc)
2365   |.  move CARG1, L
2366   |3:
2367   |  ld BASE, L->base
2368   |4:  // Re-dispatch to static ins.
2369   |  lw INS, -4(PC)
2370   |  decode_OP8a TMP1, INS
2371   |  decode_OP8b TMP1
2372   |  daddu TMP0, DISPATCH, TMP1
2373   |   decode_RD8a RD, INS
2374   |  ld AT, GG_DISP2STATIC(TMP0)
2375   |   decode_RA8a RA, INS
2376   |   decode_RD8b RD
2377   |  jr AT
2378   |   decode_RA8b RA
2379   |
2380   |->cont_hook:                         // Continue from hook yield.
2381   |  daddiu PC, PC, 4
2382   |  b <4
2383   |.  lw MULTRES, -24+LO(RB)            // Restore MULTRES for *M ins.
2384   |
2385   |->vm_hotloop:                        // Hot loop counter underflow.
2386   |.if JIT
2387   |  ld LFUNC:TMP1, FRAME_FUNC(BASE)
2388   |   daddiu CARG1, DISPATCH, GG_DISP2J
2389   |  cleartp LFUNC:TMP1
2390   |   sd PC, SAVE_PC
2391   |  ld TMP1, LFUNC:TMP1->pc
2392   |   move CARG2, PC
2393   |   sd L, DISPATCH_J(L)(DISPATCH)
2394   |  lbu TMP1, PC2PROTO(framesize)(TMP1)
2395   |  load_got lj_trace_hot
2396   |   sd BASE, L->base
2397   |  dsll TMP1, TMP1, 3
2398   |  daddu TMP1, BASE, TMP1
2399   |  call_intern lj_trace_hot           // (jit_State *J, const BCIns *pc)
2400   |.  sd TMP1, L->top
2401   |  b <3
2402   |.  nop
2403   |.endif
2404   |
2405   |
2406   |->vm_callhook:                       // Dispatch target for call hooks.
2407   |.if JIT
2408   |  b >1
2409   |.endif
2410   |.  move CARG2, PC
2411   |
2412   |->vm_hotcall:                        // Hot call counter underflow.
2413   |.if JIT
2414   |  ori CARG2, PC, 1
2415   |1:
2416   |.endif
2417   |  load_got lj_dispatch_call
2418   |  daddu TMP0, BASE, RC
2419   |   sd PC, SAVE_PC
2420   |   sd BASE, L->base
2421   |  dsubu RA, RA, BASE
2422   |   sd TMP0, L->top
2423   |  call_intern lj_dispatch_call       // (lua_State *L, const BCIns *pc)
2424   |.  move CARG1, L
2425   |  // Returns ASMFunction.
2426   |  ld BASE, L->base
2427   |   ld TMP0, L->top
2428   |   sd r0, SAVE_PC                    // Invalidate for subsequent line hook.
2429   |  dsubu NARGS8:RC, TMP0, BASE
2430   |  daddu RA, BASE, RA
2431   |  ld LFUNC:RB, FRAME_FUNC(BASE)
2432   |  cleartp LFUNC:RB
2433   |  jr CRET1
2434   |.  lw INS, -4(PC)
2435   |
2436   |->cont_stitch:                       // Trace stitching.
2437   |.if JIT
2438   |  // RA = resultptr, RB = meta base
2439   |  lw INS, -4(PC)
2440   |    ld TRACE:TMP2, -40(RB)           // Save previous trace.
2441   |  decode_RA8a RC, INS
2442   |   daddiu AT, MULTRES, -8
2443   |    cleartp TRACE:TMP2
2444   |  decode_RA8b RC
2445   |   beqz AT, >2
2446   |. daddu RC, BASE, RC                 // Call base.
2447   |1:  // Move results down.
2448   |  ld CARG1, 0(RA)
2449   |   daddiu AT, AT, -8
2450   |    daddiu RA, RA, 8
2451   |  sd CARG1, 0(RC)
2452   |   bnez AT, <1
2453   |.   daddiu RC, RC, 8
2454   |2:
2455   |   decode_RA8a RA, INS
2456   |    decode_RB8a RB, INS
2457   |   decode_RA8b RA
2458   |    decode_RB8b RB
2459   |   daddu RA, RA, RB
2460   |   daddu RA, BASE, RA
2461   |3:
2462   |   sltu AT, RC, RA
2463   |   bnez AT, >9                       // More results wanted?
2464   |.   nop
2465   |
2466   |  lhu TMP3, TRACE:TMP2->traceno
2467   |  lhu RD, TRACE:TMP2->link
2468   |  beq RD, TMP3, ->cont_nop           // Blacklisted.
2469   |.  load_got lj_dispatch_stitch
2470   |  bnez RD, =>BC_JLOOP                // Jump to stitched trace.
2471   |.  sll RD, RD, 3
2472   |
2473   |  // Stitch a new trace to the previous trace.
2474   |  sw TMP3, DISPATCH_J(exitno)(DISPATCH)
2475   |  sd L, DISPATCH_J(L)(DISPATCH)
2476   |  sd BASE, L->base
2477   |  daddiu CARG1, DISPATCH, GG_DISP2J
2478   |  call_intern lj_dispatch_stitch     // (jit_State *J, const BCIns *pc)
2479   |.  move CARG2, PC
2480   |  b ->cont_nop
2481   |.  ld BASE, L->base
2482   |
2483   |9:
2484   |  sd TISNIL, 0(RC)
2485   |  b <3
2486   |.  daddiu RC, RC, 8
2487   |.endif
2488   |
2489   |->vm_profhook:                       // Dispatch target for profiler hook.
2490 #if LJ_HASPROFILE
2491   |  load_got lj_dispatch_profile
2492   |   sw MULTRES, SAVE_MULTRES
2493   |  move CARG2, PC
2494   |   sd BASE, L->base
2495   |  call_intern lj_dispatch_profile    // (lua_State *L, const BCIns *pc)
2496   |.  move CARG1, L
2497   |  // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction.
2498   |  daddiu PC, PC, -4
2499   |  b ->cont_nop
2500   |.  ld BASE, L->base
2501 #endif
2502   |
2503   |//-----------------------------------------------------------------------
2504   |//-- Trace exit handler -------------------------------------------------
2505   |//-----------------------------------------------------------------------
2506   |
2507   |.macro savex_, a, b
2508   |.if FPU
2509   |  sdc1 f..a, a*8(sp)
2510   |  sdc1 f..b, b*8(sp)
2511   |  sd r..a, 32*8+a*8(sp)
2512   |  sd r..b, 32*8+b*8(sp)
2513   |.else
2514   |  sd r..a, a*8(sp)
2515   |  sd r..b, b*8(sp)
2516   |.endif
2517   |.endmacro
2518   |
2519   |->vm_exit_handler:
2520   |.if JIT
2521   |.if FPU
2522   |  daddiu sp, sp, -(32*8+32*8)
2523   |.else
2524   |  daddiu sp, sp, -(32*8)
2525   |.endif
2526   |  savex_ 0, 1
2527   |  savex_ 2, 3
2528   |  savex_ 4, 5
2529   |  savex_ 6, 7
2530   |  savex_ 8, 9
2531   |  savex_ 10, 11
2532   |  savex_ 12, 13
2533   |  savex_ 14, 15
2534   |  savex_ 16, 17
2535   |  savex_ 18, 19
2536   |  savex_ 20, 21
2537   |  savex_ 22, 23
2538   |  savex_ 24, 25
2539   |  savex_ 26, 27
2540   |  savex_ 28, 30
2541   |.if FPU
2542   |  sdc1 f29, 29*8(sp)
2543   |  sdc1 f31, 31*8(sp)
2544   |  sd r0, 32*8+31*8(sp)               // Clear RID_TMP.
2545   |  daddiu TMP2, sp, 32*8+32*8         // Recompute original value of sp.
2546   |  sd TMP2, 32*8+29*8(sp)             // Store sp in RID_SP
2547   |.else
2548   |  sd r0, 31*8(sp)                    // Clear RID_TMP.
2549   |  daddiu TMP2, sp, 32*8              // Recompute original value of sp.
2550   |  sd TMP2, 29*8(sp)                  // Store sp in RID_SP
2551   |.endif
2552   |  li_vmstate EXIT
2553   |  daddiu DISPATCH, JGL, -GG_DISP2G-32768
2554   |  lw TMP1, 0(TMP2)                   // Load exit number.
2555   |  st_vmstate
2556   |  ld L, DISPATCH_GL(cur_L)(DISPATCH)
2557   |   ld BASE, DISPATCH_GL(jit_base)(DISPATCH)
2558   |  load_got lj_trace_exit
2559   |  sd L, DISPATCH_J(L)(DISPATCH)
2560   |  sw ra, DISPATCH_J(parent)(DISPATCH)  // Store trace number.
2561   |   sd BASE, L->base
2562   |  sw TMP1, DISPATCH_J(exitno)(DISPATCH)  // Store exit number.
2563   |  daddiu CARG1, DISPATCH, GG_DISP2J
2564   |   sd r0, DISPATCH_GL(jit_base)(DISPATCH)
2565   |  call_intern lj_trace_exit          // (jit_State *J, ExitState *ex)
2566   |.  move CARG2, sp
2567   |  // Returns MULTRES (unscaled) or negated error code.
2568   |  ld TMP1, L->cframe
2569   |  li AT, -4
2570   |   ld BASE, L->base
2571   |  and sp, TMP1, AT
2572   |   ld PC, SAVE_PC                    // Get SAVE_PC.
2573   |  b >1
2574   |.  sd L, SAVE_L                      // Set SAVE_L (on-trace resume/yield).
2575   |.endif
2576   |->vm_exit_interp:
2577   |.if JIT
2578   |  // CRET1 = MULTRES or negated error code, BASE, PC and JGL set.
2579   |  ld L, SAVE_L
2580   |   daddiu DISPATCH, JGL, -GG_DISP2G-32768
2581   |  sd BASE, L->base
2582   |1:
2583   |  sltiu TMP0, CRET1, -LUA_ERRERR     // Check for error from exit.
2584   |  beqz TMP0, >9
2585   |.  ld LFUNC:RB, FRAME_FUNC(BASE)
2586   |    .FPU lui TMP3, 0x59c0            // TOBIT = 2^52 + 2^51 (float).
2587   |  dsll MULTRES, CRET1, 3
2588   |  cleartp LFUNC:RB
2589   |  sw MULTRES, SAVE_MULTRES
2590   |    li TISNIL, LJ_TNIL
2591   |     li TISNUM, LJ_TISNUM            // Setup type comparison constants.
2592   |    .FPU mtc1 TMP3, TOBIT
2593   |  ld TMP1, LFUNC:RB->pc
2594   |   sd r0, DISPATCH_GL(jit_base)(DISPATCH)
2595   |  ld KBASE, PC2PROTO(k)(TMP1)
2596   |    .FPU cvt.d.s TOBIT, TOBIT
2597   |  // Modified copy of ins_next which handles function header dispatch, too.
2598   |  lw INS, 0(PC)
2599   |  addiu CRET1, CRET1, 17             // Static dispatch?
2600   |    // Assumes TISNIL == ~LJ_VMST_INTERP == -1
2601   |    sw TISNIL, DISPATCH_GL(vmstate)(DISPATCH)
2602   |   decode_RD8a RD, INS
2603   |  beqz CRET1, >5
2604   |.  daddiu PC, PC, 4
2605   |  decode_OP8a TMP1, INS
2606   |  decode_OP8b TMP1
2607   |  daddu TMP0, DISPATCH, TMP1
2608   |    sltiu TMP2, TMP1, BC_FUNCF*8
2609   |  ld AT, 0(TMP0)
2610   |   decode_RA8a RA, INS
2611   |    beqz TMP2, >2
2612   |.  decode_RA8b RA
2613   |  jr AT
2614   |.  decode_RD8b RD
2615   |2:
2616   |  sltiu TMP2, TMP1, (BC_FUNCC+2)*8   // Fast function?
2617   |  bnez TMP2, >3
2618   |.  ld TMP1, FRAME_PC(BASE)
2619   |  // Check frame below fast function.
2620   |  andi TMP0, TMP1, FRAME_TYPE
2621   |  bnez TMP0, >3                      // Trace stitching continuation?
2622   |.  nop
2623   |  // Otherwise set KBASE for Lua function below fast function.
2624   |  lw TMP2, -4(TMP1)
2625   |  decode_RA8a TMP0, TMP2
2626   |  decode_RA8b TMP0
2627   |  dsubu TMP1, BASE, TMP0
2628   |  ld LFUNC:TMP2, -32(TMP1)
2629   |  cleartp LFUNC:TMP2
2630   |  ld TMP1, LFUNC:TMP2->pc
2631   |  ld KBASE, PC2PROTO(k)(TMP1)
2632   |3:
2633   |  daddiu RC, MULTRES, -8
2634   |  jr AT
2635   |.  daddu RA, RA, BASE
2636   |
2637   |5:  // Dispatch to static entry of original ins replaced by BC_JLOOP.
2638   |  ld TMP0, DISPATCH_J(trace)(DISPATCH)
2639   |  decode_RD8b RD
2640   |  daddu TMP0, TMP0, RD
2641   |  ld TRACE:TMP2, 0(TMP0)
2642   |  lw INS, TRACE:TMP2->startins
2643   |  decode_OP8a TMP1, INS
2644   |  decode_OP8b TMP1
2645   |  daddu TMP0, DISPATCH, TMP1
2646   |   decode_RD8a RD, INS
2647   |  ld AT, GG_DISP2STATIC(TMP0)
2648   |   decode_RA8a RA, INS
2649   |   decode_RD8b RD
2650   |  jr AT
2651   |.  decode_RA8b RA
2652   |
2653   |9:  // Rethrow error from the right C frame.
2654   |  load_got lj_err_trace
2655   |  sub CARG2, r0, CRET1
2656   |  call_intern lj_err_trace           // (lua_State *L, int errcode)
2657   |.  move CARG1, L
2658   |.endif
2659   |
2660   |//-----------------------------------------------------------------------
2661   |//-- Math helper functions ----------------------------------------------
2662   |//-----------------------------------------------------------------------
2663   |
2664   |// Hard-float round to integer.
2665   |// Modifies AT, TMP0, FRET1, FRET2, f4. Keeps all others incl. FARG1.
2666   |// MIPSR6: Modifies FTMP1, too.
2667   |.macro vm_round_hf, func
2668   |  lui TMP0, 0x4330                   // Hiword of 2^52 (double).
2669   |  dsll TMP0, TMP0, 32
2670   |  dmtc1 TMP0, f4
2671   |  abs.d FRET2, FARG1                 // |x|
2672   |    dmfc1 AT, FARG1
2673   |.if MIPSR6
2674   |  cmp.lt.d FTMP1, FRET2, f4
2675   |   add.d FRET1, FRET2, f4            // (|x| + 2^52) - 2^52
2676   |  bc1eqz FTMP1, >1                   // Truncate only if |x| < 2^52.
2677   |.else
2678   |  c.olt.d 0, FRET2, f4
2679   |   add.d FRET1, FRET2, f4            // (|x| + 2^52) - 2^52
2680   |  bc1f 0, >1                         // Truncate only if |x| < 2^52.
2681   |.endif
2682   |.  sub.d FRET1, FRET1, f4
2683   |    slt AT, AT, r0
2684   |.if "func" == "ceil"
2685   |   lui TMP0, 0xbff0                  // Hiword of -1 (double). Preserves -0.
2686   |.else
2687   |   lui TMP0, 0x3ff0                  // Hiword of +1 (double).
2688   |.endif
2689   |.if "func" == "trunc"
2690   |   dsll TMP0, TMP0, 32
2691   |   dmtc1 TMP0, f4
2692   |.if MIPSR6
2693   |  cmp.lt.d FTMP1, FRET2, FRET1       // |x| < result?
2694   |   sub.d FRET2, FRET1, f4
2695   |  sel.d  FTMP1, FRET1, FRET2         // If yes, subtract +1.
2696   |  dmtc1 AT, FRET1
2697   |  neg.d FRET2, FTMP1
2698   |  jr ra
2699   |.  sel.d FRET1, FTMP1, FRET2         // Merge sign bit back in.
2700   |.else
2701   |  c.olt.d 0, FRET2, FRET1            // |x| < result?
2702   |   sub.d FRET2, FRET1, f4
2703   |  movt.d FRET1, FRET2, 0             // If yes, subtract +1.
2704   |  neg.d FRET2, FRET1
2705   |  jr ra
2706   |.  movn.d FRET1, FRET2, AT           // Merge sign bit back in.
2707   |.endif
2708   |.else
2709   |  neg.d FRET2, FRET1
2710   |   dsll TMP0, TMP0, 32
2711   |   dmtc1 TMP0, f4
2712   |.if MIPSR6
2713   |  dmtc1 AT, FTMP1
2714   |  sel.d FTMP1, FRET1, FRET2
2715   |.if "func" == "ceil"
2716   |  cmp.lt.d FRET1, FTMP1, FARG1       // x > result?
2717   |.else
2718   |  cmp.lt.d FRET1, FARG1, FTMP1       // x < result?
2719   |.endif
2720   |   sub.d FRET2, FTMP1, f4            // If yes, subtract +-1.
2721   |  jr ra
2722   |.  sel.d FRET1, FTMP1, FRET2
2723   |.else
2724   |  movn.d FRET1, FRET2, AT            // Merge sign bit back in.
2725   |.if "func" == "ceil"
2726   |  c.olt.d 0, FRET1, FARG1            // x > result?
2727   |.else
2728   |  c.olt.d 0, FARG1, FRET1            // x < result?
2729   |.endif
2730   |   sub.d FRET2, FRET1, f4            // If yes, subtract +-1.
2731   |  jr ra
2732   |.  movt.d FRET1, FRET2, 0
2733   |.endif
2734   |.endif
2735   |1:
2736   |  jr ra
2737   |.  mov.d FRET1, FARG1
2738   |.endmacro
2739   |
2740   |.macro vm_round, func
2741   |.if FPU
2742   |  vm_round_hf, func
2743   |.endif
2744   |.endmacro
2745   |
2746   |->vm_floor:
2747   |  vm_round floor
2748   |->vm_ceil:
2749   |  vm_round ceil
2750   |->vm_trunc:
2751   |.if JIT
2752   |  vm_round trunc
2753   |.endif
2754   |
2755   |// Soft-float integer to number conversion.
2756   |.macro sfi2d, ARG
2757   |.if not FPU
2758   |  beqz ARG, >9                       // Handle zero first.
2759   |.  sra TMP0, ARG, 31
2760   |  xor TMP1, ARG, TMP0
2761   |  dsubu TMP1, TMP1, TMP0             // Absolute value in TMP1.
2762   |  dclz ARG, TMP1
2763   |  addiu ARG, ARG, -11
2764   |  li AT, 0x3ff+63-11-1
2765   |   dsllv TMP1, TMP1, ARG             // Align mantissa left with leading 1.
2766   |  subu ARG, AT, ARG                  // Exponent - 1.
2767   |  ins ARG, TMP0, 11, 11              // Sign | Exponent.
2768   |  dsll ARG, ARG, 52                  // Align left.
2769   |  jr ra
2770   |.  daddu ARG, ARG, TMP1              // Add mantissa, increment exponent.
2771   |9:
2772   |  jr ra
2773   |.  nop
2774   |.endif
2775   |.endmacro
2776   |
2777   |// Input CARG1. Output: CARG1. Temporaries: AT, TMP0, TMP1.
2778   |->vm_sfi2d_1:
2779   |  sfi2d CARG1
2780   |
2781   |// Input CARG2. Output: CARG2. Temporaries: AT, TMP0, TMP1.
2782   |->vm_sfi2d_2:
2783   |  sfi2d CARG2
2784   |
2785   |// Soft-float comparison. Equivalent to c.eq.d.
2786   |// Input: CARG*. Output: CRET1. Temporaries: AT, TMP0, TMP1.
2787   |->vm_sfcmpeq:
2788   |.if not FPU
2789   |  dsll AT, CARG1, 1
2790   |  dsll TMP0, CARG2, 1
2791   |  or TMP1, AT, TMP0
2792   |  beqz TMP1, >8                      // Both args +-0: return 1.
2793   |.  lui TMP1, 0xffe0
2794   |  dsll TMP1, TMP1, 32
2795   |   sltu AT, TMP1, AT
2796   |   sltu TMP0, TMP1, TMP0
2797   |  or TMP1, AT, TMP0
2798   |  bnez TMP1, >9                      // Either arg is NaN: return 0;
2799   |.  xor AT, CARG1, CARG2
2800   |  jr ra
2801   |.  sltiu CRET1, AT, 1                // Same values: return 1.
2802   |8:
2803   |  jr ra
2804   |.  li CRET1, 1
2805   |9:
2806   |  jr ra
2807   |.  li CRET1, 0
2808   |.endif
2809   |
2810   |// Soft-float comparison. Equivalent to c.ult.d and c.olt.d.
2811   |// Input: CARG1, CARG2. Output: CRET1. Temporaries: AT, TMP0, TMP1, CRET2.
2812   |->vm_sfcmpult:
2813   |.if not FPU
2814   |  b >1
2815   |.  li CRET2, 1
2816   |.endif
2817   |
2818   |->vm_sfcmpolt:
2819   |.if not FPU
2820   |  li CRET2, 0
2821   |1:
2822   |  dsll AT, CARG1, 1
2823   |  dsll TMP0, CARG2, 1
2824   |  or TMP1, AT, TMP0
2825   |  beqz TMP1, >8                      // Both args +-0: return 0.
2826   |.  lui TMP1, 0xffe0
2827   |  dsll TMP1, TMP1, 32
2828   |   sltu AT, TMP1, AT
2829   |   sltu TMP0, TMP1, TMP0
2830   |  or TMP1, AT, TMP0
2831   |  bnez TMP1, >9                      // Either arg is NaN: return 0 or 1;
2832   |.  and AT, CARG1, CARG2
2833   |  bltz AT, >5                        // Both args negative?
2834   |.  nop
2835   |  jr ra
2836   |.  slt CRET1, CARG1, CARG2
2837   |5:  // Swap conditions if both operands are negative.
2838   |  jr ra
2839   |.  slt CRET1, CARG2, CARG1
2840   |8:
2841   |  jr ra
2842   |.  li CRET1, 0
2843   |9:
2844   |  jr ra
2845   |.  move CRET1, CRET2
2846   |.endif
2847   |
2848   |->vm_sfcmpogt:
2849   |.if not FPU
2850   |  dsll AT, CARG2, 1
2851   |  dsll TMP0, CARG1, 1
2852   |  or TMP1, AT, TMP0
2853   |  beqz TMP1, >8                      // Both args +-0: return 0.
2854   |.  lui TMP1, 0xffe0
2855   |  dsll TMP1, TMP1, 32
2856   |   sltu AT, TMP1, AT
2857   |   sltu TMP0, TMP1, TMP0
2858   |  or TMP1, AT, TMP0
2859   |  bnez TMP1, >9                      // Either arg is NaN: return 0 or 1;
2860   |.  and AT, CARG2, CARG1
2861   |  bltz AT, >5                        // Both args negative?
2862   |.  nop
2863   |  jr ra
2864   |.  slt CRET1, CARG2, CARG1
2865   |5:  // Swap conditions if both operands are negative.
2866   |  jr ra
2867   |.  slt CRET1, CARG1, CARG2
2868   |8:
2869   |  jr ra
2870   |.  li CRET1, 0
2871   |9:
2872   |  jr ra
2873   |.  li CRET1, 0
2874   |.endif
2875   |
2876   |// Soft-float comparison. Equivalent to c.ole.d a, b or c.ole.d b, a.
2877   |// Input: CARG1, CARG2, TMP3. Output: CRET1. Temporaries: AT, TMP0, TMP1.
2878   |->vm_sfcmpolex:
2879   |.if not FPU
2880   |  dsll AT, CARG1, 1
2881   |  dsll TMP0, CARG2, 1
2882   |  or TMP1, AT, TMP0
2883   |  beqz TMP1, >8                      // Both args +-0: return 1.
2884   |.  lui TMP1, 0xffe0
2885   |  dsll TMP1, TMP1, 32
2886   |   sltu AT, TMP1, AT
2887   |   sltu TMP0, TMP1, TMP0
2888   |  or TMP1, AT, TMP0
2889   |  bnez TMP1, >9                      // Either arg is NaN: return 0;
2890   |.  and AT, CARG1, CARG2
2891   |  xor AT, AT, TMP3
2892   |  bltz AT, >5                        // Both args negative?
2893   |.  nop
2894   |  jr ra
2895   |.  slt CRET1, CARG2, CARG1
2896   |5:  // Swap conditions if both operands are negative.
2897   |  jr ra
2898   |.  slt CRET1, CARG1, CARG2
2899   |8:
2900   |  jr ra
2901   |.  li CRET1, 1
2902   |9:
2903   |  jr ra
2904   |.  li CRET1, 0
2905   |.endif
2906   |
2907   |.macro sfmin_max, name, fpcall
2908   |->vm_sf .. name:
2909   |.if JIT and not FPU
2910   |  move TMP2, ra
2911   |  bal ->fpcall
2912   |.  nop
2913   |  move ra, TMP2
2914   |  move TMP0, CRET1
2915   |  move CRET1, CARG1
2916   |.if MIPSR6
2917   |  selnez CRET1, CRET1, TMP0
2918   |  seleqz TMP0, CARG2, TMP0
2919   |  jr ra
2920   |.  or CRET1, CRET1, TMP0
2921   |.else
2922   |  jr ra
2923   |.  movz CRET1, CARG2, TMP0
2924   |.endif
2925   |.endif
2926   |.endmacro
2927   |
2928   |  sfmin_max min, vm_sfcmpolt
2929   |  sfmin_max max, vm_sfcmpogt
2930   |
2931   |//-----------------------------------------------------------------------
2932   |//-- Miscellaneous functions --------------------------------------------
2933   |//-----------------------------------------------------------------------
2934   |
2935   |.define NEXT_TAB,            TAB:CARG1
2936   |.define NEXT_IDX,            CARG2
2937   |.define NEXT_ASIZE,          CARG3
2938   |.define NEXT_NIL,            CARG4
2939   |.define NEXT_TMP0,           r12
2940   |.define NEXT_TMP1,           r13
2941   |.define NEXT_TMP2,           r14
2942   |.define NEXT_RES_VK,         CRET1
2943   |.define NEXT_RES_IDX,        CRET2
2944   |.define NEXT_RES_PTR,        sp
2945   |.define NEXT_RES_VAL,        0(sp)
2946   |.define NEXT_RES_KEY,        8(sp)
2947   |
2948   |// TValue *lj_vm_next(GCtab *t, uint32_t idx)
2949   |// Next idx returned in CRET2.
2950   |->vm_next:
2951   |.if JIT and ENDIAN_LE
2952   |   lw NEXT_ASIZE, NEXT_TAB->asize
2953   |  ld NEXT_TMP0, NEXT_TAB->array
2954   |    li NEXT_NIL, LJ_TNIL
2955   |1:  // Traverse array part.
2956   |   sltu AT, NEXT_IDX, NEXT_ASIZE
2957   |    sll NEXT_TMP1, NEXT_IDX, 3
2958   |   beqz AT, >5
2959   |.   daddu NEXT_TMP1, NEXT_TMP0, NEXT_TMP1
2960   |   li AT, LJ_TISNUM
2961   |  ld NEXT_TMP2, 0(NEXT_TMP1)
2962   |   dsll AT, AT, 47
2963   |   or NEXT_TMP1, NEXT_IDX, AT
2964   |  beq NEXT_TMP2, NEXT_NIL, <1
2965   |.  addiu NEXT_IDX, NEXT_IDX, 1
2966   |  sd NEXT_TMP2, NEXT_RES_VAL
2967   |   sd NEXT_TMP1, NEXT_RES_KEY
2968   |  move NEXT_RES_VK, NEXT_RES_PTR
2969   |  jr ra
2970   |.  move NEXT_RES_IDX, NEXT_IDX
2971   |
2972   |5:  // Traverse hash part.
2973   |  subu NEXT_RES_IDX, NEXT_IDX, NEXT_ASIZE
2974   |   ld NODE:NEXT_RES_VK, NEXT_TAB->node
2975   |    sll NEXT_TMP2, NEXT_RES_IDX, 5
2976   |  lw NEXT_TMP0, NEXT_TAB->hmask
2977   |    sll AT, NEXT_RES_IDX, 3
2978   |    subu AT, NEXT_TMP2, AT
2979   |   daddu NODE:NEXT_RES_VK, NODE:NEXT_RES_VK, AT
2980   |6:
2981   |  sltu AT, NEXT_TMP0, NEXT_RES_IDX
2982   |  bnez AT, >8
2983   |.  nop
2984   |  ld NEXT_TMP2, NODE:NEXT_RES_VK->val
2985   |  bne NEXT_TMP2, NEXT_NIL, >9
2986   |.  addiu NEXT_RES_IDX, NEXT_RES_IDX, 1
2987   |  // Skip holes in hash part.
2988   |  b <6
2989   |.  daddiu NODE:NEXT_RES_VK, NODE:NEXT_RES_VK, sizeof(Node)
2990   |
2991   |8:  // End of iteration. Set the key to nil (not the value).
2992   |  sd NEXT_NIL, NEXT_RES_KEY
2993   |  move NEXT_RES_VK, NEXT_RES_PTR
2994   |9:
2995   |  jr ra
2996   |.  addu NEXT_RES_IDX, NEXT_RES_IDX, NEXT_ASIZE
2997   |.endif
2998   |
2999   |//-----------------------------------------------------------------------
3000   |//-- FFI helper functions -----------------------------------------------
3001   |//-----------------------------------------------------------------------
3002   |
3003   |// Handler for callback functions. Callback slot number in r1, g in r2.
3004   |->vm_ffi_callback:
3005   |.if FFI
3006   |.type CTSTATE, CTState, PC
3007   |  saveregs
3008   |  ld CTSTATE, GL:r2->ctype_state
3009   |   daddiu DISPATCH, r2, GG_G2DISP
3010   |  load_got lj_ccallback_enter
3011   |  sw r1, CTSTATE->cb.slot
3012   |  sd CARG1, CTSTATE->cb.gpr[0]
3013   |  .FPU sdc1 FARG1, CTSTATE->cb.fpr[0]
3014   |  sd CARG2, CTSTATE->cb.gpr[1]
3015   |  .FPU sdc1 FARG2, CTSTATE->cb.fpr[1]
3016   |  sd CARG3, CTSTATE->cb.gpr[2]
3017   |  .FPU sdc1 FARG3, CTSTATE->cb.fpr[2]
3018   |  sd CARG4, CTSTATE->cb.gpr[3]
3019   |  .FPU sdc1 FARG4, CTSTATE->cb.fpr[3]
3020   |  sd CARG5, CTSTATE->cb.gpr[4]
3021   |  .FPU sdc1 FARG5, CTSTATE->cb.fpr[4]
3022   |  sd CARG6, CTSTATE->cb.gpr[5]
3023   |  .FPU sdc1 FARG6, CTSTATE->cb.fpr[5]
3024   |  sd CARG7, CTSTATE->cb.gpr[6]
3025   |  .FPU sdc1 FARG7, CTSTATE->cb.fpr[6]
3026   |  sd CARG8, CTSTATE->cb.gpr[7]
3027   |  .FPU sdc1 FARG8, CTSTATE->cb.fpr[7]
3028   |  daddiu TMP0, sp, CFRAME_SPACE
3029   |  sd TMP0, CTSTATE->cb.stack
3030   |  sd r0, SAVE_PC                     // Any value outside of bytecode is ok.
3031   |   move CARG2, sp
3032   |  call_intern lj_ccallback_enter     // (CTState *cts, void *cf)
3033   |.  move CARG1, CTSTATE
3034   |  // Returns lua_State *.
3035   |  ld BASE, L:CRET1->base
3036   |  ld RC, L:CRET1->top
3037   |   move L, CRET1
3038   |     .FPU lui TMP3, 0x59c0           // TOBIT = 2^52 + 2^51 (float).
3039   |  ld LFUNC:RB, FRAME_FUNC(BASE)
3040   |     .FPU mtc1 TMP3, TOBIT
3041   |      li TISNIL, LJ_TNIL
3042   |       li TISNUM, LJ_TISNUM
3043   |    li_vmstate INTERP
3044   |  subu RC, RC, BASE
3045   |   cleartp LFUNC:RB
3046   |    st_vmstate
3047   |     .FPU cvt.d.s TOBIT, TOBIT
3048   |  ins_callt
3049   |.endif
3050   |
3051   |->cont_ffi_callback:                 // Return from FFI callback.
3052   |.if FFI
3053   |  load_got lj_ccallback_leave
3054   |  ld CTSTATE, DISPATCH_GL(ctype_state)(DISPATCH)
3055   |   sd BASE, L->base
3056   |   sd RB, L->top
3057   |  sd L, CTSTATE->L
3058   |  move CARG2, RA
3059   |  call_intern lj_ccallback_leave     // (CTState *cts, TValue *o)
3060   |.  move CARG1, CTSTATE
3061   |  .FPU ldc1 FRET1, CTSTATE->cb.fpr[0]
3062   |  ld CRET1, CTSTATE->cb.gpr[0]
3063   |  .FPU ldc1 FRET2, CTSTATE->cb.fpr[1]
3064   |  b ->vm_leave_unw
3065   |.  ld CRET2, CTSTATE->cb.gpr[1]
3066   |.endif
3067   |
3068   |->vm_ffi_call:                       // Call C function via FFI.
3069   |  // Caveat: needs special frame unwinding, see below.
3070   |.if FFI
3071   |  .type CCSTATE, CCallState, CARG1
3072   |  lw TMP1, CCSTATE->spadj
3073   |   lbu CARG2, CCSTATE->nsp
3074   |  move TMP2, sp
3075   |  dsubu sp, sp, TMP1
3076   |  sd ra, -8(TMP2)
3077   |  sd r16, -16(TMP2)
3078   |  sd CCSTATE, -24(TMP2)
3079   |  move r16, TMP2
3080   |  daddiu TMP1, CCSTATE, offsetof(CCallState, stack)
3081   |  move TMP2, sp
3082   |  beqz CARG2, >2
3083   |.  daddu TMP3, TMP1, CARG2
3084   |1:
3085   |   ld TMP0, 0(TMP1)
3086   |  daddiu TMP1, TMP1, 8
3087   |  sltu AT, TMP1, TMP3
3088   |   sd TMP0, 0(TMP2)
3089   |  bnez AT, <1
3090   |.  daddiu TMP2, TMP2, 8
3091   |2:
3092   |  ld CFUNCADDR, CCSTATE->func
3093   |  .FPU ldc1 FARG1, CCSTATE->gpr[0]
3094   |  ld CARG2, CCSTATE->gpr[1]
3095   |  .FPU ldc1 FARG2, CCSTATE->gpr[1]
3096   |  ld CARG3, CCSTATE->gpr[2]
3097   |  .FPU ldc1 FARG3, CCSTATE->gpr[2]
3098   |  ld CARG4, CCSTATE->gpr[3]
3099   |  .FPU ldc1 FARG4, CCSTATE->gpr[3]
3100   |  ld CARG5, CCSTATE->gpr[4]
3101   |  .FPU ldc1 FARG5, CCSTATE->gpr[4]
3102   |  ld CARG6, CCSTATE->gpr[5]
3103   |  .FPU ldc1 FARG6, CCSTATE->gpr[5]
3104   |  ld CARG7, CCSTATE->gpr[6]
3105   |  .FPU ldc1 FARG7, CCSTATE->gpr[6]
3106   |  ld CARG8, CCSTATE->gpr[7]
3107   |  .FPU ldc1 FARG8, CCSTATE->gpr[7]
3108   |  jalr CFUNCADDR
3109   |.  ld CARG1, CCSTATE->gpr[0]         // Do this last, since CCSTATE is CARG1.
3110   |  ld CCSTATE:TMP1, -24(r16)
3111   |  ld TMP2, -16(r16)
3112   |  ld ra, -8(r16)
3113   |  sd CRET1, CCSTATE:TMP1->gpr[0]
3114   |  sd CRET2, CCSTATE:TMP1->gpr[1]
3115   |.if FPU
3116   |  sdc1 FRET1, CCSTATE:TMP1->fpr[0]
3117   |  sdc1 FRET2, CCSTATE:TMP1->fpr[1]
3118   |.else
3119   |  sd CARG1, CCSTATE:TMP1->gpr[2]     // 2nd FP struct field for soft-float.
3120   |.endif
3121   |  move sp, r16
3122   |  jr ra
3123   |.  move r16, TMP2
3124   |.endif
3125   |// Note: vm_ffi_call must be the last function in this object file!
3126   |
3127   |//-----------------------------------------------------------------------
3130 /* Generate the code for a single instruction. */
3131 static void build_ins(BuildCtx *ctx, BCOp op, int defop)
3133   int vk = 0;
3134   |=>defop:
3136   switch (op) {
3138   /* -- Comparison ops ---------------------------------------------------- */
3140   /* Remember: all ops branch for a true comparison, fall through otherwise. */
3142   case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT:
3143     |  // RA = src1*8, RD = src2*8, JMP with RD = target
3144     |.macro bc_comp, FRA, FRD, ARGRA, ARGRD, movop, fmovop, fcomp, sfcomp
3145     |  daddu RA, BASE, RA
3146     |   daddu RD, BASE, RD
3147     |  ld ARGRA, 0(RA)
3148     |   ld ARGRD, 0(RD)
3149     |    lhu TMP2, OFS_RD(PC)
3150     |  gettp CARG3, ARGRA
3151     |   gettp CARG4, ARGRD
3152     |  bne CARG3, TISNUM, >2
3153     |.   daddiu PC, PC, 4
3154     |  bne CARG4, TISNUM, >5
3155     |.   decode_RD4b TMP2
3156     |  sextw ARGRA, ARGRA
3157     |   sextw ARGRD, ARGRD
3158     |    lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3159     |  slt AT, CARG1, CARG2
3160     |    addu TMP2, TMP2, TMP3
3161     |.if MIPSR6
3162     |  movop TMP2, TMP2, AT
3163     |.else
3164     |  movop TMP2, r0, AT
3165     |.endif
3166     |1:
3167     |  daddu PC, PC, TMP2
3168     |  ins_next
3169     |
3170     |2:  // RA is not an integer.
3171     |  sltiu AT, CARG3, LJ_TISNUM
3172     |  beqz AT, ->vmeta_comp
3173     |.   lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3174     |  sltiu AT, CARG4, LJ_TISNUM
3175     |  beqz AT, >4
3176     |.   decode_RD4b TMP2
3177     |.if FPU
3178     |  ldc1 FRA, 0(RA)
3179     |   ldc1 FRD, 0(RD)
3180     |.endif
3181     |3:  // RA and RD are both numbers.
3182     |.if FPU
3183     |.if MIPSR6
3184     |  fcomp FTMP0, FTMP0, FTMP2
3185     |   addu TMP2, TMP2, TMP3
3186     |  mfc1 TMP3, FTMP0
3187     |  b <1
3188     |.  fmovop TMP2, TMP2, TMP3
3189     |.else
3190     |  fcomp FTMP0, FTMP2
3191     |   addu TMP2, TMP2, TMP3
3192     |  b <1
3193     |.  fmovop TMP2, r0
3194     |.endif
3195     |.else
3196     |  bal sfcomp
3197     |.   addu TMP2, TMP2, TMP3
3198     |  b <1
3199     |.if MIPSR6
3200     |.  movop TMP2, TMP2, CRET1
3201     |.else
3202     |.  movop TMP2, r0, CRET1
3203     |.endif
3204     |.endif
3205     |
3206     |4:  // RA is a number, RD is not a number.
3207     |  bne CARG4, TISNUM, ->vmeta_comp
3208     |  // RA is a number, RD is an integer. Convert RD to a number.
3209     |.if FPU
3210     |.  lwc1 FRD, LO(RD)
3211     |  ldc1 FRA, 0(RA)
3212     |  b <3
3213     |.  cvt.d.w FRD, FRD
3214     |.else
3215     |.if "ARGRD" == "CARG1"
3216     |.  sextw CARG1, CARG1
3217     |  bal ->vm_sfi2d_1
3218     |.  nop
3219     |.else
3220     |.  sextw CARG2, CARG2
3221     |  bal ->vm_sfi2d_2
3222     |.  nop
3223     |.endif
3224     |  b <3
3225     |.  nop
3226     |.endif
3227     |
3228     |5:  // RA is an integer, RD is not an integer
3229     |  sltiu AT, CARG4, LJ_TISNUM
3230     |  beqz AT, ->vmeta_comp
3231     |.  lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3232     |  // RA is an integer, RD is a number. Convert RA to a number.
3233     |.if FPU
3234     |   lwc1 FRA, LO(RA)
3235     |   ldc1 FRD, 0(RD)
3236     |  b <3
3237     |   cvt.d.w FRA, FRA
3238     |.else
3239     |.if "ARGRA" == "CARG1"
3240     |  bal ->vm_sfi2d_1
3241     |.  sextw CARG1, CARG1
3242     |.else
3243     |  bal ->vm_sfi2d_2
3244     |.  sextw CARG2, CARG2
3245     |.endif
3246     |  b <3
3247     |.  nop
3248     |.endif
3249     |.endmacro
3250     |
3251     |.if MIPSR6
3252     if (op == BC_ISLT) {
3253       |  bc_comp FTMP0, FTMP2, CARG1, CARG2, selnez, selnez, cmp.lt.d, ->vm_sfcmpolt
3254     } else if (op == BC_ISGE) {
3255       |  bc_comp FTMP0, FTMP2, CARG1, CARG2, seleqz, seleqz, cmp.lt.d, ->vm_sfcmpolt
3256     } else if (op == BC_ISLE) {
3257       |  bc_comp FTMP2, FTMP0, CARG2, CARG1, seleqz, seleqz, cmp.ult.d, ->vm_sfcmpult
3258     } else {
3259       |  bc_comp FTMP2, FTMP0, CARG2, CARG1, selnez, selnez, cmp.ult.d, ->vm_sfcmpult
3260     }
3261     |.else
3262     if (op == BC_ISLT) {
3263       |  bc_comp FTMP0, FTMP2, CARG1, CARG2, movz, movf, c.olt.d, ->vm_sfcmpolt
3264     } else if (op == BC_ISGE) {
3265       |  bc_comp FTMP0, FTMP2, CARG1, CARG2, movn, movt, c.olt.d, ->vm_sfcmpolt
3266     } else if (op == BC_ISLE) {
3267       |  bc_comp FTMP2, FTMP0, CARG2, CARG1, movn, movt, c.ult.d, ->vm_sfcmpult
3268     } else {
3269       |  bc_comp FTMP2, FTMP0, CARG2, CARG1, movz, movf, c.ult.d, ->vm_sfcmpult
3270     }
3271     |.endif
3272     break;
3274   case BC_ISEQV: case BC_ISNEV:
3275     vk = op == BC_ISEQV;
3276     |  // RA = src1*8, RD = src2*8, JMP with RD = target
3277     |  daddu RA, BASE, RA
3278     |    daddiu PC, PC, 4
3279     |   daddu RD, BASE, RD
3280     |  ld CARG1, 0(RA)
3281     |    lhu TMP2, -4+OFS_RD(PC)
3282     |   ld CARG2, 0(RD)
3283     |  gettp CARG3, CARG1
3284     |   gettp CARG4, CARG2
3285     |  sltu AT, TISNUM, CARG3
3286     |   sltu TMP1, TISNUM, CARG4
3287     |  or AT, AT, TMP1
3288     if (vk) {
3289       |  beqz AT, ->BC_ISEQN_Z
3290     } else {
3291       |  beqz AT, ->BC_ISNEN_Z
3292     }
3293     |  // Either or both types are not numbers.
3294     |    lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3295     |.if FFI
3296     |.  li AT, LJ_TCDATA
3297     |  beq CARG3, AT, ->vmeta_equal_cd
3298     |.endif
3299     |   decode_RD4b TMP2
3300     |.if FFI
3301     |  beq CARG4, AT, ->vmeta_equal_cd
3302     |.  nop
3303     |.endif
3304     |  bne CARG1, CARG2, >2
3305     |.  addu TMP2, TMP2, TMP3
3306     |  // Tag and value are equal.
3307     if (vk) {
3308       |->BC_ISEQV_Z:
3309       |  daddu PC, PC, TMP2
3310     }
3311     |1:
3312     |  ins_next
3313     |
3314     |2:  // Check if the tags are the same and it's a table or userdata.
3315     |  xor AT, CARG3, CARG4                     // Same type?
3316     |  sltiu TMP0, CARG3, LJ_TISTABUD+1         // Table or userdata?
3317     |.if MIPSR6
3318     |  seleqz TMP0, TMP0, AT
3319     |.else
3320     |  movn TMP0, r0, AT
3321     |.endif
3322     if (vk) {
3323       |  beqz TMP0, <1
3324     } else {
3325       |  beqz TMP0, ->BC_ISEQV_Z  // Reuse code from opposite instruction.
3326     }
3327     |  // Different tables or userdatas. Need to check __eq metamethod.
3328     |  // Field metatable must be at same offset for GCtab and GCudata!
3329     |.  cleartp TAB:TMP1, CARG1
3330     |  ld TAB:TMP3, TAB:TMP1->metatable
3331     if (vk) {
3332       |  beqz TAB:TMP3, <1              // No metatable?
3333       |.  nop
3334       |  lbu TMP3, TAB:TMP3->nomm
3335       |  andi TMP3, TMP3, 1<<MM_eq
3336       |  bnez TMP3, >1                  // Or 'no __eq' flag set?
3337     } else {
3338       |  beqz TAB:TMP3,->BC_ISEQV_Z     // No metatable?
3339       |.  nop
3340       |  lbu TMP3, TAB:TMP3->nomm
3341       |  andi TMP3, TMP3, 1<<MM_eq
3342       |  bnez TMP3, ->BC_ISEQV_Z        // Or 'no __eq' flag set?
3343     }
3344     |.  nop
3345     |  b ->vmeta_equal                  // Handle __eq metamethod.
3346     |.  li TMP0, 1-vk                   // ne = 0 or 1.
3347     break;
3349   case BC_ISEQS: case BC_ISNES:
3350     vk = op == BC_ISEQS;
3351     |  // RA = src*8, RD = str_const*8 (~), JMP with RD = target
3352     |  daddu RA, BASE, RA
3353     |   daddiu PC, PC, 4
3354     |  ld CARG1, 0(RA)
3355     |   dsubu RD, KBASE, RD
3356     |    lhu TMP2, -4+OFS_RD(PC)
3357     |   ld CARG2, -8(RD)                // KBASE-8-str_const*8
3358     |.if FFI
3359     |  gettp TMP0, CARG1
3360     |  li AT, LJ_TCDATA
3361     |.endif
3362     |  li TMP1, LJ_TSTR
3363     |   decode_RD4b TMP2
3364     |.if FFI
3365     |  beq TMP0, AT, ->vmeta_equal_cd
3366     |.endif
3367     |.  settp CARG2, TMP1
3368     |   lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3369     |  xor TMP1, CARG1, CARG2
3370     |   addu TMP2, TMP2, TMP3
3371     |.if MIPSR6
3372     if (vk) {
3373       |  seleqz TMP2, TMP2, TMP1
3374     } else {
3375       |  selnez TMP2, TMP2, TMP1
3376     }
3377     |.else
3378     if (vk) {
3379       |  movn TMP2, r0, TMP1
3380     } else {
3381       |  movz TMP2, r0, TMP1
3382     }
3383     |.endif
3384     |  daddu PC, PC, TMP2
3385     |  ins_next
3386     break;
3388   case BC_ISEQN: case BC_ISNEN:
3389     vk = op == BC_ISEQN;
3390     |  // RA = src*8, RD = num_const*8, JMP with RD = target
3391     |  daddu RA, BASE, RA
3392     |   daddu RD, KBASE, RD
3393     |  ld CARG1, 0(RA)
3394     |   ld CARG2, 0(RD)
3395     |    lhu TMP2, OFS_RD(PC)
3396     |  gettp CARG3, CARG1
3397     |   gettp CARG4, CARG2
3398     |    daddiu PC, PC, 4
3399     |    lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3400     if (vk) {
3401       |->BC_ISEQN_Z:
3402     } else {
3403       |->BC_ISNEN_Z:
3404     }
3405     |  bne CARG3, TISNUM, >3
3406     |.   decode_RD4b TMP2
3407     |  bne CARG4, TISNUM, >6
3408     |.   addu TMP2, TMP2, TMP3
3409     |  xor AT, CARG1, CARG2
3410     |.if MIPSR6
3411     if (vk) {
3412       | seleqz TMP2, TMP2, AT
3413       |1:
3414       |  daddu PC, PC, TMP2
3415       |2:
3416     } else {
3417       |  selnez TMP2, TMP2, AT
3418       |1:
3419       |2:
3420       |  daddu PC, PC, TMP2
3421     }
3422     |.else
3423     if (vk) {
3424       | movn TMP2, r0, AT
3425       |1:
3426       |  daddu PC, PC, TMP2
3427       |2:
3428     } else {
3429       |  movz TMP2, r0, AT
3430       |1:
3431       |2:
3432       |  daddu PC, PC, TMP2
3433     }
3434     |.endif
3435     |  ins_next
3436     |
3437     |3:  // RA is not an integer.
3438     |  sltu AT, CARG3, TISNUM
3439     |.if FFI
3440     |  beqz AT, >8
3441     |.else
3442     |  beqz AT, <2
3443     |.endif
3444     |.   addu TMP2, TMP2, TMP3
3445     |  sltu AT, CARG4, TISNUM
3446     |.if FPU
3447     |  ldc1 FTMP0, 0(RA)
3448     |   ldc1 FTMP2, 0(RD)
3449     |.endif
3450     |  beqz AT, >5
3451     |.  nop
3452     |4:  // RA and RD are both numbers.
3453     |.if FPU
3454     |.if MIPSR6
3455     |  cmp.eq.d FTMP0, FTMP0, FTMP2
3456     |  dmfc1 TMP1, FTMP0
3457     |  b <1
3458     if (vk) {
3459       |.  selnez TMP2, TMP2, TMP1
3460     } else {
3461       |.  seleqz TMP2, TMP2, TMP1
3462     }
3463     |.else
3464     |  c.eq.d FTMP0, FTMP2
3465     |  b <1
3466     if (vk) {
3467       |.  movf TMP2, r0
3468     } else {
3469       |.  movt TMP2, r0
3470     }
3471     |.endif
3472     |.else
3473     |  bal ->vm_sfcmpeq
3474     |.  nop
3475     |  b <1
3476     |.if MIPSR6
3477     if (vk) {
3478       |.  selnez TMP2, TMP2, CRET1
3479     } else {
3480       |.  seleqz TMP2, TMP2, CRET1
3481     }
3482     |.else
3483     if (vk) {
3484       |.  movz TMP2, r0, CRET1
3485     } else {
3486       |.  movn TMP2, r0, CRET1
3487     }
3488     |.endif
3489     |.endif
3490     |
3491     |5:  // RA is a number, RD is not a number.
3492     |.if FFI
3493     |  bne CARG4, TISNUM, >9
3494     |.else
3495     |  bne CARG4, TISNUM, <2
3496     |.endif
3497     |  // RA is a number, RD is an integer. Convert RD to a number.
3498     |.if FPU
3499     |.  lwc1 FTMP2, LO(RD)
3500     |  b <4
3501     |.  cvt.d.w FTMP2, FTMP2
3502     |.else
3503     |.  sextw CARG2, CARG2
3504     |  bal ->vm_sfi2d_2
3505     |.  nop
3506     |  b <4
3507     |.  nop
3508     |.endif
3509     |
3510     |6:  // RA is an integer, RD is not an integer
3511     |  sltu AT, CARG4, TISNUM
3512     |.if FFI
3513     |  beqz AT, >9
3514     |.else
3515     |  beqz AT, <2
3516     |.endif
3517     |  // RA is an integer, RD is a number. Convert RA to a number.
3518     |.if FPU
3519     |.  lwc1 FTMP0, LO(RA)
3520     |   ldc1 FTMP2, 0(RD)
3521     |  b <4
3522     |   cvt.d.w FTMP0, FTMP0
3523     |.else
3524     |.  sextw CARG1, CARG1
3525     |  bal ->vm_sfi2d_1
3526     |.  nop
3527     |  b <4
3528     |.  nop
3529     |.endif
3530     |
3531     |.if FFI
3532     |8:
3533     |  li AT, LJ_TCDATA
3534     |  bne CARG3, AT, <2
3535     |.  nop
3536     |  b ->vmeta_equal_cd
3537     |.  nop
3538     |9:
3539     |  li AT, LJ_TCDATA
3540     |  bne CARG4, AT, <2
3541     |.  nop
3542     |  b ->vmeta_equal_cd
3543     |.  nop
3544     |.endif
3545     break;
3547   case BC_ISEQP: case BC_ISNEP:
3548     vk = op == BC_ISEQP;
3549     |  // RA = src*8, RD = primitive_type*8 (~), JMP with RD = target
3550     |  daddu RA, BASE, RA
3551     |   srl TMP1, RD, 3
3552     |  ld TMP0, 0(RA)
3553     |    lhu TMP2, OFS_RD(PC)
3554     |   not TMP1, TMP1
3555     |  gettp TMP0, TMP0
3556     |    daddiu PC, PC, 4
3557     |.if FFI
3558     |  li AT, LJ_TCDATA
3559     |  beq TMP0, AT, ->vmeta_equal_cd
3560     |.endif
3561     |.  xor TMP0, TMP0, TMP1
3562     |  decode_RD4b TMP2
3563     |  lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3564     |  addu TMP2, TMP2, TMP3
3565     |.if MIPSR6
3566     if (vk) {
3567       |  seleqz TMP2, TMP2, TMP0
3568     } else {
3569       |  selnez TMP2, TMP2, TMP0
3570     }
3571     |.else
3572     if (vk) {
3573       |  movn TMP2, r0, TMP0
3574     } else {
3575       |  movz TMP2, r0, TMP0
3576     }
3577     |.endif
3578     |  daddu PC, PC, TMP2
3579     |  ins_next
3580     break;
3582   /* -- Unary test and copy ops ------------------------------------------- */
3584   case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF:
3585     |  // RA = dst*8 or unused, RD = src*8, JMP with RD = target
3586     |  daddu RD, BASE, RD
3587     |   lhu TMP2, OFS_RD(PC)
3588     |  ld TMP0, 0(RD)
3589     |   daddiu PC, PC, 4
3590     |  gettp TMP0, TMP0
3591     |  sltiu TMP0, TMP0, LJ_TISTRUECOND
3592     if (op == BC_IST || op == BC_ISF) {
3593       |   decode_RD4b TMP2
3594       |   lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3595       |   addu TMP2, TMP2, TMP3
3596       |.if MIPSR6
3597       if (op == BC_IST) {
3598         |  selnez TMP2, TMP2, TMP0;
3599       } else {
3600         |  seleqz TMP2, TMP2, TMP0;
3601       }
3602       |.else
3603       if (op == BC_IST) {
3604         |  movz TMP2, r0, TMP0
3605       } else {
3606         |  movn TMP2, r0, TMP0
3607       }
3608       |.endif
3609       |  daddu PC, PC, TMP2
3610     } else {
3611       |  ld CRET1, 0(RD)
3612       if (op == BC_ISTC) {
3613         |  beqz TMP0, >1
3614       } else {
3615         |  bnez TMP0, >1
3616       }
3617       |.  daddu RA, BASE, RA
3618       |   decode_RD4b TMP2
3619       |   lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3620       |   addu TMP2, TMP2, TMP3
3621       |  sd CRET1, 0(RA)
3622       |   daddu PC, PC, TMP2
3623       |1:
3624     }
3625     |  ins_next
3626     break;
3628   case BC_ISTYPE:
3629     |  // RA = src*8, RD = -type*8
3630     |  daddu TMP2, BASE, RA
3631     |  srl TMP1, RD, 3
3632     |  ld TMP0, 0(TMP2)
3633     |  ins_next1
3634     |  gettp TMP0, TMP0
3635     |  daddu AT, TMP0, TMP1
3636     |  bnez AT, ->vmeta_istype
3637     |.  ins_next2
3638     break;
3639   case BC_ISNUM:
3640     |  // RA = src*8, RD = -(TISNUM-1)*8
3641     |  daddu TMP2, BASE, RA
3642     |  ld TMP0, 0(TMP2)
3643     |  ins_next1
3644     |  checknum TMP0, ->vmeta_istype
3645     |.  ins_next2
3646     break;
3648   /* -- Unary ops --------------------------------------------------------- */
3650   case BC_MOV:
3651     |  // RA = dst*8, RD = src*8
3652     |  daddu RD, BASE, RD
3653     |   daddu RA, BASE, RA
3654     |  ld CRET1, 0(RD)
3655     |  ins_next1
3656     |  sd CRET1, 0(RA)
3657     |  ins_next2
3658     break;
3659   case BC_NOT:
3660     |  // RA = dst*8, RD = src*8
3661     |  daddu RD, BASE, RD
3662     |   daddu RA, BASE, RA
3663     |  ld TMP0, 0(RD)
3664     |   li AT, LJ_TTRUE
3665     |  gettp TMP0, TMP0
3666     |  sltu TMP0, AT, TMP0
3667     |  addiu TMP0, TMP0, 1
3668     |  dsll TMP0, TMP0, 47
3669     |  not TMP0, TMP0
3670     |  ins_next1
3671     |   sd TMP0, 0(RA)
3672     |  ins_next2
3673     break;
3674   case BC_UNM:
3675     |  // RA = dst*8, RD = src*8
3676     |  daddu RB, BASE, RD
3677     |  ld CARG1, 0(RB)
3678     |    daddu RA, BASE, RA
3679     |  gettp CARG3, CARG1
3680     |  bne CARG3, TISNUM, >2
3681     |.  lui TMP1, 0x8000
3682     |  sextw CARG1, CARG1
3683     |  beq CARG1, TMP1, ->vmeta_unm     // Meta handler deals with -2^31.
3684     |.  negu CARG1, CARG1
3685     |  zextw CARG1, CARG1
3686     |  settp CARG1, TISNUM
3687     |1:
3688     |  ins_next1
3689     |   sd CARG1, 0(RA)
3690     |  ins_next2
3691     |2:
3692     |  sltiu AT, CARG3, LJ_TISNUM
3693     |  beqz AT, ->vmeta_unm
3694     |.  dsll TMP1, TMP1, 32
3695     |  b <1
3696     |.  xor CARG1, CARG1, TMP1
3697     break;
3698   case BC_LEN:
3699     |  // RA = dst*8, RD = src*8
3700     |  daddu CARG2, BASE, RD
3701     |   daddu RA, BASE, RA
3702     |  ld TMP0, 0(CARG2)
3703     |  gettp TMP1, TMP0
3704     |  daddiu AT, TMP1, -LJ_TSTR
3705     |  bnez AT, >2
3706     |.  cleartp STR:CARG1, TMP0
3707     |   lw CRET1, STR:CARG1->len
3708     |1:
3709     |  settp CRET1, TISNUM
3710     |  ins_next1
3711     |  sd CRET1, 0(RA)
3712     |  ins_next2
3713     |2:
3714     |  daddiu AT, TMP1, -LJ_TTAB
3715     |  bnez AT, ->vmeta_len
3716     |.  nop
3717 #if LJ_52
3718     |  ld TAB:TMP2, TAB:CARG1->metatable
3719     |  bnez TAB:TMP2, >9
3720     |.  nop
3721     |3:
3722 #endif
3723     |->BC_LEN_Z:
3724     |  load_got lj_tab_len
3725     |  call_intern lj_tab_len           // (GCtab *t)
3726     |.  nop
3727     |  // Returns uint32_t (but less than 2^31).
3728     |  b <1
3729     |.  nop
3730 #if LJ_52
3731     |9:
3732     |  lbu TMP0, TAB:TMP2->nomm
3733     |  andi TMP0, TMP0, 1<<MM_len
3734     |  bnez TMP0, <3                    // 'no __len' flag set: done.
3735     |.  nop
3736     |  b ->vmeta_len
3737     |.  nop
3738 #endif
3739     break;
3741   /* -- Binary ops -------------------------------------------------------- */
3743     |.macro fpmod, a, b, c
3744     |  bal ->vm_floor           // floor(b/c)
3745     |.  div.d FARG1, b, c
3746     |  mul.d a, FRET1, c
3747     |  sub.d a, b, a            // b - floor(b/c)*c
3748     |.endmacro
3750     |.macro sfpmod
3751     |  daddiu sp, sp, -16
3752     |
3753     |  load_got __divdf3
3754     |  sd CARG1, 0(sp)
3755     |  call_extern
3756     |.  sd CARG2, 8(sp)
3757     |
3758     |  load_got floor
3759     |  call_extern
3760     |.  move CARG1, CRET1
3761     |
3762     |  load_got __muldf3
3763     |  move CARG1, CRET1
3764     |  call_extern
3765     |.  ld CARG2, 8(sp)
3766     |
3767     |  load_got __subdf3
3768     |  ld CARG1, 0(sp)
3769     |  call_extern
3770     |.  move CARG2, CRET1
3771     |
3772     |  daddiu sp, sp, 16
3773     |.endmacro
3775     |.macro ins_arithpre, label
3776     ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN);
3777     |  // RA = dst*8, RB = src1*8, RC = src2*8 | num_const*8
3778     ||switch (vk) {
3779     ||case 0:
3780     |   decode_RB8a RB, INS
3781     |   decode_RB8b RB
3782     |    decode_RDtoRC8 RC, RD
3783     |   // RA = dst*8, RB = src1*8, RC = num_const*8
3784     |   daddu RB, BASE, RB
3785     |.if "label" ~= "none"
3786     |   b label
3787     |.endif
3788     |.   daddu RC, KBASE, RC
3789     ||  break;
3790     ||case 1:
3791     |   decode_RB8a RC, INS
3792     |   decode_RB8b RC
3793     |    decode_RDtoRC8 RB, RD
3794     |   // RA = dst*8, RB = num_const*8, RC = src1*8
3795     |   daddu RC, BASE, RC
3796     |.if "label" ~= "none"
3797     |   b label
3798     |.endif
3799     |.   daddu RB, KBASE, RB
3800     ||  break;
3801     ||default:
3802     |   decode_RB8a RB, INS
3803     |   decode_RB8b RB
3804     |    decode_RDtoRC8 RC, RD
3805     |   // RA = dst*8, RB = src1*8, RC = src2*8
3806     |   daddu RB, BASE, RB
3807     |.if "label" ~= "none"
3808     |   b label
3809     |.endif
3810     |.   daddu RC, BASE, RC
3811     ||  break;
3812     ||}
3813     |.endmacro
3814     |
3815     |.macro ins_arith, intins, fpins, fpcall, label
3816     |  ins_arithpre none
3817     |
3818     |.if "label" ~= "none"
3819     |label:
3820     |.endif
3821     |
3822     |// Used in 5.
3823     |  ld CARG1, 0(RB)
3824     |   ld CARG2, 0(RC)
3825     |  gettp TMP0, CARG1
3826     |   gettp TMP1, CARG2
3827     |
3828     |.if "intins" ~= "div"
3829     |
3830     |  // Check for two integers.
3831     |  sextw CARG3, CARG1
3832     |  bne TMP0, TISNUM, >5
3833     |.  sextw CARG4, CARG2
3834     |  bne TMP1, TISNUM, >5
3835     |
3836     |.if "intins" == "addu"
3837     |.  intins CRET1, CARG3, CARG4
3838     |  xor TMP1, CRET1, CARG3           // ((y^a) & (y^b)) < 0: overflow.
3839     |  xor TMP2, CRET1, CARG4
3840     |  and TMP1, TMP1, TMP2
3841     |  bltz TMP1, ->vmeta_arith
3842     |.  daddu RA, BASE, RA
3843     |.elif "intins" == "subu"
3844     |.  intins CRET1, CARG3, CARG4
3845     |  xor TMP1, CRET1, CARG3           // ((y^a) & (a^b)) < 0: overflow.
3846     |  xor TMP2, CARG3, CARG4
3847     |  and TMP1, TMP1, TMP2
3848     |  bltz TMP1, ->vmeta_arith
3849     |.  daddu RA, BASE, RA
3850     |.elif "intins" == "mult"
3851     |.if MIPSR6
3852     |.  nop
3853     |  mul CRET1, CARG3, CARG4
3854     |  muh TMP2, CARG3, CARG4
3855     |.else
3856     |.  intins CARG3, CARG4
3857     |  mflo CRET1
3858     |  mfhi TMP2
3859     |.endif
3860     |  sra TMP1, CRET1, 31
3861     |  bne TMP1, TMP2, ->vmeta_arith
3862     |.  daddu RA, BASE, RA
3863     |.else
3864     |.  load_got lj_vm_modi
3865     |  beqz CARG4, ->vmeta_arith
3866     |.  daddu RA, BASE, RA
3867     |  move CARG1, CARG3
3868     |  call_extern
3869     |.  move CARG2, CARG4
3870     |.endif
3871     |
3872     |  zextw CRET1, CRET1
3873     |  settp CRET1, TISNUM
3874     |  ins_next1
3875     |  sd CRET1, 0(RA)
3876     |3:
3877     |  ins_next2
3878     |
3879     |.endif
3880     |
3881     |5:  // Check for two numbers.
3882     |  .FPU ldc1 FTMP0, 0(RB)
3883     |  sltu AT, TMP0, TISNUM
3884     |   sltu TMP0, TMP1, TISNUM
3885     |  .FPU ldc1 FTMP2, 0(RC)
3886     |   and AT, AT, TMP0
3887     |   beqz AT, ->vmeta_arith
3888     |.   daddu RA, BASE, RA
3889     |
3890     |.if FPU
3891     |  fpins FRET1, FTMP0, FTMP2
3892     |.elif "fpcall" == "sfpmod"
3893     |  sfpmod
3894     |.else
3895     |  load_got fpcall
3896     |  call_extern
3897     |.  nop
3898     |.endif
3899     |
3900     |  ins_next1
3901     |.if "intins" ~= "div"
3902     |  b <3
3903     |.endif
3904     |.if FPU
3905     |.  sdc1 FRET1, 0(RA)
3906     |.else
3907     |.  sd CRET1, 0(RA)
3908     |.endif
3909     |.if "intins" == "div"
3910     |  ins_next2
3911     |.endif
3912     |
3913     |.endmacro
3915   case BC_ADDVN: case BC_ADDNV: case BC_ADDVV:
3916     |  ins_arith addu, add.d, __adddf3, none
3917     break;
3918   case BC_SUBVN: case BC_SUBNV: case BC_SUBVV:
3919     |  ins_arith subu, sub.d, __subdf3, none
3920     break;
3921   case BC_MULVN: case BC_MULNV: case BC_MULVV:
3922     |  ins_arith mult, mul.d, __muldf3, none
3923     break;
3924   case BC_DIVVN:
3925     |  ins_arith div, div.d, __divdf3, ->BC_DIVVN_Z
3926     break;
3927   case BC_DIVNV: case BC_DIVVV:
3928     |  ins_arithpre ->BC_DIVVN_Z
3929     break;
3930   case BC_MODVN:
3931     |  ins_arith modi, fpmod, sfpmod, ->BC_MODVN_Z
3932     break;
3933   case BC_MODNV: case BC_MODVV:
3934     |  ins_arithpre ->BC_MODVN_Z
3935     break;
3936   case BC_POW:
3937     |  ins_arithpre none
3938     |  ld CARG1, 0(RB)
3939     |   ld CARG2, 0(RC)
3940     |  gettp TMP0, CARG1
3941     |   gettp TMP1, CARG2
3942     |  sltiu TMP0, TMP0, LJ_TISNUM
3943     |   sltiu TMP1, TMP1, LJ_TISNUM
3944     |  and AT, TMP0, TMP1
3945     |  load_got pow
3946     |  beqz AT, ->vmeta_arith
3947     |.  daddu RA, BASE, RA
3948     |.if FPU
3949     |  ldc1 FARG1, 0(RB)
3950     |  ldc1 FARG2, 0(RC)
3951     |.endif
3952     |  call_extern
3953     |.  nop
3954     |  ins_next1
3955     |.if FPU
3956     |  sdc1 FRET1, 0(RA)
3957     |.else
3958     |  sd CRET1, 0(RA)
3959     |.endif
3960     |  ins_next2
3961     break;
3963   case BC_CAT:
3964     |  // RA = dst*8, RB = src_start*8, RC = src_end*8
3965     |  decode_RB8a RB, INS
3966     |  decode_RB8b RB
3967     |   decode_RDtoRC8 RC, RD
3968     |  dsubu CARG3, RC, RB
3969     |   sd BASE, L->base
3970     |  daddu CARG2, BASE, RC
3971     |  move MULTRES, RB
3972     |->BC_CAT_Z:
3973     |  load_got lj_meta_cat
3974     |  srl CARG3, CARG3, 3
3975     |   sd PC, SAVE_PC
3976     |  call_intern lj_meta_cat          // (lua_State *L, TValue *top, int left)
3977     |.  move CARG1, L
3978     |  // Returns NULL (finished) or TValue * (metamethod).
3979     |  bnez CRET1, ->vmeta_binop
3980     |.  ld BASE, L->base
3981     |  daddu RB, BASE, MULTRES
3982     |  ld CRET1, 0(RB)
3983     |   daddu RA, BASE, RA
3984     |  ins_next1
3985     |  sd CRET1, 0(RA)
3986     |  ins_next2
3987     break;
3989   /* -- Constant ops ------------------------------------------------------ */
3991   case BC_KSTR:
3992     |  // RA = dst*8, RD = str_const*8 (~)
3993     |  dsubu TMP1, KBASE, RD
3994     |  ins_next1
3995     |   li TMP2, LJ_TSTR
3996     |  ld TMP0, -8(TMP1)                // KBASE-8-str_const*8
3997     |  daddu RA, BASE, RA
3998     |   settp TMP0, TMP2
3999     |  sd TMP0, 0(RA)
4000     |  ins_next2
4001     break;
4002   case BC_KCDATA:
4003     |.if FFI
4004     |  // RA = dst*8, RD = cdata_const*8 (~)
4005     |  dsubu TMP1, KBASE, RD
4006     |  ins_next1
4007     |  ld TMP0, -8(TMP1)                // KBASE-8-cdata_const*8
4008     |   li TMP2, LJ_TCDATA
4009     |  daddu RA, BASE, RA
4010     |   settp TMP0, TMP2
4011     |  sd TMP0, 0(RA)
4012     |  ins_next2
4013     |.endif
4014     break;
4015   case BC_KSHORT:
4016     |  // RA = dst*8, RD = int16_literal*8
4017     |   sra RD, INS, 16
4018     |  daddu RA, BASE, RA
4019     |   zextw RD, RD
4020     |  ins_next1
4021     |   settp RD, TISNUM
4022     |   sd RD, 0(RA)
4023     |  ins_next2
4024     break;
4025   case BC_KNUM:
4026     |  // RA = dst*8, RD = num_const*8
4027     |  daddu RD, KBASE, RD
4028     |   daddu RA, BASE, RA
4029     |  ld CRET1, 0(RD)
4030     |  ins_next1
4031     |  sd CRET1, 0(RA)
4032     |  ins_next2
4033     break;
4034   case BC_KPRI:
4035     |  // RA = dst*8, RD = primitive_type*8 (~)
4036     |   daddu RA, BASE, RA
4037     |  dsll TMP0, RD, 44
4038     |  not TMP0, TMP0
4039     |  ins_next1
4040     |   sd TMP0, 0(RA)
4041     |  ins_next2
4042     break;
4043   case BC_KNIL:
4044     |  // RA = base*8, RD = end*8
4045     |  daddu RA, BASE, RA
4046     |  sd TISNIL, 0(RA)
4047     |   daddiu RA, RA, 8
4048     |  daddu RD, BASE, RD
4049     |1:
4050     |  sd TISNIL, 0(RA)
4051     |  slt AT, RA, RD
4052     |  bnez AT, <1
4053     |.  daddiu RA, RA, 8
4054     |  ins_next_
4055     break;
4057   /* -- Upvalue and function ops ------------------------------------------ */
4059   case BC_UGET:
4060     |  // RA = dst*8, RD = uvnum*8
4061     |  ld LFUNC:RB, FRAME_FUNC(BASE)
4062     |   daddu RA, BASE, RA
4063     |  cleartp LFUNC:RB
4064     |  daddu RD, RD, LFUNC:RB
4065     |  ld UPVAL:RB, LFUNC:RD->uvptr
4066     |  ins_next1
4067     |  ld TMP1, UPVAL:RB->v
4068     |  ld CRET1, 0(TMP1)
4069     |   sd CRET1, 0(RA)
4070     |  ins_next2
4071     break;
4072   case BC_USETV:
4073     |  // RA = uvnum*8, RD = src*8
4074     |  ld LFUNC:RB, FRAME_FUNC(BASE)
4075     |   daddu RD, BASE, RD
4076     |  cleartp LFUNC:RB
4077     |  daddu RA, RA, LFUNC:RB
4078     |  ld UPVAL:RB, LFUNC:RA->uvptr
4079     |   ld CRET1, 0(RD)
4080     |  lbu TMP3, UPVAL:RB->marked
4081     |   ld CARG2, UPVAL:RB->v
4082     |  andi TMP3, TMP3, LJ_GC_BLACK     // isblack(uv)
4083     |  lbu TMP0, UPVAL:RB->closed
4084     |   gettp TMP2, CRET1
4085     |   sd CRET1, 0(CARG2)
4086     |  li AT, LJ_GC_BLACK|1
4087     |  or TMP3, TMP3, TMP0
4088     |  beq TMP3, AT, >2                 // Upvalue is closed and black?
4089     |.  daddiu TMP2, TMP2, -(LJ_TNUMX+1)
4090     |1:
4091     |  ins_next
4092     |
4093     |2:  // Check if new value is collectable.
4094     |  sltiu AT, TMP2, LJ_TISGCV - (LJ_TNUMX+1)
4095     |  beqz AT, <1                      // tvisgcv(v)
4096     |.  cleartp GCOBJ:CRET1, CRET1
4097     |  lbu TMP3, GCOBJ:CRET1->gch.marked
4098     |  andi TMP3, TMP3, LJ_GC_WHITES    // iswhite(v)
4099     |  beqz TMP3, <1
4100     |.  load_got lj_gc_barrieruv
4101     |  // Crossed a write barrier. Move the barrier forward.
4102     |  call_intern lj_gc_barrieruv      // (global_State *g, TValue *tv)
4103     |.  daddiu CARG1, DISPATCH, GG_DISP2G
4104     |  b <1
4105     |.  nop
4106     break;
4107   case BC_USETS:
4108     |  // RA = uvnum*8, RD = str_const*8 (~)
4109     |  ld LFUNC:RB, FRAME_FUNC(BASE)
4110     |   dsubu TMP1, KBASE, RD
4111     |  cleartp LFUNC:RB
4112     |  daddu RA, RA, LFUNC:RB
4113     |  ld UPVAL:RB, LFUNC:RA->uvptr
4114     |   ld STR:TMP1, -8(TMP1)           // KBASE-8-str_const*8
4115     |  lbu TMP2, UPVAL:RB->marked
4116     |   ld CARG2, UPVAL:RB->v
4117     |   lbu TMP3, STR:TMP1->marked
4118     |  andi AT, TMP2, LJ_GC_BLACK       // isblack(uv)
4119     |   lbu TMP2, UPVAL:RB->closed
4120     |   li TMP0, LJ_TSTR
4121     |   settp TMP1, TMP0
4122     |  bnez AT, >2
4123     |.  sd TMP1, 0(CARG2)
4124     |1:
4125     |  ins_next
4126     |
4127     |2:  // Check if string is white and ensure upvalue is closed.
4128     |  beqz TMP2, <1
4129     |.  andi AT, TMP3, LJ_GC_WHITES     // iswhite(str)
4130     |  beqz AT, <1
4131     |.  load_got lj_gc_barrieruv
4132     |  // Crossed a write barrier. Move the barrier forward.
4133     |  call_intern lj_gc_barrieruv      // (global_State *g, TValue *tv)
4134     |.  daddiu CARG1, DISPATCH, GG_DISP2G
4135     |  b <1
4136     |.  nop
4137     break;
4138   case BC_USETN:
4139     |  // RA = uvnum*8, RD = num_const*8
4140     |  ld LFUNC:RB, FRAME_FUNC(BASE)
4141     |   daddu RD, KBASE, RD
4142     |  cleartp LFUNC:RB
4143     |  daddu RA, RA, LFUNC:RB
4144     |  ld UPVAL:RB, LFUNC:RA->uvptr
4145     |   ld CRET1, 0(RD)
4146     |  ld TMP1, UPVAL:RB->v
4147     |  ins_next1
4148     |   sd CRET1, 0(TMP1)
4149     |  ins_next2
4150     break;
4151   case BC_USETP:
4152     |  // RA = uvnum*8, RD = primitive_type*8 (~)
4153     |  ld LFUNC:RB, FRAME_FUNC(BASE)
4154     |   dsll TMP0, RD, 44
4155     |  cleartp LFUNC:RB
4156     |  daddu RA, RA, LFUNC:RB
4157     |   not TMP0, TMP0
4158     |  ld UPVAL:RB, LFUNC:RA->uvptr
4159     |  ins_next1
4160     |  ld TMP1, UPVAL:RB->v
4161     |   sd TMP0, 0(TMP1)
4162     |  ins_next2
4163     break;
4165   case BC_UCLO:
4166     |  // RA = level*8, RD = target
4167     |  ld TMP2, L->openupval
4168     |  branch_RD                        // Do this first since RD is not saved.
4169     |  load_got lj_func_closeuv
4170     |   sd BASE, L->base
4171     |  beqz TMP2, >1
4172     |.  move CARG1, L
4173     |  call_intern lj_func_closeuv      // (lua_State *L, TValue *level)
4174     |.  daddu CARG2, BASE, RA
4175     |  ld BASE, L->base
4176     |1:
4177     |  ins_next
4178     break;
4180   case BC_FNEW:
4181     |  // RA = dst*8, RD = proto_const*8 (~) (holding function prototype)
4182     |  load_got lj_func_newL_gc
4183     |  dsubu TMP1, KBASE, RD
4184     |  ld CARG3, FRAME_FUNC(BASE)
4185     |   ld CARG2, -8(TMP1)              // KBASE-8-tab_const*8
4186     |    sd BASE, L->base
4187     |    sd PC, SAVE_PC
4188     |  cleartp CARG3
4189     |  // (lua_State *L, GCproto *pt, GCfuncL *parent)
4190     |  call_intern lj_func_newL_gc
4191     |.  move CARG1, L
4192     |  // Returns GCfuncL *.
4193     |   li TMP0, LJ_TFUNC
4194     |  ld BASE, L->base
4195     |  ins_next1
4196     |   settp CRET1, TMP0
4197     |  daddu RA, BASE, RA
4198     |   sd CRET1, 0(RA)
4199     |  ins_next2
4200     break;
4202   /* -- Table ops --------------------------------------------------------- */
4204   case BC_TNEW:
4205   case BC_TDUP:
4206     |  // RA = dst*8, RD = (hbits|asize)*8 | tab_const*8 (~)
4207     |  ld TMP0, DISPATCH_GL(gc.total)(DISPATCH)
4208     |  ld TMP1, DISPATCH_GL(gc.threshold)(DISPATCH)
4209     |   sd BASE, L->base
4210     |   sd PC, SAVE_PC
4211     |  sltu AT, TMP0, TMP1
4212     |  beqz AT, >5
4213     |1:
4214     if (op == BC_TNEW) {
4215       |  load_got lj_tab_new
4216       |  srl CARG2, RD, 3
4217       |  andi CARG2, CARG2, 0x7ff
4218       |  li TMP0, 0x801
4219       |  addiu AT, CARG2, -0x7ff
4220       |   srl CARG3, RD, 14
4221       |.if MIPSR6
4222       |  seleqz TMP0, TMP0, AT
4223       |  selnez CARG2, CARG2, AT
4224       |  or CARG2, CARG2, TMP0
4225       |.else
4226       |  movz CARG2, TMP0, AT
4227       |.endif
4228       |  // (lua_State *L, int32_t asize, uint32_t hbits)
4229       |  call_intern lj_tab_new
4230       |.  move CARG1, L
4231       |  // Returns Table *.
4232     } else {
4233       |  load_got lj_tab_dup
4234       |  dsubu TMP1, KBASE, RD
4235       |  move CARG1, L
4236       |  call_intern lj_tab_dup         // (lua_State *L, Table *kt)
4237       |.  ld CARG2, -8(TMP1)            // KBASE-8-str_const*8
4238       |  // Returns Table *.
4239     }
4240     |   li TMP0, LJ_TTAB
4241     |  ld BASE, L->base
4242     |  ins_next1
4243     |  daddu RA, BASE, RA
4244     |   settp CRET1, TMP0
4245     |   sd CRET1, 0(RA)
4246     |  ins_next2
4247     |5:
4248     |  load_got lj_gc_step_fixtop
4249     |  move MULTRES, RD
4250     |  call_intern lj_gc_step_fixtop    // (lua_State *L)
4251     |.  move CARG1, L
4252     |  b <1
4253     |.  move RD, MULTRES
4254     break;
4256   case BC_GGET:
4257     |  // RA = dst*8, RD = str_const*8 (~)
4258   case BC_GSET:
4259     |  // RA = src*8, RD = str_const*8 (~)
4260     |  ld LFUNC:TMP2, FRAME_FUNC(BASE)
4261     |   dsubu TMP1, KBASE, RD
4262     |   ld STR:RC, -8(TMP1)             // KBASE-8-str_const*8
4263     |  cleartp LFUNC:TMP2
4264     |  ld TAB:RB, LFUNC:TMP2->env
4265     if (op == BC_GGET) {
4266       |  b ->BC_TGETS_Z
4267     } else {
4268       |  b ->BC_TSETS_Z
4269     }
4270     |.  daddu RA, BASE, RA
4271     break;
4273   case BC_TGETV:
4274     |  // RA = dst*8, RB = table*8, RC = key*8
4275     |  decode_RB8a RB, INS
4276     |  decode_RB8b RB
4277     |   decode_RDtoRC8 RC, RD
4278     |  daddu CARG2, BASE, RB
4279     |   daddu CARG3, BASE, RC
4280     |  ld TAB:RB, 0(CARG2)
4281     |   ld TMP2, 0(CARG3)
4282     |   daddu RA, BASE, RA
4283     |  checktab TAB:RB, ->vmeta_tgetv
4284     |   gettp TMP3, TMP2
4285     |  bne TMP3, TISNUM, >5             // Integer key?
4286     |.  lw TMP0, TAB:RB->asize
4287     |  sextw TMP2, TMP2
4288     |   ld TMP1, TAB:RB->array
4289     |  sltu AT, TMP2, TMP0
4290     |   sll TMP2, TMP2, 3
4291     |  beqz AT, ->vmeta_tgetv           // Integer key and in array part?
4292     |.  daddu TMP2, TMP1, TMP2
4293     |  ld AT, 0(TMP2)
4294     |  beq AT, TISNIL, >2
4295     |.   ld CRET1, 0(TMP2)
4296     |1:
4297     |  ins_next1
4298     |   sd CRET1, 0(RA)
4299     |  ins_next2
4300     |
4301     |2:  // Check for __index if table value is nil.
4302     |  ld TAB:TMP2, TAB:RB->metatable
4303     |  beqz TAB:TMP2, <1                // No metatable: done.
4304     |.  nop
4305     |  lbu TMP0, TAB:TMP2->nomm
4306     |  andi TMP0, TMP0, 1<<MM_index
4307     |  bnez TMP0, <1                    // 'no __index' flag set: done.
4308     |.  nop
4309     |  b ->vmeta_tgetv
4310     |.  nop
4311     |
4312     |5:
4313     |  li AT, LJ_TSTR
4314     |  bne TMP3, AT, ->vmeta_tgetv
4315     |.  cleartp RC, TMP2
4316     |  b ->BC_TGETS_Z                   // String key?
4317     |.  nop
4318     break;
4319   case BC_TGETS:
4320     |  // RA = dst*8, RB = table*8, RC = str_const*8 (~)
4321     |  decode_RB8a RB, INS
4322     |  decode_RB8b RB
4323     |   decode_RC8a RC, INS
4324     |  daddu CARG2, BASE, RB
4325     |   decode_RC8b RC
4326     |  ld TAB:RB, 0(CARG2)
4327     |   dsubu CARG3, KBASE, RC
4328     |  daddu RA, BASE, RA
4329     |   ld STR:RC, -8(CARG3)            // KBASE-8-str_const*8
4330     |  checktab TAB:RB, ->vmeta_tgets1
4331     |->BC_TGETS_Z:
4332     |  // TAB:RB = GCtab *, STR:RC = GCstr *, RA = dst*8
4333     |  lw TMP0, TAB:RB->hmask
4334     |   lw TMP1, STR:RC->sid
4335     |    ld NODE:TMP2, TAB:RB->node
4336     |  and TMP1, TMP1, TMP0             // idx = str->sid & tab->hmask
4337     |  sll TMP0, TMP1, 5
4338     |  sll TMP1, TMP1, 3
4339     |  subu TMP1, TMP0, TMP1
4340     |   li TMP3, LJ_TSTR
4341     |  daddu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8)
4342     |   settp STR:RC, TMP3              // Tagged key to look for.
4343     |1:
4344     |  ld CARG1, NODE:TMP2->key
4345     |   ld CRET1, NODE:TMP2->val
4346     |    ld NODE:TMP1, NODE:TMP2->next
4347     |  bne CARG1, RC, >4
4348     |.  ld TAB:TMP3, TAB:RB->metatable
4349     |  beq CRET1, TISNIL, >5            // Key found, but nil value?
4350     |.  nop
4351     |3:
4352     |  ins_next1
4353     |   sd CRET1, 0(RA)
4354     |  ins_next2
4355     |
4356     |4:  // Follow hash chain.
4357     |  bnez NODE:TMP1, <1
4358     |.  move NODE:TMP2, NODE:TMP1
4359     |  // End of hash chain: key not found, nil result.
4360     |
4361     |5:  // Check for __index if table value is nil.
4362     |  beqz TAB:TMP3, <3                // No metatable: done.
4363     |.  move CRET1, TISNIL
4364     |  lbu TMP0, TAB:TMP3->nomm
4365     |  andi TMP0, TMP0, 1<<MM_index
4366     |  bnez TMP0, <3                    // 'no __index' flag set: done.
4367     |.  nop
4368     |  b ->vmeta_tgets
4369     |.  nop
4370     break;
4371   case BC_TGETB:
4372     |  // RA = dst*8, RB = table*8, RC = index*8
4373     |  decode_RB8a RB, INS
4374     |  decode_RB8b RB
4375     |  daddu CARG2, BASE, RB
4376     |   decode_RDtoRC8 RC, RD
4377     |  ld TAB:RB, 0(CARG2)
4378     |   daddu RA, BASE, RA
4379     |  srl TMP0, RC, 3
4380     |  checktab TAB:RB, ->vmeta_tgetb
4381     |  lw TMP1, TAB:RB->asize
4382     |   ld TMP2, TAB:RB->array
4383     |  sltu AT, TMP0, TMP1
4384     |  beqz AT, ->vmeta_tgetb
4385     |.  daddu RC, TMP2, RC
4386     |  ld AT, 0(RC)
4387     |  beq AT, TISNIL, >5
4388     |.  ld CRET1, 0(RC)
4389     |1:
4390     |  ins_next1
4391     |   sd CRET1, 0(RA)
4392     |  ins_next2
4393     |
4394     |5:  // Check for __index if table value is nil.
4395     |  ld TAB:TMP2, TAB:RB->metatable
4396     |  beqz TAB:TMP2, <1                // No metatable: done.
4397     |.  nop
4398     |  lbu TMP1, TAB:TMP2->nomm
4399     |  andi TMP1, TMP1, 1<<MM_index
4400     |  bnez TMP1, <1                    // 'no __index' flag set: done.
4401     |.  nop
4402     |  b ->vmeta_tgetb                  // Caveat: preserve TMP0 and CARG2!
4403     |.  nop
4404     break;
4405   case BC_TGETR:
4406     |  // RA = dst*8, RB = table*8, RC = key*8
4407     |  decode_RB8a RB, INS
4408     |  decode_RB8b RB
4409     |   decode_RDtoRC8 RC, RD
4410     |  daddu RB, BASE, RB
4411     |   daddu RC, BASE, RC
4412     |  ld TAB:CARG1, 0(RB)
4413     |   lw CARG2, LO(RC)
4414     |    daddu RA, BASE, RA
4415     |  cleartp TAB:CARG1
4416     |  lw TMP0, TAB:CARG1->asize
4417     |   ld TMP1, TAB:CARG1->array
4418     |  sltu AT, CARG2, TMP0
4419     |   sll TMP2, CARG2, 3
4420     |  beqz AT, ->vmeta_tgetr           // In array part?
4421     |.  daddu CRET1, TMP1, TMP2
4422     |   ld CARG2, 0(CRET1)
4423     |->BC_TGETR_Z:
4424     |  ins_next1
4425     |   sd CARG2, 0(RA)
4426     |  ins_next2
4427     break;
4429   case BC_TSETV:
4430     |  // RA = src*8, RB = table*8, RC = key*8
4431     |  decode_RB8a RB, INS
4432     |  decode_RB8b RB
4433     |   decode_RDtoRC8 RC, RD
4434     |  daddu CARG2, BASE, RB
4435     |   daddu CARG3, BASE, RC
4436     |  ld RB, 0(CARG2)
4437     |   ld TMP2, 0(CARG3)
4438     |  daddu RA, BASE, RA
4439     |  checktab RB, ->vmeta_tsetv
4440     |  checkint TMP2, >5
4441     |.  sextw RC, TMP2
4442     |  lw TMP0, TAB:RB->asize
4443     |   ld TMP1, TAB:RB->array
4444     |  sltu AT, RC, TMP0
4445     |   sll TMP2, RC, 3
4446     |  beqz AT, ->vmeta_tsetv           // Integer key and in array part?
4447     |.  daddu TMP1, TMP1, TMP2
4448     |  ld TMP0, 0(TMP1)
4449     |   lbu TMP3, TAB:RB->marked
4450     |  beq TMP0, TISNIL, >3
4451     |.  ld CRET1, 0(RA)
4452     |1:
4453     |   andi AT, TMP3, LJ_GC_BLACK      // isblack(table)
4454     |  bnez AT, >7
4455     |.  sd CRET1, 0(TMP1)
4456     |2:
4457     |  ins_next
4458     |
4459     |3:  // Check for __newindex if previous value is nil.
4460     |  ld TAB:TMP2, TAB:RB->metatable
4461     |  beqz TAB:TMP2, <1                // No metatable: done.
4462     |.  nop
4463     |  lbu TMP2, TAB:TMP2->nomm
4464     |  andi TMP2, TMP2, 1<<MM_newindex
4465     |  bnez TMP2, <1                    // 'no __newindex' flag set: done.
4466     |.  nop
4467     |  b ->vmeta_tsetv
4468     |.  nop
4469     |
4470     |5:
4471     |  gettp AT, TMP2
4472     |  daddiu AT, AT, -LJ_TSTR
4473     |  bnez AT, ->vmeta_tsetv
4474     |.  nop
4475     |  b ->BC_TSETS_Z                   // String key?
4476     |.  cleartp STR:RC, TMP2
4477     |
4478     |7:  // Possible table write barrier for the value. Skip valiswhite check.
4479     |  barrierback TAB:RB, TMP3, TMP0, <2
4480     break;
4481   case BC_TSETS:
4482     |  // RA = src*8, RB = table*8, RC = str_const*8 (~)
4483     |  decode_RB8a RB, INS
4484     |  decode_RB8b RB
4485     |  daddu CARG2, BASE, RB
4486     |   decode_RC8a RC, INS
4487     |    ld TAB:RB, 0(CARG2)
4488     |   decode_RC8b RC
4489     |   dsubu CARG3, KBASE, RC
4490     |   ld RC, -8(CARG3)                // KBASE-8-str_const*8
4491     |  daddu RA, BASE, RA
4492     |   cleartp STR:RC
4493     |  checktab TAB:RB, ->vmeta_tsets1
4494     |->BC_TSETS_Z:
4495     |  // TAB:RB = GCtab *, STR:RC = GCstr *, RA = BASE+src*8
4496     |  lw TMP0, TAB:RB->hmask
4497     |   lw TMP1, STR:RC->sid
4498     |    ld NODE:TMP2, TAB:RB->node
4499     |   sb r0, TAB:RB->nomm             // Clear metamethod cache.
4500     |  and TMP1, TMP1, TMP0             // idx = str->sid & tab->hmask
4501     |  sll TMP0, TMP1, 5
4502     |  sll TMP1, TMP1, 3
4503     |  subu TMP1, TMP0, TMP1
4504     |   li TMP3, LJ_TSTR
4505     |  daddu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8)
4506     |   settp STR:RC, TMP3              // Tagged key to look for.
4507     |.if FPU
4508     |   ldc1 FTMP0, 0(RA)
4509     |.else
4510     |   ld CRET1, 0(RA)
4511     |.endif
4512     |1:
4513     |  ld TMP0, NODE:TMP2->key
4514     |   ld CARG2, NODE:TMP2->val
4515     |    ld NODE:TMP1, NODE:TMP2->next
4516     |  bne TMP0, RC, >5
4517     |.    lbu TMP3, TAB:RB->marked
4518     |   beq CARG2, TISNIL, >4           // Key found, but nil value?
4519     |.   ld TAB:TMP0, TAB:RB->metatable
4520     |2:
4521     |  andi AT, TMP3, LJ_GC_BLACK       // isblack(table)
4522     |  bnez AT, >7
4523     |.if FPU
4524     |.  sdc1 FTMP0, NODE:TMP2->val
4525     |.else
4526     |.  sd CRET1, NODE:TMP2->val
4527     |.endif
4528     |3:
4529     |  ins_next
4530     |
4531     |4:  // Check for __newindex if previous value is nil.
4532     |  beqz TAB:TMP0, <2                // No metatable: done.
4533     |.  nop
4534     |  lbu TMP0, TAB:TMP0->nomm
4535     |  andi TMP0, TMP0, 1<<MM_newindex
4536     |  bnez TMP0, <2                    // 'no __newindex' flag set: done.
4537     |.  nop
4538     |  b ->vmeta_tsets
4539     |.  nop
4540     |
4541     |5:  // Follow hash chain.
4542     |  bnez NODE:TMP1, <1
4543     |.  move NODE:TMP2, NODE:TMP1
4544     |  // End of hash chain: key not found, add a new one
4545     |
4546     |  // But check for __newindex first.
4547     |  ld TAB:TMP2, TAB:RB->metatable
4548     |  beqz TAB:TMP2, >6                // No metatable: continue.
4549     |.  daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv)
4550     |  lbu TMP0, TAB:TMP2->nomm
4551     |  andi TMP0, TMP0, 1<<MM_newindex
4552     |  beqz TMP0, ->vmeta_tsets         // 'no __newindex' flag NOT set: check.
4553     |6:
4554     |  load_got lj_tab_newkey
4555     |  sd RC, 0(CARG3)
4556     |   sd BASE, L->base
4557     |  move CARG2, TAB:RB
4558     |   sd PC, SAVE_PC
4559     |  call_intern lj_tab_newkey        // (lua_State *L, GCtab *t, TValue *k
4560     |.  move CARG1, L
4561     |  // Returns TValue *.
4562     |  ld BASE, L->base
4563     |.if FPU
4564     |  b <3                             // No 2nd write barrier needed.
4565     |.  sdc1 FTMP0, 0(CRET1)
4566     |.else
4567     |  ld CARG1, 0(RA)
4568     |  b <3                             // No 2nd write barrier needed.
4569     |.  sd CARG1, 0(CRET1)
4570     |.endif
4571     |
4572     |7:  // Possible table write barrier for the value. Skip valiswhite check.
4573     |  barrierback TAB:RB, TMP3, TMP0, <3
4574     break;
4575   case BC_TSETB:
4576     |  // RA = src*8, RB = table*8, RC = index*8
4577     |  decode_RB8a RB, INS
4578     |  decode_RB8b RB
4579     |  daddu CARG2, BASE, RB
4580     |   decode_RDtoRC8 RC, RD
4581     |  ld TAB:RB, 0(CARG2)
4582     |   daddu RA, BASE, RA
4583     |  srl TMP0, RC, 3
4584     |  checktab RB, ->vmeta_tsetb
4585     |  lw TMP1, TAB:RB->asize
4586     |   ld TMP2, TAB:RB->array
4587     |  sltu AT, TMP0, TMP1
4588     |  beqz AT, ->vmeta_tsetb
4589     |.  daddu RC, TMP2, RC
4590     |  ld TMP1, 0(RC)
4591     |   lbu TMP3, TAB:RB->marked
4592     |  beq TMP1, TISNIL, >5
4593     |1:
4594     |.  ld CRET1, 0(RA)
4595     |  andi AT, TMP3, LJ_GC_BLACK       // isblack(table)
4596     |  bnez AT, >7
4597     |.   sd CRET1, 0(RC)
4598     |2:
4599     |  ins_next
4600     |
4601     |5:  // Check for __newindex if previous value is nil.
4602     |  ld TAB:TMP2, TAB:RB->metatable
4603     |  beqz TAB:TMP2, <1                // No metatable: done.
4604     |.  nop
4605     |  lbu TMP1, TAB:TMP2->nomm
4606     |  andi TMP1, TMP1, 1<<MM_newindex
4607     |  bnez TMP1, <1                    // 'no __newindex' flag set: done.
4608     |.  nop
4609     |  b ->vmeta_tsetb                  // Caveat: preserve TMP0 and CARG2!
4610     |.  nop
4611     |
4612     |7:  // Possible table write barrier for the value. Skip valiswhite check.
4613     |  barrierback TAB:RB, TMP3, TMP0, <2
4614     break;
4615   case BC_TSETR:
4616     |  // RA = dst*8, RB = table*8, RC = key*8
4617     |  decode_RB8a RB, INS
4618     |  decode_RB8b RB
4619     |   decode_RDtoRC8 RC, RD
4620     |  daddu CARG1, BASE, RB
4621     |   daddu CARG3, BASE, RC
4622     |  ld TAB:CARG2, 0(CARG1)
4623     |   lw CARG3, LO(CARG3)
4624     |  cleartp TAB:CARG2
4625     |  lbu TMP3, TAB:CARG2->marked
4626     |   lw TMP0, TAB:CARG2->asize
4627     |    ld TMP1, TAB:CARG2->array
4628     |  andi AT, TMP3, LJ_GC_BLACK       // isblack(table)
4629     |  bnez AT, >7
4630     |.  daddu RA, BASE, RA
4631     |2:
4632     |  sltu AT, CARG3, TMP0
4633     |   sll TMP2, CARG3, 3
4634     |  beqz AT, ->vmeta_tsetr           // In array part?
4635     |.  daddu CRET1, TMP1, TMP2
4636     |->BC_TSETR_Z:
4637     |  ld CARG1, 0(RA)
4638     |  ins_next1
4639     |  sd CARG1, 0(CRET1)
4640     |  ins_next2
4641     |
4642     |7:  // Possible table write barrier for the value. Skip valiswhite check.
4643     |  barrierback TAB:CARG2, TMP3, CRET1, <2
4644     break;
4646   case BC_TSETM:
4647     |  // RA = base*8 (table at base-1), RD = num_const*8 (start index)
4648     |  daddu RA, BASE, RA
4649     |1:
4650     |   daddu TMP3, KBASE, RD
4651     |  ld TAB:CARG2, -8(RA)             // Guaranteed to be a table.
4652     |    addiu TMP0, MULTRES, -8
4653     |   lw TMP3, LO(TMP3)               // Integer constant is in lo-word.
4654     |    beqz TMP0, >4                  // Nothing to copy?
4655     |.    srl CARG3, TMP0, 3
4656     |  cleartp CARG2
4657     |  addu CARG3, CARG3, TMP3
4658     |  lw TMP2, TAB:CARG2->asize
4659     |   sll TMP1, TMP3, 3
4660     |    lbu TMP3, TAB:CARG2->marked
4661     |   ld CARG1, TAB:CARG2->array
4662     |  sltu AT, TMP2, CARG3
4663     |  bnez AT, >5
4664     |.  daddu TMP2, RA, TMP0
4665     |   daddu TMP1, TMP1, CARG1
4666     |  andi TMP0, TMP3, LJ_GC_BLACK     // isblack(table)
4667     |3:  // Copy result slots to table.
4668     |   ld CRET1, 0(RA)
4669     |    daddiu RA, RA, 8
4670     |  sltu AT, RA, TMP2
4671     |   sd CRET1, 0(TMP1)
4672     |  bnez AT, <3
4673     |.   daddiu TMP1, TMP1, 8
4674     |  bnez TMP0, >7
4675     |.  nop
4676     |4:
4677     |  ins_next
4678     |
4679     |5:  // Need to resize array part.
4680     |  load_got lj_tab_reasize
4681     |   sd BASE, L->base
4682     |   sd PC, SAVE_PC
4683     |  move BASE, RD
4684     |  call_intern lj_tab_reasize       // (lua_State *L, GCtab *t, int nasize)
4685     |.  move CARG1, L
4686     |  // Must not reallocate the stack.
4687     |  move RD, BASE
4688     |  b <1
4689     |.  ld BASE, L->base        // Reload BASE for lack of a saved register.
4690     |
4691     |7:  // Possible table write barrier for any value. Skip valiswhite check.
4692     |  barrierback TAB:CARG2, TMP3, TMP0, <4
4693     break;
4695   /* -- Calls and vararg handling ----------------------------------------- */
4697   case BC_CALLM:
4698     |  // RA = base*8, (RB = (nresults+1)*8,) RC = extra_nargs*8
4699     |  decode_RDtoRC8 NARGS8:RC, RD
4700     |  b ->BC_CALL_Z
4701     |.  addu NARGS8:RC, NARGS8:RC, MULTRES
4702     break;
4703   case BC_CALL:
4704     |  // RA = base*8, (RB = (nresults+1)*8,) RC = (nargs+1)*8
4705     |  decode_RDtoRC8 NARGS8:RC, RD
4706     |->BC_CALL_Z:
4707     |  move TMP2, BASE
4708     |  daddu BASE, BASE, RA
4709     |   ld LFUNC:RB, 0(BASE)
4710     |   daddiu BASE, BASE, 16
4711     |  addiu NARGS8:RC, NARGS8:RC, -8
4712     |  checkfunc RB, ->vmeta_call
4713     |  ins_call
4714     break;
4716   case BC_CALLMT:
4717     |  // RA = base*8, (RB = 0,) RC = extra_nargs*8
4718     |  addu NARGS8:RD, NARGS8:RD, MULTRES       // BC_CALLT gets RC from RD.
4719     |  // Fall through. Assumes BC_CALLT follows.
4720     break;
4721   case BC_CALLT:
4722     |  // RA = base*8, (RB = 0,) RC = (nargs+1)*8
4723     |  daddu RA, BASE, RA
4724     |  ld RB, 0(RA)
4725     |   move NARGS8:RC, RD
4726     |    ld TMP1, FRAME_PC(BASE)
4727     |   daddiu RA, RA, 16
4728     |  addiu NARGS8:RC, NARGS8:RC, -8
4729     |  checktp CARG3, RB, -LJ_TFUNC, ->vmeta_callt
4730     |->BC_CALLT_Z:
4731     |  andi TMP0, TMP1, FRAME_TYPE      // Caveat: preserve TMP0 until the 'or'.
4732     |   lbu TMP3, LFUNC:CARG3->ffid
4733     |  bnez TMP0, >7
4734     |.  xori TMP2, TMP1, FRAME_VARG
4735     |1:
4736     |  sd RB, FRAME_FUNC(BASE)          // Copy function down, but keep PC.
4737     |  sltiu AT, TMP3, 2                // (> FF_C) Calling a fast function?
4738     |  move TMP2, BASE
4739     |  move RB, CARG3
4740     |  beqz NARGS8:RC, >3
4741     |.  move TMP3, NARGS8:RC
4742     |2:
4743     |   ld CRET1, 0(RA)
4744     |    daddiu RA, RA, 8
4745     |  addiu TMP3, TMP3, -8
4746     |   sd CRET1, 0(TMP2)
4747     |  bnez TMP3, <2
4748     |.   daddiu TMP2, TMP2, 8
4749     |3:
4750     |  or TMP0, TMP0, AT
4751     |  beqz TMP0, >5
4752     |.  nop
4753     |4:
4754     |  ins_callt
4755     |
4756     |5:  // Tailcall to a fast function with a Lua frame below.
4757     |  lw INS, -4(TMP1)
4758     |  decode_RA8a RA, INS
4759     |  decode_RA8b RA
4760     |  dsubu TMP1, BASE, RA
4761     |  ld TMP1, -32(TMP1)
4762     |  cleartp LFUNC:TMP1
4763     |  ld TMP1, LFUNC:TMP1->pc
4764     |  b <4
4765     |.  ld KBASE, PC2PROTO(k)(TMP1)     // Need to prepare KBASE.
4766     |
4767     |7:  // Tailcall from a vararg function.
4768     |  andi AT, TMP2, FRAME_TYPEP
4769     |  bnez AT, <1                      // Vararg frame below?
4770     |.  dsubu TMP2, BASE, TMP2          // Relocate BASE down.
4771     |  move BASE, TMP2
4772     |  ld TMP1, FRAME_PC(TMP2)
4773     |  b <1
4774     |.  andi TMP0, TMP1, FRAME_TYPE
4775     break;
4777   case BC_ITERC:
4778     |  // RA = base*8, (RB = (nresults+1)*8, RC = (nargs+1)*8 ((2+1)*8))
4779     |  move TMP2, BASE                  // Save old BASE fir vmeta_call.
4780     |  daddu BASE, BASE, RA
4781     |  ld RB, -24(BASE)
4782     |   ld CARG1, -16(BASE)
4783     |    ld CARG2, -8(BASE)
4784     |  li NARGS8:RC, 16                 // Iterators get 2 arguments.
4785     |  sd RB, 0(BASE)                   // Copy callable.
4786     |   sd CARG1, 16(BASE)              // Copy state.
4787     |    sd CARG2, 24(BASE)             // Copy control var.
4788     |   daddiu BASE, BASE, 16
4789     |  checkfunc RB, ->vmeta_call
4790     |  ins_call
4791     break;
4793   case BC_ITERN:
4794     |.if JIT and ENDIAN_LE
4795     |  hotloop
4796     |.endif
4797     |->vm_IITERN:
4798     |  // RA = base*8, (RB = (nresults+1)*8, RC = (nargs+1)*8 (2+1)*8)
4799     |  daddu RA, BASE, RA
4800     |  ld TAB:RB, -16(RA)
4801     |   lw RC, -8+LO(RA)                // Get index from control var.
4802     |  cleartp TAB:RB
4803     |   daddiu PC, PC, 4
4804     |  lw TMP0, TAB:RB->asize
4805     |   ld TMP1, TAB:RB->array
4806     |  dsll CARG3, TISNUM, 47
4807     |1:  // Traverse array part.
4808     |  sltu AT, RC, TMP0
4809     |  beqz AT, >5                      // Index points after array part?
4810     |.  sll TMP3, RC, 3
4811     |  daddu TMP3, TMP1, TMP3
4812     |  ld CARG1, 0(TMP3)
4813     |     lhu RD, -4+OFS_RD(PC)
4814     |   or TMP2, RC, CARG3
4815     |  beq CARG1, TISNIL, <1            // Skip holes in array part.
4816     |.  addiu RC, RC, 1
4817     |   sd TMP2, 0(RA)
4818     |  sd CARG1, 8(RA)
4819     |     lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
4820     |     decode_RD4b RD
4821     |     daddu RD, RD, TMP3
4822     |   sw RC, -8+LO(RA)                // Update control var.
4823     |     daddu PC, PC, RD
4824     |3:
4825     |  ins_next
4826     |
4827     |5:  // Traverse hash part.
4828     |  lw TMP1, TAB:RB->hmask
4829     |  subu RC, RC, TMP0
4830     |   ld TMP2, TAB:RB->node
4831     |6:
4832     |  sltu AT, TMP1, RC                // End of iteration? Branch to ITERL+1.
4833     |  bnez AT, <3
4834     |.  sll TMP3, RC, 5
4835     |   sll RB, RC, 3
4836     |   subu TMP3, TMP3, RB
4837     |  daddu NODE:TMP3, TMP3, TMP2
4838     |  ld CARG1, 0(NODE:TMP3)
4839     |     lhu RD, -4+OFS_RD(PC)
4840     |  beq CARG1, TISNIL, <6            // Skip holes in hash part.
4841     |.  addiu RC, RC, 1
4842     |  ld CARG2, NODE:TMP3->key
4843     |     lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
4844     |  sd CARG1, 8(RA)
4845     |    addu RC, RC, TMP0
4846     |     decode_RD4b RD
4847     |     addu RD, RD, TMP3
4848     |  sd CARG2, 0(RA)
4849     |     daddu PC, PC, RD
4850     |  b <3
4851     |.  sw RC, -8+LO(RA)                // Update control var.
4852     break;
4854   case BC_ISNEXT:
4855     |  // RA = base*8, RD = target (points to ITERN)
4856     |  daddu RA, BASE, RA
4857     |    srl TMP0, RD, 1
4858     |  ld CFUNC:CARG1, -24(RA)
4859     |    daddu TMP0, PC, TMP0
4860     |   ld CARG2, -16(RA)
4861     |   ld CARG3, -8(RA)
4862     |    lui TMP2, (-(BCBIAS_J*4 >> 16) & 65535)
4863     |  checkfunc CFUNC:CARG1, >5
4864     |  gettp CARG2, CARG2
4865     |  daddiu CARG2, CARG2, -LJ_TTAB
4866     |  lbu TMP1, CFUNC:CARG1->ffid
4867     |  daddiu CARG3, CARG3, -LJ_TNIL
4868     |  or AT, CARG2, CARG3
4869     |  daddiu TMP1, TMP1, -FF_next_N
4870     |  or AT, AT, TMP1
4871     |  bnez AT, >5
4872     |.  lui TMP1, (LJ_KEYINDEX >> 16)
4873     |  daddu PC, TMP0, TMP2
4874     |  ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff)
4875     |  dsll TMP1, TMP1, 32
4876     |  sd TMP1, -8(RA)
4877     |1:
4878     |  ins_next
4879     |5:  // Despecialize bytecode if any of the checks fail.
4880     |  li TMP3, BC_JMP
4881     |   li TMP1, BC_ITERC
4882     |  sb TMP3, -4+OFS_OP(PC)
4883     |   daddu PC, TMP0, TMP2
4884     |.if JIT
4885     |  lb TMP0, OFS_OP(PC)
4886     |  li AT, BC_ITERN
4887     |  bne TMP0, AT, >6
4888     |.  lhu TMP2, OFS_RD(PC)
4889     |.endif
4890     |  b <1
4891     |.  sb TMP1, OFS_OP(PC)
4892     |.if JIT
4893     |6:  // Unpatch JLOOP.
4894     |  ld TMP0, DISPATCH_J(trace)(DISPATCH)
4895     |   sll TMP2, TMP2, 3
4896     |  daddu TMP0, TMP0, TMP2
4897     |  ld TRACE:TMP2, 0(TMP0)
4898     |  lw TMP0, TRACE:TMP2->startins
4899     |   li AT, -256
4900     |  and TMP0, TMP0, AT
4901     |  or TMP0, TMP0, TMP1
4902     |  b <1
4903     |.  sw TMP0, 0(PC)
4904     |.endif
4905     break;
4907   case BC_VARG:
4908     |  // RA = base*8, RB = (nresults+1)*8, RC = numparams*8
4909     |  ld TMP0, FRAME_PC(BASE)
4910     |  decode_RDtoRC8 RC, RD
4911     |   decode_RB8a RB, INS
4912     |  daddu RC, BASE, RC
4913     |   decode_RB8b RB
4914     |   daddu RA, BASE, RA
4915     |  daddiu RC, RC, FRAME_VARG
4916     |   daddu TMP2, RA, RB
4917     |  daddiu TMP3, BASE, -16           // TMP3 = vtop
4918     |  dsubu RC, RC, TMP0               // RC = vbase
4919     |  // Note: RC may now be even _above_ BASE if nargs was < numparams.
4920     |  beqz RB, >5                      // Copy all varargs?
4921     |.  dsubu TMP1, TMP3, RC
4922     |  daddiu TMP2, TMP2, -16
4923     |1:  // Copy vararg slots to destination slots.
4924     |  ld CARG1, 0(RC)
4925     |  sltu AT, RC, TMP3
4926     |    daddiu RC, RC, 8
4927     |.if MIPSR6
4928     |  selnez CARG1, CARG1, AT
4929     |  seleqz AT, TISNIL, AT
4930     |  or CARG1, CARG1, AT
4931     |.else
4932     |  movz CARG1, TISNIL, AT
4933     |.endif
4934     |  sd CARG1, 0(RA)
4935     |  sltu AT, RA, TMP2
4936     |  bnez AT, <1
4937     |.   daddiu RA, RA, 8
4938     |3:
4939     |  ins_next
4940     |
4941     |5:  // Copy all varargs.
4942     |  ld TMP0, L->maxstack
4943     |  blez TMP1, <3                    // No vararg slots?
4944     |.  li MULTRES, 8                   // MULTRES = (0+1)*8
4945     |  daddu TMP2, RA, TMP1
4946     |  sltu AT, TMP0, TMP2
4947     |  bnez AT, >7
4948     |.  daddiu MULTRES, TMP1, 8
4949     |6:
4950     |  ld CRET1, 0(RC)
4951     |   daddiu RC, RC, 8
4952     |  sd CRET1, 0(RA)
4953     |  sltu AT, RC, TMP3
4954     |  bnez AT, <6                      // More vararg slots?
4955     |.  daddiu RA, RA, 8
4956     |  b <3
4957     |.  nop
4958     |
4959     |7:  // Grow stack for varargs.
4960     |  load_got lj_state_growstack
4961     |   sd RA, L->top
4962     |  dsubu RA, RA, BASE
4963     |   sd BASE, L->base
4964     |  dsubu BASE, RC, BASE             // Need delta, because BASE may change.
4965     |   sd PC, SAVE_PC
4966     |  srl CARG2, TMP1, 3
4967     |  call_intern lj_state_growstack   // (lua_State *L, int n)
4968     |.  move CARG1, L
4969     |  move RC, BASE
4970     |  ld BASE, L->base
4971     |  daddu RA, BASE, RA
4972     |  daddu RC, BASE, RC
4973     |  b <6
4974     |.  daddiu TMP3, BASE, -16
4975     break;
4977   /* -- Returns ----------------------------------------------------------- */
4979   case BC_RETM:
4980     |  // RA = results*8, RD = extra_nresults*8
4981     |  addu RD, RD, MULTRES             // MULTRES >= 8, so RD >= 8.
4982     |  // Fall through. Assumes BC_RET follows.
4983     break;
4985   case BC_RET:
4986     |  // RA = results*8, RD = (nresults+1)*8
4987     |  ld PC, FRAME_PC(BASE)
4988     |   daddu RA, BASE, RA
4989     |    move MULTRES, RD
4990     |1:
4991     |  andi TMP0, PC, FRAME_TYPE
4992     |  bnez TMP0, ->BC_RETV_Z
4993     |.  xori TMP1, PC, FRAME_VARG
4994     |
4995     |->BC_RET_Z:
4996     |  // BASE = base, RA = resultptr, RD = (nresults+1)*8, PC = return
4997     |   lw INS, -4(PC)
4998     |    daddiu TMP2, BASE, -16
4999     |    daddiu RC, RD, -8
5000     |  decode_RA8a TMP0, INS
5001     |   decode_RB8a RB, INS
5002     |  decode_RA8b TMP0
5003     |   decode_RB8b RB
5004     |   daddu TMP3, TMP2, RB
5005     |  beqz RC, >3
5006     |.  dsubu BASE, TMP2, TMP0
5007     |2:
5008     |   ld CRET1, 0(RA)
5009     |    daddiu RA, RA, 8
5010     |  daddiu RC, RC, -8
5011     |   sd CRET1, 0(TMP2)
5012     |  bnez RC, <2
5013     |.   daddiu TMP2, TMP2, 8
5014     |3:
5015     |  daddiu TMP3, TMP3, -8
5016     |5:
5017     |  sltu AT, TMP2, TMP3
5018     |  bnez AT, >6
5019     |.  ld LFUNC:TMP1, FRAME_FUNC(BASE)
5020     |  ins_next1
5021     |  cleartp LFUNC:TMP1
5022     |  ld TMP1, LFUNC:TMP1->pc
5023     |  ld KBASE, PC2PROTO(k)(TMP1)
5024     |  ins_next2
5025     |
5026     |6:  // Fill up results with nil.
5027     |  sd TISNIL, 0(TMP2)
5028     |  b <5
5029     |.  daddiu TMP2, TMP2, 8
5030     |
5031     |->BC_RETV_Z:  // Non-standard return case.
5032     |  andi TMP2, TMP1, FRAME_TYPEP
5033     |  bnez TMP2, ->vm_return
5034     |.  nop
5035     |  // Return from vararg function: relocate BASE down.
5036     |  dsubu BASE, BASE, TMP1
5037     |  b <1
5038     |.  ld PC, FRAME_PC(BASE)
5039     break;
5041   case BC_RET0: case BC_RET1:
5042     |  // RA = results*8, RD = (nresults+1)*8
5043     |  ld PC, FRAME_PC(BASE)
5044     |   daddu RA, BASE, RA
5045     |    move MULTRES, RD
5046     |  andi TMP0, PC, FRAME_TYPE
5047     |  bnez TMP0, ->BC_RETV_Z
5048     |.  xori TMP1, PC, FRAME_VARG
5049     |  lw INS, -4(PC)
5050     |   daddiu TMP2, BASE, -16
5051     if (op == BC_RET1) {
5052       |  ld CRET1, 0(RA)
5053     }
5054     |  decode_RB8a RB, INS
5055     |   decode_RA8a RA, INS
5056     |  decode_RB8b RB
5057     |   decode_RA8b RA
5058     |   dsubu BASE, TMP2, RA
5059     if (op == BC_RET1) {
5060       |  sd CRET1, 0(TMP2)
5061     }
5062     |5:
5063     |  sltu AT, RD, RB
5064     |  bnez AT, >6
5065     |.  ld TMP1, FRAME_FUNC(BASE)
5066     |  ins_next1
5067     |  cleartp LFUNC:TMP1
5068     |  ld TMP1, LFUNC:TMP1->pc
5069     |  ld KBASE, PC2PROTO(k)(TMP1)
5070     |  ins_next2
5071     |
5072     |6:  // Fill up results with nil.
5073     |  daddiu TMP2, TMP2, 8
5074     |  daddiu RD, RD, 8
5075     |  b <5
5076     if (op == BC_RET1) {
5077       |.  sd TISNIL, 0(TMP2)
5078     } else {
5079       |.  sd TISNIL, -8(TMP2)
5080     }
5081     break;
5083   /* -- Loops and branches ------------------------------------------------ */
5085   case BC_FORL:
5086     |.if JIT
5087     |  hotloop
5088     |.endif
5089     |  // Fall through. Assumes BC_IFORL follows.
5090     break;
5092   case BC_JFORI:
5093   case BC_JFORL:
5094 #if !LJ_HASJIT
5095     break;
5096 #endif
5097   case BC_FORI:
5098   case BC_IFORL:
5099     |  // RA = base*8, RD = target (after end of loop or start of loop)
5100     vk = (op == BC_IFORL || op == BC_JFORL);
5101     |  daddu RA, BASE, RA
5102     |  ld CARG1, FORL_IDX*8(RA)         // IDX CARG1 - CARG3 type
5103     |  gettp CARG3, CARG1
5104     if (op != BC_JFORL) {
5105       |  srl RD, RD, 1
5106       |  lui TMP2, (-(BCBIAS_J*4 >> 16) & 65535)
5107       |  daddu TMP2, RD, TMP2
5108     }
5109     if (!vk) {
5110       |  ld CARG2, FORL_STOP*8(RA)      // STOP CARG2 - CARG4 type
5111       |  ld CRET1, FORL_STEP*8(RA)      // STEP CRET1 - CRET2 type
5112       |  gettp CARG4, CARG2
5113       |  bne CARG3, TISNUM, >5
5114       |.  gettp CRET2, CRET1
5115       |  bne CARG4, TISNUM, ->vmeta_for
5116       |.  sextw CARG3, CARG1
5117       |  bne CRET2, TISNUM, ->vmeta_for
5118       |.  sextw CARG2, CARG2
5119       |  dext AT, CRET1, 31, 0
5120       |  slt CRET1, CARG2, CARG3
5121       |  slt TMP1, CARG3, CARG2
5122       |.if MIPSR6
5123       |  selnez TMP1, TMP1, AT
5124       |  seleqz CRET1, CRET1, AT
5125       |  or CRET1, CRET1, TMP1
5126       |.else
5127       |  movn CRET1, TMP1, AT
5128       |.endif
5129     } else {
5130       |  bne CARG3, TISNUM, >5
5131       |.  ld CARG2, FORL_STEP*8(RA)     // STEP CARG2 - CARG4 type
5132       |    ld CRET1, FORL_STOP*8(RA)    // STOP CRET1 - CRET2 type
5133       |  sextw TMP3, CARG1
5134       |   sextw CARG2, CARG2
5135       |    sextw CRET1, CRET1
5136       |  addu CARG1, TMP3, CARG2
5137       |  xor TMP0, CARG1, TMP3
5138       |  xor TMP1, CARG1, CARG2
5139       |  and TMP0, TMP0, TMP1
5140       |  slt TMP1, CARG1, CRET1
5141       |  slt CRET1, CRET1, CARG1
5142       |  slt AT, CARG2, r0
5143       |   slt TMP0, TMP0, r0            // ((y^a) & (y^b)) < 0: overflow.
5144       |.if MIPSR6
5145       |  selnez TMP1, TMP1, AT
5146       |  seleqz CRET1, CRET1, AT
5147       |  or CRET1, CRET1, TMP1
5148       |.else
5149       |  movn CRET1, TMP1, AT
5150       |.endif
5151       |   or CRET1, CRET1, TMP0
5152       |  zextw CARG1, CARG1
5153       |  settp CARG1, TISNUM
5154     }
5155     |1:
5156     if (op == BC_FORI) {
5157       |.if MIPSR6
5158       |  selnez TMP2, TMP2, CRET1
5159       |.else
5160       |  movz TMP2, r0, CRET1
5161       |.endif
5162       |  daddu PC, PC, TMP2
5163     } else if (op == BC_JFORI) {
5164       |  daddu PC, PC, TMP2
5165       |  lhu RD, -4+OFS_RD(PC)
5166     } else if (op == BC_IFORL) {
5167       |.if MIPSR6
5168       |  seleqz TMP2, TMP2, CRET1
5169       |.else
5170       |  movn TMP2, r0, CRET1
5171       |.endif
5172       |  daddu PC, PC, TMP2
5173     }
5174     if (vk) {
5175       |  sd CARG1, FORL_IDX*8(RA)
5176     }
5177     |  ins_next1
5178     |  sd CARG1, FORL_EXT*8(RA)
5179     |2:
5180     if (op == BC_JFORI) {
5181       |  beqz CRET1, =>BC_JLOOP
5182       |.  decode_RD8b RD
5183     } else if (op == BC_JFORL) {
5184       |  beqz CRET1, =>BC_JLOOP
5185     }
5186     |  ins_next2
5187     |
5188     |5:  // FP loop.
5189     |.if FPU
5190     if (!vk) {
5191       |  ldc1 f0, FORL_IDX*8(RA)
5192       |   ldc1 f2, FORL_STOP*8(RA)
5193       |  sltiu TMP0, CARG3, LJ_TISNUM
5194       |  sltiu TMP1, CARG4, LJ_TISNUM
5195       |  sltiu AT, CRET2, LJ_TISNUM
5196       |   ld TMP3, FORL_STEP*8(RA)
5197       |  and TMP0, TMP0, TMP1
5198       |  and AT, AT, TMP0
5199       |  beqz AT, ->vmeta_for
5200       |.  slt TMP3, TMP3, r0
5201       |.if MIPSR6
5202       |   dmtc1 TMP3, FTMP2
5203       |  cmp.lt.d FTMP0, f0, f2
5204       |  cmp.lt.d FTMP1, f2, f0
5205       |  sel.d FTMP2, FTMP1, FTMP0
5206       |  b <1
5207       |.  dmfc1 CRET1, FTMP2
5208       |.else
5209       |  c.ole.d 0, f0, f2
5210       |  c.ole.d 1, f2, f0
5211       |  li CRET1, 1
5212       |  movt CRET1, r0, 0
5213       |  movt AT, r0, 1
5214       |  b <1
5215       |.  movn CRET1, AT, TMP3
5216       |.endif
5217     } else {
5218       |  ldc1 f0, FORL_IDX*8(RA)
5219       |   ldc1 f4, FORL_STEP*8(RA)
5220       |    ldc1 f2, FORL_STOP*8(RA)
5221       |   ld TMP3, FORL_STEP*8(RA)
5222       |  add.d f0, f0, f4
5223       |.if MIPSR6
5224       |   slt TMP3, TMP3, r0
5225       |   dmtc1 TMP3, FTMP2
5226       |  cmp.lt.d FTMP0, f0, f2
5227       |  cmp.lt.d FTMP1, f2, f0
5228       |  sel.d FTMP2, FTMP1, FTMP0
5229       |  dmfc1 CRET1, FTMP2
5230       if (op == BC_IFORL) {
5231         |  seleqz TMP2, TMP2, CRET1
5232         |  daddu PC, PC, TMP2
5233       }
5234       |.else
5235       |  c.ole.d 0, f0, f2
5236       |  c.ole.d 1, f2, f0
5237       |   slt TMP3, TMP3, r0
5238       |  li CRET1, 1
5239       |  li AT, 1
5240       |  movt CRET1, r0, 0
5241       |  movt AT, r0, 1
5242       |  movn CRET1, AT, TMP3
5243       if (op == BC_IFORL) {
5244         |  movn TMP2, r0, CRET1
5245         |  daddu PC, PC, TMP2
5246       }
5247       |.endif
5248       |  sdc1 f0, FORL_IDX*8(RA)
5249       |  ins_next1
5250       |  b <2
5251       |.  sdc1 f0, FORL_EXT*8(RA)
5252     }
5253     |.else
5254     if (!vk) {
5255       |  sltiu TMP0, CARG3, LJ_TISNUM
5256       |  sltiu TMP1, CARG4, LJ_TISNUM
5257       |  sltiu AT, CRET2, LJ_TISNUM
5258       |  and TMP0, TMP0, TMP1
5259       |  and AT, AT, TMP0
5260       |  beqz AT, ->vmeta_for
5261       |.  nop
5262       |  bal ->vm_sfcmpolex
5263       |.  lw TMP3, FORL_STEP*8+HI(RA)
5264       |  b <1
5265       |.  nop
5266     } else {
5267       |  load_got __adddf3
5268       |  call_extern
5269       |.  sw TMP2, TMPD
5270       |  ld CARG2, FORL_STOP*8(RA)
5271       |  move CARG1, CRET1
5272       if ( op == BC_JFORL ) {
5273         |  lhu RD, -4+OFS_RD(PC)
5274         |  decode_RD8b RD
5275       }
5276       |  bal ->vm_sfcmpolex
5277       |.  lw TMP3, FORL_STEP*8+HI(RA)
5278       |  b <1
5279       |.  lw TMP2, TMPD
5280     }
5281     |.endif
5282     break;
5284   case BC_ITERL:
5285     |.if JIT
5286     |  hotloop
5287     |.endif
5288     |  // Fall through. Assumes BC_IITERL follows.
5289     break;
5291   case BC_JITERL:
5292 #if !LJ_HASJIT
5293     break;
5294 #endif
5295   case BC_IITERL:
5296     |  // RA = base*8, RD = target
5297     |  daddu RA, BASE, RA
5298     |  ld TMP1, 0(RA)
5299     |  beq TMP1, TISNIL, >1             // Stop if iterator returned nil.
5300     |.  nop
5301     if (op == BC_JITERL) {
5302       |  b =>BC_JLOOP
5303       |.  sd TMP1, -8(RA)
5304     } else {
5305       |  branch_RD                      // Otherwise save control var + branch.
5306       |  sd TMP1, -8(RA)
5307     }
5308     |1:
5309     |  ins_next
5310     break;
5312   case BC_LOOP:
5313     |  // RA = base*8, RD = target (loop extent)
5314     |  // Note: RA/RD is only used by trace recorder to determine scope/extent
5315     |  // This opcode does NOT jump, it's only purpose is to detect a hot loop.
5316     |.if JIT
5317     |  hotloop
5318     |.endif
5319     |  // Fall through. Assumes BC_ILOOP follows.
5320     break;
5322   case BC_ILOOP:
5323     |  // RA = base*8, RD = target (loop extent)
5324     |  ins_next
5325     break;
5327   case BC_JLOOP:
5328     |.if JIT
5329     |  // RA = base*8 (ignored), RD = traceno*8
5330     |  ld TMP1, DISPATCH_J(trace)(DISPATCH)
5331     |   li AT, 0
5332     |  daddu TMP1, TMP1, RD
5333     |  // Traces on MIPS don't store the trace number, so use 0.
5334     |   sd AT, DISPATCH_GL(vmstate)(DISPATCH)
5335     |  ld TRACE:TMP2, 0(TMP1)
5336     |   sd BASE, DISPATCH_GL(jit_base)(DISPATCH)
5337     |  ld TMP2, TRACE:TMP2->mcode
5338     |   sd L, DISPATCH_GL(tmpbuf.L)(DISPATCH)
5339     |  jr TMP2
5340     |.  daddiu JGL, DISPATCH, GG_DISP2G+32768
5341     |.endif
5342     break;
5344   case BC_JMP:
5345     |  // RA = base*8 (only used by trace recorder), RD = target
5346     |  branch_RD
5347     |  ins_next
5348     break;
5350   /* -- Function headers -------------------------------------------------- */
5352   case BC_FUNCF:
5353     |.if JIT
5354     |  hotcall
5355     |.endif
5356   case BC_FUNCV:  /* NYI: compiled vararg functions. */
5357     |  // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow.
5358     break;
5360   case BC_JFUNCF:
5361 #if !LJ_HASJIT
5362     break;
5363 #endif
5364   case BC_IFUNCF:
5365     |  // BASE = new base, RA = BASE+framesize*8, RB = LFUNC, RC = nargs*8
5366     |  ld TMP2, L->maxstack
5367     |   lbu TMP1, -4+PC2PROTO(numparams)(PC)
5368     |    ld KBASE, -4+PC2PROTO(k)(PC)
5369     |  sltu AT, TMP2, RA
5370     |  bnez AT, ->vm_growstack_l
5371     |.  sll TMP1, TMP1, 3
5372     if (op != BC_JFUNCF) {
5373       |  ins_next1
5374     }
5375     |2:
5376     |  sltu AT, NARGS8:RC, TMP1         // Check for missing parameters.
5377     |  bnez AT, >3
5378     |.  daddu AT, BASE, NARGS8:RC
5379     if (op == BC_JFUNCF) {
5380       |  decode_RD8a RD, INS
5381       |  b =>BC_JLOOP
5382       |.  decode_RD8b RD
5383     } else {
5384       |  ins_next2
5385     }
5386     |
5387     |3:  // Clear missing parameters.
5388     |  sd TISNIL, 0(AT)
5389     |  b <2
5390     |.  addiu NARGS8:RC, NARGS8:RC, 8
5391     break;
5393   case BC_JFUNCV:
5394 #if !LJ_HASJIT
5395     break;
5396 #endif
5397     |  NYI  // NYI: compiled vararg functions
5398     break;  /* NYI: compiled vararg functions. */
5400   case BC_IFUNCV:
5401     |  // BASE = new base, RA = BASE+framesize*8, RB = LFUNC, RC = nargs*8
5402     |   li TMP0, LJ_TFUNC
5403     |   daddu TMP1, BASE, RC
5404     |  ld TMP2, L->maxstack
5405     |   settp LFUNC:RB, TMP0
5406     |  daddu TMP0, RA, RC
5407     |   sd LFUNC:RB, 0(TMP1)            // Store (tagged) copy of LFUNC.
5408     |  daddiu TMP2, TMP2, -8
5409     |   daddiu TMP3, RC, 16+FRAME_VARG
5410     |  sltu AT, TMP0, TMP2
5411     |    ld KBASE, -4+PC2PROTO(k)(PC)
5412     |  beqz AT, ->vm_growstack_l
5413     |.  sd TMP3, 8(TMP1)                // Store delta + FRAME_VARG.
5414     |  lbu TMP2, -4+PC2PROTO(numparams)(PC)
5415     |   move RA, BASE
5416     |   move RC, TMP1
5417     |  ins_next1
5418     |  beqz TMP2, >3
5419     |.  daddiu BASE, TMP1, 16
5420     |1:
5421     |  ld TMP0, 0(RA)
5422     |  sltu AT, RA, RC                  // Less args than parameters?
5423     |  move CARG1, TMP0
5424     |.if MIPSR6
5425     |  selnez TMP0, TMP0, AT
5426     |  seleqz TMP3, TISNIL, AT
5427     |  or TMP0, TMP0, TMP3
5428     |  seleqz TMP3, CARG1, AT
5429     |  selnez CARG1, TISNIL, AT
5430     |  or CARG1, CARG1, TMP3
5431     |.else
5432     |  movz TMP0, TISNIL, AT            // Clear missing parameters.
5433     |  movn CARG1, TISNIL, AT           // Clear old fixarg slot (help the GC).
5434     |.endif
5435     |    addiu TMP2, TMP2, -1
5436     |  sd TMP0, 16(TMP1)
5437     |    daddiu TMP1, TMP1, 8
5438     |  sd CARG1, 0(RA)
5439     |  bnez TMP2, <1
5440     |.   daddiu RA, RA, 8
5441     |3:
5442     |  ins_next2
5443     break;
5445   case BC_FUNCC:
5446   case BC_FUNCCW:
5447     |  // BASE = new base, RA = BASE+framesize*8, RB = CFUNC, RC = nargs*8
5448     if (op == BC_FUNCC) {
5449       |  ld CFUNCADDR, CFUNC:RB->f
5450     } else {
5451       |  ld CFUNCADDR, DISPATCH_GL(wrapf)(DISPATCH)
5452     }
5453     |  daddu TMP1, RA, NARGS8:RC
5454     |  ld TMP2, L->maxstack
5455     |   daddu RC, BASE, NARGS8:RC
5456     |  sd BASE, L->base
5457     |  sltu AT, TMP2, TMP1
5458     |   sd RC, L->top
5459     |    li_vmstate C
5460     if (op == BC_FUNCCW) {
5461       |  ld CARG2, CFUNC:RB->f
5462     }
5463     |  bnez AT, ->vm_growstack_c        // Need to grow stack.
5464     |.  move CARG1, L
5465     |  jalr CFUNCADDR                   // (lua_State *L [, lua_CFunction f])
5466     |.   st_vmstate
5467     |  // Returns nresults.
5468     |  ld BASE, L->base
5469     |   sll RD, CRET1, 3
5470     |  ld TMP1, L->top
5471     |    li_vmstate INTERP
5472     |  ld PC, FRAME_PC(BASE)            // Fetch PC of caller.
5473     |   dsubu RA, TMP1, RD              // RA = L->top - nresults*8
5474     |    sd L, DISPATCH_GL(cur_L)(DISPATCH)
5475     |  b ->vm_returnc
5476     |.   st_vmstate
5477     break;
5479   /* ---------------------------------------------------------------------- */
5481   default:
5482     fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]);
5483     exit(2);
5484     break;
5485   }
5488 static int build_backend(BuildCtx *ctx)
5490   int op;
5492   dasm_growpc(Dst, BC__MAX);
5494   build_subroutines(ctx);
5496   |.code_op
5497   for (op = 0; op < BC__MAX; op++)
5498     build_ins(ctx, (BCOp)op, op);
5500   return BC__MAX;
5503 /* Emit pseudo frame-info for all assembler functions. */
5504 static void emit_asm_debug(BuildCtx *ctx)
5506   int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code);
5507   int i;
5508   switch (ctx->mode) {
5509   case BUILD_elfasm:
5510     fprintf(ctx->fp, "\t.section .debug_frame,\"\",@progbits\n");
5511     fprintf(ctx->fp,
5512         ".Lframe0:\n"
5513         "\t.4byte .LECIE0-.LSCIE0\n"
5514         ".LSCIE0:\n"
5515         "\t.4byte 0xffffffff\n"
5516         "\t.byte 0x1\n"
5517         "\t.string \"\"\n"
5518         "\t.uleb128 0x1\n"
5519         "\t.sleb128 -4\n"
5520         "\t.byte 31\n"
5521         "\t.byte 0xc\n\t.uleb128 29\n\t.uleb128 0\n"
5522         "\t.align 2\n"
5523         ".LECIE0:\n\n");
5524     fprintf(ctx->fp,
5525         ".LSFDE0:\n"
5526         "\t.4byte .LEFDE0-.LASFDE0\n"
5527         ".LASFDE0:\n"
5528         "\t.4byte .Lframe0\n"
5529         "\t.8byte .Lbegin\n"
5530         "\t.8byte %d\n"
5531         "\t.byte 0xe\n\t.uleb128 %d\n"
5532         "\t.byte 0x9f\n\t.sleb128 2*5\n"
5533         "\t.byte 0x9e\n\t.sleb128 2*6\n",
5534         fcofs, CFRAME_SIZE);
5535     for (i = 23; i >= 16; i--)
5536       fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+i, 2*(30-i));
5537 #if !LJ_SOFTFP
5538     for (i = 31; i >= 24; i--)
5539       fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+32+i, 2*(46-i));
5540 #endif
5541     fprintf(ctx->fp,
5542         "\t.align 2\n"
5543         ".LEFDE0:\n\n");
5544 #if LJ_HASFFI
5545     fprintf(ctx->fp,
5546         ".LSFDE1:\n"
5547         "\t.4byte .LEFDE1-.LASFDE1\n"
5548         ".LASFDE1:\n"
5549         "\t.4byte .Lframe0\n"
5550         "\t.4byte lj_vm_ffi_call\n"
5551         "\t.4byte %d\n"
5552         "\t.byte 0x9f\n\t.uleb128 2*1\n"
5553         "\t.byte 0x90\n\t.uleb128 2*2\n"
5554         "\t.byte 0xd\n\t.uleb128 0x10\n"
5555         "\t.align 2\n"
5556         ".LEFDE1:\n\n", (int)ctx->codesz - fcofs);
5557 #endif
5558 #if !LJ_NO_UNWIND
5559     /* NYI */
5560 #endif
5561     break;
5562   default:
5563     break;
5564   }