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_mips.dasc (143854B)


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