case Ico_U16: vex_printf( "0x%x:I16", (UInt)(con->Ico.U16)); break;
case Ico_U32: vex_printf( "0x%x:I32", (UInt)(con->Ico.U32)); break;
case Ico_U64: vex_printf( "0x%llx:I64", (ULong)(con->Ico.U64)); break;
- case Ico_F64: vex_printf( "F64{0x%llx}", *(ULong*)(&con->Ico.F64)); break;
+ case Ico_F64: vex_printf( "F64{0x%llx}", *(ULong*)(&con->Ico.F64));
+ break;
case Ico_F64i: vex_printf( "F64i{0x%llx}", con->Ico.F64i); break;
default: vpanic("ppIRConst");
}
return s;
}
-/* Constructors -- IRBB (sort of) */
+
+/* Constructors -- IRTypeEnv */
+
+IRTypeEnv* emptyIRTypeEnv ( void )
+{
+ IRTypeEnv* env = LibVEX_Alloc(sizeof(IRTypeEnv));
+ env->types = LibVEX_Alloc(8 * sizeof(IRType));
+ env->types_size = 8;
+ env->types_used = 0;
+ return env;
+}
+
+
+/* Constructors -- IRBB */
IRBB* emptyIRBB ( void )
{
return bb;
}
-void addStmtToIRBB ( IRBB* bb, IRStmt* st )
+
+/*---------------------------------------------------------------*/
+/*--- (Deep) copy constructors. These make complete copies ---*/
+/*--- the original, which can be modified without affecting ---*/
+/*--- the original. ---*/
+/*---------------------------------------------------------------*/
+
+/* Copying IR Expr vectors (for call args). */
+
+/* Shallow copy of an IRExpr vector */
+
+IRExpr** sopyIRExprVec ( IRExpr** vec )
{
- Int i;
- if (bb->stmts_used == bb->stmts_size) {
- IRStmt** stmts2 = LibVEX_Alloc(2 * bb->stmts_size * sizeof(IRStmt*));
- for (i = 0; i < bb->stmts_size; i++)
- stmts2[i] = bb->stmts[i];
- bb->stmts = stmts2;
- bb->stmts_size *= 2;
+ Int i;
+ IRExpr** newvec;
+ for (i = 0; vec[i]; i++)
+ ;
+ newvec = LibVEX_Alloc((i+1)*sizeof(IRExpr*));
+ for (i = 0; vec[i]; i++)
+ newvec[i] = vec[i];
+ newvec[i] = NULL;
+ return newvec;
+}
+
+/* Deep copy of an IRExpr vector */
+
+IRExpr** dopyIRExprVec ( IRExpr** vec )
+{
+ Int i;
+ IRExpr** newvec = sopyIRExprVec( vec );
+ for (i = 0; newvec[i]; i++)
+ newvec[i] = dopyIRExpr(newvec[i]);
+ return newvec;
+}
+
+/* Deep copy constructors for all heap-allocated IR types follow. */
+
+IRConst* dopyIRConst ( IRConst* c )
+{
+ switch (c->tag) {
+ case Ico_Bit: return IRConst_Bit(c->Ico.Bit);
+ case Ico_U8: return IRConst_U8(c->Ico.U8);
+ case Ico_U16: return IRConst_U16(c->Ico.U16);
+ case Ico_U32: return IRConst_U32(c->Ico.U32);
+ case Ico_U64: return IRConst_U64(c->Ico.U64);
+ case Ico_F64: return IRConst_F64(c->Ico.F64);
+ case Ico_F64i: return IRConst_F64i(c->Ico.F64i);
+ default: vpanic("dopyIRConst");
}
- vassert(bb->stmts_used < bb->stmts_size);
- bb->stmts[bb->stmts_used] = st;
- bb->stmts_used++;
+}
+
+IRArray* dopyIRArray ( IRArray* d )
+{
+ return mkIRArray(d->base, d->elemTy, d->nElems);
+}
+
+IRExpr* dopyIRExpr ( IRExpr* e )
+{
+ switch (e->tag) {
+ case Iex_Get:
+ return IRExpr_Get(e->Iex.Get.offset, e->Iex.Get.ty);
+ case Iex_GetI:
+ return IRExpr_GetI(dopyIRArray(e->Iex.GetI.descr),
+ dopyIRExpr(e->Iex.GetI.off),
+ e->Iex.GetI.bias);
+ case Iex_Tmp:
+ return IRExpr_Tmp(e->Iex.Tmp.tmp);
+ case Iex_Binop:
+ return IRExpr_Binop(e->Iex.Binop.op,
+ dopyIRExpr(e->Iex.Binop.arg1),
+ dopyIRExpr(e->Iex.Binop.arg2));
+ case Iex_Unop:
+ return IRExpr_Unop(e->Iex.Unop.op,
+ dopyIRExpr(e->Iex.Unop.arg));
+ case Iex_LDle:
+ return IRExpr_LDle(e->Iex.LDle.ty,
+ dopyIRExpr(e->Iex.LDle.addr));
+ case Iex_Const:
+ return IRExpr_Const(dopyIRConst(e->Iex.Const.con));
+ case Iex_CCall:
+ return IRExpr_CCall(e->Iex.CCall.name,
+ e->Iex.CCall.retty,
+ dopyIRExprVec(e->Iex.CCall.args));
+
+ case Iex_Mux0X:
+ return IRExpr_Mux0X(dopyIRExpr(e->Iex.Mux0X.cond),
+ dopyIRExpr(e->Iex.Mux0X.expr0),
+ dopyIRExpr(e->Iex.Mux0X.exprX));
+ default:
+ vpanic("dopyIRExpr");
+ }
+}
+
+IRDirty* dopyIRDirty ( IRDirty* d )
+{
+ Int i;
+ IRDirty* d2 = emptyIRDirty();
+ d2->name = d->name;
+ d2->args = dopyIRExprVec(d->args);
+ d2->tmp = d->tmp;
+ d2->mFx = d->mFx;
+ d2->mAddr = d->mAddr==NULL ? NULL : dopyIRExpr(d->mAddr);
+ d2->mSize = d->mSize;
+ d2->nFxState = d->nFxState;
+ for (i = 0; i < d2->nFxState; i++)
+ d2->fxState[i] = d->fxState[i];
+ return d2;
+}
+
+IRStmt* dopyIRStmt ( IRStmt* s )
+{
+ switch (s->tag) {
+ case Ist_Put:
+ return IRStmt_Put(s->Ist.Put.offset,
+ dopyIRExpr(s->Ist.Put.data));
+ case Ist_PutI:
+ return IRStmt_PutI(dopyIRArray(s->Ist.PutI.descr),
+ dopyIRExpr(s->Ist.PutI.off),
+ s->Ist.PutI.bias,
+ dopyIRExpr(s->Ist.PutI.data));
+ case Ist_Tmp:
+ return IRStmt_Tmp(s->Ist.Tmp.tmp,
+ dopyIRExpr(s->Ist.Tmp.data));
+ case Ist_STle:
+ return IRStmt_STle(dopyIRExpr(s->Ist.STle.addr),
+ dopyIRExpr(s->Ist.STle.data));
+ case Ist_Dirty:
+ return IRStmt_Dirty(dopyIRDirty(s->Ist.Dirty.details));
+ case Ist_Exit:
+ return IRStmt_Exit(dopyIRExpr(s->Ist.Exit.cond),
+ dopyIRConst(s->Ist.Exit.dst));
+ default:
+ vpanic("dopyIRStmt");
+ }
+}
+
+IRTypeEnv* dopyIRTypeEnv ( IRTypeEnv* src )
+{
+ Int i;
+ IRTypeEnv* dst = LibVEX_Alloc(sizeof(IRTypeEnv));
+ dst->types_size = src->types_size;
+ dst->types_used = src->types_used;
+ dst->types = LibVEX_Alloc(dst->types_size * sizeof(IRType));
+ for (i = 0; i < src->types_used; i++)
+ dst->types[i] = src->types[i];
+ return dst;
+}
+
+IRBB* dopyIRBB ( IRBB* bb )
+{
+ Int i;
+ IRStmt** sts2;
+ IRBB* bb2 = emptyIRBB();
+ bb2->tyenv = dopyIRTypeEnv(bb->tyenv);
+ bb2->stmts_used = bb2->stmts_size = bb->stmts_used;
+ sts2 = LibVEX_Alloc(bb2->stmts_used * sizeof(IRStmt*));
+ for (i = 0; i < bb2->stmts_used; i++)
+ sts2[i] = bb->stmts[i]==NULL ? NULL : dopyIRStmt(bb->stmts[i]);
+ bb2->stmts = sts2;
+ bb2->next = dopyIRExpr(bb->next);
+ bb2->jumpkind = bb->jumpkind;
+ return bb2;
}
/*---------------------------------------------------------------*/
-/*--- Helper functions for the IR -- IR Type Environments ---*/
+/*--- Helper functions for the IR -- IR Basic Blocks ---*/
/*---------------------------------------------------------------*/
-/* Make a new, empty IRTypeEnv. */
-
-IRTypeEnv* emptyIRTypeEnv ( void )
+void addStmtToIRBB ( IRBB* bb, IRStmt* st )
{
- IRTypeEnv* env = LibVEX_Alloc(sizeof(IRTypeEnv));
- env->types = LibVEX_Alloc(8 * sizeof(IRType));
- env->types_size = 8;
- env->types_used = 0;
- return env;
+ Int i;
+ if (bb->stmts_used == bb->stmts_size) {
+ IRStmt** stmts2 = LibVEX_Alloc(2 * bb->stmts_size * sizeof(IRStmt*));
+ for (i = 0; i < bb->stmts_size; i++)
+ stmts2[i] = bb->stmts[i];
+ bb->stmts = stmts2;
+ bb->stmts_size *= 2;
+ }
+ vassert(bb->stmts_used < bb->stmts_size);
+ bb->stmts[bb->stmts_used] = st;
+ bb->stmts_used++;
}
-/* Make an exact copy of the given IRTypeEnv, usually so we can
- add new stuff to the copy without messing up the original. */
-IRTypeEnv* copyIRTypeEnv ( IRTypeEnv* src )
-{
- Int i;
- IRTypeEnv* dst = LibVEX_Alloc(sizeof(IRTypeEnv));
- dst->types_size = src->types_size;
- dst->types_used = src->types_used;
- dst->types = LibVEX_Alloc(dst->types_size * sizeof(IRType));
- for (i = 0; i < src->types_used; i++)
- dst->types[i] = src->types[i];
- return dst;
-}
+/*---------------------------------------------------------------*/
+/*--- Helper functions for the IR -- IR Type Environments ---*/
+/*---------------------------------------------------------------*/
/* Allocate a new IRTemp, given its type. */
case Iex_Tmp:
return typeOfIRTemp(tyenv, e->Iex.Tmp.tmp);
case Iex_Const:
- return typeOfIRConst(e->Iex.Const.con);
+ return typeOfIRConst(e->Iex.Const.con);
case Iex_Binop:
typeOfPrimop(e->Iex.Binop.op, &t_dst, &t_arg1, &t_arg2);
return t_dst;
sanityCheckFail(bb,stmt,
"Iex.Binop: arg tys don't match op tys\n"
"... additional details precede BB printout\n");
- }
+ }
break;
}
case Iex_Unop:
Int* def_counts = LibVEX_Alloc(n_temps * sizeof(Int));
vassert(guest_word_size == Ity_I32
- || guest_word_size == Ity_I64);
+ || guest_word_size == Ity_I64);
if (bb->stmts_used < 0 || bb->stmts_size < 8
|| bb->stmts_used > bb->stmts_size)
They are not regarded as atoms, and instead lifted off and
bound to temps. This allows them to participate in CSE, which
is important for getting good performance for x86 guest code.
+
+ ToDo:
+
+ make spec_helpers_BB always return flat code
*/
}
-/* Clone the NULL-terminated vector of IRExpr*s attached to a
- CCall. */
-
-static IRExpr** copyIRExprCallArgs ( IRExpr** vec )
-{
- Int i;
- IRExpr** newvec;
- for (i = 0; vec[i]; i++)
- ;
- newvec = LibVEX_Alloc((i+1)*sizeof(IRExpr*));
- for (i = 0; vec[i]; i++)
- newvec[i] = vec[i];
- newvec[i] = NULL;
- return newvec;
-}
-
-
/* Non-critical helper, heuristic for reducing the number of tmp-tmp
copies made by flattening. If in doubt return False. */
static Bool isFlat ( IRExpr* e )
{
- if (e->tag == Iex_Get) return True;
+ if (e->tag == Iex_Get)
+ return True;
if (e->tag == Iex_Binop)
return isAtom(e->Iex.Binop.arg1) && isAtom(e->Iex.Binop.arg2);
if (e->tag == Iex_LDle)
return IRExpr_Tmp(t1);
case Iex_CCall:
- newargs = copyIRExprCallArgs(ex->Iex.CCall.args);
+ newargs = sopyIRExprVec(ex->Iex.CCall.args);
for (i = 0; newargs[i]; i++)
newargs[i] = flatten_Expr(bb, newargs[i]);
t1 = newIRTemp(bb->tyenv, ty);
d = st->Ist.Dirty.details;
d2 = emptyIRDirty();
*d2 = *d;
- d2->args = copyIRExprCallArgs(d2->args);
+ d2->args = sopyIRExprVec(d2->args);
if (d2->mFx != Ifx_None) {
d2->mAddr = flatten_Expr(bb, d2->mAddr);
} else {
Int i;
IRBB* out;
out = emptyIRBB();
- out->tyenv = copyIRTypeEnv( in->tyenv );
+ out->tyenv = dopyIRTypeEnv( in->tyenv );
for (i = 0; i < in->stmts_used; i++)
if (in->stmts[i])
flatten_Stmt( out, in->stmts[i] );
if (ex->tag == Iex_CCall) {
Int i;
- IRExpr** args2 = copyIRExprCallArgs ( ex->Iex.CCall.args );
+ IRExpr** args2 = sopyIRExprVec(ex->Iex.CCall.args);
for (i = 0; args2[i]; i++) {
vassert(isAtom(args2[i]));
args2[i] = subst_Expr(env, args2[i]);
d = st->Ist.Dirty.details;
d2 = emptyIRDirty();
*d2 = *d;
- d2->args = copyIRExprCallArgs(d2->args);
+ d2->args = sopyIRExprVec(d2->args);
if (d2->mFx != Ifx_None) {
vassert(isAtom(d2->mAddr));
d2->mAddr = fold_Expr(subst_Expr(env, d2->mAddr));
IRStmt* st2;
out = emptyIRBB();
- out->tyenv = copyIRTypeEnv( in->tyenv );
+ out->tyenv = dopyIRTypeEnv( in->tyenv );
/* Set up the env with which travels forward. This holds a
substitution, mapping IRTemps to atoms, that is, IRExprs which
Hash64* env = newH64();
for (i = bb->stmts_used-1; i >= 0; i--) {
st = bb->stmts[i];
+ if (!st)
+ continue;
/* Deal with conditional exits. */
if (st->tag == Ist_Exit) {
switch (e->tag) {
case Iex_CCall:
- args2 = copyIRExprCallArgs(e->Iex.CCall.args);
+ args2 = sopyIRExprVec(e->Iex.CCall.args);
for (i = 0; args2[i]; i++)
args2[i] = tbSubst_Expr(env,args2[i]);
return IRExpr_CCall(e->Iex.CCall.name,
/*---------------------------------------------------------------*/
-/*--- iropt main ---*/
+/*--- Loop unrolling ---*/
/*---------------------------------------------------------------*/
-static Bool iropt_verbose = False;
+static void deltaIRExpr ( IRExpr* e, Int delta )
+{
+ Int i;
+ switch (e->tag) {
+ case Iex_Tmp:
+ e->Iex.Tmp.tmp += delta;
+ break;
+ case Iex_Get:
+ case Iex_Const:
+ break;
+ case Iex_GetI:
+ deltaIRExpr(e->Iex.GetI.off, delta);
+ break;
+ case Iex_Binop:
+ deltaIRExpr(e->Iex.Binop.arg1, delta);
+ deltaIRExpr(e->Iex.Binop.arg2, delta);
+ break;
+ case Iex_Unop:
+ deltaIRExpr(e->Iex.Unop.arg, delta);
+ break;
+ case Iex_LDle:
+ deltaIRExpr(e->Iex.LDle.addr, delta);
+ break;
+ case Iex_CCall:
+ for (i = 0; e->Iex.CCall.args[i]; i++)
+ deltaIRExpr(e->Iex.CCall.args[i], delta);
+ break;
+ case Iex_Mux0X:
+ deltaIRExpr(e->Iex.Mux0X.cond, delta);
+ deltaIRExpr(e->Iex.Mux0X.expr0, delta);
+ deltaIRExpr(e->Iex.Mux0X.exprX, delta);
+ break;
+ default: vex_printf("\n"); ppIRExpr(e); vex_printf("\n");
+ vpanic("deltaIRExpr");
+ }
+}
+static void deltaIRStmt ( IRStmt* st, Int delta )
+{
+ switch (st->tag) {
+ case Ist_Put:
+ deltaIRExpr(st->Ist.Put.data, delta);
+ break;
+ case Ist_PutI:
+ deltaIRExpr(st->Ist.PutI.off, delta);
+ deltaIRExpr(st->Ist.PutI.data, delta);
+ break;
+ case Ist_Tmp: st->Ist.Tmp.tmp += delta;
+ deltaIRExpr(st->Ist.Tmp.data, delta);
+ break;
+ case Ist_Exit:
+ deltaIRExpr(st->Ist.Exit.cond, delta);
+ break;
+ case Ist_STle:
+ deltaIRExpr(st->Ist.STle.addr, delta);
+ deltaIRExpr(st->Ist.STle.data, delta);
+ break;
+ default: vex_printf("\n"); ppIRStmt(st); vex_printf("\n");
+ vpanic("deltaIRStmt");
+ }
+}
-/* Rules of the game:
+/* If possible, return a loop-unrolled version of bb0. The original
+ is changed. If not possible, return NULL. */
- - IRExpr/IRStmt trees should be treated as immutable, as they
- may get shared. So never change a field of such a tree node;
- instead construct and return a new one if needed.
+/* The two schemas considered are:
+
+ X: BODY; goto X
+ --> X: BODY;BODY; goto X
+
+ and
+
+ X: BODY; if (c) goto X; goto Y
+ which trivially transforms to
+ X: BODY; if (!c) goto Y; goto X;
+ so it falls in the scope of the first case.
+
+ X and Y must be literal (guest) addresses.
*/
+static IRBB* maybe_loop_unroll_BB ( IRBB* bb0, Addr64 my_addr )
+{
+ Int i, n_vars;
+ Bool xxx_known;
+ Addr64 xxx_value, yyy_value;
+ IRExpr* udst;
+ IRStmt* st;
+ IRConst* con;
+ IRBB* bb1;
+ IRBB* bb2;
+
+ /* First off, figure out if we can unroll this loop. Do this
+ without modifying bb0. */
+
+ if (bb0->jumpkind != Ijk_Boring)
+ return NULL;
+
+ xxx_known = False;
+ xxx_value = 0;
+
+ /* Extract the next-guest address. If it isn't a literal, we
+ have to give up. */
+
+ udst = bb0->next;
+ if (udst->tag == Iex_Const
+ && (udst->Iex.Const.con->tag == Ico_U32
+ || udst->Iex.Const.con->tag == Ico_U64)) {
+ /* The BB ends in a jump to a literal location. */
+ xxx_known = True;
+ xxx_value
+ = udst->Iex.Const.con->tag == Ico_U64
+ ? udst->Iex.Const.con->Ico.U64
+ : (Addr64)(udst->Iex.Const.con->Ico.U32);
+ }
+
+ if (!xxx_known)
+ return NULL;
+
+ /* Now we know the BB ends to a jump to a literal location.
+If it's a jump to itself (viz, idiom #1), move directly to the unrolling stage,
+first cloning the bb so the original isn't modified. */
+ if (xxx_value == my_addr) {
+ bb1 = dopyIRBB( bb0 );
+ bb0 = NULL;
+ udst = NULL; /* is now invalid */
+ goto do_unroll;
+ }
+
+ /* Search for the second idiomatic form:
+ X: BODY; if (c) goto X; goto Y
+ We know Y, but need to establish that the last stmt
+is 'if (c) goto X'.
+ */
+ yyy_value = xxx_value;
+ for (i = bb0->stmts_used-1; i >= 0; i--)
+ if (bb0->stmts[i])
+ break;
+
+ if (i < 0)
+ return NULL; /* block with no stmts. Strange. */
+ st = bb0->stmts[i];
+ if (st->tag != Ist_Exit)
+ return NULL;
+
+ con = st->Ist.Exit.dst;
+ vassert(con->tag == Ico_U32 || con->tag == Ico_U64);
+xxx_value
+= con->tag == Ico_U64
+ ? st->Ist.Exit.dst->Ico.U64
+ : (Addr64)(st->Ist.Exit.dst->Ico.U32);
+
+/* If this assertion fails, we have some kind of type error. */
+ vassert(con->tag == udst->Iex.Const.con->tag);
+
+ if (xxx_value != my_addr)
+ /* We didn't find either idiom. Give up. */
+ return NULL;
+
+ /* Ok, we found idiom #2. Copy the BB, switch around the xxx and yyy values (which makes it look like idiom #1), and go into unrolling proper. This means finding (again) the last stmt, in the copied BB. */
+ bb1 = dopyIRBB( bb0 );
+ bb0 = NULL;
+ udst = NULL; /* is now invalid */
+ for (i = bb1->stmts_used-1; i >= 0; i--)
+ if (bb1->stmts[i])
+ break;
+ /* The next bunch of assertions should be true since we already found and checked the last stmt in the original bb. */
+ vassert(i >= 0);
+ st = bb1->stmts[i];
+ vassert(st->tag == Ist_Exit);
+ con = st->Ist.Exit.dst;
+ vassert(con->tag == Ico_U32 || con->tag == Ico_U64);
+ udst = bb1->next;
+ vassert(udst->tag == Iex_Const);
+ vassert(udst->Iex.Const.con->tag == Ico_U32
+ || udst->Iex.Const.con->tag == Ico_U64);
+ vassert(con->tag == udst->Iex.Const.con->tag);
+ /* switch the xxx and yyy fields around */
+ if (con->tag == Ico_U64) {
+ udst->Iex.Const.con->Ico.U64 = xxx_value;
+ con->Ico.U64 = yyy_value;
+ } else {
+ udst->Iex.Const.con->Ico.U32 = (UInt)xxx_value;
+ con->Ico.U64 = (UInt)yyy_value;
+ }
+ /* negate the test condition; blargh */
+ st->Ist.Exit.cond = IRExpr_Unop(Iop_32to1,IRExpr_Unop(Iop_Not32,IRExpr_Unop(Iop_1Uto32,dopyIRExpr(st->Ist.Exit.cond))));
+
+ /* --- The unroller proper. Both idioms are now converted to idiom 1. --- */
+
+ do_unroll:
+
+ n_vars = bb1->tyenv->types_used;
+
+ bb2 = dopyIRBB(bb1);
+ for (i = 0; i < n_vars; i++) {
+ (void)newIRTemp(bb1->tyenv, bb2->tyenv->types[i]);
+ }
+ for (i = 0; i < bb2->stmts_used; i++) {
+ if (bb2->stmts[i] == NULL)
+ continue;
+ /* deltaIRStmt destructively modifies the stmt, but
+ that's OK since bb2 is a complete fresh copy of bb1. */
+ deltaIRStmt(bb2->stmts[i], n_vars);
+ addStmtToIRBB(bb1, bb2->stmts[i]);
+ }
+
+ if (0) {
+ vex_printf("\nUNROLLED (%llx)\n", my_addr);
+ ppIRBB(bb1);
+ vex_printf("\n");
+ }
+
+ return flatten_BB(bb1);
+
+}
+
+/*---------------------------------------------------------------*/
+/*--- iropt main ---*/
+/*---------------------------------------------------------------*/
+
+static Bool iropt_verbose = False; //True;
+
+
/* Do a simple cleanup pass on bb. This is: redundant Get removal,
redundant Put removal, constant propagation, dead code removal,
clean helper specialisation, and dead code removal (again).
-*/
+
+ Note, spec_helpers_BB destroys the 'flat' property, as the
+ expressions which replace clean helper calls can be arbitrarily
+ deep. This should be fixed. */
static
-IRBB* baseline_cleanup ( IRBB* bb,
- IRExpr* (*specHelper) ( Char*, IRExpr**) )
+IRBB* cheap_transformations (
+ IRBB* bb,
+ IRExpr* (*specHelper) ( Char*, IRExpr**) )
{
redundant_get_removal_BB ( bb );
if (iropt_verbose) {
return bb;
}
+
+/* Do some more expensive transformations on bb, which are aimed at
+ optimising as much as possible in the presence of GetI and PutI. */
+
+static
+IRBB* expensive_transformations( IRBB* bb )
+{
+ cse_BB( bb );
+ collapse_AddSub_chains_BB( bb );
+ do_PutI_GetI_forwarding_BB( bb );
+ do_redundant_PutI_elimination( bb );
+ dead_BB( bb );
+ return flatten_BB( bb );
+}
+
+
/* Scan a flattened BB to see if it has any GetI or PutIs in it. Used
as a heuristic hack to see if iropt needs to do expensive
- optimisations (CSE, PutI -> GetI forwarding) to improve code with
- those in.
-*/
+ optimisations (CSE, PutI -> GetI forwarding, redundant PutI
+ elimination) to improve code containing GetI or PutI. */
+
static Bool hasGetIorPutI ( IRBB* bb )
{
Int i, j;
}
+/* ---------------- The main iropt entry point. ---------------- */
+
/* exported from this file */
-/* The main iropt entry point. */
+/* Rules of the game:
+
+ - IRExpr/IRStmt trees should be treated as immutable, as they
+ may get shared. So never change a field of such a tree node;
+ instead construct and return a new one if needed.
+*/
+
IRBB* do_iropt_BB ( IRBB* bb0,
- IRExpr* (*specHelper) ( Char*, IRExpr**) )
+ IRExpr* (*specHelper) ( Char*, IRExpr**),
+ Addr64 guest_addr )
{
static UInt n_total = 0;
static UInt n_expensive = 0;
Bool show_res = False;
+ Bool do_expensive;
- IRBB *bb;
+ IRBB *bb, *bb2;
n_total++;
ppIRBB(bb);
}
- /* Now do a preliminary cleanup pass. */
+ /* Now do a preliminary cleanup pass, and figure out if we also
+ need to do 'expensive' optimisations. Expensive optimisations
+ are deemed necessary if the block contains any GetIs or PutIs.
+ If needed, do expensive transformations and then another cheap
+ cleanup pass. */
- bb = baseline_cleanup( bb, specHelper );
-
- /* If there are GetI/PutI in this block, do some expensive
- transformations:
-
- - CSE
- - re-run of the baseline cleanup
-
- */
-
- if (hasGetIorPutI(bb)) {
+ bb = cheap_transformations( bb, specHelper );
+ do_expensive = hasGetIorPutI(bb);
+ if (do_expensive) {
n_expensive++;
- vex_printf("***** EXPENSIVE %d %d\n", n_total, n_expensive);
- cse_BB( bb );
- //ppIRBB(bb); vex_printf("\n\n");
- collapse_AddSub_chains_BB( bb );
- do_PutI_GetI_forwarding_BB( bb );
- do_redundant_PutI_elimination( bb );
- /*
- ppIRBB(bb); vex_printf("\n\n");
- dead_BB( bb );
- bb = cprop_BB ( bb );
- dead_BB(bb);
- */
- //ppIRBB(bb); vex_printf("\n\nQQQQ\n");
- bb = baseline_cleanup( flatten_BB(bb), specHelper );
- //vassert(0);
- // vex_printf("expensive done\n");
//show_res = True;
+ vex_printf("***** EXPENSIVE %d %d\n", n_total, n_expensive);
+ bb = expensive_transformations( bb );
+ bb = cheap_transformations( bb, specHelper );
+ }
+
+ /* 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 );
+ if (bb2) {
+ //show_res = True;
+ bb = cheap_transformations( bb2, specHelper );
+ if (do_expensive) {
+ bb = expensive_transformations( bb );
+ bb = cheap_transformations( bb, specHelper );
+ }
}
/* Finally, rebuild trees, for the benefit of instruction
selection. */
- treebuild_BB ( bb );
+ treebuild_BB( bb );
if (show_res || iropt_verbose) {
vex_printf("\n========= TREEd \n\n" );
ppIRBB(bb);