accumulated prior to this point. As part of the subst_Stmt
call, also then fold any constant expressions resulting. */
- st2 = subst_and_fold_Stmt( env, in->stmts[i] );
+ st2 = in->stmts[i];
+
+ /* perhaps st2 is already a no-op? */
+ if (!st2) continue;
+
+ st2 = subst_and_fold_Stmt( env, st2 );
/* If the statement has been folded into a no-op, forget it. */
- if (!st2)
- continue;
+ if (!st2) continue;
/* Now consider what the stmt looks like. If it's of the form
't = const' or 't1 = t2', add it to the running environment
/*--- In-place removal of redundant GETs ---*/
/*---------------------------------------------------------------*/
-/* Scan forwards, building up an environment binding
- (offset,length) pairs to values, which will either be
- temps or constants.
+/* Scan forwards, building up an environment binding (min offset, max
+ offset) pairs to values, which will either be temps or constants.
- On seeing 't = Get(off,len)', look up (off,len) in the env and if
- it matches, replace the Get with the stored value.
+ On seeing 't = Get(minoff,maxoff)', look up (minoff,maxoff) in the
+ env and if it matches, replace the Get with the stored value.
- On seeing 'Put (off,len) = t or c', first remove in the env any
- binding which fully or partially overlaps with (off,len). Then
- add a new (off,len) :-> t or c binding.
-*/
+ On seeing 'Put (minoff,maxoff) = t or c', first remove in the env
+ any binding which fully or partially overlaps with (minoff,maxoff).
+ Then add a new (minoff,maxoff) :-> t or c binding. */
/* Create keys, of the form ((minoffset << 16) | maxoffset). */
return (minoff << 16) | maxoff;
}
+/* Supposing h has keys of the form generated by mk_key_GetPut and
+ mk_key_GetIPutI, invalidate any key which overlaps (k_lo
+ .. k_hi).
+*/
+
+static void invalidateOverlaps ( Hash64* h, UInt k_lo, UInt k_hi )
+{
+ Int j;
+ UInt e_lo, e_hi;
+ vassert(k_lo <= k_hi);
+ /* invalidate any env entries which in any way overlap (k_lo
+ .. k_hi) */
+ for (j = 0; j < h->used; j++) {
+ if (!h->inuse[j])
+ continue;
+ e_lo = (((UInt)h->key[j]) >> 16) & 0xFFFF;
+ e_hi = ((UInt)h->key[j]) & 0xFFFF;
+ vassert(e_lo <= e_hi);
+ if (e_hi < k_lo || k_hi < e_lo)
+ continue; /* no overlap possible */
+ else
+ /* overlap; invalidate */
+ h->inuse[j] = False;
+ }
+}
+
static void redundant_get_removal_BB ( IRBB* bb )
{
Hash64* env = newH64();
UInt key;
- Int i, j;
+ Int i;
Bool isPut;
+ ULong val;
for (i = 0; i < bb->stmts_used; i++) {
IRStmt* st = bb->stmts[i];
&& st->Ist.Tmp.expr->tag == Iex_Get) {
/* st is 't = Get(...)'. Look up in the environment and see
if the Get can be replaced. */
- ULong val;
IRExpr* get = st->Ist.Tmp.expr;
key = (ULong)mk_key_GetPut( get->Iex.Get.offset,
get->Iex.Get.ty );
/* invalidate any env entries overlapped by this Put */
if (isPut) {
- UInt k_lo, k_hi, e_lo, e_hi;
+ UInt k_lo, k_hi;
k_lo = (key >> 16) & 0xFFFF;
k_hi = key & 0xFFFF;
- vassert(k_lo <= k_hi);
- /* invalidate any env entries which in any way overlap
- (k_lo .. k_hi) */
- for (j = 0; j < env->used; j++) {
- if (!env->inuse[j])
- continue;
- e_lo = (((UInt)env->key[j]) >> 16) & 0xFFFF;
- e_hi = ((UInt)env->key[j]) & 0xFFFF;
- vassert(e_lo <= e_hi);
- if (e_hi < k_lo || k_hi < e_lo)
- continue; /* no overlap possible */
- else
- /* overlap; invalidate */
- env->inuse[j] = False;
- }
+ invalidateOverlaps(env, k_lo, k_hi);
}
/* add this one to the env, if appropriate */
}
+/*---------------------------------------------------------------*/
+/*--- In-place removal of redundant PUTs ---*/
+/*---------------------------------------------------------------*/
+
+/* Find any Get uses in st and invalidate any partially or fully
+ overlapping ranges listed in env. Due to the flattening phase, the
+ only stmt kind we expect to find a Get on is IRStmt_Tmp. */
+
+static void handle_gets_Stmt ( Hash64* env, IRStmt* st )
+{
+ UInt key;
+ Bool isGet;
+ IRExpr* e;
+ switch (st->tag) {
+
+ /* This is the only interesting case. Deal with Gets in the RHS
+ expression. */
+ case Ist_Tmp:
+ e = st->Ist.Tmp.expr;
+ switch (e->tag) {
+ case Iex_Get:
+ isGet = True;
+ key = mk_key_GetPut ( e->Iex.Get.offset, e->Iex.Get.ty );
+ break;
+ case Iex_GetI:
+ isGet = True;
+ key = mk_key_GetIPutI ( e->Iex.GetI.minoff, e->Iex.GetI.maxoff );
+ break;
+ default:
+ isGet = False;
+ }
+ if (isGet) {
+ UInt k_lo, k_hi;
+ k_lo = (key >> 16) & 0xFFFF;
+ k_hi = key & 0xFFFF;
+ invalidateOverlaps(env, k_lo, k_hi);
+ }
+ break;
+
+ /* all other cases are boring. */
+ case Ist_STle:
+ vassert(isAtom(st->Ist.STle.addr));
+ vassert(isAtom(st->Ist.STle.data));
+ return;
+
+ case Ist_Exit:
+ vassert(isAtom(st->Ist.Exit.cond));
+ return;
+
+ default:
+ vex_printf("\n");
+ ppIRStmt(st);
+ vex_printf("\n");
+ vpanic("handle_gets_Stmt");
+ }
+}
+
+
+/* Scan backwards, building up a set of (min offset, max
+ offset) pairs, indicating those parts of the guest state
+ for which the next event is a write.
+
+ On seeing a conditional exit, empty the set.
+
+ On seeing 'Put (minoff,maxoff) = t or c', if (minoff,maxoff) is
+ completely within the set, remove the Put. Otherwise, add
+ (minoff,maxoff) to the set.
+
+ On seeing 'Get (minoff,maxoff)', remove any part of the set
+ overlapping (minoff,maxoff).
+*/
+
+static void redundant_put_removal_BB ( IRBB* bb )
+{
+ Int i, j;
+ Bool isPut;
+ IRStmt* st;
+ UInt key;
+
+ Hash64* env = newH64();
+ for (i = bb->stmts_used-1; i >= 0; i--) {
+ st = bb->stmts[i];
+
+ /* Deal with conditional exits. */
+ if (st->tag == Ist_Exit) {
+ /* Since control may not get beyond this point, we must empty
+ out the set, since we can no longer claim that the next
+ event for any part of the guest state is definitely a
+ write. */
+ vassert(isAtom(st->Ist.Exit.cond));
+ for (j = 0; j < env->used; j++)
+ env->inuse[j] = False;
+ continue;
+ }
+
+ /* Deal with Puts */
+ switch (st->tag) {
+ case Ist_Put:
+ isPut = True;
+ key = mk_key_GetPut( st->Ist.Put.offset,
+ typeOfIRExpr(bb->tyenv,st->Ist.Put.expr) );
+ vassert(isAtom(st->Ist.Put.expr));
+ break;
+ case Ist_PutI:
+ isPut = True;
+ key = mk_key_GetIPutI( st->Ist.PutI.minoff,
+ st->Ist.PutI.maxoff );
+ vassert(isAtom(st->Ist.PutI.expr));
+ break;
+ default:
+ isPut = False;
+ }
+ if (isPut) {
+ /* See if any single entry in env overlaps this Put. This is
+ simplistic in that the transformation is valid if, say, two
+ or more entries in the env overlap this Put, but the use of
+ lookupH64 will only find a single entry which exactly
+ overlaps this Put. This is suboptimal but safe. */
+ if (lookupH64(env, NULL, (ULong)key)) {
+ /* This Put is redundant because a later one will overwrite
+ it. So NULL (nop) it out. */
+ if (DEBUG_IROPT) {
+ vex_printf("rPUT: "); ppIRStmt(st);
+ vex_printf("\n");
+ }
+ bb->stmts[i] = NULL;
+ } else {
+ /* We can't demonstrate that this Put is redundant, so add it
+ to the running collection. */
+ addToH64(env, (ULong)key, 0);
+ }
+ continue;
+ }
+
+ /* Deal with Gets. These remove bits of the environment since
+ appearance of a Get means that the next event for that slice
+ of the guest state is no longer a write, but a read. */
+ handle_gets_Stmt( env, st );
+ }
+}
+
+
/*---------------------------------------------------------------*/
/*--- iropt main ---*/
/*---------------------------------------------------------------*/
ppIRBB(flat);
}
+ redundant_put_removal_BB ( flat );
+ if (verbose) {
+ vex_printf("\n========= REDUNDANT PUT\n\n" );
+ ppIRBB(flat);
+ }
+
cpd = cprop_BB ( flat );
if (verbose) {
vex_printf("\n========= CPROPD\n\n" );