Merge branch 'master' into v2.1
[luajit-2.0.git] / src / vm_mips64.dasc
bloba8d20413774f8d53a1bf132d4bdf45bb0618fc7e
1 |// Low-level VM code for MIPS64 CPUs.
2 |// Bytecode interpreter, fast functions and helper functions.
3 |// Copyright (C) 2005-2023 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:RC, NARGS8:RC, -8
1424   |  bltz NARGS8:RC, ->fff_fallback
1425   |.   move TMP2, BASE
1426   |   daddiu BASE, BASE, 16
1427   |  // Remember active hook before pcall.
1428   |  srl TMP3, TMP3, HOOK_ACTIVE_SHIFT
1429   |  andi TMP3, TMP3, 1
1430   |  daddiu PC, TMP3, 16+FRAME_PCALL
1431   |  beqz NARGS8:RC, ->vm_call_dispatch
1432   |1:
1433   |.  daddu TMP0, BASE, NARGS8:RC
1434   |2:
1435   |  ld TMP1, -16(TMP0)
1436   |  sd TMP1, -8(TMP0)
1437   |  daddiu TMP0, TMP0, -8
1438   |  bne TMP0, BASE, <2
1439   |.  nop
1440   |  b ->vm_call_dispatch
1441   |.  nop
1442   |
1443   |.ffunc xpcall
1444   |  ld TMP1, L->maxstack
1445   |  daddu TMP2, BASE, NARGS8:RC
1446   |  sltu AT, TMP1, TMP2
1447   |  bnez AT, ->fff_fallback
1448   |.  ld CARG1, 0(BASE)
1449   |  daddiu NARGS8:TMP0, NARGS8:RC, -16
1450   |   ld CARG2, 8(BASE)
1451   |    bltz NARGS8:TMP0, ->fff_fallback
1452   |.    lbu TMP1, DISPATCH_GL(hookmask)(DISPATCH)
1453   |  gettp AT, CARG2
1454   |  daddiu AT, AT, -LJ_TFUNC
1455   |  bnez AT, ->fff_fallback            // Traceback must be a function.
1456   |.   move TMP2, BASE
1457   |  move NARGS8:RC, NARGS8:TMP0
1458   |   daddiu BASE, BASE, 24
1459   |  // Remember active hook before pcall.
1460   |  srl TMP3, TMP3, HOOK_ACTIVE_SHIFT
1461   |   sd CARG2, 0(TMP2)                 // Swap function and traceback.
1462   |  andi TMP3, TMP3, 1
1463   |   sd CARG1, 8(TMP2)
1464   |  beqz NARGS8:RC, ->vm_call_dispatch
1465   |.  daddiu PC, TMP3, 24+FRAME_PCALL
1466   |  b <1
1467   |.  nop
1468   |
1469   |//-- Coroutine library --------------------------------------------------
1470   |
1471   |.macro coroutine_resume_wrap, resume
1472   |.if resume
1473   |.ffunc_1 coroutine_resume
1474   |  checktp CARG1, CARG1, -LJ_TTHREAD, ->fff_fallback
1475   |.else
1476   |.ffunc coroutine_wrap_aux
1477   |  ld L:CARG1, CFUNC:RB->upvalue[0].gcr
1478   |  cleartp L:CARG1
1479   |.endif
1480   |  lbu TMP0, L:CARG1->status
1481   |   ld TMP1, L:CARG1->cframe
1482   |    ld CARG2, L:CARG1->top
1483   |    ld TMP2, L:CARG1->base
1484   |  addiu AT, TMP0, -LUA_YIELD
1485   |    daddu CARG3, CARG2, TMP0
1486   |   daddiu TMP3, CARG2, 8
1487   |.if MIPSR6
1488   |  seleqz CARG2, CARG2, AT
1489   |  selnez TMP3, TMP3, AT
1490   |  bgtz AT, ->fff_fallback            // st > LUA_YIELD?
1491   |.  or CARG2, TMP3, CARG2
1492   |.else
1493   |  bgtz AT, ->fff_fallback            // st > LUA_YIELD?
1494   |.  movn CARG2, TMP3, AT
1495   |.endif
1496   |   xor TMP2, TMP2, CARG3
1497   |  bnez TMP1, ->fff_fallback          // cframe != 0?
1498   |.  or AT, TMP2, TMP0
1499   |  ld TMP0, L:CARG1->maxstack
1500   |  beqz AT, ->fff_fallback            // base == top && st == 0?
1501   |.  ld PC, FRAME_PC(BASE)
1502   |  daddu TMP2, CARG2, NARGS8:RC
1503   |  sltu AT, TMP0, TMP2
1504   |  bnez AT, ->fff_fallback            // Stack overflow?
1505   |.  sd PC, SAVE_PC
1506   |   sd BASE, L->base
1507   |1:
1508   |.if resume
1509   |  daddiu BASE, BASE, 8               // Keep resumed thread in stack for GC.
1510   |  daddiu NARGS8:RC, NARGS8:RC, -8
1511   |  daddiu TMP2, TMP2, -8
1512   |.endif
1513   |  sd TMP2, L:CARG1->top
1514   |  daddu TMP1, BASE, NARGS8:RC
1515   |  move CARG3, CARG2
1516   |  sd BASE, L->top
1517   |2:  // Move args to coroutine.
1518   |   ld CRET1, 0(BASE)
1519   |  sltu AT, BASE, TMP1
1520   |  beqz AT, >3
1521   |.  daddiu BASE, BASE, 8
1522   |   sd CRET1, 0(CARG3)
1523   |  b <2
1524   |.  daddiu CARG3, CARG3, 8
1525   |3:
1526   |  bal ->vm_resume                    // (lua_State *L, TValue *base, 0, 0)
1527   |.  move L:RA, L:CARG1
1528   |  // Returns thread status.
1529   |4:
1530   |  ld TMP2, L:RA->base
1531   |   sltiu AT, CRET1, LUA_YIELD+1
1532   |  ld TMP3, L:RA->top
1533   |    li_vmstate INTERP
1534   |  ld BASE, L->base
1535   |    sd L, DISPATCH_GL(cur_L)(DISPATCH)
1536   |    st_vmstate
1537   |   beqz AT, >8
1538   |. dsubu RD, TMP3, TMP2
1539   |   ld TMP0, L->maxstack
1540   |  beqz RD, >6                        // No results?
1541   |.  daddu TMP1, BASE, RD
1542   |  sltu AT, TMP0, TMP1
1543   |  bnez AT, >9                        // Need to grow stack?
1544   |.  daddu TMP3, TMP2, RD
1545   |  sd TMP2, L:RA->top                 // Clear coroutine stack.
1546   |  move TMP1, BASE
1547   |5:  // Move results from coroutine.
1548   |   ld CRET1, 0(TMP2)
1549   |  daddiu TMP2, TMP2, 8
1550   |  sltu AT, TMP2, TMP3
1551   |   sd CRET1, 0(TMP1)
1552   |  bnez AT, <5
1553   |.  daddiu TMP1, TMP1, 8
1554   |6:
1555   |  andi TMP0, PC, FRAME_TYPE
1556   |.if resume
1557   |  mov_true TMP1
1558   |   daddiu RA, BASE, -8
1559   |  sd TMP1, -8(BASE)                  // Prepend true to results.
1560   |  daddiu RD, RD, 16
1561   |.else
1562   |  move RA, BASE
1563   |  daddiu RD, RD, 8
1564   |.endif
1565   |7:
1566   |  sd PC, SAVE_PC
1567   |  beqz TMP0, ->BC_RET_Z
1568   |.  move MULTRES, RD
1569   |  b ->vm_return
1570   |.  nop
1571   |
1572   |8:  // Coroutine returned with error (at co->top-1).
1573   |.if resume
1574   |  daddiu TMP3, TMP3, -8
1575   |   mov_false TMP1
1576   |  ld CRET1, 0(TMP3)
1577   |   sd TMP3, L:RA->top                // Remove error from coroutine stack.
1578   |    li RD, (2+1)*8
1579   |   sd TMP1, -8(BASE)                 // Prepend false to results.
1580   |    daddiu RA, BASE, -8
1581   |  sd CRET1, 0(BASE)                  // Copy error message.
1582   |  b <7
1583   |.  andi TMP0, PC, FRAME_TYPE
1584   |.else
1585   |  load_got lj_ffh_coroutine_wrap_err
1586   |  move CARG2, L:RA
1587   |  call_intern lj_ffh_coroutine_wrap_err  // (lua_State *L, lua_State *co)
1588   |.  move CARG1, L
1589   |.endif
1590   |
1591   |9:  // Handle stack expansion on return from yield.
1592   |  load_got lj_state_growstack
1593   |  srl CARG2, RD, 3
1594   |  call_intern lj_state_growstack     // (lua_State *L, int n)
1595   |.  move CARG1, L
1596   |  b <4
1597   |.  li CRET1, 0
1598   |.endmacro
1599   |
1600   |  coroutine_resume_wrap 1            // coroutine.resume
1601   |  coroutine_resume_wrap 0            // coroutine.wrap
1602   |
1603   |.ffunc coroutine_yield
1604   |  ld TMP0, L->cframe
1605   |   daddu TMP1, BASE, NARGS8:RC
1606   |   sd BASE, L->base
1607   |  andi TMP0, TMP0, CFRAME_RESUME
1608   |   sd TMP1, L->top
1609   |  beqz TMP0, ->fff_fallback
1610   |.   li CRET1, LUA_YIELD
1611   |  sd r0, L->cframe
1612   |  b ->vm_leave_unw
1613   |.   sb CRET1, L->status
1614   |
1615   |//-- Math library -------------------------------------------------------
1616   |
1617   |.ffunc_1 math_abs
1618   |  gettp CARG2, CARG1
1619   |  daddiu AT, CARG2, -LJ_TISNUM
1620   |  bnez AT, >1
1621   |.  sextw TMP1, CARG1
1622   |  sra TMP0, TMP1, 31                 // Extract sign.
1623   |  xor TMP1, TMP1, TMP0
1624   |  dsubu CARG1, TMP1, TMP0
1625   |  dsll TMP3, CARG1, 32
1626   |  bgez TMP3, ->fff_restv
1627   |.  settp CARG1, TISNUM
1628   |  li CARG1, 0x41e0                   // 2^31 as a double.
1629   |  b ->fff_restv
1630   |.  dsll CARG1, CARG1, 48
1631   |1:
1632   |  sltiu AT, CARG2, LJ_TISNUM
1633   |  beqz AT, ->fff_fallback
1634   |.  dextm CARG1, CARG1, 0, 30
1635   |// fallthrough
1636   |
1637   |->fff_restv:
1638   |  // CARG1 = TValue result.
1639   |  ld PC, FRAME_PC(BASE)
1640   |  daddiu RA, BASE, -16
1641   |   sd CARG1, -16(BASE)
1642   |->fff_res1:
1643   |  // RA = results, PC = return.
1644   |  li RD, (1+1)*8
1645   |->fff_res:
1646   |  // RA = results, RD = (nresults+1)*8, PC = return.
1647   |  andi TMP0, PC, FRAME_TYPE
1648   |  bnez TMP0, ->vm_return
1649   |.  move MULTRES, RD
1650   |  lw INS, -4(PC)
1651   |  decode_RB8a RB, INS
1652   |  decode_RB8b RB
1653   |5:
1654   |  sltu AT, RD, RB
1655   |  bnez AT, >6                        // More results expected?
1656   |.  decode_RA8a TMP0, INS
1657   |  decode_RA8b TMP0
1658   |  ins_next1
1659   |  // Adjust BASE. KBASE is assumed to be set for the calling frame.
1660   |   dsubu BASE, RA, TMP0
1661   |  ins_next2
1662   |
1663   |6:  // Fill up results with nil.
1664   |  daddu TMP1, RA, RD
1665   |   daddiu RD, RD, 8
1666   |  b <5
1667   |.  sd TISNIL, -8(TMP1)
1668   |
1669   |.macro math_extern, func
1670   |  .ffunc_n math_ .. func
1671   |  load_got func
1672   |  call_extern
1673   |.  nop
1674   |  b ->fff_resn
1675   |.  nop
1676   |.endmacro
1677   |
1678   |.macro math_extern2, func
1679   |  .ffunc_nn math_ .. func
1680   |.  load_got func
1681   |  call_extern
1682   |.  nop
1683   |  b ->fff_resn
1684   |.  nop
1685   |.endmacro
1686   |
1687   |// TODO: Return integer type if result is integer (own sf implementation).
1688   |.macro math_round, func
1689   |->ff_math_ .. func:
1690   |  ld CARG1, 0(BASE)
1691   |  beqz NARGS8:RC, ->fff_fallback
1692   |.  gettp TMP0, CARG1
1693   |  beq TMP0, TISNUM, ->fff_restv
1694   |.  sltu AT, TMP0, TISNUM
1695   |  beqz AT, ->fff_fallback
1696   |.if FPU
1697   |.  ldc1 FARG1, 0(BASE)
1698   |  bal ->vm_ .. func
1699   |.  nop
1700   |.else
1701   |.  load_got func
1702   |  call_extern
1703   |.  nop
1704   |.endif
1705   |  b ->fff_resn
1706   |.  nop
1707   |.endmacro
1708   |
1709   |  math_round floor
1710   |  math_round ceil
1711   |
1712   |.ffunc math_log
1713   |  li AT, 8
1714   |  bne NARGS8:RC, AT, ->fff_fallback  // Exactly 1 argument.
1715   |.  ld CARG1, 0(BASE)
1716   |  checknum CARG1, ->fff_fallback
1717   |.  load_got log
1718   |.if FPU
1719   |  call_extern
1720   |.  ldc1 FARG1, 0(BASE)
1721   |.else
1722   |  call_extern
1723   |.  nop
1724   |.endif
1725   |  b ->fff_resn
1726   |.  nop
1727   |
1728   |  math_extern log10
1729   |  math_extern exp
1730   |  math_extern sin
1731   |  math_extern cos
1732   |  math_extern tan
1733   |  math_extern asin
1734   |  math_extern acos
1735   |  math_extern atan
1736   |  math_extern sinh
1737   |  math_extern cosh
1738   |  math_extern tanh
1739   |  math_extern2 pow
1740   |  math_extern2 atan2
1741   |  math_extern2 fmod
1742   |
1743   |.if FPU
1744   |.ffunc_n math_sqrt
1745   |.  sqrt.d FRET1, FARG1
1746   |// fallthrough to ->fff_resn
1747   |.else
1748   |  math_extern sqrt
1749   |.endif
1750   |
1751   |->fff_resn:
1752   |  ld PC, FRAME_PC(BASE)
1753   |  daddiu RA, BASE, -16
1754   |  b ->fff_res1
1755   |.if FPU
1756   |.  sdc1 FRET1, 0(RA)
1757   |.else
1758   |.  sd CRET1, 0(RA)
1759   |.endif
1760   |
1761   |
1762   |.ffunc_2 math_ldexp
1763   |  checknum CARG1, ->fff_fallback
1764   |  checkint CARG2, ->fff_fallback
1765   |.  load_got ldexp
1766   |  .FPU ldc1 FARG1, 0(BASE)
1767   |  call_extern
1768   |.  lw CARG2, 8+LO(BASE)
1769   |  b ->fff_resn
1770   |.  nop
1771   |
1772   |.ffunc_n math_frexp
1773   |  load_got frexp
1774   |   ld PC, FRAME_PC(BASE)
1775   |  call_extern
1776   |.  daddiu CARG2, DISPATCH, DISPATCH_GL(tmptv)
1777   |   lw TMP1, DISPATCH_GL(tmptv)(DISPATCH)
1778   |  daddiu RA, BASE, -16
1779   |.if FPU
1780   |   mtc1 TMP1, FARG2
1781   |  sdc1 FRET1, 0(RA)
1782   |   cvt.d.w FARG2, FARG2
1783   |   sdc1 FARG2, 8(RA)
1784   |.else
1785   |  sd CRET1, 0(RA)
1786   |  zextw TMP1, TMP1
1787   |  settp TMP1, TISNUM
1788   |  sd TMP1, 8(RA)
1789   |.endif
1790   |  b ->fff_res
1791   |.  li RD, (2+1)*8
1792   |
1793   |.ffunc_n math_modf
1794   |  load_got modf
1795   |   ld PC, FRAME_PC(BASE)
1796   |  call_extern
1797   |.  daddiu CARG2, BASE, -16
1798   |  daddiu RA, BASE, -16
1799   |.if FPU
1800   |  sdc1 FRET1, -8(BASE)
1801   |.else
1802   |  sd CRET1, -8(BASE)
1803   |.endif
1804   |  b ->fff_res
1805   |.  li RD, (2+1)*8
1806   |
1807   |.macro math_minmax, name, intins, intinsc, fpins
1808   |  .ffunc_1 name
1809   |  daddu TMP3, BASE, NARGS8:RC
1810   |  checkint CARG1, >5
1811   |.  daddiu TMP2, BASE, 8
1812   |1:  // Handle integers.
1813   |  beq TMP2, TMP3, ->fff_restv
1814   |.  ld CARG2, 0(TMP2)
1815   |  checkint CARG2, >3
1816   |.  sextw CARG1, CARG1
1817   |  lw CARG2, LO(TMP2)
1818   |.  slt AT, CARG1, CARG2
1819   |.if MIPSR6
1820   |  intins TMP1, CARG2, AT
1821   |  intinsc CARG1, CARG1, AT
1822   |  or CARG1, CARG1, TMP1
1823   |.else
1824   |  intins CARG1, CARG2, AT
1825   |.endif
1826   |  daddiu TMP2, TMP2, 8
1827   |  zextw CARG1, CARG1
1828   |  b <1
1829   |.  settp CARG1, TISNUM
1830   |
1831   |3:  // Convert intermediate result to number and continue with number loop.
1832   |  checknum CARG2, ->fff_fallback
1833   |.if FPU
1834   |.  mtc1 CARG1, FRET1
1835   |  cvt.d.w FRET1, FRET1
1836   |  b >7
1837   |.  ldc1 FARG1, 0(TMP2)
1838   |.else
1839   |.  nop
1840   |  bal ->vm_sfi2d_1
1841   |.  nop
1842   |  b >7
1843   |.  nop
1844   |.endif
1845   |
1846   |5:
1847   |  .FPU ldc1 FRET1, 0(BASE)
1848   |  checknum CARG1, ->fff_fallback
1849   |6:  // Handle numbers.
1850   |.  ld CARG2, 0(TMP2)
1851   |  beq TMP2, TMP3, ->fff_resn
1852   |.if FPU
1853   |  ldc1 FARG1, 0(TMP2)
1854   |.else
1855   |  move CRET1, CARG1
1856   |.endif
1857   |  checknum CARG2, >8
1858   |.  nop
1859   |7:
1860   |.if FPU
1861   |.if MIPSR6
1862   |  fpins FRET1, FRET1, FARG1
1863   |.else
1864   |.if fpins  // ismax
1865   |  c.olt.d FARG1, FRET1
1866   |.else
1867   |  c.olt.d FRET1, FARG1
1868   |.endif
1869   |  movf.d FRET1, FARG1
1870   |.endif
1871   |.else
1872   |.if fpins  // ismax
1873   |  bal ->vm_sfcmpogt
1874   |.else
1875   |  bal ->vm_sfcmpolt
1876   |.endif
1877   |.  nop
1878   |.if MIPSR6
1879   |  seleqz AT, CARG2, CRET1
1880   |  selnez CARG1, CARG1, CRET1
1881   |  or CARG1, CARG1, AT
1882   |.else
1883   |  movz CARG1, CARG2, CRET1
1884   |.endif
1885   |.endif
1886   |  b <6
1887   |.  daddiu TMP2, TMP2, 8
1888   |
1889   |8:  // Convert integer to number and continue with number loop.
1890   |  checkint CARG2, ->fff_fallback
1891   |.if FPU
1892   |.  lwc1 FARG1, LO(TMP2)
1893   |  b <7
1894   |.  cvt.d.w FARG1, FARG1
1895   |.else
1896   |.  lw CARG2, LO(TMP2)
1897   |  bal ->vm_sfi2d_2
1898   |.  nop
1899   |  b <7
1900   |.  nop
1901   |.endif
1902   |
1903   |.endmacro
1904   |
1905   |.if MIPSR6
1906   |  math_minmax math_min, seleqz, selnez, min.d
1907   |  math_minmax math_max, selnez, seleqz, max.d
1908   |.else
1909   |  math_minmax math_min, movz, _, 0
1910   |  math_minmax math_max, movn, _, 1
1911   |.endif
1912   |
1913   |//-- String library -----------------------------------------------------
1914   |
1915   |.ffunc string_byte                   // Only handle the 1-arg case here.
1916   |  ld CARG1, 0(BASE)
1917   |  gettp TMP0, CARG1
1918   |  xori AT, NARGS8:RC, 8
1919   |  daddiu TMP0, TMP0, -LJ_TSTR
1920   |  or AT, AT, TMP0
1921   |  bnez AT, ->fff_fallback            // Need exactly 1 string argument.
1922   |.  cleartp STR:CARG1
1923   |  lw TMP0, STR:CARG1->len
1924   |    daddiu RA, BASE, -16
1925   |    ld PC, FRAME_PC(BASE)
1926   |  sltu RD, r0, TMP0
1927   |   lbu TMP1, STR:CARG1[1]            // Access is always ok (NUL at end).
1928   |  addiu RD, RD, 1
1929   |  sll RD, RD, 3                      // RD = ((str->len != 0)+1)*8
1930   |  settp TMP1, TISNUM
1931   |  b ->fff_res
1932   |.  sd TMP1, 0(RA)
1933   |
1934   |.ffunc string_char                   // Only handle the 1-arg case here.
1935   |  ffgccheck
1936   |.if not MIPSR6
1937   |.  nop
1938   |.endif
1939   |  ld CARG1, 0(BASE)
1940   |  gettp TMP0, CARG1
1941   |  xori AT, NARGS8:RC, 8              // Exactly 1 argument.
1942   |  daddiu TMP0, TMP0, -LJ_TISNUM      // Integer.
1943   |  li TMP1, 255
1944   |   sextw CARG1, CARG1
1945   |  or AT, AT, TMP0
1946   |   sltu TMP1, TMP1, CARG1            // !(255 < n).
1947   |   or AT, AT, TMP1
1948   |  bnez AT, ->fff_fallback
1949   |.  li CARG3, 1
1950   |  daddiu CARG2, sp, TMPD_OFS
1951   |  sb CARG1, TMPD
1952   |->fff_newstr:
1953   |  load_got lj_str_new
1954   |   sd BASE, L->base
1955   |   sd PC, SAVE_PC
1956   |  call_intern lj_str_new             // (lua_State *L, char *str, size_t l)
1957   |.  move CARG1, L
1958   |  // Returns GCstr *.
1959   |  ld BASE, L->base
1960   |->fff_resstr:
1961   |  li AT, LJ_TSTR
1962   |  settp CRET1, AT
1963   |  b ->fff_restv
1964   |.  move CARG1, CRET1
1965   |
1966   |.ffunc string_sub
1967   |  ffgccheck
1968   |.if not MIPSR6
1969   |.  nop
1970   |.endif
1971   |  addiu AT, NARGS8:RC, -16
1972   |  ld TMP0, 0(BASE)
1973   |  bltz AT, ->fff_fallback
1974   |.  gettp TMP3, TMP0
1975   |  cleartp STR:CARG1, TMP0
1976   |  ld CARG2, 8(BASE)
1977   |  beqz AT, >1
1978   |.  li CARG4, -1
1979   |  ld CARG3, 16(BASE)
1980   |  checkint CARG3, ->fff_fallback
1981   |.  sextw CARG4, CARG3
1982   |1:
1983   |  checkint CARG2, ->fff_fallback
1984   |.  li AT, LJ_TSTR
1985   |  bne TMP3, AT, ->fff_fallback
1986   |.  sextw CARG3, CARG2
1987   |  lw CARG2, STR:CARG1->len
1988   |  // STR:CARG1 = str, CARG2 = str->len, CARG3 = start, CARG4 = end
1989   |  slt AT, CARG4, r0
1990   |  addiu TMP0, CARG2, 1
1991   |  addu TMP1, CARG4, TMP0
1992   |   slt TMP3, CARG3, r0
1993   |.if MIPSR6
1994   |  seleqz CARG4, CARG4, AT
1995   |  selnez TMP1, TMP1, AT
1996   |  or CARG4, TMP1, CARG4              // if (end < 0) end += len+1
1997   |.else
1998   |  movn CARG4, TMP1, AT               // if (end < 0) end += len+1
1999   |.endif
2000   |   addu TMP1, CARG3, TMP0
2001   |.if MIPSR6
2002   |   selnez TMP1, TMP1, TMP3
2003   |   seleqz CARG3, CARG3, TMP3
2004   |   or CARG3, TMP1, CARG3             // if (start < 0) start += len+1
2005   |   li TMP2, 1
2006   |  slt AT, CARG4, r0
2007   |   slt TMP3, r0, CARG3
2008   |  seleqz CARG4, CARG4, AT            // if (end < 0) end = 0
2009   |   selnez CARG3, CARG3, TMP3
2010   |   seleqz TMP2, TMP2, TMP3
2011   |   or CARG3, TMP2, CARG3             // if (start < 1) start = 1
2012   |  slt AT, CARG2, CARG4
2013   |  seleqz CARG4, CARG4, AT
2014   |  selnez CARG2, CARG2, AT
2015   |  or CARG4, CARG2, CARG4             // if (end > len) end = len
2016   |.else
2017   |   movn CARG3, TMP1, TMP3            // if (start < 0) start += len+1
2018   |   li TMP2, 1
2019   |  slt AT, CARG4, r0
2020   |   slt TMP3, r0, CARG3
2021   |  movn CARG4, r0, AT                 // if (end < 0) end = 0
2022   |   movz CARG3, TMP2, TMP3            // if (start < 1) start = 1
2023   |  slt AT, CARG2, CARG4
2024   |  movn CARG4, CARG2, AT              // if (end > len) end = len
2025   |.endif
2026   |   daddu CARG2, STR:CARG1, CARG3
2027   |  subu CARG3, CARG4, CARG3           // len = end - start
2028   |   daddiu CARG2, CARG2, sizeof(GCstr)-1
2029   |  bgez CARG3, ->fff_newstr
2030   |.  addiu CARG3, CARG3, 1             // len++
2031   |->fff_emptystr:  // Return empty string.
2032   |  li AT, LJ_TSTR
2033   |  daddiu STR:CARG1, DISPATCH, DISPATCH_GL(strempty)
2034   |  b ->fff_restv
2035   |.  settp CARG1, AT
2036   |
2037   |.macro ffstring_op, name
2038   |  .ffunc string_ .. name
2039   |  ffgccheck
2040   |.  nop
2041   |  beqz NARGS8:RC, ->fff_fallback
2042   |.  ld CARG2, 0(BASE)
2043   |  checkstr STR:CARG2, ->fff_fallback
2044   |  daddiu SBUF:CARG1, DISPATCH, DISPATCH_GL(tmpbuf)
2045   |  load_got lj_buf_putstr_ .. name
2046   |  ld TMP0, SBUF:CARG1->b
2047   |   sd L, SBUF:CARG1->L
2048   |   sd BASE, L->base
2049   |  sd TMP0, SBUF:CARG1->w
2050   |  call_intern extern lj_buf_putstr_ .. name
2051   |.  sd PC, SAVE_PC
2052   |  load_got lj_buf_tostr
2053   |  call_intern lj_buf_tostr
2054   |.  move SBUF:CARG1, SBUF:CRET1
2055   |  b ->fff_resstr
2056   |.  ld BASE, L->base
2057   |.endmacro
2058   |
2059   |ffstring_op reverse
2060   |ffstring_op lower
2061   |ffstring_op upper
2062   |
2063   |//-- Bit library --------------------------------------------------------
2064   |
2065   |->vm_tobit_fb:
2066   |  beqz TMP1, ->fff_fallback
2067   |.if FPU
2068   |.  ldc1 FARG1, 0(BASE)
2069   |  add.d FARG1, FARG1, TOBIT
2070   |  mfc1 CRET1, FARG1
2071   |  jr ra
2072   |.  zextw CRET1, CRET1
2073   |.else
2074   |// FP number to bit conversion for soft-float.
2075   |->vm_tobit:
2076   |  dsll TMP0, CARG1, 1
2077   |  li CARG3, 1076
2078   |  dsrl AT, TMP0, 53
2079   |  dsubu CARG3, CARG3, AT
2080   |  sltiu AT, CARG3, 54
2081   |  beqz AT, >1
2082   |.  dextm TMP0, TMP0, 0, 20
2083   |  dinsu TMP0, AT, 21, 21
2084   |  slt AT, CARG1, r0
2085   |  dsrlv CRET1, TMP0, CARG3
2086   |  dsubu TMP0, r0, CRET1
2087   |.if MIPSR6
2088   |  selnez TMP0, TMP0, AT
2089   |  seleqz CRET1, CRET1, AT
2090   |  or CRET1, CRET1, TMP0
2091   |.else
2092   |  movn CRET1, TMP0, AT
2093   |.endif
2094   |  jr ra
2095   |.  zextw CRET1, CRET1
2096   |1:
2097   |  jr ra
2098   |.  move CRET1, r0
2099   |
2100   |// FP number to int conversion with a check for soft-float.
2101   |// Modifies CARG1, CRET1, CRET2, TMP0, AT.
2102   |->vm_tointg:
2103   |.if JIT
2104   |  dsll CRET2, CARG1, 1
2105   |  beqz CRET2, >2
2106   |.  li TMP0, 1076
2107   |  dsrl AT, CRET2, 53
2108   |  dsubu TMP0, TMP0, AT
2109   |  sltiu AT, TMP0, 54
2110   |  beqz AT, >1
2111   |.  dextm CRET2, CRET2, 0, 20
2112   |  dinsu CRET2, AT, 21, 21
2113   |  slt AT, CARG1, r0
2114   |  dsrlv CRET1, CRET2, TMP0
2115   |  dsubu CARG1, r0, CRET1
2116   |.if MIPSR6
2117   |  seleqz CRET1, CRET1, AT
2118   |  selnez CARG1, CARG1, AT
2119   |  or CRET1, CRET1, CARG1
2120   |.else
2121   |  movn CRET1, CARG1, AT
2122   |.endif
2123   |  li CARG1, 64
2124   |  subu TMP0, CARG1, TMP0
2125   |  dsllv CRET2, CRET2, TMP0   // Integer check.
2126   |  sextw AT, CRET1
2127   |  xor AT, CRET1, AT          // Range check.
2128   |.if MIPSR6
2129   |  seleqz AT, AT, CRET2
2130   |  selnez CRET2, CRET2, CRET2
2131   |  jr ra
2132   |.  or CRET2, AT, CRET2
2133   |.else
2134   |  jr ra
2135   |.  movz CRET2, AT, CRET2
2136   |.endif
2137   |1:
2138   |  jr ra
2139   |.  li CRET2, 1
2140   |2:
2141   |  jr ra
2142   |.  move CRET1, r0
2143   |.endif
2144   |.endif
2145   |
2146   |.macro .ffunc_bit, name
2147   |  .ffunc_1 bit_..name
2148   |  gettp TMP0, CARG1
2149   |  beq TMP0, TISNUM, >6
2150   |.  zextw CRET1, CARG1
2151   |  bal ->vm_tobit_fb
2152   |.  sltiu TMP1, TMP0, LJ_TISNUM
2153   |6:
2154   |.endmacro
2155   |
2156   |.macro .ffunc_bit_op, name, bins
2157   |  .ffunc_bit name
2158   |  daddiu TMP2, BASE, 8
2159   |  daddu TMP3, BASE, NARGS8:RC
2160   |1:
2161   |  beq TMP2, TMP3, ->fff_resi
2162   |.  ld CARG1, 0(TMP2)
2163   |  gettp TMP0, CARG1
2164   |.if FPU
2165   |  bne TMP0, TISNUM, >2
2166   |.  daddiu TMP2, TMP2, 8
2167   |  zextw CARG1, CARG1
2168   |  b <1
2169   |.  bins CRET1, CRET1, CARG1
2170   |2:
2171   |   ldc1 FARG1, -8(TMP2)
2172   |  sltiu AT, TMP0, LJ_TISNUM
2173   |  beqz AT, ->fff_fallback
2174   |.  add.d FARG1, FARG1, TOBIT
2175   |  mfc1 CARG1, FARG1
2176   |  zextw CARG1, CARG1
2177   |  b <1
2178   |.  bins CRET1, CRET1, CARG1
2179   |.else
2180   |  beq TMP0, TISNUM, >2
2181   |.  move CRET2, CRET1
2182   |  bal ->vm_tobit_fb
2183   |.  sltiu TMP1, TMP0, LJ_TISNUM
2184   |  move CARG1, CRET2
2185   |2:
2186   |  zextw CARG1, CARG1
2187   |  bins CRET1, CRET1, CARG1
2188   |  b <1
2189   |.  daddiu TMP2, TMP2, 8
2190   |.endif
2191   |.endmacro
2192   |
2193   |.ffunc_bit_op band, and
2194   |.ffunc_bit_op bor, or
2195   |.ffunc_bit_op bxor, xor
2196   |
2197   |.ffunc_bit bswap
2198   |  dsrl TMP0, CRET1, 8
2199   |   dsrl TMP1, CRET1, 24
2200   |  andi TMP2, TMP0, 0xff00
2201   |   dins TMP1, CRET1, 24, 31
2202   |  dins TMP2, TMP0, 16, 23
2203   |  b ->fff_resi
2204   |.  or CRET1, TMP1, TMP2
2205   |
2206   |.ffunc_bit bnot
2207   |  not CRET1, CRET1
2208   |  b ->fff_resi
2209   |.  zextw CRET1, CRET1
2210   |
2211   |.macro .ffunc_bit_sh, name, shins, shmod
2212   |  .ffunc_2 bit_..name
2213   |  gettp TMP0, CARG1
2214   |  beq TMP0, TISNUM, >1
2215   |.  nop
2216   |  bal ->vm_tobit_fb
2217   |.  sltiu TMP1, TMP0, LJ_TISNUM
2218   |  move CARG1, CRET1
2219   |1:
2220   |  gettp TMP0, CARG2
2221   |  bne TMP0, TISNUM, ->fff_fallback
2222   |.  zextw CARG2, CARG2
2223   |  sextw CARG1, CARG1
2224   |.if shmod == 1
2225   |  negu CARG2, CARG2
2226   |.endif
2227   |  shins CRET1, CARG1, CARG2
2228   |  b ->fff_resi
2229   |.  zextw CRET1, CRET1
2230   |.endmacro
2231   |
2232   |.ffunc_bit_sh lshift, sllv, 0
2233   |.ffunc_bit_sh rshift, srlv, 0
2234   |.ffunc_bit_sh arshift, srav, 0
2235   |.ffunc_bit_sh rol, rotrv, 1
2236   |.ffunc_bit_sh ror, rotrv, 0
2237   |
2238   |.ffunc_bit tobit
2239   |->fff_resi:
2240   |  ld PC, FRAME_PC(BASE)
2241   |  daddiu RA, BASE, -16
2242   |  settp CRET1, TISNUM
2243   |  b ->fff_res1
2244   |.  sd CRET1, -16(BASE)
2245   |
2246   |//-----------------------------------------------------------------------
2247   |->fff_fallback:                      // Call fast function fallback handler.
2248   |  // BASE = new base, RB = CFUNC, RC = nargs*8
2249   |  ld TMP3, CFUNC:RB->f
2250   |    daddu TMP1, BASE, NARGS8:RC
2251   |   ld PC, FRAME_PC(BASE)             // Fallback may overwrite PC.
2252   |    daddiu TMP0, TMP1, 8*LUA_MINSTACK
2253   |     ld TMP2, L->maxstack
2254   |   sd PC, SAVE_PC                    // Redundant (but a defined value).
2255   |  sltu AT, TMP2, TMP0
2256   |     sd BASE, L->base
2257   |    sd TMP1, L->top
2258   |  bnez AT, >5                        // Need to grow stack.
2259   |.  move CFUNCADDR, TMP3
2260   |  jalr TMP3                          // (lua_State *L)
2261   |.  move CARG1, L
2262   |  // Either throws an error, or recovers and returns -1, 0 or nresults+1.
2263   |  ld BASE, L->base
2264   |   sll RD, CRET1, 3
2265   |  bgtz CRET1, ->fff_res              // Returned nresults+1?
2266   |.  daddiu RA, BASE, -16
2267   |1:  // Returned 0 or -1: retry fast path.
2268   |   ld LFUNC:RB, FRAME_FUNC(BASE)
2269   |  ld TMP0, L->top
2270   |   cleartp LFUNC:RB
2271   |  bnez CRET1, ->vm_call_tail         // Returned -1?
2272   |.  dsubu NARGS8:RC, TMP0, BASE
2273   |  ins_callt                          // Returned 0: retry fast path.
2274   |
2275   |// Reconstruct previous base for vmeta_call during tailcall.
2276   |->vm_call_tail:
2277   |  andi TMP0, PC, FRAME_TYPE
2278   |   li AT, -4
2279   |  bnez TMP0, >3
2280   |.  and TMP1, PC, AT
2281   |  lbu TMP1, OFS_RA(PC)
2282   |  sll TMP1, TMP1, 3
2283   |  addiu TMP1, TMP1, 16
2284   |3:
2285   |  b ->vm_call_dispatch               // Resolve again for tailcall.
2286   |.  dsubu TMP2, BASE, TMP1
2287   |
2288   |5:  // Grow stack for fallback handler.
2289   |  load_got lj_state_growstack
2290   |  li CARG2, LUA_MINSTACK
2291   |  call_intern lj_state_growstack     // (lua_State *L, int n)
2292   |.  move CARG1, L
2293   |  ld BASE, L->base
2294   |  b <1
2295   |.  li CRET1, 0                       // Force retry.
2296   |
2297   |->fff_gcstep:                        // Call GC step function.
2298   |  // BASE = new base, RC = nargs*8
2299   |  move MULTRES, ra
2300   |  load_got lj_gc_step
2301   |   sd BASE, L->base
2302   |  daddu TMP0, BASE, NARGS8:RC
2303   |   sd PC, SAVE_PC                    // Redundant (but a defined value).
2304   |  sd TMP0, L->top
2305   |  call_intern lj_gc_step             // (lua_State *L)
2306   |.  move CARG1, L
2307   |   ld BASE, L->base
2308   |  move ra, MULTRES
2309   |    ld TMP0, L->top
2310   |  ld CFUNC:RB, FRAME_FUNC(BASE)
2311   |  cleartp CFUNC:RB
2312   |  jr ra
2313   |.  dsubu NARGS8:RC, TMP0, BASE
2314   |
2315   |//-----------------------------------------------------------------------
2316   |//-- Special dispatch targets -------------------------------------------
2317   |//-----------------------------------------------------------------------
2318   |
2319   |->vm_record:                         // Dispatch target for recording phase.
2320   |.if JIT
2321   |  lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
2322   |  andi AT, TMP3, HOOK_VMEVENT        // No recording while in vmevent.
2323   |  bnez AT, >5
2324   |  // Decrement the hookcount for consistency, but always do the call.
2325   |.  lw TMP2, DISPATCH_GL(hookcount)(DISPATCH)
2326   |  andi AT, TMP3, HOOK_ACTIVE
2327   |  bnez AT, >1
2328   |.  addiu TMP2, TMP2, -1
2329   |  andi AT, TMP3, LUA_MASKLINE|LUA_MASKCOUNT
2330   |  beqz AT, >1
2331   |.  nop
2332   |  b >1
2333   |.  sw TMP2, DISPATCH_GL(hookcount)(DISPATCH)
2334   |.endif
2335   |
2336   |->vm_rethook:                        // Dispatch target for return hooks.
2337   |  lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
2338   |  andi AT, TMP3, HOOK_ACTIVE         // Hook already active?
2339   |  beqz AT, >1
2340   |5:  // Re-dispatch to static ins.
2341   |.  ld AT, GG_DISP2STATIC(TMP0)       // Assumes TMP0 holds DISPATCH+OP*4.
2342   |  jr AT
2343   |.  nop
2344   |
2345   |->vm_inshook:                        // Dispatch target for instr/line hooks.
2346   |  lbu TMP3, DISPATCH_GL(hookmask)(DISPATCH)
2347   |  lw TMP2, DISPATCH_GL(hookcount)(DISPATCH)
2348   |  andi AT, TMP3, HOOK_ACTIVE         // Hook already active?
2349   |  bnez AT, <5
2350   |.  andi AT, TMP3, LUA_MASKLINE|LUA_MASKCOUNT
2351   |  beqz AT, <5
2352   |.  addiu TMP2, TMP2, -1
2353   |  beqz TMP2, >1
2354   |.  sw TMP2, DISPATCH_GL(hookcount)(DISPATCH)
2355   |  andi AT, TMP3, LUA_MASKLINE
2356   |  beqz AT, <5
2357   |1:
2358   |.  load_got lj_dispatch_ins
2359   |   sw MULTRES, SAVE_MULTRES
2360   |  move CARG2, PC
2361   |   sd BASE, L->base
2362   |  // SAVE_PC must hold the _previous_ PC. The callee updates it with PC.
2363   |  call_intern lj_dispatch_ins        // (lua_State *L, const BCIns *pc)
2364   |.  move CARG1, L
2365   |3:
2366   |  ld BASE, L->base
2367   |4:  // Re-dispatch to static ins.
2368   |  lw INS, -4(PC)
2369   |  decode_OP8a TMP1, INS
2370   |  decode_OP8b TMP1
2371   |  daddu TMP0, DISPATCH, TMP1
2372   |   decode_RD8a RD, INS
2373   |  ld AT, GG_DISP2STATIC(TMP0)
2374   |   decode_RA8a RA, INS
2375   |   decode_RD8b RD
2376   |  jr AT
2377   |   decode_RA8b RA
2378   |
2379   |->cont_hook:                         // Continue from hook yield.
2380   |  daddiu PC, PC, 4
2381   |  b <4
2382   |.  lw MULTRES, -24+LO(RB)            // Restore MULTRES for *M ins.
2383   |
2384   |->vm_hotloop:                        // Hot loop counter underflow.
2385   |.if JIT
2386   |  ld LFUNC:TMP1, FRAME_FUNC(BASE)
2387   |   daddiu CARG1, DISPATCH, GG_DISP2J
2388   |  cleartp LFUNC:TMP1
2389   |   sd PC, SAVE_PC
2390   |  ld TMP1, LFUNC:TMP1->pc
2391   |   move CARG2, PC
2392   |   sd L, DISPATCH_J(L)(DISPATCH)
2393   |  lbu TMP1, PC2PROTO(framesize)(TMP1)
2394   |  load_got lj_trace_hot
2395   |   sd BASE, L->base
2396   |  dsll TMP1, TMP1, 3
2397   |  daddu TMP1, BASE, TMP1
2398   |  call_intern lj_trace_hot           // (jit_State *J, const BCIns *pc)
2399   |.  sd TMP1, L->top
2400   |  b <3
2401   |.  nop
2402   |.endif
2403   |
2404   |
2405   |->vm_callhook:                       // Dispatch target for call hooks.
2406   |.if JIT
2407   |  b >1
2408   |.endif
2409   |.  move CARG2, PC
2410   |
2411   |->vm_hotcall:                        // Hot call counter underflow.
2412   |.if JIT
2413   |  ori CARG2, PC, 1
2414   |1:
2415   |.endif
2416   |  load_got lj_dispatch_call
2417   |  daddu TMP0, BASE, RC
2418   |   sd PC, SAVE_PC
2419   |   sd BASE, L->base
2420   |  dsubu RA, RA, BASE
2421   |   sd TMP0, L->top
2422   |  call_intern lj_dispatch_call       // (lua_State *L, const BCIns *pc)
2423   |.  move CARG1, L
2424   |  // Returns ASMFunction.
2425   |  ld BASE, L->base
2426   |   ld TMP0, L->top
2427   |   sd r0, SAVE_PC                    // Invalidate for subsequent line hook.
2428   |  dsubu NARGS8:RC, TMP0, BASE
2429   |  daddu RA, BASE, RA
2430   |  ld LFUNC:RB, FRAME_FUNC(BASE)
2431   |  cleartp LFUNC:RB
2432   |  jr CRET1
2433   |.  lw INS, -4(PC)
2434   |
2435   |->cont_stitch:                       // Trace stitching.
2436   |.if JIT
2437   |  // RA = resultptr, RB = meta base
2438   |  lw INS, -4(PC)
2439   |    ld TRACE:TMP2, -40(RB)           // Save previous trace.
2440   |  decode_RA8a RC, INS
2441   |   daddiu AT, MULTRES, -8
2442   |    cleartp TRACE:TMP2
2443   |  decode_RA8b RC
2444   |   beqz AT, >2
2445   |. daddu RC, BASE, RC                 // Call base.
2446   |1:  // Move results down.
2447   |  ld CARG1, 0(RA)
2448   |   daddiu AT, AT, -8
2449   |    daddiu RA, RA, 8
2450   |  sd CARG1, 0(RC)
2451   |   bnez AT, <1
2452   |.   daddiu RC, RC, 8
2453   |2:
2454   |   decode_RA8a RA, INS
2455   |    decode_RB8a RB, INS
2456   |   decode_RA8b RA
2457   |    decode_RB8b RB
2458   |   daddu RA, RA, RB
2459   |   daddu RA, BASE, RA
2460   |3:
2461   |   sltu AT, RC, RA
2462   |   bnez AT, >9                       // More results wanted?
2463   |.   nop
2464   |
2465   |  lhu TMP3, TRACE:TMP2->traceno
2466   |  lhu RD, TRACE:TMP2->link
2467   |  beq RD, TMP3, ->cont_nop           // Blacklisted.
2468   |.  load_got lj_dispatch_stitch
2469   |  bnez RD, =>BC_JLOOP                // Jump to stitched trace.
2470   |.  sll RD, RD, 3
2471   |
2472   |  // Stitch a new trace to the previous trace.
2473   |  sw TMP3, DISPATCH_J(exitno)(DISPATCH)
2474   |  sd L, DISPATCH_J(L)(DISPATCH)
2475   |  sd BASE, L->base
2476   |  daddiu CARG1, DISPATCH, GG_DISP2J
2477   |  call_intern lj_dispatch_stitch     // (jit_State *J, const BCIns *pc)
2478   |.  move CARG2, PC
2479   |  b ->cont_nop
2480   |.  ld BASE, L->base
2481   |
2482   |9:
2483   |  sd TISNIL, 0(RC)
2484   |  b <3
2485   |.  daddiu RC, RC, 8
2486   |.endif
2487   |
2488   |->vm_profhook:                       // Dispatch target for profiler hook.
2489 #if LJ_HASPROFILE
2490   |  load_got lj_dispatch_profile
2491   |   sw MULTRES, SAVE_MULTRES
2492   |  move CARG2, PC
2493   |   sd BASE, L->base
2494   |  call_intern lj_dispatch_profile    // (lua_State *L, const BCIns *pc)
2495   |.  move CARG1, L
2496   |  // HOOK_PROFILE is off again, so re-dispatch to dynamic instruction.
2497   |  daddiu PC, PC, -4
2498   |  b ->cont_nop
2499   |.  ld BASE, L->base
2500 #endif
2501   |
2502   |//-----------------------------------------------------------------------
2503   |//-- Trace exit handler -------------------------------------------------
2504   |//-----------------------------------------------------------------------
2505   |
2506   |.macro savex_, a, b
2507   |.if FPU
2508   |  sdc1 f..a, a*8(sp)
2509   |  sdc1 f..b, b*8(sp)
2510   |  sd r..a, 32*8+a*8(sp)
2511   |  sd r..b, 32*8+b*8(sp)
2512   |.else
2513   |  sd r..a, a*8(sp)
2514   |  sd r..b, b*8(sp)
2515   |.endif
2516   |.endmacro
2517   |
2518   |->vm_exit_handler:
2519   |.if JIT
2520   |.if FPU
2521   |  daddiu sp, sp, -(32*8+32*8)
2522   |.else
2523   |  daddiu sp, sp, -(32*8)
2524   |.endif
2525   |  savex_ 0, 1
2526   |  savex_ 2, 3
2527   |  savex_ 4, 5
2528   |  savex_ 6, 7
2529   |  savex_ 8, 9
2530   |  savex_ 10, 11
2531   |  savex_ 12, 13
2532   |  savex_ 14, 15
2533   |  savex_ 16, 17
2534   |  savex_ 18, 19
2535   |  savex_ 20, 21
2536   |  savex_ 22, 23
2537   |  savex_ 24, 25
2538   |  savex_ 26, 27
2539   |  savex_ 28, 30
2540   |.if FPU
2541   |  sdc1 f29, 29*8(sp)
2542   |  sdc1 f31, 31*8(sp)
2543   |  sd r0, 32*8+31*8(sp)               // Clear RID_TMP.
2544   |  daddiu TMP2, sp, 32*8+32*8         // Recompute original value of sp.
2545   |  sd TMP2, 32*8+29*8(sp)             // Store sp in RID_SP
2546   |.else
2547   |  sd r0, 31*8(sp)                    // Clear RID_TMP.
2548   |  daddiu TMP2, sp, 32*8              // Recompute original value of sp.
2549   |  sd TMP2, 29*8(sp)                  // Store sp in RID_SP
2550   |.endif
2551   |  li_vmstate EXIT
2552   |  daddiu DISPATCH, JGL, -GG_DISP2G-32768
2553   |  lw TMP1, 0(TMP2)                   // Load exit number.
2554   |  st_vmstate
2555   |  ld L, DISPATCH_GL(cur_L)(DISPATCH)
2556   |   ld BASE, DISPATCH_GL(jit_base)(DISPATCH)
2557   |  load_got lj_trace_exit
2558   |  sd L, DISPATCH_J(L)(DISPATCH)
2559   |  sw ra, DISPATCH_J(parent)(DISPATCH)  // Store trace number.
2560   |   sd BASE, L->base
2561   |  sw TMP1, DISPATCH_J(exitno)(DISPATCH)  // Store exit number.
2562   |  daddiu CARG1, DISPATCH, GG_DISP2J
2563   |   sd r0, DISPATCH_GL(jit_base)(DISPATCH)
2564   |  call_intern lj_trace_exit          // (jit_State *J, ExitState *ex)
2565   |.  move CARG2, sp
2566   |  // Returns MULTRES (unscaled) or negated error code.
2567   |  ld TMP1, L->cframe
2568   |  li AT, -4
2569   |   ld BASE, L->base
2570   |  and sp, TMP1, AT
2571   |   ld PC, SAVE_PC                    // Get SAVE_PC.
2572   |  b >1
2573   |.  sd L, SAVE_L                      // Set SAVE_L (on-trace resume/yield).
2574   |.endif
2575   |->vm_exit_interp:
2576   |.if JIT
2577   |  // CRET1 = MULTRES or negated error code, BASE, PC and JGL set.
2578   |  ld L, SAVE_L
2579   |   daddiu DISPATCH, JGL, -GG_DISP2G-32768
2580   |  sd BASE, L->base
2581   |1:
2582   |  sltiu TMP0, CRET1, -LUA_ERRERR     // Check for error from exit.
2583   |  beqz TMP0, >9
2584   |.  ld LFUNC:RB, FRAME_FUNC(BASE)
2585   |    .FPU lui TMP3, 0x59c0            // TOBIT = 2^52 + 2^51 (float).
2586   |  dsll MULTRES, CRET1, 3
2587   |  cleartp LFUNC:RB
2588   |  sw MULTRES, SAVE_MULTRES
2589   |    li TISNIL, LJ_TNIL
2590   |     li TISNUM, LJ_TISNUM            // Setup type comparison constants.
2591   |    .FPU mtc1 TMP3, TOBIT
2592   |  ld TMP1, LFUNC:RB->pc
2593   |   sd r0, DISPATCH_GL(jit_base)(DISPATCH)
2594   |  ld KBASE, PC2PROTO(k)(TMP1)
2595   |    .FPU cvt.d.s TOBIT, TOBIT
2596   |  // Modified copy of ins_next which handles function header dispatch, too.
2597   |  lw INS, 0(PC)
2598   |  addiu CRET1, CRET1, 17             // Static dispatch?
2599   |    // Assumes TISNIL == ~LJ_VMST_INTERP == -1
2600   |    sw TISNIL, DISPATCH_GL(vmstate)(DISPATCH)
2601   |   decode_RD8a RD, INS
2602   |  beqz CRET1, >5
2603   |.  daddiu PC, PC, 4
2604   |  decode_OP8a TMP1, INS
2605   |  decode_OP8b TMP1
2606   |  daddu TMP0, DISPATCH, TMP1
2607   |    sltiu TMP2, TMP1, BC_FUNCF*8
2608   |  ld AT, 0(TMP0)
2609   |   decode_RA8a RA, INS
2610   |    beqz TMP2, >2
2611   |.  decode_RA8b RA
2612   |  jr AT
2613   |.  decode_RD8b RD
2614   |2:
2615   |  sltiu TMP2, TMP1, (BC_FUNCC+2)*8   // Fast function?
2616   |  bnez TMP2, >3
2617   |.  ld TMP1, FRAME_PC(BASE)
2618   |  // Check frame below fast function.
2619   |  andi TMP0, TMP1, FRAME_TYPE
2620   |  bnez TMP0, >3                      // Trace stitching continuation?
2621   |.  nop
2622   |  // Otherwise set KBASE for Lua function below fast function.
2623   |  lw TMP2, -4(TMP1)
2624   |  decode_RA8a TMP0, TMP2
2625   |  decode_RA8b TMP0
2626   |  dsubu TMP1, BASE, TMP0
2627   |  ld LFUNC:TMP2, -32(TMP1)
2628   |  cleartp LFUNC:TMP2
2629   |  ld TMP1, LFUNC:TMP2->pc
2630   |  ld KBASE, PC2PROTO(k)(TMP1)
2631   |3:
2632   |  daddiu RC, MULTRES, -8
2633   |  jr AT
2634   |.  daddu RA, RA, BASE
2635   |
2636   |5:  // Dispatch to static entry of original ins replaced by BC_JLOOP.
2637   |  ld TMP0, DISPATCH_J(trace)(DISPATCH)
2638   |  decode_RD8b RD
2639   |  daddu TMP0, TMP0, RD
2640   |  ld TRACE:TMP2, 0(TMP0)
2641   |  lw INS, TRACE:TMP2->startins
2642   |  decode_OP8a TMP1, INS
2643   |  decode_OP8b TMP1
2644   |  daddu TMP0, DISPATCH, TMP1
2645   |   decode_RD8a RD, INS
2646   |  ld AT, GG_DISP2STATIC(TMP0)
2647   |   decode_RA8a RA, INS
2648   |   decode_RD8b RD
2649   |  jr AT
2650   |.  decode_RA8b RA
2651   |
2652   |9:  // Rethrow error from the right C frame.
2653   |  load_got lj_err_trace
2654   |  sub CARG2, r0, CRET1
2655   |  call_intern lj_err_trace           // (lua_State *L, int errcode)
2656   |.  move CARG1, L
2657   |.endif
2658   |
2659   |//-----------------------------------------------------------------------
2660   |//-- Math helper functions ----------------------------------------------
2661   |//-----------------------------------------------------------------------
2662   |
2663   |// Hard-float round to integer.
2664   |// Modifies AT, TMP0, FRET1, FRET2, f4. Keeps all others incl. FARG1.
2665   |// MIPSR6: Modifies FTMP1, too.
2666   |.macro vm_round_hf, func
2667   |  lui TMP0, 0x4330                   // Hiword of 2^52 (double).
2668   |  dsll TMP0, TMP0, 32
2669   |  dmtc1 TMP0, f4
2670   |  abs.d FRET2, FARG1                 // |x|
2671   |    dmfc1 AT, FARG1
2672   |.if MIPSR6
2673   |  cmp.lt.d FTMP1, FRET2, f4
2674   |   add.d FRET1, FRET2, f4            // (|x| + 2^52) - 2^52
2675   |  bc1eqz FTMP1, >1                   // Truncate only if |x| < 2^52.
2676   |.else
2677   |  c.olt.d 0, FRET2, f4
2678   |   add.d FRET1, FRET2, f4            // (|x| + 2^52) - 2^52
2679   |  bc1f 0, >1                         // Truncate only if |x| < 2^52.
2680   |.endif
2681   |.  sub.d FRET1, FRET1, f4
2682   |    slt AT, AT, r0
2683   |.if "func" == "ceil"
2684   |   lui TMP0, 0xbff0                  // Hiword of -1 (double). Preserves -0.
2685   |.else
2686   |   lui TMP0, 0x3ff0                  // Hiword of +1 (double).
2687   |.endif
2688   |.if "func" == "trunc"
2689   |   dsll TMP0, TMP0, 32
2690   |   dmtc1 TMP0, f4
2691   |.if MIPSR6
2692   |  cmp.lt.d FTMP1, FRET2, FRET1       // |x| < result?
2693   |   sub.d FRET2, FRET1, f4
2694   |  sel.d  FTMP1, FRET1, FRET2         // If yes, subtract +1.
2695   |  dmtc1 AT, FRET1
2696   |  neg.d FRET2, FTMP1
2697   |  jr ra
2698   |.  sel.d FRET1, FTMP1, FRET2         // Merge sign bit back in.
2699   |.else
2700   |  c.olt.d 0, FRET2, FRET1            // |x| < result?
2701   |   sub.d FRET2, FRET1, f4
2702   |  movt.d FRET1, FRET2, 0             // If yes, subtract +1.
2703   |  neg.d FRET2, FRET1
2704   |  jr ra
2705   |.  movn.d FRET1, FRET2, AT           // Merge sign bit back in.
2706   |.endif
2707   |.else
2708   |  neg.d FRET2, FRET1
2709   |   dsll TMP0, TMP0, 32
2710   |   dmtc1 TMP0, f4
2711   |.if MIPSR6
2712   |  dmtc1 AT, FTMP1
2713   |  sel.d FTMP1, FRET1, FRET2
2714   |.if "func" == "ceil"
2715   |  cmp.lt.d FRET1, FTMP1, FARG1       // x > result?
2716   |.else
2717   |  cmp.lt.d FRET1, FARG1, FTMP1       // x < result?
2718   |.endif
2719   |   sub.d FRET2, FTMP1, f4            // If yes, subtract +-1.
2720   |  jr ra
2721   |.  sel.d FRET1, FTMP1, FRET2
2722   |.else
2723   |  movn.d FRET1, FRET2, AT            // Merge sign bit back in.
2724   |.if "func" == "ceil"
2725   |  c.olt.d 0, FRET1, FARG1            // x > result?
2726   |.else
2727   |  c.olt.d 0, FARG1, FRET1            // x < result?
2728   |.endif
2729   |   sub.d FRET2, FRET1, f4            // If yes, subtract +-1.
2730   |  jr ra
2731   |.  movt.d FRET1, FRET2, 0
2732   |.endif
2733   |.endif
2734   |1:
2735   |  jr ra
2736   |.  mov.d FRET1, FARG1
2737   |.endmacro
2738   |
2739   |.macro vm_round, func
2740   |.if FPU
2741   |  vm_round_hf, func
2742   |.endif
2743   |.endmacro
2744   |
2745   |->vm_floor:
2746   |  vm_round floor
2747   |->vm_ceil:
2748   |  vm_round ceil
2749   |->vm_trunc:
2750   |.if JIT
2751   |  vm_round trunc
2752   |.endif
2753   |
2754   |// Soft-float integer to number conversion.
2755   |.macro sfi2d, ARG
2756   |.if not FPU
2757   |  beqz ARG, >9                       // Handle zero first.
2758   |.  sra TMP0, ARG, 31
2759   |  xor TMP1, ARG, TMP0
2760   |  dsubu TMP1, TMP1, TMP0             // Absolute value in TMP1.
2761   |  dclz ARG, TMP1
2762   |  addiu ARG, ARG, -11
2763   |  li AT, 0x3ff+63-11-1
2764   |   dsllv TMP1, TMP1, ARG             // Align mantissa left with leading 1.
2765   |  subu ARG, AT, ARG                  // Exponent - 1.
2766   |  ins ARG, TMP0, 11, 11              // Sign | Exponent.
2767   |  dsll ARG, ARG, 52                  // Align left.
2768   |  jr ra
2769   |.  daddu ARG, ARG, TMP1              // Add mantissa, increment exponent.
2770   |9:
2771   |  jr ra
2772   |.  nop
2773   |.endif
2774   |.endmacro
2775   |
2776   |// Input CARG1. Output: CARG1. Temporaries: AT, TMP0, TMP1.
2777   |->vm_sfi2d_1:
2778   |  sfi2d CARG1
2779   |
2780   |// Input CARG2. Output: CARG2. Temporaries: AT, TMP0, TMP1.
2781   |->vm_sfi2d_2:
2782   |  sfi2d CARG2
2783   |
2784   |// Soft-float comparison. Equivalent to c.eq.d.
2785   |// Input: CARG*. Output: CRET1. Temporaries: AT, TMP0, TMP1.
2786   |->vm_sfcmpeq:
2787   |.if not FPU
2788   |  dsll AT, CARG1, 1
2789   |  dsll TMP0, CARG2, 1
2790   |  or TMP1, AT, TMP0
2791   |  beqz TMP1, >8                      // Both args +-0: return 1.
2792   |.  lui TMP1, 0xffe0
2793   |  dsll TMP1, TMP1, 32
2794   |   sltu AT, TMP1, AT
2795   |   sltu TMP0, TMP1, TMP0
2796   |  or TMP1, AT, TMP0
2797   |  bnez TMP1, >9                      // Either arg is NaN: return 0;
2798   |.  xor AT, CARG1, CARG2
2799   |  jr ra
2800   |.  sltiu CRET1, AT, 1                // Same values: return 1.
2801   |8:
2802   |  jr ra
2803   |.  li CRET1, 1
2804   |9:
2805   |  jr ra
2806   |.  li CRET1, 0
2807   |.endif
2808   |
2809   |// Soft-float comparison. Equivalent to c.ult.d and c.olt.d.
2810   |// Input: CARG1, CARG2. Output: CRET1. Temporaries: AT, TMP0, TMP1, CRET2.
2811   |->vm_sfcmpult:
2812   |.if not FPU
2813   |  b >1
2814   |.  li CRET2, 1
2815   |.endif
2816   |
2817   |->vm_sfcmpolt:
2818   |.if not FPU
2819   |  li CRET2, 0
2820   |1:
2821   |  dsll AT, CARG1, 1
2822   |  dsll TMP0, CARG2, 1
2823   |  or TMP1, AT, TMP0
2824   |  beqz TMP1, >8                      // Both args +-0: return 0.
2825   |.  lui TMP1, 0xffe0
2826   |  dsll TMP1, TMP1, 32
2827   |   sltu AT, TMP1, AT
2828   |   sltu TMP0, TMP1, TMP0
2829   |  or TMP1, AT, TMP0
2830   |  bnez TMP1, >9                      // Either arg is NaN: return 0 or 1;
2831   |.  and AT, CARG1, CARG2
2832   |  bltz AT, >5                        // Both args negative?
2833   |.  nop
2834   |  jr ra
2835   |.  slt CRET1, CARG1, CARG2
2836   |5:  // Swap conditions if both operands are negative.
2837   |  jr ra
2838   |.  slt CRET1, CARG2, CARG1
2839   |8:
2840   |  jr ra
2841   |.  li CRET1, 0
2842   |9:
2843   |  jr ra
2844   |.  move CRET1, CRET2
2845   |.endif
2846   |
2847   |->vm_sfcmpogt:
2848   |.if not FPU
2849   |  dsll AT, CARG2, 1
2850   |  dsll TMP0, CARG1, 1
2851   |  or TMP1, AT, TMP0
2852   |  beqz TMP1, >8                      // Both args +-0: return 0.
2853   |.  lui TMP1, 0xffe0
2854   |  dsll TMP1, TMP1, 32
2855   |   sltu AT, TMP1, AT
2856   |   sltu TMP0, TMP1, TMP0
2857   |  or TMP1, AT, TMP0
2858   |  bnez TMP1, >9                      // Either arg is NaN: return 0 or 1;
2859   |.  and AT, CARG2, CARG1
2860   |  bltz AT, >5                        // Both args negative?
2861   |.  nop
2862   |  jr ra
2863   |.  slt CRET1, CARG2, CARG1
2864   |5:  // Swap conditions if both operands are negative.
2865   |  jr ra
2866   |.  slt CRET1, CARG1, CARG2
2867   |8:
2868   |  jr ra
2869   |.  li CRET1, 0
2870   |9:
2871   |  jr ra
2872   |.  li CRET1, 0
2873   |.endif
2874   |
2875   |// Soft-float comparison. Equivalent to c.ole.d a, b or c.ole.d b, a.
2876   |// Input: CARG1, CARG2, TMP3. Output: CRET1. Temporaries: AT, TMP0, TMP1.
2877   |->vm_sfcmpolex:
2878   |.if not FPU
2879   |  dsll AT, CARG1, 1
2880   |  dsll TMP0, CARG2, 1
2881   |  or TMP1, AT, TMP0
2882   |  beqz TMP1, >8                      // Both args +-0: return 1.
2883   |.  lui TMP1, 0xffe0
2884   |  dsll TMP1, TMP1, 32
2885   |   sltu AT, TMP1, AT
2886   |   sltu TMP0, TMP1, TMP0
2887   |  or TMP1, AT, TMP0
2888   |  bnez TMP1, >9                      // Either arg is NaN: return 0;
2889   |.  and AT, CARG1, CARG2
2890   |  xor AT, AT, TMP3
2891   |  bltz AT, >5                        // Both args negative?
2892   |.  nop
2893   |  jr ra
2894   |.  slt CRET1, CARG2, CARG1
2895   |5:  // Swap conditions if both operands are negative.
2896   |  jr ra
2897   |.  slt CRET1, CARG1, CARG2
2898   |8:
2899   |  jr ra
2900   |.  li CRET1, 1
2901   |9:
2902   |  jr ra
2903   |.  li CRET1, 0
2904   |.endif
2905   |
2906   |.macro sfmin_max, name, fpcall
2907   |->vm_sf .. name:
2908   |.if JIT and not FPU
2909   |  move TMP2, ra
2910   |  bal ->fpcall
2911   |.  nop
2912   |  move ra, TMP2
2913   |  move TMP0, CRET1
2914   |  move CRET1, CARG1
2915   |.if MIPSR6
2916   |  selnez CRET1, CRET1, TMP0
2917   |  seleqz TMP0, CARG2, TMP0
2918   |  jr ra
2919   |.  or CRET1, CRET1, TMP0
2920   |.else
2921   |  jr ra
2922   |.  movz CRET1, CARG2, TMP0
2923   |.endif
2924   |.endif
2925   |.endmacro
2926   |
2927   |  sfmin_max min, vm_sfcmpolt
2928   |  sfmin_max max, vm_sfcmpogt
2929   |
2930   |//-----------------------------------------------------------------------
2931   |//-- Miscellaneous functions --------------------------------------------
2932   |//-----------------------------------------------------------------------
2933   |
2934   |.define NEXT_TAB,            TAB:CARG1
2935   |.define NEXT_IDX,            CARG2
2936   |.define NEXT_ASIZE,          CARG3
2937   |.define NEXT_NIL,            CARG4
2938   |.define NEXT_TMP0,           r12
2939   |.define NEXT_TMP1,           r13
2940   |.define NEXT_TMP2,           r14
2941   |.define NEXT_RES_VK,         CRET1
2942   |.define NEXT_RES_IDX,        CRET2
2943   |.define NEXT_RES_PTR,        sp
2944   |.define NEXT_RES_VAL,        0(sp)
2945   |.define NEXT_RES_KEY,        8(sp)
2946   |
2947   |// TValue *lj_vm_next(GCtab *t, uint32_t idx)
2948   |// Next idx returned in CRET2.
2949   |->vm_next:
2950   |.if JIT and ENDIAN_LE
2951   |   lw NEXT_ASIZE, NEXT_TAB->asize
2952   |  ld NEXT_TMP0, NEXT_TAB->array
2953   |    li NEXT_NIL, LJ_TNIL
2954   |1:  // Traverse array part.
2955   |   sltu AT, NEXT_IDX, NEXT_ASIZE
2956   |    sll NEXT_TMP1, NEXT_IDX, 3
2957   |   beqz AT, >5
2958   |.   daddu NEXT_TMP1, NEXT_TMP0, NEXT_TMP1
2959   |   li AT, LJ_TISNUM
2960   |  ld NEXT_TMP2, 0(NEXT_TMP1)
2961   |   dsll AT, AT, 47
2962   |   or NEXT_TMP1, NEXT_IDX, AT
2963   |  beq NEXT_TMP2, NEXT_NIL, <1
2964   |.  addiu NEXT_IDX, NEXT_IDX, 1
2965   |  sd NEXT_TMP2, NEXT_RES_VAL
2966   |   sd NEXT_TMP1, NEXT_RES_KEY
2967   |  move NEXT_RES_VK, NEXT_RES_PTR
2968   |  jr ra
2969   |.  move NEXT_RES_IDX, NEXT_IDX
2970   |
2971   |5:  // Traverse hash part.
2972   |  subu NEXT_RES_IDX, NEXT_IDX, NEXT_ASIZE
2973   |   ld NODE:NEXT_RES_VK, NEXT_TAB->node
2974   |    sll NEXT_TMP2, NEXT_RES_IDX, 5
2975   |  lw NEXT_TMP0, NEXT_TAB->hmask
2976   |    sll AT, NEXT_RES_IDX, 3
2977   |    subu AT, NEXT_TMP2, AT
2978   |   daddu NODE:NEXT_RES_VK, NODE:NEXT_RES_VK, AT
2979   |6:
2980   |  sltu AT, NEXT_TMP0, NEXT_RES_IDX
2981   |  bnez AT, >8
2982   |.  nop
2983   |  ld NEXT_TMP2, NODE:NEXT_RES_VK->val
2984   |  bne NEXT_TMP2, NEXT_NIL, >9
2985   |.  addiu NEXT_RES_IDX, NEXT_RES_IDX, 1
2986   |  // Skip holes in hash part.
2987   |  b <6
2988   |.  daddiu NODE:NEXT_RES_VK, NODE:NEXT_RES_VK, sizeof(Node)
2989   |
2990   |8:  // End of iteration. Set the key to nil (not the value).
2991   |  sd NEXT_NIL, NEXT_RES_KEY
2992   |  move NEXT_RES_VK, NEXT_RES_PTR
2993   |9:
2994   |  jr ra
2995   |.  addu NEXT_RES_IDX, NEXT_RES_IDX, NEXT_ASIZE
2996   |.endif
2997   |
2998   |//-----------------------------------------------------------------------
2999   |//-- FFI helper functions -----------------------------------------------
3000   |//-----------------------------------------------------------------------
3001   |
3002   |// Handler for callback functions. Callback slot number in r1, g in r2.
3003   |->vm_ffi_callback:
3004   |.if FFI
3005   |.type CTSTATE, CTState, PC
3006   |  saveregs
3007   |  ld CTSTATE, GL:r2->ctype_state
3008   |   daddiu DISPATCH, r2, GG_G2DISP
3009   |  load_got lj_ccallback_enter
3010   |  sw r1, CTSTATE->cb.slot
3011   |  sd CARG1, CTSTATE->cb.gpr[0]
3012   |  .FPU sdc1 FARG1, CTSTATE->cb.fpr[0]
3013   |  sd CARG2, CTSTATE->cb.gpr[1]
3014   |  .FPU sdc1 FARG2, CTSTATE->cb.fpr[1]
3015   |  sd CARG3, CTSTATE->cb.gpr[2]
3016   |  .FPU sdc1 FARG3, CTSTATE->cb.fpr[2]
3017   |  sd CARG4, CTSTATE->cb.gpr[3]
3018   |  .FPU sdc1 FARG4, CTSTATE->cb.fpr[3]
3019   |  sd CARG5, CTSTATE->cb.gpr[4]
3020   |  .FPU sdc1 FARG5, CTSTATE->cb.fpr[4]
3021   |  sd CARG6, CTSTATE->cb.gpr[5]
3022   |  .FPU sdc1 FARG6, CTSTATE->cb.fpr[5]
3023   |  sd CARG7, CTSTATE->cb.gpr[6]
3024   |  .FPU sdc1 FARG7, CTSTATE->cb.fpr[6]
3025   |  sd CARG8, CTSTATE->cb.gpr[7]
3026   |  .FPU sdc1 FARG8, CTSTATE->cb.fpr[7]
3027   |  daddiu TMP0, sp, CFRAME_SPACE
3028   |  sd TMP0, CTSTATE->cb.stack
3029   |  sd r0, SAVE_PC                     // Any value outside of bytecode is ok.
3030   |   move CARG2, sp
3031   |  call_intern lj_ccallback_enter     // (CTState *cts, void *cf)
3032   |.  move CARG1, CTSTATE
3033   |  // Returns lua_State *.
3034   |  ld BASE, L:CRET1->base
3035   |  ld RC, L:CRET1->top
3036   |   move L, CRET1
3037   |     .FPU lui TMP3, 0x59c0           // TOBIT = 2^52 + 2^51 (float).
3038   |  ld LFUNC:RB, FRAME_FUNC(BASE)
3039   |     .FPU mtc1 TMP3, TOBIT
3040   |      li TISNIL, LJ_TNIL
3041   |       li TISNUM, LJ_TISNUM
3042   |    li_vmstate INTERP
3043   |  subu RC, RC, BASE
3044   |   cleartp LFUNC:RB
3045   |    st_vmstate
3046   |     .FPU cvt.d.s TOBIT, TOBIT
3047   |  ins_callt
3048   |.endif
3049   |
3050   |->cont_ffi_callback:                 // Return from FFI callback.
3051   |.if FFI
3052   |  load_got lj_ccallback_leave
3053   |  ld CTSTATE, DISPATCH_GL(ctype_state)(DISPATCH)
3054   |   sd BASE, L->base
3055   |   sd RB, L->top
3056   |  sd L, CTSTATE->L
3057   |  move CARG2, RA
3058   |  call_intern lj_ccallback_leave     // (CTState *cts, TValue *o)
3059   |.  move CARG1, CTSTATE
3060   |  .FPU ldc1 FRET1, CTSTATE->cb.fpr[0]
3061   |  ld CRET1, CTSTATE->cb.gpr[0]
3062   |  .FPU ldc1 FRET2, CTSTATE->cb.fpr[1]
3063   |  b ->vm_leave_unw
3064   |.  ld CRET2, CTSTATE->cb.gpr[1]
3065   |.endif
3066   |
3067   |->vm_ffi_call:                       // Call C function via FFI.
3068   |  // Caveat: needs special frame unwinding, see below.
3069   |.if FFI
3070   |  .type CCSTATE, CCallState, CARG1
3071   |  lw TMP1, CCSTATE->spadj
3072   |   lbu CARG2, CCSTATE->nsp
3073   |  move TMP2, sp
3074   |  dsubu sp, sp, TMP1
3075   |  sd ra, -8(TMP2)
3076   |  sd r16, -16(TMP2)
3077   |  sd CCSTATE, -24(TMP2)
3078   |  move r16, TMP2
3079   |  daddiu TMP1, CCSTATE, offsetof(CCallState, stack)
3080   |  move TMP2, sp
3081   |  beqz CARG2, >2
3082   |.  daddu TMP3, TMP1, CARG2
3083   |1:
3084   |   ld TMP0, 0(TMP1)
3085   |  daddiu TMP1, TMP1, 8
3086   |  sltu AT, TMP1, TMP3
3087   |   sd TMP0, 0(TMP2)
3088   |  bnez AT, <1
3089   |.  daddiu TMP2, TMP2, 8
3090   |2:
3091   |  ld CFUNCADDR, CCSTATE->func
3092   |  .FPU ldc1 FARG1, CCSTATE->gpr[0]
3093   |  ld CARG2, CCSTATE->gpr[1]
3094   |  .FPU ldc1 FARG2, CCSTATE->gpr[1]
3095   |  ld CARG3, CCSTATE->gpr[2]
3096   |  .FPU ldc1 FARG3, CCSTATE->gpr[2]
3097   |  ld CARG4, CCSTATE->gpr[3]
3098   |  .FPU ldc1 FARG4, CCSTATE->gpr[3]
3099   |  ld CARG5, CCSTATE->gpr[4]
3100   |  .FPU ldc1 FARG5, CCSTATE->gpr[4]
3101   |  ld CARG6, CCSTATE->gpr[5]
3102   |  .FPU ldc1 FARG6, CCSTATE->gpr[5]
3103   |  ld CARG7, CCSTATE->gpr[6]
3104   |  .FPU ldc1 FARG7, CCSTATE->gpr[6]
3105   |  ld CARG8, CCSTATE->gpr[7]
3106   |  .FPU ldc1 FARG8, CCSTATE->gpr[7]
3107   |  jalr CFUNCADDR
3108   |.  ld CARG1, CCSTATE->gpr[0]         // Do this last, since CCSTATE is CARG1.
3109   |  ld CCSTATE:TMP1, -24(r16)
3110   |  ld TMP2, -16(r16)
3111   |  ld ra, -8(r16)
3112   |  sd CRET1, CCSTATE:TMP1->gpr[0]
3113   |  sd CRET2, CCSTATE:TMP1->gpr[1]
3114   |.if FPU
3115   |  sdc1 FRET1, CCSTATE:TMP1->fpr[0]
3116   |  sdc1 FRET2, CCSTATE:TMP1->fpr[1]
3117   |.else
3118   |  sd CARG1, CCSTATE:TMP1->gpr[2]     // 2nd FP struct field for soft-float.
3119   |.endif
3120   |  move sp, r16
3121   |  jr ra
3122   |.  move r16, TMP2
3123   |.endif
3124   |// Note: vm_ffi_call must be the last function in this object file!
3125   |
3126   |//-----------------------------------------------------------------------
3129 /* Generate the code for a single instruction. */
3130 static void build_ins(BuildCtx *ctx, BCOp op, int defop)
3132   int vk = 0;
3133   |=>defop:
3135   switch (op) {
3137   /* -- Comparison ops ---------------------------------------------------- */
3139   /* Remember: all ops branch for a true comparison, fall through otherwise. */
3141   case BC_ISLT: case BC_ISGE: case BC_ISLE: case BC_ISGT:
3142     |  // RA = src1*8, RD = src2*8, JMP with RD = target
3143     |.macro bc_comp, FRA, FRD, ARGRA, ARGRD, movop, fmovop, fcomp, sfcomp
3144     |  daddu RA, BASE, RA
3145     |   daddu RD, BASE, RD
3146     |  ld ARGRA, 0(RA)
3147     |   ld ARGRD, 0(RD)
3148     |    lhu TMP2, OFS_RD(PC)
3149     |  gettp CARG3, ARGRA
3150     |   gettp CARG4, ARGRD
3151     |  bne CARG3, TISNUM, >2
3152     |.   daddiu PC, PC, 4
3153     |  bne CARG4, TISNUM, >5
3154     |.   decode_RD4b TMP2
3155     |  sextw ARGRA, ARGRA
3156     |   sextw ARGRD, ARGRD
3157     |    lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3158     |  slt AT, CARG1, CARG2
3159     |    addu TMP2, TMP2, TMP3
3160     |.if MIPSR6
3161     |  movop TMP2, TMP2, AT
3162     |.else
3163     |  movop TMP2, r0, AT
3164     |.endif
3165     |1:
3166     |  daddu PC, PC, TMP2
3167     |  ins_next
3168     |
3169     |2:  // RA is not an integer.
3170     |  sltiu AT, CARG3, LJ_TISNUM
3171     |  beqz AT, ->vmeta_comp
3172     |.   lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3173     |  sltiu AT, CARG4, LJ_TISNUM
3174     |  beqz AT, >4
3175     |.   decode_RD4b TMP2
3176     |.if FPU
3177     |  ldc1 FRA, 0(RA)
3178     |   ldc1 FRD, 0(RD)
3179     |.endif
3180     |3:  // RA and RD are both numbers.
3181     |.if FPU
3182     |.if MIPSR6
3183     |  fcomp FTMP0, FTMP0, FTMP2
3184     |   addu TMP2, TMP2, TMP3
3185     |  mfc1 TMP3, FTMP0
3186     |  b <1
3187     |.  fmovop TMP2, TMP2, TMP3
3188     |.else
3189     |  fcomp FTMP0, FTMP2
3190     |   addu TMP2, TMP2, TMP3
3191     |  b <1
3192     |.  fmovop TMP2, r0
3193     |.endif
3194     |.else
3195     |  bal sfcomp
3196     |.   addu TMP2, TMP2, TMP3
3197     |  b <1
3198     |.if MIPSR6
3199     |.  movop TMP2, TMP2, CRET1
3200     |.else
3201     |.  movop TMP2, r0, CRET1
3202     |.endif
3203     |.endif
3204     |
3205     |4:  // RA is a number, RD is not a number.
3206     |  bne CARG4, TISNUM, ->vmeta_comp
3207     |  // RA is a number, RD is an integer. Convert RD to a number.
3208     |.if FPU
3209     |.  lwc1 FRD, LO(RD)
3210     |  ldc1 FRA, 0(RA)
3211     |  b <3
3212     |.  cvt.d.w FRD, FRD
3213     |.else
3214     |.if "ARGRD" == "CARG1"
3215     |.  sextw CARG1, CARG1
3216     |  bal ->vm_sfi2d_1
3217     |.  nop
3218     |.else
3219     |.  sextw CARG2, CARG2
3220     |  bal ->vm_sfi2d_2
3221     |.  nop
3222     |.endif
3223     |  b <3
3224     |.  nop
3225     |.endif
3226     |
3227     |5:  // RA is an integer, RD is not an integer
3228     |  sltiu AT, CARG4, LJ_TISNUM
3229     |  beqz AT, ->vmeta_comp
3230     |.  lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3231     |  // RA is an integer, RD is a number. Convert RA to a number.
3232     |.if FPU
3233     |   lwc1 FRA, LO(RA)
3234     |   ldc1 FRD, 0(RD)
3235     |  b <3
3236     |   cvt.d.w FRA, FRA
3237     |.else
3238     |.if "ARGRA" == "CARG1"
3239     |  bal ->vm_sfi2d_1
3240     |.  sextw CARG1, CARG1
3241     |.else
3242     |  bal ->vm_sfi2d_2
3243     |.  sextw CARG2, CARG2
3244     |.endif
3245     |  b <3
3246     |.  nop
3247     |.endif
3248     |.endmacro
3249     |
3250     |.if MIPSR6
3251     if (op == BC_ISLT) {
3252       |  bc_comp FTMP0, FTMP2, CARG1, CARG2, selnez, selnez, cmp.lt.d, ->vm_sfcmpolt
3253     } else if (op == BC_ISGE) {
3254       |  bc_comp FTMP0, FTMP2, CARG1, CARG2, seleqz, seleqz, cmp.lt.d, ->vm_sfcmpolt
3255     } else if (op == BC_ISLE) {
3256       |  bc_comp FTMP2, FTMP0, CARG2, CARG1, seleqz, seleqz, cmp.ult.d, ->vm_sfcmpult
3257     } else {
3258       |  bc_comp FTMP2, FTMP0, CARG2, CARG1, selnez, selnez, cmp.ult.d, ->vm_sfcmpult
3259     }
3260     |.else
3261     if (op == BC_ISLT) {
3262       |  bc_comp FTMP0, FTMP2, CARG1, CARG2, movz, movf, c.olt.d, ->vm_sfcmpolt
3263     } else if (op == BC_ISGE) {
3264       |  bc_comp FTMP0, FTMP2, CARG1, CARG2, movn, movt, c.olt.d, ->vm_sfcmpolt
3265     } else if (op == BC_ISLE) {
3266       |  bc_comp FTMP2, FTMP0, CARG2, CARG1, movn, movt, c.ult.d, ->vm_sfcmpult
3267     } else {
3268       |  bc_comp FTMP2, FTMP0, CARG2, CARG1, movz, movf, c.ult.d, ->vm_sfcmpult
3269     }
3270     |.endif
3271     break;
3273   case BC_ISEQV: case BC_ISNEV:
3274     vk = op == BC_ISEQV;
3275     |  // RA = src1*8, RD = src2*8, JMP with RD = target
3276     |  daddu RA, BASE, RA
3277     |    daddiu PC, PC, 4
3278     |   daddu RD, BASE, RD
3279     |  ld CARG1, 0(RA)
3280     |    lhu TMP2, -4+OFS_RD(PC)
3281     |   ld CARG2, 0(RD)
3282     |  gettp CARG3, CARG1
3283     |   gettp CARG4, CARG2
3284     |  sltu AT, TISNUM, CARG3
3285     |   sltu TMP1, TISNUM, CARG4
3286     |  or AT, AT, TMP1
3287     if (vk) {
3288       |  beqz AT, ->BC_ISEQN_Z
3289     } else {
3290       |  beqz AT, ->BC_ISNEN_Z
3291     }
3292     |  // Either or both types are not numbers.
3293     |    lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3294     |.if FFI
3295     |.  li AT, LJ_TCDATA
3296     |  beq CARG3, AT, ->vmeta_equal_cd
3297     |.endif
3298     |   decode_RD4b TMP2
3299     |.if FFI
3300     |  beq CARG4, AT, ->vmeta_equal_cd
3301     |.  nop
3302     |.endif
3303     |  bne CARG1, CARG2, >2
3304     |.  addu TMP2, TMP2, TMP3
3305     |  // Tag and value are equal.
3306     if (vk) {
3307       |->BC_ISEQV_Z:
3308       |  daddu PC, PC, TMP2
3309     }
3310     |1:
3311     |  ins_next
3312     |
3313     |2:  // Check if the tags are the same and it's a table or userdata.
3314     |  xor AT, CARG3, CARG4                     // Same type?
3315     |  sltiu TMP0, CARG3, LJ_TISTABUD+1         // Table or userdata?
3316     |.if MIPSR6
3317     |  seleqz TMP0, TMP0, AT
3318     |.else
3319     |  movn TMP0, r0, AT
3320     |.endif
3321     if (vk) {
3322       |  beqz TMP0, <1
3323     } else {
3324       |  beqz TMP0, ->BC_ISEQV_Z  // Reuse code from opposite instruction.
3325     }
3326     |  // Different tables or userdatas. Need to check __eq metamethod.
3327     |  // Field metatable must be at same offset for GCtab and GCudata!
3328     |.  cleartp TAB:TMP1, CARG1
3329     |  ld TAB:TMP3, TAB:TMP1->metatable
3330     if (vk) {
3331       |  beqz TAB:TMP3, <1              // No metatable?
3332       |.  nop
3333       |  lbu TMP3, TAB:TMP3->nomm
3334       |  andi TMP3, TMP3, 1<<MM_eq
3335       |  bnez TMP3, >1                  // Or 'no __eq' flag set?
3336     } else {
3337       |  beqz TAB:TMP3,->BC_ISEQV_Z     // No metatable?
3338       |.  nop
3339       |  lbu TMP3, TAB:TMP3->nomm
3340       |  andi TMP3, TMP3, 1<<MM_eq
3341       |  bnez TMP3, ->BC_ISEQV_Z        // Or 'no __eq' flag set?
3342     }
3343     |.  nop
3344     |  b ->vmeta_equal                  // Handle __eq metamethod.
3345     |.  li TMP0, 1-vk                   // ne = 0 or 1.
3346     break;
3348   case BC_ISEQS: case BC_ISNES:
3349     vk = op == BC_ISEQS;
3350     |  // RA = src*8, RD = str_const*8 (~), JMP with RD = target
3351     |  daddu RA, BASE, RA
3352     |   daddiu PC, PC, 4
3353     |  ld CARG1, 0(RA)
3354     |   dsubu RD, KBASE, RD
3355     |    lhu TMP2, -4+OFS_RD(PC)
3356     |   ld CARG2, -8(RD)                // KBASE-8-str_const*8
3357     |.if FFI
3358     |  gettp TMP0, CARG1
3359     |  li AT, LJ_TCDATA
3360     |.endif
3361     |  li TMP1, LJ_TSTR
3362     |   decode_RD4b TMP2
3363     |.if FFI
3364     |  beq TMP0, AT, ->vmeta_equal_cd
3365     |.endif
3366     |.  settp CARG2, TMP1
3367     |   lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3368     |  xor TMP1, CARG1, CARG2
3369     |   addu TMP2, TMP2, TMP3
3370     |.if MIPSR6
3371     if (vk) {
3372       |  seleqz TMP2, TMP2, TMP1
3373     } else {
3374       |  selnez TMP2, TMP2, TMP1
3375     }
3376     |.else
3377     if (vk) {
3378       |  movn TMP2, r0, TMP1
3379     } else {
3380       |  movz TMP2, r0, TMP1
3381     }
3382     |.endif
3383     |  daddu PC, PC, TMP2
3384     |  ins_next
3385     break;
3387   case BC_ISEQN: case BC_ISNEN:
3388     vk = op == BC_ISEQN;
3389     |  // RA = src*8, RD = num_const*8, JMP with RD = target
3390     |  daddu RA, BASE, RA
3391     |   daddu RD, KBASE, RD
3392     |  ld CARG1, 0(RA)
3393     |   ld CARG2, 0(RD)
3394     |    lhu TMP2, OFS_RD(PC)
3395     |  gettp CARG3, CARG1
3396     |   gettp CARG4, CARG2
3397     |    daddiu PC, PC, 4
3398     |    lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3399     if (vk) {
3400       |->BC_ISEQN_Z:
3401     } else {
3402       |->BC_ISNEN_Z:
3403     }
3404     |  bne CARG3, TISNUM, >3
3405     |.   decode_RD4b TMP2
3406     |  bne CARG4, TISNUM, >6
3407     |.   addu TMP2, TMP2, TMP3
3408     |  xor AT, CARG1, CARG2
3409     |.if MIPSR6
3410     if (vk) {
3411       | seleqz TMP2, TMP2, AT
3412       |1:
3413       |  daddu PC, PC, TMP2
3414       |2:
3415     } else {
3416       |  selnez TMP2, TMP2, AT
3417       |1:
3418       |2:
3419       |  daddu PC, PC, TMP2
3420     }
3421     |.else
3422     if (vk) {
3423       | movn TMP2, r0, AT
3424       |1:
3425       |  daddu PC, PC, TMP2
3426       |2:
3427     } else {
3428       |  movz TMP2, r0, AT
3429       |1:
3430       |2:
3431       |  daddu PC, PC, TMP2
3432     }
3433     |.endif
3434     |  ins_next
3435     |
3436     |3:  // RA is not an integer.
3437     |  sltu AT, CARG3, TISNUM
3438     |.if FFI
3439     |  beqz AT, >8
3440     |.else
3441     |  beqz AT, <2
3442     |.endif
3443     |.   addu TMP2, TMP2, TMP3
3444     |  sltu AT, CARG4, TISNUM
3445     |.if FPU
3446     |  ldc1 FTMP0, 0(RA)
3447     |   ldc1 FTMP2, 0(RD)
3448     |.endif
3449     |  beqz AT, >5
3450     |.  nop
3451     |4:  // RA and RD are both numbers.
3452     |.if FPU
3453     |.if MIPSR6
3454     |  cmp.eq.d FTMP0, FTMP0, FTMP2
3455     |  dmfc1 TMP1, FTMP0
3456     |  b <1
3457     if (vk) {
3458       |.  selnez TMP2, TMP2, TMP1
3459     } else {
3460       |.  seleqz TMP2, TMP2, TMP1
3461     }
3462     |.else
3463     |  c.eq.d FTMP0, FTMP2
3464     |  b <1
3465     if (vk) {
3466       |.  movf TMP2, r0
3467     } else {
3468       |.  movt TMP2, r0
3469     }
3470     |.endif
3471     |.else
3472     |  bal ->vm_sfcmpeq
3473     |.  nop
3474     |  b <1
3475     |.if MIPSR6
3476     if (vk) {
3477       |.  selnez TMP2, TMP2, CRET1
3478     } else {
3479       |.  seleqz TMP2, TMP2, CRET1
3480     }
3481     |.else
3482     if (vk) {
3483       |.  movz TMP2, r0, CRET1
3484     } else {
3485       |.  movn TMP2, r0, CRET1
3486     }
3487     |.endif
3488     |.endif
3489     |
3490     |5:  // RA is a number, RD is not a number.
3491     |.if FFI
3492     |  bne CARG4, TISNUM, >9
3493     |.else
3494     |  bne CARG4, TISNUM, <2
3495     |.endif
3496     |  // RA is a number, RD is an integer. Convert RD to a number.
3497     |.if FPU
3498     |.  lwc1 FTMP2, LO(RD)
3499     |  b <4
3500     |.  cvt.d.w FTMP2, FTMP2
3501     |.else
3502     |.  sextw CARG2, CARG2
3503     |  bal ->vm_sfi2d_2
3504     |.  nop
3505     |  b <4
3506     |.  nop
3507     |.endif
3508     |
3509     |6:  // RA is an integer, RD is not an integer
3510     |  sltu AT, CARG4, TISNUM
3511     |.if FFI
3512     |  beqz AT, >9
3513     |.else
3514     |  beqz AT, <2
3515     |.endif
3516     |  // RA is an integer, RD is a number. Convert RA to a number.
3517     |.if FPU
3518     |.  lwc1 FTMP0, LO(RA)
3519     |   ldc1 FTMP2, 0(RD)
3520     |  b <4
3521     |   cvt.d.w FTMP0, FTMP0
3522     |.else
3523     |.  sextw CARG1, CARG1
3524     |  bal ->vm_sfi2d_1
3525     |.  nop
3526     |  b <4
3527     |.  nop
3528     |.endif
3529     |
3530     |.if FFI
3531     |8:
3532     |  li AT, LJ_TCDATA
3533     |  bne CARG3, AT, <2
3534     |.  nop
3535     |  b ->vmeta_equal_cd
3536     |.  nop
3537     |9:
3538     |  li AT, LJ_TCDATA
3539     |  bne CARG4, AT, <2
3540     |.  nop
3541     |  b ->vmeta_equal_cd
3542     |.  nop
3543     |.endif
3544     break;
3546   case BC_ISEQP: case BC_ISNEP:
3547     vk = op == BC_ISEQP;
3548     |  // RA = src*8, RD = primitive_type*8 (~), JMP with RD = target
3549     |  daddu RA, BASE, RA
3550     |   srl TMP1, RD, 3
3551     |  ld TMP0, 0(RA)
3552     |    lhu TMP2, OFS_RD(PC)
3553     |   not TMP1, TMP1
3554     |  gettp TMP0, TMP0
3555     |    daddiu PC, PC, 4
3556     |.if FFI
3557     |  li AT, LJ_TCDATA
3558     |  beq TMP0, AT, ->vmeta_equal_cd
3559     |.endif
3560     |.  xor TMP0, TMP0, TMP1
3561     |  decode_RD4b TMP2
3562     |  lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3563     |  addu TMP2, TMP2, TMP3
3564     |.if MIPSR6
3565     if (vk) {
3566       |  seleqz TMP2, TMP2, TMP0
3567     } else {
3568       |  selnez TMP2, TMP2, TMP0
3569     }
3570     |.else
3571     if (vk) {
3572       |  movn TMP2, r0, TMP0
3573     } else {
3574       |  movz TMP2, r0, TMP0
3575     }
3576     |.endif
3577     |  daddu PC, PC, TMP2
3578     |  ins_next
3579     break;
3581   /* -- Unary test and copy ops ------------------------------------------- */
3583   case BC_ISTC: case BC_ISFC: case BC_IST: case BC_ISF:
3584     |  // RA = dst*8 or unused, RD = src*8, JMP with RD = target
3585     |  daddu RD, BASE, RD
3586     |   lhu TMP2, OFS_RD(PC)
3587     |  ld TMP0, 0(RD)
3588     |   daddiu PC, PC, 4
3589     |  gettp TMP0, TMP0
3590     |  sltiu TMP0, TMP0, LJ_TISTRUECOND
3591     if (op == BC_IST || op == BC_ISF) {
3592       |   decode_RD4b TMP2
3593       |   lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3594       |   addu TMP2, TMP2, TMP3
3595       |.if MIPSR6
3596       if (op == BC_IST) {
3597         |  selnez TMP2, TMP2, TMP0;
3598       } else {
3599         |  seleqz TMP2, TMP2, TMP0;
3600       }
3601       |.else
3602       if (op == BC_IST) {
3603         |  movz TMP2, r0, TMP0
3604       } else {
3605         |  movn TMP2, r0, TMP0
3606       }
3607       |.endif
3608       |  daddu PC, PC, TMP2
3609     } else {
3610       |  ld CRET1, 0(RD)
3611       if (op == BC_ISTC) {
3612         |  beqz TMP0, >1
3613       } else {
3614         |  bnez TMP0, >1
3615       }
3616       |.  daddu RA, BASE, RA
3617       |   decode_RD4b TMP2
3618       |   lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
3619       |   addu TMP2, TMP2, TMP3
3620       |  sd CRET1, 0(RA)
3621       |   daddu PC, PC, TMP2
3622       |1:
3623     }
3624     |  ins_next
3625     break;
3627   case BC_ISTYPE:
3628     |  // RA = src*8, RD = -type*8
3629     |  daddu TMP2, BASE, RA
3630     |  srl TMP1, RD, 3
3631     |  ld TMP0, 0(TMP2)
3632     |  ins_next1
3633     |  gettp TMP0, TMP0
3634     |  daddu AT, TMP0, TMP1
3635     |  bnez AT, ->vmeta_istype
3636     |.  ins_next2
3637     break;
3638   case BC_ISNUM:
3639     |  // RA = src*8, RD = -(TISNUM-1)*8
3640     |  daddu TMP2, BASE, RA
3641     |  ld TMP0, 0(TMP2)
3642     |  ins_next1
3643     |  checknum TMP0, ->vmeta_istype
3644     |.  ins_next2
3645     break;
3647   /* -- Unary ops --------------------------------------------------------- */
3649   case BC_MOV:
3650     |  // RA = dst*8, RD = src*8
3651     |  daddu RD, BASE, RD
3652     |   daddu RA, BASE, RA
3653     |  ld CRET1, 0(RD)
3654     |  ins_next1
3655     |  sd CRET1, 0(RA)
3656     |  ins_next2
3657     break;
3658   case BC_NOT:
3659     |  // RA = dst*8, RD = src*8
3660     |  daddu RD, BASE, RD
3661     |   daddu RA, BASE, RA
3662     |  ld TMP0, 0(RD)
3663     |   li AT, LJ_TTRUE
3664     |  gettp TMP0, TMP0
3665     |  sltu TMP0, AT, TMP0
3666     |  addiu TMP0, TMP0, 1
3667     |  dsll TMP0, TMP0, 47
3668     |  not TMP0, TMP0
3669     |  ins_next1
3670     |   sd TMP0, 0(RA)
3671     |  ins_next2
3672     break;
3673   case BC_UNM:
3674     |  // RA = dst*8, RD = src*8
3675     |  daddu RB, BASE, RD
3676     |  ld CARG1, 0(RB)
3677     |    daddu RA, BASE, RA
3678     |  gettp CARG3, CARG1
3679     |  bne CARG3, TISNUM, >2
3680     |.  lui TMP1, 0x8000
3681     |  sextw CARG1, CARG1
3682     |  beq CARG1, TMP1, ->vmeta_unm     // Meta handler deals with -2^31.
3683     |.  negu CARG1, CARG1
3684     |  zextw CARG1, CARG1
3685     |  settp CARG1, TISNUM
3686     |1:
3687     |  ins_next1
3688     |   sd CARG1, 0(RA)
3689     |  ins_next2
3690     |2:
3691     |  sltiu AT, CARG3, LJ_TISNUM
3692     |  beqz AT, ->vmeta_unm
3693     |.  dsll TMP1, TMP1, 32
3694     |  b <1
3695     |.  xor CARG1, CARG1, TMP1
3696     break;
3697   case BC_LEN:
3698     |  // RA = dst*8, RD = src*8
3699     |  daddu CARG2, BASE, RD
3700     |   daddu RA, BASE, RA
3701     |  ld TMP0, 0(CARG2)
3702     |  gettp TMP1, TMP0
3703     |  daddiu AT, TMP1, -LJ_TSTR
3704     |  bnez AT, >2
3705     |.  cleartp STR:CARG1, TMP0
3706     |   lw CRET1, STR:CARG1->len
3707     |1:
3708     |  settp CRET1, TISNUM
3709     |  ins_next1
3710     |  sd CRET1, 0(RA)
3711     |  ins_next2
3712     |2:
3713     |  daddiu AT, TMP1, -LJ_TTAB
3714     |  bnez AT, ->vmeta_len
3715     |.  nop
3716 #if LJ_52
3717     |  ld TAB:TMP2, TAB:CARG1->metatable
3718     |  bnez TAB:TMP2, >9
3719     |.  nop
3720     |3:
3721 #endif
3722     |->BC_LEN_Z:
3723     |  load_got lj_tab_len
3724     |  call_intern lj_tab_len           // (GCtab *t)
3725     |.  nop
3726     |  // Returns uint32_t (but less than 2^31).
3727     |  b <1
3728     |.  nop
3729 #if LJ_52
3730     |9:
3731     |  lbu TMP0, TAB:TMP2->nomm
3732     |  andi TMP0, TMP0, 1<<MM_len
3733     |  bnez TMP0, <3                    // 'no __len' flag set: done.
3734     |.  nop
3735     |  b ->vmeta_len
3736     |.  nop
3737 #endif
3738     break;
3740   /* -- Binary ops -------------------------------------------------------- */
3742     |.macro fpmod, a, b, c
3743     |  bal ->vm_floor           // floor(b/c)
3744     |.  div.d FARG1, b, c
3745     |  mul.d a, FRET1, c
3746     |  sub.d a, b, a            // b - floor(b/c)*c
3747     |.endmacro
3749     |.macro sfpmod
3750     |  daddiu sp, sp, -16
3751     |
3752     |  load_got __divdf3
3753     |  sd CARG1, 0(sp)
3754     |  call_extern
3755     |.  sd CARG2, 8(sp)
3756     |
3757     |  load_got floor
3758     |  call_extern
3759     |.  move CARG1, CRET1
3760     |
3761     |  load_got __muldf3
3762     |  move CARG1, CRET1
3763     |  call_extern
3764     |.  ld CARG2, 8(sp)
3765     |
3766     |  load_got __subdf3
3767     |  ld CARG1, 0(sp)
3768     |  call_extern
3769     |.  move CARG2, CRET1
3770     |
3771     |  daddiu sp, sp, 16
3772     |.endmacro
3774     |.macro ins_arithpre, label
3775     ||vk = ((int)op - BC_ADDVN) / (BC_ADDNV-BC_ADDVN);
3776     |  // RA = dst*8, RB = src1*8, RC = src2*8 | num_const*8
3777     ||switch (vk) {
3778     ||case 0:
3779     |   decode_RB8a RB, INS
3780     |   decode_RB8b RB
3781     |    decode_RDtoRC8 RC, RD
3782     |   // RA = dst*8, RB = src1*8, RC = num_const*8
3783     |   daddu RB, BASE, RB
3784     |.if "label" ~= "none"
3785     |   b label
3786     |.endif
3787     |.   daddu RC, KBASE, RC
3788     ||  break;
3789     ||case 1:
3790     |   decode_RB8a RC, INS
3791     |   decode_RB8b RC
3792     |    decode_RDtoRC8 RB, RD
3793     |   // RA = dst*8, RB = num_const*8, RC = src1*8
3794     |   daddu RC, BASE, RC
3795     |.if "label" ~= "none"
3796     |   b label
3797     |.endif
3798     |.   daddu RB, KBASE, RB
3799     ||  break;
3800     ||default:
3801     |   decode_RB8a RB, INS
3802     |   decode_RB8b RB
3803     |    decode_RDtoRC8 RC, RD
3804     |   // RA = dst*8, RB = src1*8, RC = src2*8
3805     |   daddu RB, BASE, RB
3806     |.if "label" ~= "none"
3807     |   b label
3808     |.endif
3809     |.   daddu RC, BASE, RC
3810     ||  break;
3811     ||}
3812     |.endmacro
3813     |
3814     |.macro ins_arith, intins, fpins, fpcall, label
3815     |  ins_arithpre none
3816     |
3817     |.if "label" ~= "none"
3818     |label:
3819     |.endif
3820     |
3821     |// Used in 5.
3822     |  ld CARG1, 0(RB)
3823     |   ld CARG2, 0(RC)
3824     |  gettp TMP0, CARG1
3825     |   gettp TMP1, CARG2
3826     |
3827     |.if "intins" ~= "div"
3828     |
3829     |  // Check for two integers.
3830     |  sextw CARG3, CARG1
3831     |  bne TMP0, TISNUM, >5
3832     |.  sextw CARG4, CARG2
3833     |  bne TMP1, TISNUM, >5
3834     |
3835     |.if "intins" == "addu"
3836     |.  intins CRET1, CARG3, CARG4
3837     |  xor TMP1, CRET1, CARG3           // ((y^a) & (y^b)) < 0: overflow.
3838     |  xor TMP2, CRET1, CARG4
3839     |  and TMP1, TMP1, TMP2
3840     |  bltz TMP1, ->vmeta_arith
3841     |.  daddu RA, BASE, RA
3842     |.elif "intins" == "subu"
3843     |.  intins CRET1, CARG3, CARG4
3844     |  xor TMP1, CRET1, CARG3           // ((y^a) & (a^b)) < 0: overflow.
3845     |  xor TMP2, CARG3, CARG4
3846     |  and TMP1, TMP1, TMP2
3847     |  bltz TMP1, ->vmeta_arith
3848     |.  daddu RA, BASE, RA
3849     |.elif "intins" == "mult"
3850     |.if MIPSR6
3851     |.  nop
3852     |  mul CRET1, CARG3, CARG4
3853     |  muh TMP2, CARG3, CARG4
3854     |.else
3855     |.  intins CARG3, CARG4
3856     |  mflo CRET1
3857     |  mfhi TMP2
3858     |.endif
3859     |  sra TMP1, CRET1, 31
3860     |  bne TMP1, TMP2, ->vmeta_arith
3861     |.  daddu RA, BASE, RA
3862     |.else
3863     |.  load_got lj_vm_modi
3864     |  beqz CARG4, ->vmeta_arith
3865     |.  daddu RA, BASE, RA
3866     |  move CARG1, CARG3
3867     |  call_extern
3868     |.  move CARG2, CARG4
3869     |.endif
3870     |
3871     |  zextw CRET1, CRET1
3872     |  settp CRET1, TISNUM
3873     |  ins_next1
3874     |  sd CRET1, 0(RA)
3875     |3:
3876     |  ins_next2
3877     |
3878     |.endif
3879     |
3880     |5:  // Check for two numbers.
3881     |  .FPU ldc1 FTMP0, 0(RB)
3882     |  sltu AT, TMP0, TISNUM
3883     |   sltu TMP0, TMP1, TISNUM
3884     |  .FPU ldc1 FTMP2, 0(RC)
3885     |   and AT, AT, TMP0
3886     |   beqz AT, ->vmeta_arith
3887     |.   daddu RA, BASE, RA
3888     |
3889     |.if FPU
3890     |  fpins FRET1, FTMP0, FTMP2
3891     |.elif "fpcall" == "sfpmod"
3892     |  sfpmod
3893     |.else
3894     |  load_got fpcall
3895     |  call_extern
3896     |.  nop
3897     |.endif
3898     |
3899     |  ins_next1
3900     |.if "intins" ~= "div"
3901     |  b <3
3902     |.endif
3903     |.if FPU
3904     |.  sdc1 FRET1, 0(RA)
3905     |.else
3906     |.  sd CRET1, 0(RA)
3907     |.endif
3908     |.if "intins" == "div"
3909     |  ins_next2
3910     |.endif
3911     |
3912     |.endmacro
3914   case BC_ADDVN: case BC_ADDNV: case BC_ADDVV:
3915     |  ins_arith addu, add.d, __adddf3, none
3916     break;
3917   case BC_SUBVN: case BC_SUBNV: case BC_SUBVV:
3918     |  ins_arith subu, sub.d, __subdf3, none
3919     break;
3920   case BC_MULVN: case BC_MULNV: case BC_MULVV:
3921     |  ins_arith mult, mul.d, __muldf3, none
3922     break;
3923   case BC_DIVVN:
3924     |  ins_arith div, div.d, __divdf3, ->BC_DIVVN_Z
3925     break;
3926   case BC_DIVNV: case BC_DIVVV:
3927     |  ins_arithpre ->BC_DIVVN_Z
3928     break;
3929   case BC_MODVN:
3930     |  ins_arith modi, fpmod, sfpmod, ->BC_MODVN_Z
3931     break;
3932   case BC_MODNV: case BC_MODVV:
3933     |  ins_arithpre ->BC_MODVN_Z
3934     break;
3935   case BC_POW:
3936     |  ins_arithpre none
3937     |  ld CARG1, 0(RB)
3938     |   ld CARG2, 0(RC)
3939     |  gettp TMP0, CARG1
3940     |   gettp TMP1, CARG2
3941     |  sltiu TMP0, TMP0, LJ_TISNUM
3942     |   sltiu TMP1, TMP1, LJ_TISNUM
3943     |  and AT, TMP0, TMP1
3944     |  load_got pow
3945     |  beqz AT, ->vmeta_arith
3946     |.  daddu RA, BASE, RA
3947     |.if FPU
3948     |  ldc1 FARG1, 0(RB)
3949     |  ldc1 FARG2, 0(RC)
3950     |.endif
3951     |  call_extern
3952     |.  nop
3953     |  ins_next1
3954     |.if FPU
3955     |  sdc1 FRET1, 0(RA)
3956     |.else
3957     |  sd CRET1, 0(RA)
3958     |.endif
3959     |  ins_next2
3960     break;
3962   case BC_CAT:
3963     |  // RA = dst*8, RB = src_start*8, RC = src_end*8
3964     |  decode_RB8a RB, INS
3965     |  decode_RB8b RB
3966     |   decode_RDtoRC8 RC, RD
3967     |  dsubu CARG3, RC, RB
3968     |   sd BASE, L->base
3969     |  daddu CARG2, BASE, RC
3970     |  move MULTRES, RB
3971     |->BC_CAT_Z:
3972     |  load_got lj_meta_cat
3973     |  srl CARG3, CARG3, 3
3974     |   sd PC, SAVE_PC
3975     |  call_intern lj_meta_cat          // (lua_State *L, TValue *top, int left)
3976     |.  move CARG1, L
3977     |  // Returns NULL (finished) or TValue * (metamethod).
3978     |  bnez CRET1, ->vmeta_binop
3979     |.  ld BASE, L->base
3980     |  daddu RB, BASE, MULTRES
3981     |  ld CRET1, 0(RB)
3982     |   daddu RA, BASE, RA
3983     |  ins_next1
3984     |  sd CRET1, 0(RA)
3985     |  ins_next2
3986     break;
3988   /* -- Constant ops ------------------------------------------------------ */
3990   case BC_KSTR:
3991     |  // RA = dst*8, RD = str_const*8 (~)
3992     |  dsubu TMP1, KBASE, RD
3993     |  ins_next1
3994     |   li TMP2, LJ_TSTR
3995     |  ld TMP0, -8(TMP1)                // KBASE-8-str_const*8
3996     |  daddu RA, BASE, RA
3997     |   settp TMP0, TMP2
3998     |  sd TMP0, 0(RA)
3999     |  ins_next2
4000     break;
4001   case BC_KCDATA:
4002     |.if FFI
4003     |  // RA = dst*8, RD = cdata_const*8 (~)
4004     |  dsubu TMP1, KBASE, RD
4005     |  ins_next1
4006     |  ld TMP0, -8(TMP1)                // KBASE-8-cdata_const*8
4007     |   li TMP2, LJ_TCDATA
4008     |  daddu RA, BASE, RA
4009     |   settp TMP0, TMP2
4010     |  sd TMP0, 0(RA)
4011     |  ins_next2
4012     |.endif
4013     break;
4014   case BC_KSHORT:
4015     |  // RA = dst*8, RD = int16_literal*8
4016     |   sra RD, INS, 16
4017     |  daddu RA, BASE, RA
4018     |   zextw RD, RD
4019     |  ins_next1
4020     |   settp RD, TISNUM
4021     |   sd RD, 0(RA)
4022     |  ins_next2
4023     break;
4024   case BC_KNUM:
4025     |  // RA = dst*8, RD = num_const*8
4026     |  daddu RD, KBASE, RD
4027     |   daddu RA, BASE, RA
4028     |  ld CRET1, 0(RD)
4029     |  ins_next1
4030     |  sd CRET1, 0(RA)
4031     |  ins_next2
4032     break;
4033   case BC_KPRI:
4034     |  // RA = dst*8, RD = primitive_type*8 (~)
4035     |   daddu RA, BASE, RA
4036     |  dsll TMP0, RD, 44
4037     |  not TMP0, TMP0
4038     |  ins_next1
4039     |   sd TMP0, 0(RA)
4040     |  ins_next2
4041     break;
4042   case BC_KNIL:
4043     |  // RA = base*8, RD = end*8
4044     |  daddu RA, BASE, RA
4045     |  sd TISNIL, 0(RA)
4046     |   daddiu RA, RA, 8
4047     |  daddu RD, BASE, RD
4048     |1:
4049     |  sd TISNIL, 0(RA)
4050     |  slt AT, RA, RD
4051     |  bnez AT, <1
4052     |.  daddiu RA, RA, 8
4053     |  ins_next_
4054     break;
4056   /* -- Upvalue and function ops ------------------------------------------ */
4058   case BC_UGET:
4059     |  // RA = dst*8, RD = uvnum*8
4060     |  ld LFUNC:RB, FRAME_FUNC(BASE)
4061     |   daddu RA, BASE, RA
4062     |  cleartp LFUNC:RB
4063     |  daddu RD, RD, LFUNC:RB
4064     |  ld UPVAL:RB, LFUNC:RD->uvptr
4065     |  ins_next1
4066     |  ld TMP1, UPVAL:RB->v
4067     |  ld CRET1, 0(TMP1)
4068     |   sd CRET1, 0(RA)
4069     |  ins_next2
4070     break;
4071   case BC_USETV:
4072     |  // RA = uvnum*8, RD = src*8
4073     |  ld LFUNC:RB, FRAME_FUNC(BASE)
4074     |   daddu RD, BASE, RD
4075     |  cleartp LFUNC:RB
4076     |  daddu RA, RA, LFUNC:RB
4077     |  ld UPVAL:RB, LFUNC:RA->uvptr
4078     |   ld CRET1, 0(RD)
4079     |  lbu TMP3, UPVAL:RB->marked
4080     |   ld CARG2, UPVAL:RB->v
4081     |  andi TMP3, TMP3, LJ_GC_BLACK     // isblack(uv)
4082     |  lbu TMP0, UPVAL:RB->closed
4083     |   gettp TMP2, CRET1
4084     |   sd CRET1, 0(CARG2)
4085     |  li AT, LJ_GC_BLACK|1
4086     |  or TMP3, TMP3, TMP0
4087     |  beq TMP3, AT, >2                 // Upvalue is closed and black?
4088     |.  daddiu TMP2, TMP2, -(LJ_TNUMX+1)
4089     |1:
4090     |  ins_next
4091     |
4092     |2:  // Check if new value is collectable.
4093     |  sltiu AT, TMP2, LJ_TISGCV - (LJ_TNUMX+1)
4094     |  beqz AT, <1                      // tvisgcv(v)
4095     |.  cleartp GCOBJ:CRET1, CRET1
4096     |  lbu TMP3, GCOBJ:CRET1->gch.marked
4097     |  andi TMP3, TMP3, LJ_GC_WHITES    // iswhite(v)
4098     |  beqz TMP3, <1
4099     |.  load_got lj_gc_barrieruv
4100     |  // Crossed a write barrier. Move the barrier forward.
4101     |  call_intern lj_gc_barrieruv      // (global_State *g, TValue *tv)
4102     |.  daddiu CARG1, DISPATCH, GG_DISP2G
4103     |  b <1
4104     |.  nop
4105     break;
4106   case BC_USETS:
4107     |  // RA = uvnum*8, RD = str_const*8 (~)
4108     |  ld LFUNC:RB, FRAME_FUNC(BASE)
4109     |   dsubu TMP1, KBASE, RD
4110     |  cleartp LFUNC:RB
4111     |  daddu RA, RA, LFUNC:RB
4112     |  ld UPVAL:RB, LFUNC:RA->uvptr
4113     |   ld STR:TMP1, -8(TMP1)           // KBASE-8-str_const*8
4114     |  lbu TMP2, UPVAL:RB->marked
4115     |   ld CARG2, UPVAL:RB->v
4116     |   lbu TMP3, STR:TMP1->marked
4117     |  andi AT, TMP2, LJ_GC_BLACK       // isblack(uv)
4118     |   lbu TMP2, UPVAL:RB->closed
4119     |   li TMP0, LJ_TSTR
4120     |   settp TMP1, TMP0
4121     |  bnez AT, >2
4122     |.  sd TMP1, 0(CARG2)
4123     |1:
4124     |  ins_next
4125     |
4126     |2:  // Check if string is white and ensure upvalue is closed.
4127     |  beqz TMP2, <1
4128     |.  andi AT, TMP3, LJ_GC_WHITES     // iswhite(str)
4129     |  beqz AT, <1
4130     |.  load_got lj_gc_barrieruv
4131     |  // Crossed a write barrier. Move the barrier forward.
4132     |  call_intern lj_gc_barrieruv      // (global_State *g, TValue *tv)
4133     |.  daddiu CARG1, DISPATCH, GG_DISP2G
4134     |  b <1
4135     |.  nop
4136     break;
4137   case BC_USETN:
4138     |  // RA = uvnum*8, RD = num_const*8
4139     |  ld LFUNC:RB, FRAME_FUNC(BASE)
4140     |   daddu RD, KBASE, RD
4141     |  cleartp LFUNC:RB
4142     |  daddu RA, RA, LFUNC:RB
4143     |  ld UPVAL:RB, LFUNC:RA->uvptr
4144     |   ld CRET1, 0(RD)
4145     |  ld TMP1, UPVAL:RB->v
4146     |  ins_next1
4147     |   sd CRET1, 0(TMP1)
4148     |  ins_next2
4149     break;
4150   case BC_USETP:
4151     |  // RA = uvnum*8, RD = primitive_type*8 (~)
4152     |  ld LFUNC:RB, FRAME_FUNC(BASE)
4153     |   dsll TMP0, RD, 44
4154     |  cleartp LFUNC:RB
4155     |  daddu RA, RA, LFUNC:RB
4156     |   not TMP0, TMP0
4157     |  ld UPVAL:RB, LFUNC:RA->uvptr
4158     |  ins_next1
4159     |  ld TMP1, UPVAL:RB->v
4160     |   sd TMP0, 0(TMP1)
4161     |  ins_next2
4162     break;
4164   case BC_UCLO:
4165     |  // RA = level*8, RD = target
4166     |  ld TMP2, L->openupval
4167     |  branch_RD                        // Do this first since RD is not saved.
4168     |  load_got lj_func_closeuv
4169     |   sd BASE, L->base
4170     |  beqz TMP2, >1
4171     |.  move CARG1, L
4172     |  call_intern lj_func_closeuv      // (lua_State *L, TValue *level)
4173     |.  daddu CARG2, BASE, RA
4174     |  ld BASE, L->base
4175     |1:
4176     |  ins_next
4177     break;
4179   case BC_FNEW:
4180     |  // RA = dst*8, RD = proto_const*8 (~) (holding function prototype)
4181     |  load_got lj_func_newL_gc
4182     |  dsubu TMP1, KBASE, RD
4183     |  ld CARG3, FRAME_FUNC(BASE)
4184     |   ld CARG2, -8(TMP1)              // KBASE-8-tab_const*8
4185     |    sd BASE, L->base
4186     |    sd PC, SAVE_PC
4187     |  cleartp CARG3
4188     |  // (lua_State *L, GCproto *pt, GCfuncL *parent)
4189     |  call_intern lj_func_newL_gc
4190     |.  move CARG1, L
4191     |  // Returns GCfuncL *.
4192     |   li TMP0, LJ_TFUNC
4193     |  ld BASE, L->base
4194     |  ins_next1
4195     |   settp CRET1, TMP0
4196     |  daddu RA, BASE, RA
4197     |   sd CRET1, 0(RA)
4198     |  ins_next2
4199     break;
4201   /* -- Table ops --------------------------------------------------------- */
4203   case BC_TNEW:
4204   case BC_TDUP:
4205     |  // RA = dst*8, RD = (hbits|asize)*8 | tab_const*8 (~)
4206     |  ld TMP0, DISPATCH_GL(gc.total)(DISPATCH)
4207     |  ld TMP1, DISPATCH_GL(gc.threshold)(DISPATCH)
4208     |   sd BASE, L->base
4209     |   sd PC, SAVE_PC
4210     |  sltu AT, TMP0, TMP1
4211     |  beqz AT, >5
4212     |1:
4213     if (op == BC_TNEW) {
4214       |  load_got lj_tab_new
4215       |  srl CARG2, RD, 3
4216       |  andi CARG2, CARG2, 0x7ff
4217       |  li TMP0, 0x801
4218       |  addiu AT, CARG2, -0x7ff
4219       |   srl CARG3, RD, 14
4220       |.if MIPSR6
4221       |  seleqz TMP0, TMP0, AT
4222       |  selnez CARG2, CARG2, AT
4223       |  or CARG2, CARG2, TMP0
4224       |.else
4225       |  movz CARG2, TMP0, AT
4226       |.endif
4227       |  // (lua_State *L, int32_t asize, uint32_t hbits)
4228       |  call_intern lj_tab_new
4229       |.  move CARG1, L
4230       |  // Returns Table *.
4231     } else {
4232       |  load_got lj_tab_dup
4233       |  dsubu TMP1, KBASE, RD
4234       |  move CARG1, L
4235       |  call_intern lj_tab_dup         // (lua_State *L, Table *kt)
4236       |.  ld CARG2, -8(TMP1)            // KBASE-8-str_const*8
4237       |  // Returns Table *.
4238     }
4239     |   li TMP0, LJ_TTAB
4240     |  ld BASE, L->base
4241     |  ins_next1
4242     |  daddu RA, BASE, RA
4243     |   settp CRET1, TMP0
4244     |   sd CRET1, 0(RA)
4245     |  ins_next2
4246     |5:
4247     |  load_got lj_gc_step_fixtop
4248     |  move MULTRES, RD
4249     |  call_intern lj_gc_step_fixtop    // (lua_State *L)
4250     |.  move CARG1, L
4251     |  b <1
4252     |.  move RD, MULTRES
4253     break;
4255   case BC_GGET:
4256     |  // RA = dst*8, RD = str_const*8 (~)
4257   case BC_GSET:
4258     |  // RA = src*8, RD = str_const*8 (~)
4259     |  ld LFUNC:TMP2, FRAME_FUNC(BASE)
4260     |   dsubu TMP1, KBASE, RD
4261     |   ld STR:RC, -8(TMP1)             // KBASE-8-str_const*8
4262     |  cleartp LFUNC:TMP2
4263     |  ld TAB:RB, LFUNC:TMP2->env
4264     if (op == BC_GGET) {
4265       |  b ->BC_TGETS_Z
4266     } else {
4267       |  b ->BC_TSETS_Z
4268     }
4269     |.  daddu RA, BASE, RA
4270     break;
4272   case BC_TGETV:
4273     |  // RA = dst*8, RB = table*8, RC = key*8
4274     |  decode_RB8a RB, INS
4275     |  decode_RB8b RB
4276     |   decode_RDtoRC8 RC, RD
4277     |  daddu CARG2, BASE, RB
4278     |   daddu CARG3, BASE, RC
4279     |  ld TAB:RB, 0(CARG2)
4280     |   ld TMP2, 0(CARG3)
4281     |   daddu RA, BASE, RA
4282     |  checktab TAB:RB, ->vmeta_tgetv
4283     |   gettp TMP3, TMP2
4284     |  bne TMP3, TISNUM, >5             // Integer key?
4285     |.  lw TMP0, TAB:RB->asize
4286     |  sextw TMP2, TMP2
4287     |   ld TMP1, TAB:RB->array
4288     |  sltu AT, TMP2, TMP0
4289     |   sll TMP2, TMP2, 3
4290     |  beqz AT, ->vmeta_tgetv           // Integer key and in array part?
4291     |.  daddu TMP2, TMP1, TMP2
4292     |  ld AT, 0(TMP2)
4293     |  beq AT, TISNIL, >2
4294     |.   ld CRET1, 0(TMP2)
4295     |1:
4296     |  ins_next1
4297     |   sd CRET1, 0(RA)
4298     |  ins_next2
4299     |
4300     |2:  // Check for __index if table value is nil.
4301     |  ld TAB:TMP2, TAB:RB->metatable
4302     |  beqz TAB:TMP2, <1                // No metatable: done.
4303     |.  nop
4304     |  lbu TMP0, TAB:TMP2->nomm
4305     |  andi TMP0, TMP0, 1<<MM_index
4306     |  bnez TMP0, <1                    // 'no __index' flag set: done.
4307     |.  nop
4308     |  b ->vmeta_tgetv
4309     |.  nop
4310     |
4311     |5:
4312     |  li AT, LJ_TSTR
4313     |  bne TMP3, AT, ->vmeta_tgetv
4314     |.  cleartp RC, TMP2
4315     |  b ->BC_TGETS_Z                   // String key?
4316     |.  nop
4317     break;
4318   case BC_TGETS:
4319     |  // RA = dst*8, RB = table*8, RC = str_const*8 (~)
4320     |  decode_RB8a RB, INS
4321     |  decode_RB8b RB
4322     |   decode_RC8a RC, INS
4323     |  daddu CARG2, BASE, RB
4324     |   decode_RC8b RC
4325     |  ld TAB:RB, 0(CARG2)
4326     |   dsubu CARG3, KBASE, RC
4327     |  daddu RA, BASE, RA
4328     |   ld STR:RC, -8(CARG3)            // KBASE-8-str_const*8
4329     |  checktab TAB:RB, ->vmeta_tgets1
4330     |->BC_TGETS_Z:
4331     |  // TAB:RB = GCtab *, STR:RC = GCstr *, RA = dst*8
4332     |  lw TMP0, TAB:RB->hmask
4333     |   lw TMP1, STR:RC->sid
4334     |    ld NODE:TMP2, TAB:RB->node
4335     |  and TMP1, TMP1, TMP0             // idx = str->sid & tab->hmask
4336     |  sll TMP0, TMP1, 5
4337     |  sll TMP1, TMP1, 3
4338     |  subu TMP1, TMP0, TMP1
4339     |   li TMP3, LJ_TSTR
4340     |  daddu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8)
4341     |   settp STR:RC, TMP3              // Tagged key to look for.
4342     |1:
4343     |  ld CARG1, NODE:TMP2->key
4344     |   ld CRET1, NODE:TMP2->val
4345     |    ld NODE:TMP1, NODE:TMP2->next
4346     |  bne CARG1, RC, >4
4347     |.  ld TAB:TMP3, TAB:RB->metatable
4348     |  beq CRET1, TISNIL, >5            // Key found, but nil value?
4349     |.  nop
4350     |3:
4351     |  ins_next1
4352     |   sd CRET1, 0(RA)
4353     |  ins_next2
4354     |
4355     |4:  // Follow hash chain.
4356     |  bnez NODE:TMP1, <1
4357     |.  move NODE:TMP2, NODE:TMP1
4358     |  // End of hash chain: key not found, nil result.
4359     |
4360     |5:  // Check for __index if table value is nil.
4361     |  beqz TAB:TMP3, <3                // No metatable: done.
4362     |.  move CRET1, TISNIL
4363     |  lbu TMP0, TAB:TMP3->nomm
4364     |  andi TMP0, TMP0, 1<<MM_index
4365     |  bnez TMP0, <3                    // 'no __index' flag set: done.
4366     |.  nop
4367     |  b ->vmeta_tgets
4368     |.  nop
4369     break;
4370   case BC_TGETB:
4371     |  // RA = dst*8, RB = table*8, RC = index*8
4372     |  decode_RB8a RB, INS
4373     |  decode_RB8b RB
4374     |  daddu CARG2, BASE, RB
4375     |   decode_RDtoRC8 RC, RD
4376     |  ld TAB:RB, 0(CARG2)
4377     |   daddu RA, BASE, RA
4378     |  srl TMP0, RC, 3
4379     |  checktab TAB:RB, ->vmeta_tgetb
4380     |  lw TMP1, TAB:RB->asize
4381     |   ld TMP2, TAB:RB->array
4382     |  sltu AT, TMP0, TMP1
4383     |  beqz AT, ->vmeta_tgetb
4384     |.  daddu RC, TMP2, RC
4385     |  ld AT, 0(RC)
4386     |  beq AT, TISNIL, >5
4387     |.  ld CRET1, 0(RC)
4388     |1:
4389     |  ins_next1
4390     |   sd CRET1, 0(RA)
4391     |  ins_next2
4392     |
4393     |5:  // Check for __index if table value is nil.
4394     |  ld TAB:TMP2, TAB:RB->metatable
4395     |  beqz TAB:TMP2, <1                // No metatable: done.
4396     |.  nop
4397     |  lbu TMP1, TAB:TMP2->nomm
4398     |  andi TMP1, TMP1, 1<<MM_index
4399     |  bnez TMP1, <1                    // 'no __index' flag set: done.
4400     |.  nop
4401     |  b ->vmeta_tgetb                  // Caveat: preserve TMP0 and CARG2!
4402     |.  nop
4403     break;
4404   case BC_TGETR:
4405     |  // RA = dst*8, RB = table*8, RC = key*8
4406     |  decode_RB8a RB, INS
4407     |  decode_RB8b RB
4408     |   decode_RDtoRC8 RC, RD
4409     |  daddu RB, BASE, RB
4410     |   daddu RC, BASE, RC
4411     |  ld TAB:CARG1, 0(RB)
4412     |   lw CARG2, LO(RC)
4413     |    daddu RA, BASE, RA
4414     |  cleartp TAB:CARG1
4415     |  lw TMP0, TAB:CARG1->asize
4416     |   ld TMP1, TAB:CARG1->array
4417     |  sltu AT, CARG2, TMP0
4418     |   sll TMP2, CARG2, 3
4419     |  beqz AT, ->vmeta_tgetr           // In array part?
4420     |.  daddu CRET1, TMP1, TMP2
4421     |   ld CARG2, 0(CRET1)
4422     |->BC_TGETR_Z:
4423     |  ins_next1
4424     |   sd CARG2, 0(RA)
4425     |  ins_next2
4426     break;
4428   case BC_TSETV:
4429     |  // RA = src*8, RB = table*8, RC = key*8
4430     |  decode_RB8a RB, INS
4431     |  decode_RB8b RB
4432     |   decode_RDtoRC8 RC, RD
4433     |  daddu CARG2, BASE, RB
4434     |   daddu CARG3, BASE, RC
4435     |  ld RB, 0(CARG2)
4436     |   ld TMP2, 0(CARG3)
4437     |  daddu RA, BASE, RA
4438     |  checktab RB, ->vmeta_tsetv
4439     |  checkint TMP2, >5
4440     |.  sextw RC, TMP2
4441     |  lw TMP0, TAB:RB->asize
4442     |   ld TMP1, TAB:RB->array
4443     |  sltu AT, RC, TMP0
4444     |   sll TMP2, RC, 3
4445     |  beqz AT, ->vmeta_tsetv           // Integer key and in array part?
4446     |.  daddu TMP1, TMP1, TMP2
4447     |  ld TMP0, 0(TMP1)
4448     |   lbu TMP3, TAB:RB->marked
4449     |  beq TMP0, TISNIL, >3
4450     |.  ld CRET1, 0(RA)
4451     |1:
4452     |   andi AT, TMP3, LJ_GC_BLACK      // isblack(table)
4453     |  bnez AT, >7
4454     |.  sd CRET1, 0(TMP1)
4455     |2:
4456     |  ins_next
4457     |
4458     |3:  // Check for __newindex if previous value is nil.
4459     |  ld TAB:TMP2, TAB:RB->metatable
4460     |  beqz TAB:TMP2, <1                // No metatable: done.
4461     |.  nop
4462     |  lbu TMP2, TAB:TMP2->nomm
4463     |  andi TMP2, TMP2, 1<<MM_newindex
4464     |  bnez TMP2, <1                    // 'no __newindex' flag set: done.
4465     |.  nop
4466     |  b ->vmeta_tsetv
4467     |.  nop
4468     |
4469     |5:
4470     |  gettp AT, TMP2
4471     |  daddiu AT, AT, -LJ_TSTR
4472     |  bnez AT, ->vmeta_tsetv
4473     |.  nop
4474     |  b ->BC_TSETS_Z                   // String key?
4475     |.  cleartp STR:RC, TMP2
4476     |
4477     |7:  // Possible table write barrier for the value. Skip valiswhite check.
4478     |  barrierback TAB:RB, TMP3, TMP0, <2
4479     break;
4480   case BC_TSETS:
4481     |  // RA = src*8, RB = table*8, RC = str_const*8 (~)
4482     |  decode_RB8a RB, INS
4483     |  decode_RB8b RB
4484     |  daddu CARG2, BASE, RB
4485     |   decode_RC8a RC, INS
4486     |    ld TAB:RB, 0(CARG2)
4487     |   decode_RC8b RC
4488     |   dsubu CARG3, KBASE, RC
4489     |   ld RC, -8(CARG3)                // KBASE-8-str_const*8
4490     |  daddu RA, BASE, RA
4491     |   cleartp STR:RC
4492     |  checktab TAB:RB, ->vmeta_tsets1
4493     |->BC_TSETS_Z:
4494     |  // TAB:RB = GCtab *, STR:RC = GCstr *, RA = BASE+src*8
4495     |  lw TMP0, TAB:RB->hmask
4496     |   lw TMP1, STR:RC->sid
4497     |    ld NODE:TMP2, TAB:RB->node
4498     |   sb r0, TAB:RB->nomm             // Clear metamethod cache.
4499     |  and TMP1, TMP1, TMP0             // idx = str->sid & tab->hmask
4500     |  sll TMP0, TMP1, 5
4501     |  sll TMP1, TMP1, 3
4502     |  subu TMP1, TMP0, TMP1
4503     |   li TMP3, LJ_TSTR
4504     |  daddu NODE:TMP2, NODE:TMP2, TMP1 // node = tab->node + (idx*32-idx*8)
4505     |   settp STR:RC, TMP3              // Tagged key to look for.
4506     |.if FPU
4507     |   ldc1 FTMP0, 0(RA)
4508     |.else
4509     |   ld CRET1, 0(RA)
4510     |.endif
4511     |1:
4512     |  ld TMP0, NODE:TMP2->key
4513     |   ld CARG2, NODE:TMP2->val
4514     |    ld NODE:TMP1, NODE:TMP2->next
4515     |  bne TMP0, RC, >5
4516     |.    lbu TMP3, TAB:RB->marked
4517     |   beq CARG2, TISNIL, >4           // Key found, but nil value?
4518     |.   ld TAB:TMP0, TAB:RB->metatable
4519     |2:
4520     |  andi AT, TMP3, LJ_GC_BLACK       // isblack(table)
4521     |  bnez AT, >7
4522     |.if FPU
4523     |.  sdc1 FTMP0, NODE:TMP2->val
4524     |.else
4525     |.  sd CRET1, NODE:TMP2->val
4526     |.endif
4527     |3:
4528     |  ins_next
4529     |
4530     |4:  // Check for __newindex if previous value is nil.
4531     |  beqz TAB:TMP0, <2                // No metatable: done.
4532     |.  nop
4533     |  lbu TMP0, TAB:TMP0->nomm
4534     |  andi TMP0, TMP0, 1<<MM_newindex
4535     |  bnez TMP0, <2                    // 'no __newindex' flag set: done.
4536     |.  nop
4537     |  b ->vmeta_tsets
4538     |.  nop
4539     |
4540     |5:  // Follow hash chain.
4541     |  bnez NODE:TMP1, <1
4542     |.  move NODE:TMP2, NODE:TMP1
4543     |  // End of hash chain: key not found, add a new one
4544     |
4545     |  // But check for __newindex first.
4546     |  ld TAB:TMP2, TAB:RB->metatable
4547     |  beqz TAB:TMP2, >6                // No metatable: continue.
4548     |.  daddiu CARG3, DISPATCH, DISPATCH_GL(tmptv)
4549     |  lbu TMP0, TAB:TMP2->nomm
4550     |  andi TMP0, TMP0, 1<<MM_newindex
4551     |  beqz TMP0, ->vmeta_tsets         // 'no __newindex' flag NOT set: check.
4552     |6:
4553     |  load_got lj_tab_newkey
4554     |  sd RC, 0(CARG3)
4555     |   sd BASE, L->base
4556     |  move CARG2, TAB:RB
4557     |   sd PC, SAVE_PC
4558     |  call_intern lj_tab_newkey        // (lua_State *L, GCtab *t, TValue *k
4559     |.  move CARG1, L
4560     |  // Returns TValue *.
4561     |  ld BASE, L->base
4562     |.if FPU
4563     |  b <3                             // No 2nd write barrier needed.
4564     |.  sdc1 FTMP0, 0(CRET1)
4565     |.else
4566     |  ld CARG1, 0(RA)
4567     |  b <3                             // No 2nd write barrier needed.
4568     |.  sd CARG1, 0(CRET1)
4569     |.endif
4570     |
4571     |7:  // Possible table write barrier for the value. Skip valiswhite check.
4572     |  barrierback TAB:RB, TMP3, TMP0, <3
4573     break;
4574   case BC_TSETB:
4575     |  // RA = src*8, RB = table*8, RC = index*8
4576     |  decode_RB8a RB, INS
4577     |  decode_RB8b RB
4578     |  daddu CARG2, BASE, RB
4579     |   decode_RDtoRC8 RC, RD
4580     |  ld TAB:RB, 0(CARG2)
4581     |   daddu RA, BASE, RA
4582     |  srl TMP0, RC, 3
4583     |  checktab RB, ->vmeta_tsetb
4584     |  lw TMP1, TAB:RB->asize
4585     |   ld TMP2, TAB:RB->array
4586     |  sltu AT, TMP0, TMP1
4587     |  beqz AT, ->vmeta_tsetb
4588     |.  daddu RC, TMP2, RC
4589     |  ld TMP1, 0(RC)
4590     |   lbu TMP3, TAB:RB->marked
4591     |  beq TMP1, TISNIL, >5
4592     |1:
4593     |.  ld CRET1, 0(RA)
4594     |  andi AT, TMP3, LJ_GC_BLACK       // isblack(table)
4595     |  bnez AT, >7
4596     |.   sd CRET1, 0(RC)
4597     |2:
4598     |  ins_next
4599     |
4600     |5:  // Check for __newindex if previous value is nil.
4601     |  ld TAB:TMP2, TAB:RB->metatable
4602     |  beqz TAB:TMP2, <1                // No metatable: done.
4603     |.  nop
4604     |  lbu TMP1, TAB:TMP2->nomm
4605     |  andi TMP1, TMP1, 1<<MM_newindex
4606     |  bnez TMP1, <1                    // 'no __newindex' flag set: done.
4607     |.  nop
4608     |  b ->vmeta_tsetb                  // Caveat: preserve TMP0 and CARG2!
4609     |.  nop
4610     |
4611     |7:  // Possible table write barrier for the value. Skip valiswhite check.
4612     |  barrierback TAB:RB, TMP3, TMP0, <2
4613     break;
4614   case BC_TSETR:
4615     |  // RA = dst*8, RB = table*8, RC = key*8
4616     |  decode_RB8a RB, INS
4617     |  decode_RB8b RB
4618     |   decode_RDtoRC8 RC, RD
4619     |  daddu CARG1, BASE, RB
4620     |   daddu CARG3, BASE, RC
4621     |  ld TAB:CARG2, 0(CARG1)
4622     |   lw CARG3, LO(CARG3)
4623     |  cleartp TAB:CARG2
4624     |  lbu TMP3, TAB:CARG2->marked
4625     |   lw TMP0, TAB:CARG2->asize
4626     |    ld TMP1, TAB:CARG2->array
4627     |  andi AT, TMP3, LJ_GC_BLACK       // isblack(table)
4628     |  bnez AT, >7
4629     |.  daddu RA, BASE, RA
4630     |2:
4631     |  sltu AT, CARG3, TMP0
4632     |   sll TMP2, CARG3, 3
4633     |  beqz AT, ->vmeta_tsetr           // In array part?
4634     |.  daddu CRET1, TMP1, TMP2
4635     |->BC_TSETR_Z:
4636     |  ld CARG1, 0(RA)
4637     |  ins_next1
4638     |  sd CARG1, 0(CRET1)
4639     |  ins_next2
4640     |
4641     |7:  // Possible table write barrier for the value. Skip valiswhite check.
4642     |  barrierback TAB:CARG2, TMP3, CRET1, <2
4643     break;
4645   case BC_TSETM:
4646     |  // RA = base*8 (table at base-1), RD = num_const*8 (start index)
4647     |  daddu RA, BASE, RA
4648     |1:
4649     |   daddu TMP3, KBASE, RD
4650     |  ld TAB:CARG2, -8(RA)             // Guaranteed to be a table.
4651     |    addiu TMP0, MULTRES, -8
4652     |   lw TMP3, LO(TMP3)               // Integer constant is in lo-word.
4653     |    beqz TMP0, >4                  // Nothing to copy?
4654     |.    srl CARG3, TMP0, 3
4655     |  cleartp CARG2
4656     |  addu CARG3, CARG3, TMP3
4657     |  lw TMP2, TAB:CARG2->asize
4658     |   sll TMP1, TMP3, 3
4659     |    lbu TMP3, TAB:CARG2->marked
4660     |   ld CARG1, TAB:CARG2->array
4661     |  sltu AT, TMP2, CARG3
4662     |  bnez AT, >5
4663     |.  daddu TMP2, RA, TMP0
4664     |   daddu TMP1, TMP1, CARG1
4665     |  andi TMP0, TMP3, LJ_GC_BLACK     // isblack(table)
4666     |3:  // Copy result slots to table.
4667     |   ld CRET1, 0(RA)
4668     |    daddiu RA, RA, 8
4669     |  sltu AT, RA, TMP2
4670     |   sd CRET1, 0(TMP1)
4671     |  bnez AT, <3
4672     |.   daddiu TMP1, TMP1, 8
4673     |  bnez TMP0, >7
4674     |.  nop
4675     |4:
4676     |  ins_next
4677     |
4678     |5:  // Need to resize array part.
4679     |  load_got lj_tab_reasize
4680     |   sd BASE, L->base
4681     |   sd PC, SAVE_PC
4682     |  move BASE, RD
4683     |  call_intern lj_tab_reasize       // (lua_State *L, GCtab *t, int nasize)
4684     |.  move CARG1, L
4685     |  // Must not reallocate the stack.
4686     |  move RD, BASE
4687     |  b <1
4688     |.  ld BASE, L->base        // Reload BASE for lack of a saved register.
4689     |
4690     |7:  // Possible table write barrier for any value. Skip valiswhite check.
4691     |  barrierback TAB:CARG2, TMP3, TMP0, <4
4692     break;
4694   /* -- Calls and vararg handling ----------------------------------------- */
4696   case BC_CALLM:
4697     |  // RA = base*8, (RB = (nresults+1)*8,) RC = extra_nargs*8
4698     |  decode_RDtoRC8 NARGS8:RC, RD
4699     |  b ->BC_CALL_Z
4700     |.  addu NARGS8:RC, NARGS8:RC, MULTRES
4701     break;
4702   case BC_CALL:
4703     |  // RA = base*8, (RB = (nresults+1)*8,) RC = (nargs+1)*8
4704     |  decode_RDtoRC8 NARGS8:RC, RD
4705     |->BC_CALL_Z:
4706     |  move TMP2, BASE
4707     |  daddu BASE, BASE, RA
4708     |   ld LFUNC:RB, 0(BASE)
4709     |   daddiu BASE, BASE, 16
4710     |  addiu NARGS8:RC, NARGS8:RC, -8
4711     |  checkfunc RB, ->vmeta_call
4712     |  ins_call
4713     break;
4715   case BC_CALLMT:
4716     |  // RA = base*8, (RB = 0,) RC = extra_nargs*8
4717     |  addu NARGS8:RD, NARGS8:RD, MULTRES       // BC_CALLT gets RC from RD.
4718     |  // Fall through. Assumes BC_CALLT follows.
4719     break;
4720   case BC_CALLT:
4721     |  // RA = base*8, (RB = 0,) RC = (nargs+1)*8
4722     |  daddu RA, BASE, RA
4723     |  ld RB, 0(RA)
4724     |   move NARGS8:RC, RD
4725     |    ld TMP1, FRAME_PC(BASE)
4726     |   daddiu RA, RA, 16
4727     |  addiu NARGS8:RC, NARGS8:RC, -8
4728     |  checktp CARG3, RB, -LJ_TFUNC, ->vmeta_callt
4729     |->BC_CALLT_Z:
4730     |  andi TMP0, TMP1, FRAME_TYPE      // Caveat: preserve TMP0 until the 'or'.
4731     |   lbu TMP3, LFUNC:CARG3->ffid
4732     |  bnez TMP0, >7
4733     |.  xori TMP2, TMP1, FRAME_VARG
4734     |1:
4735     |  sd RB, FRAME_FUNC(BASE)          // Copy function down, but keep PC.
4736     |  sltiu AT, TMP3, 2                // (> FF_C) Calling a fast function?
4737     |  move TMP2, BASE
4738     |  move RB, CARG3
4739     |  beqz NARGS8:RC, >3
4740     |.  move TMP3, NARGS8:RC
4741     |2:
4742     |   ld CRET1, 0(RA)
4743     |    daddiu RA, RA, 8
4744     |  addiu TMP3, TMP3, -8
4745     |   sd CRET1, 0(TMP2)
4746     |  bnez TMP3, <2
4747     |.   daddiu TMP2, TMP2, 8
4748     |3:
4749     |  or TMP0, TMP0, AT
4750     |  beqz TMP0, >5
4751     |.  nop
4752     |4:
4753     |  ins_callt
4754     |
4755     |5:  // Tailcall to a fast function with a Lua frame below.
4756     |  lw INS, -4(TMP1)
4757     |  decode_RA8a RA, INS
4758     |  decode_RA8b RA
4759     |  dsubu TMP1, BASE, RA
4760     |  ld TMP1, -32(TMP1)
4761     |  cleartp LFUNC:TMP1
4762     |  ld TMP1, LFUNC:TMP1->pc
4763     |  b <4
4764     |.  ld KBASE, PC2PROTO(k)(TMP1)     // Need to prepare KBASE.
4765     |
4766     |7:  // Tailcall from a vararg function.
4767     |  andi AT, TMP2, FRAME_TYPEP
4768     |  bnez AT, <1                      // Vararg frame below?
4769     |.  dsubu TMP2, BASE, TMP2          // Relocate BASE down.
4770     |  move BASE, TMP2
4771     |  ld TMP1, FRAME_PC(TMP2)
4772     |  b <1
4773     |.  andi TMP0, TMP1, FRAME_TYPE
4774     break;
4776   case BC_ITERC:
4777     |  // RA = base*8, (RB = (nresults+1)*8, RC = (nargs+1)*8 ((2+1)*8))
4778     |  move TMP2, BASE                  // Save old BASE fir vmeta_call.
4779     |  daddu BASE, BASE, RA
4780     |  ld RB, -24(BASE)
4781     |   ld CARG1, -16(BASE)
4782     |    ld CARG2, -8(BASE)
4783     |  li NARGS8:RC, 16                 // Iterators get 2 arguments.
4784     |  sd RB, 0(BASE)                   // Copy callable.
4785     |   sd CARG1, 16(BASE)              // Copy state.
4786     |    sd CARG2, 24(BASE)             // Copy control var.
4787     |   daddiu BASE, BASE, 16
4788     |  checkfunc RB, ->vmeta_call
4789     |  ins_call
4790     break;
4792   case BC_ITERN:
4793     |.if JIT and ENDIAN_LE
4794     |  hotloop
4795     |.endif
4796     |->vm_IITERN:
4797     |  // RA = base*8, (RB = (nresults+1)*8, RC = (nargs+1)*8 (2+1)*8)
4798     |  daddu RA, BASE, RA
4799     |  ld TAB:RB, -16(RA)
4800     |   lw RC, -8+LO(RA)                // Get index from control var.
4801     |  cleartp TAB:RB
4802     |   daddiu PC, PC, 4
4803     |  lw TMP0, TAB:RB->asize
4804     |   ld TMP1, TAB:RB->array
4805     |  dsll CARG3, TISNUM, 47
4806     |1:  // Traverse array part.
4807     |  sltu AT, RC, TMP0
4808     |  beqz AT, >5                      // Index points after array part?
4809     |.  sll TMP3, RC, 3
4810     |  daddu TMP3, TMP1, TMP3
4811     |  ld CARG1, 0(TMP3)
4812     |     lhu RD, -4+OFS_RD(PC)
4813     |   or TMP2, RC, CARG3
4814     |  beq CARG1, TISNIL, <1            // Skip holes in array part.
4815     |.  addiu RC, RC, 1
4816     |   sd TMP2, 0(RA)
4817     |  sd CARG1, 8(RA)
4818     |     lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
4819     |     decode_RD4b RD
4820     |     daddu RD, RD, TMP3
4821     |   sw RC, -8+LO(RA)                // Update control var.
4822     |     daddu PC, PC, RD
4823     |3:
4824     |  ins_next
4825     |
4826     |5:  // Traverse hash part.
4827     |  lw TMP1, TAB:RB->hmask
4828     |  subu RC, RC, TMP0
4829     |   ld TMP2, TAB:RB->node
4830     |6:
4831     |  sltu AT, TMP1, RC                // End of iteration? Branch to ITERL+1.
4832     |  bnez AT, <3
4833     |.  sll TMP3, RC, 5
4834     |   sll RB, RC, 3
4835     |   subu TMP3, TMP3, RB
4836     |  daddu NODE:TMP3, TMP3, TMP2
4837     |  ld CARG1, 0(NODE:TMP3)
4838     |     lhu RD, -4+OFS_RD(PC)
4839     |  beq CARG1, TISNIL, <6            // Skip holes in hash part.
4840     |.  addiu RC, RC, 1
4841     |  ld CARG2, NODE:TMP3->key
4842     |     lui TMP3, (-(BCBIAS_J*4 >> 16) & 65535)
4843     |  sd CARG1, 8(RA)
4844     |    addu RC, RC, TMP0
4845     |     decode_RD4b RD
4846     |     addu RD, RD, TMP3
4847     |  sd CARG2, 0(RA)
4848     |     daddu PC, PC, RD
4849     |  b <3
4850     |.  sw RC, -8+LO(RA)                // Update control var.
4851     break;
4853   case BC_ISNEXT:
4854     |  // RA = base*8, RD = target (points to ITERN)
4855     |  daddu RA, BASE, RA
4856     |    srl TMP0, RD, 1
4857     |  ld CFUNC:CARG1, -24(RA)
4858     |    daddu TMP0, PC, TMP0
4859     |   ld CARG2, -16(RA)
4860     |   ld CARG3, -8(RA)
4861     |    lui TMP2, (-(BCBIAS_J*4 >> 16) & 65535)
4862     |  checkfunc CFUNC:CARG1, >5
4863     |  gettp CARG2, CARG2
4864     |  daddiu CARG2, CARG2, -LJ_TTAB
4865     |  lbu TMP1, CFUNC:CARG1->ffid
4866     |  daddiu CARG3, CARG3, -LJ_TNIL
4867     |  or AT, CARG2, CARG3
4868     |  daddiu TMP1, TMP1, -FF_next_N
4869     |  or AT, AT, TMP1
4870     |  bnez AT, >5
4871     |.  lui TMP1, (LJ_KEYINDEX >> 16)
4872     |  daddu PC, TMP0, TMP2
4873     |  ori TMP1, TMP1, (LJ_KEYINDEX & 0xffff)
4874     |  dsll TMP1, TMP1, 32
4875     |  sd TMP1, -8(RA)
4876     |1:
4877     |  ins_next
4878     |5:  // Despecialize bytecode if any of the checks fail.
4879     |  li TMP3, BC_JMP
4880     |   li TMP1, BC_ITERC
4881     |  sb TMP3, -4+OFS_OP(PC)
4882     |   daddu PC, TMP0, TMP2
4883     |.if JIT
4884     |  lb TMP0, OFS_OP(PC)
4885     |  li AT, BC_ITERN
4886     |  bne TMP0, AT, >6
4887     |.  lhu TMP2, OFS_RD(PC)
4888     |.endif
4889     |  b <1
4890     |.  sb TMP1, OFS_OP(PC)
4891     |.if JIT
4892     |6:  // Unpatch JLOOP.
4893     |  ld TMP0, DISPATCH_J(trace)(DISPATCH)
4894     |   sll TMP2, TMP2, 3
4895     |  daddu TMP0, TMP0, TMP2
4896     |  ld TRACE:TMP2, 0(TMP0)
4897     |  lw TMP0, TRACE:TMP2->startins
4898     |   li AT, -256
4899     |  and TMP0, TMP0, AT
4900     |  or TMP0, TMP0, TMP1
4901     |  b <1
4902     |.  sw TMP0, 0(PC)
4903     |.endif
4904     break;
4906   case BC_VARG:
4907     |  // RA = base*8, RB = (nresults+1)*8, RC = numparams*8
4908     |  ld TMP0, FRAME_PC(BASE)
4909     |  decode_RDtoRC8 RC, RD
4910     |   decode_RB8a RB, INS
4911     |  daddu RC, BASE, RC
4912     |   decode_RB8b RB
4913     |   daddu RA, BASE, RA
4914     |  daddiu RC, RC, FRAME_VARG
4915     |   daddu TMP2, RA, RB
4916     |  daddiu TMP3, BASE, -16           // TMP3 = vtop
4917     |  dsubu RC, RC, TMP0               // RC = vbase
4918     |  // Note: RC may now be even _above_ BASE if nargs was < numparams.
4919     |  beqz RB, >5                      // Copy all varargs?
4920     |.  dsubu TMP1, TMP3, RC
4921     |  daddiu TMP2, TMP2, -16
4922     |1:  // Copy vararg slots to destination slots.
4923     |  ld CARG1, 0(RC)
4924     |  sltu AT, RC, TMP3
4925     |    daddiu RC, RC, 8
4926     |.if MIPSR6
4927     |  selnez CARG1, CARG1, AT
4928     |  seleqz AT, TISNIL, AT
4929     |  or CARG1, CARG1, AT
4930     |.else
4931     |  movz CARG1, TISNIL, AT
4932     |.endif
4933     |  sd CARG1, 0(RA)
4934     |  sltu AT, RA, TMP2
4935     |  bnez AT, <1
4936     |.   daddiu RA, RA, 8
4937     |3:
4938     |  ins_next
4939     |
4940     |5:  // Copy all varargs.
4941     |  ld TMP0, L->maxstack
4942     |  blez TMP1, <3                    // No vararg slots?
4943     |.  li MULTRES, 8                   // MULTRES = (0+1)*8
4944     |  daddu TMP2, RA, TMP1
4945     |  sltu AT, TMP0, TMP2
4946     |  bnez AT, >7
4947     |.  daddiu MULTRES, TMP1, 8
4948     |6:
4949     |  ld CRET1, 0(RC)
4950     |   daddiu RC, RC, 8
4951     |  sd CRET1, 0(RA)
4952     |  sltu AT, RC, TMP3
4953     |  bnez AT, <6                      // More vararg slots?
4954     |.  daddiu RA, RA, 8
4955     |  b <3
4956     |.  nop
4957     |
4958     |7:  // Grow stack for varargs.
4959     |  load_got lj_state_growstack
4960     |   sd RA, L->top
4961     |  dsubu RA, RA, BASE
4962     |   sd BASE, L->base
4963     |  dsubu BASE, RC, BASE             // Need delta, because BASE may change.
4964     |   sd PC, SAVE_PC
4965     |  srl CARG2, TMP1, 3
4966     |  call_intern lj_state_growstack   // (lua_State *L, int n)
4967     |.  move CARG1, L
4968     |  move RC, BASE
4969     |  ld BASE, L->base
4970     |  daddu RA, BASE, RA
4971     |  daddu RC, BASE, RC
4972     |  b <6
4973     |.  daddiu TMP3, BASE, -16
4974     break;
4976   /* -- Returns ----------------------------------------------------------- */
4978   case BC_RETM:
4979     |  // RA = results*8, RD = extra_nresults*8
4980     |  addu RD, RD, MULTRES             // MULTRES >= 8, so RD >= 8.
4981     |  // Fall through. Assumes BC_RET follows.
4982     break;
4984   case BC_RET:
4985     |  // RA = results*8, RD = (nresults+1)*8
4986     |  ld PC, FRAME_PC(BASE)
4987     |   daddu RA, BASE, RA
4988     |    move MULTRES, RD
4989     |1:
4990     |  andi TMP0, PC, FRAME_TYPE
4991     |  bnez TMP0, ->BC_RETV_Z
4992     |.  xori TMP1, PC, FRAME_VARG
4993     |
4994     |->BC_RET_Z:
4995     |  // BASE = base, RA = resultptr, RD = (nresults+1)*8, PC = return
4996     |   lw INS, -4(PC)
4997     |    daddiu TMP2, BASE, -16
4998     |    daddiu RC, RD, -8
4999     |  decode_RA8a TMP0, INS
5000     |   decode_RB8a RB, INS
5001     |  decode_RA8b TMP0
5002     |   decode_RB8b RB
5003     |   daddu TMP3, TMP2, RB
5004     |  beqz RC, >3
5005     |.  dsubu BASE, TMP2, TMP0
5006     |2:
5007     |   ld CRET1, 0(RA)
5008     |    daddiu RA, RA, 8
5009     |  daddiu RC, RC, -8
5010     |   sd CRET1, 0(TMP2)
5011     |  bnez RC, <2
5012     |.   daddiu TMP2, TMP2, 8
5013     |3:
5014     |  daddiu TMP3, TMP3, -8
5015     |5:
5016     |  sltu AT, TMP2, TMP3
5017     |  bnez AT, >6
5018     |.  ld LFUNC:TMP1, FRAME_FUNC(BASE)
5019     |  ins_next1
5020     |  cleartp LFUNC:TMP1
5021     |  ld TMP1, LFUNC:TMP1->pc
5022     |  ld KBASE, PC2PROTO(k)(TMP1)
5023     |  ins_next2
5024     |
5025     |6:  // Fill up results with nil.
5026     |  sd TISNIL, 0(TMP2)
5027     |  b <5
5028     |.  daddiu TMP2, TMP2, 8
5029     |
5030     |->BC_RETV_Z:  // Non-standard return case.
5031     |  andi TMP2, TMP1, FRAME_TYPEP
5032     |  bnez TMP2, ->vm_return
5033     |.  nop
5034     |  // Return from vararg function: relocate BASE down.
5035     |  dsubu BASE, BASE, TMP1
5036     |  b <1
5037     |.  ld PC, FRAME_PC(BASE)
5038     break;
5040   case BC_RET0: case BC_RET1:
5041     |  // RA = results*8, RD = (nresults+1)*8
5042     |  ld PC, FRAME_PC(BASE)
5043     |   daddu RA, BASE, RA
5044     |    move MULTRES, RD
5045     |  andi TMP0, PC, FRAME_TYPE
5046     |  bnez TMP0, ->BC_RETV_Z
5047     |.  xori TMP1, PC, FRAME_VARG
5048     |  lw INS, -4(PC)
5049     |   daddiu TMP2, BASE, -16
5050     if (op == BC_RET1) {
5051       |  ld CRET1, 0(RA)
5052     }
5053     |  decode_RB8a RB, INS
5054     |   decode_RA8a RA, INS
5055     |  decode_RB8b RB
5056     |   decode_RA8b RA
5057     |   dsubu BASE, TMP2, RA
5058     if (op == BC_RET1) {
5059       |  sd CRET1, 0(TMP2)
5060     }
5061     |5:
5062     |  sltu AT, RD, RB
5063     |  bnez AT, >6
5064     |.  ld TMP1, FRAME_FUNC(BASE)
5065     |  ins_next1
5066     |  cleartp LFUNC:TMP1
5067     |  ld TMP1, LFUNC:TMP1->pc
5068     |  ld KBASE, PC2PROTO(k)(TMP1)
5069     |  ins_next2
5070     |
5071     |6:  // Fill up results with nil.
5072     |  daddiu TMP2, TMP2, 8
5073     |  daddiu RD, RD, 8
5074     |  b <5
5075     if (op == BC_RET1) {
5076       |.  sd TISNIL, 0(TMP2)
5077     } else {
5078       |.  sd TISNIL, -8(TMP2)
5079     }
5080     break;
5082   /* -- Loops and branches ------------------------------------------------ */
5084   case BC_FORL:
5085     |.if JIT
5086     |  hotloop
5087     |.endif
5088     |  // Fall through. Assumes BC_IFORL follows.
5089     break;
5091   case BC_JFORI:
5092   case BC_JFORL:
5093 #if !LJ_HASJIT
5094     break;
5095 #endif
5096   case BC_FORI:
5097   case BC_IFORL:
5098     |  // RA = base*8, RD = target (after end of loop or start of loop)
5099     vk = (op == BC_IFORL || op == BC_JFORL);
5100     |  daddu RA, BASE, RA
5101     |  ld CARG1, FORL_IDX*8(RA)         // IDX CARG1 - CARG3 type
5102     |  gettp CARG3, CARG1
5103     if (op != BC_JFORL) {
5104       |  srl RD, RD, 1
5105       |  lui TMP2, (-(BCBIAS_J*4 >> 16) & 65535)
5106       |  daddu TMP2, RD, TMP2
5107     }
5108     if (!vk) {
5109       |  ld CARG2, FORL_STOP*8(RA)      // STOP CARG2 - CARG4 type
5110       |  ld CRET1, FORL_STEP*8(RA)      // STEP CRET1 - CRET2 type
5111       |  gettp CARG4, CARG2
5112       |  bne CARG3, TISNUM, >5
5113       |.  gettp CRET2, CRET1
5114       |  bne CARG4, TISNUM, ->vmeta_for
5115       |.  sextw CARG3, CARG1
5116       |  bne CRET2, TISNUM, ->vmeta_for
5117       |.  sextw CARG2, CARG2
5118       |  dext AT, CRET1, 31, 0
5119       |  slt CRET1, CARG2, CARG3
5120       |  slt TMP1, CARG3, CARG2
5121       |.if MIPSR6
5122       |  selnez TMP1, TMP1, AT
5123       |  seleqz CRET1, CRET1, AT
5124       |  or CRET1, CRET1, TMP1
5125       |.else
5126       |  movn CRET1, TMP1, AT
5127       |.endif
5128     } else {
5129       |  bne CARG3, TISNUM, >5
5130       |.  ld CARG2, FORL_STEP*8(RA)     // STEP CARG2 - CARG4 type
5131       |    ld CRET1, FORL_STOP*8(RA)    // STOP CRET1 - CRET2 type
5132       |  sextw TMP3, CARG1
5133       |   sextw CARG2, CARG2
5134       |    sextw CRET1, CRET1
5135       |  addu CARG1, TMP3, CARG2
5136       |  xor TMP0, CARG1, TMP3
5137       |  xor TMP1, CARG1, CARG2
5138       |  and TMP0, TMP0, TMP1
5139       |  slt TMP1, CARG1, CRET1
5140       |  slt CRET1, CRET1, CARG1
5141       |  slt AT, CARG2, r0
5142       |   slt TMP0, TMP0, r0            // ((y^a) & (y^b)) < 0: overflow.
5143       |.if MIPSR6
5144       |  selnez TMP1, TMP1, AT
5145       |  seleqz CRET1, CRET1, AT
5146       |  or CRET1, CRET1, TMP1
5147       |.else
5148       |  movn CRET1, TMP1, AT
5149       |.endif
5150       |   or CRET1, CRET1, TMP0
5151       |  zextw CARG1, CARG1
5152       |  settp CARG1, TISNUM
5153     }
5154     |1:
5155     if (op == BC_FORI) {
5156       |.if MIPSR6
5157       |  selnez TMP2, TMP2, CRET1
5158       |.else
5159       |  movz TMP2, r0, CRET1
5160       |.endif
5161       |  daddu PC, PC, TMP2
5162     } else if (op == BC_JFORI) {
5163       |  daddu PC, PC, TMP2
5164       |  lhu RD, -4+OFS_RD(PC)
5165     } else if (op == BC_IFORL) {
5166       |.if MIPSR6
5167       |  seleqz TMP2, TMP2, CRET1
5168       |.else
5169       |  movn TMP2, r0, CRET1
5170       |.endif
5171       |  daddu PC, PC, TMP2
5172     }
5173     if (vk) {
5174       |  sd CARG1, FORL_IDX*8(RA)
5175     }
5176     |  ins_next1
5177     |  sd CARG1, FORL_EXT*8(RA)
5178     |2:
5179     if (op == BC_JFORI) {
5180       |  beqz CRET1, =>BC_JLOOP
5181       |.  decode_RD8b RD
5182     } else if (op == BC_JFORL) {
5183       |  beqz CRET1, =>BC_JLOOP
5184     }
5185     |  ins_next2
5186     |
5187     |5:  // FP loop.
5188     |.if FPU
5189     if (!vk) {
5190       |  ldc1 f0, FORL_IDX*8(RA)
5191       |   ldc1 f2, FORL_STOP*8(RA)
5192       |  sltiu TMP0, CARG3, LJ_TISNUM
5193       |  sltiu TMP1, CARG4, LJ_TISNUM
5194       |  sltiu AT, CRET2, LJ_TISNUM
5195       |   ld TMP3, FORL_STEP*8(RA)
5196       |  and TMP0, TMP0, TMP1
5197       |  and AT, AT, TMP0
5198       |  beqz AT, ->vmeta_for
5199       |.  slt TMP3, TMP3, r0
5200       |.if MIPSR6
5201       |   dmtc1 TMP3, FTMP2
5202       |  cmp.lt.d FTMP0, f0, f2
5203       |  cmp.lt.d FTMP1, f2, f0
5204       |  sel.d FTMP2, FTMP1, FTMP0
5205       |  b <1
5206       |.  dmfc1 CRET1, FTMP2
5207       |.else
5208       |  c.ole.d 0, f0, f2
5209       |  c.ole.d 1, f2, f0
5210       |  li CRET1, 1
5211       |  movt CRET1, r0, 0
5212       |  movt AT, r0, 1
5213       |  b <1
5214       |.  movn CRET1, AT, TMP3
5215       |.endif
5216     } else {
5217       |  ldc1 f0, FORL_IDX*8(RA)
5218       |   ldc1 f4, FORL_STEP*8(RA)
5219       |    ldc1 f2, FORL_STOP*8(RA)
5220       |   ld TMP3, FORL_STEP*8(RA)
5221       |  add.d f0, f0, f4
5222       |.if MIPSR6
5223       |   slt TMP3, TMP3, r0
5224       |   dmtc1 TMP3, FTMP2
5225       |  cmp.lt.d FTMP0, f0, f2
5226       |  cmp.lt.d FTMP1, f2, f0
5227       |  sel.d FTMP2, FTMP1, FTMP0
5228       |  dmfc1 CRET1, FTMP2
5229       if (op == BC_IFORL) {
5230         |  seleqz TMP2, TMP2, CRET1
5231         |  daddu PC, PC, TMP2
5232       }
5233       |.else
5234       |  c.ole.d 0, f0, f2
5235       |  c.ole.d 1, f2, f0
5236       |   slt TMP3, TMP3, r0
5237       |  li CRET1, 1
5238       |  li AT, 1
5239       |  movt CRET1, r0, 0
5240       |  movt AT, r0, 1
5241       |  movn CRET1, AT, TMP3
5242       if (op == BC_IFORL) {
5243         |  movn TMP2, r0, CRET1
5244         |  daddu PC, PC, TMP2
5245       }
5246       |.endif
5247       |  sdc1 f0, FORL_IDX*8(RA)
5248       |  ins_next1
5249       |  b <2
5250       |.  sdc1 f0, FORL_EXT*8(RA)
5251     }
5252     |.else
5253     if (!vk) {
5254       |  sltiu TMP0, CARG3, LJ_TISNUM
5255       |  sltiu TMP1, CARG4, LJ_TISNUM
5256       |  sltiu AT, CRET2, LJ_TISNUM
5257       |  and TMP0, TMP0, TMP1
5258       |  and AT, AT, TMP0
5259       |  beqz AT, ->vmeta_for
5260       |.  nop
5261       |  bal ->vm_sfcmpolex
5262       |.  lw TMP3, FORL_STEP*8+HI(RA)
5263       |  b <1
5264       |.  nop
5265     } else {
5266       |  load_got __adddf3
5267       |  call_extern
5268       |.  sw TMP2, TMPD
5269       |  ld CARG2, FORL_STOP*8(RA)
5270       |  move CARG1, CRET1
5271       if ( op == BC_JFORL ) {
5272         |  lhu RD, -4+OFS_RD(PC)
5273         |  decode_RD8b RD
5274       }
5275       |  bal ->vm_sfcmpolex
5276       |.  lw TMP3, FORL_STEP*8+HI(RA)
5277       |  b <1
5278       |.  lw TMP2, TMPD
5279     }
5280     |.endif
5281     break;
5283   case BC_ITERL:
5284     |.if JIT
5285     |  hotloop
5286     |.endif
5287     |  // Fall through. Assumes BC_IITERL follows.
5288     break;
5290   case BC_JITERL:
5291 #if !LJ_HASJIT
5292     break;
5293 #endif
5294   case BC_IITERL:
5295     |  // RA = base*8, RD = target
5296     |  daddu RA, BASE, RA
5297     |  ld TMP1, 0(RA)
5298     |  beq TMP1, TISNIL, >1             // Stop if iterator returned nil.
5299     |.  nop
5300     if (op == BC_JITERL) {
5301       |  b =>BC_JLOOP
5302       |.  sd TMP1, -8(RA)
5303     } else {
5304       |  branch_RD                      // Otherwise save control var + branch.
5305       |  sd TMP1, -8(RA)
5306     }
5307     |1:
5308     |  ins_next
5309     break;
5311   case BC_LOOP:
5312     |  // RA = base*8, RD = target (loop extent)
5313     |  // Note: RA/RD is only used by trace recorder to determine scope/extent
5314     |  // This opcode does NOT jump, it's only purpose is to detect a hot loop.
5315     |.if JIT
5316     |  hotloop
5317     |.endif
5318     |  // Fall through. Assumes BC_ILOOP follows.
5319     break;
5321   case BC_ILOOP:
5322     |  // RA = base*8, RD = target (loop extent)
5323     |  ins_next
5324     break;
5326   case BC_JLOOP:
5327     |.if JIT
5328     |  // RA = base*8 (ignored), RD = traceno*8
5329     |  ld TMP1, DISPATCH_J(trace)(DISPATCH)
5330     |   li AT, 0
5331     |  daddu TMP1, TMP1, RD
5332     |  // Traces on MIPS don't store the trace number, so use 0.
5333     |   sd AT, DISPATCH_GL(vmstate)(DISPATCH)
5334     |  ld TRACE:TMP2, 0(TMP1)
5335     |   sd BASE, DISPATCH_GL(jit_base)(DISPATCH)
5336     |  ld TMP2, TRACE:TMP2->mcode
5337     |   sd L, DISPATCH_GL(tmpbuf.L)(DISPATCH)
5338     |  jr TMP2
5339     |.  daddiu JGL, DISPATCH, GG_DISP2G+32768
5340     |.endif
5341     break;
5343   case BC_JMP:
5344     |  // RA = base*8 (only used by trace recorder), RD = target
5345     |  branch_RD
5346     |  ins_next
5347     break;
5349   /* -- Function headers -------------------------------------------------- */
5351   case BC_FUNCF:
5352     |.if JIT
5353     |  hotcall
5354     |.endif
5355   case BC_FUNCV:  /* NYI: compiled vararg functions. */
5356     |  // Fall through. Assumes BC_IFUNCF/BC_IFUNCV follow.
5357     break;
5359   case BC_JFUNCF:
5360 #if !LJ_HASJIT
5361     break;
5362 #endif
5363   case BC_IFUNCF:
5364     |  // BASE = new base, RA = BASE+framesize*8, RB = LFUNC, RC = nargs*8
5365     |  ld TMP2, L->maxstack
5366     |   lbu TMP1, -4+PC2PROTO(numparams)(PC)
5367     |    ld KBASE, -4+PC2PROTO(k)(PC)
5368     |  sltu AT, TMP2, RA
5369     |  bnez AT, ->vm_growstack_l
5370     |.  sll TMP1, TMP1, 3
5371     if (op != BC_JFUNCF) {
5372       |  ins_next1
5373     }
5374     |2:
5375     |  sltu AT, NARGS8:RC, TMP1         // Check for missing parameters.
5376     |  bnez AT, >3
5377     |.  daddu AT, BASE, NARGS8:RC
5378     if (op == BC_JFUNCF) {
5379       |  decode_RD8a RD, INS
5380       |  b =>BC_JLOOP
5381       |.  decode_RD8b RD
5382     } else {
5383       |  ins_next2
5384     }
5385     |
5386     |3:  // Clear missing parameters.
5387     |  sd TISNIL, 0(AT)
5388     |  b <2
5389     |.  addiu NARGS8:RC, NARGS8:RC, 8
5390     break;
5392   case BC_JFUNCV:
5393 #if !LJ_HASJIT
5394     break;
5395 #endif
5396     |  NYI  // NYI: compiled vararg functions
5397     break;  /* NYI: compiled vararg functions. */
5399   case BC_IFUNCV:
5400     |  // BASE = new base, RA = BASE+framesize*8, RB = LFUNC, RC = nargs*8
5401     |   li TMP0, LJ_TFUNC
5402     |   daddu TMP1, BASE, RC
5403     |  ld TMP2, L->maxstack
5404     |   settp LFUNC:RB, TMP0
5405     |  daddu TMP0, RA, RC
5406     |   sd LFUNC:RB, 0(TMP1)            // Store (tagged) copy of LFUNC.
5407     |  daddiu TMP2, TMP2, -8
5408     |   daddiu TMP3, RC, 16+FRAME_VARG
5409     |  sltu AT, TMP0, TMP2
5410     |    ld KBASE, -4+PC2PROTO(k)(PC)
5411     |  beqz AT, ->vm_growstack_l
5412     |.  sd TMP3, 8(TMP1)                // Store delta + FRAME_VARG.
5413     |  lbu TMP2, -4+PC2PROTO(numparams)(PC)
5414     |   move RA, BASE
5415     |   move RC, TMP1
5416     |  ins_next1
5417     |  beqz TMP2, >3
5418     |.  daddiu BASE, TMP1, 16
5419     |1:
5420     |  ld TMP0, 0(RA)
5421     |  sltu AT, RA, RC                  // Less args than parameters?
5422     |  move CARG1, TMP0
5423     |.if MIPSR6
5424     |  selnez TMP0, TMP0, AT
5425     |  seleqz TMP3, TISNIL, AT
5426     |  or TMP0, TMP0, TMP3
5427     |  seleqz TMP3, CARG1, AT
5428     |  selnez CARG1, TISNIL, AT
5429     |  or CARG1, CARG1, TMP3
5430     |.else
5431     |  movz TMP0, TISNIL, AT            // Clear missing parameters.
5432     |  movn CARG1, TISNIL, AT           // Clear old fixarg slot (help the GC).
5433     |.endif
5434     |    addiu TMP2, TMP2, -1
5435     |  sd TMP0, 16(TMP1)
5436     |    daddiu TMP1, TMP1, 8
5437     |  sd CARG1, 0(RA)
5438     |  bnez TMP2, <1
5439     |.   daddiu RA, RA, 8
5440     |3:
5441     |  ins_next2
5442     break;
5444   case BC_FUNCC:
5445   case BC_FUNCCW:
5446     |  // BASE = new base, RA = BASE+framesize*8, RB = CFUNC, RC = nargs*8
5447     if (op == BC_FUNCC) {
5448       |  ld CFUNCADDR, CFUNC:RB->f
5449     } else {
5450       |  ld CFUNCADDR, DISPATCH_GL(wrapf)(DISPATCH)
5451     }
5452     |  daddu TMP1, RA, NARGS8:RC
5453     |  ld TMP2, L->maxstack
5454     |   daddu RC, BASE, NARGS8:RC
5455     |  sd BASE, L->base
5456     |  sltu AT, TMP2, TMP1
5457     |   sd RC, L->top
5458     |    li_vmstate C
5459     if (op == BC_FUNCCW) {
5460       |  ld CARG2, CFUNC:RB->f
5461     }
5462     |  bnez AT, ->vm_growstack_c        // Need to grow stack.
5463     |.  move CARG1, L
5464     |  jalr CFUNCADDR                   // (lua_State *L [, lua_CFunction f])
5465     |.   st_vmstate
5466     |  // Returns nresults.
5467     |  ld BASE, L->base
5468     |   sll RD, CRET1, 3
5469     |  ld TMP1, L->top
5470     |    li_vmstate INTERP
5471     |  ld PC, FRAME_PC(BASE)            // Fetch PC of caller.
5472     |   dsubu RA, TMP1, RD              // RA = L->top - nresults*8
5473     |    sd L, DISPATCH_GL(cur_L)(DISPATCH)
5474     |  b ->vm_returnc
5475     |.   st_vmstate
5476     break;
5478   /* ---------------------------------------------------------------------- */
5480   default:
5481     fprintf(stderr, "Error: undefined opcode BC_%s\n", bc_names[op]);
5482     exit(2);
5483     break;
5484   }
5487 static int build_backend(BuildCtx *ctx)
5489   int op;
5491   dasm_growpc(Dst, BC__MAX);
5493   build_subroutines(ctx);
5495   |.code_op
5496   for (op = 0; op < BC__MAX; op++)
5497     build_ins(ctx, (BCOp)op, op);
5499   return BC__MAX;
5502 /* Emit pseudo frame-info for all assembler functions. */
5503 static void emit_asm_debug(BuildCtx *ctx)
5505   int fcofs = (int)((uint8_t *)ctx->glob[GLOB_vm_ffi_call] - ctx->code);
5506   int i;
5507   switch (ctx->mode) {
5508   case BUILD_elfasm:
5509     fprintf(ctx->fp, "\t.section .debug_frame,\"\",@progbits\n");
5510     fprintf(ctx->fp,
5511         ".Lframe0:\n"
5512         "\t.4byte .LECIE0-.LSCIE0\n"
5513         ".LSCIE0:\n"
5514         "\t.4byte 0xffffffff\n"
5515         "\t.byte 0x1\n"
5516         "\t.string \"\"\n"
5517         "\t.uleb128 0x1\n"
5518         "\t.sleb128 -4\n"
5519         "\t.byte 31\n"
5520         "\t.byte 0xc\n\t.uleb128 29\n\t.uleb128 0\n"
5521         "\t.align 2\n"
5522         ".LECIE0:\n\n");
5523     fprintf(ctx->fp,
5524         ".LSFDE0:\n"
5525         "\t.4byte .LEFDE0-.LASFDE0\n"
5526         ".LASFDE0:\n"
5527         "\t.4byte .Lframe0\n"
5528         "\t.8byte .Lbegin\n"
5529         "\t.8byte %d\n"
5530         "\t.byte 0xe\n\t.uleb128 %d\n"
5531         "\t.byte 0x9f\n\t.sleb128 2*5\n"
5532         "\t.byte 0x9e\n\t.sleb128 2*6\n",
5533         fcofs, CFRAME_SIZE);
5534     for (i = 23; i >= 16; i--)
5535       fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+i, 2*(30-i));
5536 #if !LJ_SOFTFP
5537     for (i = 31; i >= 24; i--)
5538       fprintf(ctx->fp, "\t.byte %d\n\t.uleb128 %d\n", 0x80+32+i, 2*(46-i));
5539 #endif
5540     fprintf(ctx->fp,
5541         "\t.align 2\n"
5542         ".LEFDE0:\n\n");
5543 #if LJ_HASFFI
5544     fprintf(ctx->fp,
5545         ".LSFDE1:\n"
5546         "\t.4byte .LEFDE1-.LASFDE1\n"
5547         ".LASFDE1:\n"
5548         "\t.4byte .Lframe0\n"
5549         "\t.4byte lj_vm_ffi_call\n"
5550         "\t.4byte %d\n"
5551         "\t.byte 0x9f\n\t.uleb128 2*1\n"
5552         "\t.byte 0x90\n\t.uleb128 2*2\n"
5553         "\t.byte 0xd\n\t.uleb128 0x10\n"
5554         "\t.align 2\n"
5555         ".LEFDE1:\n\n", (int)ctx->codesz - fcofs);
5556 #endif
5557 #if !LJ_NO_UNWIND
5558     /* NYI */
5559 #endif
5560     break;
5561   default:
5562     break;
5563   }