Add alias analysis for XLOAD/XSTORE. Add DSE for XSTORE.

This commit is contained in:
Mike Pall 2010-12-12 22:28:48 +01:00
parent a22ea8898e
commit 74317fa0ef
3 changed files with 90 additions and 3 deletions

View File

@ -127,6 +127,7 @@ LJ_FUNC int lj_opt_fwd_wasnonnil(jit_State *J, IROpT loadop, IRRef xref);
LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_ahstore(jit_State *J); LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_ahstore(jit_State *J);
LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_ustore(jit_State *J); LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_ustore(jit_State *J);
LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_fstore(jit_State *J); LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_fstore(jit_State *J);
LJ_FUNC TRef LJ_FASTCALL lj_opt_dse_xstore(jit_State *J);
/* Narrowing. */ /* Narrowing. */
LJ_FUNC TRef LJ_FASTCALL lj_opt_narrow_convert(jit_State *J); LJ_FUNC TRef LJ_FASTCALL lj_opt_narrow_convert(jit_State *J);

View File

@ -1696,6 +1696,9 @@ LJFOLDX(lj_opt_dse_ustore)
LJFOLD(FSTORE any any) LJFOLD(FSTORE any any)
LJFOLDX(lj_opt_dse_fstore) LJFOLDX(lj_opt_dse_fstore)
LJFOLD(XSTORE any any)
LJFOLDX(lj_opt_dse_xstore)
LJFOLD(NEWREF any any) /* Treated like a store. */ LJFOLD(NEWREF any any) /* Treated like a store. */
LJFOLD(CALLS any any) LJFOLD(CALLS any any)
LJFOLD(CALLL any any) /* Safeguard fallback. */ LJFOLD(CALLL any any) /* Safeguard fallback. */

View File

@ -523,12 +523,52 @@ doemit:
return EMITFOLD; /* Otherwise we have a conflict or simply no match. */ return EMITFOLD; /* Otherwise we have a conflict or simply no match. */
} }
/* -- XLOAD forwarding ---------------------------------------------------- */ /* -- XLOAD forwarding and XSTORE elimination ----------------------------- */
/* NYI: Alias analysis for XLOAD/XSTORE. */ /* Alias analysis for XLOAD/XSTORE. */
static AliasRet aa_xref(jit_State *J, IRIns *refa, IRIns *refb) static AliasRet aa_xref(jit_State *J, IRIns *refa, IRIns *refb)
{ {
UNUSED(J); UNUSED(refa); UNUSED(refb); ptrdiff_t ofsa = 0, ofsb = 0;
IRIns *basea = refa, *baseb = refb;
if (refa == refb)
return ALIAS_MUST; /* Shortcut for same refs. */
/* This implements (very) strict aliasing rules.
** Different types do NOT alias, except for differences in signedness.
** NYI: this also prevents type punning through unions.
*/
if (!(irt_sametype(refa->t, refb->t) ||
(irt_typerange(refa->t, IRT_I8, IRT_INT) &&
((refa->t.irt - IRT_I8) ^ (refb->t.irt - IRT_I8)) == 1)))
return ALIAS_NO;
/* Offset-based disambiguation. */
if (refa->o == IR_ADD && irref_isk(refa->op2)) {
IRIns *irk = IR(refa->op2);
basea = IR(refa->op1);
ofsa = (LJ_64 && irk->o == IR_KINT64) ? (ptrdiff_t)ir_k64(irk)->u64 :
(ptrdiff_t)irk->i;
if (basea == refb && ofsa != 0)
return ALIAS_NO; /* base+-ofs vs. base. */
}
if (refb->o == IR_ADD && irref_isk(refb->op2)) {
IRIns *irk = IR(refb->op2);
baseb = IR(refb->op1);
ofsb = (LJ_64 && irk->o == IR_KINT64) ? (ptrdiff_t)ir_k64(irk)->u64 :
(ptrdiff_t)irk->i;
if (refa == baseb && ofsb != 0)
return ALIAS_NO; /* base vs. base+-ofs. */
}
if (basea == baseb) {
/* This assumes strictly-typed, non-overlapping accesses. */
if (ofsa != ofsb)
return ALIAS_NO; /* base+-o1 vs. base+-o2 and o1 != o2. */
/* Unsigned vs. signed access to the same address.
** Really ALIAS_MUST, but store forwarding would lose the type.
** This is rare, so return ALIAS_MAY for now.
*/
return ALIAS_MAY;
}
/* NYI: structural disambiguation. */
/* NYI: disambiguate new allocations. */
return ALIAS_MAY; return ALIAS_MAY;
} }
@ -567,6 +607,49 @@ cselim:
return lj_ir_emit(J); return lj_ir_emit(J);
} }
/* XSTORE elimination. */
TRef LJ_FASTCALL lj_opt_dse_xstore(jit_State *J)
{
IRRef xref = fins->op1;
IRRef val = fins->op2; /* Stored value reference. */
IRIns *xr = IR(xref);
IRRef1 *refp = &J->chain[IR_XSTORE];
IRRef ref = *refp;
while (ref > xref) { /* Search for redundant or conflicting stores. */
IRIns *store = IR(ref);
switch (aa_xref(J, xr, IR(store->op1))) {
case ALIAS_NO:
break; /* Continue searching. */
case ALIAS_MAY:
if (store->op2 != val) /* Conflict if the value is different. */
goto doemit;
break; /* Otherwise continue searching. */
case ALIAS_MUST:
if (store->op2 == val) /* Same value: drop the new store. */
return DROPFOLD;
/* Different value: try to eliminate the redundant store. */
if (ref > J->chain[IR_LOOP]) { /* Quick check to avoid crossing LOOP. */
IRIns *ir;
/* Check for any intervening guards or any XLOADs (no AA performed). */
for (ir = IR(J->cur.nins-1); ir > store; ir--)
if (irt_isguard(ir->t) || ir->o == IR_XLOAD)
goto doemit; /* No elimination possible. */
/* Remove redundant store from chain and replace with NOP. */
*refp = store->prev;
store->o = IR_NOP; /* Unchained NOP -- does anybody care? */
store->t.irt = IRT_NIL;
store->op1 = store->op2 = 0;
store->prev = 0;
/* Now emit the new store instead. */
}
goto doemit;
}
ref = *(refp = &store->prev);
}
doemit:
return EMITFOLD; /* Otherwise we have a conflict or simply no match. */
}
/* -- Forwarding of lj_tab_len -------------------------------------------- */ /* -- Forwarding of lj_tab_len -------------------------------------------- */
/* This is rather simplistic right now, but better than nothing. */ /* This is rather simplistic right now, but better than nothing. */