Add array bounds check elimination (-Oabc, on by default).

This commit is contained in:
Mike Pall
2010-03-15 17:02:53 +01:00
parent 24402ede04
commit c4727220e8
5 changed files with 100 additions and 19 deletions

View File

@@ -806,6 +806,44 @@ static void rec_mm_comp(jit_State *J, RecordIndex *ix, int op)
/* -- Indexed access ------------------------------------------------------ */
/* Record bounds-check. */
static void rec_idx_abc(jit_State *J, TRef asizeref, TRef ikey, uint32_t asize)
{
/* Try to emit invariant bounds checks. */
if ((J->flags & (JIT_F_OPT_LOOP|JIT_F_OPT_ABC)) ==
(JIT_F_OPT_LOOP|JIT_F_OPT_ABC)) {
IRRef ref = tref_ref(ikey);
IRIns *ir = IR(ref);
int32_t ofs = 0;
IRRef ofsref = 0;
/* Handle constant offsets. */
if (ir->o == IR_ADD && irref_isk(ir->op2)) {
ofsref = ir->op2;
ofs = IR(ofsref)->i;
ref = ir->op1;
ir = IR(ref);
}
/* Got scalar evolution analysis results for this reference? */
if (ref == J->scev.idx) {
int32_t stop;
lua_assert(irt_isint(J->scev.t) && ir->o == IR_SLOAD);
stop = lj_num2int(numV(&(J->L->base - J->baseslot)[ir->op1 + FORL_STOP]));
/* Runtime value for stop of loop is within bounds? */
if ((int64_t)stop + ofs < (int64_t)asize) {
/* Emit invariant bounds check for stop. */
emitir(IRTG(IR_ABC, IRT_PTR), asizeref, ofs == 0 ? J->scev.stop :
emitir(IRTI(IR_ADD), J->scev.stop, ofsref));
/* Emit invariant bounds check for start, if not const or negative. */
if (!(J->scev.dir && J->scev.start &&
(int64_t)IR(J->scev.start)->i + ofs >= 0))
emitir(IRTG(IR_ABC, IRT_PTR), asizeref, ikey);
return;
}
}
}
emitir(IRTGI(IR_ABC), asizeref, ikey); /* Emit regular bounds check. */
}
/* Record indexed key lookup. */
static TRef rec_idx_key(jit_State *J, RecordIndex *ix)
{
@@ -827,7 +865,7 @@ static TRef rec_idx_key(jit_State *J, RecordIndex *ix)
asizeref = emitir(IRTI(IR_FLOAD), ix->tab, IRFL_TAB_ASIZE);
if ((MSize)k < t->asize) { /* Currently an array key? */
TRef arrayref;
emitir(IRTGI(IR_ABC), asizeref, ikey); /* Bounds check. */
rec_idx_abc(J, asizeref, ikey, t->asize);
arrayref = emitir(IRT(IR_FLOAD, IRT_PTR), ix->tab, IRFL_TAB_ARRAY);
return emitir(IRT(IR_AREF, IRT_PTR), arrayref, ikey);
} else { /* Currently not in array (may be an array extension)? */