Addr base2check;
UInt len2check;
HWord expectedhW;
- IRTemp tistart_tmp, tilen_tmp;
+ IRTemp tistart_tmp, tilen_tmp, callresult_tmp, exitguard_tmp;
HWord VEX_REGPARM(2) (*fn_generic)(HWord, HWord);
HWord VEX_REGPARM(1) (*fn_spec)(HWord);
const HChar* nm_generic;
const Int n_extent_slots = sizeof(vge->base) / sizeof(vge->base[0]);
vassert(n_extent_slots == 3);
- vassert(selfcheck_idx + (n_extent_slots - 1) * 5 + 4 < irsb->stmts_used);
+ vassert(selfcheck_idx + (n_extent_slots - 1) * 7 + 6 < irsb->stmts_used);
for (Int i = 0; i < vge->n_used; i++) {
/* Do we need to generate a check for this extent? */
= guest_word_type==Ity_I32 ? IRConst_U32(len2check)
: IRConst_U64(len2check);
- IRStmt** stmt0 = &irsb->stmts[selfcheck_idx + i * 5 + 0];
- IRStmt** stmt1 = &irsb->stmts[selfcheck_idx + i * 5 + 1];
- IRStmt** stmt2 = &irsb->stmts[selfcheck_idx + i * 5 + 2];
- IRStmt** stmt3 = &irsb->stmts[selfcheck_idx + i * 5 + 3];
- IRStmt** stmt4 = &irsb->stmts[selfcheck_idx + i * 5 + 4];
+ IRStmt** stmt0 = &irsb->stmts[selfcheck_idx + i * 7 + 0];
+ IRStmt** stmt1 = &irsb->stmts[selfcheck_idx + i * 7 + 1];
+ IRStmt** stmt2 = &irsb->stmts[selfcheck_idx + i * 7 + 2];
+ IRStmt** stmt3 = &irsb->stmts[selfcheck_idx + i * 7 + 3];
+ IRStmt** stmt4 = &irsb->stmts[selfcheck_idx + i * 7 + 4];
+ IRStmt** stmt5 = &irsb->stmts[selfcheck_idx + i * 7 + 5];
+ IRStmt** stmt6 = &irsb->stmts[selfcheck_idx + i * 7 + 6];
vassert((*stmt0)->tag == Ist_NoOp);
vassert((*stmt1)->tag == Ist_NoOp);
vassert((*stmt2)->tag == Ist_NoOp);
vassert((*stmt3)->tag == Ist_NoOp);
vassert((*stmt4)->tag == Ist_NoOp);
+ vassert((*stmt5)->tag == Ist_NoOp);
+ vassert((*stmt6)->tag == Ist_NoOp);
*stmt0 = IRStmt_WrTmp(tistart_tmp, IRExpr_Const(base2check_IRConst) );
*stmt1 = IRStmt_WrTmp(tilen_tmp, IRExpr_Const(len2check_IRConst) );
}
}
+ /* Generate the call to the relevant function, and the comparison of
+ the result against the expected value. */
IRExpr* callexpr = NULL;
if (fn_spec) {
callexpr = mkIRExprCCall(
);
}
- *stmt4
- = IRStmt_Exit(
- IRExpr_Binop(
- host_word_type==Ity_I64 ? Iop_CmpNE64 : Iop_CmpNE32,
- callexpr,
- host_word_type==Ity_I64
- ? IRExpr_Const(IRConst_U64(expectedhW))
- : IRExpr_Const(IRConst_U32(expectedhW))
- ),
- Ijk_InvalICache,
- /* Where we must restart if there's a failure: at the
- first extent, regardless of which extent the
- failure actually happened in. */
- guest_IP_sbstart_IRConst,
- offB_GUEST_IP
- );
+ callresult_tmp = newIRTemp(irsb->tyenv, host_word_type);
+ *stmt4 = IRStmt_WrTmp(callresult_tmp, callexpr);
+
+ exitguard_tmp = newIRTemp(irsb->tyenv, Ity_I1);
+ *stmt5 = IRStmt_WrTmp(
+ exitguard_tmp,
+ IRExpr_Binop(
+ host_word_type==Ity_I64 ? Iop_CmpNE64 : Iop_CmpNE32,
+ IRExpr_RdTmp(callresult_tmp),
+ host_word_type==Ity_I64
+ ? IRExpr_Const(IRConst_U64(expectedhW))
+ : IRExpr_Const(IRConst_U32(expectedhW))));
+
+ *stmt6 = IRStmt_Exit(
+ IRExpr_RdTmp(exitguard_tmp),
+ Ijk_InvalICache,
+ /* Where we must restart if there's a failure: at the
+ first extent, regardless of which extent the failure
+ actually happened in. */
+ guest_IP_sbstart_IRConst,
+ offB_GUEST_IP
+ );
} /* for (i = 0; i < vge->n_used; i++) */
for (Int i = vge->n_used;
i < sizeof(vge->base) / sizeof(vge->base[0]); i++) {
- IRStmt* stmt0 = irsb->stmts[selfcheck_idx + i * 5 + 0];
- IRStmt* stmt1 = irsb->stmts[selfcheck_idx + i * 5 + 1];
- IRStmt* stmt2 = irsb->stmts[selfcheck_idx + i * 5 + 2];
- IRStmt* stmt3 = irsb->stmts[selfcheck_idx + i * 5 + 3];
- IRStmt* stmt4 = irsb->stmts[selfcheck_idx + i * 5 + 4];
+ IRStmt* stmt0 = irsb->stmts[selfcheck_idx + i * 7 + 0];
+ IRStmt* stmt1 = irsb->stmts[selfcheck_idx + i * 7 + 1];
+ IRStmt* stmt2 = irsb->stmts[selfcheck_idx + i * 7 + 2];
+ IRStmt* stmt3 = irsb->stmts[selfcheck_idx + i * 7 + 3];
+ IRStmt* stmt4 = irsb->stmts[selfcheck_idx + i * 7 + 4];
+ IRStmt* stmt5 = irsb->stmts[selfcheck_idx + i * 7 + 5];
+ IRStmt* stmt6 = irsb->stmts[selfcheck_idx + i * 7 + 6];
vassert(stmt0->tag == Ist_NoOp);
vassert(stmt1->tag == Ist_NoOp);
vassert(stmt2->tag == Ist_NoOp);
vassert(stmt3->tag == Ist_NoOp);
vassert(stmt4->tag == Ist_NoOp);
+ vassert(stmt5->tag == Ist_NoOp);
+ vassert(stmt6->tag == Ist_NoOp);
}
}
}
/* And a new IR superblock to dump the result into. */
IRSB* irsb = emptyIRSB();
- /* Leave 15 spaces in which to put the check statements for a self
- checking translation (up to 3 extents, and 5 stmts required for
+ /* Leave 21 spaces in which to put the check statements for a self
+ checking translation (up to 3 extents, and 7 stmts required for
each). We won't know until later the extents and checksums of
the areas, if any, that need to be checked. */
IRStmt* nop = IRStmt_NoOp();
Int selfcheck_idx = irsb->stmts_used;
- for (Int i = 0; i < 3 * 5; i++)
+ for (Int i = 0; i < 3 * 7; i++)
addStmtToIRSB( irsb, nop );
/* If the caller supplied a function to add its own preamble, use
/* The callback has completed the IR block without any guest
insns being disassembled into it, so just return it at
this point, even if a self-check was requested - as there
- is nothing to self-check. The 15 self-check no-ops will
+ is nothing to self-check. The 21 self-check no-ops will
still be in place, but they are harmless. */
vge->n_used = 1;
vge->base[0] = guest_IP_sbstart;
/* We're almost done. The only thing that might need attending to is that
a self-checking preamble may need to be created. If so it gets placed
- in the 15 slots reserved above. */
+ in the 21 slots reserved above. */
create_self_checks_as_needed(
irsb, n_sc_extents, pxControl, callback_opaque, needs_self_check,
vge, abiinfo_both, guest_word_type, selfcheck_idx, offB_GUEST_CMSTART,
return env[(Int)e->Iex.RdTmp.tmp];
}
-static IRExpr* fold_Expr ( IRExpr** env, IRExpr* e )
+__attribute__((noinline))
+static IRExpr* fold_Expr_WRK ( IRExpr** env, IRExpr* e )
{
Int shift;
IRExpr* e2 = e; /* e2 is the result of folding e, if possible */
&& !debug_only_hack_sameIRExprs_might_assert(e->Iex.Binop.arg1,
e->Iex.Binop.arg2)
&& sameIRExprs(env, e->Iex.Binop.arg1, e->Iex.Binop.arg2)) {
- vex_printf("vex iropt: fold_Expr: no ident rule for: ");
+ vex_printf("vex iropt: fold_Expr_WRK: no ident rule for: ");
ppIRExpr(e);
vex_printf("\n");
}
vpanic("fold_Expr: no rule for the above");
# else
if (vex_control.iropt_verbosity > 0) {
- vex_printf("vex iropt: fold_Expr: no const rule for: ");
+ vex_printf("vex iropt: fold_Expr_WRK: no const rule for: ");
ppIRExpr(e);
vex_printf("\n");
}
# endif
}
+/* Fold |e| as much as possible, given the bindings in |env|. If no folding is
+ possible, just return |e|. Also, if |env| is NULL, don't even try to
+ fold; just return |e| directly. */
+inline
+static IRExpr* fold_Expr ( IRExpr** env, IRExpr* e )
+{
+ return env == NULL ? e : fold_Expr_WRK(env, e);
+}
/* Apply the subst to a simple 1-level expression -- guaranteed to be
1-level due to previous flattening pass. */
}
-/* Apply the subst to stmt, then fold the result as much as possible.
- Much simplified due to stmt being previously flattened. As a
- result of this, the stmt may wind up being turned into a no-op.
+/* Apply the subst to stmt, then, if |doFolding| is |True|, fold the result as
+ much as possible. Much simplified due to stmt being previously flattened.
+ As a result of this, the stmt may wind up being turned into a no-op.
*/
-static IRStmt* subst_and_fold_Stmt ( IRExpr** env, IRStmt* st )
+static IRStmt* subst_and_maybe_fold_Stmt ( Bool doFolding,
+ IRExpr** env, IRStmt* st )
{
# if 0
- vex_printf("\nsubst and fold stmt\n");
+ vex_printf("\nsubst and maybe fold stmt\n");
ppIRStmt(st);
vex_printf("\n");
# endif
+ IRExpr** s_env = env;
+ IRExpr** f_env = doFolding ? env : NULL;
+
switch (st->tag) {
case Ist_AbiHint:
vassert(isIRAtom(st->Ist.AbiHint.base));
vassert(isIRAtom(st->Ist.AbiHint.nia));
return IRStmt_AbiHint(
- fold_Expr(env, subst_Expr(env, st->Ist.AbiHint.base)),
+ fold_Expr(f_env, subst_Expr(s_env, st->Ist.AbiHint.base)),
st->Ist.AbiHint.len,
- fold_Expr(env, subst_Expr(env, st->Ist.AbiHint.nia))
+ fold_Expr(f_env, subst_Expr(s_env, st->Ist.AbiHint.nia))
);
case Ist_Put:
vassert(isIRAtom(st->Ist.Put.data));
return IRStmt_Put(
st->Ist.Put.offset,
- fold_Expr(env, subst_Expr(env, st->Ist.Put.data))
+ fold_Expr(f_env, subst_Expr(s_env, st->Ist.Put.data))
);
case Ist_PutI: {
vassert(isIRAtom(puti->ix));
vassert(isIRAtom(puti->data));
puti2 = mkIRPutI(puti->descr,
- fold_Expr(env, subst_Expr(env, puti->ix)),
+ fold_Expr(f_env, subst_Expr(s_env, puti->ix)),
puti->bias,
- fold_Expr(env, subst_Expr(env, puti->data)));
+ fold_Expr(f_env, subst_Expr(s_env, puti->data)));
return IRStmt_PutI(puti2);
}
allowed to be more than just a constant or a tmp. */
return IRStmt_WrTmp(
st->Ist.WrTmp.tmp,
- fold_Expr(env, subst_Expr(env, st->Ist.WrTmp.data))
+ fold_Expr(f_env, subst_Expr(s_env, st->Ist.WrTmp.data))
);
case Ist_Store:
vassert(isIRAtom(st->Ist.Store.data));
return IRStmt_Store(
st->Ist.Store.end,
- fold_Expr(env, subst_Expr(env, st->Ist.Store.addr)),
- fold_Expr(env, subst_Expr(env, st->Ist.Store.data))
+ fold_Expr(f_env, subst_Expr(s_env, st->Ist.Store.addr)),
+ fold_Expr(f_env, subst_Expr(s_env, st->Ist.Store.data))
);
case Ist_StoreG: {
vassert(isIRAtom(sg->addr));
vassert(isIRAtom(sg->data));
vassert(isIRAtom(sg->guard));
- IRExpr* faddr = fold_Expr(env, subst_Expr(env, sg->addr));
- IRExpr* fdata = fold_Expr(env, subst_Expr(env, sg->data));
- IRExpr* fguard = fold_Expr(env, subst_Expr(env, sg->guard));
+ IRExpr* faddr = fold_Expr(f_env, subst_Expr(s_env, sg->addr));
+ IRExpr* fdata = fold_Expr(f_env, subst_Expr(s_env, sg->data));
+ IRExpr* fguard = fold_Expr(f_env, subst_Expr(s_env, sg->guard));
if (fguard->tag == Iex_Const) {
/* The condition on this store has folded down to a constant. */
vassert(fguard->Iex.Const.con->tag == Ico_U1);
vassert(isIRAtom(lg->addr));
vassert(isIRAtom(lg->alt));
vassert(isIRAtom(lg->guard));
- IRExpr* faddr = fold_Expr(env, subst_Expr(env, lg->addr));
- IRExpr* falt = fold_Expr(env, subst_Expr(env, lg->alt));
- IRExpr* fguard = fold_Expr(env, subst_Expr(env, lg->guard));
+ IRExpr* faddr = fold_Expr(f_env, subst_Expr(s_env, lg->addr));
+ IRExpr* falt = fold_Expr(f_env, subst_Expr(s_env, lg->alt));
+ IRExpr* fguard = fold_Expr(f_env, subst_Expr(s_env, lg->guard));
if (fguard->tag == Iex_Const) {
/* The condition on this load has folded down to a constant. */
vassert(fguard->Iex.Const.con->tag == Ico_U1);
vassert(isIRAtom(cas->dataLo));
cas2 = mkIRCAS(
cas->oldHi, cas->oldLo, cas->end,
- fold_Expr(env, subst_Expr(env, cas->addr)),
- cas->expdHi ? fold_Expr(env, subst_Expr(env, cas->expdHi))
+ fold_Expr(f_env, subst_Expr(s_env, cas->addr)),
+ cas->expdHi ? fold_Expr(f_env,
+ subst_Expr(s_env, cas->expdHi))
: NULL,
- fold_Expr(env, subst_Expr(env, cas->expdLo)),
- cas->dataHi ? fold_Expr(env, subst_Expr(env, cas->dataHi))
+ fold_Expr(f_env, subst_Expr(s_env, cas->expdLo)),
+ cas->dataHi ? fold_Expr(f_env,
+ subst_Expr(s_env, cas->dataHi))
: NULL,
- fold_Expr(env, subst_Expr(env, cas->dataLo))
+ fold_Expr(f_env, subst_Expr(s_env, cas->dataLo))
);
return IRStmt_CAS(cas2);
}
return IRStmt_LLSC(
st->Ist.LLSC.end,
st->Ist.LLSC.result,
- fold_Expr(env, subst_Expr(env, st->Ist.LLSC.addr)),
+ fold_Expr(f_env, subst_Expr(s_env, st->Ist.LLSC.addr)),
st->Ist.LLSC.storedata
- ? fold_Expr(env, subst_Expr(env, st->Ist.LLSC.storedata))
+ ? fold_Expr(f_env,
+ subst_Expr(s_env, st->Ist.LLSC.storedata))
: NULL
);
d2->args = shallowCopyIRExprVec(d2->args);
if (d2->mFx != Ifx_None) {
vassert(isIRAtom(d2->mAddr));
- d2->mAddr = fold_Expr(env, subst_Expr(env, d2->mAddr));
+ d2->mAddr = fold_Expr(f_env, subst_Expr(s_env, d2->mAddr));
}
vassert(isIRAtom(d2->guard));
- d2->guard = fold_Expr(env, subst_Expr(env, d2->guard));
+ d2->guard = fold_Expr(f_env, subst_Expr(s_env, d2->guard));
for (i = 0; d2->args[i]; i++) {
IRExpr* arg = d2->args[i];
if (LIKELY(!is_IRExpr_VECRET_or_GSPTR(arg))) {
vassert(isIRAtom(arg));
- d2->args[i] = fold_Expr(env, subst_Expr(env, arg));
+ d2->args[i] = fold_Expr(f_env, subst_Expr(s_env, arg));
}
}
return IRStmt_Dirty(d2);
case Ist_Exit: {
IRExpr* fcond;
vassert(isIRAtom(st->Ist.Exit.guard));
- fcond = fold_Expr(env, subst_Expr(env, st->Ist.Exit.guard));
+ fcond = fold_Expr(f_env, subst_Expr(s_env, st->Ist.Exit.guard));
if (fcond->tag == Iex_Const) {
/* Interesting. The condition on this exit has folded down to
a constant. */
}
-static IRSB* cprop_BB_wrk ( IRSB* in, Bool mustRetainNoOps )
+__attribute__((noinline))
+static IRSB* cprop_BB_WRK ( IRSB* in, Bool mustRetainNoOps, Bool doFolding )
{
Int i;
IRSB* out;
/* perhaps st2 is already a no-op? */
if (st2->tag == Ist_NoOp && !mustRetainNoOps) continue;
- st2 = subst_and_fold_Stmt( env, st2 );
+ st2 = subst_and_maybe_fold_Stmt( doFolding, env, st2 );
/* Deal with some post-folding special cases. */
switch (st2->tag) {
IRExpr* guard = lg->guard;
if (guard->tag == Iex_Const) {
/* The guard has folded to a constant, and that
- constant must be 1:I1, since subst_and_fold_Stmt
+ constant must be 1:I1, since subst_and_maybe_fold_Stmt
folds out the case 0:I1 by itself. */
vassert(guard->Iex.Const.con->tag == Ico_U1);
vassert(guard->Iex.Const.con->Ico.U1 == True);
IRSB* cprop_BB ( IRSB* in ) {
- return cprop_BB_wrk(in, /*mustRetainNoOps=*/False);
+ return cprop_BB_WRK(in, /*mustRetainNoOps=*/False, /*doFolding=*/True);
}
static Int n_expensive = 0;
Bool hasGetIorPutI, hasVorFtemps;
- IRSB *bb, *bb2;
n_total++;
- /* First flatten the block out, since all other
- phases assume flat code. */
- // FIXME this is no longer necessary, since minimal_iropt should have
- // flattened it
- bb = flatten_BB ( bb0 );
-
- if (iropt_verbose) {
- vex_printf("\n========= FLAT\n\n" );
- ppIRSB(bb);
- }
+ /* Flatness: this function assumes that the incoming block is already flat.
+ That's because all blocks that arrive here should already have been
+ processed by do_minimal_initial_iropt_BB. And that will have flattened
+ them out. */
+ // FIXME Remove this assertion once the 'grail' machinery seems stable
+ vassert(isFlatIRSB(bb0));
/* If at level 0, stop now. */
- if (vex_control.iropt_level <= 0) return bb;
+ if (vex_control.iropt_level <= 0) return bb0;
/* Now do a preliminary cleanup pass, and figure out if we also
need to do 'expensive' optimisations. Expensive optimisations
If needed, do expensive transformations and then another cheap
cleanup pass. */
- bb = cheap_transformations( bb, specHelper, preciseMemExnsFn, pxControl );
+ IRSB* bb = cheap_transformations( bb0, specHelper,
+ preciseMemExnsFn, pxControl );
if (guest_arch == VexArchARM) {
/* Translating Thumb2 code produces a lot of chaff. We have to
/* Now have a go at unrolling simple (single-BB) loops. If
successful, clean up the results as much as possible. */
- bb2 = maybe_loop_unroll_BB( bb, guest_addr );
+ IRSB* bb2 = maybe_loop_unroll_BB( bb, guest_addr );
if (bb2) {
bb = cheap_transformations( bb2, specHelper,
preciseMemExnsFn, pxControl );
return bb;
}
-//static Bool alwaysPrecise ( Int minoff, Int maxoff,
-// VexRegisterUpdates pxControl )
-//{
-// return True;
-//}
-
-// FIXME make this as cheap as possible
-IRSB* do_minimal_initial_iropt_BB(
- IRSB* bb0
- //IRExpr* (*specHelper) (const HChar*, IRExpr**, IRStmt**, Int),
- //Bool (*preciseMemExnsFn)(Int,Int,VexRegisterUpdates),
- //VexRegisterUpdates pxControl,
- //Addr guest_addr,
- //VexArch guest_arch
- )
-{
+IRSB* do_minimal_initial_iropt_BB(IRSB* bb0) {
/* First flatten the block out, since all other phases assume flat code. */
IRSB* bb = flatten_BB ( bb0 );
ppIRSB(bb);
}
+ // Remove redundant GETs
redundant_get_removal_BB ( bb );
- bb = cprop_BB_wrk ( bb, /*mustRetainNoOps=*/True ); // FIXME
- // This is overkill. We only really want constant prop, not folding
+
+ // Do minimal constant prop: copy prop and constant prop only. No folding.
+ bb = cprop_BB_WRK ( bb, /*mustRetainNoOps=*/True,
+ /*doFolding=*/False );
// Minor tidying of the block end, to remove a redundant Put of the IP right
// at the end: