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. */ |