aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/dis_mips.lua2
-rw-r--r--lib/dump.lua17
-rw-r--r--src/lj_arch.h1
-rw-r--r--src/lj_asm.c24
-rw-r--r--src/lj_asm_mips.h1949
-rw-r--r--src/lj_emit_mips.h205
-rw-r--r--src/lj_ircall.h6
-rw-r--r--src/lj_mcode.c6
-rw-r--r--src/lj_target.h6
-rw-r--r--src/lj_target_mips.h117
10 files changed, 2308 insertions, 25 deletions
diff --git a/lib/dis_mips.lua b/lib/dis_mips.lua
index 165405d2..2edfdf40 100644
--- a/lib/dis_mips.lua
+++ b/lib/dis_mips.lua
@@ -231,7 +231,7 @@ local map_gpr = {
231 [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", 231 [0] = "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
232 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15", 232 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
233 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", 233 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
234 "r24", "r25", "r26", "r27", "gp", "sp", "r30", "ra", 234 "r24", "r25", "r26", "r27", "r28", "sp", "r30", "ra",
235} 235}
236 236
237------------------------------------------------------------------------------ 237------------------------------------------------------------------------------
diff --git a/lib/dump.lua b/lib/dump.lua
index 37c06502..3d62c4ea 100644
--- a/lib/dump.lua
+++ b/lib/dump.lua
@@ -84,6 +84,10 @@ local nexitsym = 0
84local function fillsymtab_tr(tr, nexit) 84local function fillsymtab_tr(tr, nexit)
85 local t = {} 85 local t = {}
86 symtabmt.__index = t 86 symtabmt.__index = t
87 if jit.arch == "mips" or jit.arch == "mipsel" then
88 t[traceexitstub(tr, 0)] = "exit"
89 return
90 end
87 for i=0,nexit-1 do 91 for i=0,nexit-1 do
88 local addr = traceexitstub(tr, i) 92 local addr = traceexitstub(tr, i)
89 t[addr] = tostring(i) 93 t[addr] = tostring(i)
@@ -604,9 +608,16 @@ local function dump_texit(tr, ex, ngpr, nfpr, ...)
604 if i % 8 == 0 then out:write("\n") end 608 if i % 8 == 0 then out:write("\n") end
605 end 609 end
606 end 610 end
607 for i=1,nfpr do 611 if jit.arch == "mips" or jit.arch == "mipsel" then
608 out:write(format(" %+17.14g", regs[ngpr+i])) 612 for i=1,nfpr,2 do
609 if i % 4 == 0 then out:write("\n") end 613 out:write(format(" %+17.14g", regs[ngpr+i]))
614 if i % 8 == 7 then out:write("\n") end
615 end
616 else
617 for i=1,nfpr do
618 out:write(format(" %+17.14g", regs[ngpr+i]))
619 if i % 4 == 0 then out:write("\n") end
620 end
610 end 621 end
611 end 622 end
612end 623end
diff --git a/src/lj_arch.h b/src/lj_arch.h
index 50741154..1f8e1026 100644
--- a/src/lj_arch.h
+++ b/src/lj_arch.h
@@ -204,7 +204,6 @@
204#define LJ_TARGET_MASKROT 1 204#define LJ_TARGET_MASKROT 1
205#define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */ 205#define LJ_TARGET_UNIFYROT 2 /* Want only IR_BROR. */
206#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE 206#define LJ_ARCH_NUMMODE LJ_NUMMODE_SINGLE
207#define LJ_ARCH_NOJIT 1
208 207
209#else 208#else
210#error "No target architecture defined" 209#error "No target architecture defined"
diff --git a/src/lj_asm.c b/src/lj_asm.c
index 7c27a98f..1a78e32a 100644
--- a/src/lj_asm.c
+++ b/src/lj_asm.c
@@ -155,6 +155,8 @@ IRFLDEF(FLOFS)
155#include "lj_emit_arm.h" 155#include "lj_emit_arm.h"
156#elif LJ_TARGET_PPC 156#elif LJ_TARGET_PPC
157#include "lj_emit_ppc.h" 157#include "lj_emit_ppc.h"
158#elif LJ_TARGET_MIPS
159#include "lj_emit_mips.h"
158#else 160#else
159#error "Missing instruction emitter for target CPU" 161#error "Missing instruction emitter for target CPU"
160#endif 162#endif
@@ -441,12 +443,22 @@ static Reg ra_scratch(ASMState *as, RegSet allow)
441/* Evict all registers from a set (if not free). */ 443/* Evict all registers from a set (if not free). */
442static void ra_evictset(ASMState *as, RegSet drop) 444static void ra_evictset(ASMState *as, RegSet drop)
443{ 445{
446 RegSet work;
444 as->modset |= drop; 447 as->modset |= drop;
445 drop &= ~as->freeset; 448#if !LJ_SOFTFP
446 while (drop) { 449 work = (drop & ~as->freeset) & RSET_FPR;
447 Reg r = rset_pickbot(drop); 450 while (work) {
451 Reg r = rset_pickbot(work);
448 ra_restore(as, regcost_ref(as->cost[r])); 452 ra_restore(as, regcost_ref(as->cost[r]));
449 rset_clear(drop, r); 453 rset_clear(work, r);
454 checkmclim(as);
455 }
456#endif
457 work = (drop & ~as->freeset) & RSET_GPR;
458 while (work) {
459 Reg r = rset_pickbot(work);
460 ra_restore(as, regcost_ref(as->cost[r]));
461 rset_clear(work, r);
450 checkmclim(as); 462 checkmclim(as);
451 } 463 }
452} 464}
@@ -1153,6 +1165,8 @@ static void asm_loop(ASMState *as)
1153#include "lj_asm_arm.h" 1165#include "lj_asm_arm.h"
1154#elif LJ_TARGET_PPC 1166#elif LJ_TARGET_PPC
1155#include "lj_asm_ppc.h" 1167#include "lj_asm_ppc.h"
1168#elif LJ_TARGET_MIPS
1169#include "lj_asm_mips.h"
1156#else 1170#else
1157#error "Missing assembler for target CPU" 1171#error "Missing assembler for target CPU"
1158#endif 1172#endif
@@ -1530,9 +1544,7 @@ static void asm_setup_regsp(ASMState *as)
1530#if LJ_SOFTFP 1544#if LJ_SOFTFP
1531 case IR_MIN: case IR_MAX: 1545 case IR_MIN: case IR_MAX:
1532#endif 1546#endif
1533#if LJ_BE
1534 (ir-1)->prev = REGSP_HINT(RID_RETLO); 1547 (ir-1)->prev = REGSP_HINT(RID_RETLO);
1535#endif
1536 ir->prev = REGSP_HINT(RID_RETHI); 1548 ir->prev = REGSP_HINT(RID_RETHI);
1537 continue; 1549 continue;
1538 default: 1550 default:
diff --git a/src/lj_asm_mips.h b/src/lj_asm_mips.h
new file mode 100644
index 00000000..9bae4778
--- /dev/null
+++ b/src/lj_asm_mips.h
@@ -0,0 +1,1949 @@
1/*
2** MIPS IR assembler (SSA IR -> machine code).
3** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6/* -- Register allocator extensions --------------------------------------- */
7
8/* Allocate a register with a hint. */
9static Reg ra_hintalloc(ASMState *as, IRRef ref, Reg hint, RegSet allow)
10{
11 Reg r = IR(ref)->r;
12 if (ra_noreg(r)) {
13 if (!ra_hashint(r) && !iscrossref(as, ref))
14 ra_sethint(IR(ref)->r, hint); /* Propagate register hint. */
15 r = ra_allocref(as, ref, allow);
16 }
17 ra_noweak(as, r);
18 return r;
19}
20
21/* Allocate a register or RID_ZERO. */
22static Reg ra_alloc1z(ASMState *as, IRRef ref, RegSet allow)
23{
24 Reg r = IR(ref)->r;
25 if (ra_noreg(r)) {
26 if (!(allow & RSET_FPR) && irref_isk(ref) && IR(ref)->i == 0)
27 return RID_ZERO;
28 r = ra_allocref(as, ref, allow);
29 } else {
30 ra_noweak(as, r);
31 }
32 return r;
33}
34
35/* Allocate two source registers for three-operand instructions. */
36static Reg ra_alloc2(ASMState *as, IRIns *ir, RegSet allow)
37{
38 IRIns *irl = IR(ir->op1), *irr = IR(ir->op2);
39 Reg left = irl->r, right = irr->r;
40 if (ra_hasreg(left)) {
41 ra_noweak(as, left);
42 if (ra_noreg(right))
43 right = ra_alloc1z(as, ir->op2, rset_exclude(allow, left));
44 else
45 ra_noweak(as, right);
46 } else if (ra_hasreg(right)) {
47 ra_noweak(as, right);
48 left = ra_alloc1z(as, ir->op1, rset_exclude(allow, right));
49 } else if (ra_hashint(right)) {
50 right = ra_alloc1z(as, ir->op2, allow);
51 left = ra_alloc1z(as, ir->op1, rset_exclude(allow, right));
52 } else {
53 left = ra_alloc1z(as, ir->op1, allow);
54 right = ra_alloc1z(as, ir->op2, rset_exclude(allow, left));
55 }
56 return left | (right << 8);
57}
58
59/* -- Guard handling ------------------------------------------------------ */
60
61/* Need some spare long-range jump slots, for out-of-range branches. */
62#define MIPS_SPAREJUMP 4
63
64/* Setup spare long-range jump slots per mcarea. */
65static void asm_sparejump_setup(ASMState *as)
66{
67 MCode *mxp = as->mcbot;
68 /* Assumes sizeof(MCLink) == 8. */
69 if (((uintptr_t)mxp & (LJ_PAGESIZE-1)) == 8) {
70 lua_assert(MIPSI_NOP == 0);
71 memset(mxp+2, 0, MIPS_SPAREJUMP*8);
72 mxp += MIPS_SPAREJUMP*2;
73 lua_assert(mxp < as->mctop);
74 lj_mcode_commitbot(as->J, mxp);
75 as->mcbot = mxp;
76 as->mclim = as->mcbot + MCLIM_REDZONE;
77 }
78}
79
80/* Setup exit stub after the end of each trace. */
81static void asm_exitstub_setup(ASMState *as)
82{
83 MCode *mxp = as->mctop;
84 /* sw TMP, 0(sp); j ->vm_exit_handler; li TMP, traceno */
85 *--mxp = MIPSI_LI|MIPSF_T(RID_TMP)|as->T->traceno;
86 *--mxp = MIPSI_J|((((uintptr_t)(void *)lj_vm_exit_handler)>>2)&0x03ffffffu);
87 lua_assert(((uintptr_t)mxp ^ (uintptr_t)(void *)lj_vm_exit_handler)>>28 == 0);
88 *--mxp = MIPSI_SW|MIPSF_T(RID_TMP)|MIPSF_S(RID_SP)|0;
89 as->mctop = mxp;
90}
91
92/* Keep this in-sync with exitstub_trace_addr(). */
93#define asm_exitstub_addr(as) ((as)->mctop)
94
95/* Emit conditional branch to exit for guard. */
96static void asm_guard(ASMState *as, MIPSIns mi, Reg rs, Reg rt)
97{
98 MCode *target = asm_exitstub_addr(as);
99 MCode *p = as->mcp;
100 if (LJ_UNLIKELY(p == as->invmcp)) {
101 as->invmcp = NULL;
102 as->loopinv = 1;
103 as->mcp = p+1;
104 mi = mi ^ ((mi>>28) == 1 ? 0x04000000u : 0x00010000u); /* Invert cond. */
105 target = p; /* Patch target later in asm_loop_fixup. */
106 }
107 emit_ti(as, MIPSI_LI, RID_TMP, as->snapno);
108 emit_branch(as, mi, rs, rt, target);
109}
110
111/* -- Operand fusion ------------------------------------------------------ */
112
113/* Limit linear search to this distance. Avoids O(n^2) behavior. */
114#define CONFLICT_SEARCH_LIM 31
115
116/* Check if there's no conflicting instruction between curins and ref. */
117static int noconflict(ASMState *as, IRRef ref, IROp conflict)
118{
119 IRIns *ir = as->ir;
120 IRRef i = as->curins;
121 if (i > ref + CONFLICT_SEARCH_LIM)
122 return 0; /* Give up, ref is too far away. */
123 while (--i > ref)
124 if (ir[i].o == conflict)
125 return 0; /* Conflict found. */
126 return 1; /* Ok, no conflict. */
127}
128
129/* Fuse the array base of colocated arrays. */
130static int32_t asm_fuseabase(ASMState *as, IRRef ref)
131{
132 IRIns *ir = IR(ref);
133 if (ir->o == IR_TNEW && ir->op1 <= LJ_MAX_COLOSIZE &&
134 !neverfuse(as) && noconflict(as, ref, IR_NEWREF))
135 return (int32_t)sizeof(GCtab);
136 return 0;
137}
138
139/* Fuse array/hash/upvalue reference into register+offset operand. */
140static Reg asm_fuseahuref(ASMState *as, IRRef ref, int32_t *ofsp, RegSet allow)
141{
142 IRIns *ir = IR(ref);
143 if (ra_noreg(ir->r)) {
144 if (ir->o == IR_AREF) {
145 if (mayfuse(as, ref)) {
146 if (irref_isk(ir->op2)) {
147 IRRef tab = IR(ir->op1)->op1;
148 int32_t ofs = asm_fuseabase(as, tab);
149 IRRef refa = ofs ? tab : ir->op1;
150 ofs += 8*IR(ir->op2)->i;
151 if (checki16(ofs)) {
152 *ofsp = ofs;
153 return ra_alloc1(as, refa, allow);
154 }
155 }
156 }
157 } else if (ir->o == IR_HREFK) {
158 if (mayfuse(as, ref)) {
159 int32_t ofs = (int32_t)(IR(ir->op2)->op2 * sizeof(Node));
160 if (checki16(ofs)) {
161 *ofsp = ofs;
162 return ra_alloc1(as, ir->op1, allow);
163 }
164 }
165 } else if (ir->o == IR_UREFC) {
166 if (irref_isk(ir->op1)) {
167 GCfunc *fn = ir_kfunc(IR(ir->op1));
168 int32_t ofs = i32ptr(&gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.tv);
169 int32_t jgl = (intptr_t)J2G(as->J);
170 if ((uint32_t)(ofs-jgl) < 65536) {
171 *ofsp = ofs-jgl-32768;
172 return RID_JGL;
173 } else {
174 *ofsp = (int16_t)ofs;
175 return ra_allock(as, ofs-(int16_t)ofs, allow);
176 }
177 }
178 }
179 }
180 *ofsp = 0;
181 return ra_alloc1(as, ref, allow);
182}
183
184/* Fuse XLOAD/XSTORE reference into load/store operand. */
185static void asm_fusexref(ASMState *as, MIPSIns mi, Reg rt, IRRef ref,
186 RegSet allow)
187{
188 IRIns *ir = IR(ref);
189 int32_t ofs = 0;
190 Reg base;
191 if (ra_noreg(ir->r) && mayfuse(as, ref)) {
192 if (ir->o == IR_ADD) {
193 int32_t ofs2;
194 if (irref_isk(ir->op2) && (ofs2 = IR(ir->op2)->i, checki16(ofs2))) {
195 ref = ir->op1;
196 ofs = ofs2;
197 }
198 } else if (ir->o == IR_STRREF) {
199 int32_t ofs2 = 65536;
200 ofs = (int32_t)sizeof(GCstr);
201 if (irref_isk(ir->op2)) {
202 ofs2 = ofs + IR(ir->op2)->i;
203 ref = ir->op1;
204 } else if (irref_isk(ir->op1)) {
205 ofs2 = ofs + IR(ir->op1)->i;
206 ref = ir->op2;
207 }
208 if (!checki16(ofs2)) {
209 /* NYI: Fuse ADD with constant. */
210 Reg right, left = ra_alloc2(as, ir, allow);
211 right = (left >> 8); left &= 255;
212 emit_hsi(as, mi, rt, RID_TMP, ofs);
213 emit_dst(as, MIPSI_ADDU, RID_TMP, left, right);
214 return;
215 }
216 ofs = ofs2;
217 }
218 }
219 base = ra_alloc1(as, ref, allow);
220 emit_hsi(as, mi, rt, base, ofs);
221}
222
223/* -- Calls --------------------------------------------------------------- */
224
225/* Generate a call to a C function. */
226static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args)
227{
228 uint32_t n, nargs = CCI_NARGS(ci);
229 int32_t ofs = 16;
230 Reg gpr = REGARG_FIRSTGPR, fpr = REGARG_FIRSTFPR;
231 if ((void *)ci->func)
232 emit_call(as, (void *)ci->func);
233 for (n = 0; n < nargs; n++) { /* Setup args. */
234 IRRef ref = args[n];
235 if (ref) {
236 IRIns *ir = IR(ref);
237 if (irt_isfp(ir->t) && fpr <= REGARG_LASTFPR &&
238 !(ci->flags & CCI_VARARG)) {
239 lua_assert(rset_test(as->freeset, fpr)); /* Already evicted. */
240 ra_leftov(as, fpr, ref);
241 fpr += 2;
242 gpr += irt_isnum(ir->t) ? 2 : 1;
243 } else {
244 fpr = REGARG_LASTFPR+1;
245 if (irt_isnum(ir->t)) gpr = (gpr+1) & ~1;
246 if (gpr <= REGARG_LASTGPR) {
247 lua_assert(rset_test(as->freeset, gpr)); /* Already evicted. */
248 if (irt_isnum(ir->t)) {
249 Reg r = ra_alloc1(as, ref, RSET_FPR);
250 emit_tg(as, MIPSI_MFC1, gpr+(LJ_BE?0:1), r+1);
251 emit_tg(as, MIPSI_MFC1, gpr+(LJ_BE?1:0), r);
252 lua_assert(rset_test(as->freeset, gpr+1)); /* Already evicted. */
253 gpr += 2;
254 } else if (irt_isfloat(ir->t)) {
255 Reg r = ra_alloc1(as, ref, RSET_FPR);
256 emit_tg(as, MIPSI_MFC1, gpr, r);
257 gpr++;
258 } else {
259 ra_leftov(as, gpr, ref);
260 gpr++;
261 }
262 } else {
263 Reg r = ra_alloc1z(as, ref, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR);
264 if (irt_isnum(ir->t)) ofs = (ofs + 4) & ~4;
265 emit_spstore(as, ir, r, ofs);
266 ofs += irt_isnum(ir->t) ? 8 : 4;
267 }
268 }
269 } else {
270 fpr = REGARG_LASTFPR+1;
271 if (gpr <= REGARG_LASTGPR)
272 gpr++;
273 else
274 ofs += 4;
275 }
276 }
277}
278
279/* Setup result reg/sp for call. Evict scratch regs. */
280static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci)
281{
282 RegSet drop = RSET_SCRATCH;
283 int hiop = ((ir+1)->o == IR_HIOP);
284 if ((ci->flags & CCI_NOFPRCLOBBER))
285 drop &= ~RSET_FPR;
286 if (ra_hasreg(ir->r))
287 rset_clear(drop, ir->r); /* Dest reg handled below. */
288 if (hiop && ra_hasreg((ir+1)->r))
289 rset_clear(drop, (ir+1)->r); /* Dest reg handled below. */
290 ra_evictset(as, drop); /* Evictions must be performed first. */
291 if (ra_used(ir)) {
292 lua_assert(!irt_ispri(ir->t));
293 if (irt_isfp(ir->t)) {
294 if ((ci->flags & CCI_CASTU64)) {
295 int32_t ofs = sps_scale(ir->s);
296 Reg dest = ir->r;
297 if (ra_hasreg(dest)) {
298 ra_free(as, dest);
299 ra_modified(as, dest);
300 emit_tg(as, MIPSI_MTC1, RID_RETHI, dest+1);
301 emit_tg(as, MIPSI_MTC1, RID_RETLO, dest);
302 }
303 if (ofs) {
304 emit_tsi(as, MIPSI_SW, RID_RETLO, RID_SP, ofs+(LJ_BE?4:0));
305 emit_tsi(as, MIPSI_SW, RID_RETHI, RID_SP, ofs+(LJ_BE?0:4));
306 }
307 } else {
308 ra_destreg(as, ir, RID_FPRET);
309 }
310 } else if (hiop) {
311 ra_destpair(as, ir);
312 } else {
313 ra_destreg(as, ir, RID_RET);
314 }
315 }
316}
317
318static void asm_call(ASMState *as, IRIns *ir)
319{
320 IRRef args[CCI_NARGS_MAX];
321 const CCallInfo *ci = &lj_ir_callinfo[ir->op2];
322 asm_collectargs(as, ir, ci, args);
323 asm_setupresult(as, ir, ci);
324 asm_gencall(as, ci, args);
325}
326
327static void asm_callx(ASMState *as, IRIns *ir)
328{
329 IRRef args[CCI_NARGS_MAX];
330 CCallInfo ci;
331 IRRef func;
332 IRIns *irf;
333 ci.flags = asm_callx_flags(as, ir);
334 asm_collectargs(as, ir, &ci, args);
335 asm_setupresult(as, ir, &ci);
336 func = ir->op2; irf = IR(func);
337 if (irf->o == IR_CARG) { func = irf->op1; irf = IR(func); }
338 if (irref_isk(func)) { /* Call to constant address. */
339 ci.func = (ASMFunction)(void *)(irf->i);
340 } else { /* Need specific register for indirect calls. */
341 Reg r = ra_alloc1(as, func, RID2RSET(RID_CFUNCADDR));
342 MCode *p = as->mcp;
343 if (r == RID_CFUNCADDR)
344 *--p = MIPSI_NOP;
345 else
346 *--p = MIPSI_MOVE | MIPSF_D(RID_CFUNCADDR) | MIPSF_S(r);
347 *--p = MIPSI_JALR | MIPSF_S(r);
348 as->mcp = p;
349 ci.func = (ASMFunction)(void *)0;
350 }
351 asm_gencall(as, &ci, args);
352}
353
354static void asm_callid(ASMState *as, IRIns *ir, IRCallID id)
355{
356 const CCallInfo *ci = &lj_ir_callinfo[id];
357 IRRef args[2];
358 args[0] = ir->op1;
359 args[1] = ir->op2;
360 asm_setupresult(as, ir, ci);
361 asm_gencall(as, ci, args);
362}
363
364static void asm_callround(ASMState *as, IRIns *ir, IRCallID id)
365{
366 /* The modified regs must match with the *.dasc implementation. */
367 RegSet drop = RID2RSET(RID_R1)|RID2RSET(RID_R12)|RID2RSET(RID_F2)|
368 RID2RSET(RID_F4)|RID2RSET(RID_F12)|RID2RSET(RID_F14);
369 const CCallInfo *ci = &lj_ir_callinfo[id];
370 IRRef args[2];
371 args[0] = ir->op1;
372 args[1] = ir->op2;
373 ra_evictset(as, drop);
374 ra_destreg(as, ir, RID_FPRET);
375 asm_gencall(as, ci, args);
376}
377
378/* -- Returns ------------------------------------------------------------- */
379
380/* Return to lower frame. Guard that it goes to the right spot. */
381static void asm_retf(ASMState *as, IRIns *ir)
382{
383 Reg base = ra_alloc1(as, REF_BASE, RSET_GPR);
384 void *pc = ir_kptr(IR(ir->op2));
385 int32_t delta = 1+bc_a(*((const BCIns *)pc - 1));
386 as->topslot -= (BCReg)delta;
387 if ((int32_t)as->topslot < 0) as->topslot = 0;
388 emit_setgl(as, base, jit_base);
389 emit_addptr(as, base, -8*delta);
390 asm_guard(as, MIPSI_BNE, RID_TMP,
391 ra_allock(as, i32ptr(pc), rset_exclude(RSET_GPR, base)));
392 emit_tsi(as, MIPSI_LW, RID_TMP, base, -8);
393}
394
395/* -- Type conversions ---------------------------------------------------- */
396
397static void asm_tointg(ASMState *as, IRIns *ir, Reg left)
398{
399 Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left));
400 Reg dest = ra_dest(as, ir, RSET_GPR);
401 asm_guard(as, MIPSI_BC1F, 0, 0);
402 emit_fgh(as, MIPSI_C_EQ_D, 0, tmp, left);
403 emit_fg(as, MIPSI_CVT_D_W, tmp, tmp);
404 emit_tg(as, MIPSI_MFC1, dest, tmp);
405 emit_fg(as, MIPSI_CVT_W_D, tmp, left);
406}
407
408static void asm_tobit(ASMState *as, IRIns *ir)
409{
410 RegSet allow = RSET_FPR;
411 Reg dest = ra_dest(as, ir, RSET_GPR);
412 Reg left = ra_alloc1(as, ir->op1, allow);
413 Reg right = ra_alloc1(as, ir->op2, rset_clear(allow, left));
414 Reg tmp = ra_scratch(as, rset_clear(allow, right));
415 emit_tg(as, MIPSI_MFC1, dest, tmp);
416 emit_fgh(as, MIPSI_ADD_D, tmp, left, right);
417}
418
419static void asm_conv(ASMState *as, IRIns *ir)
420{
421 IRType st = (IRType)(ir->op2 & IRCONV_SRCMASK);
422 int stfp = (st == IRT_NUM || st == IRT_FLOAT);
423 IRRef lref = ir->op1;
424 lua_assert(irt_type(ir->t) != st);
425 lua_assert(!(irt_isint64(ir->t) ||
426 (st == IRT_I64 || st == IRT_U64))); /* Handled by SPLIT. */
427 if (irt_isfp(ir->t)) {
428 Reg dest = ra_dest(as, ir, RSET_FPR);
429 if (stfp) { /* FP to FP conversion. */
430 emit_fg(as, st == IRT_NUM ? MIPSI_CVT_S_D : MIPSI_CVT_D_S,
431 dest, ra_alloc1(as, lref, RSET_FPR));
432 } else if (st == IRT_U32) { /* U32 to FP conversion. */
433 /* y = (x ^ 0x8000000) + 2147483648.0 */
434 Reg left = ra_alloc1(as, lref, RSET_GPR);
435 Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, dest));
436 emit_fgh(as, irt_isfloat(ir->t) ? MIPSI_ADD_S : MIPSI_ADD_D,
437 dest, dest, tmp);
438 emit_fg(as, irt_isfloat(ir->t) ? MIPSI_CVT_S_W : MIPSI_CVT_D_W,
439 dest, dest);
440 if (irt_isfloat(ir->t))
441 emit_lsptr(as, MIPSI_LWC1, (tmp & 31),
442 (void *)lj_ir_k64_find(as->J, U64x(4f000000,4f000000)),
443 RSET_GPR);
444 else
445 emit_lsptr(as, MIPSI_LDC1, (tmp & 31),
446 (void *)lj_ir_k64_find(as->J, U64x(41e00000,00000000)),
447 RSET_GPR);
448 emit_tg(as, MIPSI_MTC1, RID_TMP, dest);
449 emit_dst(as, MIPSI_XOR, RID_TMP, RID_TMP, left);
450 emit_ti(as, MIPSI_LUI, RID_TMP, 0x8000);
451 } else { /* Integer to FP conversion. */
452 Reg left = ra_alloc1(as, lref, RSET_GPR);
453 emit_fg(as, irt_isfloat(ir->t) ? MIPSI_CVT_S_W : MIPSI_CVT_D_W,
454 dest, dest);
455 emit_tg(as, MIPSI_MTC1, left, dest);
456 }
457 } else if (stfp) { /* FP to integer conversion. */
458 if (irt_isguard(ir->t)) {
459 /* Checked conversions are only supported from number to int. */
460 lua_assert(irt_isint(ir->t) && st == IRT_NUM);
461 asm_tointg(as, ir, ra_alloc1(as, lref, RSET_FPR));
462 } else {
463 Reg dest = ra_dest(as, ir, RSET_GPR);
464 Reg left = ra_alloc1(as, lref, RSET_FPR);
465 Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left));
466 if (irt_isu32(ir->t)) {
467 /* y = (int)floor(x - 2147483648.0) ^ 0x80000000 */
468 emit_dst(as, MIPSI_XOR, dest, dest, RID_TMP);
469 emit_ti(as, MIPSI_LUI, RID_TMP, 0x8000);
470 emit_tg(as, MIPSI_MFC1, dest, tmp);
471 emit_fg(as, st == IRT_FLOAT ? MIPSI_FLOOR_W_S : MIPSI_FLOOR_W_D,
472 tmp, tmp);
473 emit_fgh(as, st == IRT_FLOAT ? MIPSI_SUB_S : MIPSI_SUB_D,
474 tmp, left, tmp);
475 if (st == IRT_FLOAT)
476 emit_lsptr(as, MIPSI_LWC1, (tmp & 31),
477 (void *)lj_ir_k64_find(as->J, U64x(4f000000,4f000000)),
478 RSET_GPR);
479 else
480 emit_lsptr(as, MIPSI_LDC1, (tmp & 31),
481 (void *)lj_ir_k64_find(as->J, U64x(41e00000,00000000)),
482 RSET_GPR);
483 } else {
484 emit_tg(as, MIPSI_MFC1, dest, tmp);
485 emit_fg(as, st == IRT_FLOAT ? MIPSI_TRUNC_W_S : MIPSI_TRUNC_W_D,
486 tmp, left);
487 }
488 }
489 } else {
490 Reg dest = ra_dest(as, ir, RSET_GPR);
491 if (st >= IRT_I8 && st <= IRT_U16) { /* Extend to 32 bit integer. */
492 Reg left = ra_alloc1(as, ir->op1, RSET_GPR);
493 lua_assert(irt_isint(ir->t) || irt_isu32(ir->t));
494 if ((ir->op2 & IRCONV_SEXT)) {
495 if ((as->flags & JIT_F_MIPS32R2)) {
496 emit_dst(as, st == IRT_I8 ? MIPSI_SEB : MIPSI_SEH, dest, 0, left);
497 } else {
498 uint32_t shift = st == IRT_I8 ? 24 : 16;
499 emit_dta(as, MIPSI_SRA, dest, dest, shift);
500 emit_dta(as, MIPSI_SLL, dest, left, shift);
501 }
502 } else {
503 emit_tsi(as, MIPSI_ANDI, dest, left,
504 (int32_t)(st == IRT_U8 ? 0xff : 0xffff));
505 }
506 } else { /* 32/64 bit integer conversions. */
507 /* Only need to handle 32/32 bit no-op (cast) on 32 bit archs. */
508 ra_leftov(as, dest, lref); /* Do nothing, but may need to move regs. */
509 }
510 }
511}
512
513#if LJ_HASFFI
514static void asm_conv64(ASMState *as, IRIns *ir)
515{
516 IRType st = (IRType)((ir-1)->op2 & IRCONV_SRCMASK);
517 IRType dt = (((ir-1)->op2 & IRCONV_DSTMASK) >> IRCONV_DSH);
518 IRCallID id;
519 const CCallInfo *ci;
520 IRRef args[2];
521 args[LJ_BE?0:1] = ir->op1;
522 args[LJ_BE?1:0] = (ir-1)->op1;
523 if (st == IRT_NUM || st == IRT_FLOAT) {
524 id = IRCALL_fp64_d2l + ((st == IRT_FLOAT) ? 2 : 0) + (dt - IRT_I64);
525 ir--;
526 } else {
527 id = IRCALL_fp64_l2d + ((dt == IRT_FLOAT) ? 2 : 0) + (st - IRT_I64);
528 }
529 ci = &lj_ir_callinfo[id];
530 asm_setupresult(as, ir, ci);
531 asm_gencall(as, ci, args);
532}
533#endif
534
535static void asm_strto(ASMState *as, IRIns *ir)
536{
537 const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_str_tonum];
538 IRRef args[2];
539 RegSet drop = RSET_SCRATCH;
540 if (ra_hasreg(ir->r)) rset_set(drop, ir->r); /* Spill dest reg (if any). */
541 ra_evictset(as, drop);
542 asm_guard(as, MIPSI_BEQ, RID_RET, RID_ZERO); /* Test return status. */
543 args[0] = ir->op1; /* GCstr *str */
544 args[1] = ASMREF_TMP1; /* TValue *n */
545 asm_gencall(as, ci, args);
546 /* Store the result to the spill slot or temp slots. */
547 emit_tsi(as, MIPSI_ADDIU, ra_releasetmp(as, ASMREF_TMP1),
548 RID_SP, sps_scale(ir->s));
549}
550
551/* Get pointer to TValue. */
552static void asm_tvptr(ASMState *as, Reg dest, IRRef ref)
553{
554 IRIns *ir = IR(ref);
555 if (irt_isnum(ir->t)) {
556 if (irref_isk(ref)) /* Use the number constant itself as a TValue. */
557 ra_allockreg(as, i32ptr(ir_knum(ir)), dest);
558 else /* Otherwise force a spill and use the spill slot. */
559 emit_tsi(as, MIPSI_ADDIU, dest, RID_SP, ra_spill(as, ir));
560 } else {
561 /* Otherwise use g->tmptv to hold the TValue. */
562 RegSet allow = rset_exclude(RSET_GPR, dest);
563 Reg type;
564 emit_tsi(as, MIPSI_ADDIU, dest, RID_JGL, offsetof(global_State, tmptv)-32768);
565 if (!irt_ispri(ir->t)) {
566 Reg src = ra_alloc1(as, ref, allow);
567 emit_setgl(as, src, tmptv.gcr);
568 }
569 type = ra_allock(as, irt_toitype(ir->t), allow);
570 emit_setgl(as, type, tmptv.it);
571 }
572}
573
574static void asm_tostr(ASMState *as, IRIns *ir)
575{
576 IRRef args[2];
577 args[0] = ASMREF_L;
578 as->gcsteps++;
579 if (irt_isnum(IR(ir->op1)->t) || (ir+1)->o == IR_HIOP) {
580 const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_str_fromnum];
581 args[1] = ASMREF_TMP1; /* const lua_Number * */
582 asm_setupresult(as, ir, ci); /* GCstr * */
583 asm_gencall(as, ci, args);
584 asm_tvptr(as, ra_releasetmp(as, ASMREF_TMP1), ir->op1);
585 } else {
586 const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_str_fromint];
587 args[1] = ir->op1; /* int32_t k */
588 asm_setupresult(as, ir, ci); /* GCstr * */
589 asm_gencall(as, ci, args);
590 }
591}
592
593/* -- Memory references --------------------------------------------------- */
594
595static void asm_aref(ASMState *as, IRIns *ir)
596{
597 Reg dest = ra_dest(as, ir, RSET_GPR);
598 Reg idx, base;
599 if (irref_isk(ir->op2)) {
600 IRRef tab = IR(ir->op1)->op1;
601 int32_t ofs = asm_fuseabase(as, tab);
602 IRRef refa = ofs ? tab : ir->op1;
603 ofs += 8*IR(ir->op2)->i;
604 if (checki16(ofs)) {
605 base = ra_alloc1(as, refa, RSET_GPR);
606 emit_tsi(as, MIPSI_ADDIU, dest, base, ofs);
607 return;
608 }
609 }
610 base = ra_alloc1(as, ir->op1, RSET_GPR);
611 idx = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, base));
612 emit_dst(as, MIPSI_ADDU, dest, RID_TMP, base);
613 emit_dta(as, MIPSI_SLL, RID_TMP, idx, 3);
614}
615
616/* Inlined hash lookup. Specialized for key type and for const keys.
617** The equivalent C code is:
618** Node *n = hashkey(t, key);
619** do {
620** if (lj_obj_equal(&n->key, key)) return &n->val;
621** } while ((n = nextnode(n)));
622** return niltv(L);
623*/
624static void asm_href(ASMState *as, IRIns *ir)
625{
626 RegSet allow = RSET_GPR;
627 int destused = ra_used(ir);
628 Reg dest = ra_dest(as, ir, allow);
629 Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest));
630 Reg key = RID_NONE, type = RID_NONE, tmpnum = RID_NONE, tmp1 = RID_TMP, tmp2;
631 IRRef refkey = ir->op2;
632 IRIns *irkey = IR(refkey);
633 IRType1 kt = irkey->t;
634 uint32_t khash;
635 MCLabel l_end, l_loop, l_next;
636
637 rset_clear(allow, tab);
638 if (irt_isnum(kt)) {
639 key = ra_alloc1(as, refkey, RSET_FPR);
640 tmpnum = ra_scratch(as, rset_exclude(RSET_FPR, key));
641 } else if (!irt_ispri(kt)) {
642 key = ra_alloc1(as, refkey, allow);
643 rset_clear(allow, key);
644 type = ra_allock(as, irt_toitype(irkey->t), allow);
645 rset_clear(allow, type);
646 }
647 tmp2 = ra_scratch(as, allow);
648 rset_clear(allow, tmp2);
649
650 /* Key not found in chain: load niltv. */
651 l_end = emit_label(as);
652 if (destused)
653 emit_loada(as, dest, niltvg(J2G(as->J)));
654 else
655 *--as->mcp = MIPSI_NOP;
656 /* Follow hash chain until the end. */
657 emit_move(as, dest, tmp1);
658 l_loop = --as->mcp;
659 emit_tsi(as, MIPSI_LW, tmp1, dest, (int32_t)offsetof(Node, next));
660 l_next = emit_label(as);
661
662 /* Type and value comparison. */
663 if (irt_isnum(kt)) {
664 emit_branch(as, MIPSI_BC1T, 0, 0, l_end);
665 emit_fgh(as, MIPSI_C_EQ_D, 0, tmpnum, key);
666 emit_tg(as, MIPSI_MFC1, tmp1, key+1);
667 emit_branch(as, MIPSI_BEQ, tmp1, RID_ZERO, l_next);
668 emit_tsi(as, MIPSI_SLTIU, tmp1, tmp1, (int32_t)LJ_TISNUM);
669 emit_hsi(as, MIPSI_LDC1, tmpnum, dest, (int32_t)offsetof(Node, key.n));
670 } else {
671 if (irt_ispri(kt)) {
672 emit_branch(as, MIPSI_BEQ, tmp1, type, l_end);
673 } else {
674 emit_branch(as, MIPSI_BEQ, tmp2, key, l_end);
675 emit_tsi(as, MIPSI_LW, tmp2, dest, (int32_t)offsetof(Node, key.gcr));
676 emit_branch(as, MIPSI_BNE, tmp1, type, l_next);
677 }
678 }
679 emit_tsi(as, MIPSI_LW, tmp1, dest, (int32_t)offsetof(Node, key.it));
680 *l_loop = MIPSI_BNE | MIPSF_S(tmp1) | ((as->mcp-l_loop-1) & 0xffffu);
681
682 /* Load main position relative to tab->node into dest. */
683 khash = irref_isk(refkey) ? ir_khash(irkey) : 1;
684 if (khash == 0) {
685 emit_tsi(as, MIPSI_LW, dest, tab, (int32_t)offsetof(GCtab, node));
686 } else {
687 Reg tmphash = tmp1;
688 if (irref_isk(refkey))
689 tmphash = ra_allock(as, khash, allow);
690 emit_dst(as, MIPSI_ADDU, dest, dest, tmp1);
691 lua_assert(sizeof(Node) == 24);
692 emit_dst(as, MIPSI_SUBU, tmp1, tmp2, tmp1);
693 emit_dta(as, MIPSI_SLL, tmp1, tmp1, 3);
694 emit_dta(as, MIPSI_SLL, tmp2, tmp1, 5);
695 emit_dst(as, MIPSI_AND, tmp1, tmp2, tmphash);
696 emit_tsi(as, MIPSI_LW, dest, tab, (int32_t)offsetof(GCtab, node));
697 emit_tsi(as, MIPSI_LW, tmp2, tab, (int32_t)offsetof(GCtab, hmask));
698 if (irref_isk(refkey)) {
699 /* Nothing to do. */
700 } else if (irt_isstr(kt)) {
701 emit_tsi(as, MIPSI_LW, tmp1, key, (int32_t)offsetof(GCstr, hash));
702 } else { /* Must match with hash*() in lj_tab.c. */
703 emit_dst(as, MIPSI_SUBU, tmp1, tmp1, tmp2);
704 emit_rotr(as, tmp2, tmp2, dest, (-HASH_ROT3)&31);
705 emit_dst(as, MIPSI_XOR, tmp1, tmp1, tmp2);
706 emit_rotr(as, tmp1, tmp1, dest, (-HASH_ROT2-HASH_ROT1)&31);
707 emit_dst(as, MIPSI_SUBU, tmp2, tmp2, dest);
708 if (irt_isnum(kt)) {
709 emit_dst(as, MIPSI_XOR, tmp2, tmp2, tmp1);
710 if ((as->flags & JIT_F_MIPS32R2)) {
711 emit_dta(as, MIPSI_ROTR, dest, tmp1, (-HASH_ROT1)&31);
712 } else {
713 emit_dst(as, MIPSI_OR, dest, dest, tmp1);
714 emit_dta(as, MIPSI_SLL, tmp1, tmp1, HASH_ROT1);
715 emit_dta(as, MIPSI_SRL, dest, tmp1, (-HASH_ROT1)&31);
716 }
717 emit_dst(as, MIPSI_ADDU, tmp1, tmp1, tmp1);
718 emit_tg(as, MIPSI_MFC1, tmp2, key);
719 emit_tg(as, MIPSI_MFC1, tmp1, key+1);
720 } else {
721 emit_dst(as, MIPSI_XOR, tmp2, key, tmp1);
722 emit_rotr(as, dest, tmp1, tmp2, (-HASH_ROT1)&31);
723 emit_dst(as, MIPSI_ADDU, tmp1, key, ra_allock(as, HASH_BIAS, allow));
724 }
725 }
726 }
727}
728
729static void asm_hrefk(ASMState *as, IRIns *ir)
730{
731 IRIns *kslot = IR(ir->op2);
732 IRIns *irkey = IR(kslot->op1);
733 int32_t ofs = (int32_t)(kslot->op2 * sizeof(Node));
734 int32_t kofs = ofs + (int32_t)offsetof(Node, key);
735 Reg dest = (ra_used(ir)||ofs > 32736) ? ra_dest(as, ir, RSET_GPR) : RID_NONE;
736 Reg node = ra_alloc1(as, ir->op1, RSET_GPR);
737 Reg key = RID_NONE, type = RID_TMP, idx = node;
738 RegSet allow = rset_exclude(RSET_GPR, node);
739 int32_t lo, hi;
740 lua_assert(ofs % sizeof(Node) == 0);
741 if (ofs > 32736) {
742 idx = dest;
743 rset_clear(allow, dest);
744 kofs = (int32_t)offsetof(Node, key);
745 } else if (ra_hasreg(dest)) {
746 emit_tsi(as, MIPSI_ADDIU, dest, node, ofs);
747 }
748 if (!irt_ispri(irkey->t)) {
749 key = ra_scratch(as, allow);
750 rset_clear(allow, key);
751 }
752 if (irt_isnum(irkey->t)) {
753 lo = (int32_t)ir_knum(irkey)->u32.lo;
754 hi = (int32_t)ir_knum(irkey)->u32.hi;
755 } else {
756 lo = irkey->i;
757 hi = irt_toitype(irkey->t);
758 if (!ra_hasreg(key))
759 goto nolo;
760 }
761 asm_guard(as, MIPSI_BNE, key, lo ? ra_allock(as, lo, allow) : RID_ZERO);
762nolo:
763 asm_guard(as, MIPSI_BNE, type, hi ? ra_allock(as, hi, allow) : RID_ZERO);
764 if (ra_hasreg(key)) emit_tsi(as, MIPSI_LW, key, idx, kofs+(LJ_BE?4:0));
765 emit_tsi(as, MIPSI_LW, type, idx, kofs+(LJ_BE?0:4));
766 if (ofs > 32736)
767 emit_tsi(as, MIPSI_ADDU, dest, node, ra_allock(as, ofs, allow));
768}
769
770static void asm_newref(ASMState *as, IRIns *ir)
771{
772 const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_tab_newkey];
773 IRRef args[3];
774 args[0] = ASMREF_L; /* lua_State *L */
775 args[1] = ir->op1; /* GCtab *t */
776 args[2] = ASMREF_TMP1; /* cTValue *key */
777 asm_setupresult(as, ir, ci); /* TValue * */
778 asm_gencall(as, ci, args);
779 asm_tvptr(as, ra_releasetmp(as, ASMREF_TMP1), ir->op2);
780}
781
782static void asm_uref(ASMState *as, IRIns *ir)
783{
784 /* NYI: Check that UREFO is still open and not aliasing a slot. */
785 Reg dest = ra_dest(as, ir, RSET_GPR);
786 if (irref_isk(ir->op1)) {
787 GCfunc *fn = ir_kfunc(IR(ir->op1));
788 MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v;
789 emit_lsptr(as, MIPSI_LW, dest, v, RSET_GPR);
790 } else {
791 Reg uv = ra_scratch(as, RSET_GPR);
792 Reg func = ra_alloc1(as, ir->op1, RSET_GPR);
793 if (ir->o == IR_UREFC) {
794 asm_guard(as, MIPSI_BEQ, RID_TMP, RID_ZERO);
795 emit_tsi(as, MIPSI_ADDIU, dest, uv, (int32_t)offsetof(GCupval, tv));
796 emit_tsi(as, MIPSI_LBU, RID_TMP, uv, (int32_t)offsetof(GCupval, closed));
797 } else {
798 emit_tsi(as, MIPSI_LW, dest, uv, (int32_t)offsetof(GCupval, v));
799 }
800 emit_tsi(as, MIPSI_LW, uv, func,
801 (int32_t)offsetof(GCfuncL, uvptr) + 4*(int32_t)(ir->op2 >> 8));
802 }
803}
804
805static void asm_fref(ASMState *as, IRIns *ir)
806{
807 UNUSED(as); UNUSED(ir);
808 lua_assert(!ra_used(ir));
809}
810
811static void asm_strref(ASMState *as, IRIns *ir)
812{
813 Reg dest = ra_dest(as, ir, RSET_GPR);
814 IRRef ref = ir->op2, refk = ir->op1;
815 int32_t ofs = (int32_t)sizeof(GCstr);
816 Reg r;
817 if (irref_isk(ref)) {
818 IRRef tmp = refk; refk = ref; ref = tmp;
819 } else if (!irref_isk(refk)) {
820 Reg right, left = ra_alloc1(as, ir->op1, RSET_GPR);
821 IRIns *irr = IR(ir->op2);
822 if (ra_hasreg(irr->r)) {
823 ra_noweak(as, irr->r);
824 right = irr->r;
825 } else if (mayfuse(as, irr->op2) &&
826 irr->o == IR_ADD && irref_isk(irr->op2) &&
827 checki16(ofs + IR(irr->op2)->i)) {
828 ofs += IR(irr->op2)->i;
829 right = ra_alloc1(as, irr->op1, rset_exclude(RSET_GPR, left));
830 } else {
831 right = ra_allocref(as, ir->op2, rset_exclude(RSET_GPR, left));
832 }
833 emit_tsi(as, MIPSI_ADDIU, dest, dest, ofs);
834 emit_dst(as, MIPSI_ADDU, dest, left, right);
835 return;
836 }
837 r = ra_alloc1(as, ref, RSET_GPR);
838 ofs += IR(refk)->i;
839 if (checki16(ofs))
840 emit_tsi(as, MIPSI_ADDIU, dest, r, ofs);
841 else
842 emit_dst(as, MIPSI_ADDU, dest, r,
843 ra_allock(as, ofs, rset_exclude(RSET_GPR, r)));
844}
845
846/* -- Loads and stores ---------------------------------------------------- */
847
848static MIPSIns asm_fxloadins(IRIns *ir)
849{
850 switch (irt_type(ir->t)) {
851 case IRT_I8: return MIPSI_LB;
852 case IRT_U8: return MIPSI_LBU;
853 case IRT_I16: return MIPSI_LH;
854 case IRT_U16: return MIPSI_LHU;
855 case IRT_NUM: return MIPSI_LDC1;
856 case IRT_FLOAT: return MIPSI_LWC1;
857 default: return MIPSI_LW;
858 }
859}
860
861static MIPSIns asm_fxstoreins(IRIns *ir)
862{
863 switch (irt_type(ir->t)) {
864 case IRT_I8: case IRT_U8: return MIPSI_SB;
865 case IRT_I16: case IRT_U16: return MIPSI_SH;
866 case IRT_NUM: return MIPSI_SDC1;
867 case IRT_FLOAT: return MIPSI_SWC1;
868 default: return MIPSI_SW;
869 }
870}
871
872static void asm_fload(ASMState *as, IRIns *ir)
873{
874 Reg dest = ra_dest(as, ir, RSET_GPR);
875 Reg idx = ra_alloc1(as, ir->op1, RSET_GPR);
876 MIPSIns mi = asm_fxloadins(ir);
877 int32_t ofs;
878 if (ir->op2 == IRFL_TAB_ARRAY) {
879 ofs = asm_fuseabase(as, ir->op1);
880 if (ofs) { /* Turn the t->array load into an add for colocated arrays. */
881 emit_tsi(as, MIPSI_ADDIU, dest, idx, ofs);
882 return;
883 }
884 }
885 ofs = field_ofs[ir->op2];
886 lua_assert(!irt_isfp(ir->t));
887 emit_tsi(as, mi, dest, idx, ofs);
888}
889
890static void asm_fstore(ASMState *as, IRIns *ir)
891{
892 Reg src = ra_alloc1z(as, ir->op2, RSET_GPR);
893 IRIns *irf = IR(ir->op1);
894 Reg idx = ra_alloc1(as, irf->op1, rset_exclude(RSET_GPR, src));
895 int32_t ofs = field_ofs[irf->op2];
896 MIPSIns mi = asm_fxstoreins(ir);
897 lua_assert(!irt_isfp(ir->t));
898 emit_tsi(as, mi, src, idx, ofs);
899}
900
901static void asm_xload(ASMState *as, IRIns *ir)
902{
903 Reg dest = ra_dest(as, ir, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR);
904 lua_assert(!(ir->op2 & IRXLOAD_UNALIGNED));
905 asm_fusexref(as, asm_fxloadins(ir), dest, ir->op1, RSET_GPR);
906}
907
908static void asm_xstore(ASMState *as, IRIns *ir)
909{
910 Reg src = ra_alloc1z(as, ir->op2, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR);
911 asm_fusexref(as, asm_fxstoreins(ir), src, ir->op1,
912 rset_exclude(RSET_GPR, src));
913}
914
915static void asm_ahuvload(ASMState *as, IRIns *ir)
916{
917 IRType1 t = ir->t;
918 Reg dest = RID_NONE, type = RID_TMP, idx;
919 RegSet allow = RSET_GPR;
920 int32_t ofs = 0;
921 if (ra_used(ir)) {
922 lua_assert(irt_isnum(t) || irt_isint(t) || irt_isaddr(t));
923 dest = ra_dest(as, ir, irt_isnum(t) ? RSET_FPR : RSET_GPR);
924 rset_clear(allow, dest);
925 }
926 idx = asm_fuseahuref(as, ir->op1, &ofs, allow);
927 rset_clear(allow, idx);
928 if (irt_isnum(t)) {
929 asm_guard(as, MIPSI_BEQ, type, RID_ZERO);
930 emit_tsi(as, MIPSI_SLTIU, type, type, (int32_t)LJ_TISNUM);
931 if (ra_hasreg(dest))
932 emit_hsi(as, MIPSI_LDC1, dest, idx, ofs);
933 } else {
934 asm_guard(as, MIPSI_BNE, type, ra_allock(as, irt_toitype(t), allow));
935 if (ra_hasreg(dest)) emit_tsi(as, MIPSI_LW, dest, idx, ofs+(LJ_BE?4:0));
936 }
937 emit_tsi(as, MIPSI_LW, type, idx, ofs+(LJ_BE?0:4));
938}
939
940static void asm_ahustore(ASMState *as, IRIns *ir)
941{
942 RegSet allow = RSET_GPR;
943 Reg idx, src = RID_NONE, type = RID_NONE;
944 int32_t ofs = 0;
945 if (irt_isnum(ir->t)) {
946 src = ra_alloc1(as, ir->op2, RSET_FPR);
947 } else {
948 if (!irt_ispri(ir->t)) {
949 src = ra_alloc1(as, ir->op2, allow);
950 rset_clear(allow, src);
951 }
952 type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow);
953 rset_clear(allow, type);
954 }
955 idx = asm_fuseahuref(as, ir->op1, &ofs, allow);
956 if (irt_isnum(ir->t)) {
957 emit_hsi(as, MIPSI_SDC1, src, idx, ofs);
958 } else {
959 if (ra_hasreg(src))
960 emit_tsi(as, MIPSI_SW, src, idx, ofs+(LJ_BE?4:0));
961 emit_tsi(as, MIPSI_SW, type, idx, ofs+(LJ_BE?0:4));
962 }
963}
964
965static void asm_sload(ASMState *as, IRIns *ir)
966{
967 int32_t ofs = 8*((int32_t)ir->op1-1) + ((ir->op2 & IRSLOAD_FRAME) ? 4 : 0);
968 IRType1 t = ir->t;
969 Reg dest = RID_NONE, type = RID_NONE, base;
970 RegSet allow = RSET_GPR;
971 lua_assert(!(ir->op2 & IRSLOAD_PARENT)); /* Handled by asm_head_side(). */
972 lua_assert(irt_isguard(t) || !(ir->op2 & IRSLOAD_TYPECHECK));
973 lua_assert(!irt_isint(t) || (ir->op2 & (IRSLOAD_CONVERT|IRSLOAD_FRAME)));
974 if ((ir->op2 & IRSLOAD_CONVERT) && irt_isguard(t) && irt_isint(t)) {
975 dest = ra_scratch(as, RSET_FPR);
976 asm_tointg(as, ir, dest);
977 t.irt = IRT_NUM; /* Continue with a regular number type check. */
978 } else if (ra_used(ir)) {
979 lua_assert(irt_isnum(t) || irt_isint(t) || irt_isaddr(t));
980 dest = ra_dest(as, ir, irt_isnum(t) ? RSET_FPR : RSET_GPR);
981 rset_clear(allow, dest);
982 base = ra_alloc1(as, REF_BASE, allow);
983 rset_clear(allow, base);
984 if ((ir->op2 & IRSLOAD_CONVERT)) {
985 if (irt_isint(t)) {
986 Reg tmp = ra_scratch(as, RSET_FPR);
987 emit_tg(as, MIPSI_MFC1, dest, tmp);
988 emit_fg(as, MIPSI_CVT_W_D, tmp, tmp);
989 dest = tmp;
990 t.irt = IRT_NUM; /* Check for original type. */
991 } else {
992 Reg tmp = ra_scratch(as, RSET_GPR);
993 emit_fg(as, MIPSI_CVT_D_W, dest, dest);
994 emit_tg(as, MIPSI_MTC1, tmp, dest);
995 dest = tmp;
996 t.irt = IRT_INT; /* Check for original type. */
997 }
998 }
999 goto dotypecheck;
1000 }
1001 base = ra_alloc1(as, REF_BASE, allow);
1002 rset_clear(allow, base);
1003dotypecheck:
1004 if (irt_isnum(t)) {
1005 if ((ir->op2 & IRSLOAD_TYPECHECK)) {
1006 asm_guard(as, MIPSI_BEQ, RID_TMP, RID_ZERO);
1007 emit_tsi(as, MIPSI_SLTIU, RID_TMP, RID_TMP, (int32_t)LJ_TISNUM);
1008 type = RID_TMP;
1009 }
1010 if (ra_hasreg(dest)) emit_hsi(as, MIPSI_LDC1, dest, base, ofs);
1011 } else {
1012 if ((ir->op2 & IRSLOAD_TYPECHECK)) {
1013 Reg ktype = ra_allock(as, irt_toitype(t), allow);
1014 asm_guard(as, MIPSI_BNE, RID_TMP, ktype);
1015 type = RID_TMP;
1016 }
1017 if (ra_hasreg(dest)) emit_tsi(as, MIPSI_LW, dest, base, ofs ^ (LJ_BE?4:0));
1018 }
1019 if (ra_hasreg(type)) emit_tsi(as, MIPSI_LW, type, base, ofs ^ (LJ_BE?0:4));
1020}
1021
1022/* -- Allocations --------------------------------------------------------- */
1023
1024#if LJ_HASFFI
1025static void asm_cnew(ASMState *as, IRIns *ir)
1026{
1027 CTState *cts = ctype_ctsG(J2G(as->J));
1028 CTypeID typeid = (CTypeID)IR(ir->op1)->i;
1029 CTSize sz = (ir->o == IR_CNEWI || ir->op2 == REF_NIL) ?
1030 lj_ctype_size(cts, typeid) : (CTSize)IR(ir->op2)->i;
1031 const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco];
1032 IRRef args[2];
1033 RegSet allow = (RSET_GPR & ~RSET_SCRATCH);
1034 RegSet drop = RSET_SCRATCH;
1035 lua_assert(sz != CTSIZE_INVALID);
1036
1037 args[0] = ASMREF_L; /* lua_State *L */
1038 args[1] = ASMREF_TMP1; /* MSize size */
1039 as->gcsteps++;
1040
1041 if (ra_hasreg(ir->r))
1042 rset_clear(drop, ir->r); /* Dest reg handled below. */
1043 ra_evictset(as, drop);
1044 if (ra_used(ir))
1045 ra_destreg(as, ir, RID_RET); /* GCcdata * */
1046
1047 /* Initialize immutable cdata object. */
1048 if (ir->o == IR_CNEWI) {
1049 int32_t ofs = sizeof(GCcdata);
1050 lua_assert(sz == 4 || sz == 8);
1051 if (sz == 8) {
1052 ofs += 4;
1053 lua_assert((ir+1)->o == IR_HIOP);
1054 if (LJ_LE) ir++;
1055 }
1056 for (;;) {
1057 Reg r = ra_alloc1z(as, ir->op2, allow);
1058 emit_tsi(as, MIPSI_SW, r, RID_RET, ofs);
1059 rset_clear(allow, r);
1060 if (ofs == sizeof(GCcdata)) break;
1061 ofs -= 4; if (LJ_BE) ir++; else ir--;
1062 }
1063 }
1064 /* Initialize gct and typeid. lj_mem_newgco() already sets marked. */
1065 emit_tsi(as, MIPSI_SB, RID_RET+1, RID_RET, offsetof(GCcdata, gct));
1066 emit_tsi(as, MIPSI_SH, RID_TMP, RID_RET, offsetof(GCcdata, typeid));
1067 emit_ti(as, MIPSI_LI, RID_RET+1, ~LJ_TCDATA);
1068 emit_ti(as, MIPSI_LI, RID_TMP, typeid); /* Lower 16 bit used. Sign-ext ok. */
1069 asm_gencall(as, ci, args);
1070 ra_allockreg(as, (int32_t)(sz+sizeof(GCcdata)),
1071 ra_releasetmp(as, ASMREF_TMP1));
1072}
1073#else
1074#define asm_cnew(as, ir) ((void)0)
1075#endif
1076
1077/* -- Write barriers ------------------------------------------------------ */
1078
1079static void asm_tbar(ASMState *as, IRIns *ir)
1080{
1081 Reg tab = ra_alloc1(as, ir->op1, RSET_GPR);
1082 Reg mark = ra_scratch(as, rset_exclude(RSET_GPR, tab));
1083 Reg link = RID_TMP;
1084 MCLabel l_end = emit_label(as);
1085 emit_tsi(as, MIPSI_SW, link, tab, (int32_t)offsetof(GCtab, gclist));
1086 emit_tsi(as, MIPSI_SB, mark, tab, (int32_t)offsetof(GCtab, marked));
1087 emit_setgl(as, tab, gc.grayagain);
1088 emit_getgl(as, link, gc.grayagain);
1089 emit_dst(as, MIPSI_XOR, mark, mark, RID_TMP); /* Clear black bit. */
1090 emit_branch(as, MIPSI_BEQ, RID_TMP, RID_ZERO, l_end);
1091 emit_tsi(as, MIPSI_ANDI, RID_TMP, mark, LJ_GC_BLACK);
1092 emit_tsi(as, MIPSI_LBU, mark, tab, (int32_t)offsetof(GCtab, marked));
1093}
1094
1095static void asm_obar(ASMState *as, IRIns *ir)
1096{
1097 const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_barrieruv];
1098 IRRef args[2];
1099 MCLabel l_end;
1100 Reg obj, val, tmp;
1101 /* No need for other object barriers (yet). */
1102 lua_assert(IR(ir->op1)->o == IR_UREFC);
1103 ra_evictset(as, RSET_SCRATCH);
1104 l_end = emit_label(as);
1105 args[0] = ASMREF_TMP1; /* global_State *g */
1106 args[1] = ir->op1; /* TValue *tv */
1107 asm_gencall(as, ci, args);
1108 emit_tsi(as, MIPSI_ADDIU, ra_releasetmp(as, ASMREF_TMP1), RID_JGL, -32768);
1109 obj = IR(ir->op1)->r;
1110 tmp = ra_scratch(as, rset_exclude(RSET_GPR, obj));
1111 emit_branch(as, MIPSI_BEQ, RID_TMP, RID_ZERO, l_end);
1112 emit_tsi(as, MIPSI_ANDI, tmp, tmp, LJ_GC_BLACK);
1113 emit_branch(as, MIPSI_BEQ, RID_TMP, RID_ZERO, l_end);
1114 emit_tsi(as, MIPSI_ANDI, RID_TMP, RID_TMP, LJ_GC_WHITES);
1115 val = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, obj));
1116 emit_tsi(as, MIPSI_LBU, tmp, obj,
1117 (int32_t)offsetof(GCupval, marked)-(int32_t)offsetof(GCupval, tv));
1118 emit_tsi(as, MIPSI_LBU, RID_TMP, val, (int32_t)offsetof(GChead, marked));
1119}
1120
1121/* -- Arithmetic and logic operations ------------------------------------- */
1122
1123static void asm_fparith(ASMState *as, IRIns *ir, MIPSIns mi)
1124{
1125 Reg dest = ra_dest(as, ir, RSET_FPR);
1126 Reg right, left = ra_alloc2(as, ir, RSET_FPR);
1127 right = (left >> 8); left &= 255;
1128 emit_fgh(as, mi, dest, left, right);
1129}
1130
1131static void asm_fpunary(ASMState *as, IRIns *ir, MIPSIns mi)
1132{
1133 Reg dest = ra_dest(as, ir, RSET_FPR);
1134 Reg left = ra_hintalloc(as, ir->op1, dest, RSET_FPR);
1135 emit_fg(as, mi, dest, left);
1136}
1137
1138static int asm_fpjoin_pow(ASMState *as, IRIns *ir)
1139{
1140 IRIns *irp = IR(ir->op1);
1141 if (irp == ir-1 && irp->o == IR_MUL && !ra_used(irp)) {
1142 IRIns *irpp = IR(irp->op1);
1143 if (irpp == ir-2 && irpp->o == IR_FPMATH &&
1144 irpp->op2 == IRFPM_LOG2 && !ra_used(irpp)) {
1145 const CCallInfo *ci = &lj_ir_callinfo[IRCALL_pow];
1146 IRRef args[2];
1147 args[0] = irpp->op1;
1148 args[1] = irp->op2;
1149 asm_setupresult(as, ir, ci);
1150 asm_gencall(as, ci, args);
1151 return 1;
1152 }
1153 }
1154 return 0;
1155}
1156
1157static void asm_add(ASMState *as, IRIns *ir)
1158{
1159 if (irt_isnum(ir->t)) {
1160 asm_fparith(as, ir, MIPSI_ADD_D);
1161 } else {
1162 Reg dest = ra_dest(as, ir, RSET_GPR);
1163 Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR);
1164 if (irref_isk(ir->op2)) {
1165 int32_t k = IR(ir->op2)->i;
1166 if (checki16(k)) {
1167 emit_tsi(as, MIPSI_ADDIU, dest, left, k);
1168 return;
1169 }
1170 }
1171 right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left));
1172 emit_dst(as, MIPSI_ADDU, dest, left, right);
1173 }
1174}
1175
1176static void asm_sub(ASMState *as, IRIns *ir)
1177{
1178 if (irt_isnum(ir->t)) {
1179 asm_fparith(as, ir, MIPSI_SUB_D);
1180 } else {
1181 Reg dest = ra_dest(as, ir, RSET_GPR);
1182 Reg right, left = ra_alloc2(as, ir, RSET_GPR);
1183 right = (left >> 8); left &= 255;
1184 emit_dst(as, MIPSI_SUBU, dest, left, right);
1185 }
1186}
1187
1188static void asm_mul(ASMState *as, IRIns *ir)
1189{
1190 if (irt_isnum(ir->t)) {
1191 asm_fparith(as, ir, MIPSI_MUL_D);
1192 } else {
1193 Reg dest = ra_dest(as, ir, RSET_GPR);
1194 Reg right, left = ra_alloc2(as, ir, RSET_GPR);
1195 right = (left >> 8); left &= 255;
1196 emit_dst(as, MIPSI_MUL, dest, left, right);
1197 }
1198}
1199
1200static void asm_neg(ASMState *as, IRIns *ir)
1201{
1202 if (irt_isnum(ir->t)) {
1203 asm_fpunary(as, ir, MIPSI_NEG_D);
1204 } else {
1205 Reg dest = ra_dest(as, ir, RSET_GPR);
1206 Reg left = ra_hintalloc(as, ir->op1, dest, RSET_GPR);
1207 emit_dst(as, MIPSI_SUBU, dest, RID_ZERO, left);
1208 }
1209}
1210
1211static void asm_arithov(ASMState *as, IRIns *ir)
1212{
1213 Reg right, left, tmp, dest = ra_dest(as, ir, RSET_GPR);
1214 if (irref_isk(ir->op2)) {
1215 int k = IR(ir->op2)->i;
1216 if (ir->o == IR_SUBOV) k = -k;
1217 if (checki16(k)) { /* (dest < left) == (k >= 0 ? 1 : 0) */
1218 left = ra_alloc1(as, ir->op1, RSET_GPR);
1219 asm_guard(as, k >= 0 ? MIPSI_BNE : MIPSI_BEQ, RID_TMP, RID_ZERO);
1220 emit_dst(as, MIPSI_SLT, RID_TMP, dest, dest == left ? RID_TMP : left);
1221 emit_tsi(as, MIPSI_ADDIU, dest, left, k);
1222 if (dest == left) emit_move(as, RID_TMP, left);
1223 return;
1224 }
1225 }
1226 left = ra_alloc2(as, ir, RSET_GPR);
1227 right = (left >> 8); left &= 255;
1228 tmp = ra_scratch(as, rset_exclude(rset_exclude(rset_exclude(RSET_GPR, left),
1229 right), dest));
1230 asm_guard(as, MIPSI_BLTZ, RID_TMP, 0);
1231 emit_dst(as, MIPSI_AND, RID_TMP, RID_TMP, tmp);
1232 if (ir->o == IR_ADDOV) { /* ((dest^left) & (dest^right)) < 0 */
1233 emit_dst(as, MIPSI_XOR, RID_TMP, dest, dest == right ? RID_TMP : right);
1234 } else { /* ((dest^left) & (dest^~right)) < 0 */
1235 emit_dst(as, MIPSI_XOR, RID_TMP, RID_TMP, dest);
1236 emit_dst(as, MIPSI_NOR, RID_TMP, dest == right ? RID_TMP : right, RID_ZERO);
1237 }
1238 emit_dst(as, MIPSI_XOR, tmp, dest, dest == left ? RID_TMP : left);
1239 emit_dst(as, ir->o == IR_ADDOV ? MIPSI_ADDU : MIPSI_SUBU, dest, left, right);
1240 if (dest == left || dest == right)
1241 emit_move(as, RID_TMP, dest == left ? left : right);
1242}
1243
1244static void asm_mulov(ASMState *as, IRIns *ir)
1245{
1246#if LJ_DUALNUM
1247#error "NYI: MULOV"
1248#else
1249 UNUSED(as); UNUSED(ir); lua_assert(0); /* Unused in single-number mode. */
1250#endif
1251}
1252
1253#if LJ_HASFFI
1254static void asm_add64(ASMState *as, IRIns *ir)
1255{
1256 Reg dest = ra_dest(as, ir, RSET_GPR);
1257 Reg right, left = ra_alloc1(as, ir->op1, RSET_GPR);
1258 if (irref_isk(ir->op2)) {
1259 int32_t k = IR(ir->op2)->i;
1260 if (k == 0) {
1261 emit_dst(as, MIPSI_ADDU, dest, left, RID_TMP);
1262 goto loarith;
1263 } else if (checki16(k)) {
1264 emit_dst(as, MIPSI_ADDU, dest, dest, RID_TMP);
1265 emit_tsi(as, MIPSI_ADDIU, dest, left, k);
1266 goto loarith;
1267 }
1268 }
1269 emit_dst(as, MIPSI_ADDU, dest, dest, RID_TMP);
1270 right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left));
1271 emit_dst(as, MIPSI_ADDU, dest, left, right);
1272loarith:
1273 ir--;
1274 dest = ra_dest(as, ir, RSET_GPR);
1275 left = ra_alloc1(as, ir->op1, RSET_GPR);
1276 if (irref_isk(ir->op2)) {
1277 int32_t k = IR(ir->op2)->i;
1278 if (k == 0) {
1279 if (dest != left)
1280 emit_move(as, dest, left);
1281 return;
1282 } else if (checki16(k)) {
1283 if (dest == left) {
1284 Reg tmp = ra_scratch(as, rset_exclude(RSET_GPR, left));
1285 emit_move(as, dest, tmp);
1286 dest = tmp;
1287 }
1288 emit_dst(as, MIPSI_SLTU, RID_TMP, dest, left);
1289 emit_tsi(as, MIPSI_ADDIU, dest, left, k);
1290 return;
1291 }
1292 }
1293 right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left));
1294 if (dest == left && dest == right) {
1295 Reg tmp = ra_scratch(as, rset_exclude(rset_exclude(RSET_GPR, left), right));
1296 emit_move(as, dest, tmp);
1297 dest = tmp;
1298 }
1299 emit_dst(as, MIPSI_SLTU, RID_TMP, dest, dest == left ? right : left);
1300 emit_dst(as, MIPSI_ADDU, dest, left, right);
1301}
1302
1303static void asm_sub64(ASMState *as, IRIns *ir)
1304{
1305 Reg dest = ra_dest(as, ir, RSET_GPR);
1306 Reg right, left = ra_alloc2(as, ir, RSET_GPR);
1307 right = (left >> 8); left &= 255;
1308 emit_dst(as, MIPSI_SUBU, dest, dest, RID_TMP);
1309 emit_dst(as, MIPSI_SUBU, dest, left, right);
1310 ir--;
1311 dest = ra_dest(as, ir, RSET_GPR);
1312 left = ra_alloc2(as, ir, RSET_GPR);
1313 right = (left >> 8); left &= 255;
1314 if (dest == left) {
1315 Reg tmp = ra_scratch(as, rset_exclude(rset_exclude(RSET_GPR, left), right));
1316 emit_move(as, dest, tmp);
1317 dest = tmp;
1318 }
1319 emit_dst(as, MIPSI_SLTU, RID_TMP, left, dest);
1320 emit_dst(as, MIPSI_SUBU, dest, left, right);
1321}
1322
1323static void asm_neg64(ASMState *as, IRIns *ir)
1324{
1325 Reg dest = ra_dest(as, ir, RSET_GPR);
1326 Reg left = ra_alloc1(as, ir->op1, RSET_GPR);
1327 emit_dst(as, MIPSI_SUBU, dest, dest, RID_TMP);
1328 emit_dst(as, MIPSI_SUBU, dest, RID_ZERO, left);
1329 ir--;
1330 dest = ra_dest(as, ir, RSET_GPR);
1331 left = ra_alloc1(as, ir->op1, RSET_GPR);
1332 emit_dst(as, MIPSI_SLTU, RID_TMP, RID_ZERO, dest);
1333 emit_dst(as, MIPSI_SUBU, dest, RID_ZERO, left);
1334}
1335#endif
1336
1337static void asm_bitnot(ASMState *as, IRIns *ir)
1338{
1339 Reg left, right, dest = ra_dest(as, ir, RSET_GPR);
1340 IRIns *irl = IR(ir->op1);
1341 if (mayfuse(as, ir->op1) && irl->o == IR_BOR) {
1342 left = ra_alloc2(as, irl, RSET_GPR);
1343 right = (left >> 8); left &= 255;
1344 } else {
1345 left = ra_hintalloc(as, ir->op1, dest, RSET_GPR);
1346 right = RID_ZERO;
1347 }
1348 emit_dst(as, MIPSI_NOR, dest, left, right);
1349}
1350
1351static void asm_bitswap(ASMState *as, IRIns *ir)
1352{
1353 Reg dest = ra_dest(as, ir, RSET_GPR);
1354 Reg left = ra_alloc1(as, ir->op1, RSET_GPR);
1355 if ((as->flags & JIT_F_MIPS32R2)) {
1356 emit_dta(as, MIPSI_ROTR, dest, RID_TMP, 16);
1357 emit_dst(as, MIPSI_WSBH, RID_TMP, 0, left);
1358 } else {
1359 Reg tmp = ra_scratch(as, rset_exclude(rset_exclude(RSET_GPR, left), dest));
1360 emit_dst(as, MIPSI_OR, dest, dest, tmp);
1361 emit_dst(as, MIPSI_OR, dest, dest, RID_TMP);
1362 emit_tsi(as, MIPSI_ANDI, dest, dest, 0xff00);
1363 emit_dta(as, MIPSI_SLL, RID_TMP, RID_TMP, 8);
1364 emit_dta(as, MIPSI_SRL, dest, left, 8);
1365 emit_tsi(as, MIPSI_ANDI, RID_TMP, left, 0xff00);
1366 emit_dst(as, MIPSI_OR, tmp, tmp, RID_TMP);
1367 emit_dta(as, MIPSI_SRL, tmp, left, 24);
1368 emit_dta(as, MIPSI_SLL, RID_TMP, left, 24);
1369 }
1370}
1371
1372static void asm_bitop(ASMState *as, IRIns *ir, MIPSIns mi, MIPSIns mik)
1373{
1374 Reg dest = ra_dest(as, ir, RSET_GPR);
1375 Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR);
1376 if (irref_isk(ir->op2)) {
1377 int32_t k = IR(ir->op2)->i;
1378 if (checku16(k)) {
1379 emit_tsi(as, mik, dest, left, k);
1380 return;
1381 }
1382 }
1383 right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left));
1384 emit_dst(as, mi, dest, left, right);
1385}
1386
1387static void asm_bitshift(ASMState *as, IRIns *ir, MIPSIns mi, MIPSIns mik)
1388{
1389 Reg dest = ra_dest(as, ir, RSET_GPR);
1390 if (irref_isk(ir->op2)) { /* Constant shifts. */
1391 uint32_t shift = (uint32_t)(IR(ir->op2)->i & 31);
1392 emit_dta(as, mik, dest, ra_hintalloc(as, ir->op1, dest, RSET_GPR), shift);
1393 } else {
1394 Reg right, left = ra_alloc2(as, ir, RSET_GPR);
1395 right = (left >> 8); left &= 255;
1396 emit_dst(as, mi, dest, right, left); /* Shift amount is in rs. */
1397 }
1398}
1399
1400static void asm_bitror(ASMState *as, IRIns *ir)
1401{
1402 if ((as->flags & JIT_F_MIPS32R2)) {
1403 asm_bitshift(as, ir, MIPSI_ROTRV, MIPSI_ROTR);
1404 } else {
1405 Reg dest = ra_dest(as, ir, RSET_GPR);
1406 if (irref_isk(ir->op2)) { /* Constant shifts. */
1407 uint32_t shift = (uint32_t)(IR(ir->op2)->i & 31);
1408 Reg left = ra_hintalloc(as, ir->op1, dest, RSET_GPR);
1409 emit_rotr(as, dest, left, RID_TMP, shift);
1410 } else {
1411 Reg right, left = ra_alloc2(as, ir, RSET_GPR);
1412 right = (left >> 8); left &= 255;
1413 emit_dst(as, MIPSI_OR, dest, dest, RID_TMP);
1414 emit_dst(as, MIPSI_SRLV, dest, right, left);
1415 emit_dst(as, MIPSI_SLLV, RID_TMP, RID_TMP, left);
1416 emit_dst(as, MIPSI_SUBU, RID_TMP, ra_allock(as, 32, RSET_GPR), right);
1417 }
1418 }
1419}
1420
1421static void asm_min_max(ASMState *as, IRIns *ir, int ismax)
1422{
1423 if (irt_isnum(ir->t)) {
1424 Reg dest = ra_dest(as, ir, RSET_FPR);
1425 Reg right, left = ra_alloc2(as, ir, RSET_FPR);
1426 right = (left >> 8); left &= 255;
1427 if (dest == left) {
1428 emit_fg(as, MIPSI_MOVT_D, dest, right);
1429 } else {
1430 emit_fg(as, MIPSI_MOVF_D, dest, left);
1431 if (dest != right) emit_fg(as, MIPSI_MOV_D, dest, right);
1432 }
1433 emit_fgh(as, MIPSI_C_OLT_D, 0, ismax ? left : right, ismax ? right : left);
1434 } else {
1435 Reg dest = ra_dest(as, ir, RSET_GPR);
1436 Reg right, left = ra_alloc2(as, ir, RSET_GPR);
1437 right = (left >> 8); left &= 255;
1438 if (dest == left) {
1439 emit_dst(as, MIPSI_MOVN, dest, right, RID_TMP);
1440 } else {
1441 emit_dst(as, MIPSI_MOVZ, dest, left, RID_TMP);
1442 if (dest != right) emit_move(as, dest, right);
1443 }
1444 emit_dst(as, MIPSI_SLT, RID_TMP,
1445 ismax ? left : right, ismax ? right : left);
1446 }
1447}
1448
1449/* -- Comparisons --------------------------------------------------------- */
1450
1451static void asm_comp(ASMState *as, IRIns *ir)
1452{
1453 /* ORDER IR: LT GE LE GT ULT UGE ULE UGT. */
1454 IROp op = ir->o;
1455 if (irt_isnum(ir->t)) {
1456 Reg right, left = ra_alloc2(as, ir, RSET_FPR);
1457 right = (left >> 8); left &= 255;
1458 asm_guard(as, (op&1) ? MIPSI_BC1T : MIPSI_BC1F, 0, 0);
1459 emit_fgh(as, MIPSI_C_OLT_D + ((op&3) ^ ((op>>2)&1)), 0, left, right);
1460 } else {
1461 Reg right, left = ra_alloc1(as, ir->op1, RSET_GPR);
1462 if (op == IR_ABC) op = IR_UGT;
1463 if ((op&4) == 0 && irref_isk(ir->op2) && IR(ir->op2)->i == 0) {
1464 MIPSIns mi = (op&2) ? ((op&1) ? MIPSI_BLEZ : MIPSI_BGTZ) :
1465 ((op&1) ? MIPSI_BLTZ : MIPSI_BGEZ);
1466 asm_guard(as, mi, left, 0);
1467 } else {
1468 if (irref_isk(ir->op2)) {
1469 int32_t k = IR(ir->op2)->i;
1470 if ((op&2)) k++;
1471 if (checki16(k)) {
1472 asm_guard(as, (op&1) ? MIPSI_BNE : MIPSI_BEQ, RID_TMP, RID_ZERO);
1473 emit_tsi(as, (op&4) ? MIPSI_SLTIU : MIPSI_SLTI,
1474 RID_TMP, left, k);
1475 return;
1476 }
1477 }
1478 right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left));
1479 asm_guard(as, ((op^(op>>1))&1) ? MIPSI_BNE : MIPSI_BEQ, RID_TMP, RID_ZERO);
1480 emit_dst(as, (op&4) ? MIPSI_SLTU : MIPSI_SLT,
1481 RID_TMP, (op&2) ? right : left, (op&2) ? left : right);
1482 }
1483 }
1484}
1485
1486static void asm_compeq(ASMState *as, IRIns *ir)
1487{
1488 Reg right, left = ra_alloc2(as, ir, irt_isnum(ir->t) ? RSET_FPR : RSET_GPR);
1489 right = (left >> 8); left &= 255;
1490 if (irt_isnum(ir->t)) {
1491 asm_guard(as, (ir->o & 1) ? MIPSI_BC1T : MIPSI_BC1F, 0, 0);
1492 emit_fgh(as, MIPSI_C_EQ_D, 0, left, right);
1493 } else {
1494 asm_guard(as, (ir->o & 1) ? MIPSI_BEQ : MIPSI_BNE, left, right);
1495 }
1496}
1497
1498#if LJ_HASFFI
1499/* 64 bit integer comparisons. */
1500static void asm_comp64(ASMState *as, IRIns *ir)
1501{
1502 /* ORDER IR: LT GE LE GT ULT UGE ULE UGT. */
1503 IROp op = (ir-1)->o;
1504 MCLabel l_end;
1505 Reg rightlo, leftlo, righthi, lefthi = ra_alloc2(as, ir, RSET_GPR);
1506 righthi = (lefthi >> 8); lefthi &= 255;
1507 leftlo = ra_alloc2(as, ir-1,
1508 rset_exclude(rset_exclude(RSET_GPR, lefthi), righthi));
1509 rightlo = (leftlo >> 8); leftlo &= 255;
1510 asm_guard(as, ((op^(op>>1))&1) ? MIPSI_BNE : MIPSI_BEQ, RID_TMP, RID_ZERO);
1511 l_end = emit_label(as);
1512 if (lefthi != righthi)
1513 emit_dst(as, (op&4) ? MIPSI_SLTU : MIPSI_SLT, RID_TMP,
1514 (op&2) ? righthi : lefthi, (op&2) ? lefthi : righthi);
1515 emit_dst(as, MIPSI_SLTU, RID_TMP,
1516 (op&2) ? rightlo : leftlo, (op&2) ? leftlo : rightlo);
1517 if (lefthi != righthi)
1518 emit_branch(as, MIPSI_BEQ, lefthi, righthi, l_end);
1519}
1520
1521static void asm_comp64eq(ASMState *as, IRIns *ir)
1522{
1523 Reg tmp, right, left = ra_alloc2(as, ir, RSET_GPR);
1524 right = (left >> 8); left &= 255;
1525 asm_guard(as, ((ir-1)->o & 1) ? MIPSI_BEQ : MIPSI_BNE, RID_TMP, RID_ZERO);
1526 tmp = ra_scratch(as, rset_exclude(rset_exclude(RSET_GPR, left), right));
1527 emit_dst(as, MIPSI_OR, RID_TMP, RID_TMP, tmp);
1528 emit_dst(as, MIPSI_XOR, tmp, left, right);
1529 left = ra_alloc2(as, ir-1, RSET_GPR);
1530 right = (left >> 8); left &= 255;
1531 emit_dst(as, MIPSI_XOR, RID_TMP, left, right);
1532}
1533#endif
1534
1535/* -- Support for 64 bit ops in 32 bit mode ------------------------------- */
1536
1537/* Hiword op of a split 64 bit op. Previous op must be the loword op. */
1538static void asm_hiop(ASMState *as, IRIns *ir)
1539{
1540#if LJ_HASFFI
1541 /* HIOP is marked as a store because it needs its own DCE logic. */
1542 int uselo = ra_used(ir-1), usehi = ra_used(ir); /* Loword/hiword used? */
1543 if (LJ_UNLIKELY(!(as->flags & JIT_F_OPT_DCE))) uselo = usehi = 1;
1544 if ((ir-1)->o == IR_CONV) { /* Conversions to/from 64 bit. */
1545 as->curins--; /* Always skip the CONV. */
1546 if (usehi || uselo)
1547 asm_conv64(as, ir);
1548 return;
1549 } else if ((ir-1)->o < IR_EQ) { /* 64 bit integer comparisons. ORDER IR. */
1550 as->curins--; /* Always skip the loword comparison. */
1551 asm_comp64(as, ir);
1552 return;
1553 } else if ((ir-1)->o <= IR_NE) { /* 64 bit integer comparisons. ORDER IR. */
1554 as->curins--; /* Always skip the loword comparison. */
1555 asm_comp64eq(as, ir);
1556 return;
1557 }
1558 if (!usehi) return; /* Skip unused hiword op for all remaining ops. */
1559 switch ((ir-1)->o) {
1560 case IR_ADD: as->curins--; asm_add64(as, ir); break;
1561 case IR_SUB: as->curins--; asm_sub64(as, ir); break;
1562 case IR_NEG: as->curins--; asm_neg64(as, ir); break;
1563 case IR_CALLN:
1564 case IR_CALLXS:
1565 if (!uselo)
1566 ra_allocref(as, ir->op1, RID2RSET(RID_RETLO)); /* Mark lo op as used. */
1567 break;
1568 case IR_CNEWI:
1569 /* Nothing to do here. Handled by lo op itself. */
1570 break;
1571 default: lua_assert(0); break;
1572 }
1573#else
1574 UNUSED(as); UNUSED(ir); lua_assert(0); /* Unused without FFI. */
1575#endif
1576}
1577
1578/* -- Stack handling ------------------------------------------------------ */
1579
1580/* Check Lua stack size for overflow. Use exit handler as fallback. */
1581static void asm_stack_check(ASMState *as, BCReg topslot,
1582 IRIns *irp, RegSet allow, ExitNo exitno)
1583{
1584 /* Try to get an unused temp. register, otherwise spill/restore RID_RET*. */
1585 Reg tmp, pbase = irp ? (ra_hasreg(irp->r) ? irp->r : RID_TMP) : RID_BASE;
1586 ExitNo oldsnap = as->snapno;
1587 rset_clear(allow, pbase);
1588 tmp = allow ? rset_pickbot(allow) :
1589 (pbase == RID_RETHI ? RID_RETLO : RID_RETHI);
1590 as->snapno = exitno;
1591 asm_guard(as, MIPSI_BNE, RID_TMP, RID_ZERO);
1592 as->snapno = oldsnap;
1593 if (allow == RSET_EMPTY) /* Restore temp. register. */
1594 emit_tsi(as, MIPSI_LW, tmp, RID_SP, 0);
1595 else
1596 ra_modified(as, tmp);
1597 emit_tsi(as, MIPSI_SLTIU, RID_TMP, RID_TMP, (int32_t)(8*topslot));
1598 emit_dst(as, MIPSI_SUBU, RID_TMP, tmp, pbase);
1599 emit_tsi(as, MIPSI_LW, tmp, tmp, offsetof(lua_State, maxstack));
1600 if (pbase == RID_TMP)
1601 emit_getgl(as, RID_TMP, jit_base);
1602 emit_getgl(as, tmp, jit_L);
1603 if (allow == RSET_EMPTY) /* Spill temp. register. */
1604 emit_tsi(as, MIPSI_SW, tmp, RID_SP, 0);
1605}
1606
1607/* Restore Lua stack from on-trace state. */
1608static void asm_stack_restore(ASMState *as, SnapShot *snap)
1609{
1610 SnapEntry *map = &as->T->snapmap[snap->mapofs];
1611 SnapEntry *flinks = &as->T->snapmap[snap_nextofs(as->T, snap)-1];
1612 MSize n, nent = snap->nent;
1613 /* Store the value of all modified slots to the Lua stack. */
1614 for (n = 0; n < nent; n++) {
1615 SnapEntry sn = map[n];
1616 BCReg s = snap_slot(sn);
1617 int32_t ofs = 8*((int32_t)s-1);
1618 IRRef ref = snap_ref(sn);
1619 IRIns *ir = IR(ref);
1620 if ((sn & SNAP_NORESTORE))
1621 continue;
1622 if (irt_isnum(ir->t)) {
1623 Reg src = ra_alloc1(as, ref, RSET_FPR);
1624 emit_hsi(as, MIPSI_SDC1, src, RID_BASE, ofs);
1625 } else {
1626 Reg type;
1627 RegSet allow = rset_exclude(RSET_GPR, RID_BASE);
1628 lua_assert(irt_ispri(ir->t) || irt_isaddr(ir->t) || irt_isinteger(ir->t));
1629 if (!irt_ispri(ir->t)) {
1630 Reg src = ra_alloc1(as, ref, allow);
1631 rset_clear(allow, src);
1632 emit_tsi(as, MIPSI_SW, src, RID_BASE, ofs+(LJ_BE?4:0));
1633 }
1634 if ((sn & (SNAP_CONT|SNAP_FRAME))) {
1635 if (s == 0) continue; /* Do not overwrite link to previous frame. */
1636 type = ra_allock(as, (int32_t)(*flinks--), allow);
1637 } else {
1638 type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow);
1639 }
1640 emit_tsi(as, MIPSI_SW, type, RID_BASE, ofs+(LJ_BE?0:4));
1641 }
1642 checkmclim(as);
1643 }
1644 lua_assert(map + nent == flinks);
1645}
1646
1647/* -- GC handling --------------------------------------------------------- */
1648
1649/* Check GC threshold and do one or more GC steps. */
1650static void asm_gc_check(ASMState *as)
1651{
1652 const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_gc_step_jit];
1653 IRRef args[2];
1654 MCLabel l_end;
1655 Reg tmp;
1656 ra_evictset(as, RSET_SCRATCH);
1657 l_end = emit_label(as);
1658 /* Exit trace if in GCSatomic or GCSfinalize. Avoids syncing GC objects. */
1659 /* Assumes asm_snap_prep() already done. */
1660 asm_guard(as, MIPSI_BNE, RID_RET, RID_ZERO);
1661 args[0] = ASMREF_TMP1; /* global_State *g */
1662 args[1] = ASMREF_TMP2; /* MSize steps */
1663 asm_gencall(as, ci, args);
1664 emit_tsi(as, MIPSI_ADDIU, ra_releasetmp(as, ASMREF_TMP1), RID_JGL, -32768);
1665 tmp = ra_releasetmp(as, ASMREF_TMP2);
1666 emit_loadi(as, tmp, (int32_t)as->gcsteps);
1667 /* Jump around GC step if GC total < GC threshold. */
1668 emit_branch(as, MIPSI_BNE, RID_TMP, RID_ZERO, l_end);
1669 emit_dst(as, MIPSI_SLTU, RID_TMP, RID_TMP, tmp);
1670 emit_getgl(as, tmp, gc.threshold);
1671 emit_getgl(as, RID_TMP, gc.total);
1672 as->gcsteps = 0;
1673 checkmclim(as);
1674}
1675
1676/* -- Loop handling ------------------------------------------------------- */
1677
1678/* Fixup the loop branch. */
1679static void asm_loop_fixup(ASMState *as)
1680{
1681 MCode *p = as->mctop;
1682 MCode *target = as->mcp;
1683 p[-1] = MIPSI_NOP;
1684 if (as->loopinv) { /* Inverted loop branch? */
1685 /* asm_guard already inverted the cond branch. Only patch the target. */
1686 p[-3] |= ((target-p+2) & 0x0000ffffu);
1687 } else {
1688 p[-2] = MIPSI_J|(((uintptr_t)target>>2)&0x03ffffffu);
1689 }
1690}
1691
1692/* -- Head of trace ------------------------------------------------------- */
1693
1694/* Coalesce BASE register for a root trace. */
1695static void asm_head_root_base(ASMState *as)
1696{
1697 IRIns *ir = IR(REF_BASE);
1698 Reg r = ir->r;
1699 if (as->loopinv) as->mctop--;
1700 if (ra_hasreg(r)) {
1701 ra_free(as, r);
1702 if (rset_test(as->modset, r))
1703 ir->r = RID_INIT; /* No inheritance for modified BASE register. */
1704 if (r != RID_BASE)
1705 emit_move(as, r, RID_BASE);
1706 }
1707}
1708
1709/* Coalesce BASE register for a side trace. */
1710static RegSet asm_head_side_base(ASMState *as, IRIns *irp, RegSet allow)
1711{
1712 IRIns *ir = IR(REF_BASE);
1713 Reg r = ir->r;
1714 if (as->loopinv) as->mctop--;
1715 if (ra_hasreg(r)) {
1716 ra_free(as, r);
1717 if (rset_test(as->modset, r))
1718 ir->r = RID_INIT; /* No inheritance for modified BASE register. */
1719 if (irp->r == r) {
1720 rset_clear(allow, r); /* Mark same BASE register as coalesced. */
1721 } else if (ra_hasreg(irp->r) && rset_test(as->freeset, irp->r)) {
1722 rset_clear(allow, irp->r);
1723 emit_move(as, r, irp->r); /* Move from coalesced parent reg. */
1724 } else {
1725 emit_getgl(as, r, jit_base); /* Otherwise reload BASE. */
1726 }
1727 }
1728 return allow;
1729}
1730
1731/* -- Tail of trace ------------------------------------------------------- */
1732
1733/* Fixup the tail code. */
1734static void asm_tail_fixup(ASMState *as, TraceNo lnk)
1735{
1736 MCode *target = lnk ? traceref(as->J,lnk)->mcode : (MCode *)lj_vm_exit_interp;
1737 int32_t spadj = as->T->spadjust;
1738 MCode *p = as->mctop-1;
1739 *p = spadj ? (MIPSI_ADDIU|MIPSF_T(RID_SP)|MIPSF_S(RID_SP)|spadj) : MIPSI_NOP;
1740 p[-1] = MIPSI_J|(((uintptr_t)target>>2)&0x03ffffffu);
1741}
1742
1743/* Prepare tail of code. */
1744static void asm_tail_prep(ASMState *as)
1745{
1746 as->mcp = as->mctop-2; /* Leave room for branch plus nop or stack adj. */
1747 as->invmcp = as->loopref ? as->mcp : NULL;
1748}
1749
1750/* -- Instruction dispatch ------------------------------------------------ */
1751
1752/* Assemble a single instruction. */
1753static void asm_ir(ASMState *as, IRIns *ir)
1754{
1755 switch ((IROp)ir->o) {
1756 /* Miscellaneous ops. */
1757 case IR_LOOP: asm_loop(as); break;
1758 case IR_NOP: case IR_XBAR: lua_assert(!ra_used(ir)); break;
1759 case IR_USE:
1760 ra_alloc1(as, ir->op1, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); break;
1761 case IR_PHI: asm_phi(as, ir); break;
1762 case IR_HIOP: asm_hiop(as, ir); break;
1763
1764 /* Guarded assertions. */
1765 case IR_EQ: case IR_NE: asm_compeq(as, ir); break;
1766 case IR_LT: case IR_GE: case IR_LE: case IR_GT:
1767 case IR_ULT: case IR_UGE: case IR_ULE: case IR_UGT:
1768 case IR_ABC:
1769 asm_comp(as, ir);
1770 break;
1771
1772 case IR_RETF: asm_retf(as, ir); break;
1773
1774 /* Bit ops. */
1775 case IR_BNOT: asm_bitnot(as, ir); break;
1776 case IR_BSWAP: asm_bitswap(as, ir); break;
1777
1778 case IR_BAND: asm_bitop(as, ir, MIPSI_AND, MIPSI_ANDI); break;
1779 case IR_BOR: asm_bitop(as, ir, MIPSI_OR, MIPSI_ORI); break;
1780 case IR_BXOR: asm_bitop(as, ir, MIPSI_XOR, MIPSI_XORI); break;
1781
1782 case IR_BSHL: asm_bitshift(as, ir, MIPSI_SLLV, MIPSI_SLL); break;
1783 case IR_BSHR: asm_bitshift(as, ir, MIPSI_SRLV, MIPSI_SRL); break;
1784 case IR_BSAR: asm_bitshift(as, ir, MIPSI_SRAV, MIPSI_SRA); break;
1785 case IR_BROL: lua_assert(0); break;
1786 case IR_BROR: asm_bitror(as, ir); break;
1787
1788 /* Arithmetic ops. */
1789 case IR_ADD: asm_add(as, ir); break;
1790 case IR_SUB: asm_sub(as, ir); break;
1791 case IR_MUL: asm_mul(as, ir); break;
1792 case IR_DIV: asm_fparith(as, ir, MIPSI_DIV_D); break;
1793 case IR_MOD: asm_callid(as, ir, IRCALL_lj_vm_modi); break;
1794 case IR_POW: asm_callid(as, ir, IRCALL_lj_vm_powi); break;
1795 case IR_NEG: asm_neg(as, ir); break;
1796
1797 case IR_ABS: asm_fpunary(as, ir, MIPSI_ABS_D); break;
1798 case IR_ATAN2: asm_callid(as, ir, IRCALL_atan2); break;
1799 case IR_LDEXP: asm_callid(as, ir, IRCALL_ldexp); break;
1800 case IR_MIN: asm_min_max(as, ir, 0); break;
1801 case IR_MAX: asm_min_max(as, ir, 1); break;
1802 case IR_FPMATH:
1803 if (ir->op2 == IRFPM_EXP2 && asm_fpjoin_pow(as, ir))
1804 break;
1805 if (ir->op2 <= IRFPM_TRUNC)
1806 asm_callround(as, ir, IRCALL_lj_vm_floor + ir->op2);
1807 else
1808 asm_callid(as, ir, IRCALL_lj_vm_floor + ir->op2);
1809 break;
1810
1811 /* Overflow-checking arithmetic ops. */
1812 case IR_ADDOV: asm_arithov(as, ir); break;
1813 case IR_SUBOV: asm_arithov(as, ir); break;
1814 case IR_MULOV: asm_mulov(as, ir); break;
1815
1816 /* Memory references. */
1817 case IR_AREF: asm_aref(as, ir); break;
1818 case IR_HREF: asm_href(as, ir); break;
1819 case IR_HREFK: asm_hrefk(as, ir); break;
1820 case IR_NEWREF: asm_newref(as, ir); break;
1821 case IR_UREFO: case IR_UREFC: asm_uref(as, ir); break;
1822 case IR_FREF: asm_fref(as, ir); break;
1823 case IR_STRREF: asm_strref(as, ir); break;
1824
1825 /* Loads and stores. */
1826 case IR_ALOAD: case IR_HLOAD: case IR_ULOAD: case IR_VLOAD:
1827 asm_ahuvload(as, ir);
1828 break;
1829 case IR_FLOAD: asm_fload(as, ir); break;
1830 case IR_XLOAD: asm_xload(as, ir); break;
1831 case IR_SLOAD: asm_sload(as, ir); break;
1832
1833 case IR_ASTORE: case IR_HSTORE: case IR_USTORE: asm_ahustore(as, ir); break;
1834 case IR_FSTORE: asm_fstore(as, ir); break;
1835 case IR_XSTORE: asm_xstore(as, ir); break;
1836
1837 /* Allocations. */
1838 case IR_SNEW: case IR_XSNEW: asm_snew(as, ir); break;
1839 case IR_TNEW: asm_tnew(as, ir); break;
1840 case IR_TDUP: asm_tdup(as, ir); break;
1841 case IR_CNEW: case IR_CNEWI: asm_cnew(as, ir); break;
1842
1843 /* Write barriers. */
1844 case IR_TBAR: asm_tbar(as, ir); break;
1845 case IR_OBAR: asm_obar(as, ir); break;
1846
1847 /* Type conversions. */
1848 case IR_CONV: asm_conv(as, ir); break;
1849 case IR_TOBIT: asm_tobit(as, ir); break;
1850 case IR_TOSTR: asm_tostr(as, ir); break;
1851 case IR_STRTO: asm_strto(as, ir); break;
1852
1853 /* Calls. */
1854 case IR_CALLN: case IR_CALLL: case IR_CALLS: asm_call(as, ir); break;
1855 case IR_CALLXS: asm_callx(as, ir); break;
1856 case IR_CARG: break;
1857
1858 default:
1859 setintV(&as->J->errinfo, ir->o);
1860 lj_trace_err_info(as->J, LJ_TRERR_NYIIR);
1861 break;
1862 }
1863}
1864
1865/* -- Trace setup --------------------------------------------------------- */
1866
1867/* Ensure there are enough stack slots for call arguments. */
1868static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci)
1869{
1870 IRRef args[CCI_NARGS_MAX];
1871 uint32_t i, nargs = (int)CCI_NARGS(ci);
1872 int nslots = 4, ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR;
1873 asm_collectargs(as, ir, ci, args);
1874 for (i = 0; i < nargs; i++) {
1875 if (args[i] && irt_isfp(IR(args[i])->t) &&
1876 nfpr > 0 && !(ci->flags & CCI_VARARG)) {
1877 nfpr--;
1878 ngpr -= irt_isnum(IR(args[i])->t) ? 2 : 1;
1879 } else if (args[i] && irt_isnum(IR(args[i])->t)) {
1880 nfpr = 0;
1881 ngpr = ngpr & ~1;
1882 if (ngpr > 0) ngpr -= 2; else nslots = (nslots+3) & ~1;
1883 } else {
1884 nfpr = 0;
1885 if (ngpr > 0) ngpr--; else nslots++;
1886 }
1887 }
1888 if (nslots > as->evenspill) /* Leave room for args in stack slots. */
1889 as->evenspill = nslots;
1890 return irt_isfp(ir->t) ? REGSP_HINT(RID_FPRET) : REGSP_HINT(RID_RET);
1891}
1892
1893static void asm_setup_target(ASMState *as)
1894{
1895 asm_sparejump_setup(as);
1896 asm_exitstub_setup(as);
1897}
1898
1899/* -- Trace patching ------------------------------------------------------ */
1900
1901/* Patch exit jumps of existing machine code to a new target. */
1902void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target)
1903{
1904 MCode *p = T->mcode;
1905 MCode *pe = (MCode *)((char *)p + T->szmcode);
1906 MCode *px = exitstub_trace_addr(T, exitno);
1907 MCode *cstart = NULL, *cstop = NULL;
1908 MCode *mcarea = lj_mcode_patch(J, p, 0);
1909 MCode exitload = MIPSI_LI | MIPSF_T(RID_TMP) | exitno;
1910 MCode tjump = MIPSI_J|(((uintptr_t)target>>2)&0x03ffffffu);
1911 for (p++; p < pe; p++) {
1912 if (*p == exitload) { /* Look for load of exit number. */
1913 if (((p[-1] ^ (px-p)) & 0xffffu) == 0) { /* Look for exitstub branch. */
1914 ptrdiff_t delta = target - p;
1915 if (((delta + 0x8000) >> 16) == 0) { /* Patch in-range branch. */
1916 patchbranch:
1917 p[-1] = (p[-1] & 0xffff0000u) | (delta & 0xffffu);
1918 *p = MIPSI_NOP; /* Replace the load of the exit number. */
1919 cstop = p;
1920 if (!cstart) cstart = p-1;
1921 } else { /* Branch out of range. Use spare jump slot in mcarea. */
1922 int i;
1923 for (i = 2; i < 2+MIPS_SPAREJUMP*2; i += 2) {
1924 if (mcarea[i] == tjump) {
1925 delta = mcarea+i - p;
1926 goto patchbranch;
1927 } else if (mcarea[i] == MIPSI_NOP) {
1928 mcarea[i] = tjump;
1929 cstart = mcarea+i;
1930 delta = mcarea+i - p;
1931 goto patchbranch;
1932 }
1933 }
1934 /* Ignore jump slot overflow. Child trace is simply not attached. */
1935 }
1936 } else if (p+1 == pe) {
1937 /* Patch NOP after code for inverted loop branch. Use of J is ok. */
1938 lua_assert(p[1] == MIPSI_NOP);
1939 p[1] = tjump;
1940 *p = MIPSI_NOP; /* Replace the load of the exit number. */
1941 cstop = p+2;
1942 if (!cstart) cstart = p+1;
1943 }
1944 }
1945 }
1946 if (cstart) lj_mcode_sync(cstart, cstop);
1947 lj_mcode_patch(J, mcarea, 1);
1948}
1949
diff --git a/src/lj_emit_mips.h b/src/lj_emit_mips.h
new file mode 100644
index 00000000..59f0640b
--- /dev/null
+++ b/src/lj_emit_mips.h
@@ -0,0 +1,205 @@
1/*
2** MIPS instruction emitter.
3** Copyright (C) 2005-2012 Mike Pall. See Copyright Notice in luajit.h
4*/
5
6/* -- Emit basic instructions --------------------------------------------- */
7
8static void emit_dst(ASMState *as, MIPSIns mi, Reg rd, Reg rs, Reg rt)
9{
10 *--as->mcp = mi | MIPSF_D(rd) | MIPSF_S(rs) | MIPSF_T(rt);
11}
12
13static void emit_dta(ASMState *as, MIPSIns mi, Reg rd, Reg rt, uint32_t a)
14{
15 *--as->mcp = mi | MIPSF_D(rd) | MIPSF_T(rt) | MIPSF_A(a);
16}
17
18#define emit_ds(as, mi, rd, rs) emit_dst(as, (mi), (rd), (rs), 0)
19#define emit_tg(as, mi, rt, rg) emit_dst(as, (mi), (rg)&31, 0, (rt))
20
21static void emit_tsi(ASMState *as, MIPSIns mi, Reg rt, Reg rs, int32_t i)
22{
23 *--as->mcp = mi | MIPSF_T(rt) | MIPSF_S(rs) | (i & 0xffff);
24}
25
26#define emit_ti(as, mi, rt, i) emit_tsi(as, (mi), (rt), 0, (i))
27#define emit_hsi(as, mi, rh, rs, i) emit_tsi(as, (mi), (rh) & 31, (rs), (i))
28
29static void emit_fgh(ASMState *as, MIPSIns mi, Reg rf, Reg rg, Reg rh)
30{
31 *--as->mcp = mi | MIPSF_F(rf&31) | MIPSF_G(rg&31) | MIPSF_H(rh&31);
32}
33
34#define emit_fg(as, mi, rf, rg) emit_fgh(as, (mi), (rf), (rg), 0)
35
36static void emit_rotr(ASMState *as, Reg dest, Reg src, Reg tmp, uint32_t shift)
37{
38 if ((as->flags & JIT_F_MIPS32R2)) {
39 emit_dta(as, MIPSI_ROTR, dest, src, shift);
40 } else {
41 emit_dst(as, MIPSI_OR, dest, dest, tmp);
42 emit_dta(as, MIPSI_SLL, dest, src, (-shift)&31);
43 emit_dta(as, MIPSI_SRL, tmp, src, shift);
44 }
45}
46
47/* -- Emit loads/stores --------------------------------------------------- */
48
49/* Prefer rematerialization of BASE/L from global_State over spills. */
50#define emit_canremat(ref) ((ref) <= REF_BASE)
51
52/* Try to find a one step delta relative to another constant. */
53static int emit_kdelta1(ASMState *as, Reg t, int32_t i)
54{
55 RegSet work = ~as->freeset & RSET_GPR;
56 while (work) {
57 Reg r = rset_picktop(work);
58 IRRef ref = regcost_ref(as->cost[r]);
59 lua_assert(r != t);
60 if (ref < ASMREF_L) {
61 int32_t delta = i - (ra_iskref(ref) ? ra_krefk(as, ref) : IR(ref)->i);
62 if (checki16(delta)) {
63 emit_tsi(as, MIPSI_ADDIU, t, r, delta);
64 return 1;
65 }
66 }
67 rset_clear(work, r);
68 }
69 return 0; /* Failed. */
70}
71
72/* Load a 32 bit constant into a GPR. */
73static void emit_loadi(ASMState *as, Reg r, int32_t i)
74{
75 if (checki16(i)) {
76 emit_ti(as, MIPSI_LI, r, i);
77 } else {
78 if ((i & 0xffff)) {
79 int32_t jgl = i32ptr(J2G(as->J));
80 if ((uint32_t)(i-jgl) < 65536) {
81 emit_tsi(as, MIPSI_ADDIU, r, RID_JGL, i-jgl-32768);
82 return;
83 } else if (emit_kdelta1(as, r, i)) {
84 return;
85 } else if ((i >> 16) == 0) {
86 emit_tsi(as, MIPSI_ORI, r, RID_ZERO, i);
87 return;
88 }
89 emit_tsi(as, MIPSI_ORI, r, r, i);
90 }
91 emit_ti(as, MIPSI_LUI, r, (i >> 16));
92 }
93}
94
95#define emit_loada(as, r, addr) emit_loadi(as, (r), i32ptr((addr)))
96
97static Reg ra_allock(ASMState *as, int32_t k, RegSet allow);
98static void ra_allockreg(ASMState *as, int32_t k, Reg r);
99
100/* Get/set from constant pointer. */
101static void emit_lsptr(ASMState *as, MIPSIns mi, Reg r, void *p, RegSet allow)
102{
103 int32_t jgl = i32ptr(J2G(as->J));
104 int32_t i = i32ptr(p);
105 Reg base;
106 if ((uint32_t)(i-jgl) < 65536) {
107 i = i-jgl-32768;
108 base = RID_JGL;
109 } else {
110 base = ra_allock(as, i-(int16_t)i, allow);
111 }
112 emit_tsi(as, mi, r, base, i);
113}
114
115#define emit_loadn(as, r, tv) \
116 emit_lsptr(as, MIPSI_LDC1, ((r) & 31), (void *)(tv), RSET_GPR)
117
118/* Get/set global_State fields. */
119static void emit_lsglptr(ASMState *as, MIPSIns mi, Reg r, int32_t ofs)
120{
121 emit_tsi(as, mi, r, RID_JGL, ofs-32768);
122}
123
124#define emit_getgl(as, r, field) \
125 emit_lsglptr(as, MIPSI_LW, (r), (int32_t)offsetof(global_State, field))
126#define emit_setgl(as, r, field) \
127 emit_lsglptr(as, MIPSI_SW, (r), (int32_t)offsetof(global_State, field))
128
129/* Trace number is determined from per-trace exit stubs. */
130#define emit_setvmstate(as, i) UNUSED(i)
131
132/* -- Emit control-flow instructions -------------------------------------- */
133
134/* Label for internal jumps. */
135typedef MCode *MCLabel;
136
137/* Return label pointing to current PC. */
138#define emit_label(as) ((as)->mcp)
139
140static void emit_branch(ASMState *as, MIPSIns mi, Reg rs, Reg rt, MCode *target)
141{
142 MCode *p = as->mcp;
143 ptrdiff_t delta = target - p;
144 lua_assert(((delta + 0x8000) >> 16) == 0);
145 *--p = mi | MIPSF_S(rs) | MIPSF_T(rt) | ((uint32_t)delta & 0xffffu);
146 as->mcp = p;
147}
148
149static void emit_call(ASMState *as, void *target)
150{
151 MCode *p = as->mcp;
152 *--p = MIPSI_NOP;
153 if ((((uintptr_t)target ^ (uintptr_t)p) >> 28) == 0)
154 *--p = MIPSI_JAL | (((uintptr_t)target >>2) & 0x03ffffffu);
155 else /* Target out of range: need indirect call. */
156 *--p = MIPSI_JALR | MIPSF_S(RID_CFUNCADDR);
157 as->mcp = p;
158 ra_allockreg(as, i32ptr(target), RID_CFUNCADDR);
159}
160
161/* -- Emit generic operations --------------------------------------------- */
162
163#define emit_move(as, dst, src) \
164 emit_ds(as, MIPSI_MOVE, (dst), (src))
165
166/* Generic move between two regs. */
167static void emit_movrr(ASMState *as, IRIns *ir, Reg dst, Reg src)
168{
169 if (dst < RID_MAX_GPR)
170 emit_move(as, dst, src);
171 else
172 emit_fg(as, irt_isnum(ir->t) ? MIPSI_MOV_D : MIPSI_MOV_S, dst, src);
173}
174
175/* Generic load of register from stack slot. */
176static void emit_spload(ASMState *as, IRIns *ir, Reg r, int32_t ofs)
177{
178 if (r < RID_MAX_GPR)
179 emit_tsi(as, MIPSI_LW, r, RID_SP, ofs);
180 else
181 emit_tsi(as, irt_isnum(ir->t) ? MIPSI_LDC1 : MIPSI_LWC1,
182 (r & 31), RID_SP, ofs);
183}
184
185/* Generic store of register to stack slot. */
186static void emit_spstore(ASMState *as, IRIns *ir, Reg r, int32_t ofs)
187{
188 if (r < RID_MAX_GPR)
189 emit_tsi(as, MIPSI_SW, r, RID_SP, ofs);
190 else
191 emit_tsi(as, irt_isnum(ir->t) ? MIPSI_SDC1 : MIPSI_SWC1,
192 (r&31), RID_SP, ofs);
193}
194
195/* Add offset to pointer. */
196static void emit_addptr(ASMState *as, Reg r, int32_t ofs)
197{
198 if (ofs) {
199 lua_assert(checki16(ofs));
200 emit_tsi(as, MIPSI_ADDIU, r, r, ofs);
201 }
202}
203
204#define emit_spsub(as, ofs) emit_addptr(as, RID_SP, -(ofs))
205
diff --git a/src/lj_ircall.h b/src/lj_ircall.h
index b30db5ea..4e8b7246 100644
--- a/src/lj_ircall.h
+++ b/src/lj_ircall.h
@@ -66,7 +66,7 @@ typedef struct CCallInfo {
66#define IRCALLCOND_SOFTFP_FFI(x) NULL 66#define IRCALLCOND_SOFTFP_FFI(x) NULL
67#endif 67#endif
68 68
69#define LJ_NEED_FP64 LJ_TARGET_PPC 69#define LJ_NEED_FP64 (LJ_TARGET_PPC || LJ_TARGET_MIPS)
70 70
71#if LJ_HASFFI && (LJ_SOFTFP || LJ_NEED_FP64) 71#if LJ_HASFFI && (LJ_SOFTFP || LJ_NEED_FP64)
72#define IRCALLCOND_FP64_FFI(x) x 72#define IRCALLCOND_FP64_FFI(x) x
@@ -157,8 +157,8 @@ typedef struct CCallInfo {
157 _(FP64_FFI, fp64_ul2d, 2, N, NUM, 0) \ 157 _(FP64_FFI, fp64_ul2d, 2, N, NUM, 0) \
158 _(FP64_FFI, fp64_l2f, 2, N, FLOAT, 0) \ 158 _(FP64_FFI, fp64_l2f, 2, N, FLOAT, 0) \
159 _(FP64_FFI, fp64_ul2f, 2, N, FLOAT, 0) \ 159 _(FP64_FFI, fp64_ul2f, 2, N, FLOAT, 0) \
160 _(FP64_FFI, fp64_d2l, 2, N, I64, 0) \ 160 _(FP64_FFI, fp64_d2l, ARG1_FP, N, I64, 0) \
161 _(FP64_FFI, fp64_d2ul, 2, N, U64, 0) \ 161 _(FP64_FFI, fp64_d2ul, ARG1_FP, N, U64, 0) \
162 _(FP64_FFI, fp64_f2l, 1, N, I64, 0) \ 162 _(FP64_FFI, fp64_f2l, 1, N, I64, 0) \
163 _(FP64_FFI, fp64_f2ul, 1, N, U64, 0) \ 163 _(FP64_FFI, fp64_f2ul, 1, N, U64, 0) \
164 _(FFI, lj_carith_divi64, ARG2_64, N, I64, CCI_NOFPRCLOBBER) \ 164 _(FFI, lj_carith_divi64, ARG2_64, N, I64, CCI_NOFPRCLOBBER) \
diff --git a/src/lj_mcode.c b/src/lj_mcode.c
index 7857ebc0..fb6b6dce 100644
--- a/src/lj_mcode.c
+++ b/src/lj_mcode.c
@@ -203,7 +203,13 @@ static void *mcode_alloc(jit_State *J, size_t sz)
203 /* Target an address in the static assembler code (64K aligned). 203 /* Target an address in the static assembler code (64K aligned).
204 ** Try addresses within a distance of target-range/2+1MB..target+range/2-1MB. 204 ** Try addresses within a distance of target-range/2+1MB..target+range/2-1MB.
205 */ 205 */
206#if LJ_TARGET_MIPS
207 /* Use the middle of the 256MB-aligned region. */
208 uintptr_t target = ((uintptr_t)(void *)lj_vm_exit_handler & 0xf0000000u) +
209 0x08000000u;
210#else
206 uintptr_t target = (uintptr_t)(void *)lj_vm_exit_handler & ~(uintptr_t)0xffff; 211 uintptr_t target = (uintptr_t)(void *)lj_vm_exit_handler & ~(uintptr_t)0xffff;
212#endif
207 const uintptr_t range = (1u << LJ_TARGET_JUMPRANGE) - (1u << 21); 213 const uintptr_t range = (1u << LJ_TARGET_JUMPRANGE) - (1u << 21);
208 /* First try a contiguous area below the last one. */ 214 /* First try a contiguous area below the last one. */
209 uintptr_t hint = J->mcarea ? (uintptr_t)J->mcarea - sz : 0; 215 uintptr_t hint = J->mcarea ? (uintptr_t)J->mcarea - sz : 0;
diff --git a/src/lj_target.h b/src/lj_target.h
index 8575dd5a..13de8fc6 100644
--- a/src/lj_target.h
+++ b/src/lj_target.h
@@ -53,7 +53,7 @@ typedef uint32_t RegSP;
53/* Bitset for registers. 32 registers suffice for most architectures. 53/* Bitset for registers. 32 registers suffice for most architectures.
54** Note that one set holds bits for both GPRs and FPRs. 54** Note that one set holds bits for both GPRs and FPRs.
55*/ 55*/
56#if LJ_TARGET_PPC 56#if LJ_TARGET_PPC || LJ_TARGET_MIPS
57typedef uint64_t RegSet; 57typedef uint64_t RegSet;
58#else 58#else
59typedef uint32_t RegSet; 59typedef uint32_t RegSet;
@@ -63,11 +63,11 @@ typedef uint32_t RegSet;
63#define RSET_EMPTY ((RegSet)0) 63#define RSET_EMPTY ((RegSet)0)
64#define RSET_RANGE(lo, hi) ((RID2RSET((hi)-(lo))-1) << (lo)) 64#define RSET_RANGE(lo, hi) ((RID2RSET((hi)-(lo))-1) << (lo))
65 65
66#define rset_test(rs, r) (((rs) >> (r)) & 1) 66#define rset_test(rs, r) ((int)((rs) >> (r)) & 1)
67#define rset_set(rs, r) (rs |= RID2RSET(r)) 67#define rset_set(rs, r) (rs |= RID2RSET(r))
68#define rset_clear(rs, r) (rs &= ~RID2RSET(r)) 68#define rset_clear(rs, r) (rs &= ~RID2RSET(r))
69#define rset_exclude(rs, r) (rs & ~RID2RSET(r)) 69#define rset_exclude(rs, r) (rs & ~RID2RSET(r))
70#if LJ_TARGET_PPC 70#if LJ_TARGET_PPC || LJ_TARGET_MIPS
71#define rset_picktop(rs) ((Reg)(__builtin_clzll(rs)^63)) 71#define rset_picktop(rs) ((Reg)(__builtin_clzll(rs)^63))
72#define rset_pickbot(rs) ((Reg)__builtin_ctzll(rs)) 72#define rset_pickbot(rs) ((Reg)__builtin_ctzll(rs))
73#else 73#else
diff --git a/src/lj_target_mips.h b/src/lj_target_mips.h
index 88d066d6..e81d55bd 100644
--- a/src/lj_target_mips.h
+++ b/src/lj_target_mips.h
@@ -12,7 +12,7 @@
12 _(R0) _(R1) _(R2) _(R3) _(R4) _(R5) _(R6) _(R7) \ 12 _(R0) _(R1) _(R2) _(R3) _(R4) _(R5) _(R6) _(R7) \
13 _(R8) _(R9) _(R10) _(R11) _(R12) _(R13) _(R14) _(R15) \ 13 _(R8) _(R9) _(R10) _(R11) _(R12) _(R13) _(R14) _(R15) \
14 _(R16) _(R17) _(R18) _(R19) _(R20) _(R21) _(R22) _(R23) \ 14 _(R16) _(R17) _(R18) _(R19) _(R20) _(R21) _(R22) _(R23) \
15 _(R24) _(R25) _(SYS1) _(SYS2) _(GP) _(SP) _(R30) _(RA) 15 _(R24) _(R25) _(SYS1) _(SYS2) _(R28) _(SP) _(R30) _(RA)
16#define FPRDEF(_) \ 16#define FPRDEF(_) \
17 _(F0) _(F1) _(F2) _(F3) _(F4) _(F5) _(F6) _(F7) \ 17 _(F0) _(F1) _(F2) _(F3) _(F4) _(F5) _(F6) _(F7) \
18 _(F8) _(F9) _(F10) _(F11) _(F12) _(F13) _(F14) _(F15) \ 18 _(F8) _(F9) _(F10) _(F11) _(F12) _(F13) _(F14) _(F15) \
@@ -26,6 +26,7 @@ enum {
26 GPRDEF(RIDENUM) /* General-purpose registers (GPRs). */ 26 GPRDEF(RIDENUM) /* General-purpose registers (GPRs). */
27 FPRDEF(RIDENUM) /* Floating-point registers (FPRs). */ 27 FPRDEF(RIDENUM) /* Floating-point registers (FPRs). */
28 RID_MAX, 28 RID_MAX,
29 RID_ZERO = RID_R0,
29 RID_TMP = RID_RA, 30 RID_TMP = RID_RA,
30 31
31 /* Calling conventions. */ 32 /* Calling conventions. */
@@ -38,6 +39,7 @@ enum {
38 RID_RETLO = RID_R3, 39 RID_RETLO = RID_R3,
39#endif 40#endif
40 RID_FPRET = RID_F0, 41 RID_FPRET = RID_F0,
42 RID_CFUNCADDR = RID_R25,
41 43
42 /* These definitions must match with the *.dasc file(s): */ 44 /* These definitions must match with the *.dasc file(s): */
43 RID_BASE = RID_R16, /* Interpreter BASE. */ 45 RID_BASE = RID_R16, /* Interpreter BASE. */
@@ -52,7 +54,7 @@ enum {
52 RID_MIN_FPR = RID_F0, 54 RID_MIN_FPR = RID_F0,
53 RID_MAX_FPR = RID_F31+1, 55 RID_MAX_FPR = RID_F31+1,
54 RID_NUM_GPR = RID_MAX_GPR - RID_MIN_GPR, 56 RID_NUM_GPR = RID_MAX_GPR - RID_MIN_GPR,
55 RID_NUM_FPR = (RID_MAX_FPR - RID_MIN_FPR)/2 57 RID_NUM_FPR = RID_MAX_FPR - RID_MIN_FPR /* Only even regs are used. */
56}; 58};
57 59
58#define RID_NUM_KREF RID_NUM_GPR 60#define RID_NUM_KREF RID_NUM_GPR
@@ -60,10 +62,10 @@ enum {
60 62
61/* -- Register sets ------------------------------------------------------- */ 63/* -- Register sets ------------------------------------------------------- */
62 64
63/* Make use of all registers, except TMP, SP, SYS1, SYS2 and JGL. */ 65/* Make use of all registers, except ZERO, TMP, SP, SYS1, SYS2 and JGL. */
64#define RSET_FIXED \ 66#define RSET_FIXED \
65 (RID2RSET(RID_TMP)|RID2RSET(RID_SP)|RID2RSET(RID_SYS1)|\ 67 (RID2RSET(RID_ZERO)|RID2RSET(RID_TMP)|RID2RSET(RID_SP)|\
66 RID2RSET(RID_SYS2)|RID2RSET(RID_JGL)) 68 RID2RSET(RID_SYS1)|RID2RSET(RID_SYS2)|RID2RSET(RID_JGL))
67#define RSET_GPR (RSET_RANGE(RID_MIN_GPR, RID_MAX_GPR) - RSET_FIXED) 69#define RSET_GPR (RSET_RANGE(RID_MIN_GPR, RID_MAX_GPR) - RSET_FIXED)
68#define RSET_FPR \ 70#define RSET_FPR \
69 (RID2RSET(RID_F0)|RID2RSET(RID_F2)|RID2RSET(RID_F4)|RID2RSET(RID_F6)|\ 71 (RID2RSET(RID_F0)|RID2RSET(RID_F2)|RID2RSET(RID_F4)|RID2RSET(RID_F6)|\
@@ -75,7 +77,7 @@ enum {
75 77
76#define RSET_SCRATCH_GPR \ 78#define RSET_SCRATCH_GPR \
77 (RSET_RANGE(RID_R1, RID_R15+1)|\ 79 (RSET_RANGE(RID_R1, RID_R15+1)|\
78 RID2RSET(RID_R24)|RID2RSET(RID_R25)|RID2RSET(RID_GP)|RID2RSET(RID_RA)) 80 RID2RSET(RID_R24)|RID2RSET(RID_R25)|RID2RSET(RID_R28))
79#define RSET_SCRATCH_FPR \ 81#define RSET_SCRATCH_FPR \
80 (RID2RSET(RID_F0)|RID2RSET(RID_F2)|RID2RSET(RID_F4)|RID2RSET(RID_F6)|\ 82 (RID2RSET(RID_F0)|RID2RSET(RID_F2)|RID2RSET(RID_F4)|RID2RSET(RID_F6)|\
81 RID2RSET(RID_F8)|RID2RSET(RID_F10)|RID2RSET(RID_F12)|RID2RSET(RID_F14)|\ 83 RID2RSET(RID_F8)|RID2RSET(RID_F10)|RID2RSET(RID_F12)|RID2RSET(RID_F14)|\
@@ -115,8 +117,15 @@ typedef struct {
115/* Highest exit + 1 indicates stack check. */ 117/* Highest exit + 1 indicates stack check. */
116#define EXITSTATE_CHECKEXIT 1 118#define EXITSTATE_CHECKEXIT 1
117 119
118#define EXITSTUB_SPACING 8 120/* Return the address of a per-trace exit stub. */
119#define EXITSTUBS_PER_GROUP 16 121static LJ_AINLINE uint32_t *exitstub_trace_addr_(uint32_t *p)
122{
123 while (*p == 0x00000000) p++; /* Skip MIPSI_NOP. */
124 return p;
125}
126/* Avoid dependence on lj_jit.h if only including lj_target.h. */
127#define exitstub_trace_addr(T, exitno) \
128 exitstub_trace_addr_((MCode *)((char *)(T)->mcode + (T)->szmcode))
120 129
121/* -- Instructions -------------------------------------------------------- */ 130/* -- Instructions -------------------------------------------------------- */
122 131
@@ -140,14 +149,106 @@ typedef enum MIPSIns {
140 MIPSI_LU = 0x34000000, 149 MIPSI_LU = 0x34000000,
141 MIPSI_LUI = 0x3c000000, 150 MIPSI_LUI = 0x3c000000,
142 151
152 MIPSI_ADDIU = 0x24000000,
153 MIPSI_ANDI = 0x30000000,
143 MIPSI_ORI = 0x34000000, 154 MIPSI_ORI = 0x34000000,
155 MIPSI_XORI = 0x38000000,
156 MIPSI_SLTI = 0x28000000,
157 MIPSI_SLTIU = 0x2c000000,
158
159 MIPSI_ADDU = 0x00000021,
160 MIPSI_SUBU = 0x00000023,
161 MIPSI_MUL = 0x70000002,
162 MIPSI_AND = 0x00000024,
163 MIPSI_OR = 0x00000025,
164 MIPSI_XOR = 0x00000026,
165 MIPSI_NOR = 0x00000027,
166 MIPSI_SLT = 0x0000002a,
167 MIPSI_SLTU = 0x0000002b,
168 MIPSI_MOVZ = 0x0000000a,
169 MIPSI_MOVN = 0x0000000b,
170
171 MIPSI_SLL = 0x00000000,
172 MIPSI_SRL = 0x00000002,
173 MIPSI_SRA = 0x00000003,
174 MIPSI_ROTR = 0x00200002, /* MIPS32R2 */
175 MIPSI_SLLV = 0x00000004,
176 MIPSI_SRLV = 0x00000006,
177 MIPSI_SRAV = 0x00000007,
178 MIPSI_ROTRV = 0x00000046, /* MIPS32R2 */
179
180 MIPSI_SEB = 0x7c000420, /* MIPS32R2 */
181 MIPSI_SEH = 0x7c000620, /* MIPS32R2 */
182 MIPSI_WSBH = 0x7c0000a0, /* MIPS32R2 */
144 183
145 MIPSI_B = 0x10000000, 184 MIPSI_B = 0x10000000,
185 MIPSI_J = 0x08000000,
186 MIPSI_JAL = 0x0c000000,
146 MIPSI_JR = 0x00000008, 187 MIPSI_JR = 0x00000008,
188 MIPSI_JALR = 0x0000f809,
189
190 MIPSI_BEQ = 0x10000000,
191 MIPSI_BNE = 0x14000000,
192 MIPSI_BLEZ = 0x18000000,
193 MIPSI_BGTZ = 0x1c000000,
194 MIPSI_BLTZ = 0x04000000,
195 MIPSI_BGEZ = 0x04010000,
147 196
148 /* Load/store instructions. */ 197 /* Load/store instructions. */
149 MIPSI_LW = 0x8c000000, 198 MIPSI_LW = 0x8c000000,
150 MIPSI_SW = 0xac000000, 199 MIPSI_SW = 0xac000000,
200 MIPSI_LB = 0x80000000,
201 MIPSI_SB = 0xa0000000,
202 MIPSI_LH = 0x84000000,
203 MIPSI_SH = 0xa4000000,
204 MIPSI_LBU = 0x90000000,
205 MIPSI_LHU = 0x94000000,
206 MIPSI_LWC1 = 0xc4000000,
207 MIPSI_SWC1 = 0xe4000000,
208 MIPSI_LDC1 = 0xd4000000,
209 MIPSI_SDC1 = 0xf4000000,
210
211 /* FP instructions. */
212 MIPSI_MOV_S = 0x46000006,
213 MIPSI_MOV_D = 0x46200006,
214 MIPSI_MOVT_D = 0x46210011,
215 MIPSI_MOVF_D = 0x46200011,
216
217 MIPSI_ABS_D = 0x46200005,
218 MIPSI_NEG_D = 0x46200007,
219
220 MIPSI_ADD_D = 0x46200000,
221 MIPSI_SUB_D = 0x46200001,
222 MIPSI_MUL_D = 0x46200002,
223 MIPSI_DIV_D = 0x46200003,
224
225 MIPSI_ADD_S = 0x46000000,
226 MIPSI_SUB_S = 0x46000001,
227
228 MIPSI_CVT_D_S = 0x46000021,
229 MIPSI_CVT_W_S = 0x46000024,
230 MIPSI_CVT_S_D = 0x46200020,
231 MIPSI_CVT_W_D = 0x46200024,
232 MIPSI_CVT_S_W = 0x46800020,
233 MIPSI_CVT_D_W = 0x46800021,
234
235 MIPSI_TRUNC_W_S = 0x4600000d,
236 MIPSI_TRUNC_W_D = 0x4620000d,
237 MIPSI_FLOOR_W_S = 0x4600000f,
238 MIPSI_FLOOR_W_D = 0x4620000f,
239
240 MIPSI_MFC1 = 0x44000000,
241 MIPSI_MTC1 = 0x44800000,
242
243 MIPSI_BC1F = 0x45000000,
244 MIPSI_BC1T = 0x45010000,
245
246 MIPSI_C_EQ_D = 0x46200032,
247 MIPSI_C_OLT_D = 0x46200034,
248 MIPSI_C_ULT_D = 0x46200035,
249 MIPSI_C_OLE_D = 0x46200036,
250 MIPSI_C_ULE_D = 0x46200037,
251
151} MIPSIns; 252} MIPSIns;
152 253
153#endif 254#endif