diff options
| author | Mike Pall <mike> | 2017-09-03 23:20:53 +0200 |
|---|---|---|
| committer | Mike Pall <mike> | 2017-09-03 23:20:53 +0200 |
| commit | 71b7bc88341945f13f3951e2bb5fd247b639ff7a (patch) | |
| tree | fd495ce0307a7319e40df467beaf8843d505b998 /src | |
| parent | 6b0824852677cc12570c20a3211fbfe0e4f0ce14 (diff) | |
| download | luajit-71b7bc88341945f13f3951e2bb5fd247b639ff7a.tar.gz luajit-71b7bc88341945f13f3951e2bb5fd247b639ff7a.tar.bz2 luajit-71b7bc88341945f13f3951e2bb5fd247b639ff7a.zip | |
PPC: Add soft-float support to JIT compiler backend.
Contributed by Djordje Kovacevic and Stefan Pejic from RT-RK.com.
Sponsored by Cisco Systems, Inc.
Diffstat (limited to 'src')
| -rw-r--r-- | src/lj_arch.h | 1 | ||||
| -rw-r--r-- | src/lj_asm_ppc.h | 321 |
2 files changed, 278 insertions, 44 deletions
diff --git a/src/lj_arch.h b/src/lj_arch.h index 0145a7c0..5962f3af 100644 --- a/src/lj_arch.h +++ b/src/lj_arch.h | |||
| @@ -273,7 +273,6 @@ | |||
| 273 | #endif | 273 | #endif |
| 274 | 274 | ||
| 275 | #if LJ_ABI_SOFTFP | 275 | #if LJ_ABI_SOFTFP |
| 276 | #define LJ_ARCH_NOJIT 1 /* NYI */ | ||
| 277 | #define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL | 276 | #define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL |
| 278 | #else | 277 | #else |
| 279 | #define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL_SINGLE | 278 | #define LJ_ARCH_NUMMODE LJ_NUMMODE_DUAL_SINGLE |
diff --git a/src/lj_asm_ppc.h b/src/lj_asm_ppc.h index 6daa861b..1955429f 100644 --- a/src/lj_asm_ppc.h +++ b/src/lj_asm_ppc.h | |||
| @@ -226,6 +226,7 @@ static void asm_fusexrefx(ASMState *as, PPCIns pi, Reg rt, IRRef ref, | |||
| 226 | emit_tab(as, pi, rt, left, right); | 226 | emit_tab(as, pi, rt, left, right); |
| 227 | } | 227 | } |
| 228 | 228 | ||
| 229 | #if !LJ_SOFTFP | ||
| 229 | /* Fuse to multiply-add/sub instruction. */ | 230 | /* Fuse to multiply-add/sub instruction. */ |
| 230 | static int asm_fusemadd(ASMState *as, IRIns *ir, PPCIns pi, PPCIns pir) | 231 | static int asm_fusemadd(ASMState *as, IRIns *ir, PPCIns pi, PPCIns pir) |
| 231 | { | 232 | { |
| @@ -245,6 +246,7 @@ static int asm_fusemadd(ASMState *as, IRIns *ir, PPCIns pi, PPCIns pir) | |||
| 245 | } | 246 | } |
| 246 | return 0; | 247 | return 0; |
| 247 | } | 248 | } |
| 249 | #endif | ||
| 248 | 250 | ||
| 249 | /* -- Calls --------------------------------------------------------------- */ | 251 | /* -- Calls --------------------------------------------------------------- */ |
| 250 | 252 | ||
| @@ -253,13 +255,17 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) | |||
| 253 | { | 255 | { |
| 254 | uint32_t n, nargs = CCI_XNARGS(ci); | 256 | uint32_t n, nargs = CCI_XNARGS(ci); |
| 255 | int32_t ofs = 8; | 257 | int32_t ofs = 8; |
| 256 | Reg gpr = REGARG_FIRSTGPR, fpr = REGARG_FIRSTFPR; | 258 | Reg gpr = REGARG_FIRSTGPR; |
| 259 | #if !LJ_SOFTFP | ||
| 260 | Reg fpr = REGARG_FIRSTFPR; | ||
| 261 | #endif | ||
| 257 | if ((void *)ci->func) | 262 | if ((void *)ci->func) |
| 258 | emit_call(as, (void *)ci->func); | 263 | emit_call(as, (void *)ci->func); |
| 259 | for (n = 0; n < nargs; n++) { /* Setup args. */ | 264 | for (n = 0; n < nargs; n++) { /* Setup args. */ |
| 260 | IRRef ref = args[n]; | 265 | IRRef ref = args[n]; |
| 261 | if (ref) { | 266 | if (ref) { |
| 262 | IRIns *ir = IR(ref); | 267 | IRIns *ir = IR(ref); |
| 268 | #if !LJ_SOFTFP | ||
| 263 | if (irt_isfp(ir->t)) { | 269 | if (irt_isfp(ir->t)) { |
| 264 | if (fpr <= REGARG_LASTFPR) { | 270 | if (fpr <= REGARG_LASTFPR) { |
| 265 | lua_assert(rset_test(as->freeset, fpr)); /* Already evicted. */ | 271 | lua_assert(rset_test(as->freeset, fpr)); /* Already evicted. */ |
| @@ -271,7 +277,9 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) | |||
| 271 | emit_spstore(as, ir, r, ofs); | 277 | emit_spstore(as, ir, r, ofs); |
| 272 | ofs += irt_isnum(ir->t) ? 8 : 4; | 278 | ofs += irt_isnum(ir->t) ? 8 : 4; |
| 273 | } | 279 | } |
| 274 | } else { | 280 | } else |
| 281 | #endif | ||
| 282 | { | ||
| 275 | if (gpr <= REGARG_LASTGPR) { | 283 | if (gpr <= REGARG_LASTGPR) { |
| 276 | lua_assert(rset_test(as->freeset, gpr)); /* Already evicted. */ | 284 | lua_assert(rset_test(as->freeset, gpr)); /* Already evicted. */ |
| 277 | ra_leftov(as, gpr, ref); | 285 | ra_leftov(as, gpr, ref); |
| @@ -290,8 +298,10 @@ static void asm_gencall(ASMState *as, const CCallInfo *ci, IRRef *args) | |||
| 290 | } | 298 | } |
| 291 | checkmclim(as); | 299 | checkmclim(as); |
| 292 | } | 300 | } |
| 301 | #if !LJ_SOFTFP | ||
| 293 | if ((ci->flags & CCI_VARARG)) /* Vararg calls need to know about FPR use. */ | 302 | if ((ci->flags & CCI_VARARG)) /* Vararg calls need to know about FPR use. */ |
| 294 | emit_tab(as, fpr == REGARG_FIRSTFPR ? PPCI_CRXOR : PPCI_CREQV, 6, 6, 6); | 303 | emit_tab(as, fpr == REGARG_FIRSTFPR ? PPCI_CRXOR : PPCI_CREQV, 6, 6, 6); |
| 304 | #endif | ||
| 295 | } | 305 | } |
| 296 | 306 | ||
| 297 | /* Setup result reg/sp for call. Evict scratch regs. */ | 307 | /* Setup result reg/sp for call. Evict scratch regs. */ |
| @@ -299,8 +309,10 @@ static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci) | |||
| 299 | { | 309 | { |
| 300 | RegSet drop = RSET_SCRATCH; | 310 | RegSet drop = RSET_SCRATCH; |
| 301 | int hiop = ((ir+1)->o == IR_HIOP && !irt_isnil((ir+1)->t)); | 311 | int hiop = ((ir+1)->o == IR_HIOP && !irt_isnil((ir+1)->t)); |
| 312 | #if !LJ_SOFTFP | ||
| 302 | if ((ci->flags & CCI_NOFPRCLOBBER)) | 313 | if ((ci->flags & CCI_NOFPRCLOBBER)) |
| 303 | drop &= ~RSET_FPR; | 314 | drop &= ~RSET_FPR; |
| 315 | #endif | ||
| 304 | if (ra_hasreg(ir->r)) | 316 | if (ra_hasreg(ir->r)) |
| 305 | rset_clear(drop, ir->r); /* Dest reg handled below. */ | 317 | rset_clear(drop, ir->r); /* Dest reg handled below. */ |
| 306 | if (hiop && ra_hasreg((ir+1)->r)) | 318 | if (hiop && ra_hasreg((ir+1)->r)) |
| @@ -308,7 +320,7 @@ static void asm_setupresult(ASMState *as, IRIns *ir, const CCallInfo *ci) | |||
| 308 | ra_evictset(as, drop); /* Evictions must be performed first. */ | 320 | ra_evictset(as, drop); /* Evictions must be performed first. */ |
| 309 | if (ra_used(ir)) { | 321 | if (ra_used(ir)) { |
| 310 | lua_assert(!irt_ispri(ir->t)); | 322 | lua_assert(!irt_ispri(ir->t)); |
| 311 | if (irt_isfp(ir->t)) { | 323 | if (!LJ_SOFTFP && irt_isfp(ir->t)) { |
| 312 | if ((ci->flags & CCI_CASTU64)) { | 324 | if ((ci->flags & CCI_CASTU64)) { |
| 313 | /* Use spill slot or temp slots. */ | 325 | /* Use spill slot or temp slots. */ |
| 314 | int32_t ofs = ir->s ? sps_scale(ir->s) : SPOFS_TMP; | 326 | int32_t ofs = ir->s ? sps_scale(ir->s) : SPOFS_TMP; |
| @@ -377,6 +389,7 @@ static void asm_retf(ASMState *as, IRIns *ir) | |||
| 377 | 389 | ||
| 378 | /* -- Type conversions ---------------------------------------------------- */ | 390 | /* -- Type conversions ---------------------------------------------------- */ |
| 379 | 391 | ||
| 392 | #if !LJ_SOFTFP | ||
| 380 | static void asm_tointg(ASMState *as, IRIns *ir, Reg left) | 393 | static void asm_tointg(ASMState *as, IRIns *ir, Reg left) |
| 381 | { | 394 | { |
| 382 | RegSet allow = RSET_FPR; | 395 | RegSet allow = RSET_FPR; |
| @@ -409,15 +422,23 @@ static void asm_tobit(ASMState *as, IRIns *ir) | |||
| 409 | emit_fai(as, PPCI_STFD, tmp, RID_SP, SPOFS_TMP); | 422 | emit_fai(as, PPCI_STFD, tmp, RID_SP, SPOFS_TMP); |
| 410 | emit_fab(as, PPCI_FADD, tmp, left, right); | 423 | emit_fab(as, PPCI_FADD, tmp, left, right); |
| 411 | } | 424 | } |
| 425 | #endif | ||
| 412 | 426 | ||
| 413 | static void asm_conv(ASMState *as, IRIns *ir) | 427 | static void asm_conv(ASMState *as, IRIns *ir) |
| 414 | { | 428 | { |
| 415 | IRType st = (IRType)(ir->op2 & IRCONV_SRCMASK); | 429 | IRType st = (IRType)(ir->op2 & IRCONV_SRCMASK); |
| 430 | #if !LJ_SOFTFP | ||
| 416 | int stfp = (st == IRT_NUM || st == IRT_FLOAT); | 431 | int stfp = (st == IRT_NUM || st == IRT_FLOAT); |
| 432 | #endif | ||
| 417 | IRRef lref = ir->op1; | 433 | IRRef lref = ir->op1; |
| 418 | lua_assert(irt_type(ir->t) != st); | ||
| 419 | lua_assert(!(irt_isint64(ir->t) || | 434 | lua_assert(!(irt_isint64(ir->t) || |
| 420 | (st == IRT_I64 || st == IRT_U64))); /* Handled by SPLIT. */ | 435 | (st == IRT_I64 || st == IRT_U64))); /* Handled by SPLIT. */ |
| 436 | #if LJ_SOFTFP | ||
| 437 | /* FP conversions are handled by SPLIT. */ | ||
| 438 | lua_assert(!irt_isfp(ir->t) && !(st == IRT_NUM || st == IRT_FLOAT)); | ||
| 439 | /* Can't check for same types: SPLIT uses CONV int.int + BXOR for sfp NEG. */ | ||
| 440 | #else | ||
| 441 | lua_assert(irt_type(ir->t) != st); | ||
| 421 | if (irt_isfp(ir->t)) { | 442 | if (irt_isfp(ir->t)) { |
| 422 | Reg dest = ra_dest(as, ir, RSET_FPR); | 443 | Reg dest = ra_dest(as, ir, RSET_FPR); |
| 423 | if (stfp) { /* FP to FP conversion. */ | 444 | if (stfp) { /* FP to FP conversion. */ |
| @@ -476,7 +497,9 @@ static void asm_conv(ASMState *as, IRIns *ir) | |||
| 476 | emit_fb(as, PPCI_FCTIWZ, tmp, left); | 497 | emit_fb(as, PPCI_FCTIWZ, tmp, left); |
| 477 | } | 498 | } |
| 478 | } | 499 | } |
| 479 | } else { | 500 | } else |
| 501 | #endif | ||
| 502 | { | ||
| 480 | Reg dest = ra_dest(as, ir, RSET_GPR); | 503 | Reg dest = ra_dest(as, ir, RSET_GPR); |
| 481 | if (st >= IRT_I8 && st <= IRT_U16) { /* Extend to 32 bit integer. */ | 504 | if (st >= IRT_I8 && st <= IRT_U16) { /* Extend to 32 bit integer. */ |
| 482 | Reg left = ra_alloc1(as, ir->op1, RSET_GPR); | 505 | Reg left = ra_alloc1(as, ir->op1, RSET_GPR); |
| @@ -496,17 +519,41 @@ static void asm_strto(ASMState *as, IRIns *ir) | |||
| 496 | { | 519 | { |
| 497 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_strscan_num]; | 520 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_lj_strscan_num]; |
| 498 | IRRef args[2]; | 521 | IRRef args[2]; |
| 499 | int32_t ofs; | 522 | int32_t ofs = SPOFS_TMP; |
| 523 | #if LJ_SOFTFP | ||
| 524 | ra_evictset(as, RSET_SCRATCH); | ||
| 525 | if (ra_used(ir)) { | ||
| 526 | if (ra_hasspill(ir->s) && ra_hasspill((ir+1)->s) && | ||
| 527 | (ir->s & 1) == LJ_BE && (ir->s ^ 1) == (ir+1)->s) { | ||
| 528 | int i; | ||
| 529 | for (i = 0; i < 2; i++) { | ||
| 530 | Reg r = (ir+i)->r; | ||
| 531 | if (ra_hasreg(r)) { | ||
| 532 | ra_free(as, r); | ||
| 533 | ra_modified(as, r); | ||
| 534 | emit_spload(as, ir+i, r, sps_scale((ir+i)->s)); | ||
| 535 | } | ||
| 536 | } | ||
| 537 | ofs = sps_scale(ir->s & ~1); | ||
| 538 | } else { | ||
| 539 | Reg rhi = ra_dest(as, ir+1, RSET_GPR); | ||
| 540 | Reg rlo = ra_dest(as, ir, rset_exclude(RSET_GPR, rhi)); | ||
| 541 | emit_tai(as, PPCI_LWZ, rhi, RID_SP, ofs); | ||
| 542 | emit_tai(as, PPCI_LWZ, rlo, RID_SP, ofs+4); | ||
| 543 | } | ||
| 544 | } | ||
| 545 | #else | ||
| 500 | RegSet drop = RSET_SCRATCH; | 546 | RegSet drop = RSET_SCRATCH; |
| 501 | if (ra_hasreg(ir->r)) rset_set(drop, ir->r); /* Spill dest reg (if any). */ | 547 | if (ra_hasreg(ir->r)) rset_set(drop, ir->r); /* Spill dest reg (if any). */ |
| 502 | ra_evictset(as, drop); | 548 | ra_evictset(as, drop); |
| 549 | if (ir->s) ofs = sps_scale(ir->s); | ||
| 550 | #endif | ||
| 503 | asm_guardcc(as, CC_EQ); | 551 | asm_guardcc(as, CC_EQ); |
| 504 | emit_ai(as, PPCI_CMPWI, RID_RET, 0); /* Test return status. */ | 552 | emit_ai(as, PPCI_CMPWI, RID_RET, 0); /* Test return status. */ |
| 505 | args[0] = ir->op1; /* GCstr *str */ | 553 | args[0] = ir->op1; /* GCstr *str */ |
| 506 | args[1] = ASMREF_TMP1; /* TValue *n */ | 554 | args[1] = ASMREF_TMP1; /* TValue *n */ |
| 507 | asm_gencall(as, ci, args); | 555 | asm_gencall(as, ci, args); |
| 508 | /* Store the result to the spill slot or temp slots. */ | 556 | /* Store the result to the spill slot or temp slots. */ |
| 509 | ofs = ir->s ? sps_scale(ir->s) : SPOFS_TMP; | ||
| 510 | emit_tai(as, PPCI_ADDI, ra_releasetmp(as, ASMREF_TMP1), RID_SP, ofs); | 557 | emit_tai(as, PPCI_ADDI, ra_releasetmp(as, ASMREF_TMP1), RID_SP, ofs); |
| 511 | } | 558 | } |
| 512 | 559 | ||
| @@ -530,7 +577,10 @@ static void asm_tvptr(ASMState *as, Reg dest, IRRef ref) | |||
| 530 | Reg src = ra_alloc1(as, ref, allow); | 577 | Reg src = ra_alloc1(as, ref, allow); |
| 531 | emit_setgl(as, src, tmptv.gcr); | 578 | emit_setgl(as, src, tmptv.gcr); |
| 532 | } | 579 | } |
| 533 | type = ra_allock(as, irt_toitype(ir->t), allow); | 580 | if (LJ_SOFTFP && (ir+1)->o == IR_HIOP) |
| 581 | type = ra_alloc1(as, ref+1, allow); | ||
| 582 | else | ||
| 583 | type = ra_allock(as, irt_toitype(ir->t), allow); | ||
| 534 | emit_setgl(as, type, tmptv.it); | 584 | emit_setgl(as, type, tmptv.it); |
| 535 | } | 585 | } |
| 536 | } | 586 | } |
| @@ -574,11 +624,27 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge) | |||
| 574 | Reg tisnum = RID_NONE, tmpnum = RID_NONE; | 624 | Reg tisnum = RID_NONE, tmpnum = RID_NONE; |
| 575 | IRRef refkey = ir->op2; | 625 | IRRef refkey = ir->op2; |
| 576 | IRIns *irkey = IR(refkey); | 626 | IRIns *irkey = IR(refkey); |
| 627 | int isk = irref_isk(refkey); | ||
| 577 | IRType1 kt = irkey->t; | 628 | IRType1 kt = irkey->t; |
| 578 | uint32_t khash; | 629 | uint32_t khash; |
| 579 | MCLabel l_end, l_loop, l_next; | 630 | MCLabel l_end, l_loop, l_next; |
| 580 | 631 | ||
| 581 | rset_clear(allow, tab); | 632 | rset_clear(allow, tab); |
| 633 | #if LJ_SOFTFP | ||
| 634 | if (!isk) { | ||
| 635 | key = ra_alloc1(as, refkey, allow); | ||
| 636 | rset_clear(allow, key); | ||
| 637 | if (irkey[1].o == IR_HIOP) { | ||
| 638 | if (ra_hasreg((irkey+1)->r)) { | ||
| 639 | tmpnum = (irkey+1)->r; | ||
| 640 | ra_noweak(as, tmpnum); | ||
| 641 | } else { | ||
| 642 | tmpnum = ra_allocref(as, refkey+1, allow); | ||
| 643 | } | ||
| 644 | rset_clear(allow, tmpnum); | ||
| 645 | } | ||
| 646 | } | ||
| 647 | #else | ||
| 582 | if (irt_isnum(kt)) { | 648 | if (irt_isnum(kt)) { |
| 583 | key = ra_alloc1(as, refkey, RSET_FPR); | 649 | key = ra_alloc1(as, refkey, RSET_FPR); |
| 584 | tmpnum = ra_scratch(as, rset_exclude(RSET_FPR, key)); | 650 | tmpnum = ra_scratch(as, rset_exclude(RSET_FPR, key)); |
| @@ -588,6 +654,7 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge) | |||
| 588 | key = ra_alloc1(as, refkey, allow); | 654 | key = ra_alloc1(as, refkey, allow); |
| 589 | rset_clear(allow, key); | 655 | rset_clear(allow, key); |
| 590 | } | 656 | } |
| 657 | #endif | ||
| 591 | tmp2 = ra_scratch(as, allow); | 658 | tmp2 = ra_scratch(as, allow); |
| 592 | rset_clear(allow, tmp2); | 659 | rset_clear(allow, tmp2); |
| 593 | 660 | ||
| @@ -610,7 +677,7 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge) | |||
| 610 | asm_guardcc(as, CC_EQ); | 677 | asm_guardcc(as, CC_EQ); |
| 611 | else | 678 | else |
| 612 | emit_condbranch(as, PPCI_BC|PPCF_Y, CC_EQ, l_end); | 679 | emit_condbranch(as, PPCI_BC|PPCF_Y, CC_EQ, l_end); |
| 613 | if (irt_isnum(kt)) { | 680 | if (!LJ_SOFTFP && irt_isnum(kt)) { |
| 614 | emit_fab(as, PPCI_FCMPU, 0, tmpnum, key); | 681 | emit_fab(as, PPCI_FCMPU, 0, tmpnum, key); |
| 615 | emit_condbranch(as, PPCI_BC, CC_GE, l_next); | 682 | emit_condbranch(as, PPCI_BC, CC_GE, l_next); |
| 616 | emit_ab(as, PPCI_CMPLW, tmp1, tisnum); | 683 | emit_ab(as, PPCI_CMPLW, tmp1, tisnum); |
| @@ -620,7 +687,10 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge) | |||
| 620 | emit_ab(as, PPCI_CMPW, tmp2, key); | 687 | emit_ab(as, PPCI_CMPW, tmp2, key); |
| 621 | emit_condbranch(as, PPCI_BC, CC_NE, l_next); | 688 | emit_condbranch(as, PPCI_BC, CC_NE, l_next); |
| 622 | } | 689 | } |
| 623 | emit_ai(as, PPCI_CMPWI, tmp1, irt_toitype(irkey->t)); | 690 | if (LJ_SOFTFP && ra_hasreg(tmpnum)) |
| 691 | emit_ab(as, PPCI_CMPW, tmp1, tmpnum); | ||
| 692 | else | ||
| 693 | emit_ai(as, PPCI_CMPWI, tmp1, irt_toitype(irkey->t)); | ||
| 624 | if (!irt_ispri(kt)) | 694 | if (!irt_ispri(kt)) |
| 625 | emit_tai(as, PPCI_LWZ, tmp2, dest, (int32_t)offsetof(Node, key.gcr)); | 695 | emit_tai(as, PPCI_LWZ, tmp2, dest, (int32_t)offsetof(Node, key.gcr)); |
| 626 | } | 696 | } |
| @@ -629,19 +699,19 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge) | |||
| 629 | (((char *)as->mcp-(char *)l_loop) & 0xffffu); | 699 | (((char *)as->mcp-(char *)l_loop) & 0xffffu); |
| 630 | 700 | ||
| 631 | /* Load main position relative to tab->node into dest. */ | 701 | /* Load main position relative to tab->node into dest. */ |
| 632 | khash = irref_isk(refkey) ? ir_khash(irkey) : 1; | 702 | khash = isk ? ir_khash(irkey) : 1; |
| 633 | if (khash == 0) { | 703 | if (khash == 0) { |
| 634 | emit_tai(as, PPCI_LWZ, dest, tab, (int32_t)offsetof(GCtab, node)); | 704 | emit_tai(as, PPCI_LWZ, dest, tab, (int32_t)offsetof(GCtab, node)); |
| 635 | } else { | 705 | } else { |
| 636 | Reg tmphash = tmp1; | 706 | Reg tmphash = tmp1; |
| 637 | if (irref_isk(refkey)) | 707 | if (isk) |
| 638 | tmphash = ra_allock(as, khash, allow); | 708 | tmphash = ra_allock(as, khash, allow); |
| 639 | emit_tab(as, PPCI_ADD, dest, dest, tmp1); | 709 | emit_tab(as, PPCI_ADD, dest, dest, tmp1); |
| 640 | emit_tai(as, PPCI_MULLI, tmp1, tmp1, sizeof(Node)); | 710 | emit_tai(as, PPCI_MULLI, tmp1, tmp1, sizeof(Node)); |
| 641 | emit_asb(as, PPCI_AND, tmp1, tmp2, tmphash); | 711 | emit_asb(as, PPCI_AND, tmp1, tmp2, tmphash); |
| 642 | emit_tai(as, PPCI_LWZ, dest, tab, (int32_t)offsetof(GCtab, node)); | 712 | emit_tai(as, PPCI_LWZ, dest, tab, (int32_t)offsetof(GCtab, node)); |
| 643 | emit_tai(as, PPCI_LWZ, tmp2, tab, (int32_t)offsetof(GCtab, hmask)); | 713 | emit_tai(as, PPCI_LWZ, tmp2, tab, (int32_t)offsetof(GCtab, hmask)); |
| 644 | if (irref_isk(refkey)) { | 714 | if (isk) { |
| 645 | /* Nothing to do. */ | 715 | /* Nothing to do. */ |
| 646 | } else if (irt_isstr(kt)) { | 716 | } else if (irt_isstr(kt)) { |
| 647 | emit_tai(as, PPCI_LWZ, tmp1, key, (int32_t)offsetof(GCstr, hash)); | 717 | emit_tai(as, PPCI_LWZ, tmp1, key, (int32_t)offsetof(GCstr, hash)); |
| @@ -651,13 +721,19 @@ static void asm_href(ASMState *as, IRIns *ir, IROp merge) | |||
| 651 | emit_asb(as, PPCI_XOR, tmp1, tmp1, tmp2); | 721 | emit_asb(as, PPCI_XOR, tmp1, tmp1, tmp2); |
| 652 | emit_rotlwi(as, tmp1, tmp1, (HASH_ROT2+HASH_ROT1)&31); | 722 | emit_rotlwi(as, tmp1, tmp1, (HASH_ROT2+HASH_ROT1)&31); |
| 653 | emit_tab(as, PPCI_SUBF, tmp2, dest, tmp2); | 723 | emit_tab(as, PPCI_SUBF, tmp2, dest, tmp2); |
| 654 | if (irt_isnum(kt)) { | 724 | if (LJ_SOFTFP ? (irkey[1].o == IR_HIOP) : irt_isnum(kt)) { |
| 725 | #if LJ_SOFTFP | ||
| 726 | emit_asb(as, PPCI_XOR, tmp2, key, tmp1); | ||
| 727 | emit_rotlwi(as, dest, tmp1, HASH_ROT1); | ||
| 728 | emit_tab(as, PPCI_ADD, tmp1, tmpnum, tmpnum); | ||
| 729 | #else | ||
| 655 | int32_t ofs = ra_spill(as, irkey); | 730 | int32_t ofs = ra_spill(as, irkey); |
| 656 | emit_asb(as, PPCI_XOR, tmp2, tmp2, tmp1); | 731 | emit_asb(as, PPCI_XOR, tmp2, tmp2, tmp1); |
| 657 | emit_rotlwi(as, dest, tmp1, HASH_ROT1); | 732 | emit_rotlwi(as, dest, tmp1, HASH_ROT1); |
| 658 | emit_tab(as, PPCI_ADD, tmp1, tmp1, tmp1); | 733 | emit_tab(as, PPCI_ADD, tmp1, tmp1, tmp1); |
| 659 | emit_tai(as, PPCI_LWZ, tmp2, RID_SP, ofs+4); | 734 | emit_tai(as, PPCI_LWZ, tmp2, RID_SP, ofs+4); |
| 660 | emit_tai(as, PPCI_LWZ, tmp1, RID_SP, ofs); | 735 | emit_tai(as, PPCI_LWZ, tmp1, RID_SP, ofs); |
| 736 | #endif | ||
| 661 | } else { | 737 | } else { |
| 662 | emit_asb(as, PPCI_XOR, tmp2, key, tmp1); | 738 | emit_asb(as, PPCI_XOR, tmp2, key, tmp1); |
| 663 | emit_rotlwi(as, dest, tmp1, HASH_ROT1); | 739 | emit_rotlwi(as, dest, tmp1, HASH_ROT1); |
| @@ -784,8 +860,8 @@ static PPCIns asm_fxloadins(IRIns *ir) | |||
| 784 | case IRT_U8: return PPCI_LBZ; | 860 | case IRT_U8: return PPCI_LBZ; |
| 785 | case IRT_I16: return PPCI_LHA; | 861 | case IRT_I16: return PPCI_LHA; |
| 786 | case IRT_U16: return PPCI_LHZ; | 862 | case IRT_U16: return PPCI_LHZ; |
| 787 | case IRT_NUM: return PPCI_LFD; | 863 | case IRT_NUM: lua_assert(!LJ_SOFTFP); return PPCI_LFD; |
| 788 | case IRT_FLOAT: return PPCI_LFS; | 864 | case IRT_FLOAT: if (!LJ_SOFTFP) return PPCI_LFS; |
| 789 | default: return PPCI_LWZ; | 865 | default: return PPCI_LWZ; |
| 790 | } | 866 | } |
| 791 | } | 867 | } |
| @@ -795,8 +871,8 @@ static PPCIns asm_fxstoreins(IRIns *ir) | |||
| 795 | switch (irt_type(ir->t)) { | 871 | switch (irt_type(ir->t)) { |
| 796 | case IRT_I8: case IRT_U8: return PPCI_STB; | 872 | case IRT_I8: case IRT_U8: return PPCI_STB; |
| 797 | case IRT_I16: case IRT_U16: return PPCI_STH; | 873 | case IRT_I16: case IRT_U16: return PPCI_STH; |
| 798 | case IRT_NUM: return PPCI_STFD; | 874 | case IRT_NUM: lua_assert(!LJ_SOFTFP); return PPCI_STFD; |
| 799 | case IRT_FLOAT: return PPCI_STFS; | 875 | case IRT_FLOAT: if (!LJ_SOFTFP) return PPCI_STFS; |
| 800 | default: return PPCI_STW; | 876 | default: return PPCI_STW; |
| 801 | } | 877 | } |
| 802 | } | 878 | } |
| @@ -839,7 +915,8 @@ static void asm_fstore(ASMState *as, IRIns *ir) | |||
| 839 | 915 | ||
| 840 | static void asm_xload(ASMState *as, IRIns *ir) | 916 | static void asm_xload(ASMState *as, IRIns *ir) |
| 841 | { | 917 | { |
| 842 | Reg dest = ra_dest(as, ir, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); | 918 | Reg dest = ra_dest(as, ir, |
| 919 | (!LJ_SOFTFP && irt_isfp(ir->t)) ? RSET_FPR : RSET_GPR); | ||
| 843 | lua_assert(!(ir->op2 & IRXLOAD_UNALIGNED)); | 920 | lua_assert(!(ir->op2 & IRXLOAD_UNALIGNED)); |
| 844 | if (irt_isi8(ir->t)) | 921 | if (irt_isi8(ir->t)) |
| 845 | emit_as(as, PPCI_EXTSB, dest, dest); | 922 | emit_as(as, PPCI_EXTSB, dest, dest); |
| @@ -857,7 +934,8 @@ static void asm_xstore_(ASMState *as, IRIns *ir, int32_t ofs) | |||
| 857 | Reg src = ra_alloc1(as, irb->op1, RSET_GPR); | 934 | Reg src = ra_alloc1(as, irb->op1, RSET_GPR); |
| 858 | asm_fusexrefx(as, PPCI_STWBRX, src, ir->op1, rset_exclude(RSET_GPR, src)); | 935 | asm_fusexrefx(as, PPCI_STWBRX, src, ir->op1, rset_exclude(RSET_GPR, src)); |
| 859 | } else { | 936 | } else { |
| 860 | Reg src = ra_alloc1(as, ir->op2, irt_isfp(ir->t) ? RSET_FPR : RSET_GPR); | 937 | Reg src = ra_alloc1(as, ir->op2, |
| 938 | (!LJ_SOFTFP && irt_isfp(ir->t)) ? RSET_FPR : RSET_GPR); | ||
| 861 | asm_fusexref(as, asm_fxstoreins(ir), src, ir->op1, | 939 | asm_fusexref(as, asm_fxstoreins(ir), src, ir->op1, |
| 862 | rset_exclude(RSET_GPR, src), ofs); | 940 | rset_exclude(RSET_GPR, src), ofs); |
| 863 | } | 941 | } |
| @@ -871,10 +949,19 @@ static void asm_ahuvload(ASMState *as, IRIns *ir) | |||
| 871 | Reg dest = RID_NONE, type = RID_TMP, tmp = RID_TMP, idx; | 949 | Reg dest = RID_NONE, type = RID_TMP, tmp = RID_TMP, idx; |
| 872 | RegSet allow = RSET_GPR; | 950 | RegSet allow = RSET_GPR; |
| 873 | int32_t ofs = AHUREF_LSX; | 951 | int32_t ofs = AHUREF_LSX; |
| 952 | if (LJ_SOFTFP && (ir+1)->o == IR_HIOP) { | ||
| 953 | t.irt = IRT_NUM; | ||
| 954 | if (ra_used(ir+1)) { | ||
| 955 | type = ra_dest(as, ir+1, allow); | ||
| 956 | rset_clear(allow, type); | ||
| 957 | } | ||
| 958 | ofs = 0; | ||
| 959 | } | ||
| 874 | if (ra_used(ir)) { | 960 | if (ra_used(ir)) { |
| 875 | lua_assert(irt_isnum(t) || irt_isint(t) || irt_isaddr(t)); | 961 | lua_assert((LJ_SOFTFP ? 0 : irt_isnum(ir->t)) || |
| 876 | if (!irt_isnum(t)) ofs = 0; | 962 | irt_isint(ir->t) || irt_isaddr(ir->t)); |
| 877 | dest = ra_dest(as, ir, irt_isnum(t) ? RSET_FPR : RSET_GPR); | 963 | if (LJ_SOFTFP || !irt_isnum(t)) ofs = 0; |
| 964 | dest = ra_dest(as, ir, (!LJ_SOFTFP && irt_isnum(t)) ? RSET_FPR : allow); | ||
| 878 | rset_clear(allow, dest); | 965 | rset_clear(allow, dest); |
| 879 | } | 966 | } |
| 880 | idx = asm_fuseahuref(as, ir->op1, &ofs, allow); | 967 | idx = asm_fuseahuref(as, ir->op1, &ofs, allow); |
| @@ -883,12 +970,13 @@ static void asm_ahuvload(ASMState *as, IRIns *ir) | |||
| 883 | asm_guardcc(as, CC_GE); | 970 | asm_guardcc(as, CC_GE); |
| 884 | emit_ab(as, PPCI_CMPLW, type, tisnum); | 971 | emit_ab(as, PPCI_CMPLW, type, tisnum); |
| 885 | if (ra_hasreg(dest)) { | 972 | if (ra_hasreg(dest)) { |
| 886 | if (ofs == AHUREF_LSX) { | 973 | if (!LJ_SOFTFP && ofs == AHUREF_LSX) { |
| 887 | tmp = ra_scratch(as, rset_exclude(rset_exclude(RSET_GPR, | 974 | tmp = ra_scratch(as, rset_exclude(rset_exclude(RSET_GPR, |
| 888 | (idx&255)), (idx>>8))); | 975 | (idx&255)), (idx>>8))); |
| 889 | emit_fab(as, PPCI_LFDX, dest, (idx&255), tmp); | 976 | emit_fab(as, PPCI_LFDX, dest, (idx&255), tmp); |
| 890 | } else { | 977 | } else { |
| 891 | emit_fai(as, PPCI_LFD, dest, idx, ofs); | 978 | emit_fai(as, LJ_SOFTFP ? PPCI_LWZ : PPCI_LFD, dest, idx, |
| 979 | ofs+4*LJ_SOFTFP); | ||
| 892 | } | 980 | } |
| 893 | } | 981 | } |
| 894 | } else { | 982 | } else { |
| @@ -911,7 +999,7 @@ static void asm_ahustore(ASMState *as, IRIns *ir) | |||
| 911 | int32_t ofs = AHUREF_LSX; | 999 | int32_t ofs = AHUREF_LSX; |
| 912 | if (ir->r == RID_SINK) | 1000 | if (ir->r == RID_SINK) |
| 913 | return; | 1001 | return; |
| 914 | if (irt_isnum(ir->t)) { | 1002 | if (!LJ_SOFTFP && irt_isnum(ir->t)) { |
| 915 | src = ra_alloc1(as, ir->op2, RSET_FPR); | 1003 | src = ra_alloc1(as, ir->op2, RSET_FPR); |
| 916 | } else { | 1004 | } else { |
| 917 | if (!irt_ispri(ir->t)) { | 1005 | if (!irt_ispri(ir->t)) { |
| @@ -919,11 +1007,14 @@ static void asm_ahustore(ASMState *as, IRIns *ir) | |||
| 919 | rset_clear(allow, src); | 1007 | rset_clear(allow, src); |
| 920 | ofs = 0; | 1008 | ofs = 0; |
| 921 | } | 1009 | } |
| 922 | type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); | 1010 | if (LJ_SOFTFP && (ir+1)->o == IR_HIOP) |
| 1011 | type = ra_alloc1(as, (ir+1)->op2, allow); | ||
| 1012 | else | ||
| 1013 | type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); | ||
| 923 | rset_clear(allow, type); | 1014 | rset_clear(allow, type); |
| 924 | } | 1015 | } |
| 925 | idx = asm_fuseahuref(as, ir->op1, &ofs, allow); | 1016 | idx = asm_fuseahuref(as, ir->op1, &ofs, allow); |
| 926 | if (irt_isnum(ir->t)) { | 1017 | if (!LJ_SOFTFP && irt_isnum(ir->t)) { |
| 927 | if (ofs == AHUREF_LSX) { | 1018 | if (ofs == AHUREF_LSX) { |
| 928 | emit_fab(as, PPCI_STFDX, src, (idx&255), RID_TMP); | 1019 | emit_fab(as, PPCI_STFDX, src, (idx&255), RID_TMP); |
| 929 | emit_slwi(as, RID_TMP, (idx>>8), 3); | 1020 | emit_slwi(as, RID_TMP, (idx>>8), 3); |
| @@ -948,21 +1039,33 @@ static void asm_sload(ASMState *as, IRIns *ir) | |||
| 948 | IRType1 t = ir->t; | 1039 | IRType1 t = ir->t; |
| 949 | Reg dest = RID_NONE, type = RID_NONE, base; | 1040 | Reg dest = RID_NONE, type = RID_NONE, base; |
| 950 | RegSet allow = RSET_GPR; | 1041 | RegSet allow = RSET_GPR; |
| 1042 | int hiop = (LJ_SOFTFP && (ir+1)->o == IR_HIOP); | ||
| 1043 | if (hiop) | ||
| 1044 | t.irt = IRT_NUM; | ||
| 951 | lua_assert(!(ir->op2 & IRSLOAD_PARENT)); /* Handled by asm_head_side(). */ | 1045 | lua_assert(!(ir->op2 & IRSLOAD_PARENT)); /* Handled by asm_head_side(). */ |
| 952 | lua_assert(irt_isguard(t) || !(ir->op2 & IRSLOAD_TYPECHECK)); | 1046 | lua_assert(irt_isguard(ir->t) || !(ir->op2 & IRSLOAD_TYPECHECK)); |
| 953 | lua_assert(LJ_DUALNUM || | 1047 | lua_assert(LJ_DUALNUM || |
| 954 | !irt_isint(t) || (ir->op2 & (IRSLOAD_CONVERT|IRSLOAD_FRAME))); | 1048 | !irt_isint(t) || (ir->op2 & (IRSLOAD_CONVERT|IRSLOAD_FRAME))); |
| 1049 | #if LJ_SOFTFP | ||
| 1050 | lua_assert(!(ir->op2 & IRSLOAD_CONVERT)); /* Handled by LJ_SOFTFP SPLIT. */ | ||
| 1051 | if (hiop && ra_used(ir+1)) { | ||
| 1052 | type = ra_dest(as, ir+1, allow); | ||
| 1053 | rset_clear(allow, type); | ||
| 1054 | } | ||
| 1055 | #else | ||
| 955 | if ((ir->op2 & IRSLOAD_CONVERT) && irt_isguard(t) && irt_isint(t)) { | 1056 | if ((ir->op2 & IRSLOAD_CONVERT) && irt_isguard(t) && irt_isint(t)) { |
| 956 | dest = ra_scratch(as, RSET_FPR); | 1057 | dest = ra_scratch(as, RSET_FPR); |
| 957 | asm_tointg(as, ir, dest); | 1058 | asm_tointg(as, ir, dest); |
| 958 | t.irt = IRT_NUM; /* Continue with a regular number type check. */ | 1059 | t.irt = IRT_NUM; /* Continue with a regular number type check. */ |
| 959 | } else if (ra_used(ir)) { | 1060 | } else |
| 1061 | #endif | ||
| 1062 | if (ra_used(ir)) { | ||
| 960 | lua_assert(irt_isnum(t) || irt_isint(t) || irt_isaddr(t)); | 1063 | lua_assert(irt_isnum(t) || irt_isint(t) || irt_isaddr(t)); |
| 961 | dest = ra_dest(as, ir, irt_isnum(t) ? RSET_FPR : RSET_GPR); | 1064 | dest = ra_dest(as, ir, (!LJ_SOFTFP && irt_isnum(t)) ? RSET_FPR : allow); |
| 962 | rset_clear(allow, dest); | 1065 | rset_clear(allow, dest); |
| 963 | base = ra_alloc1(as, REF_BASE, allow); | 1066 | base = ra_alloc1(as, REF_BASE, allow); |
| 964 | rset_clear(allow, base); | 1067 | rset_clear(allow, base); |
| 965 | if ((ir->op2 & IRSLOAD_CONVERT)) { | 1068 | if (!LJ_SOFTFP && (ir->op2 & IRSLOAD_CONVERT)) { |
| 966 | if (irt_isint(t)) { | 1069 | if (irt_isint(t)) { |
| 967 | emit_tai(as, PPCI_LWZ, dest, RID_SP, SPOFS_TMPLO); | 1070 | emit_tai(as, PPCI_LWZ, dest, RID_SP, SPOFS_TMPLO); |
| 968 | dest = ra_scratch(as, RSET_FPR); | 1071 | dest = ra_scratch(as, RSET_FPR); |
| @@ -994,10 +1097,13 @@ dotypecheck: | |||
| 994 | if ((ir->op2 & IRSLOAD_TYPECHECK)) { | 1097 | if ((ir->op2 & IRSLOAD_TYPECHECK)) { |
| 995 | Reg tisnum = ra_allock(as, (int32_t)LJ_TISNUM, allow); | 1098 | Reg tisnum = ra_allock(as, (int32_t)LJ_TISNUM, allow); |
| 996 | asm_guardcc(as, CC_GE); | 1099 | asm_guardcc(as, CC_GE); |
| 997 | emit_ab(as, PPCI_CMPLW, RID_TMP, tisnum); | 1100 | #if !LJ_SOFTFP |
| 998 | type = RID_TMP; | 1101 | type = RID_TMP; |
| 1102 | #endif | ||
| 1103 | emit_ab(as, PPCI_CMPLW, type, tisnum); | ||
| 999 | } | 1104 | } |
| 1000 | if (ra_hasreg(dest)) emit_fai(as, PPCI_LFD, dest, base, ofs-4); | 1105 | if (ra_hasreg(dest)) emit_fai(as, LJ_SOFTFP ? PPCI_LWZ : PPCI_LFD, dest, |
| 1106 | base, ofs-(LJ_SOFTFP?0:4)); | ||
| 1001 | } else { | 1107 | } else { |
| 1002 | if ((ir->op2 & IRSLOAD_TYPECHECK)) { | 1108 | if ((ir->op2 & IRSLOAD_TYPECHECK)) { |
| 1003 | asm_guardcc(as, CC_NE); | 1109 | asm_guardcc(as, CC_NE); |
| @@ -1119,6 +1225,7 @@ static void asm_obar(ASMState *as, IRIns *ir) | |||
| 1119 | 1225 | ||
| 1120 | /* -- Arithmetic and logic operations ------------------------------------- */ | 1226 | /* -- Arithmetic and logic operations ------------------------------------- */ |
| 1121 | 1227 | ||
| 1228 | #if !LJ_SOFTFP | ||
| 1122 | static void asm_fparith(ASMState *as, IRIns *ir, PPCIns pi) | 1229 | static void asm_fparith(ASMState *as, IRIns *ir, PPCIns pi) |
| 1123 | { | 1230 | { |
| 1124 | Reg dest = ra_dest(as, ir, RSET_FPR); | 1231 | Reg dest = ra_dest(as, ir, RSET_FPR); |
| @@ -1146,13 +1253,17 @@ static void asm_fpmath(ASMState *as, IRIns *ir) | |||
| 1146 | else | 1253 | else |
| 1147 | asm_callid(as, ir, IRCALL_lj_vm_floor + ir->op2); | 1254 | asm_callid(as, ir, IRCALL_lj_vm_floor + ir->op2); |
| 1148 | } | 1255 | } |
| 1256 | #endif | ||
| 1149 | 1257 | ||
| 1150 | static void asm_add(ASMState *as, IRIns *ir) | 1258 | static void asm_add(ASMState *as, IRIns *ir) |
| 1151 | { | 1259 | { |
| 1260 | #if !LJ_SOFTFP | ||
| 1152 | if (irt_isnum(ir->t)) { | 1261 | if (irt_isnum(ir->t)) { |
| 1153 | if (!asm_fusemadd(as, ir, PPCI_FMADD, PPCI_FMADD)) | 1262 | if (!asm_fusemadd(as, ir, PPCI_FMADD, PPCI_FMADD)) |
| 1154 | asm_fparith(as, ir, PPCI_FADD); | 1263 | asm_fparith(as, ir, PPCI_FADD); |
| 1155 | } else { | 1264 | } else |
| 1265 | #endif | ||
| 1266 | { | ||
| 1156 | Reg dest = ra_dest(as, ir, RSET_GPR); | 1267 | Reg dest = ra_dest(as, ir, RSET_GPR); |
| 1157 | Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); | 1268 | Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); |
| 1158 | PPCIns pi; | 1269 | PPCIns pi; |
| @@ -1191,10 +1302,13 @@ static void asm_add(ASMState *as, IRIns *ir) | |||
| 1191 | 1302 | ||
| 1192 | static void asm_sub(ASMState *as, IRIns *ir) | 1303 | static void asm_sub(ASMState *as, IRIns *ir) |
| 1193 | { | 1304 | { |
| 1305 | #if !LJ_SOFTFP | ||
| 1194 | if (irt_isnum(ir->t)) { | 1306 | if (irt_isnum(ir->t)) { |
| 1195 | if (!asm_fusemadd(as, ir, PPCI_FMSUB, PPCI_FNMSUB)) | 1307 | if (!asm_fusemadd(as, ir, PPCI_FMSUB, PPCI_FNMSUB)) |
| 1196 | asm_fparith(as, ir, PPCI_FSUB); | 1308 | asm_fparith(as, ir, PPCI_FSUB); |
| 1197 | } else { | 1309 | } else |
| 1310 | #endif | ||
| 1311 | { | ||
| 1198 | PPCIns pi = PPCI_SUBF; | 1312 | PPCIns pi = PPCI_SUBF; |
| 1199 | Reg dest = ra_dest(as, ir, RSET_GPR); | 1313 | Reg dest = ra_dest(as, ir, RSET_GPR); |
| 1200 | Reg left, right; | 1314 | Reg left, right; |
| @@ -1220,9 +1334,12 @@ static void asm_sub(ASMState *as, IRIns *ir) | |||
| 1220 | 1334 | ||
| 1221 | static void asm_mul(ASMState *as, IRIns *ir) | 1335 | static void asm_mul(ASMState *as, IRIns *ir) |
| 1222 | { | 1336 | { |
| 1337 | #if !LJ_SOFTFP | ||
| 1223 | if (irt_isnum(ir->t)) { | 1338 | if (irt_isnum(ir->t)) { |
| 1224 | asm_fparith(as, ir, PPCI_FMUL); | 1339 | asm_fparith(as, ir, PPCI_FMUL); |
| 1225 | } else { | 1340 | } else |
| 1341 | #endif | ||
| 1342 | { | ||
| 1226 | PPCIns pi = PPCI_MULLW; | 1343 | PPCIns pi = PPCI_MULLW; |
| 1227 | Reg dest = ra_dest(as, ir, RSET_GPR); | 1344 | Reg dest = ra_dest(as, ir, RSET_GPR); |
| 1228 | Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); | 1345 | Reg right, left = ra_hintalloc(as, ir->op1, dest, RSET_GPR); |
| @@ -1250,9 +1367,12 @@ static void asm_mul(ASMState *as, IRIns *ir) | |||
| 1250 | 1367 | ||
| 1251 | static void asm_neg(ASMState *as, IRIns *ir) | 1368 | static void asm_neg(ASMState *as, IRIns *ir) |
| 1252 | { | 1369 | { |
| 1370 | #if !LJ_SOFTFP | ||
| 1253 | if (irt_isnum(ir->t)) { | 1371 | if (irt_isnum(ir->t)) { |
| 1254 | asm_fpunary(as, ir, PPCI_FNEG); | 1372 | asm_fpunary(as, ir, PPCI_FNEG); |
| 1255 | } else { | 1373 | } else |
| 1374 | #endif | ||
| 1375 | { | ||
| 1256 | Reg dest, left; | 1376 | Reg dest, left; |
| 1257 | PPCIns pi = PPCI_NEG; | 1377 | PPCIns pi = PPCI_NEG; |
| 1258 | if (as->flagmcp == as->mcp) { | 1378 | if (as->flagmcp == as->mcp) { |
| @@ -1563,9 +1683,40 @@ static void asm_bitshift(ASMState *as, IRIns *ir, PPCIns pi, PPCIns pik) | |||
| 1563 | PPCI_RLWINM|PPCF_MB(0)|PPCF_ME(31)) | 1683 | PPCI_RLWINM|PPCF_MB(0)|PPCF_ME(31)) |
| 1564 | #define asm_bror(as, ir) lua_assert(0) | 1684 | #define asm_bror(as, ir) lua_assert(0) |
| 1565 | 1685 | ||
| 1686 | #if LJ_SOFTFP | ||
| 1687 | static void asm_sfpmin_max(ASMState *as, IRIns *ir) | ||
| 1688 | { | ||
| 1689 | CCallInfo ci = lj_ir_callinfo[IRCALL_softfp_cmp]; | ||
| 1690 | IRRef args[4]; | ||
| 1691 | MCLabel l_right, l_end; | ||
| 1692 | Reg desthi = ra_dest(as, ir, RSET_GPR), destlo = ra_dest(as, ir+1, RSET_GPR); | ||
| 1693 | Reg righthi, lefthi = ra_alloc2(as, ir, RSET_GPR); | ||
| 1694 | Reg rightlo, leftlo = ra_alloc2(as, ir+1, RSET_GPR); | ||
| 1695 | PPCCC cond = (IROp)ir->o == IR_MIN ? CC_EQ : CC_NE; | ||
| 1696 | righthi = (lefthi >> 8); lefthi &= 255; | ||
| 1697 | rightlo = (leftlo >> 8); leftlo &= 255; | ||
| 1698 | args[0^LJ_BE] = ir->op1; args[1^LJ_BE] = (ir+1)->op1; | ||
| 1699 | args[2^LJ_BE] = ir->op2; args[3^LJ_BE] = (ir+1)->op2; | ||
| 1700 | l_end = emit_label(as); | ||
| 1701 | if (desthi != righthi) emit_mr(as, desthi, righthi); | ||
| 1702 | if (destlo != rightlo) emit_mr(as, destlo, rightlo); | ||
| 1703 | l_right = emit_label(as); | ||
| 1704 | if (l_end != l_right) emit_jmp(as, l_end); | ||
| 1705 | if (desthi != lefthi) emit_mr(as, desthi, lefthi); | ||
| 1706 | if (destlo != leftlo) emit_mr(as, destlo, leftlo); | ||
| 1707 | if (l_right == as->mcp+1) { | ||
| 1708 | cond ^= 4; l_right = l_end; ++as->mcp; | ||
| 1709 | } | ||
| 1710 | emit_condbranch(as, PPCI_BC, cond, l_right); | ||
| 1711 | ra_evictset(as, RSET_SCRATCH); | ||
| 1712 | emit_cmpi(as, RID_RET, 1); | ||
| 1713 | asm_gencall(as, &ci, args); | ||
| 1714 | } | ||
| 1715 | #endif | ||
| 1716 | |||
| 1566 | static void asm_min_max(ASMState *as, IRIns *ir, int ismax) | 1717 | static void asm_min_max(ASMState *as, IRIns *ir, int ismax) |
| 1567 | { | 1718 | { |
| 1568 | if (irt_isnum(ir->t)) { | 1719 | if (!LJ_SOFTFP && irt_isnum(ir->t)) { |
| 1569 | Reg dest = ra_dest(as, ir, RSET_FPR); | 1720 | Reg dest = ra_dest(as, ir, RSET_FPR); |
| 1570 | Reg tmp = dest; | 1721 | Reg tmp = dest; |
| 1571 | Reg right, left = ra_alloc2(as, ir, RSET_FPR); | 1722 | Reg right, left = ra_alloc2(as, ir, RSET_FPR); |
| @@ -1653,7 +1804,7 @@ static void asm_intcomp_(ASMState *as, IRRef lref, IRRef rref, Reg cr, PPCCC cc) | |||
| 1653 | static void asm_comp(ASMState *as, IRIns *ir) | 1804 | static void asm_comp(ASMState *as, IRIns *ir) |
| 1654 | { | 1805 | { |
| 1655 | PPCCC cc = asm_compmap[ir->o]; | 1806 | PPCCC cc = asm_compmap[ir->o]; |
| 1656 | if (irt_isnum(ir->t)) { | 1807 | if (!LJ_SOFTFP && irt_isnum(ir->t)) { |
| 1657 | Reg right, left = ra_alloc2(as, ir, RSET_FPR); | 1808 | Reg right, left = ra_alloc2(as, ir, RSET_FPR); |
| 1658 | right = (left >> 8); left &= 255; | 1809 | right = (left >> 8); left &= 255; |
| 1659 | asm_guardcc(as, (cc >> 4)); | 1810 | asm_guardcc(as, (cc >> 4)); |
| @@ -1674,6 +1825,44 @@ static void asm_comp(ASMState *as, IRIns *ir) | |||
| 1674 | 1825 | ||
| 1675 | #define asm_equal(as, ir) asm_comp(as, ir) | 1826 | #define asm_equal(as, ir) asm_comp(as, ir) |
| 1676 | 1827 | ||
| 1828 | #if LJ_SOFTFP | ||
| 1829 | /* SFP comparisons. */ | ||
| 1830 | static void asm_sfpcomp(ASMState *as, IRIns *ir) | ||
| 1831 | { | ||
| 1832 | const CCallInfo *ci = &lj_ir_callinfo[IRCALL_softfp_cmp]; | ||
| 1833 | RegSet drop = RSET_SCRATCH; | ||
| 1834 | Reg r; | ||
| 1835 | IRRef args[4]; | ||
| 1836 | args[0^LJ_BE] = ir->op1; args[1^LJ_BE] = (ir+1)->op1; | ||
| 1837 | args[2^LJ_BE] = ir->op2; args[3^LJ_BE] = (ir+1)->op2; | ||
| 1838 | |||
| 1839 | for (r = REGARG_FIRSTGPR; r <= REGARG_FIRSTGPR+3; r++) { | ||
| 1840 | if (!rset_test(as->freeset, r) && | ||
| 1841 | regcost_ref(as->cost[r]) == args[r-REGARG_FIRSTGPR]) | ||
| 1842 | rset_clear(drop, r); | ||
| 1843 | } | ||
| 1844 | ra_evictset(as, drop); | ||
| 1845 | asm_setupresult(as, ir, ci); | ||
| 1846 | switch ((IROp)ir->o) { | ||
| 1847 | case IR_ULT: | ||
| 1848 | asm_guardcc(as, CC_EQ); | ||
| 1849 | emit_ai(as, PPCI_CMPWI, RID_RET, 0); | ||
| 1850 | case IR_ULE: | ||
| 1851 | asm_guardcc(as, CC_EQ); | ||
| 1852 | emit_ai(as, PPCI_CMPWI, RID_RET, 1); | ||
| 1853 | break; | ||
| 1854 | case IR_GE: case IR_GT: | ||
| 1855 | asm_guardcc(as, CC_EQ); | ||
| 1856 | emit_ai(as, PPCI_CMPWI, RID_RET, 2); | ||
| 1857 | default: | ||
| 1858 | asm_guardcc(as, (asm_compmap[ir->o] & 0xf)); | ||
| 1859 | emit_ai(as, PPCI_CMPWI, RID_RET, 0); | ||
| 1860 | break; | ||
| 1861 | } | ||
| 1862 | asm_gencall(as, ci, args); | ||
| 1863 | } | ||
| 1864 | #endif | ||
| 1865 | |||
| 1677 | #if LJ_HASFFI | 1866 | #if LJ_HASFFI |
| 1678 | /* 64 bit integer comparisons. */ | 1867 | /* 64 bit integer comparisons. */ |
| 1679 | static void asm_comp64(ASMState *as, IRIns *ir) | 1868 | static void asm_comp64(ASMState *as, IRIns *ir) |
| @@ -1703,19 +1892,36 @@ static void asm_comp64(ASMState *as, IRIns *ir) | |||
| 1703 | /* Hiword op of a split 64 bit op. Previous op must be the loword op. */ | 1892 | /* Hiword op of a split 64 bit op. Previous op must be the loword op. */ |
| 1704 | static void asm_hiop(ASMState *as, IRIns *ir) | 1893 | static void asm_hiop(ASMState *as, IRIns *ir) |
| 1705 | { | 1894 | { |
| 1706 | #if LJ_HASFFI | 1895 | #if LJ_HASFFI || LJ_SOFTFP |
| 1707 | /* HIOP is marked as a store because it needs its own DCE logic. */ | 1896 | /* HIOP is marked as a store because it needs its own DCE logic. */ |
| 1708 | int uselo = ra_used(ir-1), usehi = ra_used(ir); /* Loword/hiword used? */ | 1897 | int uselo = ra_used(ir-1), usehi = ra_used(ir); /* Loword/hiword used? */ |
| 1709 | if (LJ_UNLIKELY(!(as->flags & JIT_F_OPT_DCE))) uselo = usehi = 1; | 1898 | if (LJ_UNLIKELY(!(as->flags & JIT_F_OPT_DCE))) uselo = usehi = 1; |
| 1710 | if ((ir-1)->o == IR_CONV) { /* Conversions to/from 64 bit. */ | 1899 | if ((ir-1)->o == IR_CONV) { /* Conversions to/from 64 bit. */ |
| 1711 | as->curins--; /* Always skip the CONV. */ | 1900 | as->curins--; /* Always skip the CONV. */ |
| 1901 | #if LJ_HASFFI && !LJ_SOFTFP | ||
| 1712 | if (usehi || uselo) | 1902 | if (usehi || uselo) |
| 1713 | asm_conv64(as, ir); | 1903 | asm_conv64(as, ir); |
| 1714 | return; | 1904 | return; |
| 1905 | #endif | ||
| 1715 | } else if ((ir-1)->o <= IR_NE) { /* 64 bit integer comparisons. ORDER IR. */ | 1906 | } else if ((ir-1)->o <= IR_NE) { /* 64 bit integer comparisons. ORDER IR. */ |
| 1716 | as->curins--; /* Always skip the loword comparison. */ | 1907 | as->curins--; /* Always skip the loword comparison. */ |
| 1908 | #if LJ_SOFTFP | ||
| 1909 | if (!irt_isint(ir->t)) { | ||
| 1910 | asm_sfpcomp(as, ir-1); | ||
| 1911 | return; | ||
| 1912 | } | ||
| 1913 | #endif | ||
| 1914 | #if LJ_HASFFI | ||
| 1717 | asm_comp64(as, ir); | 1915 | asm_comp64(as, ir); |
| 1916 | #endif | ||
| 1917 | return; | ||
| 1918 | #if LJ_SOFTFP | ||
| 1919 | } else if ((ir-1)->o == IR_MIN || (ir-1)->o == IR_MAX) { | ||
| 1920 | as->curins--; /* Always skip the loword min/max. */ | ||
| 1921 | if (uselo || usehi) | ||
| 1922 | asm_sfpmin_max(as, ir-1); | ||
| 1718 | return; | 1923 | return; |
| 1924 | #endif | ||
| 1719 | } else if ((ir-1)->o == IR_XSTORE) { | 1925 | } else if ((ir-1)->o == IR_XSTORE) { |
| 1720 | as->curins--; /* Handle both stores here. */ | 1926 | as->curins--; /* Handle both stores here. */ |
| 1721 | if ((ir-1)->r != RID_SINK) { | 1927 | if ((ir-1)->r != RID_SINK) { |
| @@ -1726,14 +1932,27 @@ static void asm_hiop(ASMState *as, IRIns *ir) | |||
| 1726 | } | 1932 | } |
| 1727 | if (!usehi) return; /* Skip unused hiword op for all remaining ops. */ | 1933 | if (!usehi) return; /* Skip unused hiword op for all remaining ops. */ |
| 1728 | switch ((ir-1)->o) { | 1934 | switch ((ir-1)->o) { |
| 1935 | #if LJ_HASFFI | ||
| 1729 | case IR_ADD: as->curins--; asm_add64(as, ir); break; | 1936 | case IR_ADD: as->curins--; asm_add64(as, ir); break; |
| 1730 | case IR_SUB: as->curins--; asm_sub64(as, ir); break; | 1937 | case IR_SUB: as->curins--; asm_sub64(as, ir); break; |
| 1731 | case IR_NEG: as->curins--; asm_neg64(as, ir); break; | 1938 | case IR_NEG: as->curins--; asm_neg64(as, ir); break; |
| 1939 | #endif | ||
| 1940 | #if LJ_SOFTFP | ||
| 1941 | case IR_SLOAD: case IR_ALOAD: case IR_HLOAD: case IR_ULOAD: case IR_VLOAD: | ||
| 1942 | case IR_STRTO: | ||
| 1943 | if (!uselo) | ||
| 1944 | ra_allocref(as, ir->op1, RSET_GPR); /* Mark lo op as used. */ | ||
| 1945 | break; | ||
| 1946 | #endif | ||
| 1732 | case IR_CALLN: | 1947 | case IR_CALLN: |
| 1948 | case IR_CALLS: | ||
| 1733 | case IR_CALLXS: | 1949 | case IR_CALLXS: |
| 1734 | if (!uselo) | 1950 | if (!uselo) |
| 1735 | ra_allocref(as, ir->op1, RID2RSET(RID_RETLO)); /* Mark lo op as used. */ | 1951 | ra_allocref(as, ir->op1, RID2RSET(RID_RETLO)); /* Mark lo op as used. */ |
| 1736 | break; | 1952 | break; |
| 1953 | #if LJ_SOFTFP | ||
| 1954 | case IR_ASTORE: case IR_HSTORE: case IR_USTORE: case IR_TOSTR: | ||
| 1955 | #endif | ||
| 1737 | case IR_CNEWI: | 1956 | case IR_CNEWI: |
| 1738 | /* Nothing to do here. Handled by lo op itself. */ | 1957 | /* Nothing to do here. Handled by lo op itself. */ |
| 1739 | break; | 1958 | break; |
| @@ -1797,8 +2016,19 @@ static void asm_stack_restore(ASMState *as, SnapShot *snap) | |||
| 1797 | if ((sn & SNAP_NORESTORE)) | 2016 | if ((sn & SNAP_NORESTORE)) |
| 1798 | continue; | 2017 | continue; |
| 1799 | if (irt_isnum(ir->t)) { | 2018 | if (irt_isnum(ir->t)) { |
| 2019 | #if LJ_SOFTFP | ||
| 2020 | Reg tmp; | ||
| 2021 | RegSet allow = rset_exclude(RSET_GPR, RID_BASE); | ||
| 2022 | lua_assert(irref_isk(ref)); /* LJ_SOFTFP: must be a number constant. */ | ||
| 2023 | tmp = ra_allock(as, (int32_t)ir_knum(ir)->u32.lo, allow); | ||
| 2024 | emit_tai(as, PPCI_STW, tmp, RID_BASE, ofs+(LJ_BE?4:0)); | ||
| 2025 | if (rset_test(as->freeset, tmp+1)) allow = RID2RSET(tmp+1); | ||
| 2026 | tmp = ra_allock(as, (int32_t)ir_knum(ir)->u32.hi, allow); | ||
| 2027 | emit_tai(as, PPCI_STW, tmp, RID_BASE, ofs+(LJ_BE?0:4)); | ||
| 2028 | #else | ||
| 1800 | Reg src = ra_alloc1(as, ref, RSET_FPR); | 2029 | Reg src = ra_alloc1(as, ref, RSET_FPR); |
| 1801 | emit_fai(as, PPCI_STFD, src, RID_BASE, ofs); | 2030 | emit_fai(as, PPCI_STFD, src, RID_BASE, ofs); |
| 2031 | #endif | ||
| 1802 | } else { | 2032 | } else { |
| 1803 | Reg type; | 2033 | Reg type; |
| 1804 | RegSet allow = rset_exclude(RSET_GPR, RID_BASE); | 2034 | RegSet allow = rset_exclude(RSET_GPR, RID_BASE); |
| @@ -1811,6 +2041,10 @@ static void asm_stack_restore(ASMState *as, SnapShot *snap) | |||
| 1811 | if ((sn & (SNAP_CONT|SNAP_FRAME))) { | 2041 | if ((sn & (SNAP_CONT|SNAP_FRAME))) { |
| 1812 | if (s == 0) continue; /* Do not overwrite link to previous frame. */ | 2042 | if (s == 0) continue; /* Do not overwrite link to previous frame. */ |
| 1813 | type = ra_allock(as, (int32_t)(*flinks--), allow); | 2043 | type = ra_allock(as, (int32_t)(*flinks--), allow); |
| 2044 | #if LJ_SOFTFP | ||
| 2045 | } else if ((sn & SNAP_SOFTFPNUM)) { | ||
| 2046 | type = ra_alloc1(as, ref+1, rset_exclude(RSET_GPR, RID_BASE)); | ||
| 2047 | #endif | ||
| 1814 | } else { | 2048 | } else { |
| 1815 | type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); | 2049 | type = ra_allock(as, (int32_t)irt_toitype(ir->t), allow); |
| 1816 | } | 2050 | } |
| @@ -1947,14 +2181,15 @@ static Reg asm_setup_call_slots(ASMState *as, IRIns *ir, const CCallInfo *ci) | |||
| 1947 | int nslots = 2, ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR; | 2181 | int nslots = 2, ngpr = REGARG_NUMGPR, nfpr = REGARG_NUMFPR; |
| 1948 | asm_collectargs(as, ir, ci, args); | 2182 | asm_collectargs(as, ir, ci, args); |
| 1949 | for (i = 0; i < nargs; i++) | 2183 | for (i = 0; i < nargs; i++) |
| 1950 | if (args[i] && irt_isfp(IR(args[i])->t)) { | 2184 | if (!LJ_SOFTFP && args[i] && irt_isfp(IR(args[i])->t)) { |
| 1951 | if (nfpr > 0) nfpr--; else nslots = (nslots+3) & ~1; | 2185 | if (nfpr > 0) nfpr--; else nslots = (nslots+3) & ~1; |
| 1952 | } else { | 2186 | } else { |
| 1953 | if (ngpr > 0) ngpr--; else nslots++; | 2187 | if (ngpr > 0) ngpr--; else nslots++; |
| 1954 | } | 2188 | } |
| 1955 | if (nslots > as->evenspill) /* Leave room for args in stack slots. */ | 2189 | if (nslots > as->evenspill) /* Leave room for args in stack slots. */ |
| 1956 | as->evenspill = nslots; | 2190 | as->evenspill = nslots; |
| 1957 | return irt_isfp(ir->t) ? REGSP_HINT(RID_FPRET) : REGSP_HINT(RID_RET); | 2191 | return (!LJ_SOFTFP && irt_isfp(ir->t)) ? REGSP_HINT(RID_FPRET) : |
| 2192 | REGSP_HINT(RID_RET); | ||
| 1958 | } | 2193 | } |
| 1959 | 2194 | ||
| 1960 | static void asm_setup_target(ASMState *as) | 2195 | static void asm_setup_target(ASMState *as) |
