]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Redundant-Put removal.
authorJulian Seward <jseward@acm.org>
Fri, 20 Aug 2004 00:11:12 +0000 (00:11 +0000)
committerJulian Seward <jseward@acm.org>
Fri, 20 Aug 2004 00:11:12 +0000 (00:11 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@186

VEX/priv/ir/iropt.c

index 4e888c10f7c736322948dade52ff3265013c8436..1c66e8beb9ab2e0aceaab77de0ab39175c714d32 100644 (file)
@@ -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" );