From: Julian Seward Date: Fri, 20 Aug 2004 00:11:12 +0000 (+0000) Subject: Redundant-Put removal. X-Git-Tag: svn/VALGRIND_3_0_1^2~1148 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=aad9035c5dfd050174683609c38998e9a4a989bc;p=thirdparty%2Fvalgrind.git Redundant-Put removal. git-svn-id: svn://svn.valgrind.org/vex/trunk@186 --- diff --git a/VEX/priv/ir/iropt.c b/VEX/priv/ir/iropt.c index 4e888c10f7..1c66e8beb9 100644 --- a/VEX/priv/ir/iropt.c +++ b/VEX/priv/ir/iropt.c @@ -606,11 +606,15 @@ static IRBB* cprop_BB ( IRBB* in ) 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 @@ -759,17 +763,15 @@ static void dead_BB ( IRBB* bb ) /*--- 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). */ @@ -790,13 +792,40 @@ static UInt mk_key_GetIPutI ( UShort minoff16, UShort maxoff16 ) 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]; @@ -809,7 +838,6 @@ static void redundant_get_removal_BB ( IRBB* bb ) && 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 ); @@ -843,24 +871,10 @@ static void redundant_get_removal_BB ( IRBB* bb ) /* 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 */ @@ -874,6 +888,148 @@ static void redundant_get_removal_BB ( IRBB* bb ) } +/*---------------------------------------------------------------*/ +/*--- 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 ---*/ /*---------------------------------------------------------------*/ @@ -902,6 +1058,12 @@ IRBB* do_iropt_BB ( IRBB* bb0 ) 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" );