diff options
Diffstat (limited to 'src/lj_asm_mips.h')
-rw-r--r-- | src/lj_asm_mips.h | 1779 |
1 files changed, 1292 insertions, 487 deletions
diff --git a/src/lj_asm_mips.h b/src/lj_asm_mips.h index c0e491a6..db42b8f3 100644 --- a/src/lj_asm_mips.h +++ b/src/lj_asm_mips.h | |||
@@ -23,7 +23,7 @@ static Reg ra_alloc1z(ASMState *as, IRRef ref, RegSet allow) | |||
23 | { | 23 | { |
24 | Reg r = IR(ref)->r; | 24 | Reg r = IR(ref)->r; |
25 | if (ra_noreg(r)) { | 25 | if (ra_noreg(r)) { |
26 | if (!(allow & RSET_FPR) && irref_isk(ref) && IR(ref)->i == 0) | 26 | if (!(allow & RSET_FPR) && irref_isk(ref) && get_kval(as, ref) == 0) |
27 | return RID_ZERO; | 27 | return RID_ZERO; |
28 | r = ra_allocref(as, ref, allow); | 28 | r = ra_allocref(as, ref, allow); |
29 | } else { | 29 | } else { |
@@ -64,17 +64,29 @@ static Reg ra_alloc2(ASMState *as, IRIns *ir, RegSet allow) | |||
64 | /* Setup spare long-range jump slots per mcarea. */ | 64 | /* Setup spare long-range jump slots per mcarea. */ |
65 | static void asm_sparejump_setup(ASMState *as) | 65 | static void asm_sparejump_setup(ASMState *as) |
66 | { | 66 | { |
67 | MCode *mxp = as->mcbot; | 67 | MCode *mxp = as->mctop; |
68 | if (((uintptr_t)mxp & (LJ_PAGESIZE-1)) == sizeof(MCLink)) { | 68 | if ((char *)mxp == (char *)as->J->mcarea + as->J->szmcarea) { |
69 | lua_assert(MIPSI_NOP == 0); | 69 | mxp -= MIPS_SPAREJUMP*2; |
70 | lj_assertA(MIPSI_NOP == 0, "bad NOP"); | ||
70 | memset(mxp, 0, MIPS_SPAREJUMP*2*sizeof(MCode)); | 71 | memset(mxp, 0, MIPS_SPAREJUMP*2*sizeof(MCode)); |
71 | mxp += MIPS_SPAREJUMP*2; | 72 | as->mctop = mxp; |
72 | lua_assert(mxp < as->mctop); | 73 | } |
73 | lj_mcode_sync(as->mcbot, mxp); | 74 | } |
74 | lj_mcode_commitbot(as->J, mxp); | 75 | |
75 | as->mcbot = mxp; | 76 | static MCode *asm_sparejump_use(MCode *mcarea, MCode tjump) |
76 | as->mclim = as->mcbot + MCLIM_REDZONE; | 77 | { |
78 | MCode *mxp = (MCode *)((char *)mcarea + ((MCLink *)mcarea)->size); | ||
79 | int slot = MIPS_SPAREJUMP; | ||
80 | while (slot--) { | ||
81 | mxp -= 2; | ||
82 | if (*mxp == tjump) { | ||
83 | return mxp; | ||
84 | } else if (*mxp == MIPSI_NOP) { | ||
85 | *mxp = tjump; | ||
86 | return mxp; | ||
87 | } | ||
77 | } | 88 | } |
89 | return NULL; | ||
78 | } | 90 | } |
79 | 91 | ||
80 | /* Setup exit stub after the end of each trace. */ | 92 | /* Setup exit stub after the end of each trace. */ |
@@ -84,7 +96,8 @@ static void asm_exitstub_setup(ASMState *as) | |||
84 | /* sw TMP, 0(sp); j ->vm_exit_handler; li TMP, traceno */ | 96 | /* sw TMP, 0(sp); j ->vm_exit_handler; li TMP, traceno */ |
85 | *--mxp = MIPSI_LI|MIPSF_T(RID_TMP)|as->T->traceno; | 97 | *--mxp = MIPSI_LI|MIPSF_T(RID_TMP)|as->T->traceno; |
86 | *--mxp = MIPSI_J|((((uintptr_t)(void *)lj_vm_exit_handler)>>2)&0x03ffffffu); | 98 | *--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); | 99 | lj_assertA(((uintptr_t)mxp ^ (uintptr_t)(void *)lj_vm_exit_handler)>>28 == 0, |
100 | "branch target out of range"); | ||
88 | *--mxp = MIPSI_SW|MIPSF_T(RID_TMP)|MIPSF_S(RID_SP)|0; | 101 | *--mxp = MIPSI_SW|MIPSF_T(RID_TMP)|MIPSF_S(RID_SP)|0; |
89 | as->mctop = mxp; | 102 | as->mctop = mxp; |
90 | } | 103 | } |
@@ -101,7 +114,12 @@ static void asm_guard(ASMState *as, MIPSIns mi, Reg rs, Reg rt) | |||
101 | as->invmcp = NULL; | 114 | as->invmcp = NULL; |
102 | as->loopinv = 1; | 115 | as->loopinv = 1; |
103 | as->mcp = p+1; | 116 | as->mcp = p+1; |
117 | #if !LJ_TARGET_MIPSR6 | ||
104 | mi = mi ^ ((mi>>28) == 1 ? 0x04000000u : 0x00010000u); /* Invert cond. */ | 118 | mi = mi ^ ((mi>>28) == 1 ? 0x04000000u : 0x00010000u); /* Invert cond. */ |
119 | #else | ||
120 | mi = mi ^ ((mi>>28) == 1 ? 0x04000000u : | ||
121 | (mi>>28) == 4 ? 0x00800000u : 0x00010000u); /* Invert cond. */ | ||
122 | #endif | ||
105 | target = p; /* Patch target later in asm_loop_fixup. */ | 123 | target = p; /* Patch target later in asm_loop_fixup. */ |
106 | } | 124 | } |
107 | emit_ti(as, MIPSI_LI, RID_TMP, as->snapno); | 125 | emit_ti(as, MIPSI_LI, RID_TMP, as->snapno); |
@@ -165,9 +183,9 @@ static Reg asm_fuseahuref(ASMState *as, IRRef ref, int32_t *ofsp, RegSet allow) | |||
165 | } else if (ir->o == IR_UREFC) { | 183 | } else if (ir->o == IR_UREFC) { |
166 | if (irref_isk(ir->op1)) { | 184 | if (irref_isk(ir->op1)) { |
167 | GCfunc *fn = ir_kfunc(IR(ir->op1)); | 185 | GCfunc *fn = ir_kfunc(IR(ir->op1)); |
168 | int32_t ofs = i32ptr(&gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.tv); | 186 | intptr_t ofs = (intptr_t)&gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.tv; |
169 | int32_t jgl = (intptr_t)J2G(as->J); | 187 | intptr_t jgl = (intptr_t)J2G(as->J); |
170 | if ((uint32_t)(ofs-jgl) < 65536) { | 188 | if ((uintptr_t)(ofs-jgl) < 65536) { |
171 | *ofsp = ofs-jgl-32768; | 189 | *ofsp = ofs-jgl-32768; |
172 | return RID_JGL; | 190 | return RID_JGL; |
173 | } else { | 191 | } else { |
@@ -175,6 +193,9 @@ static Reg asm_fuseahuref(ASMState *as, IRRef ref, int32_t *ofsp, RegSet allow) | |||
175 | return ra_allock(as, ofs-(int16_t)ofs, allow); | 193 | return ra_allock(as, ofs-(int16_t)ofs, allow); |
176 | } | 194 | } |
177 | } | 195 | } |
196 | } else if (ir->o == IR_TMPREF) { | ||
197 | *ofsp = (int32_t)(offsetof(global_State, tmptv)-32768); | ||
198 | return RID_JGL; | ||
178 | } | 199 | } |
179 | } | 200 | } |
180 | *ofsp = 0; | 201 | *ofsp = 0; |
@@ -189,20 +210,21 @@ static void asm_fusexref(ASMState *as, MIPSIns mi, Reg rt, IRRef ref, | |||
189 | Reg base; | 210 | Reg base; |
190 | if (ra_noreg(ir->r) && canfuse(as, ir)) { | 211 | if (ra_noreg(ir->r) && canfuse(as, ir)) { |
191 | if (ir->o == IR_ADD) { | 212 | if (ir->o == IR_ADD) { |
192 | int32_t ofs2; | 213 | intptr_t ofs2; |
193 | if (irref_isk(ir->op2) && (ofs2 = ofs + IR(ir->op2)->i, checki16(ofs2))) { | 214 | if (irref_isk(ir->op2) && (ofs2 = ofs + get_kval(as, ir->op2), |
215 | checki16(ofs2))) { | ||
194 | ref = ir->op1; | 216 | ref = ir->op1; |
195 | ofs = ofs2; | 217 | ofs = (int32_t)ofs2; |
196 | } | 218 | } |
197 | } else if (ir->o == IR_STRREF) { | 219 | } else if (ir->o == IR_STRREF) { |
198 | int32_t ofs2 = 65536; | 220 | intptr_t ofs2 = 65536; |
199 | lua_assert(ofs == 0); | 221 | lj_assertA(ofs == 0, "bad usage"); |
200 | ofs = (int32_t)sizeof(GCstr); | 222 | ofs = (int32_t)sizeof(GCstr); |
201 | if (irref_isk(ir->op2)) { | 223 | if (irref_isk(ir->op2)) { |
202 | ofs2 = ofs + IR(ir->op2)->i; | 224 | ofs2 = ofs + get_kval(as, ir->op2); |
203 | ref = ir->op1; | 225 | ref = ir->op1; |
204 | } else if (irref_isk(ir->op1)) { | 226 | } else if (irref_isk(ir->op1)) { |
205 | ofs2 = ofs + IR(ir->op1)->i; | 227 | ofs2 = ofs + get_kval(as, ir->op1); |
206 | ref = ir->op2; | 228 | ref = ir->op2; |
207 | } | 229 | } |
208 | if (!checki16(ofs2)) { | 230 | if (!checki16(ofs2)) { |
@@ -210,7 +232,7 @@ static void asm_fusexref(ASMState *as, MIPSIns mi, Reg rt, IRRef ref, | |||
210 | Reg right, left = ra_alloc2(as, ir, allow); | 232 | Reg right, left = ra_alloc2(as, ir, allow); |
211 | right = (left >> 8); left &= 255; | 233 | right = (left >> 8); left &= 255; |
212 | emit_hsi(as, mi, rt, RID_TMP, ofs); | 234 | emit_hsi(as, mi, rt, RID_TMP, ofs); |
213 | emit_dst(as, MIPSI_ADDU, RID_TMP, left, right); | 235 | emit_dst(as, MIPSI_AADDU, RID_TMP, left, right); |
214 | return; | 236 | return; |
215 | } | 237 | } |
216 | ofs = ofs2; | 238 | ofs = ofs2; |
@@ -225,29 +247,43 @@ static void asm_fusexref(ASMState *as, MIPSIns mi, Reg rt, IRRef ref, | |||
225 | /* Generate a call to a C function. */ | 247 | /* Generate a call to a C function. */ |
226 | static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) | 248 | static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) |
227 | { | 249 | { |
228 | uint32_t n, nargs = CCI_NARGS(ci); | 250 | uint32_t n, nargs = CCI_XNARGS(ci); |
229 | int32_t ofs = 16; | 251 | int32_t ofs = LJ_32 ? 16 : 0; |
252 | #if LJ_SOFTFP | ||
253 | Reg gpr = REGARG_FIRSTGPR; | ||
254 | #else | ||
230 | Reg gpr, fpr = REGARG_FIRSTFPR; | 255 | Reg gpr, fpr = REGARG_FIRSTFPR; |
256 | #endif | ||
231 | if ((void *)ci->func) | 257 | if ((void *)ci->func) |
232 | emit_call(as, (void *)ci->func); | 258 | emit_call(as, (void *)ci->func, 1); |
259 | #if !LJ_SOFTFP | ||
233 | for (gpr = REGARG_FIRSTGPR; gpr <= REGARG_LASTGPR; gpr++) | 260 | for (gpr = REGARG_FIRSTGPR; gpr <= REGARG_LASTGPR; gpr++) |
234 | as->cost[gpr] = REGCOST(~0u, ASMREF_L); | 261 | as->cost[gpr] = REGCOST(~0u, ASMREF_L); |
235 | gpr = REGARG_FIRSTGPR; | 262 | gpr = REGARG_FIRSTGPR; |
263 | #endif | ||
236 | for (n = 0; n < nargs; n++) { /* Setup args. */ | 264 | for (n = 0; n < nargs; n++) { /* Setup args. */ |
237 | IRRef ref = args[n]; | 265 | IRRef ref = args[n]; |
238 | if (ref) { | 266 | if (ref) { |
239 | IRIns *ir = IR(ref); | 267 | IRIns *ir = IR(ref); |
268 | #if !LJ_SOFTFP | ||
240 | if (irt_isfp(ir->t) && fpr <= REGARG_LASTFPR && | 269 | if (irt_isfp(ir->t) && fpr <= REGARG_LASTFPR && |
241 | !(ci->flags & CCI_VARARG)) { | 270 | !(ci->flags & CCI_VARARG)) { |
242 | lua_assert(rset_test(as->freeset, fpr)); /* Already evicted. */ | 271 | lj_assertA(rset_test(as->freeset, fpr), |
272 | "reg %d not free", fpr); /* Already evicted. */ | ||
243 | ra_leftov(as, fpr, ref); | 273 | ra_leftov(as, fpr, ref); |
244 | fpr += 2; | 274 | fpr += LJ_32 ? 2 : 1; |
245 | gpr += irt_isnum(ir->t) ? 2 : 1; | 275 | gpr += (LJ_32 && irt_isnum(ir->t)) ? 2 : 1; |
246 | } else { | 276 | } else |
277 | #endif | ||
278 | { | ||
279 | #if LJ_32 && !LJ_SOFTFP | ||
247 | fpr = REGARG_LASTFPR+1; | 280 | fpr = REGARG_LASTFPR+1; |
248 | if (irt_isnum(ir->t)) gpr = (gpr+1) & ~1; | 281 | #endif |
282 | if (LJ_32 && irt_isnum(ir->t)) gpr = (gpr+1) & ~1; | ||
249 | if (gpr <= REGARG_LASTGPR) { | 283 | if (gpr <= REGARG_LASTGPR) { |
250 | lua_assert(rset_test(as->freeset, gpr)); /* Already evicted. */ | 284 | lj_assertA(rset_test(as->freeset, gpr), |
285 | "reg %d not free", gpr); /* Already evicted. */ | ||
286 | #if !LJ_SOFTFP | ||
251 | if (irt_isfp(ir->t)) { | 287 | if (irt_isfp(ir->t)) { |
252 | RegSet of = as->freeset; | 288 | RegSet of = as->freeset; |
253 | Reg r; | 289 | Reg r; |
@@ -256,31 +292,56 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) | |||
256 | r = ra_alloc1(as, ref, RSET_FPR); | 292 | r = ra_alloc1(as, ref, RSET_FPR); |
257 | as->freeset |= (of & RSET_RANGE(REGARG_FIRSTGPR, REGARG_LASTGPR+1)); | 293 | as->freeset |= (of & RSET_RANGE(REGARG_FIRSTGPR, REGARG_LASTGPR+1)); |
258 | if (irt_isnum(ir->t)) { | 294 | if (irt_isnum(ir->t)) { |
295 | #if LJ_32 | ||
259 | emit_tg(as, MIPSI_MFC1, gpr+(LJ_BE?0:1), r+1); | 296 | emit_tg(as, MIPSI_MFC1, gpr+(LJ_BE?0:1), r+1); |
260 | emit_tg(as, MIPSI_MFC1, gpr+(LJ_BE?1:0), r); | 297 | emit_tg(as, MIPSI_MFC1, gpr+(LJ_BE?1:0), r); |
261 | lua_assert(rset_test(as->freeset, gpr+1)); /* Already evicted. */ | 298 | lj_assertA(rset_test(as->freeset, gpr+1), |
299 | "reg %d not free", gpr+1); /* Already evicted. */ | ||
262 | gpr += 2; | 300 | gpr += 2; |
301 | #else | ||
302 | emit_tg(as, MIPSI_DMFC1, gpr, r); | ||
303 | gpr++; fpr++; | ||
304 | #endif | ||
263 | } else if (irt_isfloat(ir->t)) { | 305 | } else if (irt_isfloat(ir->t)) { |
264 | emit_tg(as, MIPSI_MFC1, gpr, r); | 306 | emit_tg(as, MIPSI_MFC1, gpr, r); |
265 | gpr++; | 307 | gpr++; |
308 | #if LJ_64 | ||
309 | fpr++; | ||
310 | #endif | ||
266 | } | 311 | } |
267 | } else { | 312 | } else |
313 | #endif | ||
314 | { | ||
268 | ra_leftov(as, gpr, ref); | 315 | ra_leftov(as, gpr, ref); |
269 | gpr++; | 316 | gpr++; |
317 | #if LJ_64 && !LJ_SOFTFP | ||
318 | fpr++; | ||
319 | #endif | ||
270 | } | 320 | } |
271 | } else { | 321 | } else { |
272 | Reg r = ra_alloc1z(as, ref, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); | 322 | Reg r = ra_alloc1z(as, ref, !LJ_SOFTFP && irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); |
323 | #if LJ_32 | ||
273 | if (irt_isnum(ir->t)) ofs = (ofs + 4) & ~4; | 324 | if (irt_isnum(ir->t)) ofs = (ofs + 4) & ~4; |
274 | emit_spstore(as, ir, r, ofs); | 325 | emit_spstore(as, ir, r, ofs); |
275 | ofs += irt_isnum(ir->t) ? 8 : 4; | 326 | ofs += irt_isnum(ir->t) ? 8 : 4; |
327 | #else | ||
328 | emit_spstore(as, ir, r, ofs + ((LJ_BE && !irt_isfp(ir->t) && !irt_is64(ir->t)) ? 4 : 0)); | ||
329 | ofs += 8; | ||
330 | #endif | ||
276 | } | 331 | } |
277 | } | 332 | } |
278 | } else { | 333 | } else { |
334 | #if !LJ_SOFTFP | ||
279 | fpr = REGARG_LASTFPR+1; | 335 | fpr = REGARG_LASTFPR+1; |
280 | if (gpr <= REGARG_LASTGPR) | 336 | #endif |
337 | if (gpr <= REGARG_LASTGPR) { | ||
281 | gpr++; | 338 | gpr++; |
282 | else | 339 | #if LJ_64 && !LJ_SOFTFP |
283 | ofs += 4; | 340 | fpr++; |
341 | #endif | ||
342 | } else { | ||
343 | ofs += LJ_32 ? 4 : 8; | ||
344 | } | ||
284 | } | 345 | } |
285 | checkmclim(as); | 346 | checkmclim(as); |
286 | } | 347 | } |
@@ -291,28 +352,38 @@ static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci) | |||
291 | { | 352 | { |
292 | RegSet drop = RSET_SCRATCH; | 353 | RegSet drop = RSET_SCRATCH; |
293 | int hiop = ((ir+1)->o == IR_HIOP && !irt_isnil((ir+1)->t)); | 354 | int hiop = ((ir+1)->o == IR_HIOP && !irt_isnil((ir+1)->t)); |
355 | #if !LJ_SOFTFP | ||
294 | if ((ci->flags & CCI_NOFPRCLOBBER)) | 356 | if ((ci->flags & CCI_NOFPRCLOBBER)) |
295 | drop &= ~RSET_FPR; | 357 | drop &= ~RSET_FPR; |
358 | #endif | ||
296 | if (ra_hasreg(ir->r)) | 359 | if (ra_hasreg(ir->r)) |
297 | rset_clear(drop, ir->r); /* Dest reg handled below. */ | 360 | rset_clear(drop, ir->r); /* Dest reg handled below. */ |
298 | if (hiop && ra_hasreg((ir+1)->r)) | 361 | if (hiop && ra_hasreg((ir+1)->r)) |
299 | rset_clear(drop, (ir+1)->r); /* Dest reg handled below. */ | 362 | rset_clear(drop, (ir+1)->r); /* Dest reg handled below. */ |
300 | ra_evictset(as, drop); /* Evictions must be performed first. */ | 363 | ra_evictset(as, drop); /* Evictions must be performed first. */ |
301 | if (ra_used(ir)) { | 364 | if (ra_used(ir)) { |
302 | lua_assert(!irt_ispri(ir->t)); | 365 | lj_assertA(!irt_ispri(ir->t), "PRI dest"); |
303 | if (irt_isfp(ir->t)) { | 366 | if (!LJ_SOFTFP && irt_isfp(ir->t)) { |
304 | if ((ci->flags & CCI_CASTU64)) { | 367 | if ((ci->flags & CCI_CASTU64)) { |
305 | int32_t ofs = sps_scale(ir->s); | 368 | int32_t ofs = sps_scale(ir->s); |
306 | Reg dest = ir->r; | 369 | Reg dest = ir->r; |
307 | if (ra_hasreg(dest)) { | 370 | if (ra_hasreg(dest)) { |
308 | ra_free(as, dest); | 371 | ra_free(as, dest); |
309 | ra_modified(as, dest); | 372 | ra_modified(as, dest); |
373 | #if LJ_32 | ||
310 | emit_tg(as, MIPSI_MTC1, RID_RETHI, dest+1); | 374 | emit_tg(as, MIPSI_MTC1, RID_RETHI, dest+1); |
311 | emit_tg(as, MIPSI_MTC1, RID_RETLO, dest); | 375 | emit_tg(as, MIPSI_MTC1, RID_RETLO, dest); |
376 | #else | ||
377 | emit_tg(as, MIPSI_DMTC1, RID_RET, dest); | ||
378 | #endif | ||
312 | } | 379 | } |
313 | if (ofs) { | 380 | if (ofs) { |
381 | #if LJ_32 | ||
314 | emit_tsi(as, MIPSI_SW, RID_RETLO, RID_SP, ofs+(LJ_BE?4:0)); | 382 | emit_tsi(as, MIPSI_SW, RID_RETLO, RID_SP, ofs+(LJ_BE?4:0)); |
315 | emit_tsi(as, MIPSI_SW, RID_RETHI, RID_SP, ofs+(LJ_BE?0:4)); | 383 | emit_tsi(as, MIPSI_SW, RID_RETHI, RID_SP, ofs+(LJ_BE?0:4)); |
384 | #else | ||
385 | emit_tsi(as, MIPSI_SD, RID_RET, RID_SP, ofs); | ||
386 | #endif | ||
316 | } | 387 | } |
317 | } else { | 388 | } else { |
318 | ra_destreg(as, ir, RID_FPRET); | 389 | ra_destreg(as, ir, RID_FPRET); |
@@ -325,15 +396,6 @@ static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci) | |||
325 | } | 396 | } |
326 | } | 397 | } |
327 | 398 | ||
328 | static void asm_call(ASMState *as, IRIns *ir) | ||
329 | { | ||
330 | IRRef args[CCI_NARGS_MAX]; | ||
331 | const CCallInfo *ci = &lj_ir_callinfo[ir->op2]; | ||
332 | asm_collectargs(as, ir, ci, args); | ||
333 | asm_setupresult(as, ir, ci); | ||
334 | asm_gencall(as, ci, args); | ||
335 | } | ||
336 | |||
337 | static void asm_callx(ASMState *as, IRIns *ir) | 399 | static void asm_callx(ASMState *as, IRIns *ir) |
338 | { | 400 | { |
339 | IRRef args[CCI_NARGS_MAX*2]; | 401 | IRRef args[CCI_NARGS_MAX*2]; |
@@ -346,7 +408,7 @@ static void asm_callx(ASMState *as, IRIns *ir) | |||
346 | func = ir->op2; irf = IR(func); | 408 | func = ir->op2; irf = IR(func); |
347 | if (irf->o == IR_CARG) { func = irf->op1; irf = IR(func); } | 409 | if (irf->o == IR_CARG) { func = irf->op1; irf = IR(func); } |
348 | if (irref_isk(func)) { /* Call to constant address. */ | 410 | if (irref_isk(func)) { /* Call to constant address. */ |
349 | ci.func = (ASMFunction)(void *)(irf->i); | 411 | ci.func = (ASMFunction)(void *)get_kval(as, func); |
350 | } else { /* Need specific register for indirect calls. */ | 412 | } else { /* Need specific register for indirect calls. */ |
351 | Reg r = ra_alloc1(as, func, RID2RSET(RID_CFUNCADDR)); | 413 | Reg r = ra_alloc1(as, func, RID2RSET(RID_CFUNCADDR)); |
352 | MCode *p = as->mcp; | 414 | MCode *p = as->mcp; |
@@ -361,27 +423,23 @@ static void asm_callx(ASMState *as, IRIns *ir) | |||
361 | asm_gencall(as, &ci, args); | 423 | asm_gencall(as, &ci, args); |
362 | } | 424 | } |
363 | 425 | ||
364 | static void asm_callid(ASMState *as, IRIns *ir, IRCallID id) | 426 | #if !LJ_SOFTFP |
365 | { | ||
366 | const CCallInfo *ci = &lj_ir_callinfo[id]; | ||
367 | IRRef args[2]; | ||
368 | args[0] = ir->op1; | ||
369 | args[1] = ir->op2; | ||
370 | asm_setupresult(as, ir, ci); | ||
371 | asm_gencall(as, ci, args); | ||
372 | } | ||
373 | |||
374 | static void asm_callround(ASMState *as, IRIns *ir, IRCallID id) | 427 | static void asm_callround(ASMState *as, IRIns *ir, IRCallID id) |
375 | { | 428 | { |
376 | /* The modified regs must match with the *.dasc implementation. */ | 429 | /* The modified regs must match with the *.dasc implementation. */ |
377 | RegSet drop = RID2RSET(RID_R1)|RID2RSET(RID_R12)|RID2RSET(RID_FPRET)| | 430 | RegSet drop = RID2RSET(RID_R1)|RID2RSET(RID_R12)|RID2RSET(RID_FPRET)| |
378 | RID2RSET(RID_F2)|RID2RSET(RID_F4)|RID2RSET(REGARG_FIRSTFPR); | 431 | RID2RSET(RID_F2)|RID2RSET(RID_F4)|RID2RSET(REGARG_FIRSTFPR) |
432 | #if LJ_TARGET_MIPSR6 | ||
433 | |RID2RSET(RID_F21) | ||
434 | #endif | ||
435 | ; | ||
379 | if (ra_hasreg(ir->r)) rset_clear(drop, ir->r); | 436 | if (ra_hasreg(ir->r)) rset_clear(drop, ir->r); |
380 | ra_evictset(as, drop); | 437 | ra_evictset(as, drop); |
381 | ra_destreg(as, ir, RID_FPRET); | 438 | ra_destreg(as, ir, RID_FPRET); |
382 | emit_call(as, (void *)lj_ir_callinfo[id].func); | 439 | emit_call(as, (void *)lj_ir_callinfo[id].func, 0); |
383 | ra_leftov(as, REGARG_FIRSTFPR, ir->op1); | 440 | ra_leftov(as, REGARG_FIRSTFPR, ir->op1); |
384 | } | 441 | } |
442 | #endif | ||
385 | 443 | ||
386 | /* -- Returns ------------------------------------------------------------- */ | 444 | /* -- Returns ------------------------------------------------------------- */ |
387 | 445 | ||
@@ -390,25 +448,52 @@ static void asm_retf(ASMState *as, IRIns *ir) | |||
390 | { | 448 | { |
391 | Reg base = ra_alloc1(as, REF_BASE, RSET_GPR); | 449 | Reg base = ra_alloc1(as, REF_BASE, RSET_GPR); |
392 | void *pc = ir_kptr(IR(ir->op2)); | 450 | void *pc = ir_kptr(IR(ir->op2)); |
393 | int32_t delta = 1+bc_a(*((const BCIns *)pc - 1)); | 451 | int32_t delta = 1+LJ_FR2+bc_a(*((const BCIns *)pc - 1)); |
394 | as->topslot -= (BCReg)delta; | 452 | as->topslot -= (BCReg)delta; |
395 | if ((int32_t)as->topslot < 0) as->topslot = 0; | 453 | if ((int32_t)as->topslot < 0) as->topslot = 0; |
396 | irt_setmark(IR(REF_BASE)->t); /* Children must not coalesce with BASE reg. */ | 454 | irt_setmark(IR(REF_BASE)->t); /* Children must not coalesce with BASE reg. */ |
397 | emit_setgl(as, base, jit_base); | 455 | emit_setgl(as, base, jit_base); |
398 | emit_addptr(as, base, -8*delta); | 456 | emit_addptr(as, base, -8*delta); |
399 | asm_guard(as, MIPSI_BNE, RID_TMP, | 457 | asm_guard(as, MIPSI_BNE, RID_TMP, |
400 | ra_allock(as, i32ptr(pc), rset_exclude(RSET_GPR, base))); | 458 | ra_allock(as, igcptr(pc), rset_exclude(RSET_GPR, base))); |
401 | emit_tsi(as, MIPSI_LW, RID_TMP, base, -8); | 459 | emit_tsi(as, MIPSI_AL, RID_TMP, base, -8); |
402 | } | 460 | } |
403 | 461 | ||
462 | /* -- Buffer operations --------------------------------------------------- */ | ||
463 | |||
464 | #if LJ_HASBUFFER | ||
465 | static void asm_bufhdr_write(ASMState *as, Reg sb) | ||
466 | { | ||
467 | Reg tmp = ra_scratch(as, rset_exclude(RSET_GPR, sb)); | ||
468 | IRIns irgc; | ||
469 | irgc.ot = IRT(0, IRT_PGC); /* GC type. */ | ||
470 | emit_storeofs(as, &irgc, RID_TMP, sb, offsetof(SBuf, L)); | ||
471 | if ((as->flags & JIT_F_MIPSXXR2)) { | ||
472 | emit_tsml(as, LJ_64 ? MIPSI_DINS : MIPSI_INS, RID_TMP, tmp, | ||
473 | lj_fls(SBUF_MASK_FLAG), 0); | ||
474 | } else { | ||
475 | emit_dst(as, MIPSI_OR, RID_TMP, RID_TMP, tmp); | ||
476 | emit_tsi(as, MIPSI_ANDI, tmp, tmp, SBUF_MASK_FLAG); | ||
477 | } | ||
478 | emit_getgl(as, RID_TMP, cur_L); | ||
479 | emit_loadofs(as, &irgc, tmp, sb, offsetof(SBuf, L)); | ||
480 | } | ||
481 | #endif | ||
482 | |||
404 | /* -- Type conversions ---------------------------------------------------- */ | 483 | /* -- Type conversions ---------------------------------------------------- */ |
405 | 484 | ||
485 | #if !LJ_SOFTFP | ||
406 | static void asm_tointg(ASMState *as, IRIns *ir, Reg left) | 486 | static void asm_tointg(ASMState *as, IRIns *ir, Reg left) |
407 | { | 487 | { |
408 | Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left)); | 488 | Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left)); |
409 | Reg dest = ra_dest(as, ir, RSET_GPR); | 489 | Reg dest = ra_dest(as, ir, RSET_GPR); |
490 | #if !LJ_TARGET_MIPSR6 | ||
410 | asm_guard(as, MIPSI_BC1F, 0, 0); | 491 | asm_guard(as, MIPSI_BC1F, 0, 0); |
411 | emit_fgh(as, MIPSI_C_EQ_D, 0, tmp, left); | 492 | emit_fgh(as, MIPSI_C_EQ_D, 0, tmp, left); |
493 | #else | ||
494 | asm_guard(as, MIPSI_BC1EQZ, 0, (tmp&31)); | ||
495 | emit_fgh(as, MIPSI_CMP_EQ_D, tmp, tmp, left); | ||
496 | #endif | ||
412 | emit_fg(as, MIPSI_CVT_D_W, tmp, tmp); | 497 | emit_fg(as, MIPSI_CVT_D_W, tmp, tmp); |
413 | emit_tg(as, MIPSI_MFC1, dest, tmp); | 498 | emit_tg(as, MIPSI_MFC1, dest, tmp); |
414 | emit_fg(as, MIPSI_CVT_W_D, tmp, left); | 499 | emit_fg(as, MIPSI_CVT_W_D, tmp, left); |
@@ -424,15 +509,57 @@ static void asm_tobit(ASMState *as, IRIns *ir) | |||
424 | emit_tg(as, MIPSI_MFC1, dest, tmp); | 509 | emit_tg(as, MIPSI_MFC1, dest, tmp); |
425 | emit_fgh(as, MIPSI_ADD_D, tmp, left, right); | 510 | emit_fgh(as, MIPSI_ADD_D, tmp, left, right); |
426 | } | 511 | } |
512 | #elif LJ_64 /* && LJ_SOFTFP */ | ||
513 | static void asm_tointg(ASMState *as, IRIns *ir, Reg r) | ||
514 | { | ||
515 | /* The modified regs must match with the *.dasc implementation. */ | ||
516 | RegSet drop = RID2RSET(REGARG_FIRSTGPR)|RID2RSET(RID_RET)|RID2RSET(RID_RET+1)| | ||
517 | RID2RSET(RID_R1)|RID2RSET(RID_R12); | ||
518 | if (ra_hasreg(ir->r)) rset_clear(drop, ir->r); | ||
519 | ra_evictset(as, drop); | ||
520 | /* Return values are in RID_RET (converted value) and RID_RET+1 (status). */ | ||
521 | ra_destreg(as, ir, RID_RET); | ||
522 | asm_guard(as, MIPSI_BNE, RID_RET+1, RID_ZERO); | ||
523 | emit_call(as, (void *)lj_ir_callinfo[IRCALL_lj_vm_tointg].func, 0); | ||
524 | if (r == RID_NONE) | ||
525 | ra_leftov(as, REGARG_FIRSTGPR, ir->op1); | ||
526 | else if (r != REGARG_FIRSTGPR) | ||
527 | emit_move(as, REGARG_FIRSTGPR, r); | ||
528 | } | ||
529 | |||
530 | static void asm_tobit(ASMState *as, IRIns *ir) | ||
531 | { | ||
532 | Reg dest = ra_dest(as, ir, RSET_GPR); | ||
533 | emit_dta(as, MIPSI_SLL, dest, dest, 0); | ||
534 | asm_callid(as, ir, IRCALL_lj_vm_tobit); | ||
535 | } | ||
536 | #endif | ||
427 | 537 | ||
428 | static void asm_conv(ASMState *as, IRIns *ir) | 538 | static void asm_conv(ASMState *as, IRIns *ir) |
429 | { | 539 | { |
430 | IRType st = (IRType)(ir->op2 & IRCONV_SRCMASK); | 540 | IRType st = (IRType)(ir->op2 & IRCONV_SRCMASK); |
541 | #if !LJ_SOFTFP32 | ||
431 | int stfp = (st == IRT_NUM || st == IRT_FLOAT); | 542 | int stfp = (st == IRT_NUM || st == IRT_FLOAT); |
543 | #endif | ||
544 | #if LJ_64 | ||
545 | int st64 = (st == IRT_I64 || st == IRT_U64 || st == IRT_P64); | ||
546 | #endif | ||
432 | IRRef lref = ir->op1; | 547 | IRRef lref = ir->op1; |
433 | lua_assert(irt_type(ir->t) != st); | 548 | #if LJ_32 |
434 | lua_assert(!(irt_isint64(ir->t) || | 549 | /* 64 bit integer conversions are handled by SPLIT. */ |
435 | (st == IRT_I64 || st == IRT_U64))); /* Handled by SPLIT. */ | 550 | lj_assertA(!(irt_isint64(ir->t) || (st == IRT_I64 || st == IRT_U64)), |
551 | "IR %04d has unsplit 64 bit type", | ||
552 | (int)(ir - as->ir) - REF_BIAS); | ||
553 | #endif | ||
554 | #if LJ_SOFTFP32 | ||
555 | /* FP conversions are handled by SPLIT. */ | ||
556 | lj_assertA(!irt_isfp(ir->t) && !(st == IRT_NUM || st == IRT_FLOAT), | ||
557 | "IR %04d has FP type", | ||
558 | (int)(ir - as->ir) - REF_BIAS); | ||
559 | /* Can't check for same types: SPLIT uses CONV int.int + BXOR for sfp NEG. */ | ||
560 | #else | ||
561 | lj_assertA(irt_type(ir->t) != st, "inconsistent types for CONV"); | ||
562 | #if !LJ_SOFTFP | ||
436 | if (irt_isfp(ir->t)) { | 563 | if (irt_isfp(ir->t)) { |
437 | Reg dest = ra_dest(as, ir, RSET_FPR); | 564 | Reg dest = ra_dest(as, ir, RSET_FPR); |
438 | if (stfp) { /* FP to FP conversion. */ | 565 | if (stfp) { /* FP to FP conversion. */ |
@@ -448,27 +575,56 @@ static void asm_conv(ASMState *as, IRIns *ir) | |||
448 | emit_fgh(as, MIPSI_ADD_D, dest, dest, tmp); | 575 | emit_fgh(as, MIPSI_ADD_D, dest, dest, tmp); |
449 | emit_fg(as, MIPSI_CVT_D_W, dest, dest); | 576 | emit_fg(as, MIPSI_CVT_D_W, dest, dest); |
450 | emit_lsptr(as, MIPSI_LDC1, (tmp & 31), | 577 | emit_lsptr(as, MIPSI_LDC1, (tmp & 31), |
451 | (void *)lj_ir_k64_find(as->J, U64x(41e00000,00000000)), | 578 | (void *)&as->J->k64[LJ_K64_2P31], RSET_GPR); |
452 | RSET_GPR); | ||
453 | emit_tg(as, MIPSI_MTC1, RID_TMP, dest); | 579 | emit_tg(as, MIPSI_MTC1, RID_TMP, dest); |
454 | emit_dst(as, MIPSI_XOR, RID_TMP, RID_TMP, left); | 580 | emit_dst(as, MIPSI_XOR, RID_TMP, RID_TMP, left); |
455 | emit_ti(as, MIPSI_LUI, RID_TMP, 0x8000); | 581 | emit_ti(as, MIPSI_LUI, RID_TMP, 0x8000); |
582 | #if LJ_64 | ||
583 | } else if(st == IRT_U64) { /* U64 to FP conversion. */ | ||
584 | /* if (x >= 1u<<63) y = (double)(int64_t)(x&(1u<<63)-1) + pow(2.0, 63) */ | ||
585 | Reg left = ra_alloc1(as, lref, RSET_GPR); | ||
586 | Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, dest)); | ||
587 | MCLabel l_end = emit_label(as); | ||
588 | if (irt_isfloat(ir->t)) { | ||
589 | emit_fgh(as, MIPSI_ADD_S, dest, dest, tmp); | ||
590 | emit_lsptr(as, MIPSI_LWC1, (tmp & 31), (void *)&as->J->k32[LJ_K32_2P63], | ||
591 | rset_exclude(RSET_GPR, left)); | ||
592 | emit_fg(as, MIPSI_CVT_S_L, dest, dest); | ||
593 | } else { | ||
594 | emit_fgh(as, MIPSI_ADD_D, dest, dest, tmp); | ||
595 | emit_lsptr(as, MIPSI_LDC1, (tmp & 31), (void *)&as->J->k64[LJ_K64_2P63], | ||
596 | rset_exclude(RSET_GPR, left)); | ||
597 | emit_fg(as, MIPSI_CVT_D_L, dest, dest); | ||
598 | } | ||
599 | emit_branch(as, MIPSI_BGEZ, left, RID_ZERO, l_end); | ||
600 | emit_tg(as, MIPSI_DMTC1, RID_TMP, dest); | ||
601 | emit_tsml(as, MIPSI_DEXTM, RID_TMP, left, 30, 0); | ||
602 | #endif | ||
456 | } else { /* Integer to FP conversion. */ | 603 | } else { /* Integer to FP conversion. */ |
457 | Reg left = ra_alloc1(as, lref, RSET_GPR); | 604 | Reg left = ra_alloc1(as, lref, RSET_GPR); |
605 | #if LJ_32 | ||
458 | emit_fg(as, irt_isfloat(ir->t) ? MIPSI_CVT_S_W : MIPSI_CVT_D_W, | 606 | emit_fg(as, irt_isfloat(ir->t) ? MIPSI_CVT_S_W : MIPSI_CVT_D_W, |
459 | dest, dest); | 607 | dest, dest); |
460 | emit_tg(as, MIPSI_MTC1, left, dest); | 608 | emit_tg(as, MIPSI_MTC1, left, dest); |
609 | #else | ||
610 | MIPSIns mi = irt_isfloat(ir->t) ? | ||
611 | (st64 ? MIPSI_CVT_S_L : MIPSI_CVT_S_W) : | ||
612 | (st64 ? MIPSI_CVT_D_L : MIPSI_CVT_D_W); | ||
613 | emit_fg(as, mi, dest, dest); | ||
614 | emit_tg(as, st64 ? MIPSI_DMTC1 : MIPSI_MTC1, left, dest); | ||
615 | #endif | ||
461 | } | 616 | } |
462 | } else if (stfp) { /* FP to integer conversion. */ | 617 | } else if (stfp) { /* FP to integer conversion. */ |
463 | if (irt_isguard(ir->t)) { | 618 | if (irt_isguard(ir->t)) { |
464 | /* Checked conversions are only supported from number to int. */ | 619 | /* Checked conversions are only supported from number to int. */ |
465 | lua_assert(irt_isint(ir->t) && st == IRT_NUM); | 620 | lj_assertA(irt_isint(ir->t) && st == IRT_NUM, |
621 | "bad type for checked CONV"); | ||
466 | asm_tointg(as, ir, ra_alloc1(as, lref, RSET_FPR)); | 622 | asm_tointg(as, ir, ra_alloc1(as, lref, RSET_FPR)); |
467 | } else { | 623 | } else { |
468 | Reg dest = ra_dest(as, ir, RSET_GPR); | 624 | Reg dest = ra_dest(as, ir, RSET_GPR); |
469 | Reg left = ra_alloc1(as, lref, RSET_FPR); | 625 | Reg left = ra_alloc1(as, lref, RSET_FPR); |
470 | Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left)); | 626 | Reg tmp = ra_scratch(as, rset_exclude(RSET_FPR, left)); |
471 | if (irt_isu32(ir->t)) { | 627 | if (irt_isu32(ir->t)) { /* FP to U32 conversion. */ |
472 | /* y = (int)floor(x - 2147483648.0) ^ 0x80000000 */ | 628 | /* y = (int)floor(x - 2147483648.0) ^ 0x80000000 */ |
473 | emit_dst(as, MIPSI_XOR, dest, dest, RID_TMP); | 629 | emit_dst(as, MIPSI_XOR, dest, dest, RID_TMP); |
474 | emit_ti(as, MIPSI_LUI, RID_TMP, 0x8000); | 630 | emit_ti(as, MIPSI_LUI, RID_TMP, 0x8000); |
@@ -479,25 +635,112 @@ static void asm_conv(ASMState *as, IRIns *ir) | |||
479 | tmp, left, tmp); | 635 | tmp, left, tmp); |
480 | if (st == IRT_FLOAT) | 636 | if (st == IRT_FLOAT) |
481 | emit_lsptr(as, MIPSI_LWC1, (tmp & 31), | 637 | emit_lsptr(as, MIPSI_LWC1, (tmp & 31), |
482 | (void *)lj_ir_k64_find(as->J, U64x(4f000000,4f000000)), | 638 | (void *)&as->J->k32[LJ_K32_2P31], RSET_GPR); |
483 | RSET_GPR); | ||
484 | else | 639 | else |
485 | emit_lsptr(as, MIPSI_LDC1, (tmp & 31), | 640 | emit_lsptr(as, MIPSI_LDC1, (tmp & 31), |
486 | (void *)lj_ir_k64_find(as->J, U64x(41e00000,00000000)), | 641 | (void *)&as->J->k64[LJ_K64_2P31], RSET_GPR); |
487 | RSET_GPR); | 642 | #if LJ_64 |
643 | } else if (irt_isu64(ir->t)) { /* FP to U64 conversion. */ | ||
644 | MCLabel l_end; | ||
645 | emit_tg(as, MIPSI_DMFC1, dest, tmp); | ||
646 | l_end = emit_label(as); | ||
647 | /* For inputs >= 2^63 add -2^64 and convert again. */ | ||
648 | if (st == IRT_NUM) { | ||
649 | emit_fg(as, MIPSI_TRUNC_L_D, tmp, tmp); | ||
650 | emit_fgh(as, MIPSI_ADD_D, tmp, left, tmp); | ||
651 | emit_lsptr(as, MIPSI_LDC1, (tmp & 31), | ||
652 | (void *)&as->J->k64[LJ_K64_M2P64], | ||
653 | rset_exclude(RSET_GPR, dest)); | ||
654 | emit_fg(as, MIPSI_TRUNC_L_D, tmp, left); /* Delay slot. */ | ||
655 | #if !LJ_TARGET_MIPSR6 | ||
656 | emit_branch(as, MIPSI_BC1T, 0, 0, l_end); | ||
657 | emit_fgh(as, MIPSI_C_OLT_D, 0, left, tmp); | ||
658 | #else | ||
659 | emit_branch(as, MIPSI_BC1NEZ, 0, (left&31), l_end); | ||
660 | emit_fgh(as, MIPSI_CMP_LT_D, left, left, tmp); | ||
661 | #endif | ||
662 | emit_lsptr(as, MIPSI_LDC1, (tmp & 31), | ||
663 | (void *)&as->J->k64[LJ_K64_2P63], | ||
664 | rset_exclude(RSET_GPR, dest)); | ||
665 | } else { | ||
666 | emit_fg(as, MIPSI_TRUNC_L_S, tmp, tmp); | ||
667 | emit_fgh(as, MIPSI_ADD_S, tmp, left, tmp); | ||
668 | emit_lsptr(as, MIPSI_LWC1, (tmp & 31), | ||
669 | (void *)&as->J->k32[LJ_K32_M2P64], | ||
670 | rset_exclude(RSET_GPR, dest)); | ||
671 | emit_fg(as, MIPSI_TRUNC_L_S, tmp, left); /* Delay slot. */ | ||
672 | #if !LJ_TARGET_MIPSR6 | ||
673 | emit_branch(as, MIPSI_BC1T, 0, 0, l_end); | ||
674 | emit_fgh(as, MIPSI_C_OLT_S, 0, left, tmp); | ||
675 | #else | ||
676 | emit_branch(as, MIPSI_BC1NEZ, 0, (left&31), l_end); | ||
677 | emit_fgh(as, MIPSI_CMP_LT_S, left, left, tmp); | ||
678 | #endif | ||
679 | emit_lsptr(as, MIPSI_LWC1, (tmp & 31), | ||
680 | (void *)&as->J->k32[LJ_K32_2P63], | ||
681 | rset_exclude(RSET_GPR, dest)); | ||
682 | } | ||
683 | #endif | ||
488 | } else { | 684 | } else { |
685 | #if LJ_32 | ||
489 | emit_tg(as, MIPSI_MFC1, dest, tmp); | 686 | emit_tg(as, MIPSI_MFC1, dest, tmp); |
490 | emit_fg(as, st == IRT_FLOAT ? MIPSI_TRUNC_W_S : MIPSI_TRUNC_W_D, | 687 | emit_fg(as, st == IRT_FLOAT ? MIPSI_TRUNC_W_S : MIPSI_TRUNC_W_D, |
491 | tmp, left); | 688 | tmp, left); |
689 | #else | ||
690 | MIPSIns mi = irt_is64(ir->t) ? | ||
691 | (st == IRT_NUM ? MIPSI_TRUNC_L_D : MIPSI_TRUNC_L_S) : | ||
692 | (st == IRT_NUM ? MIPSI_TRUNC_W_D : MIPSI_TRUNC_W_S); | ||
693 | emit_tg(as, irt_is64(ir->t) ? MIPSI_DMFC1 : MIPSI_MFC1, dest, left); | ||
694 | emit_fg(as, mi, left, left); | ||
695 | #endif | ||
492 | } | 696 | } |
493 | } | 697 | } |
494 | } else { | 698 | } else |
699 | #else | ||
700 | if (irt_isfp(ir->t)) { | ||
701 | #if LJ_64 && LJ_HASFFI | ||
702 | if (stfp) { /* FP to FP conversion. */ | ||
703 | asm_callid(as, ir, irt_isnum(ir->t) ? IRCALL_softfp_f2d : | ||
704 | IRCALL_softfp_d2f); | ||
705 | } else { /* Integer to FP conversion. */ | ||
706 | IRCallID cid = ((IRT_IS64 >> st) & 1) ? | ||
707 | (irt_isnum(ir->t) ? | ||
708 | (st == IRT_I64 ? IRCALL_fp64_l2d : IRCALL_fp64_ul2d) : | ||
709 | (st == IRT_I64 ? IRCALL_fp64_l2f : IRCALL_fp64_ul2f)) : | ||
710 | (irt_isnum(ir->t) ? | ||
711 | (st == IRT_INT ? IRCALL_softfp_i2d : IRCALL_softfp_ui2d) : | ||
712 | (st == IRT_INT ? IRCALL_softfp_i2f : IRCALL_softfp_ui2f)); | ||
713 | asm_callid(as, ir, cid); | ||
714 | } | ||
715 | #else | ||
716 | asm_callid(as, ir, IRCALL_softfp_i2d); | ||
717 | #endif | ||
718 | } else if (stfp) { /* FP to integer conversion. */ | ||
719 | if (irt_isguard(ir->t)) { | ||
720 | /* Checked conversions are only supported from number to int. */ | ||
721 | lj_assertA(irt_isint(ir->t) && st == IRT_NUM, | ||
722 | "bad type for checked CONV"); | ||
723 | asm_tointg(as, ir, RID_NONE); | ||
724 | } else { | ||
725 | IRCallID cid = irt_is64(ir->t) ? | ||
726 | ((st == IRT_NUM) ? | ||
727 | (irt_isi64(ir->t) ? IRCALL_fp64_d2l : IRCALL_fp64_d2ul) : | ||
728 | (irt_isi64(ir->t) ? IRCALL_fp64_f2l : IRCALL_fp64_f2ul)) : | ||
729 | ((st == IRT_NUM) ? | ||
730 | (irt_isint(ir->t) ? IRCALL_softfp_d2i : IRCALL_softfp_d2ui) : | ||
731 | (irt_isint(ir->t) ? IRCALL_softfp_f2i : IRCALL_softfp_f2ui)); | ||
732 | asm_callid(as, ir, cid); | ||
733 | } | ||
734 | } else | ||
735 | #endif | ||
736 | #endif | ||
737 | { | ||
495 | Reg dest = ra_dest(as, ir, RSET_GPR); | 738 | Reg dest = ra_dest(as, ir, RSET_GPR); |
496 | if (st >= IRT_I8 && st <= IRT_U16) { /* Extend to 32 bit integer. */ | 739 | if (st >= IRT_I8 && st <= IRT_U16) { /* Extend to 32 bit integer. */ |
497 | Reg left = ra_alloc1(as, ir->op1, RSET_GPR); | 740 | Reg left = ra_alloc1(as, ir->op1, RSET_GPR); |
498 | lua_assert(irt_isint(ir->t) || irt_isu32(ir->t)); | 741 | lj_assertA(irt_isint(ir->t) || irt_isu32(ir->t), "bad type for CONV EXT"); |
499 | if ((ir->op2 & IRCONV_SEXT)) { | 742 | if ((ir->op2 & IRCONV_SEXT)) { |
500 | if ((as->flags & JIT_F_MIPS32R2)) { | 743 | if (LJ_64 || (as->flags & JIT_F_MIPSXXR2)) { |
501 | emit_dst(as, st == IRT_I8 ? MIPSI_SEB : MIPSI_SEH, dest, 0, left); | 744 | emit_dst(as, st == IRT_I8 ? MIPSI_SEB : MIPSI_SEH, dest, 0, left); |
502 | } else { | 745 | } else { |
503 | uint32_t shift = st == IRT_I8 ? 24 : 16; | 746 | uint32_t shift = st == IRT_I8 ? 24 : 16; |
@@ -509,94 +752,171 @@ static void asm_conv(ASMState *as, IRIns *ir) | |||
509 | (int32_t)(st == IRT_U8 ? 0xff : 0xffff)); | 752 | (int32_t)(st == IRT_U8 ? 0xff : 0xffff)); |
510 | } | 753 | } |
511 | } else { /* 32/64 bit integer conversions. */ | 754 | } else { /* 32/64 bit integer conversions. */ |
755 | #if LJ_32 | ||
512 | /* Only need to handle 32/32 bit no-op (cast) on 32 bit archs. */ | 756 | /* Only need to handle 32/32 bit no-op (cast) on 32 bit archs. */ |
513 | ra_leftov(as, dest, lref); /* Do nothing, but may need to move regs. */ | 757 | ra_leftov(as, dest, lref); /* Do nothing, but may need to move regs. */ |
758 | #else | ||
759 | if (irt_is64(ir->t)) { | ||
760 | if (st64) { | ||
761 | /* 64/64 bit no-op (cast)*/ | ||
762 | ra_leftov(as, dest, lref); | ||
763 | } else { | ||
764 | Reg left = ra_alloc1(as, lref, RSET_GPR); | ||
765 | if ((ir->op2 & IRCONV_SEXT)) { /* 32 to 64 bit sign extension. */ | ||
766 | emit_dta(as, MIPSI_SLL, dest, left, 0); | ||
767 | } else { /* 32 to 64 bit zero extension. */ | ||
768 | emit_tsml(as, MIPSI_DEXT, dest, left, 31, 0); | ||
769 | } | ||
770 | } | ||
771 | } else { | ||
772 | if (st64 && !(ir->op2 & IRCONV_NONE)) { | ||
773 | /* This is either a 32 bit reg/reg mov which zeroes the hiword | ||
774 | ** or a load of the loword from a 64 bit address. | ||
775 | */ | ||
776 | Reg left = ra_alloc1(as, lref, RSET_GPR); | ||
777 | emit_tsml(as, MIPSI_DEXT, dest, left, 31, 0); | ||
778 | } else { /* 32/32 bit no-op (cast). */ | ||
779 | /* Do nothing, but may need to move regs. */ | ||
780 | ra_leftov(as, dest, lref); | ||
781 | } | ||
782 | } | ||
783 | #endif | ||
514 | } | 784 | } |
515 | } | 785 | } |
516 | } | 786 | } |
517 | 787 | ||
518 | #if LJ_HASFFI | ||
519 | static void asm_conv64(ASMState *as, IRIns *ir) | ||
520 | { | ||
521 | IRType st = (IRType)((ir-1)->op2 & IRCONV_SRCMASK); | ||
522 | IRType dt = (((ir-1)->op2 & IRCONV_DSTMASK) >> IRCONV_DSH); | ||
523 | IRCallID id; | ||
524 | const CCallInfo *ci; | ||
525 | IRRef args[2]; | ||
526 | args[LJ_BE?0:1] = ir->op1; | ||
527 | args[LJ_BE?1:0] = (ir-1)->op1; | ||
528 | if (st == IRT_NUM || st == IRT_FLOAT) { | ||
529 | id = IRCALL_fp64_d2l + ((st == IRT_FLOAT) ? 2 : 0) + (dt - IRT_I64); | ||
530 | ir--; | ||
531 | } else { | ||
532 | id = IRCALL_fp64_l2d + ((dt == IRT_FLOAT) ? 2 : 0) + (st - IRT_I64); | ||
533 | } | ||
534 | ci = &lj_ir_callinfo[id]; | ||
535 | asm_setupresult(as, ir, ci); | ||
536 | asm_gencall(as, ci, args); | ||
537 | } | ||
538 | #endif | ||
539 | |||
540 | static void asm_strto(ASMState *as, IRIns *ir) | 788 | static void asm_strto(ASMState *as, IRIns *ir) |
541 | { | 789 | { |
542 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_strscan_num]; | 790 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_strscan_num]; |
543 | IRRef args[2]; | 791 | IRRef args[2]; |
792 | int32_t ofs = 0; | ||
793 | #if LJ_SOFTFP32 | ||
794 | ra_evictset(as, RSET_SCRATCH); | ||
795 | if (ra_used(ir)) { | ||
796 | if (ra_hasspill(ir->s) && ra_hasspill((ir+1)->s) && | ||
797 | (ir->s & 1) == LJ_BE && (ir->s ^ 1) == (ir+1)->s) { | ||
798 | int i; | ||
799 | for (i = 0; i < 2; i++) { | ||
800 | Reg r = (ir+i)->r; | ||
801 | if (ra_hasreg(r)) { | ||
802 | ra_free(as, r); | ||
803 | ra_modified(as, r); | ||
804 | emit_spload(as, ir+i, r, sps_scale((ir+i)->s)); | ||
805 | } | ||
806 | } | ||
807 | ofs = sps_scale(ir->s & ~1); | ||
808 | } else { | ||
809 | Reg rhi = ra_dest(as, ir+1, RSET_GPR); | ||
810 | Reg rlo = ra_dest(as, ir, rset_exclude(RSET_GPR, rhi)); | ||
811 | emit_tsi(as, MIPSI_LW, rhi, RID_SP, ofs+(LJ_BE?0:4)); | ||
812 | emit_tsi(as, MIPSI_LW, rlo, RID_SP, ofs+(LJ_BE?4:0)); | ||
813 | } | ||
814 | } | ||
815 | #else | ||
544 | RegSet drop = RSET_SCRATCH; | 816 | RegSet drop = RSET_SCRATCH; |
545 | if (ra_hasreg(ir->r)) rset_set(drop, ir->r); /* Spill dest reg (if any). */ | 817 | if (ra_hasreg(ir->r)) rset_set(drop, ir->r); /* Spill dest reg (if any). */ |
546 | ra_evictset(as, drop); | 818 | ra_evictset(as, drop); |
819 | ofs = sps_scale(ir->s); | ||
820 | #endif | ||
547 | asm_guard(as, MIPSI_BEQ, RID_RET, RID_ZERO); /* Test return status. */ | 821 | asm_guard(as, MIPSI_BEQ, RID_RET, RID_ZERO); /* Test return status. */ |
548 | args[0] = ir->op1; /* GCstr *str */ | 822 | args[0] = ir->op1; /* GCstr *str */ |
549 | args[1] = ASMREF_TMP1; /* TValue *n */ | 823 | args[1] = ASMREF_TMP1; /* TValue *n */ |
550 | asm_gencall(as, ci, args); | 824 | asm_gencall(as, ci, args); |
551 | /* Store the result to the spill slot or temp slots. */ | 825 | /* Store the result to the spill slot or temp slots. */ |
552 | emit_tsi(as, MIPSI_ADDIU, ra_releasetmp(as, ASMREF_TMP1), | 826 | emit_tsi(as, MIPSI_AADDIU, ra_releasetmp(as, ASMREF_TMP1), |
553 | RID_SP, sps_scale(ir->s)); | 827 | RID_SP, ofs); |
554 | } | 828 | } |
555 | 829 | ||
556 | /* Get pointer to TValue. */ | 830 | /* -- Memory references --------------------------------------------------- */ |
557 | static void asm_tvptr(ASMState *as, Reg dest, IRRef ref) | 831 | |
832 | #if LJ_64 | ||
833 | /* Store tagged value for ref at base+ofs. */ | ||
834 | static void asm_tvstore64(ASMState *as, Reg base, int32_t ofs, IRRef ref) | ||
558 | { | 835 | { |
836 | RegSet allow = rset_exclude(RSET_GPR, base); | ||
559 | IRIns *ir = IR(ref); | 837 | IRIns *ir = IR(ref); |
560 | if (irt_isnum(ir->t)) { | 838 | lj_assertA(irt_ispri(ir->t) || irt_isaddr(ir->t) || irt_isinteger(ir->t), |
561 | if (irref_isk(ref)) /* Use the number constant itself as a TValue. */ | 839 | "store of IR type %d", irt_type(ir->t)); |
562 | ra_allockreg(as, i32ptr(ir_knum(ir)), dest); | 840 | if (irref_isk(ref)) { |
563 | else /* Otherwise force a spill and use the spill slot. */ | 841 | TValue k; |
564 | emit_tsi(as, MIPSI_ADDIU, dest, RID_SP, ra_spill(as, ir)); | 842 | lj_ir_kvalue(as->J->L, &k, ir); |
843 | emit_tsi(as, MIPSI_SD, ra_allock(as, (int64_t)k.u64, allow), base, ofs); | ||
565 | } else { | 844 | } else { |
566 | /* Otherwise use g->tmptv to hold the TValue. */ | 845 | Reg src = ra_alloc1(as, ref, allow); |
567 | RegSet allow = rset_exclude(RSET_GPR, dest); | 846 | Reg type = ra_allock(as, (int64_t)irt_toitype(ir->t) << 47, |
568 | Reg type; | 847 | rset_exclude(allow, src)); |
569 | emit_tsi(as, MIPSI_ADDIU, dest, RID_JGL, offsetof(global_State, tmptv)-32768); | 848 | emit_tsi(as, MIPSI_SD, RID_TMP, base, ofs); |
570 | if (!irt_ispri(ir->t)) { | 849 | if (irt_isinteger(ir->t)) { |
571 | Reg src = ra_alloc1(as, ref, allow); | 850 | emit_dst(as, MIPSI_DADDU, RID_TMP, RID_TMP, type); |
572 | emit_setgl(as, src, tmptv.gcr); | 851 | emit_tsml(as, MIPSI_DEXT, RID_TMP, src, 31, 0); |
852 | } else { | ||
853 | emit_dst(as, MIPSI_DADDU, RID_TMP, src, type); | ||
573 | } | 854 | } |
574 | type = ra_allock(as, irt_toitype(ir->t), allow); | ||
575 | emit_setgl(as, type, tmptv.it); | ||
576 | } | 855 | } |
577 | } | 856 | } |
857 | #endif | ||
578 | 858 | ||
579 | static void asm_tostr(ASMState *as, IRIns *ir) | 859 | /* Get pointer to TValue. */ |
860 | static void asm_tvptr(ASMState *as, Reg dest, IRRef ref, MSize mode) | ||
580 | { | 861 | { |
581 | IRRef args[2]; | 862 | int32_t tmpofs = (int32_t)(offsetof(global_State, tmptv)-32768); |
582 | args[0] = ASMREF_L; | 863 | if ((mode & IRTMPREF_IN1)) { |
583 | as->gcsteps++; | 864 | IRIns *ir = IR(ref); |
584 | if (irt_isnum(IR(ir->op1)->t) || (ir+1)->o == IR_HIOP) { | 865 | if (irt_isnum(ir->t)) { |
585 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_str_fromnum]; | 866 | if ((mode & IRTMPREF_OUT1)) { |
586 | args[1] = ASMREF_TMP1; /* const lua_Number * */ | 867 | #if LJ_SOFTFP |
587 | asm_setupresult(as, ir, ci); /* GCstr * */ | 868 | emit_tsi(as, MIPSI_AADDIU, dest, RID_JGL, tmpofs); |
588 | asm_gencall(as, ci, args); | 869 | #if LJ_64 |
589 | asm_tvptr(as, ra_releasetmp(as, ASMREF_TMP1), ir->op1); | 870 | emit_setgl(as, ra_alloc1(as, ref, RSET_GPR), tmptv.u64); |
871 | #else | ||
872 | lj_assertA(irref_isk(ref), "unsplit FP op"); | ||
873 | emit_setgl(as, | ||
874 | ra_allock(as, (int32_t)ir_knum(ir)->u32.lo, RSET_GPR), | ||
875 | tmptv.u32.lo); | ||
876 | emit_setgl(as, | ||
877 | ra_allock(as, (int32_t)ir_knum(ir)->u32.hi, RSET_GPR), | ||
878 | tmptv.u32.hi); | ||
879 | #endif | ||
880 | #else | ||
881 | Reg src = ra_alloc1(as, ref, RSET_FPR); | ||
882 | emit_tsi(as, MIPSI_AADDIU, dest, RID_JGL, tmpofs); | ||
883 | emit_tsi(as, MIPSI_SDC1, (src & 31), RID_JGL, tmpofs); | ||
884 | #endif | ||
885 | } else if (irref_isk(ref)) { | ||
886 | /* Use the number constant itself as a TValue. */ | ||
887 | ra_allockreg(as, igcptr(ir_knum(ir)), dest); | ||
888 | } else { | ||
889 | #if LJ_SOFTFP32 | ||
890 | lj_assertA(0, "unsplit FP op"); | ||
891 | #else | ||
892 | /* Otherwise force a spill and use the spill slot. */ | ||
893 | emit_tsi(as, MIPSI_AADDIU, dest, RID_SP, ra_spill(as, ir)); | ||
894 | #endif | ||
895 | } | ||
896 | } else { | ||
897 | /* Otherwise use g->tmptv to hold the TValue. */ | ||
898 | #if LJ_32 | ||
899 | Reg type; | ||
900 | emit_tsi(as, MIPSI_ADDIU, dest, RID_JGL, tmpofs); | ||
901 | if (!irt_ispri(ir->t)) { | ||
902 | Reg src = ra_alloc1(as, ref, RSET_GPR); | ||
903 | emit_setgl(as, src, tmptv.gcr); | ||
904 | } | ||
905 | if (LJ_SOFTFP && (ir+1)->o == IR_HIOP && !irt_isnil((ir+1)->t)) | ||
906 | type = ra_alloc1(as, ref+1, RSET_GPR); | ||
907 | else | ||
908 | type = ra_allock(as, (int32_t)irt_toitype(ir->t), RSET_GPR); | ||
909 | emit_setgl(as, type, tmptv.it); | ||
910 | #else | ||
911 | asm_tvstore64(as, dest, 0, ref); | ||
912 | emit_tsi(as, MIPSI_DADDIU, dest, RID_JGL, tmpofs); | ||
913 | #endif | ||
914 | } | ||
590 | } else { | 915 | } else { |
591 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_str_fromint]; | 916 | emit_tsi(as, MIPSI_AADDIU, dest, RID_JGL, tmpofs); |
592 | args[1] = ir->op1; /* int32_t k */ | ||
593 | asm_setupresult(as, ir, ci); /* GCstr * */ | ||
594 | asm_gencall(as, ci, args); | ||
595 | } | 917 | } |
596 | } | 918 | } |
597 | 919 | ||
598 | /* -- Memory references --------------------------------------------------- */ | ||
599 | |||
600 | static void asm_aref(ASMState *as, IRIns *ir) | 920 | static void asm_aref(ASMState *as, IRIns *ir) |
601 | { | 921 | { |
602 | Reg dest = ra_dest(as, ir, RSET_GPR); | 922 | Reg dest = ra_dest(as, ir, RSET_GPR); |
@@ -608,14 +928,18 @@ static void asm_aref(ASMState *as, IRIns *ir) | |||
608 | ofs += 8*IR(ir->op2)->i; | 928 | ofs += 8*IR(ir->op2)->i; |
609 | if (checki16(ofs)) { | 929 | if (checki16(ofs)) { |
610 | base = ra_alloc1(as, refa, RSET_GPR); | 930 | base = ra_alloc1(as, refa, RSET_GPR); |
611 | emit_tsi(as, MIPSI_ADDIU, dest, base, ofs); | 931 | emit_tsi(as, MIPSI_AADDIU, dest, base, ofs); |
612 | return; | 932 | return; |
613 | } | 933 | } |
614 | } | 934 | } |
615 | base = ra_alloc1(as, ir->op1, RSET_GPR); | 935 | base = ra_alloc1(as, ir->op1, RSET_GPR); |
616 | idx = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, base)); | 936 | idx = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, base)); |
617 | emit_dst(as, MIPSI_ADDU, dest, RID_TMP, base); | 937 | #if !LJ_TARGET_MIPSR6 |
938 | emit_dst(as, MIPSI_AADDU, dest, RID_TMP, base); | ||
618 | emit_dta(as, MIPSI_SLL, RID_TMP, idx, 3); | 939 | emit_dta(as, MIPSI_SLL, RID_TMP, idx, 3); |
940 | #else | ||
941 | emit_dst(as, MIPSI_ALSA | MIPSF_A(3-1), dest, idx, base); | ||
942 | #endif | ||
619 | } | 943 | } |
620 | 944 | ||
621 | /* Inlined hash lookup. Specialized for key type and for const keys. | 945 | /* Inlined hash lookup. Specialized for key type and for const keys. |
@@ -626,21 +950,25 @@ static void asm_aref(ASMState *as, IRIns *ir) | |||
626 | ** } while ((n = nextnode(n))); | 950 | ** } while ((n = nextnode(n))); |
627 | ** return niltv(L); | 951 | ** return niltv(L); |
628 | */ | 952 | */ |
629 | static void asm_href(ASMState *as, IRIns *ir) | 953 | static void asm_href(ASMState *as, IRIns *ir, IROp merge) |
630 | { | 954 | { |
631 | RegSet allow = RSET_GPR; | 955 | RegSet allow = RSET_GPR; |
632 | int destused = ra_used(ir); | 956 | int destused = ra_used(ir); |
633 | Reg dest = ra_dest(as, ir, allow); | 957 | Reg dest = ra_dest(as, ir, allow); |
634 | Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest)); | 958 | Reg tab = ra_alloc1(as, ir->op1, rset_clear(allow, dest)); |
635 | Reg key = RID_NONE, type = RID_NONE, tmpnum = RID_NONE, tmp1 = RID_TMP, tmp2; | 959 | Reg key = RID_NONE, type = RID_NONE, tmpnum = RID_NONE, tmp1 = RID_TMP, tmp2; |
960 | #if LJ_64 | ||
961 | Reg cmp64 = RID_NONE; | ||
962 | #endif | ||
636 | IRRef refkey = ir->op2; | 963 | IRRef refkey = ir->op2; |
637 | IRIns *irkey = IR(refkey); | 964 | IRIns *irkey = IR(refkey); |
965 | int isk = irref_isk(refkey); | ||
638 | IRType1 kt = irkey->t; | 966 | IRType1 kt = irkey->t; |
639 | uint32_t khash; | 967 | uint32_t khash; |
640 | MCLabel l_end, l_loop, l_next; | 968 | MCLabel l_end, l_loop, l_next; |
641 | 969 | ||
642 | rset_clear(allow, tab); | 970 | rset_clear(allow, tab); |
643 | if (irt_isnum(kt)) { | 971 | if (!LJ_SOFTFP && irt_isnum(kt)) { |
644 | key = ra_alloc1(as, refkey, RSET_FPR); | 972 | key = ra_alloc1(as, refkey, RSET_FPR); |
645 | tmpnum = ra_scratch(as, rset_exclude(RSET_FPR, key)); | 973 | tmpnum = ra_scratch(as, rset_exclude(RSET_FPR, key)); |
646 | } else { | 974 | } else { |
@@ -648,31 +976,76 @@ static void asm_href(ASMState *as, IRIns *ir) | |||
648 | key = ra_alloc1(as, refkey, allow); | 976 | key = ra_alloc1(as, refkey, allow); |
649 | rset_clear(allow, key); | 977 | rset_clear(allow, key); |
650 | } | 978 | } |
651 | type = ra_allock(as, irt_toitype(irkey->t), allow); | 979 | #if LJ_32 |
652 | rset_clear(allow, type); | 980 | if (LJ_SOFTFP && irkey[1].o == IR_HIOP) { |
981 | if (ra_hasreg((irkey+1)->r)) { | ||
982 | type = tmpnum = (irkey+1)->r; | ||
983 | tmp1 = ra_scratch(as, allow); | ||
984 | rset_clear(allow, tmp1); | ||
985 | ra_noweak(as, tmpnum); | ||
986 | } else { | ||
987 | type = tmpnum = ra_allocref(as, refkey+1, allow); | ||
988 | } | ||
989 | rset_clear(allow, tmpnum); | ||
990 | } else { | ||
991 | type = ra_allock(as, (int32_t)irt_toitype(kt), allow); | ||
992 | rset_clear(allow, type); | ||
993 | } | ||
994 | #endif | ||
653 | } | 995 | } |
654 | tmp2 = ra_scratch(as, allow); | 996 | tmp2 = ra_scratch(as, allow); |
655 | rset_clear(allow, tmp2); | 997 | rset_clear(allow, tmp2); |
998 | #if LJ_64 | ||
999 | if (LJ_SOFTFP || !irt_isnum(kt)) { | ||
1000 | /* Allocate cmp64 register used for 64-bit comparisons */ | ||
1001 | if (LJ_SOFTFP && irt_isnum(kt)) { | ||
1002 | cmp64 = key; | ||
1003 | } else if (!isk && irt_isaddr(kt)) { | ||
1004 | cmp64 = tmp2; | ||
1005 | } else { | ||
1006 | int64_t k; | ||
1007 | if (isk && irt_isaddr(kt)) { | ||
1008 | k = ((int64_t)irt_toitype(kt) << 47) | irkey[1].tv.u64; | ||
1009 | } else { | ||
1010 | lj_assertA(irt_ispri(kt) && !irt_isnil(kt), "bad HREF key type"); | ||
1011 | k = ~((int64_t)~irt_toitype(kt) << 47); | ||
1012 | } | ||
1013 | cmp64 = ra_allock(as, k, allow); | ||
1014 | rset_clear(allow, cmp64); | ||
1015 | } | ||
1016 | } | ||
1017 | #endif | ||
656 | 1018 | ||
657 | /* Key not found in chain: load niltv. */ | 1019 | /* Key not found in chain: jump to exit (if merged) or load niltv. */ |
658 | l_end = emit_label(as); | 1020 | l_end = emit_label(as); |
659 | if (destused) | 1021 | as->invmcp = NULL; |
1022 | if (merge == IR_NE) | ||
1023 | asm_guard(as, MIPSI_B, RID_ZERO, RID_ZERO); | ||
1024 | else if (destused) | ||
660 | emit_loada(as, dest, niltvg(J2G(as->J))); | 1025 | emit_loada(as, dest, niltvg(J2G(as->J))); |
661 | else | ||
662 | *--as->mcp = MIPSI_NOP; | ||
663 | /* Follow hash chain until the end. */ | 1026 | /* Follow hash chain until the end. */ |
664 | emit_move(as, dest, tmp1); | 1027 | emit_move(as, dest, tmp1); |
665 | l_loop = --as->mcp; | 1028 | l_loop = --as->mcp; |
666 | emit_tsi(as, MIPSI_LW, tmp1, dest, (int32_t)offsetof(Node, next)); | 1029 | emit_tsi(as, MIPSI_AL, tmp1, dest, (int32_t)offsetof(Node, next)); |
667 | l_next = emit_label(as); | 1030 | l_next = emit_label(as); |
668 | 1031 | ||
669 | /* Type and value comparison. */ | 1032 | /* Type and value comparison. */ |
670 | if (irt_isnum(kt)) { | 1033 | if (merge == IR_EQ) { /* Must match asm_guard(). */ |
1034 | emit_ti(as, MIPSI_LI, RID_TMP, as->snapno); | ||
1035 | l_end = asm_exitstub_addr(as); | ||
1036 | } | ||
1037 | if (!LJ_SOFTFP && irt_isnum(kt)) { | ||
1038 | #if !LJ_TARGET_MIPSR6 | ||
671 | emit_branch(as, MIPSI_BC1T, 0, 0, l_end); | 1039 | emit_branch(as, MIPSI_BC1T, 0, 0, l_end); |
672 | emit_fgh(as, MIPSI_C_EQ_D, 0, tmpnum, key); | 1040 | emit_fgh(as, MIPSI_C_EQ_D, 0, tmpnum, key); |
673 | emit_tg(as, MIPSI_MFC1, tmp1, key+1); | 1041 | #else |
1042 | emit_branch(as, MIPSI_BC1NEZ, 0, (tmpnum&31), l_end); | ||
1043 | emit_fgh(as, MIPSI_CMP_EQ_D, tmpnum, tmpnum, key); | ||
1044 | #endif | ||
1045 | *--as->mcp = MIPSI_NOP; /* Avoid NaN comparison overhead. */ | ||
674 | emit_branch(as, MIPSI_BEQ, tmp1, RID_ZERO, l_next); | 1046 | emit_branch(as, MIPSI_BEQ, tmp1, RID_ZERO, l_next); |
675 | emit_tsi(as, MIPSI_SLTIU, tmp1, tmp1, (int32_t)LJ_TISNUM); | 1047 | emit_tsi(as, MIPSI_SLTIU, tmp1, tmp1, (int32_t)LJ_TISNUM); |
1048 | #if LJ_32 | ||
676 | emit_hsi(as, MIPSI_LDC1, tmpnum, dest, (int32_t)offsetof(Node, key.n)); | 1049 | emit_hsi(as, MIPSI_LDC1, tmpnum, dest, (int32_t)offsetof(Node, key.n)); |
677 | } else { | 1050 | } else { |
678 | if (irt_ispri(kt)) { | 1051 | if (irt_ispri(kt)) { |
@@ -685,36 +1058,52 @@ static void asm_href(ASMState *as, IRIns *ir) | |||
685 | } | 1058 | } |
686 | emit_tsi(as, MIPSI_LW, tmp1, dest, (int32_t)offsetof(Node, key.it)); | 1059 | emit_tsi(as, MIPSI_LW, tmp1, dest, (int32_t)offsetof(Node, key.it)); |
687 | *l_loop = MIPSI_BNE | MIPSF_S(tmp1) | ((as->mcp-l_loop-1) & 0xffffu); | 1060 | *l_loop = MIPSI_BNE | MIPSF_S(tmp1) | ((as->mcp-l_loop-1) & 0xffffu); |
1061 | #else | ||
1062 | emit_dta(as, MIPSI_DSRA32, tmp1, tmp1, 15); | ||
1063 | emit_tg(as, MIPSI_DMTC1, tmp1, tmpnum); | ||
1064 | emit_tsi(as, MIPSI_LD, tmp1, dest, (int32_t)offsetof(Node, key.u64)); | ||
1065 | } else { | ||
1066 | emit_branch(as, MIPSI_BEQ, tmp1, cmp64, l_end); | ||
1067 | emit_tsi(as, MIPSI_LD, tmp1, dest, (int32_t)offsetof(Node, key.u64)); | ||
1068 | } | ||
1069 | *l_loop = MIPSI_BNE | MIPSF_S(tmp1) | ((as->mcp-l_loop-1) & 0xffffu); | ||
1070 | if (!isk && irt_isaddr(kt)) { | ||
1071 | type = ra_allock(as, (int64_t)irt_toitype(kt) << 47, allow); | ||
1072 | emit_dst(as, MIPSI_DADDU, tmp2, key, type); | ||
1073 | rset_clear(allow, type); | ||
1074 | } | ||
1075 | #endif | ||
688 | 1076 | ||
689 | /* Load main position relative to tab->node into dest. */ | 1077 | /* Load main position relative to tab->node into dest. */ |
690 | khash = irref_isk(refkey) ? ir_khash(irkey) : 1; | 1078 | khash = isk ? ir_khash(as, irkey) : 1; |
691 | if (khash == 0) { | 1079 | if (khash == 0) { |
692 | emit_tsi(as, MIPSI_LW, dest, tab, (int32_t)offsetof(GCtab, node)); | 1080 | emit_tsi(as, MIPSI_AL, dest, tab, (int32_t)offsetof(GCtab, node)); |
693 | } else { | 1081 | } else { |
694 | Reg tmphash = tmp1; | 1082 | Reg tmphash = tmp1; |
695 | if (irref_isk(refkey)) | 1083 | if (isk) |
696 | tmphash = ra_allock(as, khash, allow); | 1084 | tmphash = ra_allock(as, khash, allow); |
697 | emit_dst(as, MIPSI_ADDU, dest, dest, tmp1); | 1085 | emit_dst(as, MIPSI_AADDU, dest, dest, tmp1); |
698 | lua_assert(sizeof(Node) == 24); | 1086 | lj_assertA(sizeof(Node) == 24, "bad Node size"); |
699 | emit_dst(as, MIPSI_SUBU, tmp1, tmp2, tmp1); | 1087 | emit_dst(as, MIPSI_SUBU, tmp1, tmp2, tmp1); |
700 | emit_dta(as, MIPSI_SLL, tmp1, tmp1, 3); | 1088 | emit_dta(as, MIPSI_SLL, tmp1, tmp1, 3); |
701 | emit_dta(as, MIPSI_SLL, tmp2, tmp1, 5); | 1089 | emit_dta(as, MIPSI_SLL, tmp2, tmp1, 5); |
702 | emit_dst(as, MIPSI_AND, tmp1, tmp2, tmphash); | 1090 | emit_dst(as, MIPSI_AND, tmp1, tmp2, tmphash); |
703 | emit_tsi(as, MIPSI_LW, dest, tab, (int32_t)offsetof(GCtab, node)); | 1091 | emit_tsi(as, MIPSI_AL, dest, tab, (int32_t)offsetof(GCtab, node)); |
704 | emit_tsi(as, MIPSI_LW, tmp2, tab, (int32_t)offsetof(GCtab, hmask)); | 1092 | emit_tsi(as, MIPSI_LW, tmp2, tab, (int32_t)offsetof(GCtab, hmask)); |
705 | if (irref_isk(refkey)) { | 1093 | if (isk) { |
706 | /* Nothing to do. */ | 1094 | /* Nothing to do. */ |
707 | } else if (irt_isstr(kt)) { | 1095 | } else if (irt_isstr(kt)) { |
708 | emit_tsi(as, MIPSI_LW, tmp1, key, (int32_t)offsetof(GCstr, hash)); | 1096 | emit_tsi(as, MIPSI_LW, tmp1, key, (int32_t)offsetof(GCstr, sid)); |
709 | } else { /* Must match with hash*() in lj_tab.c. */ | 1097 | } else { /* Must match with hash*() in lj_tab.c. */ |
710 | emit_dst(as, MIPSI_SUBU, tmp1, tmp1, tmp2); | 1098 | emit_dst(as, MIPSI_SUBU, tmp1, tmp1, tmp2); |
711 | emit_rotr(as, tmp2, tmp2, dest, (-HASH_ROT3)&31); | 1099 | emit_rotr(as, tmp2, tmp2, dest, (-HASH_ROT3)&31); |
712 | emit_dst(as, MIPSI_XOR, tmp1, tmp1, tmp2); | 1100 | emit_dst(as, MIPSI_XOR, tmp1, tmp1, tmp2); |
713 | emit_rotr(as, tmp1, tmp1, dest, (-HASH_ROT2-HASH_ROT1)&31); | 1101 | emit_rotr(as, tmp1, tmp1, dest, (-HASH_ROT2-HASH_ROT1)&31); |
714 | emit_dst(as, MIPSI_SUBU, tmp2, tmp2, dest); | 1102 | emit_dst(as, MIPSI_SUBU, tmp2, tmp2, dest); |
715 | if (irt_isnum(kt)) { | 1103 | #if LJ_32 |
1104 | if (LJ_SOFTFP ? (irkey[1].o == IR_HIOP) : irt_isnum(kt)) { | ||
716 | emit_dst(as, MIPSI_XOR, tmp2, tmp2, tmp1); | 1105 | emit_dst(as, MIPSI_XOR, tmp2, tmp2, tmp1); |
717 | if ((as->flags & JIT_F_MIPS32R2)) { | 1106 | if ((as->flags & JIT_F_MIPSXXR2)) { |
718 | emit_dta(as, MIPSI_ROTR, dest, tmp1, (-HASH_ROT1)&31); | 1107 | emit_dta(as, MIPSI_ROTR, dest, tmp1, (-HASH_ROT1)&31); |
719 | } else { | 1108 | } else { |
720 | emit_dst(as, MIPSI_OR, dest, dest, tmp1); | 1109 | emit_dst(as, MIPSI_OR, dest, dest, tmp1); |
@@ -722,13 +1111,35 @@ static void asm_href(ASMState *as, IRIns *ir) | |||
722 | emit_dta(as, MIPSI_SRL, dest, tmp1, (-HASH_ROT1)&31); | 1111 | emit_dta(as, MIPSI_SRL, dest, tmp1, (-HASH_ROT1)&31); |
723 | } | 1112 | } |
724 | emit_dst(as, MIPSI_ADDU, tmp1, tmp1, tmp1); | 1113 | emit_dst(as, MIPSI_ADDU, tmp1, tmp1, tmp1); |
1114 | #if LJ_SOFTFP | ||
1115 | emit_ds(as, MIPSI_MOVE, tmp1, type); | ||
1116 | emit_ds(as, MIPSI_MOVE, tmp2, key); | ||
1117 | #else | ||
725 | emit_tg(as, MIPSI_MFC1, tmp2, key); | 1118 | emit_tg(as, MIPSI_MFC1, tmp2, key); |
726 | emit_tg(as, MIPSI_MFC1, tmp1, key+1); | 1119 | emit_tg(as, MIPSI_MFC1, tmp1, key+1); |
1120 | #endif | ||
727 | } else { | 1121 | } else { |
728 | emit_dst(as, MIPSI_XOR, tmp2, key, tmp1); | 1122 | emit_dst(as, MIPSI_XOR, tmp2, key, tmp1); |
729 | emit_rotr(as, dest, tmp1, tmp2, (-HASH_ROT1)&31); | 1123 | emit_rotr(as, dest, tmp1, tmp2, (-HASH_ROT1)&31); |
730 | emit_dst(as, MIPSI_ADDU, tmp1, key, ra_allock(as, HASH_BIAS, allow)); | 1124 | emit_dst(as, MIPSI_ADDU, tmp1, key, ra_allock(as, HASH_BIAS, allow)); |
731 | } | 1125 | } |
1126 | #else | ||
1127 | emit_dst(as, MIPSI_XOR, tmp2, tmp2, tmp1); | ||
1128 | emit_dta(as, MIPSI_ROTR, dest, tmp1, (-HASH_ROT1)&31); | ||
1129 | if (irt_isnum(kt)) { | ||
1130 | emit_dst(as, MIPSI_ADDU, tmp1, tmp1, tmp1); | ||
1131 | emit_dta(as, MIPSI_DSRA32, tmp1, LJ_SOFTFP ? key : tmp1, 0); | ||
1132 | emit_dta(as, MIPSI_SLL, tmp2, LJ_SOFTFP ? key : tmp1, 0); | ||
1133 | #if !LJ_SOFTFP | ||
1134 | emit_tg(as, MIPSI_DMFC1, tmp1, key); | ||
1135 | #endif | ||
1136 | } else { | ||
1137 | checkmclim(as); | ||
1138 | emit_dta(as, MIPSI_DSRA32, tmp1, tmp1, 0); | ||
1139 | emit_dta(as, MIPSI_SLL, tmp2, key, 0); | ||
1140 | emit_dst(as, MIPSI_DADDU, tmp1, key, type); | ||
1141 | } | ||
1142 | #endif | ||
732 | } | 1143 | } |
733 | } | 1144 | } |
734 | } | 1145 | } |
@@ -741,17 +1152,24 @@ static void asm_hrefk(ASMState *as, IRIns *ir) | |||
741 | int32_t kofs = ofs + (int32_t)offsetof(Node, key); | 1152 | int32_t kofs = ofs + (int32_t)offsetof(Node, key); |
742 | Reg dest = (ra_used(ir)||ofs > 32736) ? ra_dest(as, ir, RSET_GPR) : RID_NONE; | 1153 | Reg dest = (ra_used(ir)||ofs > 32736) ? ra_dest(as, ir, RSET_GPR) : RID_NONE; |
743 | Reg node = ra_alloc1(as, ir->op1, RSET_GPR); | 1154 | Reg node = ra_alloc1(as, ir->op1, RSET_GPR); |
744 | Reg key = RID_NONE, type = RID_TMP, idx = node; | ||
745 | RegSet allow = rset_exclude(RSET_GPR, node); | 1155 | RegSet allow = rset_exclude(RSET_GPR, node); |
1156 | Reg idx = node; | ||
1157 | #if LJ_32 | ||
1158 | Reg key = RID_NONE, type = RID_TMP; | ||
746 | int32_t lo, hi; | 1159 | int32_t lo, hi; |
747 | lua_assert(ofs % sizeof(Node) == 0); | 1160 | #else |
1161 | Reg key = ra_scratch(as, allow); | ||
1162 | int64_t k; | ||
1163 | #endif | ||
1164 | lj_assertA(ofs % sizeof(Node) == 0, "unaligned HREFK slot"); | ||
748 | if (ofs > 32736) { | 1165 | if (ofs > 32736) { |
749 | idx = dest; | 1166 | idx = dest; |
750 | rset_clear(allow, dest); | 1167 | rset_clear(allow, dest); |
751 | kofs = (int32_t)offsetof(Node, key); | 1168 | kofs = (int32_t)offsetof(Node, key); |
752 | } else if (ra_hasreg(dest)) { | 1169 | } else if (ra_hasreg(dest)) { |
753 | emit_tsi(as, MIPSI_ADDIU, dest, node, ofs); | 1170 | emit_tsi(as, MIPSI_AADDIU, dest, node, ofs); |
754 | } | 1171 | } |
1172 | #if LJ_32 | ||
755 | if (!irt_ispri(irkey->t)) { | 1173 | if (!irt_ispri(irkey->t)) { |
756 | key = ra_scratch(as, allow); | 1174 | key = ra_scratch(as, allow); |
757 | rset_clear(allow, key); | 1175 | rset_clear(allow, key); |
@@ -770,22 +1188,20 @@ nolo: | |||
770 | asm_guard(as, MIPSI_BNE, type, hi ? ra_allock(as, hi, allow) : RID_ZERO); | 1188 | asm_guard(as, MIPSI_BNE, type, hi ? ra_allock(as, hi, allow) : RID_ZERO); |
771 | if (ra_hasreg(key)) emit_tsi(as, MIPSI_LW, key, idx, kofs+(LJ_BE?4:0)); | 1189 | if (ra_hasreg(key)) emit_tsi(as, MIPSI_LW, key, idx, kofs+(LJ_BE?4:0)); |
772 | emit_tsi(as, MIPSI_LW, type, idx, kofs+(LJ_BE?0:4)); | 1190 | emit_tsi(as, MIPSI_LW, type, idx, kofs+(LJ_BE?0:4)); |
773 | if (ofs > 32736) | 1191 | #else |
774 | emit_tsi(as, MIPSI_ADDU, dest, node, ra_allock(as, ofs, allow)); | 1192 | if (irt_ispri(irkey->t)) { |
775 | } | 1193 | lj_assertA(!irt_isnil(irkey->t), "bad HREFK key type"); |
776 | 1194 | k = ~((int64_t)~irt_toitype(irkey->t) << 47); | |
777 | static void asm_newref(ASMState *as, IRIns *ir) | 1195 | } else if (irt_isnum(irkey->t)) { |
778 | { | 1196 | k = (int64_t)ir_knum(irkey)->u64; |
779 | if (ir->r != RID_SINK) { | 1197 | } else { |
780 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_tab_newkey]; | 1198 | k = ((int64_t)irt_toitype(irkey->t) << 47) | (int64_t)ir_kgc(irkey); |
781 | IRRef args[3]; | ||
782 | args[0] = ASMREF_L; /* lua_State *L */ | ||
783 | args[1] = ir->op1; /* GCtab *t */ | ||
784 | args[2] = ASMREF_TMP1; /* cTValue *key */ | ||
785 | asm_setupresult(as, ir, ci); /* TValue * */ | ||
786 | asm_gencall(as, ci, args); | ||
787 | asm_tvptr(as, ra_releasetmp(as, ASMREF_TMP1), ir->op2); | ||
788 | } | 1199 | } |
1200 | asm_guard(as, MIPSI_BNE, key, ra_allock(as, k, allow)); | ||
1201 | emit_tsi(as, MIPSI_LD, key, idx, kofs); | ||
1202 | #endif | ||
1203 | if (ofs > 32736) | ||
1204 | emit_tsi(as, MIPSI_AADDU, dest, node, ra_allock(as, ofs, allow)); | ||
789 | } | 1205 | } |
790 | 1206 | ||
791 | static void asm_uref(ASMState *as, IRIns *ir) | 1207 | static void asm_uref(ASMState *as, IRIns *ir) |
@@ -794,30 +1210,31 @@ static void asm_uref(ASMState *as, IRIns *ir) | |||
794 | if (irref_isk(ir->op1)) { | 1210 | if (irref_isk(ir->op1)) { |
795 | GCfunc *fn = ir_kfunc(IR(ir->op1)); | 1211 | GCfunc *fn = ir_kfunc(IR(ir->op1)); |
796 | MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v; | 1212 | MRef *v = &gcref(fn->l.uvptr[(ir->op2 >> 8)])->uv.v; |
797 | emit_lsptr(as, MIPSI_LW, dest, v, RSET_GPR); | 1213 | emit_lsptr(as, MIPSI_AL, dest, v, RSET_GPR); |
798 | } else { | 1214 | } else { |
799 | Reg uv = ra_scratch(as, RSET_GPR); | 1215 | Reg uv = ra_scratch(as, RSET_GPR); |
800 | Reg func = ra_alloc1(as, ir->op1, RSET_GPR); | 1216 | Reg func = ra_alloc1(as, ir->op1, RSET_GPR); |
801 | if (ir->o == IR_UREFC) { | 1217 | if (ir->o == IR_UREFC) { |
802 | asm_guard(as, MIPSI_BEQ, RID_TMP, RID_ZERO); | 1218 | asm_guard(as, MIPSI_BEQ, RID_TMP, RID_ZERO); |
803 | emit_tsi(as, MIPSI_ADDIU, dest, uv, (int32_t)offsetof(GCupval, tv)); | 1219 | emit_tsi(as, MIPSI_AADDIU, dest, uv, (int32_t)offsetof(GCupval, tv)); |
804 | emit_tsi(as, MIPSI_LBU, RID_TMP, uv, (int32_t)offsetof(GCupval, closed)); | 1220 | emit_tsi(as, MIPSI_LBU, RID_TMP, uv, (int32_t)offsetof(GCupval, closed)); |
805 | } else { | 1221 | } else { |
806 | emit_tsi(as, MIPSI_LW, dest, uv, (int32_t)offsetof(GCupval, v)); | 1222 | emit_tsi(as, MIPSI_AL, dest, uv, (int32_t)offsetof(GCupval, v)); |
807 | } | 1223 | } |
808 | emit_tsi(as, MIPSI_LW, uv, func, | 1224 | emit_tsi(as, MIPSI_AL, uv, func, (int32_t)offsetof(GCfuncL, uvptr) + |
809 | (int32_t)offsetof(GCfuncL, uvptr) + 4*(int32_t)(ir->op2 >> 8)); | 1225 | (int32_t)sizeof(MRef) * (int32_t)(ir->op2 >> 8)); |
810 | } | 1226 | } |
811 | } | 1227 | } |
812 | 1228 | ||
813 | static void asm_fref(ASMState *as, IRIns *ir) | 1229 | static void asm_fref(ASMState *as, IRIns *ir) |
814 | { | 1230 | { |
815 | UNUSED(as); UNUSED(ir); | 1231 | UNUSED(as); UNUSED(ir); |
816 | lua_assert(!ra_used(ir)); | 1232 | lj_assertA(!ra_used(ir), "unfused FREF"); |
817 | } | 1233 | } |
818 | 1234 | ||
819 | static void asm_strref(ASMState *as, IRIns *ir) | 1235 | static void asm_strref(ASMState *as, IRIns *ir) |
820 | { | 1236 | { |
1237 | #if LJ_32 | ||
821 | Reg dest = ra_dest(as, ir, RSET_GPR); | 1238 | Reg dest = ra_dest(as, ir, RSET_GPR); |
822 | IRRef ref = ir->op2, refk = ir->op1; | 1239 | IRRef ref = ir->op2, refk = ir->op1; |
823 | int32_t ofs = (int32_t)sizeof(GCstr); | 1240 | int32_t ofs = (int32_t)sizeof(GCstr); |
@@ -849,49 +1266,79 @@ static void asm_strref(ASMState *as, IRIns *ir) | |||
849 | else | 1266 | else |
850 | emit_dst(as, MIPSI_ADDU, dest, r, | 1267 | emit_dst(as, MIPSI_ADDU, dest, r, |
851 | ra_allock(as, ofs, rset_exclude(RSET_GPR, r))); | 1268 | ra_allock(as, ofs, rset_exclude(RSET_GPR, r))); |
1269 | #else | ||
1270 | RegSet allow = RSET_GPR; | ||
1271 | Reg dest = ra_dest(as, ir, allow); | ||
1272 | Reg base = ra_alloc1(as, ir->op1, allow); | ||
1273 | IRIns *irr = IR(ir->op2); | ||
1274 | int32_t ofs = sizeof(GCstr); | ||
1275 | rset_clear(allow, base); | ||
1276 | if (irref_isk(ir->op2) && checki16(ofs + irr->i)) { | ||
1277 | emit_tsi(as, MIPSI_DADDIU, dest, base, ofs + irr->i); | ||
1278 | } else { | ||
1279 | emit_tsi(as, MIPSI_DADDIU, dest, dest, ofs); | ||
1280 | emit_dst(as, MIPSI_DADDU, dest, base, ra_alloc1(as, ir->op2, allow)); | ||
1281 | } | ||
1282 | #endif | ||
852 | } | 1283 | } |
853 | 1284 | ||
854 | /* -- Loads and stores ---------------------------------------------------- */ | 1285 | /* -- Loads and stores ---------------------------------------------------- */ |
855 | 1286 | ||
856 | static MIPSIns asm_fxloadins(IRIns *ir) | 1287 | static MIPSIns asm_fxloadins(ASMState *as, IRIns *ir) |
857 | { | 1288 | { |
1289 | UNUSED(as); | ||
858 | switch (irt_type(ir->t)) { | 1290 | switch (irt_type(ir->t)) { |
859 | case IRT_I8: return MIPSI_LB; | 1291 | case IRT_I8: return MIPSI_LB; |
860 | case IRT_U8: return MIPSI_LBU; | 1292 | case IRT_U8: return MIPSI_LBU; |
861 | case IRT_I16: return MIPSI_LH; | 1293 | case IRT_I16: return MIPSI_LH; |
862 | case IRT_U16: return MIPSI_LHU; | 1294 | case IRT_U16: return MIPSI_LHU; |
863 | case IRT_NUM: return MIPSI_LDC1; | 1295 | case IRT_NUM: |
864 | case IRT_FLOAT: return MIPSI_LWC1; | 1296 | lj_assertA(!LJ_SOFTFP32, "unsplit FP op"); |
865 | default: return MIPSI_LW; | 1297 | if (!LJ_SOFTFP) return MIPSI_LDC1; |
1298 | /* fallthrough */ | ||
1299 | case IRT_FLOAT: if (!LJ_SOFTFP) return MIPSI_LWC1; | ||
1300 | /* fallthrough */ | ||
1301 | default: return (LJ_64 && irt_is64(ir->t)) ? MIPSI_LD : MIPSI_LW; | ||
866 | } | 1302 | } |
867 | } | 1303 | } |
868 | 1304 | ||
869 | static MIPSIns asm_fxstoreins(IRIns *ir) | 1305 | static MIPSIns asm_fxstoreins(ASMState *as, IRIns *ir) |
870 | { | 1306 | { |
1307 | UNUSED(as); | ||
871 | switch (irt_type(ir->t)) { | 1308 | switch (irt_type(ir->t)) { |
872 | case IRT_I8: case IRT_U8: return MIPSI_SB; | 1309 | case IRT_I8: case IRT_U8: return MIPSI_SB; |
873 | case IRT_I16: case IRT_U16: return MIPSI_SH; | 1310 | case IRT_I16: case IRT_U16: return MIPSI_SH; |
874 | case IRT_NUM: return MIPSI_SDC1; | 1311 | case IRT_NUM: |
875 | case IRT_FLOAT: return MIPSI_SWC1; | 1312 | lj_assertA(!LJ_SOFTFP32, "unsplit FP op"); |
876 | default: return MIPSI_SW; | 1313 | if (!LJ_SOFTFP) return MIPSI_SDC1; |
1314 | /* fallthrough */ | ||
1315 | case IRT_FLOAT: if (!LJ_SOFTFP) return MIPSI_SWC1; | ||
1316 | /* fallthrough */ | ||
1317 | default: return (LJ_64 && irt_is64(ir->t)) ? MIPSI_SD : MIPSI_SW; | ||
877 | } | 1318 | } |
878 | } | 1319 | } |
879 | 1320 | ||
880 | static void asm_fload(ASMState *as, IRIns *ir) | 1321 | static void asm_fload(ASMState *as, IRIns *ir) |
881 | { | 1322 | { |
882 | Reg dest = ra_dest(as, ir, RSET_GPR); | 1323 | Reg dest = ra_dest(as, ir, RSET_GPR); |
883 | Reg idx = ra_alloc1(as, ir->op1, RSET_GPR); | 1324 | MIPSIns mi = asm_fxloadins(as, ir); |
884 | MIPSIns mi = asm_fxloadins(ir); | 1325 | Reg idx; |
885 | int32_t ofs; | 1326 | int32_t ofs; |
886 | if (ir->op2 == IRFL_TAB_ARRAY) { | 1327 | if (ir->op1 == REF_NIL) { /* FLOAD from GG_State with offset. */ |
887 | ofs = asm_fuseabase(as, ir->op1); | 1328 | idx = RID_JGL; |
888 | if (ofs) { /* Turn the t->array load into an add for colocated arrays. */ | 1329 | ofs = (ir->op2 << 2) - 32768 - GG_OFS(g); |
889 | emit_tsi(as, MIPSI_ADDIU, dest, idx, ofs); | 1330 | } else { |
890 | return; | 1331 | idx = ra_alloc1(as, ir->op1, RSET_GPR); |
1332 | if (ir->op2 == IRFL_TAB_ARRAY) { | ||
1333 | ofs = asm_fuseabase(as, ir->op1); | ||
1334 | if (ofs) { /* Turn the t->array load into an add for colocated arrays. */ | ||
1335 | emit_tsi(as, MIPSI_AADDIU, dest, idx, ofs); | ||
1336 | return; | ||
1337 | } | ||
891 | } | 1338 | } |
1339 | ofs = field_ofs[ir->op2]; | ||
892 | } | 1340 | } |
893 | ofs = field_ofs[ir->op2]; | 1341 | lj_assertA(!irt_isfp(ir->t), "bad FP FLOAD"); |
894 | lua_assert(!irt_isfp(ir->t)); | ||
895 | emit_tsi(as, mi, dest, idx, ofs); | 1342 | emit_tsi(as, mi, dest, idx, ofs); |
896 | } | 1343 | } |
897 | 1344 | ||
@@ -902,51 +1349,90 @@ static void asm_fstore(ASMState *as, IRIns *ir) | |||
902 | IRIns *irf = IR(ir->op1); | 1349 | IRIns *irf = IR(ir->op1); |
903 | Reg idx = ra_alloc1(as, irf->op1, rset_exclude(RSET_GPR, src)); | 1350 | Reg idx = ra_alloc1(as, irf->op1, rset_exclude(RSET_GPR, src)); |
904 | int32_t ofs = field_ofs[irf->op2]; | 1351 | int32_t ofs = field_ofs[irf->op2]; |
905 | MIPSIns mi = asm_fxstoreins(ir); | 1352 | MIPSIns mi = asm_fxstoreins(as, ir); |
906 | lua_assert(!irt_isfp(ir->t)); | 1353 | lj_assertA(!irt_isfp(ir->t), "bad FP FSTORE"); |
907 | emit_tsi(as, mi, src, idx, ofs); | 1354 | emit_tsi(as, mi, src, idx, ofs); |
908 | } | 1355 | } |
909 | } | 1356 | } |
910 | 1357 | ||
911 | static void asm_xload(ASMState *as, IRIns *ir) | 1358 | static void asm_xload(ASMState *as, IRIns *ir) |
912 | { | 1359 | { |
913 | Reg dest = ra_dest(as, ir, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); | 1360 | Reg dest = ra_dest(as, ir, |
914 | lua_assert(!(ir->op2 & IRXLOAD_UNALIGNED)); | 1361 | (!LJ_SOFTFP && irt_isfp(ir->t)) ? RSET_FPR : RSET_GPR); |
915 | asm_fusexref(as, asm_fxloadins(ir), dest, ir->op1, RSET_GPR, 0); | 1362 | lj_assertA(LJ_TARGET_UNALIGNED || !(ir->op2 & IRXLOAD_UNALIGNED), |
1363 | "unaligned XLOAD"); | ||
1364 | asm_fusexref(as, asm_fxloadins(as, ir), dest, ir->op1, RSET_GPR, 0); | ||
916 | } | 1365 | } |
917 | 1366 | ||
918 | static void asm_xstore(ASMState *as, IRIns *ir, int32_t ofs) | 1367 | static void asm_xstore_(ASMState *as, IRIns *ir, int32_t ofs) |
919 | { | 1368 | { |
920 | if (ir->r != RID_SINK) { | 1369 | if (ir->r != RID_SINK) { |
921 | Reg src = ra_alloc1z(as, ir->op2, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); | 1370 | Reg src = ra_alloc1z(as, ir->op2, |
922 | asm_fusexref(as, asm_fxstoreins(ir), src, ir->op1, | 1371 | (!LJ_SOFTFP && irt_isfp(ir->t)) ? RSET_FPR : RSET_GPR); |
1372 | asm_fusexref(as, asm_fxstoreins(as, ir), src, ir->op1, | ||
923 | rset_exclude(RSET_GPR, src), ofs); | 1373 | rset_exclude(RSET_GPR, src), ofs); |
924 | } | 1374 | } |
925 | } | 1375 | } |
926 | 1376 | ||
1377 | #define asm_xstore(as, ir) asm_xstore_(as, ir, 0) | ||
1378 | |||
927 | static void asm_ahuvload(ASMState *as, IRIns *ir) | 1379 | static void asm_ahuvload(ASMState *as, IRIns *ir) |
928 | { | 1380 | { |
929 | IRType1 t = ir->t; | 1381 | int hiop = (LJ_SOFTFP32 && (ir+1)->o == IR_HIOP); |
930 | Reg dest = RID_NONE, type = RID_TMP, idx; | 1382 | Reg dest = RID_NONE, type = RID_TMP, idx; |
931 | RegSet allow = RSET_GPR; | 1383 | RegSet allow = RSET_GPR; |
932 | int32_t ofs = 0; | 1384 | int32_t ofs = 0; |
1385 | IRType1 t = ir->t; | ||
1386 | if (hiop) { | ||
1387 | t.irt = IRT_NUM; | ||
1388 | if (ra_used(ir+1)) { | ||
1389 | type = ra_dest(as, ir+1, allow); | ||
1390 | rset_clear(allow, type); | ||
1391 | } | ||
1392 | } | ||
933 | if (ra_used(ir)) { | 1393 | if (ra_used(ir)) { |
934 | lua_assert(irt_isnum(t) || irt_isint(t) || irt_isaddr(t)); | 1394 | lj_assertA((LJ_SOFTFP32 ? 0 : irt_isnum(ir->t)) || |
935 | dest = ra_dest(as, ir, irt_isnum(t) ? RSET_FPR : RSET_GPR); | 1395 | irt_isint(ir->t) || irt_isaddr(ir->t), |
1396 | "bad load type %d", irt_type(ir->t)); | ||
1397 | dest = ra_dest(as, ir, (!LJ_SOFTFP && irt_isnum(t)) ? RSET_FPR : allow); | ||
936 | rset_clear(allow, dest); | 1398 | rset_clear(allow, dest); |
1399 | #if LJ_64 | ||
1400 | if (irt_isaddr(t)) | ||
1401 | emit_tsml(as, MIPSI_DEXTM, dest, dest, 14, 0); | ||
1402 | else if (irt_isint(t)) | ||
1403 | emit_dta(as, MIPSI_SLL, dest, dest, 0); | ||
1404 | #endif | ||
937 | } | 1405 | } |
938 | idx = asm_fuseahuref(as, ir->op1, &ofs, allow); | 1406 | idx = asm_fuseahuref(as, ir->op1, &ofs, allow); |
1407 | if (ir->o == IR_VLOAD) ofs += 8 * ir->op2; | ||
939 | rset_clear(allow, idx); | 1408 | rset_clear(allow, idx); |
940 | if (irt_isnum(t)) { | 1409 | if (irt_isnum(t)) { |
941 | asm_guard(as, MIPSI_BEQ, type, RID_ZERO); | 1410 | asm_guard(as, MIPSI_BEQ, RID_TMP, RID_ZERO); |
942 | emit_tsi(as, MIPSI_SLTIU, type, type, (int32_t)LJ_TISNUM); | 1411 | emit_tsi(as, MIPSI_SLTIU, RID_TMP, type, (int32_t)LJ_TISNUM); |
943 | if (ra_hasreg(dest)) | ||
944 | emit_hsi(as, MIPSI_LDC1, dest, idx, ofs); | ||
945 | } else { | 1412 | } else { |
946 | asm_guard(as, MIPSI_BNE, type, ra_allock(as, irt_toitype(t), allow)); | 1413 | asm_guard(as, MIPSI_BNE, type, |
947 | if (ra_hasreg(dest)) emit_tsi(as, MIPSI_LW, dest, idx, ofs+(LJ_BE?4:0)); | 1414 | ra_allock(as, (int32_t)irt_toitype(t), allow)); |
1415 | } | ||
1416 | #if LJ_32 | ||
1417 | if (ra_hasreg(dest)) { | ||
1418 | if (!LJ_SOFTFP && irt_isnum(t)) | ||
1419 | emit_hsi(as, MIPSI_LDC1, dest, idx, ofs); | ||
1420 | else | ||
1421 | emit_tsi(as, MIPSI_LW, dest, idx, ofs+(LJ_BE?4:0)); | ||
948 | } | 1422 | } |
949 | emit_tsi(as, MIPSI_LW, type, idx, ofs+(LJ_BE?0:4)); | 1423 | emit_tsi(as, MIPSI_LW, type, idx, ofs+(LJ_BE?0:4)); |
1424 | #else | ||
1425 | if (ra_hasreg(dest)) { | ||
1426 | if (!LJ_SOFTFP && irt_isnum(t)) { | ||
1427 | emit_hsi(as, MIPSI_LDC1, dest, idx, ofs); | ||
1428 | dest = type; | ||
1429 | } | ||
1430 | } else { | ||
1431 | dest = type; | ||
1432 | } | ||
1433 | emit_dta(as, MIPSI_DSRA32, type, dest, 15); | ||
1434 | emit_tsi(as, MIPSI_LD, dest, idx, ofs); | ||
1435 | #endif | ||
950 | } | 1436 | } |
951 | 1437 | ||
952 | static void asm_ahustore(ASMState *as, IRIns *ir) | 1438 | static void asm_ahustore(ASMState *as, IRIns *ir) |
@@ -956,81 +1442,180 @@ static void asm_ahustore(ASMState *as, IRIns *ir) | |||
956 | int32_t ofs = 0; | 1442 | int32_t ofs = 0; |
957 | if (ir->r == RID_SINK) | 1443 | if (ir->r == RID_SINK) |
958 | return; | 1444 | return; |
959 | if (irt_isnum(ir->t)) { | 1445 | if (!LJ_SOFTFP32 && irt_isnum(ir->t)) { |
960 | src = ra_alloc1(as, ir->op2, RSET_FPR); | 1446 | src = ra_alloc1(as, ir->op2, LJ_SOFTFP ? RSET_GPR : RSET_FPR); |
1447 | idx = asm_fuseahuref(as, ir->op1, &ofs, allow); | ||
1448 | emit_hsi(as, LJ_SOFTFP ? MIPSI_SD : MIPSI_SDC1, src, idx, ofs); | ||
961 | } else { | 1449 | } else { |
1450 | #if LJ_32 | ||
962 | if (!irt_ispri(ir->t)) { | 1451 | if (!irt_ispri(ir->t)) { |
963 | src = ra_alloc1(as, ir->op2, allow); | 1452 | src = ra_alloc1(as, ir->op2, allow); |
964 | rset_clear(allow, src); | 1453 | rset_clear(allow, src); |
965 | } | 1454 | } |
966 | type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); | 1455 | if (LJ_SOFTFP && (ir+1)->o == IR_HIOP) |
1456 | type = ra_alloc1(as, (ir+1)->op2, allow); | ||
1457 | else | ||
1458 | type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); | ||
967 | rset_clear(allow, type); | 1459 | rset_clear(allow, type); |
968 | } | 1460 | idx = asm_fuseahuref(as, ir->op1, &ofs, allow); |
969 | idx = asm_fuseahuref(as, ir->op1, &ofs, allow); | ||
970 | if (irt_isnum(ir->t)) { | ||
971 | emit_hsi(as, MIPSI_SDC1, src, idx, ofs); | ||
972 | } else { | ||
973 | if (ra_hasreg(src)) | 1461 | if (ra_hasreg(src)) |
974 | emit_tsi(as, MIPSI_SW, src, idx, ofs+(LJ_BE?4:0)); | 1462 | emit_tsi(as, MIPSI_SW, src, idx, ofs+(LJ_BE?4:0)); |
975 | emit_tsi(as, MIPSI_SW, type, idx, ofs+(LJ_BE?0:4)); | 1463 | emit_tsi(as, MIPSI_SW, type, idx, ofs+(LJ_BE?0:4)); |
1464 | #else | ||
1465 | Reg tmp = RID_TMP; | ||
1466 | if (irt_ispri(ir->t)) { | ||
1467 | tmp = ra_allock(as, ~((int64_t)~irt_toitype(ir->t) << 47), allow); | ||
1468 | rset_clear(allow, tmp); | ||
1469 | } else { | ||
1470 | src = ra_alloc1(as, ir->op2, allow); | ||
1471 | rset_clear(allow, src); | ||
1472 | type = ra_allock(as, (int64_t)irt_toitype(ir->t) << 47, allow); | ||
1473 | rset_clear(allow, type); | ||
1474 | } | ||
1475 | idx = asm_fuseahuref(as, ir->op1, &ofs, allow); | ||
1476 | emit_tsi(as, MIPSI_SD, tmp, idx, ofs); | ||
1477 | if (ra_hasreg(src)) { | ||
1478 | if (irt_isinteger(ir->t)) { | ||
1479 | emit_dst(as, MIPSI_DADDU, tmp, tmp, type); | ||
1480 | emit_tsml(as, MIPSI_DEXT, tmp, src, 31, 0); | ||
1481 | } else { | ||
1482 | emit_dst(as, MIPSI_DADDU, tmp, src, type); | ||
1483 | } | ||
1484 | } | ||
1485 | #endif | ||
976 | } | 1486 | } |
977 | } | 1487 | } |
978 | 1488 | ||
979 | static void asm_sload(ASMState *as, IRIns *ir) | 1489 | static void asm_sload(ASMState *as, IRIns *ir) |
980 | { | 1490 | { |
981 | int32_t ofs = 8*((int32_t)ir->op1-1) + ((ir->op2 & IRSLOAD_FRAME) ? 4 : 0); | ||
982 | IRType1 t = ir->t; | ||
983 | Reg dest = RID_NONE, type = RID_NONE, base; | 1491 | Reg dest = RID_NONE, type = RID_NONE, base; |
984 | RegSet allow = RSET_GPR; | 1492 | RegSet allow = RSET_GPR; |
985 | lua_assert(!(ir->op2 & IRSLOAD_PARENT)); /* Handled by asm_head_side(). */ | 1493 | IRType1 t = ir->t; |
986 | lua_assert(irt_isguard(t) || !(ir->op2 & IRSLOAD_TYPECHECK)); | 1494 | #if LJ_32 |
987 | lua_assert(!irt_isint(t) || (ir->op2 & (IRSLOAD_CONVERT|IRSLOAD_FRAME))); | 1495 | int32_t ofs = 8*((int32_t)ir->op1-1) + ((ir->op2 & IRSLOAD_FRAME) ? 4 : 0); |
1496 | int hiop = (LJ_SOFTFP32 && (ir+1)->o == IR_HIOP); | ||
1497 | if (hiop) | ||
1498 | t.irt = IRT_NUM; | ||
1499 | #else | ||
1500 | int32_t ofs = 8*((int32_t)ir->op1-2); | ||
1501 | #endif | ||
1502 | lj_assertA(!(ir->op2 & IRSLOAD_PARENT), | ||
1503 | "bad parent SLOAD"); /* Handled by asm_head_side(). */ | ||
1504 | lj_assertA(irt_isguard(ir->t) || !(ir->op2 & IRSLOAD_TYPECHECK), | ||
1505 | "inconsistent SLOAD variant"); | ||
1506 | #if LJ_SOFTFP32 | ||
1507 | lj_assertA(!(ir->op2 & IRSLOAD_CONVERT), | ||
1508 | "unsplit SLOAD convert"); /* Handled by LJ_SOFTFP SPLIT. */ | ||
1509 | if (hiop && ra_used(ir+1)) { | ||
1510 | type = ra_dest(as, ir+1, allow); | ||
1511 | rset_clear(allow, type); | ||
1512 | } | ||
1513 | #else | ||
988 | if ((ir->op2 & IRSLOAD_CONVERT) && irt_isguard(t) && irt_isint(t)) { | 1514 | if ((ir->op2 & IRSLOAD_CONVERT) && irt_isguard(t) && irt_isint(t)) { |
989 | dest = ra_scratch(as, RSET_FPR); | 1515 | dest = ra_scratch(as, LJ_SOFTFP ? allow : RSET_FPR); |
990 | asm_tointg(as, ir, dest); | 1516 | asm_tointg(as, ir, dest); |
991 | t.irt = IRT_NUM; /* Continue with a regular number type check. */ | 1517 | t.irt = IRT_NUM; /* Continue with a regular number type check. */ |
992 | } else if (ra_used(ir)) { | 1518 | } else |
993 | lua_assert(irt_isnum(t) || irt_isint(t) || irt_isaddr(t)); | 1519 | #endif |
994 | dest = ra_dest(as, ir, irt_isnum(t) ? RSET_FPR : RSET_GPR); | 1520 | if (ra_used(ir)) { |
1521 | lj_assertA((LJ_SOFTFP32 ? 0 : irt_isnum(ir->t)) || | ||
1522 | irt_isint(ir->t) || irt_isaddr(ir->t), | ||
1523 | "bad SLOAD type %d", irt_type(ir->t)); | ||
1524 | dest = ra_dest(as, ir, (!LJ_SOFTFP && irt_isnum(t)) ? RSET_FPR : allow); | ||
995 | rset_clear(allow, dest); | 1525 | rset_clear(allow, dest); |
996 | base = ra_alloc1(as, REF_BASE, allow); | 1526 | base = ra_alloc1(as, REF_BASE, allow); |
997 | rset_clear(allow, base); | 1527 | rset_clear(allow, base); |
998 | if ((ir->op2 & IRSLOAD_CONVERT)) { | 1528 | if (!LJ_SOFTFP32 && (ir->op2 & IRSLOAD_CONVERT)) { |
999 | if (irt_isint(t)) { | 1529 | if (irt_isint(t)) { |
1000 | Reg tmp = ra_scratch(as, RSET_FPR); | 1530 | Reg tmp = ra_scratch(as, LJ_SOFTFP ? RSET_GPR : RSET_FPR); |
1531 | #if LJ_SOFTFP | ||
1532 | ra_evictset(as, rset_exclude(RSET_SCRATCH, dest)); | ||
1533 | ra_destreg(as, ir, RID_RET); | ||
1534 | emit_call(as, (void *)lj_ir_callinfo[IRCALL_softfp_d2i].func, 0); | ||
1535 | if (tmp != REGARG_FIRSTGPR) | ||
1536 | emit_move(as, REGARG_FIRSTGPR, tmp); | ||
1537 | #else | ||
1001 | emit_tg(as, MIPSI_MFC1, dest, tmp); | 1538 | emit_tg(as, MIPSI_MFC1, dest, tmp); |
1002 | emit_fg(as, MIPSI_CVT_W_D, tmp, tmp); | 1539 | emit_fg(as, MIPSI_TRUNC_W_D, tmp, tmp); |
1540 | #endif | ||
1003 | dest = tmp; | 1541 | dest = tmp; |
1004 | t.irt = IRT_NUM; /* Check for original type. */ | 1542 | t.irt = IRT_NUM; /* Check for original type. */ |
1005 | } else { | 1543 | } else { |
1006 | Reg tmp = ra_scratch(as, RSET_GPR); | 1544 | Reg tmp = ra_scratch(as, RSET_GPR); |
1545 | #if LJ_SOFTFP | ||
1546 | ra_evictset(as, rset_exclude(RSET_SCRATCH, dest)); | ||
1547 | ra_destreg(as, ir, RID_RET); | ||
1548 | emit_call(as, (void *)lj_ir_callinfo[IRCALL_softfp_i2d].func, 0); | ||
1549 | emit_dta(as, MIPSI_SLL, REGARG_FIRSTGPR, tmp, 0); | ||
1550 | #else | ||
1007 | emit_fg(as, MIPSI_CVT_D_W, dest, dest); | 1551 | emit_fg(as, MIPSI_CVT_D_W, dest, dest); |
1008 | emit_tg(as, MIPSI_MTC1, tmp, dest); | 1552 | emit_tg(as, MIPSI_MTC1, tmp, dest); |
1553 | #endif | ||
1009 | dest = tmp; | 1554 | dest = tmp; |
1010 | t.irt = IRT_INT; /* Check for original type. */ | 1555 | t.irt = IRT_INT; /* Check for original type. */ |
1011 | } | 1556 | } |
1012 | } | 1557 | } |
1558 | #if LJ_64 | ||
1559 | else if (irt_isaddr(t)) { | ||
1560 | /* Clear type from pointers. */ | ||
1561 | emit_tsml(as, MIPSI_DEXTM, dest, dest, 14, 0); | ||
1562 | } else if (irt_isint(t) && (ir->op2 & IRSLOAD_TYPECHECK)) { | ||
1563 | /* Sign-extend integers. */ | ||
1564 | emit_dta(as, MIPSI_SLL, dest, dest, 0); | ||
1565 | } | ||
1566 | #endif | ||
1013 | goto dotypecheck; | 1567 | goto dotypecheck; |
1014 | } | 1568 | } |
1015 | base = ra_alloc1(as, REF_BASE, allow); | 1569 | base = ra_alloc1(as, REF_BASE, allow); |
1016 | rset_clear(allow, base); | 1570 | rset_clear(allow, base); |
1017 | dotypecheck: | 1571 | dotypecheck: |
1018 | if (irt_isnum(t)) { | 1572 | #if LJ_32 |
1019 | if ((ir->op2 & IRSLOAD_TYPECHECK)) { | 1573 | if ((ir->op2 & IRSLOAD_TYPECHECK)) { |
1020 | asm_guard(as, MIPSI_BEQ, RID_TMP, RID_ZERO); | 1574 | if (ra_noreg(type)) |
1021 | emit_tsi(as, MIPSI_SLTIU, RID_TMP, RID_TMP, (int32_t)LJ_TISNUM); | ||
1022 | type = RID_TMP; | 1575 | type = RID_TMP; |
1023 | } | 1576 | if (irt_isnum(t)) { |
1024 | if (ra_hasreg(dest)) emit_hsi(as, MIPSI_LDC1, dest, base, ofs); | 1577 | asm_guard(as, MIPSI_BEQ, RID_TMP, RID_ZERO); |
1025 | } else { | 1578 | emit_tsi(as, MIPSI_SLTIU, RID_TMP, type, (int32_t)LJ_TISNUM); |
1026 | if ((ir->op2 & IRSLOAD_TYPECHECK)) { | 1579 | } else { |
1027 | Reg ktype = ra_allock(as, irt_toitype(t), allow); | 1580 | Reg ktype = ra_allock(as, irt_toitype(t), allow); |
1028 | asm_guard(as, MIPSI_BNE, RID_TMP, ktype); | 1581 | asm_guard(as, MIPSI_BNE, type, ktype); |
1029 | type = RID_TMP; | ||
1030 | } | 1582 | } |
1031 | if (ra_hasreg(dest)) emit_tsi(as, MIPSI_LW, dest, base, ofs ^ (LJ_BE?4:0)); | ||
1032 | } | 1583 | } |
1033 | if (ra_hasreg(type)) emit_tsi(as, MIPSI_LW, type, base, ofs ^ (LJ_BE?0:4)); | 1584 | if (ra_hasreg(dest)) { |
1585 | if (!LJ_SOFTFP && irt_isnum(t)) | ||
1586 | emit_hsi(as, MIPSI_LDC1, dest, base, ofs); | ||
1587 | else | ||
1588 | emit_tsi(as, MIPSI_LW, dest, base, ofs ^ (LJ_BE?4:0)); | ||
1589 | } | ||
1590 | if (ra_hasreg(type)) | ||
1591 | emit_tsi(as, MIPSI_LW, type, base, ofs ^ (LJ_BE?0:4)); | ||
1592 | #else | ||
1593 | if ((ir->op2 & IRSLOAD_TYPECHECK)) { | ||
1594 | type = dest < RID_MAX_GPR ? dest : RID_TMP; | ||
1595 | if (irt_ispri(t)) { | ||
1596 | asm_guard(as, MIPSI_BNE, type, | ||
1597 | ra_allock(as, ~((int64_t)~irt_toitype(t) << 47) , allow)); | ||
1598 | } else { | ||
1599 | if (irt_isnum(t)) { | ||
1600 | asm_guard(as, MIPSI_BEQ, RID_TMP, RID_ZERO); | ||
1601 | emit_tsi(as, MIPSI_SLTIU, RID_TMP, RID_TMP, (int32_t)LJ_TISNUM); | ||
1602 | if (!LJ_SOFTFP && ra_hasreg(dest)) | ||
1603 | emit_hsi(as, MIPSI_LDC1, dest, base, ofs); | ||
1604 | } else { | ||
1605 | asm_guard(as, MIPSI_BNE, RID_TMP, | ||
1606 | ra_allock(as, (int32_t)irt_toitype(t), allow)); | ||
1607 | } | ||
1608 | emit_dta(as, MIPSI_DSRA32, RID_TMP, type, 15); | ||
1609 | } | ||
1610 | emit_tsi(as, MIPSI_LD, type, base, ofs); | ||
1611 | } else if (ra_hasreg(dest)) { | ||
1612 | if (!LJ_SOFTFP && irt_isnum(t)) | ||
1613 | emit_hsi(as, MIPSI_LDC1, dest, base, ofs); | ||
1614 | else | ||
1615 | emit_tsi(as, irt_isint(t) ? MIPSI_LW : MIPSI_LD, dest, base, | ||
1616 | ofs ^ ((LJ_BE && irt_isint(t)) ? 4 : 0)); | ||
1617 | } | ||
1618 | #endif | ||
1034 | } | 1619 | } |
1035 | 1620 | ||
1036 | /* -- Allocations --------------------------------------------------------- */ | 1621 | /* -- Allocations --------------------------------------------------------- */ |
@@ -1039,19 +1624,16 @@ dotypecheck: | |||
1039 | static void asm_cnew(ASMState *as, IRIns *ir) | 1624 | static void asm_cnew(ASMState *as, IRIns *ir) |
1040 | { | 1625 | { |
1041 | CTState *cts = ctype_ctsG(J2G(as->J)); | 1626 | CTState *cts = ctype_ctsG(J2G(as->J)); |
1042 | CTypeID ctypeid = (CTypeID)IR(ir->op1)->i; | 1627 | CTypeID id = (CTypeID)IR(ir->op1)->i; |
1043 | CTSize sz = (ir->o == IR_CNEWI || ir->op2 == REF_NIL) ? | 1628 | CTSize sz; |
1044 | lj_ctype_size(cts, ctypeid) : (CTSize)IR(ir->op2)->i; | 1629 | CTInfo info = lj_ctype_info(cts, id, &sz); |
1045 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco]; | 1630 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_mem_newgco]; |
1046 | IRRef args[2]; | 1631 | IRRef args[4]; |
1047 | RegSet allow = (RSET_GPR & ~RSET_SCRATCH); | ||
1048 | RegSet drop = RSET_SCRATCH; | 1632 | RegSet drop = RSET_SCRATCH; |
1049 | lua_assert(sz != CTSIZE_INVALID); | 1633 | lj_assertA(sz != CTSIZE_INVALID || (ir->o == IR_CNEW && ir->op2 != REF_NIL), |
1634 | "bad CNEW/CNEWI operands"); | ||
1050 | 1635 | ||
1051 | args[0] = ASMREF_L; /* lua_State *L */ | ||
1052 | args[1] = ASMREF_TMP1; /* MSize size */ | ||
1053 | as->gcsteps++; | 1636 | as->gcsteps++; |
1054 | |||
1055 | if (ra_hasreg(ir->r)) | 1637 | if (ra_hasreg(ir->r)) |
1056 | rset_clear(drop, ir->r); /* Dest reg handled below. */ | 1638 | rset_clear(drop, ir->r); /* Dest reg handled below. */ |
1057 | ra_evictset(as, drop); | 1639 | ra_evictset(as, drop); |
@@ -1060,11 +1642,12 @@ static void asm_cnew(ASMState *as, IRIns *ir) | |||
1060 | 1642 | ||
1061 | /* Initialize immutable cdata object. */ | 1643 | /* Initialize immutable cdata object. */ |
1062 | if (ir->o == IR_CNEWI) { | 1644 | if (ir->o == IR_CNEWI) { |
1645 | RegSet allow = (RSET_GPR & ~RSET_SCRATCH); | ||
1646 | #if LJ_32 | ||
1063 | int32_t ofs = sizeof(GCcdata); | 1647 | int32_t ofs = sizeof(GCcdata); |
1064 | lua_assert(sz == 4 || sz == 8); | ||
1065 | if (sz == 8) { | 1648 | if (sz == 8) { |
1066 | ofs += 4; | 1649 | ofs += 4; |
1067 | lua_assert((ir+1)->o == IR_HIOP); | 1650 | lj_assertA((ir+1)->o == IR_HIOP, "expected HIOP for CNEWI"); |
1068 | if (LJ_LE) ir++; | 1651 | if (LJ_LE) ir++; |
1069 | } | 1652 | } |
1070 | for (;;) { | 1653 | for (;;) { |
@@ -1074,18 +1657,33 @@ static void asm_cnew(ASMState *as, IRIns *ir) | |||
1074 | if (ofs == sizeof(GCcdata)) break; | 1657 | if (ofs == sizeof(GCcdata)) break; |
1075 | ofs -= 4; if (LJ_BE) ir++; else ir--; | 1658 | ofs -= 4; if (LJ_BE) ir++; else ir--; |
1076 | } | 1659 | } |
1660 | #else | ||
1661 | emit_tsi(as, sz == 8 ? MIPSI_SD : MIPSI_SW, ra_alloc1(as, ir->op2, allow), | ||
1662 | RID_RET, sizeof(GCcdata)); | ||
1663 | #endif | ||
1664 | lj_assertA(sz == 4 || sz == 8, "bad CNEWI size %d", sz); | ||
1665 | } else if (ir->op2 != REF_NIL) { /* Create VLA/VLS/aligned cdata. */ | ||
1666 | ci = &lj_ir_callinfo[IRCALL_lj_cdata_newv]; | ||
1667 | args[0] = ASMREF_L; /* lua_State *L */ | ||
1668 | args[1] = ir->op1; /* CTypeID id */ | ||
1669 | args[2] = ir->op2; /* CTSize sz */ | ||
1670 | args[3] = ASMREF_TMP1; /* CTSize align */ | ||
1671 | asm_gencall(as, ci, args); | ||
1672 | emit_loadi(as, ra_releasetmp(as, ASMREF_TMP1), (int32_t)ctype_align(info)); | ||
1673 | return; | ||
1077 | } | 1674 | } |
1675 | |||
1078 | /* Initialize gct and ctypeid. lj_mem_newgco() already sets marked. */ | 1676 | /* Initialize gct and ctypeid. lj_mem_newgco() already sets marked. */ |
1079 | emit_tsi(as, MIPSI_SB, RID_RET+1, RID_RET, offsetof(GCcdata, gct)); | 1677 | emit_tsi(as, MIPSI_SB, RID_RET+1, RID_RET, offsetof(GCcdata, gct)); |
1080 | emit_tsi(as, MIPSI_SH, RID_TMP, RID_RET, offsetof(GCcdata, ctypeid)); | 1678 | emit_tsi(as, MIPSI_SH, RID_TMP, RID_RET, offsetof(GCcdata, ctypeid)); |
1081 | emit_ti(as, MIPSI_LI, RID_RET+1, ~LJ_TCDATA); | 1679 | emit_ti(as, MIPSI_LI, RID_RET+1, ~LJ_TCDATA); |
1082 | emit_ti(as, MIPSI_LI, RID_TMP, ctypeid); /* Lower 16 bit used. Sign-ext ok. */ | 1680 | emit_ti(as, MIPSI_LI, RID_TMP, id); /* Lower 16 bit used. Sign-ext ok. */ |
1681 | args[0] = ASMREF_L; /* lua_State *L */ | ||
1682 | args[1] = ASMREF_TMP1; /* MSize size */ | ||
1083 | asm_gencall(as, ci, args); | 1683 | asm_gencall(as, ci, args); |
1084 | ra_allockreg(as, (int32_t)(sz+sizeof(GCcdata)), | 1684 | ra_allockreg(as, (int32_t)(sz+sizeof(GCcdata)), |
1085 | ra_releasetmp(as, ASMREF_TMP1)); | 1685 | ra_releasetmp(as, ASMREF_TMP1)); |
1086 | } | 1686 | } |
1087 | #else | ||
1088 | #define asm_cnew(as, ir) ((void)0) | ||
1089 | #endif | 1687 | #endif |
1090 | 1688 | ||
1091 | /* -- Write barriers ------------------------------------------------------ */ | 1689 | /* -- Write barriers ------------------------------------------------------ */ |
@@ -1096,7 +1694,7 @@ static void asm_tbar(ASMState *as, IRIns *ir) | |||
1096 | Reg mark = ra_scratch(as, rset_exclude(RSET_GPR, tab)); | 1694 | Reg mark = ra_scratch(as, rset_exclude(RSET_GPR, tab)); |
1097 | Reg link = RID_TMP; | 1695 | Reg link = RID_TMP; |
1098 | MCLabel l_end = emit_label(as); | 1696 | MCLabel l_end = emit_label(as); |
1099 | emit_tsi(as, MIPSI_SW, link, tab, (int32_t)offsetof(GCtab, gclist)); | 1697 | emit_tsi(as, MIPSI_AS, link, tab, (int32_t)offsetof(GCtab, gclist)); |
1100 | emit_tsi(as, MIPSI_SB, mark, tab, (int32_t)offsetof(GCtab, marked)); | 1698 | emit_tsi(as, MIPSI_SB, mark, tab, (int32_t)offsetof(GCtab, marked)); |
1101 | emit_setgl(as, tab, gc.grayagain); | 1699 | emit_setgl(as, tab, gc.grayagain); |
1102 | emit_getgl(as, link, gc.grayagain); | 1700 | emit_getgl(as, link, gc.grayagain); |
@@ -1113,13 +1711,13 @@ static void asm_obar(ASMState *as, IRIns *ir) | |||
1113 | MCLabel l_end; | 1711 | MCLabel l_end; |
1114 | Reg obj, val, tmp; | 1712 | Reg obj, val, tmp; |
1115 | /* No need for other object barriers (yet). */ | 1713 | /* No need for other object barriers (yet). */ |
1116 | lua_assert(IR(ir->op1)->o == IR_UREFC); | 1714 | lj_assertA(IR(ir->op1)->o == IR_UREFC, "bad OBAR type"); |
1117 | ra_evictset(as, RSET_SCRATCH); | 1715 | ra_evictset(as, RSET_SCRATCH); |
1118 | l_end = emit_label(as); | 1716 | l_end = emit_label(as); |
1119 | args[0] = ASMREF_TMP1; /* global_State *g */ | 1717 | args[0] = ASMREF_TMP1; /* global_State *g */ |
1120 | args[1] = ir->op1; /* TValue *tv */ | 1718 | args[1] = ir->op1; /* TValue *tv */ |
1121 | asm_gencall(as, ci, args); | 1719 | asm_gencall(as, ci, args); |
1122 | emit_tsi(as, MIPSI_ADDIU, ra_releasetmp(as, ASMREF_TMP1), RID_JGL, -32768); | 1720 | emit_tsi(as, MIPSI_AADDIU, ra_releasetmp(as, ASMREF_TMP1), RID_JGL, -32768); |
1123 | obj = IR(ir->op1)->r; | 1721 | obj = IR(ir->op1)->r; |
1124 | tmp = ra_scratch(as, rset_exclude(RSET_GPR, obj)); | 1722 | tmp = ra_scratch(as, rset_exclude(RSET_GPR, obj)); |
1125 | emit_branch(as, MIPSI_BEQ, RID_TMP, RID_ZERO, l_end); | 1723 | emit_branch(as, MIPSI_BEQ, RID_TMP, RID_ZERO, l_end); |
@@ -1134,6 +1732,7 @@ static void asm_obar(ASMState *as, IRIns *ir) | |||
1134 | 1732 | ||
1135 | /* -- Arithmetic and logic operations ------------------------------------- */ | 1733 | /* -- Arithmetic and logic operations ------------------------------------- */ |
1136 | 1734 | ||
1735 | #if !LJ_SOFTFP | ||
1137 | static void asm_fparith(ASMState *as, IRIns *ir, MIPSIns mi) | 1736 | static void asm_fparith(ASMState *as, IRIns *ir, MIPSIns mi) |
1138 | { | 1737 | { |
1139 | Reg dest = ra_dest(as, ir, RSET_FPR); | 1738 | Reg dest = ra_dest(as, ir, RSET_FPR); |
@@ -1148,83 +1747,147 @@ static void asm_fpunary(ASMState *as, IRIns *ir, MIPSIns mi) | |||
1148 | Reg left = ra_hintalloc(as, ir->op1, dest, RSET_FPR); | 1747 | Reg left = ra_hintalloc(as, ir->op1, dest, RSET_FPR); |
1149 | emit_fg(as, mi, dest, left); | 1748 | emit_fg(as, mi, dest, left); |
1150 | } | 1749 | } |
1750 | #endif | ||
1151 | 1751 | ||
1152 | static int asm_fpjoin_pow(ASMState *as, IRIns *ir) | 1752 | #if !LJ_SOFTFP32 |
1153 | { | 1753 | static void asm_fpmath(ASMState *as, IRIns *ir) |
1154 | IRIns *irp = IR(ir->op1); | 1754 | { |
1155 | if (irp == ir-1 && irp->o == IR_MUL && !ra_used(irp)) { | 1755 | #if !LJ_SOFTFP |
1156 | IRIns *irpp = IR(irp->op1); | 1756 | if (ir->op2 <= IRFPM_TRUNC) |
1157 | if (irpp == ir-2 && irpp->o == IR_FPMATH && | 1757 | asm_callround(as, ir, IRCALL_lj_vm_floor + ir->op2); |
1158 | irpp->op2 == IRFPM_LOG2 && !ra_used(irpp)) { | 1758 | else if (ir->op2 == IRFPM_SQRT) |
1159 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_pow]; | 1759 | asm_fpunary(as, ir, MIPSI_SQRT_D); |
1160 | IRRef args[2]; | 1760 | else |
1161 | args[0] = irpp->op1; | 1761 | #endif |
1162 | args[1] = irp->op2; | 1762 | asm_callid(as, ir, IRCALL_lj_vm_floor + ir->op2); |
1163 | asm_setupresult(as, ir, ci); | ||
1164 | asm_gencall(as, ci, args); | ||
1165 | return 1; | ||
1166 | } | ||
1167 | } | ||
1168 | return 0; | ||
1169 | } | 1763 | } |
1764 | #endif | ||
1765 | |||
1766 | #if !LJ_SOFTFP | ||
1767 | #define asm_fpadd(as, ir) asm_fparith(as, ir, MIPSI_ADD_D) | ||
1768 | #define asm_fpsub(as, ir) asm_fparith(as, ir, MIPSI_SUB_D) | ||
1769 | #define asm_fpmul(as, ir) asm_fparith(as, ir, MIPSI_MUL_D) | ||
1770 | #elif LJ_64 /* && LJ_SOFTFP */ | ||
1771 | #define asm_fpadd(as, ir) asm_callid(as, ir, IRCALL_softfp_add) | ||
1772 | #define asm_fpsub(as, ir) asm_callid(as, ir, IRCALL_softfp_sub) | ||
1773 | #define asm_fpmul(as, ir) asm_callid(as, ir, IRCALL_softfp_mul) | ||
1774 | #endif | ||
1170 | 1775 | ||
1171 | static void asm_add(ASMState *as, IRIns *ir) | 1776 | static void asm_add(ASMState *as, IRIns *ir) |
1172 | { | 1777 | { |
1173 | if (irt_isnum(ir->t)) { | 1778 | IRType1 t = ir->t; |
1174 | asm_fparith(as, ir, MIPSI_ADD_D); | 1779 | #if !LJ_SOFTFP32 |
1175 | } else { | 1780 | if (irt_isnum(t)) { |
1781 | asm_fpadd(as, ir); | ||
1782 | } else | ||
1783 | #endif | ||
1784 | { | ||
1785 | /* TODO MIPSR6: Fuse ADD(BSHL(a,1-4),b) or ADD(ADD(a,a),b) to MIPSI_ALSA. */ | ||
1176 | Reg dest = ra_dest(as, ir, RSET_GPR); | 1786 | Reg dest = ra_dest(as, ir, RSET_GPR); |
1177 | Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); | 1787 | Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); |
1178 | if (irref_isk(ir->op2)) { | 1788 | if (irref_isk(ir->op2)) { |
1179 | int32_t k = IR(ir->op2)->i; | 1789 | intptr_t k = get_kval(as, ir->op2); |
1180 | if (checki16(k)) { | 1790 | if (checki16(k)) { |
1181 | emit_tsi(as, MIPSI_ADDIU, dest, left, k); | 1791 | emit_tsi(as, (LJ_64 && irt_is64(t)) ? MIPSI_DADDIU : MIPSI_ADDIU, dest, |
1792 | left, k); | ||
1182 | return; | 1793 | return; |
1183 | } | 1794 | } |
1184 | } | 1795 | } |
1185 | right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); | 1796 | right = ra_alloc1(as, ir->op2, rset_exclude(RSET_GPR, left)); |
1186 | emit_dst(as, MIPSI_ADDU, dest, left, right); | 1797 | emit_dst(as, (LJ_64 && irt_is64(t)) ? MIPSI_DADDU : MIPSI_ADDU, dest, |
1798 | left, right); | ||
1187 | } | 1799 | } |
1188 | } | 1800 | } |
1189 | 1801 | ||
1190 | static void asm_sub(ASMState *as, IRIns *ir) | 1802 | static void asm_sub(ASMState *as, IRIns *ir) |
1191 | { | 1803 | { |
1804 | #if !LJ_SOFTFP32 | ||
1192 | if (irt_isnum(ir->t)) { | 1805 | if (irt_isnum(ir->t)) { |
1193 | asm_fparith(as, ir, MIPSI_SUB_D); | 1806 | asm_fpsub(as, ir); |
1194 | } else { | 1807 | } else |
1808 | #endif | ||
1809 | { | ||
1195 | Reg dest = ra_dest(as, ir, RSET_GPR); | 1810 | Reg dest = ra_dest(as, ir, RSET_GPR); |
1196 | Reg right, left = ra_alloc2(as, ir, RSET_GPR); | 1811 | Reg right, left = ra_alloc2(as, ir, RSET_GPR); |
1197 | right = (left >> 8); left &= 255; | 1812 | right = (left >> 8); left &= 255; |
1198 | emit_dst(as, MIPSI_SUBU, dest, left, right); | 1813 | emit_dst(as, (LJ_64 && irt_is64(ir->t)) ? MIPSI_DSUBU : MIPSI_SUBU, dest, |
1814 | left, right); | ||
1199 | } | 1815 | } |
1200 | } | 1816 | } |
1201 | 1817 | ||
1202 | static void asm_mul(ASMState *as, IRIns *ir) | 1818 | static void asm_mul(ASMState *as, IRIns *ir) |
1203 | { | 1819 | { |
1820 | #if !LJ_SOFTFP32 | ||
1204 | if (irt_isnum(ir->t)) { | 1821 | if (irt_isnum(ir->t)) { |
1205 | asm_fparith(as, ir, MIPSI_MUL_D); | 1822 | asm_fpmul(as, ir); |
1206 | } else { | 1823 | } else |
1824 | #endif | ||
1825 | { | ||
1207 | Reg dest = ra_dest(as, ir, RSET_GPR); | 1826 | Reg dest = ra_dest(as, ir, RSET_GPR); |
1208 | Reg right, left = ra_alloc2(as, ir, RSET_GPR); | 1827 | Reg right, left = ra_alloc2(as, ir, RSET_GPR); |
1209 | right = (left >> 8); left &= 255; | 1828 | right = (left >> 8); left &= 255; |
1210 | emit_dst(as, MIPSI_MUL, dest, left, right); | 1829 | if (LJ_64 && irt_is64(ir->t)) { |
1830 | #if !LJ_TARGET_MIPSR6 | ||
1831 | emit_dst(as, MIPSI_MFLO, dest, 0, 0); | ||
1832 | emit_dst(as, MIPSI_DMULT, 0, left, right); | ||
1833 | #else | ||
1834 | emit_dst(as, MIPSI_DMUL, dest, left, right); | ||
1835 | #endif | ||
1836 | } else { | ||
1837 | emit_dst(as, MIPSI_MUL, dest, left, right); | ||
1838 | } | ||
1211 | } | 1839 | } |
1212 | } | 1840 | } |
1213 | 1841 | ||
1842 | #if !LJ_SOFTFP32 | ||
1843 | static void asm_fpdiv(ASMState *as, IRIns *ir) | ||
1844 | { | ||
1845 | #if !LJ_SOFTFP | ||
1846 | asm_fparith(as, ir, MIPSI_DIV_D); | ||
1847 | #else | ||
1848 | asm_callid(as, ir, IRCALL_softfp_div); | ||
1849 | #endif | ||
1850 | } | ||
1851 | #endif | ||
1852 | |||
1214 | static void asm_neg(ASMState *as, IRIns *ir) | 1853 | static void asm_neg(ASMState *as, IRIns *ir) |
1215 | { | 1854 | { |
1855 | #if !LJ_SOFTFP | ||
1216 | if (irt_isnum(ir->t)) { | 1856 | if (irt_isnum(ir->t)) { |
1217 | asm_fpunary(as, ir, MIPSI_NEG_D); | 1857 | asm_fpunary(as, ir, MIPSI_NEG_D); |
1218 | } else { | 1858 | } else |
1859 | #elif LJ_64 /* && LJ_SOFTFP */ | ||
1860 | if (irt_isnum(ir->t)) { | ||
1861 | Reg dest = ra_dest(as, ir, RSET_GPR); | ||
1862 | Reg left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); | ||
1863 | emit_dst(as, MIPSI_XOR, dest, left, | ||
1864 | ra_allock(as, 0x8000000000000000ll, rset_exclude(RSET_GPR, dest))); | ||
1865 | } else | ||
1866 | #endif | ||
1867 | { | ||
1219 | Reg dest = ra_dest(as, ir, RSET_GPR); | 1868 | Reg dest = ra_dest(as, ir, RSET_GPR); |
1220 | Reg left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); | 1869 | Reg left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); |
1221 | emit_dst(as, MIPSI_SUBU, dest, RID_ZERO, left); | 1870 | emit_dst(as, (LJ_64 && irt_is64(ir->t)) ? MIPSI_DSUBU : MIPSI_SUBU, dest, |
1871 | RID_ZERO, left); | ||
1222 | } | 1872 | } |
1223 | } | 1873 | } |
1224 | 1874 | ||
1875 | #if !LJ_SOFTFP | ||
1876 | #define asm_abs(as, ir) asm_fpunary(as, ir, MIPSI_ABS_D) | ||
1877 | #elif LJ_64 /* && LJ_SOFTFP */ | ||
1878 | static void asm_abs(ASMState *as, IRIns *ir) | ||
1879 | { | ||
1880 | Reg dest = ra_dest(as, ir, RSET_GPR); | ||
1881 | Reg left = ra_alloc1(as, ir->op1, RSET_GPR); | ||
1882 | emit_tsml(as, MIPSI_DEXTM, dest, left, 30, 0); | ||
1883 | } | ||
1884 | #endif | ||
1885 | |||
1225 | static void asm_arithov(ASMState *as, IRIns *ir) | 1886 | static void asm_arithov(ASMState *as, IRIns *ir) |
1226 | { | 1887 | { |
1888 | /* TODO MIPSR6: bovc/bnvc. Caveat: no delay slot to load RID_TMP. */ | ||
1227 | Reg right, left, tmp, dest = ra_dest(as, ir, RSET_GPR); | 1889 | Reg right, left, tmp, dest = ra_dest(as, ir, RSET_GPR); |
1890 | lj_assertA(!irt_is64(ir->t), "bad usage"); | ||
1228 | if (irref_isk(ir->op2)) { | 1891 | if (irref_isk(ir->op2)) { |
1229 | int k = IR(ir->op2)->i; | 1892 | int k = IR(ir->op2)->i; |
1230 | if (ir->o == IR_SUBOV) k = -k; | 1893 | if (ir->o == IR_SUBOV) k = -k; |
@@ -1255,16 +1918,29 @@ static void asm_arithov(ASMState *as, IRIns *ir) | |||
1255 | emit_move(as, RID_TMP, dest == left ? left : right); | 1918 | emit_move(as, RID_TMP, dest == left ? left : right); |
1256 | } | 1919 | } |
1257 | 1920 | ||
1921 | #define asm_addov(as, ir) asm_arithov(as, ir) | ||
1922 | #define asm_subov(as, ir) asm_arithov(as, ir) | ||
1923 | |||
1258 | static void asm_mulov(ASMState *as, IRIns *ir) | 1924 | static void asm_mulov(ASMState *as, IRIns *ir) |
1259 | { | 1925 | { |
1260 | #if LJ_DUALNUM | 1926 | Reg dest = ra_dest(as, ir, RSET_GPR); |
1261 | #error "NYI: MULOV" | 1927 | Reg tmp, right, left = ra_alloc2(as, ir, RSET_GPR); |
1928 | right = (left >> 8); left &= 255; | ||
1929 | tmp = ra_scratch(as, rset_exclude(rset_exclude(rset_exclude(RSET_GPR, left), | ||
1930 | right), dest)); | ||
1931 | asm_guard(as, MIPSI_BNE, RID_TMP, tmp); | ||
1932 | emit_dta(as, MIPSI_SRA, RID_TMP, dest, 31); | ||
1933 | #if !LJ_TARGET_MIPSR6 | ||
1934 | emit_dst(as, MIPSI_MFHI, tmp, 0, 0); | ||
1935 | emit_dst(as, MIPSI_MFLO, dest, 0, 0); | ||
1936 | emit_dst(as, MIPSI_MULT, 0, left, right); | ||
1262 | #else | 1937 | #else |
1263 | UNUSED(as); UNUSED(ir); lua_assert(0); /* Unused in single-number mode. */ | 1938 | emit_dst(as, MIPSI_MUL, dest, left, right); |
1939 | emit_dst(as, MIPSI_MUH, tmp, left, right); | ||
1264 | #endif | 1940 | #endif |
1265 | } | 1941 | } |
1266 | 1942 | ||
1267 | #if LJ_HASFFI | 1943 | #if LJ_32 && LJ_HASFFI |
1268 | static void asm_add64(ASMState *as, IRIns *ir) | 1944 | static void asm_add64(ASMState *as, IRIns *ir) |
1269 | { | 1945 | { |
1270 | Reg dest = ra_dest(as, ir, RSET_GPR); | 1946 | Reg dest = ra_dest(as, ir, RSET_GPR); |
@@ -1348,7 +2024,7 @@ static void asm_neg64(ASMState *as, IRIns *ir) | |||
1348 | } | 2024 | } |
1349 | #endif | 2025 | #endif |
1350 | 2026 | ||
1351 | static void asm_bitnot(ASMState *as, IRIns *ir) | 2027 | static void asm_bnot(ASMState *as, IRIns *ir) |
1352 | { | 2028 | { |
1353 | Reg left, right, dest = ra_dest(as, ir, RSET_GPR); | 2029 | Reg left, right, dest = ra_dest(as, ir, RSET_GPR); |
1354 | IRIns *irl = IR(ir->op1); | 2030 | IRIns *irl = IR(ir->op1); |
@@ -1362,11 +2038,12 @@ static void asm_bitnot(ASMState *as, IRIns *ir) | |||
1362 | emit_dst(as, MIPSI_NOR, dest, left, right); | 2038 | emit_dst(as, MIPSI_NOR, dest, left, right); |
1363 | } | 2039 | } |
1364 | 2040 | ||
1365 | static void asm_bitswap(ASMState *as, IRIns *ir) | 2041 | static void asm_bswap(ASMState *as, IRIns *ir) |
1366 | { | 2042 | { |
1367 | Reg dest = ra_dest(as, ir, RSET_GPR); | 2043 | Reg dest = ra_dest(as, ir, RSET_GPR); |
1368 | Reg left = ra_alloc1(as, ir->op1, RSET_GPR); | 2044 | Reg left = ra_alloc1(as, ir->op1, RSET_GPR); |
1369 | if ((as->flags & JIT_F_MIPS32R2)) { | 2045 | #if LJ_32 |
2046 | if ((as->flags & JIT_F_MIPSXXR2)) { | ||
1370 | emit_dta(as, MIPSI_ROTR, dest, RID_TMP, 16); | 2047 | emit_dta(as, MIPSI_ROTR, dest, RID_TMP, 16); |
1371 | emit_dst(as, MIPSI_WSBH, RID_TMP, 0, left); | 2048 | emit_dst(as, MIPSI_WSBH, RID_TMP, 0, left); |
1372 | } else { | 2049 | } else { |
@@ -1381,6 +2058,15 @@ static void asm_bitswap(ASMState *as, IRIns *ir) | |||
1381 | emit_dta(as, MIPSI_SRL, tmp, left, 24); | 2058 | emit_dta(as, MIPSI_SRL, tmp, left, 24); |
1382 | emit_dta(as, MIPSI_SLL, RID_TMP, left, 24); | 2059 | emit_dta(as, MIPSI_SLL, RID_TMP, left, 24); |
1383 | } | 2060 | } |
2061 | #else | ||
2062 | if (irt_is64(ir->t)) { | ||
2063 | emit_dst(as, MIPSI_DSHD, dest, 0, RID_TMP); | ||
2064 | emit_dst(as, MIPSI_DSBH, RID_TMP, 0, left); | ||
2065 | } else { | ||
2066 | emit_dta(as, MIPSI_ROTR, dest, RID_TMP, 16); | ||
2067 | emit_dst(as, MIPSI_WSBH, RID_TMP, 0, left); | ||
2068 | } | ||
2069 | #endif | ||
1384 | } | 2070 | } |
1385 | 2071 | ||
1386 | static void asm_bitop(ASMState *as, IRIns *ir, MIPSIns mi, MIPSIns mik) | 2072 | static void asm_bitop(ASMState *as, IRIns *ir, MIPSIns mi, MIPSIns mik) |
@@ -1388,7 +2074,7 @@ static void asm_bitop(ASMState *as, IRIns *ir, MIPSIns mi, MIPSIns mik) | |||
1388 | Reg dest = ra_dest(as, ir, RSET_GPR); | 2074 | Reg dest = ra_dest(as, ir, RSET_GPR); |
1389 | Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); | 2075 | Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); |
1390 | if (irref_isk(ir->op2)) { | 2076 | if (irref_isk(ir->op2)) { |
1391 | int32_t k = IR(ir->op2)->i; | 2077 | intptr_t k = get_kval(as, ir->op2); |
1392 | if (checku16(k)) { | 2078 | if (checku16(k)) { |
1393 | emit_tsi(as, mik, dest, left, k); | 2079 | emit_tsi(as, mik, dest, left, k); |
1394 | return; | 2080 | return; |
@@ -1398,22 +2084,34 @@ static void asm_bitop(ASMState *as, IRIns *ir, MIPSIns mi, MIPSIns mik) | |||
1398 | emit_dst(as, mi, dest, left, right); | 2084 | emit_dst(as, mi, dest, left, right); |
1399 | } | 2085 | } |
1400 | 2086 | ||
2087 | #define asm_band(as, ir) asm_bitop(as, ir, MIPSI_AND, MIPSI_ANDI) | ||
2088 | #define asm_bor(as, ir) asm_bitop(as, ir, MIPSI_OR, MIPSI_ORI) | ||
2089 | #define asm_bxor(as, ir) asm_bitop(as, ir, MIPSI_XOR, MIPSI_XORI) | ||
2090 | |||
1401 | static void asm_bitshift(ASMState *as, IRIns *ir, MIPSIns mi, MIPSIns mik) | 2091 | static void asm_bitshift(ASMState *as, IRIns *ir, MIPSIns mi, MIPSIns mik) |
1402 | { | 2092 | { |
1403 | Reg dest = ra_dest(as, ir, RSET_GPR); | 2093 | Reg dest = ra_dest(as, ir, RSET_GPR); |
1404 | if (irref_isk(ir->op2)) { /* Constant shifts. */ | 2094 | if (irref_isk(ir->op2)) { /* Constant shifts. */ |
1405 | uint32_t shift = (uint32_t)(IR(ir->op2)->i & 31); | 2095 | uint32_t shift = (uint32_t)IR(ir->op2)->i; |
1406 | emit_dta(as, mik, dest, ra_hintalloc(as, ir->op1, dest, RSET_GPR), shift); | 2096 | if (LJ_64 && irt_is64(ir->t)) mik |= (shift & 32) ? MIPSI_D32 : MIPSI_D; |
2097 | emit_dta(as, mik, dest, ra_hintalloc(as, ir->op1, dest, RSET_GPR), | ||
2098 | (shift & 31)); | ||
1407 | } else { | 2099 | } else { |
1408 | Reg right, left = ra_alloc2(as, ir, RSET_GPR); | 2100 | Reg right, left = ra_alloc2(as, ir, RSET_GPR); |
1409 | right = (left >> 8); left &= 255; | 2101 | right = (left >> 8); left &= 255; |
2102 | if (LJ_64 && irt_is64(ir->t)) mi |= MIPSI_DV; | ||
1410 | emit_dst(as, mi, dest, right, left); /* Shift amount is in rs. */ | 2103 | emit_dst(as, mi, dest, right, left); /* Shift amount is in rs. */ |
1411 | } | 2104 | } |
1412 | } | 2105 | } |
1413 | 2106 | ||
1414 | static void asm_bitror(ASMState *as, IRIns *ir) | 2107 | #define asm_bshl(as, ir) asm_bitshift(as, ir, MIPSI_SLLV, MIPSI_SLL) |
2108 | #define asm_bshr(as, ir) asm_bitshift(as, ir, MIPSI_SRLV, MIPSI_SRL) | ||
2109 | #define asm_bsar(as, ir) asm_bitshift(as, ir, MIPSI_SRAV, MIPSI_SRA) | ||
2110 | #define asm_brol(as, ir) lj_assertA(0, "unexpected BROL") | ||
2111 | |||
2112 | static void asm_bror(ASMState *as, IRIns *ir) | ||
1415 | { | 2113 | { |
1416 | if ((as->flags & JIT_F_MIPS32R2)) { | 2114 | if (LJ_64 || (as->flags & JIT_F_MIPSXXR2)) { |
1417 | asm_bitshift(as, ir, MIPSI_ROTRV, MIPSI_ROTR); | 2115 | asm_bitshift(as, ir, MIPSI_ROTRV, MIPSI_ROTR); |
1418 | } else { | 2116 | } else { |
1419 | Reg dest = ra_dest(as, ir, RSET_GPR); | 2117 | Reg dest = ra_dest(as, ir, RSET_GPR); |
@@ -1432,55 +2130,182 @@ static void asm_bitror(ASMState *as, IRIns *ir) | |||
1432 | } | 2130 | } |
1433 | } | 2131 | } |
1434 | 2132 | ||
2133 | #if LJ_SOFTFP | ||
2134 | static void asm_sfpmin_max(ASMState *as, IRIns *ir) | ||
2135 | { | ||
2136 | CCallInfo ci = lj_ir_callinfo[(IROp)ir->o == IR_MIN ? IRCALL_lj_vm_sfmin : IRCALL_lj_vm_sfmax]; | ||
2137 | #if LJ_64 | ||
2138 | IRRef args[2]; | ||
2139 | args[0] = ir->op1; | ||
2140 | args[1] = ir->op2; | ||
2141 | #else | ||
2142 | IRRef args[4]; | ||
2143 | args[0^LJ_BE] = ir->op1; | ||
2144 | args[1^LJ_BE] = (ir+1)->op1; | ||
2145 | args[2^LJ_BE] = ir->op2; | ||
2146 | args[3^LJ_BE] = (ir+1)->op2; | ||
2147 | #endif | ||
2148 | asm_setupresult(as, ir, &ci); | ||
2149 | emit_call(as, (void *)ci.func, 0); | ||
2150 | ci.func = NULL; | ||
2151 | asm_gencall(as, &ci, args); | ||
2152 | } | ||
2153 | #endif | ||
2154 | |||
1435 | static void asm_min_max(ASMState *as, IRIns *ir, int ismax) | 2155 | static void asm_min_max(ASMState *as, IRIns *ir, int ismax) |
1436 | { | 2156 | { |
1437 | if (irt_isnum(ir->t)) { | 2157 | if (!LJ_SOFTFP32 && irt_isnum(ir->t)) { |
2158 | #if LJ_SOFTFP | ||
2159 | asm_sfpmin_max(as, ir); | ||
2160 | #else | ||
1438 | Reg dest = ra_dest(as, ir, RSET_FPR); | 2161 | Reg dest = ra_dest(as, ir, RSET_FPR); |
1439 | Reg right, left = ra_alloc2(as, ir, RSET_FPR); | 2162 | Reg right, left = ra_alloc2(as, ir, RSET_FPR); |
1440 | right = (left >> 8); left &= 255; | 2163 | right = (left >> 8); left &= 255; |
2164 | #if !LJ_TARGET_MIPSR6 | ||
1441 | if (dest == left) { | 2165 | if (dest == left) { |
1442 | emit_fg(as, MIPSI_MOVT_D, dest, right); | 2166 | emit_fg(as, MIPSI_MOVF_D, dest, right); |
1443 | } else { | 2167 | } else { |
1444 | emit_fg(as, MIPSI_MOVF_D, dest, left); | 2168 | emit_fg(as, MIPSI_MOVT_D, dest, left); |
1445 | if (dest != right) emit_fg(as, MIPSI_MOV_D, dest, right); | 2169 | if (dest != right) emit_fg(as, MIPSI_MOV_D, dest, right); |
1446 | } | 2170 | } |
1447 | emit_fgh(as, MIPSI_C_OLT_D, 0, ismax ? left : right, ismax ? right : left); | 2171 | emit_fgh(as, MIPSI_C_OLT_D, 0, ismax ? right : left, ismax ? left : right); |
2172 | #else | ||
2173 | emit_fgh(as, ismax ? MIPSI_MAX_D : MIPSI_MIN_D, dest, left, right); | ||
2174 | #endif | ||
2175 | #endif | ||
1448 | } else { | 2176 | } else { |
1449 | Reg dest = ra_dest(as, ir, RSET_GPR); | 2177 | Reg dest = ra_dest(as, ir, RSET_GPR); |
1450 | Reg right, left = ra_alloc2(as, ir, RSET_GPR); | 2178 | Reg right, left = ra_alloc2(as, ir, RSET_GPR); |
1451 | right = (left >> 8); left &= 255; | 2179 | right = (left >> 8); left &= 255; |
1452 | if (dest == left) { | 2180 | if (left == right) { |
1453 | emit_dst(as, MIPSI_MOVN, dest, right, RID_TMP); | 2181 | if (dest != left) emit_move(as, dest, left); |
1454 | } else { | 2182 | } else { |
1455 | emit_dst(as, MIPSI_MOVZ, dest, left, RID_TMP); | 2183 | #if !LJ_TARGET_MIPSR6 |
1456 | if (dest != right) emit_move(as, dest, right); | 2184 | if (dest == left) { |
2185 | emit_dst(as, MIPSI_MOVN, dest, right, RID_TMP); | ||
2186 | } else { | ||
2187 | emit_dst(as, MIPSI_MOVZ, dest, left, RID_TMP); | ||
2188 | if (dest != right) emit_move(as, dest, right); | ||
2189 | } | ||
2190 | #else | ||
2191 | emit_dst(as, MIPSI_OR, dest, dest, RID_TMP); | ||
2192 | if (dest != right) { | ||
2193 | emit_dst(as, MIPSI_SELNEZ, RID_TMP, right, RID_TMP); | ||
2194 | emit_dst(as, MIPSI_SELEQZ, dest, left, RID_TMP); | ||
2195 | } else { | ||
2196 | emit_dst(as, MIPSI_SELEQZ, RID_TMP, left, RID_TMP); | ||
2197 | emit_dst(as, MIPSI_SELNEZ, dest, right, RID_TMP); | ||
2198 | } | ||
2199 | #endif | ||
2200 | emit_dst(as, MIPSI_SLT, RID_TMP, | ||
2201 | ismax ? left : right, ismax ? right : left); | ||
1457 | } | 2202 | } |
1458 | emit_dst(as, MIPSI_SLT, RID_TMP, | ||
1459 | ismax ? left : right, ismax ? right : left); | ||
1460 | } | 2203 | } |
1461 | } | 2204 | } |
1462 | 2205 | ||
2206 | #define asm_min(as, ir) asm_min_max(as, ir, 0) | ||
2207 | #define asm_max(as, ir) asm_min_max(as, ir, 1) | ||
2208 | |||
1463 | /* -- Comparisons --------------------------------------------------------- */ | 2209 | /* -- Comparisons --------------------------------------------------------- */ |
1464 | 2210 | ||
2211 | #if LJ_SOFTFP | ||
2212 | /* SFP comparisons. */ | ||
2213 | static void asm_sfpcomp(ASMState *as, IRIns *ir) | ||
2214 | { | ||
2215 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_softfp_cmp]; | ||
2216 | RegSet drop = RSET_SCRATCH; | ||
2217 | Reg r; | ||
2218 | #if LJ_64 | ||
2219 | IRRef args[2]; | ||
2220 | args[0] = ir->op1; | ||
2221 | args[1] = ir->op2; | ||
2222 | #else | ||
2223 | IRRef args[4]; | ||
2224 | args[LJ_LE ? 0 : 1] = ir->op1; args[LJ_LE ? 1 : 0] = (ir+1)->op1; | ||
2225 | args[LJ_LE ? 2 : 3] = ir->op2; args[LJ_LE ? 3 : 2] = (ir+1)->op2; | ||
2226 | #endif | ||
2227 | |||
2228 | for (r = REGARG_FIRSTGPR; r <= REGARG_FIRSTGPR+(LJ_64?1:3); r++) { | ||
2229 | if (!rset_test(as->freeset, r) && | ||
2230 | regcost_ref(as->cost[r]) == args[r-REGARG_FIRSTGPR]) | ||
2231 | rset_clear(drop, r); | ||
2232 | } | ||
2233 | ra_evictset(as, drop); | ||
2234 | |||
2235 | asm_setupresult(as, ir, ci); | ||
2236 | |||
2237 | switch ((IROp)ir->o) { | ||
2238 | case IR_LT: | ||
2239 | asm_guard(as, MIPSI_BGEZ, RID_RET, 0); | ||
2240 | break; | ||
2241 | case IR_ULT: | ||
2242 | asm_guard(as, MIPSI_BEQ, RID_RET, RID_TMP); | ||
2243 | emit_loadi(as, RID_TMP, 1); | ||
2244 | asm_guard(as, MIPSI_BEQ, RID_RET, RID_ZERO); | ||
2245 | break; | ||
2246 | case IR_GE: | ||
2247 | asm_guard(as, MIPSI_BEQ, RID_RET, RID_TMP); | ||
2248 | emit_loadi(as, RID_TMP, 2); | ||
2249 | asm_guard(as, MIPSI_BLTZ, RID_RET, 0); | ||
2250 | break; | ||
2251 | case IR_LE: | ||
2252 | asm_guard(as, MIPSI_BGTZ, RID_RET, 0); | ||
2253 | break; | ||
2254 | case IR_GT: | ||
2255 | asm_guard(as, MIPSI_BEQ, RID_RET, RID_TMP); | ||
2256 | emit_loadi(as, RID_TMP, 2); | ||
2257 | asm_guard(as, MIPSI_BLEZ, RID_RET, 0); | ||
2258 | break; | ||
2259 | case IR_UGE: | ||
2260 | asm_guard(as, MIPSI_BLTZ, RID_RET, 0); | ||
2261 | break; | ||
2262 | case IR_ULE: | ||
2263 | asm_guard(as, MIPSI_BEQ, RID_RET, RID_TMP); | ||
2264 | emit_loadi(as, RID_TMP, 1); | ||
2265 | break; | ||
2266 | case IR_UGT: case IR_ABC: | ||
2267 | asm_guard(as, MIPSI_BLEZ, RID_RET, 0); | ||
2268 | break; | ||
2269 | case IR_EQ: case IR_NE: | ||
2270 | asm_guard(as, (ir->o & 1) ? MIPSI_BEQ : MIPSI_BNE, RID_RET, RID_ZERO); | ||
2271 | default: | ||
2272 | break; | ||
2273 | } | ||
2274 | asm_gencall(as, ci, args); | ||
2275 | } | ||
2276 | #endif | ||
2277 | |||
1465 | static void asm_comp(ASMState *as, IRIns *ir) | 2278 | static void asm_comp(ASMState *as, IRIns *ir) |
1466 | { | 2279 | { |
1467 | /* ORDER IR: LT GE LE GT ULT UGE ULE UGT. */ | 2280 | /* ORDER IR: LT GE LE GT ULT UGE ULE UGT. */ |
1468 | IROp op = ir->o; | 2281 | IROp op = ir->o; |
1469 | if (irt_isnum(ir->t)) { | 2282 | if (!LJ_SOFTFP32 && irt_isnum(ir->t)) { |
2283 | #if LJ_SOFTFP | ||
2284 | asm_sfpcomp(as, ir); | ||
2285 | #else | ||
2286 | #if !LJ_TARGET_MIPSR6 | ||
1470 | Reg right, left = ra_alloc2(as, ir, RSET_FPR); | 2287 | Reg right, left = ra_alloc2(as, ir, RSET_FPR); |
1471 | right = (left >> 8); left &= 255; | 2288 | right = (left >> 8); left &= 255; |
1472 | asm_guard(as, (op&1) ? MIPSI_BC1T : MIPSI_BC1F, 0, 0); | 2289 | asm_guard(as, (op&1) ? MIPSI_BC1T : MIPSI_BC1F, 0, 0); |
1473 | emit_fgh(as, MIPSI_C_OLT_D + ((op&3) ^ ((op>>2)&1)), 0, left, right); | 2290 | emit_fgh(as, MIPSI_C_OLT_D + ((op&3) ^ ((op>>2)&1)), 0, left, right); |
2291 | #else | ||
2292 | Reg tmp, right, left = ra_alloc2(as, ir, RSET_FPR); | ||
2293 | right = (left >> 8); left &= 255; | ||
2294 | tmp = ra_scratch(as, rset_exclude(rset_exclude(RSET_FPR, left), right)); | ||
2295 | asm_guard(as, (op&1) ? MIPSI_BC1NEZ : MIPSI_BC1EQZ, 0, (tmp&31)); | ||
2296 | emit_fgh(as, MIPSI_CMP_LT_D + ((op&3) ^ ((op>>2)&1)), tmp, left, right); | ||
2297 | #endif | ||
2298 | #endif | ||
1474 | } else { | 2299 | } else { |
1475 | Reg right, left = ra_alloc1(as, ir->op1, RSET_GPR); | 2300 | Reg right, left = ra_alloc1(as, ir->op1, RSET_GPR); |
1476 | if (op == IR_ABC) op = IR_UGT; | 2301 | if (op == IR_ABC) op = IR_UGT; |
1477 | if ((op&4) == 0 && irref_isk(ir->op2) && IR(ir->op2)->i == 0) { | 2302 | if ((op&4) == 0 && irref_isk(ir->op2) && get_kval(as, ir->op2) == 0) { |
1478 | MIPSIns mi = (op&2) ? ((op&1) ? MIPSI_BLEZ : MIPSI_BGTZ) : | 2303 | MIPSIns mi = (op&2) ? ((op&1) ? MIPSI_BLEZ : MIPSI_BGTZ) : |
1479 | ((op&1) ? MIPSI_BLTZ : MIPSI_BGEZ); | 2304 | ((op&1) ? MIPSI_BLTZ : MIPSI_BGEZ); |
1480 | asm_guard(as, mi, left, 0); | 2305 | asm_guard(as, mi, left, 0); |
1481 | } else { | 2306 | } else { |
1482 | if (irref_isk(ir->op2)) { | 2307 | if (irref_isk(ir->op2)) { |
1483 | int32_t k = IR(ir->op2)->i; | 2308 | intptr_t k = get_kval(as, ir->op2); |
1484 | if ((op&2)) k++; | 2309 | if ((op&2)) k++; |
1485 | if (checki16(k)) { | 2310 | if (checki16(k)) { |
1486 | asm_guard(as, (op&1) ? MIPSI_BNE : MIPSI_BEQ, RID_TMP, RID_ZERO); | 2311 | asm_guard(as, (op&1) ? MIPSI_BNE : MIPSI_BEQ, RID_TMP, RID_ZERO); |
@@ -1497,19 +2322,28 @@ static void asm_comp(ASMState *as, IRIns *ir) | |||
1497 | } | 2322 | } |
1498 | } | 2323 | } |
1499 | 2324 | ||
1500 | static void asm_compeq(ASMState *as, IRIns *ir) | 2325 | static void asm_equal(ASMState *as, IRIns *ir) |
1501 | { | 2326 | { |
1502 | Reg right, left = ra_alloc2(as, ir, irt_isnum(ir->t) ? RSET_FPR : RSET_GPR); | 2327 | Reg right, left = ra_alloc2(as, ir, (!LJ_SOFTFP && irt_isnum(ir->t)) ? |
2328 | RSET_FPR : RSET_GPR); | ||
1503 | right = (left >> 8); left &= 255; | 2329 | right = (left >> 8); left &= 255; |
1504 | if (irt_isnum(ir->t)) { | 2330 | if (!LJ_SOFTFP32 && irt_isnum(ir->t)) { |
2331 | #if LJ_SOFTFP | ||
2332 | asm_sfpcomp(as, ir); | ||
2333 | #elif !LJ_TARGET_MIPSR6 | ||
1505 | asm_guard(as, (ir->o & 1) ? MIPSI_BC1T : MIPSI_BC1F, 0, 0); | 2334 | asm_guard(as, (ir->o & 1) ? MIPSI_BC1T : MIPSI_BC1F, 0, 0); |
1506 | emit_fgh(as, MIPSI_C_EQ_D, 0, left, right); | 2335 | emit_fgh(as, MIPSI_C_EQ_D, 0, left, right); |
2336 | #else | ||
2337 | Reg tmp = ra_scratch(as, rset_exclude(rset_exclude(RSET_FPR, left), right)); | ||
2338 | asm_guard(as, (ir->o & 1) ? MIPSI_BC1NEZ : MIPSI_BC1EQZ, 0, (tmp&31)); | ||
2339 | emit_fgh(as, MIPSI_CMP_EQ_D, tmp, left, right); | ||
2340 | #endif | ||
1507 | } else { | 2341 | } else { |
1508 | asm_guard(as, (ir->o & 1) ? MIPSI_BEQ : MIPSI_BNE, left, right); | 2342 | asm_guard(as, (ir->o & 1) ? MIPSI_BEQ : MIPSI_BNE, left, right); |
1509 | } | 2343 | } |
1510 | } | 2344 | } |
1511 | 2345 | ||
1512 | #if LJ_HASFFI | 2346 | #if LJ_32 && LJ_HASFFI |
1513 | /* 64 bit integer comparisons. */ | 2347 | /* 64 bit integer comparisons. */ |
1514 | static void asm_comp64(ASMState *as, IRIns *ir) | 2348 | static void asm_comp64(ASMState *as, IRIns *ir) |
1515 | { | 2349 | { |
@@ -1546,54 +2380,99 @@ static void asm_comp64eq(ASMState *as, IRIns *ir) | |||
1546 | } | 2380 | } |
1547 | #endif | 2381 | #endif |
1548 | 2382 | ||
1549 | /* -- Support for 64 bit ops in 32 bit mode ------------------------------- */ | 2383 | /* -- Split register ops -------------------------------------------------- */ |
1550 | 2384 | ||
1551 | /* Hiword op of a split 64 bit op. Previous op must be the loword op. */ | 2385 | /* Hiword op of a split 32/32 or 64/64 bit op. Previous op is the loword op. */ |
1552 | static void asm_hiop(ASMState *as, IRIns *ir) | 2386 | static void asm_hiop(ASMState *as, IRIns *ir) |
1553 | { | 2387 | { |
1554 | #if LJ_HASFFI | ||
1555 | /* HIOP is marked as a store because it needs its own DCE logic. */ | 2388 | /* HIOP is marked as a store because it needs its own DCE logic. */ |
1556 | int uselo = ra_used(ir-1), usehi = ra_used(ir); /* Loword/hiword used? */ | 2389 | int uselo = ra_used(ir-1), usehi = ra_used(ir); /* Loword/hiword used? */ |
1557 | if (LJ_UNLIKELY(!(as->flags & JIT_F_OPT_DCE))) uselo = usehi = 1; | 2390 | if (LJ_UNLIKELY(!(as->flags & JIT_F_OPT_DCE))) uselo = usehi = 1; |
2391 | #if LJ_32 && (LJ_HASFFI || LJ_SOFTFP) | ||
1558 | if ((ir-1)->o == IR_CONV) { /* Conversions to/from 64 bit. */ | 2392 | if ((ir-1)->o == IR_CONV) { /* Conversions to/from 64 bit. */ |
1559 | as->curins--; /* Always skip the CONV. */ | 2393 | as->curins--; /* Always skip the CONV. */ |
2394 | #if LJ_HASFFI && !LJ_SOFTFP | ||
1560 | if (usehi || uselo) | 2395 | if (usehi || uselo) |
1561 | asm_conv64(as, ir); | 2396 | asm_conv64(as, ir); |
1562 | return; | 2397 | return; |
2398 | #endif | ||
1563 | } else if ((ir-1)->o < IR_EQ) { /* 64 bit integer comparisons. ORDER IR. */ | 2399 | } else if ((ir-1)->o < IR_EQ) { /* 64 bit integer comparisons. ORDER IR. */ |
1564 | as->curins--; /* Always skip the loword comparison. */ | 2400 | as->curins--; /* Always skip the loword comparison. */ |
2401 | #if LJ_SOFTFP | ||
2402 | if (!irt_isint(ir->t)) { | ||
2403 | asm_sfpcomp(as, ir-1); | ||
2404 | return; | ||
2405 | } | ||
2406 | #endif | ||
2407 | #if LJ_HASFFI | ||
1565 | asm_comp64(as, ir); | 2408 | asm_comp64(as, ir); |
2409 | #endif | ||
1566 | return; | 2410 | return; |
1567 | } else if ((ir-1)->o <= IR_NE) { /* 64 bit integer comparisons. ORDER IR. */ | 2411 | } else if ((ir-1)->o <= IR_NE) { /* 64 bit integer comparisons. ORDER IR. */ |
1568 | as->curins--; /* Always skip the loword comparison. */ | 2412 | as->curins--; /* Always skip the loword comparison. */ |
2413 | #if LJ_SOFTFP | ||
2414 | if (!irt_isint(ir->t)) { | ||
2415 | asm_sfpcomp(as, ir-1); | ||
2416 | return; | ||
2417 | } | ||
2418 | #endif | ||
2419 | #if LJ_HASFFI | ||
1569 | asm_comp64eq(as, ir); | 2420 | asm_comp64eq(as, ir); |
2421 | #endif | ||
2422 | return; | ||
2423 | #if LJ_SOFTFP | ||
2424 | } else if ((ir-1)->o == IR_MIN || (ir-1)->o == IR_MAX) { | ||
2425 | as->curins--; /* Always skip the loword min/max. */ | ||
2426 | if (uselo || usehi) | ||
2427 | asm_sfpmin_max(as, ir-1); | ||
1570 | return; | 2428 | return; |
2429 | #endif | ||
1571 | } else if ((ir-1)->o == IR_XSTORE) { | 2430 | } else if ((ir-1)->o == IR_XSTORE) { |
1572 | as->curins--; /* Handle both stores here. */ | 2431 | as->curins--; /* Handle both stores here. */ |
1573 | if ((ir-1)->r != RID_SINK) { | 2432 | if ((ir-1)->r != RID_SINK) { |
1574 | asm_xstore(as, ir, LJ_LE ? 4 : 0); | 2433 | asm_xstore_(as, ir, LJ_LE ? 4 : 0); |
1575 | asm_xstore(as, ir-1, LJ_LE ? 0 : 4); | 2434 | asm_xstore_(as, ir-1, LJ_LE ? 0 : 4); |
1576 | } | 2435 | } |
1577 | return; | 2436 | return; |
1578 | } | 2437 | } |
2438 | #endif | ||
1579 | if (!usehi) return; /* Skip unused hiword op for all remaining ops. */ | 2439 | if (!usehi) return; /* Skip unused hiword op for all remaining ops. */ |
1580 | switch ((ir-1)->o) { | 2440 | switch ((ir-1)->o) { |
2441 | #if LJ_32 && LJ_HASFFI | ||
1581 | case IR_ADD: as->curins--; asm_add64(as, ir); break; | 2442 | case IR_ADD: as->curins--; asm_add64(as, ir); break; |
1582 | case IR_SUB: as->curins--; asm_sub64(as, ir); break; | 2443 | case IR_SUB: as->curins--; asm_sub64(as, ir); break; |
1583 | case IR_NEG: as->curins--; asm_neg64(as, ir); break; | 2444 | case IR_NEG: as->curins--; asm_neg64(as, ir); break; |
1584 | case IR_CALLN: | 2445 | case IR_CNEWI: |
1585 | case IR_CALLXS: | 2446 | /* Nothing to do here. Handled by lo op itself. */ |
2447 | break; | ||
2448 | #endif | ||
2449 | #if LJ_32 && LJ_SOFTFP | ||
2450 | case IR_SLOAD: case IR_ALOAD: case IR_HLOAD: case IR_ULOAD: case IR_VLOAD: | ||
2451 | case IR_STRTO: | ||
1586 | if (!uselo) | 2452 | if (!uselo) |
1587 | ra_allocref(as, ir->op1, RID2RSET(RID_RETLO)); /* Mark lo op as used. */ | 2453 | ra_allocref(as, ir->op1, RSET_GPR); /* Mark lo op as used. */ |
1588 | break; | 2454 | break; |
1589 | case IR_CNEWI: | 2455 | case IR_ASTORE: case IR_HSTORE: case IR_USTORE: case IR_TOSTR: case IR_TMPREF: |
1590 | /* Nothing to do here. Handled by lo op itself. */ | 2456 | /* Nothing to do here. Handled by lo op itself. */ |
1591 | break; | 2457 | break; |
1592 | default: lua_assert(0); break; | ||
1593 | } | ||
1594 | #else | ||
1595 | UNUSED(as); UNUSED(ir); lua_assert(0); /* Unused without FFI. */ | ||
1596 | #endif | 2458 | #endif |
2459 | case IR_CALLN: case IR_CALLL: case IR_CALLS: case IR_CALLXS: | ||
2460 | if (!uselo) | ||
2461 | ra_allocref(as, ir->op1, RID2RSET(RID_RETLO)); /* Mark lo op as used. */ | ||
2462 | break; | ||
2463 | default: lj_assertA(0, "bad HIOP for op %d", (ir-1)->o); break; | ||
2464 | } | ||
2465 | } | ||
2466 | |||
2467 | /* -- Profiling ----------------------------------------------------------- */ | ||
2468 | |||
2469 | static void asm_prof(ASMState *as, IRIns *ir) | ||
2470 | { | ||
2471 | UNUSED(ir); | ||
2472 | asm_guard(as, MIPSI_BNE, RID_TMP, RID_ZERO); | ||
2473 | emit_tsi(as, MIPSI_ANDI, RID_TMP, RID_TMP, HOOK_PROFILE); | ||
2474 | emit_lsglptr(as, MIPSI_LBU, RID_TMP, | ||
2475 | (int32_t)offsetof(global_State, hookmask)); | ||
1597 | } | 2476 | } |
1598 | 2477 | ||
1599 | /* -- Stack handling ------------------------------------------------------ */ | 2478 | /* -- Stack handling ------------------------------------------------------ */ |
@@ -1606,47 +2485,70 @@ static void asm_stack_check(ASMState *as, BCReg topslot, | |||
1606 | Reg tmp, pbase = irp ? (ra_hasreg(irp->r) ? irp->r : RID_TMP) : RID_BASE; | 2485 | Reg tmp, pbase = irp ? (ra_hasreg(irp->r) ? irp->r : RID_TMP) : RID_BASE; |
1607 | ExitNo oldsnap = as->snapno; | 2486 | ExitNo oldsnap = as->snapno; |
1608 | rset_clear(allow, pbase); | 2487 | rset_clear(allow, pbase); |
2488 | #if LJ_32 | ||
1609 | tmp = allow ? rset_pickbot(allow) : | 2489 | tmp = allow ? rset_pickbot(allow) : |
1610 | (pbase == RID_RETHI ? RID_RETLO : RID_RETHI); | 2490 | (pbase == RID_RETHI ? RID_RETLO : RID_RETHI); |
2491 | #else | ||
2492 | tmp = allow ? rset_pickbot(allow) : RID_RET; | ||
2493 | #endif | ||
1611 | as->snapno = exitno; | 2494 | as->snapno = exitno; |
1612 | asm_guard(as, MIPSI_BNE, RID_TMP, RID_ZERO); | 2495 | asm_guard(as, MIPSI_BNE, RID_TMP, RID_ZERO); |
1613 | as->snapno = oldsnap; | 2496 | as->snapno = oldsnap; |
1614 | if (allow == RSET_EMPTY) /* Restore temp. register. */ | 2497 | if (allow == RSET_EMPTY) /* Restore temp. register. */ |
1615 | emit_tsi(as, MIPSI_LW, tmp, RID_SP, 0); | 2498 | emit_tsi(as, MIPSI_AL, tmp, RID_SP, 0); |
1616 | else | 2499 | else |
1617 | ra_modified(as, tmp); | 2500 | ra_modified(as, tmp); |
1618 | emit_tsi(as, MIPSI_SLTIU, RID_TMP, RID_TMP, (int32_t)(8*topslot)); | 2501 | emit_tsi(as, MIPSI_SLTIU, RID_TMP, RID_TMP, (int32_t)(8*topslot)); |
1619 | emit_dst(as, MIPSI_SUBU, RID_TMP, tmp, pbase); | 2502 | emit_dst(as, MIPSI_ASUBU, RID_TMP, tmp, pbase); |
1620 | emit_tsi(as, MIPSI_LW, tmp, tmp, offsetof(lua_State, maxstack)); | 2503 | emit_tsi(as, MIPSI_AL, tmp, tmp, offsetof(lua_State, maxstack)); |
1621 | if (pbase == RID_TMP) | 2504 | if (pbase == RID_TMP) |
1622 | emit_getgl(as, RID_TMP, jit_base); | 2505 | emit_getgl(as, RID_TMP, jit_base); |
1623 | emit_getgl(as, tmp, jit_L); | 2506 | emit_getgl(as, tmp, cur_L); |
1624 | if (allow == RSET_EMPTY) /* Spill temp. register. */ | 2507 | if (allow == RSET_EMPTY) /* Spill temp. register. */ |
1625 | emit_tsi(as, MIPSI_SW, tmp, RID_SP, 0); | 2508 | emit_tsi(as, MIPSI_AS, tmp, RID_SP, 0); |
1626 | } | 2509 | } |
1627 | 2510 | ||
1628 | /* Restore Lua stack from on-trace state. */ | 2511 | /* Restore Lua stack from on-trace state. */ |
1629 | static void asm_stack_restore(ASMState *as, SnapShot *snap) | 2512 | static void asm_stack_restore(ASMState *as, SnapShot *snap) |
1630 | { | 2513 | { |
1631 | SnapEntry *map = &as->T->snapmap[snap->mapofs]; | 2514 | SnapEntry *map = &as->T->snapmap[snap->mapofs]; |
1632 | SnapEntry *flinks = &as->T->snapmap[snap_nextofs(as->T, snap)-1]; | 2515 | #if LJ_32 || defined(LUA_USE_ASSERT) |
2516 | SnapEntry *flinks = &as->T->snapmap[snap_nextofs(as->T, snap)-1-LJ_FR2]; | ||
2517 | #endif | ||
1633 | MSize n, nent = snap->nent; | 2518 | MSize n, nent = snap->nent; |
1634 | /* Store the value of all modified slots to the Lua stack. */ | 2519 | /* Store the value of all modified slots to the Lua stack. */ |
1635 | for (n = 0; n < nent; n++) { | 2520 | for (n = 0; n < nent; n++) { |
1636 | SnapEntry sn = map[n]; | 2521 | SnapEntry sn = map[n]; |
1637 | BCReg s = snap_slot(sn); | 2522 | BCReg s = snap_slot(sn); |
1638 | int32_t ofs = 8*((int32_t)s-1); | 2523 | int32_t ofs = 8*((int32_t)s-1-LJ_FR2); |
1639 | IRRef ref = snap_ref(sn); | 2524 | IRRef ref = snap_ref(sn); |
1640 | IRIns *ir = IR(ref); | 2525 | IRIns *ir = IR(ref); |
1641 | if ((sn & SNAP_NORESTORE)) | 2526 | if ((sn & SNAP_NORESTORE)) |
1642 | continue; | 2527 | continue; |
1643 | if (irt_isnum(ir->t)) { | 2528 | if (irt_isnum(ir->t)) { |
2529 | #if LJ_SOFTFP32 | ||
2530 | Reg tmp; | ||
2531 | RegSet allow = rset_exclude(RSET_GPR, RID_BASE); | ||
2532 | /* LJ_SOFTFP: must be a number constant. */ | ||
2533 | lj_assertA(irref_isk(ref), "unsplit FP op"); | ||
2534 | tmp = ra_allock(as, (int32_t)ir_knum(ir)->u32.lo, allow); | ||
2535 | emit_tsi(as, MIPSI_SW, tmp, RID_BASE, ofs+(LJ_BE?4:0)); | ||
2536 | if (rset_test(as->freeset, tmp+1)) allow = RID2RSET(tmp+1); | ||
2537 | tmp = ra_allock(as, (int32_t)ir_knum(ir)->u32.hi, allow); | ||
2538 | emit_tsi(as, MIPSI_SW, tmp, RID_BASE, ofs+(LJ_BE?0:4)); | ||
2539 | #elif LJ_SOFTFP /* && LJ_64 */ | ||
2540 | Reg src = ra_alloc1(as, ref, rset_exclude(RSET_GPR, RID_BASE)); | ||
2541 | emit_tsi(as, MIPSI_SD, src, RID_BASE, ofs); | ||
2542 | #else | ||
1644 | Reg src = ra_alloc1(as, ref, RSET_FPR); | 2543 | Reg src = ra_alloc1(as, ref, RSET_FPR); |
1645 | emit_hsi(as, MIPSI_SDC1, src, RID_BASE, ofs); | 2544 | emit_hsi(as, MIPSI_SDC1, src, RID_BASE, ofs); |
2545 | #endif | ||
1646 | } else { | 2546 | } else { |
1647 | Reg type; | 2547 | #if LJ_32 |
1648 | RegSet allow = rset_exclude(RSET_GPR, RID_BASE); | 2548 | RegSet allow = rset_exclude(RSET_GPR, RID_BASE); |
1649 | lua_assert(irt_ispri(ir->t) || irt_isaddr(ir->t) || irt_isinteger(ir->t)); | 2549 | Reg type; |
2550 | lj_assertA(irt_ispri(ir->t) || irt_isaddr(ir->t) || irt_isinteger(ir->t), | ||
2551 | "restore of IR type %d", irt_type(ir->t)); | ||
1650 | if (!irt_ispri(ir->t)) { | 2552 | if (!irt_ispri(ir->t)) { |
1651 | Reg src = ra_alloc1(as, ref, allow); | 2553 | Reg src = ra_alloc1(as, ref, allow); |
1652 | rset_clear(allow, src); | 2554 | rset_clear(allow, src); |
@@ -1655,14 +2557,23 @@ static void asm_stack_restore(ASMState *as, SnapShot *snap) | |||
1655 | if ((sn & (SNAP_CONT|SNAP_FRAME))) { | 2557 | if ((sn & (SNAP_CONT|SNAP_FRAME))) { |
1656 | if (s == 0) continue; /* Do not overwrite link to previous frame. */ | 2558 | if (s == 0) continue; /* Do not overwrite link to previous frame. */ |
1657 | type = ra_allock(as, (int32_t)(*flinks--), allow); | 2559 | type = ra_allock(as, (int32_t)(*flinks--), allow); |
2560 | #if LJ_SOFTFP | ||
2561 | } else if ((sn & SNAP_SOFTFPNUM)) { | ||
2562 | type = ra_alloc1(as, ref+1, rset_exclude(RSET_GPR, RID_BASE)); | ||
2563 | #endif | ||
2564 | } else if ((sn & SNAP_KEYINDEX)) { | ||
2565 | type = ra_allock(as, (int32_t)LJ_KEYINDEX, allow); | ||
1658 | } else { | 2566 | } else { |
1659 | type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); | 2567 | type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); |
1660 | } | 2568 | } |
1661 | emit_tsi(as, MIPSI_SW, type, RID_BASE, ofs+(LJ_BE?0:4)); | 2569 | emit_tsi(as, MIPSI_SW, type, RID_BASE, ofs+(LJ_BE?0:4)); |
2570 | #else | ||
2571 | asm_tvstore64(as, RID_BASE, ofs, ref); | ||
2572 | #endif | ||
1662 | } | 2573 | } |
1663 | checkmclim(as); | 2574 | checkmclim(as); |
1664 | } | 2575 | } |
1665 | lua_assert(map + nent == flinks); | 2576 | lj_assertA(map + nent == flinks, "inconsistent frames in snapshot"); |
1666 | } | 2577 | } |
1667 | 2578 | ||
1668 | /* -- GC handling --------------------------------------------------------- */ | 2579 | /* -- GC handling --------------------------------------------------------- */ |
@@ -1686,7 +2597,7 @@ static void asm_gc_check(ASMState *as) | |||
1686 | args[1] = ASMREF_TMP2; /* MSize steps */ | 2597 | args[1] = ASMREF_TMP2; /* MSize steps */ |
1687 | asm_gencall(as, ci, args); | 2598 | asm_gencall(as, ci, args); |
1688 | l_end[-3] = MIPS_NOPATCH_GC_CHECK; /* Replace the nop after the call. */ | 2599 | l_end[-3] = MIPS_NOPATCH_GC_CHECK; /* Replace the nop after the call. */ |
1689 | emit_tsi(as, MIPSI_ADDIU, ra_releasetmp(as, ASMREF_TMP1), RID_JGL, -32768); | 2600 | emit_tsi(as, MIPSI_AADDIU, ra_releasetmp(as, ASMREF_TMP1), RID_JGL, -32768); |
1690 | tmp = ra_releasetmp(as, ASMREF_TMP2); | 2601 | tmp = ra_releasetmp(as, ASMREF_TMP2); |
1691 | emit_loadi(as, tmp, as->gcsteps); | 2602 | emit_loadi(as, tmp, as->gcsteps); |
1692 | /* Jump around GC step if GC total < GC threshold. */ | 2603 | /* Jump around GC step if GC total < GC threshold. */ |
@@ -1714,6 +2625,12 @@ static void asm_loop_fixup(ASMState *as) | |||
1714 | } | 2625 | } |
1715 | } | 2626 | } |
1716 | 2627 | ||
2628 | /* Fixup the tail of the loop. */ | ||
2629 | static void asm_loop_tail_fixup(ASMState *as) | ||
2630 | { | ||
2631 | if (as->loopinv) as->mctop--; | ||
2632 | } | ||
2633 | |||
1717 | /* -- Head of trace ------------------------------------------------------- */ | 2634 | /* -- Head of trace ------------------------------------------------------- */ |
1718 | 2635 | ||
1719 | /* Coalesce BASE register for a root trace. */ | 2636 | /* Coalesce BASE register for a root trace. */ |
@@ -1721,7 +2638,6 @@ static void asm_head_root_base(ASMState *as) | |||
1721 | { | 2638 | { |
1722 | IRIns *ir = IR(REF_BASE); | 2639 | IRIns *ir = IR(REF_BASE); |
1723 | Reg r = ir->r; | 2640 | Reg r = ir->r; |
1724 | if (as->loopinv) as->mctop--; | ||
1725 | if (ra_hasreg(r)) { | 2641 | if (ra_hasreg(r)) { |
1726 | ra_free(as, r); | 2642 | ra_free(as, r); |
1727 | if (rset_test(as->modset, r) || irt_ismarked(ir->t)) | 2643 | if (rset_test(as->modset, r) || irt_ismarked(ir->t)) |
@@ -1736,7 +2652,6 @@ static RegSet asm_head_side_base(ASMState *as, IRIns *irp, RegSet allow) | |||
1736 | { | 2652 | { |
1737 | IRIns *ir = IR(REF_BASE); | 2653 | IRIns *ir = IR(REF_BASE); |
1738 | Reg r = ir->r; | 2654 | Reg r = ir->r; |
1739 | if (as->loopinv) as->mctop--; | ||
1740 | if (ra_hasreg(r)) { | 2655 | if (ra_hasreg(r)) { |
1741 | ra_free(as, r); | 2656 | ra_free(as, r); |
1742 | if (rset_test(as->modset, r) || irt_ismarked(ir->t)) | 2657 | if (rset_test(as->modset, r) || irt_ismarked(ir->t)) |
@@ -1761,7 +2676,7 @@ static void asm_tail_fixup(ASMState *as, TraceNo lnk) | |||
1761 | MCode *target = lnk ? traceref(as->J,lnk)->mcode : (MCode *)lj_vm_exit_interp; | 2676 | MCode *target = lnk ? traceref(as->J,lnk)->mcode : (MCode *)lj_vm_exit_interp; |
1762 | int32_t spadj = as->T->spadjust; | 2677 | int32_t spadj = as->T->spadjust; |
1763 | MCode *p = as->mctop-1; | 2678 | MCode *p = as->mctop-1; |
1764 | *p = spadj ? (MIPSI_ADDIU|MIPSF_T(RID_SP)|MIPSF_S(RID_SP)|spadj) : MIPSI_NOP; | 2679 | *p = spadj ? (MIPSI_AADDIU|MIPSF_T(RID_SP)|MIPSF_S(RID_SP)|spadj) : MIPSI_NOP; |
1765 | p[-1] = MIPSI_J|(((uintptr_t)target>>2)&0x03ffffffu); | 2680 | p[-1] = MIPSI_J|(((uintptr_t)target>>2)&0x03ffffffu); |
1766 | } | 2681 | } |
1767 | 2682 | ||
@@ -1772,139 +2687,26 @@ static void asm_tail_prep(ASMState *as) | |||
1772 | as->invmcp = as->loopref ? as->mcp : NULL; | 2687 | as->invmcp = as->loopref ? as->mcp : NULL; |
1773 | } | 2688 | } |
1774 | 2689 | ||
1775 | /* -- Instruction dispatch ------------------------------------------------ */ | ||
1776 | |||
1777 | /* Assemble a single instruction. */ | ||
1778 | static void asm_ir(ASMState *as, IRIns *ir) | ||
1779 | { | ||
1780 | switch ((IROp)ir->o) { | ||
1781 | /* Miscellaneous ops. */ | ||
1782 | case IR_LOOP: asm_loop(as); break; | ||
1783 | case IR_NOP: case IR_XBAR: lua_assert(!ra_used(ir)); break; | ||
1784 | case IR_USE: | ||
1785 | ra_alloc1(as, ir->op1, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); break; | ||
1786 | case IR_PHI: asm_phi(as, ir); break; | ||
1787 | case IR_HIOP: asm_hiop(as, ir); break; | ||
1788 | case IR_GCSTEP: asm_gcstep(as, ir); break; | ||
1789 | |||
1790 | /* Guarded assertions. */ | ||
1791 | case IR_EQ: case IR_NE: asm_compeq(as, ir); break; | ||
1792 | case IR_LT: case IR_GE: case IR_LE: case IR_GT: | ||
1793 | case IR_ULT: case IR_UGE: case IR_ULE: case IR_UGT: | ||
1794 | case IR_ABC: | ||
1795 | asm_comp(as, ir); | ||
1796 | break; | ||
1797 | |||
1798 | case IR_RETF: asm_retf(as, ir); break; | ||
1799 | |||
1800 | /* Bit ops. */ | ||
1801 | case IR_BNOT: asm_bitnot(as, ir); break; | ||
1802 | case IR_BSWAP: asm_bitswap(as, ir); break; | ||
1803 | |||
1804 | case IR_BAND: asm_bitop(as, ir, MIPSI_AND, MIPSI_ANDI); break; | ||
1805 | case IR_BOR: asm_bitop(as, ir, MIPSI_OR, MIPSI_ORI); break; | ||
1806 | case IR_BXOR: asm_bitop(as, ir, MIPSI_XOR, MIPSI_XORI); break; | ||
1807 | |||
1808 | case IR_BSHL: asm_bitshift(as, ir, MIPSI_SLLV, MIPSI_SLL); break; | ||
1809 | case IR_BSHR: asm_bitshift(as, ir, MIPSI_SRLV, MIPSI_SRL); break; | ||
1810 | case IR_BSAR: asm_bitshift(as, ir, MIPSI_SRAV, MIPSI_SRA); break; | ||
1811 | case IR_BROL: lua_assert(0); break; | ||
1812 | case IR_BROR: asm_bitror(as, ir); break; | ||
1813 | |||
1814 | /* Arithmetic ops. */ | ||
1815 | case IR_ADD: asm_add(as, ir); break; | ||
1816 | case IR_SUB: asm_sub(as, ir); break; | ||
1817 | case IR_MUL: asm_mul(as, ir); break; | ||
1818 | case IR_DIV: asm_fparith(as, ir, MIPSI_DIV_D); break; | ||
1819 | case IR_MOD: asm_callid(as, ir, IRCALL_lj_vm_modi); break; | ||
1820 | case IR_POW: asm_callid(as, ir, IRCALL_lj_vm_powi); break; | ||
1821 | case IR_NEG: asm_neg(as, ir); break; | ||
1822 | |||
1823 | case IR_ABS: asm_fpunary(as, ir, MIPSI_ABS_D); break; | ||
1824 | case IR_ATAN2: asm_callid(as, ir, IRCALL_atan2); break; | ||
1825 | case IR_LDEXP: asm_callid(as, ir, IRCALL_ldexp); break; | ||
1826 | case IR_MIN: asm_min_max(as, ir, 0); break; | ||
1827 | case IR_MAX: asm_min_max(as, ir, 1); break; | ||
1828 | case IR_FPMATH: | ||
1829 | if (ir->op2 == IRFPM_EXP2 && asm_fpjoin_pow(as, ir)) | ||
1830 | break; | ||
1831 | if (ir->op2 <= IRFPM_TRUNC) | ||
1832 | asm_callround(as, ir, IRCALL_lj_vm_floor + ir->op2); | ||
1833 | else if (ir->op2 == IRFPM_SQRT) | ||
1834 | asm_fpunary(as, ir, MIPSI_SQRT_D); | ||
1835 | else | ||
1836 | asm_callid(as, ir, IRCALL_lj_vm_floor + ir->op2); | ||
1837 | break; | ||
1838 | |||
1839 | /* Overflow-checking arithmetic ops. */ | ||
1840 | case IR_ADDOV: asm_arithov(as, ir); break; | ||
1841 | case IR_SUBOV: asm_arithov(as, ir); break; | ||
1842 | case IR_MULOV: asm_mulov(as, ir); break; | ||
1843 | |||
1844 | /* Memory references. */ | ||
1845 | case IR_AREF: asm_aref(as, ir); break; | ||
1846 | case IR_HREF: asm_href(as, ir); break; | ||
1847 | case IR_HREFK: asm_hrefk(as, ir); break; | ||
1848 | case IR_NEWREF: asm_newref(as, ir); break; | ||
1849 | case IR_UREFO: case IR_UREFC: asm_uref(as, ir); break; | ||
1850 | case IR_FREF: asm_fref(as, ir); break; | ||
1851 | case IR_STRREF: asm_strref(as, ir); break; | ||
1852 | |||
1853 | /* Loads and stores. */ | ||
1854 | case IR_ALOAD: case IR_HLOAD: case IR_ULOAD: case IR_VLOAD: | ||
1855 | asm_ahuvload(as, ir); | ||
1856 | break; | ||
1857 | case IR_FLOAD: asm_fload(as, ir); break; | ||
1858 | case IR_XLOAD: asm_xload(as, ir); break; | ||
1859 | case IR_SLOAD: asm_sload(as, ir); break; | ||
1860 | |||
1861 | case IR_ASTORE: case IR_HSTORE: case IR_USTORE: asm_ahustore(as, ir); break; | ||
1862 | case IR_FSTORE: asm_fstore(as, ir); break; | ||
1863 | case IR_XSTORE: asm_xstore(as, ir, 0); break; | ||
1864 | |||
1865 | /* Allocations. */ | ||
1866 | case IR_SNEW: case IR_XSNEW: asm_snew(as, ir); break; | ||
1867 | case IR_TNEW: asm_tnew(as, ir); break; | ||
1868 | case IR_TDUP: asm_tdup(as, ir); break; | ||
1869 | case IR_CNEW: case IR_CNEWI: asm_cnew(as, ir); break; | ||
1870 | |||
1871 | /* Write barriers. */ | ||
1872 | case IR_TBAR: asm_tbar(as, ir); break; | ||
1873 | case IR_OBAR: asm_obar(as, ir); break; | ||
1874 | |||
1875 | /* Type conversions. */ | ||
1876 | case IR_CONV: asm_conv(as, ir); break; | ||
1877 | case IR_TOBIT: asm_tobit(as, ir); break; | ||
1878 | case IR_TOSTR: asm_tostr(as, ir); break; | ||
1879 | case IR_STRTO: asm_strto(as, ir); break; | ||
1880 | |||
1881 | /* Calls. */ | ||
1882 | case IR_CALLN: case IR_CALLL: case IR_CALLS: asm_call(as, ir); break; | ||
1883 | case IR_CALLXS: asm_callx(as, ir); break; | ||
1884 | case IR_CARG: break; | ||
1885 | |||
1886 | default: | ||
1887 | setintV(&as->J->errinfo, ir->o); | ||
1888 | lj_trace_err_info(as->J, LJ_TRERR_NYIIR); | ||
1889 | break; | ||
1890 | } | ||
1891 | } | ||
1892 | |||
1893 | /* -- Trace setup --------------------------------------------------------- */ | 2690 | /* -- Trace setup --------------------------------------------------------- */ |
1894 | 2691 | ||
1895 | /* Ensure there are enough stack slots for call arguments. */ | 2692 | /* Ensure there are enough stack slots for call arguments. */ |
1896 | static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) | 2693 | static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) |
1897 | { | 2694 | { |
1898 | IRRef args[CCI_NARGS_MAX*2]; | 2695 | IRRef args[CCI_NARGS_MAX*2]; |
1899 | uint32_t i, nargs = (int)CCI_NARGS(ci); | 2696 | uint32_t i, nargs = CCI_XNARGS(ci); |
2697 | #if LJ_32 | ||
1900 | int nslots = 4, ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR; | 2698 | int nslots = 4, ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR; |
2699 | #else | ||
2700 | int nslots = 0, ngpr = REGARG_NUMGPR; | ||
2701 | #endif | ||
1901 | asm_collectargs(as, ir, ci, args); | 2702 | asm_collectargs(as, ir, ci, args); |
1902 | for (i = 0; i < nargs; i++) { | 2703 | for (i = 0; i < nargs; i++) { |
1903 | if (args[i] && irt_isfp(IR(args[i])->t) && | 2704 | #if LJ_32 |
2705 | if (!LJ_SOFTFP && args[i] && irt_isfp(IR(args[i])->t) && | ||
1904 | nfpr > 0 && !(ci->flags & CCI_VARARG)) { | 2706 | nfpr > 0 && !(ci->flags & CCI_VARARG)) { |
1905 | nfpr--; | 2707 | nfpr--; |
1906 | ngpr -= irt_isnum(IR(args[i])->t) ? 2 : 1; | 2708 | ngpr -= irt_isnum(IR(args[i])->t) ? 2 : 1; |
1907 | } else if (args[i] && irt_isnum(IR(args[i])->t)) { | 2709 | } else if (!LJ_SOFTFP && args[i] && irt_isnum(IR(args[i])->t)) { |
1908 | nfpr = 0; | 2710 | nfpr = 0; |
1909 | ngpr = ngpr & ~1; | 2711 | ngpr = ngpr & ~1; |
1910 | if (ngpr > 0) ngpr -= 2; else nslots = (nslots+3) & ~1; | 2712 | if (ngpr > 0) ngpr -= 2; else nslots = (nslots+3) & ~1; |
@@ -1912,6 +2714,9 @@ static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) | |||
1912 | nfpr = 0; | 2714 | nfpr = 0; |
1913 | if (ngpr > 0) ngpr--; else nslots++; | 2715 | if (ngpr > 0) ngpr--; else nslots++; |
1914 | } | 2716 | } |
2717 | #else | ||
2718 | if (ngpr > 0) ngpr--; else nslots += 2; | ||
2719 | #endif | ||
1915 | } | 2720 | } |
1916 | if (nslots > as->evenspill) /* Leave room for args in stack slots. */ | 2721 | if (nslots > as->evenspill) /* Leave room for args in stack slots. */ |
1917 | as->evenspill = nslots; | 2722 | as->evenspill = nslots; |
@@ -1942,35 +2747,35 @@ void lj_asm_patchexit(jit_State *J, GCtrace *T, ExitNo exitno, MCode *target) | |||
1942 | if (((p[-1] ^ (px-p)) & 0xffffu) == 0 && | 2747 | if (((p[-1] ^ (px-p)) & 0xffffu) == 0 && |
1943 | ((p[-1] & 0xf0000000u) == MIPSI_BEQ || | 2748 | ((p[-1] & 0xf0000000u) == MIPSI_BEQ || |
1944 | (p[-1] & 0xfc1e0000u) == MIPSI_BLTZ || | 2749 | (p[-1] & 0xfc1e0000u) == MIPSI_BLTZ || |
1945 | (p[-1] & 0xffe00000u) == MIPSI_BC1F) && | 2750 | #if !LJ_TARGET_MIPSR6 |
1946 | p[-2] != MIPS_NOPATCH_GC_CHECK) { | 2751 | (p[-1] & 0xffe00000u) == MIPSI_BC1F |
2752 | #else | ||
2753 | (p[-1] & 0xff600000u) == MIPSI_BC1EQZ | ||
2754 | #endif | ||
2755 | ) && p[-2] != MIPS_NOPATCH_GC_CHECK) { | ||
1947 | ptrdiff_t delta = target - p; | 2756 | ptrdiff_t delta = target - p; |
1948 | if (((delta + 0x8000) >> 16) == 0) { /* Patch in-range branch. */ | 2757 | if (((delta + 0x8000) >> 16) == 0) { /* Patch in-range branch. */ |
1949 | patchbranch: | 2758 | patchbranch: |
1950 | p[-1] = (p[-1] & 0xffff0000u) | (delta & 0xffffu); | 2759 | p[-1] = (p[-1] & 0xffff0000u) | (delta & 0xffffu); |
1951 | *p = MIPSI_NOP; /* Replace the load of the exit number. */ | 2760 | *p = MIPSI_NOP; /* Replace the load of the exit number. */ |
1952 | cstop = p; | 2761 | cstop = p+1; |
1953 | if (!cstart) cstart = p-1; | 2762 | if (!cstart) cstart = p-1; |
1954 | } else { /* Branch out of range. Use spare jump slot in mcarea. */ | 2763 | } else { /* Branch out of range. Use spare jump slot in mcarea. */ |
1955 | int i; | 2764 | MCode *mcjump = asm_sparejump_use(mcarea, tjump); |
1956 | for (i = (int)(sizeof(MCLink)/sizeof(MCode)); | 2765 | if (mcjump) { |
1957 | i < (int)(sizeof(MCLink)/sizeof(MCode)+MIPS_SPAREJUMP*2); | 2766 | lj_mcode_sync(mcjump, mcjump+1); |
1958 | i += 2) { | 2767 | delta = mcjump - p; |
1959 | if (mcarea[i] == tjump) { | 2768 | if (((delta + 0x8000) >> 16) == 0) { |
1960 | delta = mcarea+i - p; | ||
1961 | goto patchbranch; | ||
1962 | } else if (mcarea[i] == MIPSI_NOP) { | ||
1963 | mcarea[i] = tjump; | ||
1964 | cstart = mcarea+i; | ||
1965 | delta = mcarea+i - p; | ||
1966 | goto patchbranch; | 2769 | goto patchbranch; |
2770 | } else { | ||
2771 | lj_assertJ(0, "spare jump out of range: -Osizemcode too big"); | ||
1967 | } | 2772 | } |
1968 | } | 2773 | } |
1969 | /* Ignore jump slot overflow. Child trace is simply not attached. */ | 2774 | /* Ignore jump slot overflow. Child trace is simply not attached. */ |
1970 | } | 2775 | } |
1971 | } else if (p+1 == pe) { | 2776 | } else if (p+1 == pe) { |
1972 | /* Patch NOP after code for inverted loop branch. Use of J is ok. */ | 2777 | /* Patch NOP after code for inverted loop branch. Use of J is ok. */ |
1973 | lua_assert(p[1] == MIPSI_NOP); | 2778 | lj_assertJ(p[1] == MIPSI_NOP, "expected NOP"); |
1974 | p[1] = tjump; | 2779 | p[1] = tjump; |
1975 | *p = MIPSI_NOP; /* Replace the load of the exit number. */ | 2780 | *p = MIPSI_NOP; /* Replace the load of the exit number. */ |
1976 | cstop = p+2; | 2781 | cstop = p+2; |