diff options
| -rw-r--r-- | src/lj_iropt.h | 1 | ||||
| -rw-r--r-- | src/lj_opt_fold.c | 3 | ||||
| -rw-r--r-- | src/lj_opt_mem.c | 89 |
3 files changed, 90 insertions, 3 deletions
diff --git a/src/lj_iropt.h b/src/lj_iropt.h index 9e7ac9cd..4739f846 100644 --- a/src/lj_iropt.h +++ b/src/lj_iropt.h | |||
| @@ -127,6 +127,7 @@ LJ_FUNC int lj_opt_fwd_wasnonnil(jit_State *J, IROpT loadop, IRRef xref); | |||
| 127 | LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_ahstore(jit_State *J); | 127 | LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_ahstore(jit_State *J); |
| 128 | LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_ustore(jit_State *J); | 128 | LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_ustore(jit_State *J); |
| 129 | LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_fstore(jit_State *J); | 129 | LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_fstore(jit_State *J); |
| 130 | LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_xstore(jit_State *J); | ||
| 130 | 131 | ||
| 131 | /* Narrowing. */ | 132 | /* Narrowing. */ |
| 132 | LJ_FUNC TRef LJ_FASTCALL lj_opt_narrow_convert(jit_State *J); | 133 | LJ_FUNC TRef LJ_FASTCALL lj_opt_narrow_convert(jit_State *J); |
diff --git a/src/lj_opt_fold.c b/src/lj_opt_fold.c index 18471abf..cbcbb448 100644 --- a/src/lj_opt_fold.c +++ b/src/lj_opt_fold.c | |||
| @@ -1696,6 +1696,9 @@ LJFOLDX(lj_opt_dse_ustore) | |||
| 1696 | LJFOLD(FSTORE any any) | 1696 | LJFOLD(FSTORE any any) |
| 1697 | LJFOLDX(lj_opt_dse_fstore) | 1697 | LJFOLDX(lj_opt_dse_fstore) |
| 1698 | 1698 | ||
| 1699 | LJFOLD(XSTORE any any) | ||
| 1700 | LJFOLDX(lj_opt_dse_xstore) | ||
| 1701 | |||
| 1699 | LJFOLD(NEWREF any any) /* Treated like a store. */ | 1702 | LJFOLD(NEWREF any any) /* Treated like a store. */ |
| 1700 | LJFOLD(CALLS any any) | 1703 | LJFOLD(CALLS any any) |
| 1701 | LJFOLD(CALLL any any) /* Safeguard fallback. */ | 1704 | LJFOLD(CALLL any any) /* Safeguard fallback. */ |
diff --git a/src/lj_opt_mem.c b/src/lj_opt_mem.c index d47706fb..ec080697 100644 --- a/src/lj_opt_mem.c +++ b/src/lj_opt_mem.c | |||
| @@ -523,12 +523,52 @@ doemit: | |||
| 523 | return EMITFOLD; /* Otherwise we have a conflict or simply no match. */ | 523 | return EMITFOLD; /* Otherwise we have a conflict or simply no match. */ |
| 524 | } | 524 | } |
| 525 | 525 | ||
| 526 | /* -- XLOAD forwarding ---------------------------------------------------- */ | 526 | /* -- XLOAD forwarding and XSTORE elimination ----------------------------- */ |
| 527 | 527 | ||
| 528 | /* NYI: Alias analysis for XLOAD/XSTORE. */ | 528 | /* Alias analysis for XLOAD/XSTORE. */ |
| 529 | static AliasRet aa_xref(jit_State *J, IRIns *refa, IRIns *refb) | 529 | static AliasRet aa_xref(jit_State *J, IRIns *refa, IRIns *refb) |
| 530 | { | 530 | { |
| 531 | UNUSED(J); UNUSED(refa); UNUSED(refb); | 531 | ptrdiff_t ofsa = 0, ofsb = 0; |
| 532 | IRIns *basea = refa, *baseb = refb; | ||
| 533 | if (refa == refb) | ||
| 534 | return ALIAS_MUST; /* Shortcut for same refs. */ | ||
| 535 | /* This implements (very) strict aliasing rules. | ||
| 536 | ** Different types do NOT alias, except for differences in signedness. | ||
| 537 | ** NYI: this also prevents type punning through unions. | ||
| 538 | */ | ||
| 539 | if (!(irt_sametype(refa->t, refb->t) || | ||
| 540 | (irt_typerange(refa->t, IRT_I8, IRT_INT) && | ||
| 541 | ((refa->t.irt - IRT_I8) ^ (refb->t.irt - IRT_I8)) == 1))) | ||
| 542 | return ALIAS_NO; | ||
| 543 | /* Offset-based disambiguation. */ | ||
| 544 | if (refa->o == IR_ADD && irref_isk(refa->op2)) { | ||
| 545 | IRIns *irk = IR(refa->op2); | ||
| 546 | basea = IR(refa->op1); | ||
| 547 | ofsa = (LJ_64 && irk->o == IR_KINT64) ? (ptrdiff_t)ir_k64(irk)->u64 : | ||
| 548 | (ptrdiff_t)irk->i; | ||
| 549 | if (basea == refb && ofsa != 0) | ||
| 550 | return ALIAS_NO; /* base+-ofs vs. base. */ | ||
| 551 | } | ||
| 552 | if (refb->o == IR_ADD && irref_isk(refb->op2)) { | ||
| 553 | IRIns *irk = IR(refb->op2); | ||
| 554 | baseb = IR(refb->op1); | ||
| 555 | ofsb = (LJ_64 && irk->o == IR_KINT64) ? (ptrdiff_t)ir_k64(irk)->u64 : | ||
| 556 | (ptrdiff_t)irk->i; | ||
| 557 | if (refa == baseb && ofsb != 0) | ||
| 558 | return ALIAS_NO; /* base vs. base+-ofs. */ | ||
| 559 | } | ||
| 560 | if (basea == baseb) { | ||
| 561 | /* This assumes strictly-typed, non-overlapping accesses. */ | ||
| 562 | if (ofsa != ofsb) | ||
| 563 | return ALIAS_NO; /* base+-o1 vs. base+-o2 and o1 != o2. */ | ||
| 564 | /* Unsigned vs. signed access to the same address. | ||
| 565 | ** Really ALIAS_MUST, but store forwarding would lose the type. | ||
| 566 | ** This is rare, so return ALIAS_MAY for now. | ||
| 567 | */ | ||
| 568 | return ALIAS_MAY; | ||
| 569 | } | ||
| 570 | /* NYI: structural disambiguation. */ | ||
| 571 | /* NYI: disambiguate new allocations. */ | ||
| 532 | return ALIAS_MAY; | 572 | return ALIAS_MAY; |
| 533 | } | 573 | } |
| 534 | 574 | ||
| @@ -567,6 +607,49 @@ cselim: | |||
| 567 | return lj_ir_emit(J); | 607 | return lj_ir_emit(J); |
| 568 | } | 608 | } |
| 569 | 609 | ||
| 610 | /* XSTORE elimination. */ | ||
| 611 | TRef LJ_FASTCALL lj_opt_dse_xstore(jit_State *J) | ||
| 612 | { | ||
| 613 | IRRef xref = fins->op1; | ||
| 614 | IRRef val = fins->op2; /* Stored value reference. */ | ||
| 615 | IRIns *xr = IR(xref); | ||
| 616 | IRRef1 *refp = &J->chain[IR_XSTORE]; | ||
| 617 | IRRef ref = *refp; | ||
| 618 | while (ref > xref) { /* Search for redundant or conflicting stores. */ | ||
| 619 | IRIns *store = IR(ref); | ||
| 620 | switch (aa_xref(J, xr, IR(store->op1))) { | ||
| 621 | case ALIAS_NO: | ||
| 622 | break; /* Continue searching. */ | ||
| 623 | case ALIAS_MAY: | ||
| 624 | if (store->op2 != val) /* Conflict if the value is different. */ | ||
| 625 | goto doemit; | ||
| 626 | break; /* Otherwise continue searching. */ | ||
| 627 | case ALIAS_MUST: | ||
| 628 | if (store->op2 == val) /* Same value: drop the new store. */ | ||
| 629 | return DROPFOLD; | ||
| 630 | /* Different value: try to eliminate the redundant store. */ | ||
| 631 | if (ref > J->chain[IR_LOOP]) { /* Quick check to avoid crossing LOOP. */ | ||
| 632 | IRIns *ir; | ||
| 633 | /* Check for any intervening guards or any XLOADs (no AA performed). */ | ||
| 634 | for (ir = IR(J->cur.nins-1); ir > store; ir--) | ||
| 635 | if (irt_isguard(ir->t) || ir->o == IR_XLOAD) | ||
| 636 | goto doemit; /* No elimination possible. */ | ||
| 637 | /* Remove redundant store from chain and replace with NOP. */ | ||
| 638 | *refp = store->prev; | ||
| 639 | store->o = IR_NOP; /* Unchained NOP -- does anybody care? */ | ||
| 640 | store->t.irt = IRT_NIL; | ||
| 641 | store->op1 = store->op2 = 0; | ||
| 642 | store->prev = 0; | ||
| 643 | /* Now emit the new store instead. */ | ||
| 644 | } | ||
| 645 | goto doemit; | ||
| 646 | } | ||
| 647 | ref = *(refp = &store->prev); | ||
| 648 | } | ||
| 649 | doemit: | ||
| 650 | return EMITFOLD; /* Otherwise we have a conflict or simply no match. */ | ||
| 651 | } | ||
| 652 | |||
| 570 | /* -- Forwarding of lj_tab_len -------------------------------------------- */ | 653 | /* -- Forwarding of lj_tab_len -------------------------------------------- */ |
| 571 | 654 | ||
| 572 | /* This is rather simplistic right now, but better than nothing. */ | 655 | /* This is rather simplistic right now, but better than nothing. */ |
