ljx

FORK: LuaJIT with native 5.2 and 5.3 support
git clone https://git.neptards.moe/neptards/ljx.git
Log | Files | Refs | README

vm_mips64.dasc (131219B)


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