Fix alias analysis for table.len vs. table.clear.

This commit is contained in:
Mike Pall 2014-04-01 01:55:12 +02:00
parent caefd06871
commit 423f10fb40

View File

@ -309,6 +309,20 @@ int LJ_FASTCALL lj_opt_fwd_href_nokey(jit_State *J)
return 1; /* No conflict. Can fold to niltv. */ return 1; /* No conflict. Can fold to niltv. */
} }
/* Check whether there's no aliasing table.clear. */
static int fwd_aa_tab_clear(jit_State *J, IRRef lim, IRRef ta)
{
IRRef ref = J->chain[IR_CALLS];
while (ref > lim) {
IRIns *calls = IR(ref);
if (calls->op2 == IRCALL_lj_tab_clear &&
(ta == calls->op1 || aa_table(J, ta, calls->op1) != ALIAS_NO))
return 0; /* Conflict. */
ref = calls->prev;
}
return 1; /* No conflict. Can safely FOLD/CSE. */
}
/* Check whether there's no aliasing NEWREF/table.clear for the left operand. */ /* Check whether there's no aliasing NEWREF/table.clear for the left operand. */
int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim) int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim)
{ {
@ -320,15 +334,7 @@ int LJ_FASTCALL lj_opt_fwd_tptr(jit_State *J, IRRef lim)
return 0; /* Conflict. */ return 0; /* Conflict. */
ref = newref->prev; ref = newref->prev;
} }
ref = J->chain[IR_CALLS]; return fwd_aa_tab_clear(J, lim, ta);
while (ref > lim) {
IRIns *calls = IR(ref);
if (calls->op2 == IRCALL_lj_tab_clear &&
(ta == calls->op1 || aa_table(J, ta, calls->op1) != ALIAS_NO))
return 0; /* Conflict. */
ref = calls->prev;
}
return 1; /* No conflict. Can safely FOLD/CSE. */
} }
/* ASTORE/HSTORE elimination. */ /* ASTORE/HSTORE elimination. */
@ -862,6 +868,10 @@ TRef LJ_FASTCALL lj_opt_fwd_tab_len(jit_State *J)
ref = store->prev; ref = store->prev;
} }
/* Search for aliasing table.clear. */
if (!fwd_aa_tab_clear(J, lim, tab))
return lj_ir_emit(J);
/* Try to find a matching load. Below the conflicting store, if any. */ /* Try to find a matching load. Below the conflicting store, if any. */
return lj_opt_cselim(J, lim); return lj_opt_cselim(J, lim);
} }