Quantcast

vex: r3310 - in /branches/VEX_JIT_HACKS: priv/ir_defs.c priv/ir_inject.c priv/ir_opt.c priv/main_main.c priv/main_util.c pub/libvex_ir.h useful/test_main.c

classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

vex: r3310 - in /branches/VEX_JIT_HACKS: priv/ir_defs.c priv/ir_inject.c priv/ir_opt.c priv/main_main.c priv/main_util.c pub/libvex_ir.h useful/test_main.c

svn-2
Author: iraisr
Date: Sat Mar 11 14:07:07 2017
New Revision: 3310

Log:
First cut at introducing "if-then-else" control flow
into Valgrind's intermediate representation (IR).
Major rework done so far in modules: ir_defs.c and ir_opt.c.

Modified:
    branches/VEX_JIT_HACKS/priv/ir_defs.c
    branches/VEX_JIT_HACKS/priv/ir_inject.c
    branches/VEX_JIT_HACKS/priv/ir_opt.c
    branches/VEX_JIT_HACKS/priv/main_main.c
    branches/VEX_JIT_HACKS/priv/main_util.c
    branches/VEX_JIT_HACKS/pub/libvex_ir.h
    branches/VEX_JIT_HACKS/useful/test_main.c

Modified: branches/VEX_JIT_HACKS/priv/ir_defs.c
==============================================================================
--- branches/VEX_JIT_HACKS/priv/ir_defs.c (original)
+++ branches/VEX_JIT_HACKS/priv/ir_defs.c Sat Mar 11 14:07:07 2017
@@ -33,6 +33,8 @@
    without prior written permission.
 */
 
+/* Copyright (C) 2017-2017 Ivo Raisr <[hidden email]> */
+
 #include "libvex_basictypes.h"
 #include "libvex_ir.h"
 #include "libvex.h"
@@ -111,10 +113,10 @@
 
 void ppIRTemp ( IRTemp tmp )
 {
-   if (tmp == IRTemp_INVALID)
+   if (isIRTempInvalid(tmp))
       vex_printf("IRTemp_INVALID");
    else
-      vex_printf( "t%u", tmp);
+      vex_printf("t%u:%u", tmp.id, tmp.index);
 }
 
 void ppIROp ( IROp op )
@@ -1409,7 +1411,7 @@
 void ppIRDirty ( const IRDirty* d )
 {
    Int i;
-   if (d->tmp != IRTemp_INVALID) {
+   if (!isIRTempInvalid(d->tmp)) {
       ppIRTemp(d->tmp);
       vex_printf(" = ");
    }
@@ -1451,7 +1453,7 @@
 {
    /* Print even structurally invalid constructions, as an aid to
       debugging. */
-   if (cas->oldHi != IRTemp_INVALID) {
+   if (!isIRTempInvalid(cas->oldHi)) {
       ppIRTemp(cas->oldHi);
       vex_printf(",");
    }
@@ -1567,6 +1569,25 @@
    }
 }
 
+void ppIRPhi(const IRPhi* phi)
+{
+   ppIRTemp(phi->dst);
+   vex_printf(" = phi(");
+   ppIRTemp(phi->srcThen);
+   vex_printf(",");
+   ppIRTemp(phi->srcElse);
+   vex_printf(")");
+}
+
+void ppIRPhiVec(const IRPhiVec* phis)
+{
+   for (UInt i = 0; i < phis->phis_used; i++) {
+      vex_printf("   ");
+      ppIRPhi(phis->phis[i]);
+      vex_printf("\n");
+   }
+}
+
 void ppIRStmt ( const IRStmt* s )
 {
    if (!s) {
@@ -1649,19 +1670,32 @@
          ppIRJumpKind(s->Ist.Exit.jk);
          vex_printf(" } ");
          break;
-      default:
+      case Ist_IfThenElse:
+         vex_printf("if (");
+         ppIRExpr(s->Ist.IfThenElse.cond);
+         vex_printf(") then {\n");
+         ppIRStmtVec(s->Ist.IfThenElse.then_leg); // TODO-JIT: indent properly
+         vex_printf("} else {\n");
+         ppIRStmtVec(s->Ist.IfThenElse.else_leg); // TODO-JIT: indent properly
+         vex_printf("}\n");
+         IRPhiVec* phi_nodes = s->Ist.IfThenElse.phi_nodes;
+         if (phi_nodes != NULL) {
+            ppIRPhiVec(phi_nodes);
+         }
+         break;
+      default:
          vpanic("ppIRStmt");
    }
 }
 
 void ppIRTypeEnv ( const IRTypeEnv* env )
 {
-   UInt i;
-   for (i = 0; i < env->types_used; i++) {
+   for (UInt i = 0; i < env->types_used; i++) {
       if (i % 8 == 0)
          vex_printf( "   ");
-      ppIRTemp(i);
-      vex_printf( ":");
+      IRTemp temp = {env->id, i};
+      ppIRTemp(temp);
+      vex_printf("=");
       ppIRType(env->types[i]);
       if (i % 8 == 7)
          vex_printf( "\n");
@@ -1672,17 +1706,22 @@
       vex_printf( "\n");
 }
 
-void ppIRSB ( const IRSB* bb )
+/* TODO-JIT: account for indentation */
+void ppIRStmtVec(const IRStmtVec* stmts)
 {
-   Int i;
-   vex_printf("IRSB {\n");
-   ppIRTypeEnv(bb->tyenv);
+   ppIRTypeEnv(stmts->tyenv);
    vex_printf("\n");
-   for (i = 0; i < bb->stmts_used; i++) {
+   for (UInt i = 0; i < stmts->stmts_used; i++) {
       vex_printf( "   ");
-      ppIRStmt(bb->stmts[i]);
-      vex_printf( "\n");
+      ppIRStmt(stmts->stmts[i]);
+      vex_printf("\n");
    }
+}
+
+void ppIRSB ( const IRSB* bb )
+{
+   vex_printf("IRSB {\n");
+   ppIRStmtVec(bb->stmts);
    vex_printf( "   PUT(%d) = ", bb->offsIP );
    ppIRExpr( bb->next );
    vex_printf( "; exit-");
@@ -2056,15 +2095,16 @@
 /* Constructors -- IRDirty */
 
 IRDirty* emptyIRDirty ( void ) {
-   IRDirty* d = LibVEX_Alloc_inline(sizeof(IRDirty));
-   d->cee      = NULL;
-   d->guard    = NULL;
-   d->args     = NULL;
-   d->tmp      = IRTemp_INVALID;
-   d->mFx      = Ifx_None;
-   d->mAddr    = NULL;
-   d->mSize    = 0;
-   d->nFxState = 0;
+   IRDirty* d   = LibVEX_Alloc_inline(sizeof(IRDirty));
+   d->cee       = NULL;
+   d->guard     = NULL;
+   d->args      = NULL;
+   d->tmp.id    = IRTyEnvID_INVALID;
+   d->tmp.index = IRTyEnvIndex_INVALID;
+   d->mFx       = Ifx_None;
+   d->mAddr     = NULL;
+   d->mSize     = 0;
+   d->nFxState  = 0;
    return d;
 }
 
@@ -2131,6 +2171,24 @@
 
 /* Constructors -- IRStmt */
 
+IRPhi* mkIRPhi(IRTemp dst, IRTemp srcThen, IRTemp srcElse)
+{
+   IRPhi* phi   = LibVEX_Alloc_inline(sizeof(IRPhi));
+   phi->dst     = dst;
+   phi->srcThen = srcThen;
+   phi->srcElse = srcElse;
+   return phi;
+}
+
+IRPhiVec* emptyIRPhiVec(void)
+{
+   IRPhiVec* vec  = LibVEX_Alloc_inline(sizeof(IRPhiVec));
+   vec->phis_used = 0;
+   vec->phis_size = 8;
+   vec->phis      = LibVEX_Alloc_inline(vec->phis_size * sizeof(IRPhi*));
+   return vec;
+}
+
 IRStmt* IRStmt_NoOp ( void )
 {
    /* Just use a single static closure. */
@@ -2239,6 +2297,18 @@
    return s;
 }
 
+IRStmt* IRStmt_IfThenElse(IRExpr* cond, IRStmtVec* then_leg,
+                          IRStmtVec* else_leg, IRPhiVec* phi_nodes)
+{
+   IRStmt* s = LibVEX_Alloc_inline(sizeof(IRStmt));
+   s->tag                      = Ist_IfThenElse;
+   s->Ist.IfThenElse.cond      = cond;
+   s->Ist.IfThenElse.then_leg  = then_leg;
+   s->Ist.IfThenElse.else_leg  = else_leg;
+   s->Ist.IfThenElse.phi_nodes = phi_nodes;
+   return s;
+}
+
 
 /* Constructors -- IRTypeEnv */
 
@@ -2248,31 +2318,54 @@
    env->types       = LibVEX_Alloc_inline(8 * sizeof(IRType));
    env->types_size  = 8;
    env->types_used  = 0;
+   env->id          = IRTyEnvID_INVALID;
    return env;
 }
 
 
+/* Constructors -- IRStmtVec */
+
+IRStmtVec* emptyIRStmtVec(void)
+{
+   IRStmtVec* stmts  = LibVEX_Alloc_inline(sizeof(IRStmtVec));
+   stmts->tyenv      = emptyIRTypeEnv();
+   stmts->stmts_used = 0;
+   stmts->stmts_size = 8;
+   stmts->stmts      = LibVEX_Alloc_inline(stmts->stmts_size * sizeof(IRStmt*));
+   stmts->parent     = NULL;
+   return stmts;
+}
+
+
 /* Constructors -- IRSB */
 
 IRSB* emptyIRSB ( void )
 {
-   IRSB* bb       = LibVEX_Alloc_inline(sizeof(IRSB));
-   bb->tyenv      = emptyIRTypeEnv();
-   bb->stmts_used = 0;
-   bb->stmts_size = 8;
-   bb->stmts      = LibVEX_Alloc_inline(bb->stmts_size * sizeof(IRStmt*));
-   bb->next       = NULL;
-   bb->jumpkind   = Ijk_Boring;
-   bb->offsIP     = 0;
+   IRSB* bb     = LibVEX_Alloc_inline(sizeof(IRSB));
+   bb->stmts    = emptyIRStmtVec();
+   bb->id_seq   = 0;
+   bb->next     = NULL;
+   bb->jumpkind = Ijk_Boring;
+   bb->offsIP   = 0;
+
+   bb->stmts->tyenv->id = nextIRTyEnvID(bb);
    return bb;
 }
 
+IRTyEnvID nextIRTyEnvID(IRSB* irsb)
+{
+   IRTyEnvID next = irsb->id_seq;
+   irsb->id_seq += 1;
+   vassert(irsb->id_seq < IRTyEnvID_INVALID);
+   return next;
+}
 
-/*---------------------------------------------------------------*/
-/*--- (Deep) copy constructors.  These make complete copies   ---*/
-/*--- the original, which can be modified without affecting   ---*/
-/*--- the original.                                           ---*/
-/*---------------------------------------------------------------*/
+
+/*----------------------------------------------------------------*/
+/*--- (Deep) copy constructors.  These make complete copies    ---*/
+/*--- of the original, which can be modified without affecting ---*/
+/*--- the original.                                            ---*/
+/*----------------------------------------------------------------*/
 
 /* Copying IR Expr vectors (for call args). */
 
@@ -2437,7 +2530,27 @@
                    deepCopyIRExpr(puti->data));
 }
 
-IRStmt* deepCopyIRStmt ( const IRStmt* s )
+IRPhi* deepCopyIRPhi(const IRPhi* phi)
+{
+   return mkIRPhi(phi->dst, phi->srcThen, phi->srcElse);
+}
+
+IRPhiVec* deepCopyIRPhiVec(const IRPhiVec* vec)
+{
+   if (vec == NULL) {
+      return NULL;
+   }
+
+   IRPhiVec* vec2  = LibVEX_Alloc_inline(sizeof(IRPhiVec));
+   vec2->phis_used = vec2->phis_size = vec->phis_used;
+   IRPhi **phis2   = LibVEX_Alloc_inline(vec2->phis_used * sizeof(IRPhi*));
+   for (UInt i = 0; i < vec2->phis_used; i++)
+      phis2[i] = deepCopyIRPhi(vec->phis[i]);
+   vec2->phis      = phis2;
+   return vec2;
+}
+
+IRStmt* deepCopyIRStmt(const IRStmt* s, IRStmtVec* parent)
 {
    switch (s->tag) {
       case Ist_NoOp:
@@ -2494,43 +2607,59 @@
                             s->Ist.Exit.jk,
                             deepCopyIRConst(s->Ist.Exit.dst),
                             s->Ist.Exit.offsIP);
+      case Ist_IfThenElse:
+         return IRStmt_IfThenElse(deepCopyIRExpr(s->Ist.IfThenElse.cond),
+                          deepCopyIRStmtVec(s->Ist.IfThenElse.then_leg, parent),
+                          deepCopyIRStmtVec(s->Ist.IfThenElse.else_leg, parent),
+                          deepCopyIRPhiVec(s->Ist.IfThenElse.phi_nodes));
       default:
          vpanic("deepCopyIRStmt");
    }
 }
 
-IRTypeEnv* deepCopyIRTypeEnv ( const IRTypeEnv* src )
+IRStmtVec* deepCopyIRStmtVec(const IRStmtVec* src, IRStmtVec* parent)
 {
-   Int        i;
-   IRTypeEnv* dst = LibVEX_Alloc_inline(sizeof(IRTypeEnv));
+   IRStmtVec* vec2  = LibVEX_Alloc_inline(sizeof(IRStmtVec));
+   vec2->tyenv      = deepCopyIRTypeEnv(src->tyenv);
+   vec2->parent     = parent;
+   vec2->stmts_used = vec2->stmts_size = src->stmts_used;
+   IRStmt **stmts2  = LibVEX_Alloc_inline(vec2->stmts_used * sizeof(IRStmt*));
+   for (UInt i = 0; i < vec2->stmts_used; i++) {
+      stmts2[i] = deepCopyIRStmt(src->stmts[i], vec2);
+   }
+   vec2->stmts      = stmts2;
+   return vec2;
+}
+
+IRTypeEnv* deepCopyIRTypeEnv(const IRTypeEnv* src)
+{
+   IRTypeEnv* dst  = LibVEX_Alloc_inline(sizeof(IRTypeEnv));
    dst->types_size = src->types_size;
    dst->types_used = src->types_used;
-   dst->types = LibVEX_Alloc_inline(dst->types_size * sizeof(IRType));
-   for (i = 0; i < src->types_used; i++)
+   dst->types      = LibVEX_Alloc_inline(dst->types_size * sizeof(IRType));
+   for (UInt i = 0; i < src->types_used; i++)
       dst->types[i] = src->types[i];
+   dst->id = src->id;
    return dst;
 }
 
 IRSB* deepCopyIRSB ( const IRSB* bb )
 {
-   Int      i;
-   IRStmt** sts2;
    IRSB* bb2 = deepCopyIRSBExceptStmts(bb);
-   bb2->stmts_used = bb2->stmts_size = bb->stmts_used;
-   sts2 = LibVEX_Alloc_inline(bb2->stmts_used * sizeof(IRStmt*));
-   for (i = 0; i < bb2->stmts_used; i++)
-      sts2[i] = deepCopyIRStmt(bb->stmts[i]);
-   bb2->stmts = sts2;
+   // TODO-JIT: does a deep copy of bb->stmts->tyenv once more
+   bb2->stmts = deepCopyIRStmtVec(bb->stmts, NULL);
    return bb2;
 }
 
 IRSB* deepCopyIRSBExceptStmts ( const IRSB* bb )
 {
-   IRSB* bb2     = emptyIRSB();
-   bb2->tyenv    = deepCopyIRTypeEnv(bb->tyenv);
-   bb2->next     = deepCopyIRExpr(bb->next);
-   bb2->jumpkind = bb->jumpkind;
-   bb2->offsIP   = bb->offsIP;
+   IRSB* bb2         = emptyIRSB();
+   bb2->stmts        = emptyIRStmtVec();
+   bb2->stmts->tyenv = deepCopyIRTypeEnv(bb->stmts->tyenv);
+   bb2->id_seq       = bb->id_seq;
+   bb2->next         = deepCopyIRExpr(bb->next);
+   bb2->jumpkind     = bb->jumpkind;
+   bb2->offsIP       = bb->offsIP;
    return bb2;
 }
 
@@ -3543,22 +3672,54 @@
 
 
 /*---------------------------------------------------------------*/
+/*--- Helper functions for the IR -- IR Phi Nodes             ---*/
+/*---------------------------------------------------------------*/
+
+void addIRPhi(IRStmt* st, IRPhi* phi)
+{
+   vassert(st->tag == Ist_IfThenElse);
+
+   IRPhiVec* phi_nodes = st->Ist.IfThenElse.phi_nodes;
+   if (phi_nodes == NULL) {
+      phi_nodes = emptyIRPhiVec();
+      st->Ist.IfThenElse.phi_nodes = phi_nodes;
+   }
+
+   if (phi_nodes->phis_used == phi_nodes->phis_size) {
+      IRPhi** phis2 = LibVEX_Alloc_inline(2 * phi_nodes->phis_size * sizeof(IRPhi*));
+      for (UInt i = 0; i < phi_nodes->phis_size; i++)
+         phis2[i] = phi_nodes->phis[i];
+      phi_nodes->phis = phis2;
+      phi_nodes->phis_size *= 2;
+   }
+
+   vassert(phi_nodes->phis_used < phi_nodes->phis_size);
+   phi_nodes->phis[phi_nodes->phis_used] = phi;
+   phi_nodes->phis_used += 1;
+}
+
+
+/*---------------------------------------------------------------*/
 /*--- Helper functions for the IR -- IR Basic Blocks          ---*/
 /*---------------------------------------------------------------*/
 
+void addStmtToIRStmtVec(IRStmtVec* stmts, IRStmt* st)
+{
+   if (stmts->stmts_used == stmts->stmts_size) {
+      IRStmt** stmts2 = LibVEX_Alloc_inline(2 * stmts->stmts_size * sizeof(IRStmt*));
+      for (UInt i = 0; i < stmts->stmts_size; i++)
+         stmts2[i] = stmts->stmts[i];
+      stmts->stmts = stmts2;
+      stmts->stmts_size *= 2;
+   }
+   vassert(stmts->stmts_used < stmts->stmts_size);
+   stmts->stmts[stmts->stmts_used] = st;
+   stmts->stmts_used++;
+}
+
 void addStmtToIRSB ( IRSB* bb, IRStmt* st )
 {
-   Int i;
-   if (bb->stmts_used == bb->stmts_size) {
-      IRStmt** stmts2 = LibVEX_Alloc_inline(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++;
+   addStmtToIRStmtVec(bb->stmts, st);
 }
 
 
@@ -3574,9 +3735,12 @@
    vassert(env->types_used >= 0);
    vassert(env->types_size >= 0);
    vassert(env->types_used <= env->types_size);
+   vassert(env->id != IRTyEnvID_INVALID);
+
    if (env->types_used < env->types_size) {
       env->types[env->types_used] = ty;
-      return env->types_used++;
+      IRTemp tmp = {env->id, env->types_used++};
+      return tmp;
    } else {
       Int i;
       Int new_size = env->types_size==0 ? 8 : 2*env->types_size;
@@ -3598,9 +3762,9 @@
 inline
 IRType typeOfIRTemp ( const IRTypeEnv* env, IRTemp tmp )
 {
-   vassert(tmp >= 0);
-   vassert(tmp < env->types_used);
-   return env->types[tmp];
+   vassert(tmp.index >= 0);
+   vassert(tmp.index < env->types_used);
+   return env->types[tmp.index];
 }
 
 IRType typeOfIRConst ( const IRConst* con )
@@ -3729,6 +3893,9 @@
   return UNLIKELY(is_IRExpr_VECRET_or_GSPTR(e));
 }
 
+static Bool isFlatIRStmtVec(const IRStmtVec* stmts);
+
+static
 Bool isFlatIRStmt ( const IRStmt* st )
 {
    Int      i;
@@ -3828,11 +3995,25 @@
          return True;
       case Ist_Exit:
          return isIRAtom(st->Ist.Exit.guard);
+      case Ist_IfThenElse:
+         return isIRAtom(st->Ist.IfThenElse.cond)
+                && isFlatIRStmtVec(st->Ist.IfThenElse.then_leg)
+                && isFlatIRStmtVec(st->Ist.IfThenElse.else_leg);
       default:
          vpanic("isFlatIRStmt(st)");
    }
 }
 
+static
+Bool isFlatIRStmtVec(const IRStmtVec* stmts)
+{
+   for (UInt i = 0; i < stmts->stmts_used; i++) {
+      if (!isFlatIRStmt(stmts->stmts[i]))
+         return False;
+   }
+
+   return True;
+}
 
 /*---------------------------------------------------------------*/
 /*--- Sanity checking                                         ---*/
@@ -3845,6 +4026,10 @@
    bit expression, depending on the guest's word size.
 
    Each temp is assigned only once, before its uses.
+   Each temp is referenced from the right scope.
+
+   Phi functions refer to existing, already assigned temporaries from
+   [parent, then leg, else leg] type environments.
 */
 
 static inline Int countArgs ( IRExpr** args )
@@ -3903,74 +4088,107 @@
    }
 }
 
-/* Traverse a Stmt/Expr, inspecting IRTemp uses.  Report any out of
-   range ones.  Report any which are read and for which the current
-   def_count is zero. */
+/* Traverse a Stmt/Expr, inspecting IRTemp uses. Report any out of range or out
+   of scope ones. Report any which are read and for which the current
+   def_count is zero. Report any which are assigned more than once or assigned
+   after being used. */
+
+static Bool inRangeIRTemp(const IRStmtVec* stmts, IRTemp tmp)
+{
+   vassert(tmp.id != IRTyEnvID_INVALID);
+
+   if (tmp.index >= 0 || tmp.index < stmts->tyenv->types_used) {
+      return True;
+   }
+   return False;
+}
+
+static Bool inScopeIRTemp(const IRStmtVec* stmts, IRTemp tmp)
+{
+   vassert(tmp.id != IRTyEnvID_INVALID);
+
+   if (stmts->tyenv->id == tmp.id) {
+      return True;
+   }
+   if (stmts->parent != NULL) {
+      return inScopeIRTemp(stmts->parent, tmp);
+   }
+   return False;
+}
 
 static
-void useBeforeDef_Temp ( const IRSB* bb, const IRStmt* stmt, IRTemp tmp,
-                         Int* def_counts )
+void useBeforeDef_Temp(const IRSB* bb, const IRStmtVec* stmts,
+                       const IRStmt* stmt, IRTemp tmp, UInt* def_counts[])
 {
-   if (tmp < 0 || tmp >= bb->tyenv->types_used)
-      sanityCheckFail(bb,stmt, "out of range Temp in IRExpr");
-   if (def_counts[tmp] < 1)
-      sanityCheckFail(bb,stmt, "IRTemp use before def in IRExpr");
+   vassert(tmp.id != IRTyEnvID_INVALID);
+
+   if (!inRangeIRTemp(stmts, tmp))
+      sanityCheckFail(bb, stmt, "out of range Temp in IRExpr");
+   if (!inScopeIRTemp(stmts, tmp))
+      sanityCheckFail(bb, stmt, "out of scope Temp in IRExpr");
+   if (def_counts[tmp.id][tmp.index] < 1)
+      sanityCheckFail(bb, stmt, "IRTemp use before def in IRExpr");
 }
 
 static
-void assignedOnce_Temp(const IRSB *bb, const IRStmt *stmt, IRTemp tmp,
-                       Int *def_counts, UInt n_def_counts,
-                       const HChar *err_msg_out_of_range,
-                       const HChar *err_msg_assigned_more_than_once)
+void assignedOnce_Temp(const IRSB* bb, const IRStmtVec* stmts,
+                       const IRStmt* stmt, IRTemp tmp, UInt* def_counts[],
+                       const HChar* err_msg_out_of_range,
+                       const HChar* err_msg_out_of_scope,
+                       const HChar* err_msg_assigned_more_than_once)
 {
-   if (tmp < 0 || tmp >= n_def_counts) {
+   vassert(tmp.id != IRTyEnvID_INVALID);
+
+   if (!inRangeIRTemp(stmts, tmp))
       sanityCheckFail(bb, stmt, err_msg_out_of_range);
-   }
+   if (!inScopeIRTemp(stmts, tmp))
+      sanityCheckFail(bb, stmt, err_msg_out_of_scope);
 
-   def_counts[tmp]++;
-   if (def_counts[tmp] > 1) {
-      sanityCheckFail(bb, stmt, err_msg_assigned_more_than_once);
+   def_counts[tmp.id][tmp.index]++;
+   if (def_counts[tmp.id][tmp.index] > 1) {
+      sanityCheckFail(bb,stmt,err_msg_assigned_more_than_once);
    }
 }
 
 static
-void useBeforeDef_Expr ( const IRSB* bb, const IRStmt* stmt,
-                         const IRExpr* expr, Int* def_counts )
+void useBeforeDef_Expr(const IRSB *bb, const IRStmtVec* stmts,
+                       const IRStmt* stmt, const IRExpr* expr,
+                       UInt* def_counts[])
 {
    Int i;
    switch (expr->tag) {
       case Iex_Get:
          break;
       case Iex_GetI:
-         useBeforeDef_Expr(bb,stmt,expr->Iex.GetI.ix,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, expr->Iex.GetI.ix, def_counts);
          break;
       case Iex_RdTmp:
-         useBeforeDef_Temp(bb,stmt,expr->Iex.RdTmp.tmp,def_counts);
+         useBeforeDef_Temp(bb, stmts, stmt, expr->Iex.RdTmp.tmp, def_counts);
          break;
       case Iex_Qop: {
          const IRQop* qop = expr->Iex.Qop.details;
-         useBeforeDef_Expr(bb,stmt,qop->arg1,def_counts);
-         useBeforeDef_Expr(bb,stmt,qop->arg2,def_counts);
-         useBeforeDef_Expr(bb,stmt,qop->arg3,def_counts);
-         useBeforeDef_Expr(bb,stmt,qop->arg4,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, qop->arg1, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, qop->arg2, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, qop->arg3, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, qop->arg4, def_counts);
          break;
       }
       case Iex_Triop: {
          const IRTriop* triop = expr->Iex.Triop.details;
-         useBeforeDef_Expr(bb,stmt,triop->arg1,def_counts);
-         useBeforeDef_Expr(bb,stmt,triop->arg2,def_counts);
-         useBeforeDef_Expr(bb,stmt,triop->arg3,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, triop->arg1, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, triop->arg2, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, triop->arg3, def_counts);
          break;
       }
       case Iex_Binop:
-         useBeforeDef_Expr(bb,stmt,expr->Iex.Binop.arg1,def_counts);
-         useBeforeDef_Expr(bb,stmt,expr->Iex.Binop.arg2,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, expr->Iex.Binop.arg1, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, expr->Iex.Binop.arg2, def_counts);
          break;
       case Iex_Unop:
-         useBeforeDef_Expr(bb,stmt,expr->Iex.Unop.arg,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, expr->Iex.Unop.arg, def_counts);
          break;
       case Iex_Load:
-         useBeforeDef_Expr(bb,stmt,expr->Iex.Load.addr,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, expr->Iex.Load.addr, def_counts);
          break;
       case Iex_Const:
          break;
@@ -3981,16 +4199,17 @@
                /* These aren't allowed in CCall lists.  Let's detect
                   and throw them out here, though, rather than
                   segfaulting a bit later on. */
-               sanityCheckFail(bb,stmt, "IRExprP__* value in CCall arg list");
+               sanityCheckFail(bb,stmt,
+                               "IRExprP__* value in CCall arg list");
             } else {
-               useBeforeDef_Expr(bb,stmt,arg,def_counts);
+               useBeforeDef_Expr(bb, stmts, stmt, arg, def_counts);
             }
          }
          break;
       case Iex_ITE:
-         useBeforeDef_Expr(bb,stmt,expr->Iex.ITE.cond,def_counts);
-         useBeforeDef_Expr(bb,stmt,expr->Iex.ITE.iftrue,def_counts);
-         useBeforeDef_Expr(bb,stmt,expr->Iex.ITE.iffalse,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, expr->Iex.ITE.cond, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, expr->Iex.ITE.iftrue, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, expr->Iex.ITE.iffalse, def_counts);
          break;
       default:
          vpanic("useBeforeDef_Expr");
@@ -3998,7 +4217,40 @@
 }
 
 static
-void useBeforeDef_Stmt ( const IRSB* bb, const IRStmt* stmt, Int* def_counts )
+void useBeforeDef_PhiNodes(const IRSB* bb, const IRStmtVec* stmts,
+                           const IRStmt* stmt, const IRPhiVec* phi_nodes,
+                           UInt* def_counts[])
+{
+   vassert(stmt->tag == Ist_IfThenElse);
+
+   for (UInt i = 0; i < phi_nodes->phis_used; i++) {
+      const IRPhi* phi = phi_nodes->phis[i];
+      useBeforeDef_Temp(bb, stmts, stmt, phi->srcThen, def_counts);
+      useBeforeDef_Temp(bb, stmts, stmt, phi->srcElse, def_counts);
+
+      /* Check also that referenced IRStmtVec's actually exist and belong to
+         "parent", "then", and "else", respectively. */
+      if (phi->dst.id != stmts->tyenv->id) {
+         sanityCheckFail(bb,stmt,"Istmt.IfThenElse.Phi.dst does not "
+                                    "reference parent IRStmtVec");
+      }
+      if (phi->srcThen.id != stmt->Ist.IfThenElse.then_leg->tyenv->id) {
+         sanityCheckFail(bb,stmt,"Istmt.IfThenElse.Phi.srcThen does not "
+                                    "reference \"then\" IRStmtVec leg");
+      }
+      if (phi->srcElse.id != stmt->Ist.IfThenElse.else_leg->tyenv->id) {
+         sanityCheckFail(bb,stmt,"Istmt.IfThenElse.Phi.srcElse does not "
+                                    "reference \"else\" IRStmtVec leg");
+      }
+   }
+}
+
+static void useBeforeDef_Stmts(const IRSB* bb, const IRStmtVec* stmts,
+                               UInt* def_counts[]);
+
+static
+void useBeforeDef_Stmt(const IRSB* bb, const IRStmtVec* stmts,
+                       const IRStmt* stmt, UInt* def_counts[])
 {
    Int       i;
    const IRDirty*  d;
@@ -4010,50 +4262,51 @@
       case Ist_IMark:
          break;
       case Ist_AbiHint:
-         useBeforeDef_Expr(bb,stmt,stmt->Ist.AbiHint.base,def_counts);
-         useBeforeDef_Expr(bb,stmt,stmt->Ist.AbiHint.nia,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, stmt->Ist.AbiHint.base, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, stmt->Ist.AbiHint.nia, def_counts);
          break;
       case Ist_Put:
-         useBeforeDef_Expr(bb,stmt,stmt->Ist.Put.data,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, stmt->Ist.Put.data, def_counts);
          break;
       case Ist_PutI:
          puti = stmt->Ist.PutI.details;
-         useBeforeDef_Expr(bb,stmt,puti->ix,def_counts);
-         useBeforeDef_Expr(bb,stmt,puti->data,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, puti->ix, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, puti->data, def_counts);
          break;
       case Ist_WrTmp:
-         useBeforeDef_Expr(bb,stmt,stmt->Ist.WrTmp.data,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, stmt->Ist.WrTmp.data, def_counts);
          break;
       case Ist_Store:
-         useBeforeDef_Expr(bb,stmt,stmt->Ist.Store.addr,def_counts);
-         useBeforeDef_Expr(bb,stmt,stmt->Ist.Store.data,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, stmt->Ist.Store.addr, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, stmt->Ist.Store.data, def_counts);
          break;
       case Ist_StoreG:
          sg = stmt->Ist.StoreG.details;
-         useBeforeDef_Expr(bb,stmt,sg->addr,def_counts);
-         useBeforeDef_Expr(bb,stmt,sg->data,def_counts);
-         useBeforeDef_Expr(bb,stmt,sg->guard,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, sg->addr, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, sg->data, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, sg->guard, def_counts);
          break;
       case Ist_LoadG:
          lg = stmt->Ist.LoadG.details;
-         useBeforeDef_Expr(bb,stmt,lg->addr,def_counts);
-         useBeforeDef_Expr(bb,stmt,lg->alt,def_counts);
-         useBeforeDef_Expr(bb,stmt,lg->guard,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, lg->addr, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, lg->alt, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, lg->guard, def_counts);
          break;
       case Ist_CAS:
          cas = stmt->Ist.CAS.details;
-         useBeforeDef_Expr(bb,stmt,cas->addr,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, cas->addr, def_counts);
          if (cas->expdHi)
-            useBeforeDef_Expr(bb,stmt,cas->expdHi,def_counts);
-         useBeforeDef_Expr(bb,stmt,cas->expdLo,def_counts);
+            useBeforeDef_Expr(bb, stmts, stmt, cas->expdHi, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, cas->expdLo, def_counts);
          if (cas->dataHi)
-            useBeforeDef_Expr(bb,stmt,cas->dataHi,def_counts);
-         useBeforeDef_Expr(bb,stmt,cas->dataLo,def_counts);
+            useBeforeDef_Expr(bb, stmts, stmt, cas->dataHi, def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, cas->dataLo, def_counts);
          break;
       case Ist_LLSC:
-         useBeforeDef_Expr(bb,stmt,stmt->Ist.LLSC.addr,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, stmt->Ist.LLSC.addr, def_counts);
          if (stmt->Ist.LLSC.storedata != NULL)
-            useBeforeDef_Expr(bb,stmt,stmt->Ist.LLSC.storedata,def_counts);
+            useBeforeDef_Expr(bb, stmts, stmt, stmt->Ist.LLSC.storedata,
+                              def_counts);
          break;
       case Ist_Dirty:
          d = stmt->Ist.Dirty.details;
@@ -4063,17 +4316,27 @@
                /* This is ensured by isFlatIRStmt */
               ;
             } else {
-               useBeforeDef_Expr(bb,stmt,arg,def_counts);
+               useBeforeDef_Expr(bb, stmts, stmt, arg, def_counts);
             }
          }
          if (d->mFx != Ifx_None)
-            useBeforeDef_Expr(bb,stmt,d->mAddr,def_counts);
+            useBeforeDef_Expr(bb, stmts, stmt, d->mAddr, def_counts);
          break;
       case Ist_NoOp:
       case Ist_MBE:
          break;
       case Ist_Exit:
-         useBeforeDef_Expr(bb,stmt,stmt->Ist.Exit.guard,def_counts);
+         useBeforeDef_Expr(bb, stmts, stmt, stmt->Ist.Exit.guard, def_counts);
+         break;
+      case Ist_IfThenElse:
+         useBeforeDef_Expr(bb, stmts, stmt, stmt->Ist.IfThenElse.cond,
+                           def_counts);
+         useBeforeDef_Stmts(bb, stmt->Ist.IfThenElse.then_leg, def_counts);
+         useBeforeDef_Stmts(bb, stmt->Ist.IfThenElse.else_leg, def_counts);
+         if (stmt->Ist.IfThenElse.phi_nodes != NULL) {
+            useBeforeDef_PhiNodes(bb, stmts, stmt,
+                                  stmt->Ist.IfThenElse.phi_nodes, def_counts);
+         }
          break;
       default:
          vpanic("useBeforeDef_Stmt");
@@ -4081,48 +4344,81 @@
 }
 
 static
-void assignedOnce_Stmt(const IRSB *bb, const IRStmt *stmt,
-                       Int *def_counts, UInt n_def_counts)
+void useBeforeDef_Stmts(const IRSB* bb, const IRStmtVec* stmts,
+                        UInt* def_counts[])
+{
+   for (UInt i = 0; i < stmts->stmts_used; i++) {
+      useBeforeDef_Stmt(bb, stmts, stmts->stmts[i], def_counts);
+   }
+}
+
+static void assignedOnce_Stmts(const IRSB* bb, const IRStmtVec* stmts,
+                               UInt* def_counts[]);
+
+static
+void assignedOnce_Stmt(const IRSB* bb, const IRStmtVec* stmts,
+                       const IRStmt* stmt, UInt* def_counts[])
 {
    switch (stmt->tag) {
    case Ist_WrTmp:
       assignedOnce_Temp(
-         bb, stmt, stmt->Ist.WrTmp.tmp, def_counts, n_def_counts,
+         bb, stmts, stmt, stmt->Ist.WrTmp.tmp, def_counts,
          "IRStmt.Tmp: destination tmp is out of range",
+         "IRStmt.Tmp: destination tmp is out of scope",
          "IRStmt.Tmp: destination tmp is assigned more than once");
       break;
    case Ist_LoadG:
       assignedOnce_Temp(
-         bb, stmt, stmt->Ist.LoadG.details->dst, def_counts, n_def_counts,
+         bb, stmts, stmt, stmt->Ist.LoadG.details->dst, def_counts,
          "IRStmt.LoadG: destination tmp is out of range",
+         "IRStmt.LoadG: destination tmp is out of scope",
          "IRStmt.LoadG: destination tmp is assigned more than once");
       break;
    case Ist_Dirty:
-      if (stmt->Ist.Dirty.details->tmp != IRTemp_INVALID) {
+      if (!isIRTempInvalid(stmt->Ist.Dirty.details->tmp)) {
          assignedOnce_Temp(
-            bb, stmt, stmt->Ist.Dirty.details->tmp, def_counts, n_def_counts,
+            bb, stmts, stmt, stmt->Ist.Dirty.details->tmp, def_counts,
             "IRStmt.Dirty: destination tmp is out of range",
+            "IRStmt.Dirty: destination tmp is out of scope",
             "IRStmt.Dirty: destination tmp is assigned more than once");
       }
       break;
    case Ist_CAS:
-      if (stmt->Ist.CAS.details->oldHi != IRTemp_INVALID) {
+      if (!isIRTempInvalid(stmt->Ist.CAS.details->oldHi)) {
          assignedOnce_Temp(
-            bb, stmt, stmt->Ist.CAS.details->oldHi, def_counts, n_def_counts,
+            bb, stmts, stmt, stmt->Ist.CAS.details->oldHi, def_counts,
             "IRStmt.CAS: destination tmpHi is out of range",
+            "IRStmt.CAS: destination tmpHi is out of scope",
             "IRStmt.CAS: destination tmpHi is assigned more than once");
       }
       assignedOnce_Temp(
-         bb, stmt, stmt->Ist.CAS.details->oldLo, def_counts, n_def_counts,
+         bb, stmts, stmt, stmt->Ist.CAS.details->oldLo, def_counts,
          "IRStmt.CAS: destination tmpLo is out of range",
+         "IRStmt.CAS: destination tmpLo is out of scope",
          "IRStmt.CAS: destination tmpLo is assigned more than once");
       break;
    case Ist_LLSC:
       assignedOnce_Temp(
-         bb, stmt, stmt->Ist.LLSC.result, def_counts, n_def_counts,
+         bb, stmts, stmt, stmt->Ist.LLSC.result, def_counts,
          "IRStmt.LLSC: destination tmp is out of range",
+         "IRStmt.LLSC: destination tmp is out of scope",
          "IRStmt.LLSC: destination tmp is assigned more than once");
       break;
+   case Ist_IfThenElse: {
+      assignedOnce_Stmts(bb, stmt->Ist.IfThenElse.then_leg, def_counts);
+      assignedOnce_Stmts(bb, stmt->Ist.IfThenElse.else_leg, def_counts);
+      const IRPhiVec* phi_nodes = stmt->Ist.IfThenElse.phi_nodes;
+      if (phi_nodes != NULL) {
+         for (UInt i = 0; i < phi_nodes->phis_used; i++) {
+            assignedOnce_Temp(
+               bb, stmts, stmt, phi_nodes->phis[i]->dst, def_counts,
+               "IRStmt.IfThenElse.Phi: destination tmp is out of range",
+               "IRStmt.IfThenElse.Phi: destination tmp is out of scope",
+               "IRStmt.IfThenElse: destination tmp is assigned more than once");
+         }
+      }
+      break;
+   }
    // Ignore all other cases
    case Ist_NoOp: case Ist_IMark: case Ist_AbiHint: case Ist_Put: case Ist_PutI:
    case Ist_Store: case Ist_StoreG: case Ist_MBE: case Ist_Exit:
@@ -4133,18 +4429,27 @@
 }
 
 static
-void tcExpr ( const IRSB* bb, const IRStmt* stmt, const IRExpr* expr,
-              IRType gWordTy )
+void assignedOnce_Stmts(const IRSB* bb, const IRStmtVec* stmts,
+                        UInt* def_counts[])
+{
+   for (UInt i = 0; i < stmts->stmts_used; i++) {
+      assignedOnce_Stmt(bb, stmts, stmts->stmts[i], def_counts);
+   }
+}
+
+static
+void tcExpr(const IRSB* bb, const IRStmtVec* stmts, const IRStmt* stmt,
+            const IRExpr* expr, IRType gWordTy)
 {
    Int        i;
    IRType     t_dst, t_arg1, t_arg2, t_arg3, t_arg4;
-   const IRTypeEnv* tyenv = bb->tyenv;
+   const IRTypeEnv* tyenv = stmts->tyenv;
    switch (expr->tag) {
       case Iex_Get:
       case Iex_RdTmp:
          break;
       case Iex_GetI:
-         tcExpr(bb,stmt, expr->Iex.GetI.ix, gWordTy );
+         tcExpr(bb, stmts, stmt, expr->Iex.GetI.ix, gWordTy);
          if (typeOfIRExpr(tyenv,expr->Iex.GetI.ix) != Ity_I32)
             sanityCheckFail(bb,stmt,"IRExpr.GetI.ix: not :: Ity_I32");
          if (!saneIRRegArray(expr->Iex.GetI.descr))
@@ -4153,10 +4458,10 @@
       case Iex_Qop: {
          IRType ttarg1, ttarg2, ttarg3, ttarg4;
          const IRQop* qop = expr->Iex.Qop.details;
-         tcExpr(bb,stmt, qop->arg1, gWordTy );
-         tcExpr(bb,stmt, qop->arg2, gWordTy );
-         tcExpr(bb,stmt, qop->arg3, gWordTy );
-         tcExpr(bb,stmt, qop->arg4, gWordTy );
+         tcExpr(bb, stmts, stmt, qop->arg1, gWordTy);
+         tcExpr(bb, stmts, stmt, qop->arg2, gWordTy);
+         tcExpr(bb, stmts, stmt, qop->arg3, gWordTy);
+         tcExpr(bb, stmts, stmt, qop->arg4, gWordTy);
          typeOfPrimop(qop->op,
                       &t_dst, &t_arg1, &t_arg2, &t_arg3, &t_arg4);
          if (t_arg1 == Ity_INVALID || t_arg2 == Ity_INVALID
@@ -4205,9 +4510,9 @@
       case Iex_Triop: {
          IRType ttarg1, ttarg2, ttarg3;
          const IRTriop *triop = expr->Iex.Triop.details;
-         tcExpr(bb,stmt, triop->arg1, gWordTy );
-         tcExpr(bb,stmt, triop->arg2, gWordTy );
-         tcExpr(bb,stmt, triop->arg3, gWordTy );
+         tcExpr(bb, stmts, stmt, triop->arg1, gWordTy);
+         tcExpr(bb, stmts, stmt, triop->arg2, gWordTy);
+         tcExpr(bb, stmts, stmt, triop->arg3, gWordTy);
          typeOfPrimop(triop->op,
                       &t_dst, &t_arg1, &t_arg2, &t_arg3, &t_arg4);
          if (t_arg1 == Ity_INVALID || t_arg2 == Ity_INVALID
@@ -4249,8 +4554,8 @@
       }
       case Iex_Binop: {
          IRType ttarg1, ttarg2;
-         tcExpr(bb,stmt, expr->Iex.Binop.arg1, gWordTy );
-         tcExpr(bb,stmt, expr->Iex.Binop.arg2, gWordTy );
+         tcExpr(bb, stmts, stmt, expr->Iex.Binop.arg1, gWordTy);
+         tcExpr(bb, stmts, stmt, expr->Iex.Binop.arg2, gWordTy);
          typeOfPrimop(expr->Iex.Binop.op,
                       &t_dst, &t_arg1, &t_arg2, &t_arg3, &t_arg4);
          if (t_arg1 == Ity_INVALID || t_arg2 == Ity_INVALID
@@ -4286,7 +4591,7 @@
          break;
       }
       case Iex_Unop:
-         tcExpr(bb,stmt, expr->Iex.Unop.arg, gWordTy );
+         tcExpr(bb, stmts, stmt, expr->Iex.Unop.arg, gWordTy);
          typeOfPrimop(expr->Iex.Unop.op,
                       &t_dst, &t_arg1, &t_arg2, &t_arg3, &t_arg4);
          if (t_arg1 == Ity_INVALID || t_arg2 != Ity_INVALID
@@ -4296,7 +4601,7 @@
             sanityCheckFail(bb,stmt,"Iex.Unop: arg ty doesn't match op ty");
          break;
       case Iex_Load:
-         tcExpr(bb,stmt, expr->Iex.Load.addr, gWordTy);
+         tcExpr(bb, stmts, stmt, expr->Iex.Load.addr, gWordTy);
          if (typeOfIRExpr(tyenv, expr->Iex.Load.addr) != gWordTy)
             sanityCheckFail(bb,stmt,"Iex.Load.addr: not :: guest word type");
          if (expr->Iex.Load.end != Iend_LE && expr->Iex.Load.end != Iend_BE)
@@ -4313,10 +4618,11 @@
             IRExpr* arg = expr->Iex.CCall.args[i];
             if (UNLIKELY(is_IRExpr_VECRET_or_GSPTR(arg)))
                sanityCheckFail(bb,stmt,"Iex.CCall.args: is VECRET/GSPTR");
-            tcExpr(bb,stmt, arg, gWordTy);
+            tcExpr(bb, stmts, stmt, arg, gWordTy);
          }
          if (expr->Iex.CCall.retty == Ity_I1)
-            sanityCheckFail(bb,stmt,"Iex.CCall.retty: cannot return :: Ity_I1");
+            sanityCheckFail(bb,stmt,
+                            "Iex.CCall.retty: cannot return :: Ity_I1");
          for (i = 0; expr->Iex.CCall.args[i]; i++)
             if (typeOfIRExpr(tyenv, expr->Iex.CCall.args[i]) == Ity_I1)
                sanityCheckFail(bb,stmt,"Iex.CCall.arg: arg :: Ity_I1");
@@ -4326,9 +4632,9 @@
             sanityCheckFail(bb,stmt,"Iex.Const.con: invalid const");
          break;
       case Iex_ITE:
-         tcExpr(bb,stmt, expr->Iex.ITE.cond, gWordTy);
-         tcExpr(bb,stmt, expr->Iex.ITE.iftrue, gWordTy);
-         tcExpr(bb,stmt, expr->Iex.ITE.iffalse, gWordTy);
+         tcExpr(bb, stmts, stmt, expr->Iex.ITE.cond, gWordTy);
+         tcExpr(bb, stmts, stmt, expr->Iex.ITE.iftrue, gWordTy);
+         tcExpr(bb, stmts, stmt, expr->Iex.ITE.iffalse, gWordTy);
          if (typeOfIRExpr(tyenv, expr->Iex.ITE.cond) != Ity_I1)
             sanityCheckFail(bb,stmt,"Iex.ITE.cond: cond :: Ity_I1");
          if (typeOfIRExpr(tyenv, expr->Iex.ITE.iftrue)
@@ -4340,13 +4646,30 @@
    }
 }
 
+static
+void tcPhi(const IRSB* bb, const IRStmtVec* stmts, const IRStmt* stmt,
+           const IRPhi* phi)
+{
+   const IRTypeEnv* tyenv = stmts->tyenv;
+   if (typeOfIRTemp(tyenv, phi->srcThen) != typeOfIRTemp(tyenv, phi->srcElse)) {
+      sanityCheckFail(bb,stmt,"IRStmt.IfThenElse.Phi: 'then' and 'else' "
+                                "tmp do not match");
+   }
+   if (typeOfIRTemp(tyenv, phi->dst) != typeOfIRTemp(tyenv, phi->srcThen)) {
+      sanityCheckFail(bb,stmt,"IRStmt.IfThenElse.Phi: 'dst' and 'then' "
+                                "tmp do not match");
+   }
+}
+
+static void tcStmts(const IRSB* bb, const IRStmtVec* stmts, Bool require_flat,
+                    IRType gWordTy);
 
 static
-void tcStmt ( const IRSB* bb, const IRStmt* stmt, IRType gWordTy )
+void tcStmt(const IRSB* bb, const IRStmtVec* stmts, const IRStmt* stmt,
+            Bool require_flat, IRType gWordTy)
 {
-   Int        i;
    IRType     tyExpd, tyData;
-   const IRTypeEnv* tyenv = bb->tyenv;
+   const IRTypeEnv* tyenv = stmts->tyenv;
    switch (stmt->tag) {
       case Ist_IMark:
          /* Somewhat heuristic, but rule out totally implausible
@@ -4365,18 +4688,18 @@
                                     "not :: guest word type");
          break;
       case Ist_Put:
-         tcExpr( bb, stmt, stmt->Ist.Put.data, gWordTy );
+         tcExpr(bb, stmts, stmt, stmt->Ist.Put.data, gWordTy);
          if (typeOfIRExpr(tyenv,stmt->Ist.Put.data) == Ity_I1)
             sanityCheckFail(bb,stmt,"IRStmt.Put.data: cannot Put :: Ity_I1");
          break;
       case Ist_PutI:{
          const IRPutI* puti = stmt->Ist.PutI.details;
-         tcExpr( bb, stmt, puti->data, gWordTy );
-         tcExpr( bb, stmt, puti->ix, gWordTy );
+         tcExpr(bb, stmts, stmt, puti->data, gWordTy);
+         tcExpr(bb, stmts, stmt, puti->ix, gWordTy);
          if (typeOfIRExpr(tyenv,puti->data) == Ity_I1)
-            sanityCheckFail(bb,stmt,"IRStmt.PutI.data: cannot PutI :: Ity_I1");
-         if (typeOfIRExpr(tyenv,puti->data)
-             != puti->descr->elemTy)
+            sanityCheckFail(bb,stmt,
+                            "IRStmt.PutI.data: cannot PutI :: Ity_I1");
+         if (typeOfIRExpr(tyenv,puti->data) != puti->descr->elemTy)
             sanityCheckFail(bb,stmt,"IRStmt.PutI.data: data ty != elem ty");
          if (typeOfIRExpr(tyenv,puti->ix) != Ity_I32)
             sanityCheckFail(bb,stmt,"IRStmt.PutI.ix: not :: Ity_I32");
@@ -4385,15 +4708,15 @@
          break;
       }
       case Ist_WrTmp:
-         tcExpr( bb, stmt, stmt->Ist.WrTmp.data, gWordTy );
+         tcExpr(bb, stmts, stmt, stmt->Ist.WrTmp.data, gWordTy);
          if (typeOfIRTemp(tyenv, stmt->Ist.WrTmp.tmp)
              != typeOfIRExpr(tyenv, stmt->Ist.WrTmp.data))
             sanityCheckFail(bb,stmt,
                             "IRStmt.Put.Tmp: tmp and expr do not match");
          break;
       case Ist_Store:
-         tcExpr( bb, stmt, stmt->Ist.Store.addr, gWordTy );
-         tcExpr( bb, stmt, stmt->Ist.Store.data, gWordTy );
+         tcExpr(bb, stmts, stmt, stmt->Ist.Store.addr, gWordTy);
+         tcExpr(bb, stmts, stmt, stmt->Ist.Store.data, gWordTy);
          if (typeOfIRExpr(tyenv, stmt->Ist.Store.addr) != gWordTy)
             sanityCheckFail(bb,stmt,
                             "IRStmt.Store.addr: not :: guest word type");
@@ -4405,9 +4728,9 @@
          break;
       case Ist_StoreG: {
          const IRStoreG* sg = stmt->Ist.StoreG.details;
-         tcExpr( bb, stmt, sg->addr, gWordTy );
-         tcExpr( bb, stmt, sg->data, gWordTy );
-         tcExpr( bb, stmt, sg->guard, gWordTy );
+         tcExpr(bb, stmts, stmt, sg->addr, gWordTy);
+         tcExpr(bb, stmts, stmt, sg->data, gWordTy);
+         tcExpr(bb, stmts, stmt, sg->guard, gWordTy);
          if (typeOfIRExpr(tyenv, sg->addr) != gWordTy)
             sanityCheckFail(bb,stmt,"IRStmtG...addr: not :: guest word type");
          if (typeOfIRExpr(tyenv, sg->data) == Ity_I1)
@@ -4420,9 +4743,9 @@
       }
       case Ist_LoadG: {
          const IRLoadG* lg = stmt->Ist.LoadG.details;
-         tcExpr( bb, stmt, lg->addr, gWordTy );
-         tcExpr( bb, stmt, lg->alt, gWordTy );
-         tcExpr( bb, stmt, lg->guard, gWordTy );
+         tcExpr(bb, stmts, stmt, lg->addr, gWordTy);
+         tcExpr(bb, stmts, stmt, lg->alt, gWordTy);
+         tcExpr(bb, stmts, stmt, lg->guard, gWordTy);
          if (typeOfIRExpr(tyenv, lg->guard) != Ity_I1)
             sanityCheckFail(bb,stmt,"IRStmt.LoadG.guard: not :: Ity_I1");
          if (typeOfIRExpr(tyenv, lg->addr) != gWordTy)
@@ -4439,12 +4762,12 @@
       case Ist_CAS: {
          const IRCAS* cas = stmt->Ist.CAS.details;
          /* make sure it's definitely either a CAS or a DCAS */
-         if (cas->oldHi == IRTemp_INVALID
+         if (isIRTempInvalid(cas->oldHi)
              && cas->expdHi == NULL && cas->dataHi == NULL) {
             /* fine; it's a single cas */
          }
          else
-         if (cas->oldHi != IRTemp_INVALID
+         if (!isIRTempInvalid(cas->oldHi)
              && cas->expdHi != NULL && cas->dataHi != NULL) {
             /* fine; it's a double cas */
          }
@@ -4453,7 +4776,7 @@
             goto bad_cas;
          }
          /* check the address type */
-         tcExpr( bb, stmt, cas->addr, gWordTy );
+         tcExpr(bb, stmts, stmt, cas->addr, gWordTy);
          if (typeOfIRExpr(tyenv, cas->addr) != gWordTy) goto bad_cas;
          /* check types on the {old,expd,data}Lo components agree */
          tyExpd = typeOfIRExpr(tyenv, cas->expdLo);
@@ -4470,7 +4793,7 @@
          }
          /* If it's a DCAS, check types on the {old,expd,data}Hi
             components too */
-         if (cas->oldHi != IRTemp_INVALID) {
+         if (!isIRTempInvalid(cas->oldHi)) {
             tyExpd = typeOfIRExpr(tyenv, cas->expdHi);
             tyData = typeOfIRExpr(tyenv, cas->dataHi);
             if (tyExpd != tyData) goto bad_cas;
@@ -4526,7 +4849,7 @@
          }
          if (d->nFxState < 0 || d->nFxState > VEX_N_FXSTATE)
             goto bad_dirty;
-         for (i = 0; i < d->nFxState; i++) {
+         for (UInt i = 0; i < d->nFxState; i++) {
             if (d->fxState[i].fx == Ifx_None) goto bad_dirty;
             if (d->fxState[i].size <= 0) goto bad_dirty;
             if (d->fxState[i].nRepeats == 0) {
@@ -4541,18 +4864,18 @@
          }
          /* check guard */
          if (d->guard == NULL) goto bad_dirty;
-         tcExpr( bb, stmt, d->guard, gWordTy );
+         tcExpr(bb, stmts, stmt, d->guard, gWordTy);
          if (typeOfIRExpr(tyenv, d->guard) != Ity_I1)
             sanityCheckFail(bb,stmt,"IRStmt.Dirty.guard not :: Ity_I1");
          /* check types, minimally */
          IRType retTy = Ity_INVALID;
-         if (d->tmp != IRTemp_INVALID) {
+         if (!isIRTempInvalid(d->tmp)) {
             retTy = typeOfIRTemp(tyenv, d->tmp);
             if (retTy == Ity_I1)
                sanityCheckFail(bb,stmt,"IRStmt.Dirty.dst :: Ity_I1");
          }
          UInt nVECRETs = 0, nGSPTRs = 0;
-         for (i = 0; d->args[i] != NULL; i++) {
+         for (UInt i = 0; d->args[i] != NULL; i++) {
             if (i >= 32)
                sanityCheckFail(bb,stmt,"IRStmt.Dirty: > 32 args");
             const IRExpr* arg = d->args[i];
@@ -4611,7 +4934,7 @@
          }
          break;
       case Ist_Exit:
-         tcExpr( bb, stmt, stmt->Ist.Exit.guard, gWordTy );
+         tcExpr(bb, stmts, stmt, stmt->Ist.Exit.guard, gWordTy);
          if (typeOfIRExpr(tyenv,stmt->Ist.Exit.guard) != Ity_I1)
             sanityCheckFail(bb,stmt,"IRStmt.Exit.guard: not :: Ity_I1");
          if (!saneIRConst(stmt->Ist.Exit.dst))
@@ -4622,77 +4945,139 @@
          if (stmt->Ist.Exit.offsIP < 16)
             sanityCheckFail(bb,stmt,"IRStmt.Exit.offsIP: too low");
          break;
+      case Ist_IfThenElse:
+         tcExpr(bb, stmts, stmt, stmt->Ist.IfThenElse.cond, gWordTy);
+         if (typeOfIRExpr(tyenv, stmt->Ist.IfThenElse.cond) != Ity_I1)
+            sanityCheckFail(bb,stmt,"IRStmt.IfThenElse.cond: not :: Ity_I1");
+         tcStmts(bb, stmt->Ist.IfThenElse.then_leg, require_flat, gWordTy);
+         tcStmts(bb, stmt->Ist.IfThenElse.else_leg, require_flat, gWordTy);
+         const IRPhiVec* phi_nodes = stmt->Ist.IfThenElse.phi_nodes;
+         if (phi_nodes != NULL) {
+            for (UInt i = 0; i < phi_nodes->phis_used; i++) {
+               tcPhi(bb, stmts, stmt, phi_nodes->phis[i]);
+            }
+         }
+         break;
       default:
          vpanic("tcStmt");
    }
 }
 
-void sanityCheckIRSB ( const IRSB* bb, const HChar* caller,
-                       Bool require_flat, IRType guest_word_size )
+static
+void tcStmts(const IRSB* bb, const IRStmtVec* stmts, Bool require_flat,
+             IRType gWordTy)
 {
-   Int     i;
-   Int     n_temps    = bb->tyenv->types_used;
-   Int*    def_counts = LibVEX_Alloc_inline(n_temps * sizeof(Int));
+   for (UInt i = 0; i < stmts->stmts_used; i++) {
+      tcStmt(bb, stmts, stmts->stmts[i], require_flat, gWordTy);
+   }
+}
 
-   if (0)
-      vex_printf("sanityCheck: %s\n", caller);
+static
+void sanityCheckIRStmtVec(const IRSB* bb, const IRStmtVec* stmts,
+                          Bool require_flat, UInt* def_counts[],
+                          UInt n_stmt_vecs, UInt id_counts[])
+{
+   const IRTypeEnv* tyenv = stmts->tyenv;
+   IRTyEnvID id = tyenv->id;
+   if (id == IRTyEnvID_INVALID) {
+      vpanic("sanityCheckIRStmtVec: invalid IRTypeEnv ID");
+   }
+
+   if (id >= n_stmt_vecs) {
+      vex_printf("IRTypeEnv's ID (%u) is larger than number of IRStmtVec's "
+                 "(%u)\n", id, n_stmt_vecs);
+      sanityCheckFail(bb, NULL, "IRTypeEnv's ID larger than number of "
+                                "IRStmtVec's");
+   }
 
-   vassert(guest_word_size == Ity_I32
-           || guest_word_size == Ity_I64);
+   id_counts[id] += 1;
+   if (id_counts[id] > 1) {
+      sanityCheckFail(bb, NULL, "the same IRTyEnv ID used more than once");
+   }
+
+   UInt n_temps = tyenv->types_used;
+   def_counts[id] = LibVEX_Alloc_inline(n_temps * sizeof(UInt));
+   for (UInt i = 0; i < n_temps; i++)
+      def_counts[id][i] = 0;
 
-   if (bb->stmts_used < 0 || bb->stmts_size < 8
-       || bb->stmts_used > bb->stmts_size)
-      /* this BB is so strange we can't even print it */
-      vpanic("sanityCheckIRSB: stmts array limits wierd");
+   if (stmts->stmts_used < 0 || stmts->stmts_size < 8
+       || stmts->stmts_used > stmts->stmts_size) {
+      /* this IRStmtVec is so strange we can't even print it */
+      vpanic("sanityCheckIRStmtVec: stmts array limits wierd");
+   }
 
    /* Ensure each temp has a plausible type. */
-   for (i = 0; i < n_temps; i++) {
-      IRType ty = typeOfIRTemp(bb->tyenv,(IRTemp)i);
+   for (UInt i = 0; i < n_temps; i++) {
+      IRTemp temp = {id, i};
+      IRType ty = typeOfIRTemp(tyenv, temp);
       if (!isPlausibleIRType(ty)) {
-         vex_printf("Temp t%d declared with implausible type 0x%x\n",
-                    i, (UInt)ty);
-         sanityCheckFail(bb,NULL,"Temp declared with implausible type");
+         vex_printf("Temp ");
+         ppIRTemp(temp);
+         vex_printf(" declared with implausible type 0x%x\n", (UInt) ty);
+         sanityCheckFail(bb, NULL, "Temp declared with implausible type");
       }
    }
 
-   const IRStmt* stmt;
-
    /* Check for flatness, if required. */
    if (require_flat) {
-      for (i = 0; i < bb->stmts_used; i++) {
-         stmt = bb->stmts[i];
-         if (!stmt)
-            sanityCheckFail(bb, stmt, "IRStmt: is NULL");
+      for (UInt i = 0; i < stmts->stmts_used; i++) {
+         const IRStmt *stmt = stmts->stmts[i];
+         if (stmt == NULL)
+            sanityCheckFail(bb,stmt,"IRStmt: is NULL");
          if (!isFlatIRStmt(stmt))
-            sanityCheckFail(bb, stmt, "IRStmt: is not flat");
+            sanityCheckFail(bb,stmt,"IRStmt: is not flat");
+         if (stmt->tag == Ist_IfThenElse) {
+            sanityCheckIRStmtVec(bb, stmt->Ist.IfThenElse.then_leg,
+                              require_flat, def_counts, n_stmt_vecs, id_counts);
+            sanityCheckIRStmtVec(bb, stmt->Ist.IfThenElse.else_leg,
+                              require_flat, def_counts, n_stmt_vecs, id_counts);
+         }
       }
-      if (!isIRAtom(bb->next))
-         sanityCheckFail(bb, NULL, "bb->next is not an atom");
    }
+}
+
+
+/* Sanity checks basic block of IR.
+   Also checks for IRTyEnvID uniqueness. */
+void sanityCheckIRSB(const IRSB* bb, const  HChar* caller, Bool require_flat,
+                     IRType gWordTy)
+{
+   UInt n_stmt_vecs = bb->id_seq;
+   UInt **def_counts = LibVEX_Alloc_inline(n_stmt_vecs * sizeof(UInt *));
+   UInt *id_counts = LibVEX_Alloc_inline(n_stmt_vecs * sizeof(UInt));
+   for (UInt i = 0; i < n_stmt_vecs; i++) {
+      def_counts[i] = NULL;
+      id_counts[i] = 0;
+   }
+
+   if (0)
+      vex_printf("sanityCheck: %s\n", caller);
+
+   vassert(gWordTy == Ity_I32 || gWordTy == Ity_I64);
+
+   sanityCheckIRStmtVec(bb, bb->stmts, require_flat, def_counts, n_stmt_vecs,
+                        id_counts);
 
    /* Count the defs of each temp.  Only one def is allowed.
       Also, check that each used temp has already been defd. */
+   useBeforeDef_Stmts(bb, bb->stmts, def_counts);
+   assignedOnce_Stmts(bb, bb->stmts, def_counts);
+   tcStmts(bb, bb->stmts, require_flat, gWordTy);
 
-   for (i = 0; i < n_temps; i++)
-      def_counts[i] = 0;
+   if (require_flat) {
+      if (!isIRAtom(bb->next)) {
+         sanityCheckFail(bb, NULL, "bb->next is not an atom");
+      }
+   }
 
-   for (i = 0; i < bb->stmts_used; i++) {
-      stmt = bb->stmts[i];
-      /* Check any temps used by this statement. */
-      useBeforeDef_Stmt(bb,stmt,def_counts);
-
-      /* Now make note of any temps defd by this statement. */
-      assignedOnce_Stmt(bb, stmt, def_counts, n_temps);
-   }
-
-   /* Typecheck everything. */
-   for (i = 0; i < bb->stmts_used; i++)
-      tcStmt(bb, bb->stmts[i], guest_word_size);
-   if (typeOfIRExpr(bb->tyenv,bb->next) != guest_word_size)
+   /* Typecheck also next destination. */
+   if (typeOfIRExpr(bb->stmts->tyenv, bb->next) != gWordTy) {
       sanityCheckFail(bb, NULL, "bb->next field has wrong type");
+   }
    /* because it would intersect with host_EvC_* */
-   if (bb->offsIP < 16)
+   if (bb->offsIP < 16) {
       sanityCheckFail(bb, NULL, "bb->offsIP: too low");
+   }
 }
 
 /*---------------------------------------------------------------*/
@@ -4805,7 +5190,7 @@
    vassert(isIRAtom(a1));
    vassert(isIRAtom(a2));
    if (a1->tag == Iex_RdTmp && a2->tag == Iex_RdTmp)
-      return toBool(a1->Iex.RdTmp.tmp == a2->Iex.RdTmp.tmp);
+      return eqIRTemp(a1->Iex.RdTmp.tmp, a2->Iex.RdTmp.tmp);
    if (a1->tag == Iex_Const && a2->tag == Iex_Const)
       return eqIRConst(a1->Iex.Const.con, a2->Iex.Const.con);
    return False;

Modified: branches/VEX_JIT_HACKS/priv/ir_inject.c
==============================================================================
--- branches/VEX_JIT_HACKS/priv/ir_inject.c (original)
+++ branches/VEX_JIT_HACKS/priv/ir_inject.c Sat Mar 11 14:07:07 2017
@@ -43,7 +43,7 @@
 #define binop(kind, a1, a2)  IRExpr_Binop(kind, a1, a2)
 #define triop(kind, a1, a2, a3)  IRExpr_Triop(kind, a1, a2, a3)
 #define qop(kind, a1, a2, a3, a4)  IRExpr_Qop(kind, a1, a2, a3, a4)
-#define stmt(irsb, st)  addStmtToIRSB(irsb, st)
+#define stmt(irsb, st)  addStmtToIRStmtVec(irsb->stmts, st)
 
 
 /* The IR Injection Control Block. vex_inject_ir will query its contents
@@ -125,13 +125,13 @@
 static void
 store_aux(IRSB *irsb, IREndness endian, IRExpr *addr, IRExpr *data)
 {
-   if (typeOfIRExpr(irsb->tyenv, data) == Ity_D64) {
+   if (typeOfIRExpr(irsb->stmts->tyenv, data) == Ity_D64) {
       /* The insn selectors do not support writing a DFP value to memory.
          So we need to fix it here by reinterpreting the DFP value as an
          integer and storing that. */
       data = unop(Iop_ReinterpD64asI64, data);
    }
-   if (typeOfIRExpr(irsb->tyenv, data) == Ity_I1) {
+   if (typeOfIRExpr(irsb->stmts->tyenv, data) == Ity_I1) {
       /* We cannot store a single bit. So we store it in a 32-bit container.
          See also load_aux. */
       data = unop(Iop_1Uto32, data);
@@ -158,7 +158,7 @@
       vpanic("invalid #bytes for address");
    }
 
-   IRType type = typeOfIRExpr(irsb->tyenv, data);
+   IRType type = typeOfIRExpr(irsb->stmts->tyenv, data);
 
    vassert(type == Ity_I1 || sizeofIRType(type) <= 16);
 
@@ -188,7 +188,7 @@
 
 
 /* Inject IR stmts depending on the data provided in the control
-   block iricb. */
+   block iricb. IR statements are injected into main IRStmtVec with ID #0. */
 void
 vex_inject_ir(IRSB *irsb, IREndness endian)
 {
@@ -310,11 +310,11 @@
    if (0) {
       vex_printf("BEGIN inject\n");
       if (iricb.t_result == Ity_I1 || sizeofIRType(iricb.t_result) <= 8) {
-         ppIRStmt(irsb->stmts[irsb->stmts_used - 1]);
+         ppIRStmt(irsb->stmts->stmts[irsb->stmts->stmts_used - 1]);
       } else if (sizeofIRType(iricb.t_result) == 16) {
-         ppIRStmt(irsb->stmts[irsb->stmts_used - 2]);
+         ppIRStmt(irsb->stmts->stmts[irsb->stmts->stmts_used - 2]);
          vex_printf("\n");
-         ppIRStmt(irsb->stmts[irsb->stmts_used - 1]);
+         ppIRStmt(irsb->stmts->stmts[irsb->stmts->stmts_used - 1]);
       }
       vex_printf("\nEND inject\n");
    }

Modified: branches/VEX_JIT_HACKS/priv/ir_opt.c
==============================================================================
--- branches/VEX_JIT_HACKS/priv/ir_opt.c (original)
+++ branches/VEX_JIT_HACKS/priv/ir_opt.c Sat Mar 11 14:07:07 2017
@@ -266,7 +266,7 @@
 /* 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 )
+static Bool isFlat(const IRExpr* e)
 {
    if (e->tag == Iex_Get)
       return True;
@@ -280,102 +280,102 @@
 
 /* Flatten out 'ex' so it is atomic, returning a new expression with
    the same value, after having appended extra IRTemp assignments to
-   the end of 'bb'. */
+   the end of 'stmts'. */
 
-static IRExpr* flatten_Expr ( IRSB* bb, IRExpr* ex )
+static IRExpr* flatten_Expr(IRStmtVec* stmts, IRExpr* ex)
 {
    Int i;
    IRExpr** newargs;
-   IRType ty = typeOfIRExpr(bb->tyenv, ex);
+   IRTypeEnv* tyenv = stmts->tyenv;
+   IRType ty = typeOfIRExpr(tyenv, ex);
    IRTemp t1;
 
    switch (ex->tag) {
 
       case Iex_GetI:
-         t1 = newIRTemp(bb->tyenv, ty);
-         addStmtToIRSB(bb, IRStmt_WrTmp(t1,
+         t1 = newIRTemp(tyenv, ty);
+         addStmtToIRStmtVec(stmts, IRStmt_WrTmp(t1,
             IRExpr_GetI(ex->Iex.GetI.descr,
-                        flatten_Expr(bb, ex->Iex.GetI.ix),
+                        flatten_Expr(stmts, ex->Iex.GetI.ix),
                         ex->Iex.GetI.bias)));
          return IRExpr_RdTmp(t1);
 
       case Iex_Get:
-         t1 = newIRTemp(bb->tyenv, ty);
-         addStmtToIRSB(bb,
-            IRStmt_WrTmp(t1, ex));
+         t1 = newIRTemp(tyenv, ty);
+         addStmtToIRStmtVec(stmts, IRStmt_WrTmp(t1, ex));
          return IRExpr_RdTmp(t1);
 
       case Iex_Qop: {
          IRQop* qop = ex->Iex.Qop.details;
-         t1 = newIRTemp(bb->tyenv, ty);
-         addStmtToIRSB(bb, IRStmt_WrTmp(t1,
+         t1 = newIRTemp(tyenv, ty);
+         addStmtToIRStmtVec(stmts, IRStmt_WrTmp(t1,
             IRExpr_Qop(qop->op,
-                         flatten_Expr(bb, qop->arg1),
-                         flatten_Expr(bb, qop->arg2),
-                         flatten_Expr(bb, qop->arg3),
-                         flatten_Expr(bb, qop->arg4))));
+                         flatten_Expr(stmts, qop->arg1),
+                         flatten_Expr(stmts, qop->arg2),
+                         flatten_Expr(stmts, qop->arg3),
+                         flatten_Expr(stmts, qop->arg4))));
          return IRExpr_RdTmp(t1);
       }
 
       case Iex_Triop: {
          IRTriop* triop = ex->Iex.Triop.details;
-         t1 = newIRTemp(bb->tyenv, ty);
-         addStmtToIRSB(bb, IRStmt_WrTmp(t1,
+         t1 = newIRTemp(tyenv, ty);
+         addStmtToIRStmtVec(stmts, IRStmt_WrTmp(t1,
             IRExpr_Triop(triop->op,
-                         flatten_Expr(bb, triop->arg1),
-                         flatten_Expr(bb, triop->arg2),
-                         flatten_Expr(bb, triop->arg3))));
+                         flatten_Expr(stmts, triop->arg1),
+                         flatten_Expr(stmts, triop->arg2),
+                         flatten_Expr(stmts, triop->arg3))));
          return IRExpr_RdTmp(t1);
       }
 
       case Iex_Binop:
-         t1 = newIRTemp(bb->tyenv, ty);
-         addStmtToIRSB(bb, IRStmt_WrTmp(t1,
+         t1 = newIRTemp(tyenv, ty);
+         addStmtToIRStmtVec(stmts, IRStmt_WrTmp(t1,
             IRExpr_Binop(ex->Iex.Binop.op,
-                         flatten_Expr(bb, ex->Iex.Binop.arg1),
-                         flatten_Expr(bb, ex->Iex.Binop.arg2))));
+                         flatten_Expr(stmts, ex->Iex.Binop.arg1),
+                         flatten_Expr(stmts, ex->Iex.Binop.arg2))));
          return IRExpr_RdTmp(t1);
 
       case Iex_Unop:
-         t1 = newIRTemp(bb->tyenv, ty);
-         addStmtToIRSB(bb, IRStmt_WrTmp(t1,
+         t1 = newIRTemp(tyenv, ty);
+         addStmtToIRStmtVec(stmts, IRStmt_WrTmp(t1,
             IRExpr_Unop(ex->Iex.Unop.op,
-                        flatten_Expr(bb, ex->Iex.Unop.arg))));
+                        flatten_Expr(stmts, ex->Iex.Unop.arg))));
          return IRExpr_RdTmp(t1);
 
       case Iex_Load:
-         t1 = newIRTemp(bb->tyenv, ty);
-         addStmtToIRSB(bb, IRStmt_WrTmp(t1,
+         t1 = newIRTemp(tyenv, ty);
+         addStmtToIRStmtVec(stmts, IRStmt_WrTmp(t1,
             IRExpr_Load(ex->Iex.Load.end,
                         ex->Iex.Load.ty,
-                        flatten_Expr(bb, ex->Iex.Load.addr))));
+                        flatten_Expr(stmts, ex->Iex.Load.addr))));
          return IRExpr_RdTmp(t1);
 
       case Iex_CCall:
          newargs = shallowCopyIRExprVec(ex->Iex.CCall.args);
          for (i = 0; newargs[i]; i++)
-            newargs[i] = flatten_Expr(bb, newargs[i]);
-         t1 = newIRTemp(bb->tyenv, ty);
-         addStmtToIRSB(bb, IRStmt_WrTmp(t1,
+            newargs[i] = flatten_Expr(stmts, newargs[i]);
+         t1 = newIRTemp(tyenv, ty);
+         addStmtToIRStmtVec(stmts, IRStmt_WrTmp(t1,
             IRExpr_CCall(ex->Iex.CCall.cee,
                          ex->Iex.CCall.retty,
                          newargs)));
          return IRExpr_RdTmp(t1);
 
       case Iex_ITE:
-         t1 = newIRTemp(bb->tyenv, ty);
-         addStmtToIRSB(bb, IRStmt_WrTmp(t1,
-            IRExpr_ITE(flatten_Expr(bb, ex->Iex.ITE.cond),
-                       flatten_Expr(bb, ex->Iex.ITE.iftrue),
-                       flatten_Expr(bb, ex->Iex.ITE.iffalse))));
+         t1 = newIRTemp(tyenv, ty);
+         addStmtToIRStmtVec(stmts, IRStmt_WrTmp(t1,
+            IRExpr_ITE(flatten_Expr(stmts, ex->Iex.ITE.cond),
+                       flatten_Expr(stmts, ex->Iex.ITE.iftrue),
+                       flatten_Expr(stmts, ex->Iex.ITE.iffalse))));
          return IRExpr_RdTmp(t1);
 
       case Iex_Const:
          /* Lift F64i constants out onto temps so they can be CSEd
             later. */
          if (ex->Iex.Const.con->tag == Ico_F64i) {
-            t1 = newIRTemp(bb->tyenv, ty);
-            addStmtToIRSB(bb, IRStmt_WrTmp(t1,
+            t1 = newIRTemp(tyenv, ty);
+            addStmtToIRStmtVec(stmts, IRStmt_WrTmp(t1,
                IRExpr_Const(ex->Iex.Const.con)));
             return IRExpr_RdTmp(t1);
          } else {
@@ -394,10 +394,10 @@
    }
 }
 
+static IRStmtVec* flatten_IRStmtVec(IRStmtVec* in, IRStmtVec* parent);
 
-/* Append a completely flattened form of 'st' to the end of 'bb'. */
-
-static void flatten_Stmt ( IRSB* bb, IRStmt* st )
+/* Append a completely flattened form of 'st' to the end of 'stmts'. */
+static void flatten_Stmt(IRStmtVec* stmts, IRStmt* st, IRStmtVec* parent)
 {
    Int i;
    IRExpr   *e1, *e2, *e3, *e4, *e5;
@@ -411,69 +411,69 @@
          if (isIRAtom(st->Ist.Put.data)) {
             /* optimisation to reduce the amount of heap wasted
                by the flattener */
-            addStmtToIRSB(bb, st);
+            addStmtToIRStmtVec(stmts, st);
          } else {
             /* general case, always correct */
-            e1 = flatten_Expr(bb, st->Ist.Put.data);
-            addStmtToIRSB(bb, IRStmt_Put(st->Ist.Put.offset, e1));
+            e1 = flatten_Expr(stmts, st->Ist.Put.data);
+            addStmtToIRStmtVec(stmts, IRStmt_Put(st->Ist.Put.offset, e1));
          }
          break;
       case Ist_PutI:
          puti = st->Ist.PutI.details;
-         e1 = flatten_Expr(bb, puti->ix);
-         e2 = flatten_Expr(bb, puti->data);
+         e1 = flatten_Expr(stmts, puti->ix);
+         e2 = flatten_Expr(stmts, puti->data);
          puti2 = mkIRPutI(puti->descr, e1, puti->bias, e2);
-         addStmtToIRSB(bb, IRStmt_PutI(puti2));
+         addStmtToIRStmtVec(stmts, IRStmt_PutI(puti2));
          break;
       case Ist_WrTmp:
          if (isFlat(st->Ist.WrTmp.data)) {
             /* optimisation, to reduce the number of tmp-tmp
                copies generated */
-            addStmtToIRSB(bb, st);
+            addStmtToIRStmtVec(stmts, st);
          } else {
             /* general case, always correct */
-            e1 = flatten_Expr(bb, st->Ist.WrTmp.data);
-            addStmtToIRSB(bb, IRStmt_WrTmp(st->Ist.WrTmp.tmp, e1));
+            e1 = flatten_Expr(stmts, st->Ist.WrTmp.data);
+            addStmtToIRStmtVec(stmts, IRStmt_WrTmp(st->Ist.WrTmp.tmp, e1));
          }
          break;
       case Ist_Store:
-         e1 = flatten_Expr(bb, st->Ist.Store.addr);
-         e2 = flatten_Expr(bb, st->Ist.Store.data);
-         addStmtToIRSB(bb, IRStmt_Store(st->Ist.Store.end, e1,e2));
+         e1 = flatten_Expr(stmts, st->Ist.Store.addr);
+         e2 = flatten_Expr(stmts, st->Ist.Store.data);
+         addStmtToIRStmtVec(stmts, IRStmt_Store(st->Ist.Store.end, e1,e2));
          break;
       case Ist_StoreG:
          sg = st->Ist.StoreG.details;
-         e1 = flatten_Expr(bb, sg->addr);
-         e2 = flatten_Expr(bb, sg->data);
-         e3 = flatten_Expr(bb, sg->guard);
-         addStmtToIRSB(bb, IRStmt_StoreG(sg->end, e1, e2, e3));
+         e1 = flatten_Expr(stmts, sg->addr);
+         e2 = flatten_Expr(stmts, sg->data);
+         e3 = flatten_Expr(stmts, sg->guard);
+         addStmtToIRStmtVec(stmts, IRStmt_StoreG(sg->end, e1, e2, e3));
          break;
       case Ist_LoadG:
          lg = st->Ist.LoadG.details;
-         e1 = flatten_Expr(bb, lg->addr);
-         e2 = flatten_Expr(bb, lg->alt);
-         e3 = flatten_Expr(bb, lg->guard);
-         addStmtToIRSB(bb, IRStmt_LoadG(lg->end, lg->cvt, lg->dst,
-                                        e1, e2, e3));
+         e1 = flatten_Expr(stmts, lg->addr);
+         e2 = flatten_Expr(stmts, lg->alt);
+         e3 = flatten_Expr(stmts, lg->guard);
+         addStmtToIRStmtVec(stmts, IRStmt_LoadG(lg->end, lg->cvt, lg->dst,
+                                                e1, e2, e3));
          break;
       case Ist_CAS:
          cas  = st->Ist.CAS.details;
-         e1   = flatten_Expr(bb, cas->addr);
-         e2   = cas->expdHi ? flatten_Expr(bb, cas->expdHi) : NULL;
-         e3   = flatten_Expr(bb, cas->expdLo);
-         e4   = cas->dataHi ? flatten_Expr(bb, cas->dataHi) : NULL;
-         e5   = flatten_Expr(bb, cas->dataLo);
+         e1   = flatten_Expr(stmts, cas->addr);
+         e2   = cas->expdHi ? flatten_Expr(stmts, cas->expdHi) : NULL;
+         e3   = flatten_Expr(stmts, cas->expdLo);
+         e4   = cas->dataHi ? flatten_Expr(stmts, cas->dataHi) : NULL;
+         e5   = flatten_Expr(stmts, cas->dataLo);
          cas2 = mkIRCAS( cas->oldHi, cas->oldLo, cas->end,
                          e1, e2, e3, e4, e5 );
-         addStmtToIRSB(bb, IRStmt_CAS(cas2));
+         addStmtToIRStmtVec(stmts, IRStmt_CAS(cas2));
          break;
       case Ist_LLSC:
-         e1 = flatten_Expr(bb, st->Ist.LLSC.addr);
+         e1 = flatten_Expr(stmts, st->Ist.LLSC.addr);
          e2 = st->Ist.LLSC.storedata
-                 ? flatten_Expr(bb, st->Ist.LLSC.storedata)
+                 ? flatten_Expr(stmts, st->Ist.LLSC.storedata)
                  : NULL;
-         addStmtToIRSB(bb, IRStmt_LLSC(st->Ist.LLSC.end,
-                                       st->Ist.LLSC.result, e1, e2));
+         addStmtToIRStmtVec(stmts, IRStmt_LLSC(st->Ist.LLSC.end,
+                                               st->Ist.LLSC.result, e1, e2));
          break;
       case Ist_Dirty:
          d = st->Ist.Dirty.details;
@@ -481,33 +481,40 @@
          *d2 = *d;
          d2->args = shallowCopyIRExprVec(d2->args);
          if (d2->mFx != Ifx_None) {
-            d2->mAddr = flatten_Expr(bb, d2->mAddr);
+            d2->mAddr = flatten_Expr(stmts, d2->mAddr);
          } else {
             vassert(d2->mAddr == NULL);
          }
-         d2->guard = flatten_Expr(bb, d2->guard);
+         d2->guard = flatten_Expr(stmts, d2->guard);
          for (i = 0; d2->args[i]; i++) {
             IRExpr* arg = d2->args[i];
             if (LIKELY(!is_IRExpr_VECRET_or_GSPTR(arg)))
-               d2->args[i] = flatten_Expr(bb, arg);
+               d2->args[i] = flatten_Expr(stmts, arg);
          }
-         addStmtToIRSB(bb, IRStmt_Dirty(d2));
+         addStmtToIRStmtVec(stmts, IRStmt_Dirty(d2));
          break;
       case Ist_NoOp:
       case Ist_MBE:
       case Ist_IMark:
-         addStmtToIRSB(bb, st);
+         addStmtToIRStmtVec(stmts, st);
          break;
       case Ist_AbiHint:
-         e1 = flatten_Expr(bb, st->Ist.AbiHint.base);
-         e2 = flatten_Expr(bb, st->Ist.AbiHint.nia);
-         addStmtToIRSB(bb, IRStmt_AbiHint(e1, st->Ist.AbiHint.len, e2));
+         e1 = flatten_Expr(stmts, st->Ist.AbiHint.base);
+         e2 = flatten_Expr(stmts, st->Ist.AbiHint.nia);
+         addStmtToIRStmtVec(stmts, IRStmt_AbiHint(e1, st->Ist.AbiHint.len, e2));
          break;
       case Ist_Exit:
-         e1 = flatten_Expr(bb, st->Ist.Exit.guard);
-         addStmtToIRSB(bb, IRStmt_Exit(e1, st->Ist.Exit.jk,
-                                       st->Ist.Exit.dst,
-                                       st->Ist.Exit.offsIP));
+         e1 = flatten_Expr(stmts, st->Ist.Exit.guard);
+         addStmtToIRStmtVec(stmts, IRStmt_Exit(e1, st->Ist.Exit.jk,
+                                               st->Ist.Exit.dst,
+                                               st->Ist.Exit.offsIP));
+         break;
+      case Ist_IfThenElse:
+         e1 = flatten_Expr(stmts, st->Ist.IfThenElse.cond);
+         addStmtToIRStmtVec(stmts, IRStmt_IfThenElse(e1,
+                         flatten_IRStmtVec(st->Ist.IfThenElse.then_leg, parent),
+                         flatten_IRStmtVec(st->Ist.IfThenElse.else_leg, parent),
+                         st->Ist.IfThenElse.phi_nodes));
          break;
       default:
          vex_printf("\n");
@@ -517,17 +524,22 @@
    }
 }
 
+static IRStmtVec* flatten_IRStmtVec(IRStmtVec* in, IRStmtVec* parent)
+{
+   IRStmtVec* out = emptyIRStmtVec();
+   out->tyenv     = deepCopyIRTypeEnv(in->tyenv);
+   out->parent    = parent;
+   for (UInt i = 0; i < in->stmts_used; i++) {
+      flatten_Stmt(out, in->stmts[i], out);
+   }
+   return out;
+}
 
 static IRSB* flatten_BB ( IRSB* in )
 {
-   Int   i;
-   IRSB* out;
-   out = emptyIRSB();
-   out->tyenv = deepCopyIRTypeEnv( in->tyenv );
-   for (i = 0; i < in->stmts_used; i++)
-      if (in->stmts[i])
-         flatten_Stmt( out, in->stmts[i] );
-   out->next     = flatten_Expr( out, in->next );
+   IRSB* out     = emptyIRSB();
+   out->stmts    = flatten_IRStmtVec(in->stmts, NULL);
+   out->next     = flatten_Expr(out->stmts, in->next);
    out->jumpkind = in->jumpkind;
    out->offsIP   = in->offsIP;
    return out;
@@ -610,16 +622,15 @@
    }
 }
 
-
-static void redundant_get_removal_BB ( IRSB* bb )
+static void redundant_get_removal_IRStmtVec(IRStmtVec* stmts)
 {
    HashHW* env = newHHW();
    UInt    key = 0; /* keep gcc -O happy */
-   Int     i, j;
+   Int     j;
    HWord   val;
 
-   for (i = 0; i < bb->stmts_used; i++) {
-      IRStmt* st = bb->stmts[i];
+   for (UInt i = 0; i < stmts->stmts_used; i++) {
+      IRStmt* st = stmts->stmts[i];
 
       if (st->tag == Ist_NoOp)
          continue;
@@ -640,7 +651,7 @@
                be to stick in a reinterpret-style cast, although that
                would make maintaining flatness more difficult. */
             IRExpr* valE    = (IRExpr*)val;
-            Bool    typesOK = toBool( typeOfIRExpr(bb->tyenv,valE)
+            Bool    typesOK = toBool( typeOfIRExpr(stmts->tyenv,valE)
                                       == st->Ist.WrTmp.data->Iex.Get.ty );
             if (typesOK && DEBUG_IROPT) {
                vex_printf("rGET: "); ppIRExpr(get);
@@ -648,7 +659,7 @@
                vex_printf("\n");
             }
             if (typesOK)
-               bb->stmts[i] = IRStmt_WrTmp(st->Ist.WrTmp.tmp, valE);
+               stmts->stmts[i] = IRStmt_WrTmp(st->Ist.WrTmp.tmp, valE);
          } else {
             /* Not found, but at least we know that t and the Get(...)
                are now associated.  So add a binding to reflect that
@@ -664,7 +675,7 @@
          UInt k_lo, k_hi;
          if (st->tag == Ist_Put) {
             key = mk_key_GetPut( st->Ist.Put.offset,
-                                 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
+                                 typeOfIRExpr(stmts->tyenv,st->Ist.Put.data) );
          } else {
             vassert(st->tag == Ist_PutI);
             key = mk_key_GetIPutI( st->Ist.PutI.details->descr );
@@ -700,8 +711,18 @@
          addToHHW( env, (HWord)key, (HWord)(st->Ist.Put.data));
       }
 
-   } /* for (i = 0; i < bb->stmts_used; i++) */
+      if (st->tag == Ist_IfThenElse) {
+         /* Consider "then" and "else" legs in isolation. */
+         redundant_get_removal_IRStmtVec(st->Ist.IfThenElse.then_leg);
+         redundant_get_removal_IRStmtVec(st->Ist.IfThenElse.else_leg);
+      }
 
+   } /* for (UInt i = 0; i < stmts->stmts_used; i++) */
+}
+
+static void redundant_get_removal_BB(IRSB* bb)
+{
+   redundant_get_removal_IRStmtVec(bb->stmts);
 }
 
 
@@ -713,8 +734,8 @@
    overlapping ranges listed in env.  Due to the flattening phase, the
    only stmt kind we expect to find a Get on is IRStmt_WrTmp. */
 
-static void handle_gets_Stmt (
-               HashHW* env,
+static void handle_gets_Stmt (
+               HashHW* env,
                IRStmt* st,
                Bool (*preciseMemExnsFn)(Int,Int,VexRegisterUpdates),
                VexRegisterUpdates pxControl
@@ -817,6 +838,11 @@
       case Ist_IMark:
          break;
 
+      case Ist_IfThenElse:
+         /* Recursing into "then" and "else" branches is done in
+            redundant_put_removal_IRStmtVec() */
+         break;
+
       default:
          vex_printf("\n");
          ppIRStmt(st);
@@ -882,30 +908,17 @@
    and loads/stores.
 */
 
-static void redundant_put_removal_BB (
-               IRSB* bb,
+static void redundant_put_removal_IRStmtVec(
+               IRStmtVec* stmts,
                Bool (*preciseMemExnsFn)(Int,Int,VexRegisterUpdates),
-               VexRegisterUpdates pxControl
-            )
+               VexRegisterUpdates pxControl,
+               HashHW* env)
 {
-   Int     i, j;
-   Bool    isPut;
-   IRStmt* st;
-   UInt    key = 0; /* keep gcc -O happy */
-
-   vassert(pxControl < VexRegUpdAllregsAtEachInsn);
-
-   HashHW* env = newHHW();
-
-   /* Initialise the running env with the fact that the final exit
-      writes the IP (or, whatever it claims to write.  We don't
-      care.) */
-   key = mk_key_GetPut(bb->offsIP, typeOfIRExpr(bb->tyenv, bb->next));
-   addToHHW(env, (HWord)key, 0);
-
    /* And now scan backwards through the statements. */
-   for (i = bb->stmts_used-1; i >= 0; i--) {
-      st = bb->stmts[i];
+   for (UInt i = stmts->stmts_used - 1; i >= 0; i--) {
+      IRStmt* st = stmts->stmts[i];
+      Bool    isPut;
+      UInt    key;
 
       if (st->tag == Ist_NoOp)
          continue;
@@ -933,7 +946,7 @@
          //                    typeOfIRConst(st->Ist.Exit.dst));
          //re_add = lookupHHW(env, NULL, key);
          /* (2) */
-         for (j = 0; j < env->used; j++)
+         for (UInt j = 0; j < env->used; j++)
             env->inuse[j] = False;
          /* (3) */
          //if (0 && re_add)
@@ -946,7 +959,7 @@
          case Ist_Put:
             isPut = True;
             key = mk_key_GetPut( st->Ist.Put.offset,
-                                 typeOfIRExpr(bb->tyenv,st->Ist.Put.data) );
+                                 typeOfIRExpr(stmts->tyenv,st->Ist.Put.data) );
             vassert(isIRAtom(st->Ist.Put.data));
             break;
          case Ist_PutI:
@@ -971,7 +984,7 @@
                vex_printf("rPUT: "); ppIRStmt(st);
                vex_printf("\n");
             }
-            bb->stmts[i] = IRStmt_NoOp();
+            stmts->stmts[i] = IRStmt_NoOp();
          } else {
             /* We can't demonstrate that this Put is redundant, so add it
                to the running collection. */
@@ -986,9 +999,36 @@
          deals with implicit reads of guest state needed to maintain
          precise exceptions. */
       handle_gets_Stmt( env, st, preciseMemExnsFn, pxControl );
+
+      /* Consider "then" and "else" legs in isolation. They get a new env. */
+      if (st->tag == Ist_IfThenElse) {
+         redundant_put_removal_IRStmtVec(st->Ist.IfThenElse.then_leg,
+                                         preciseMemExnsFn, pxControl, newHHW());
+         redundant_put_removal_IRStmtVec(st->Ist.IfThenElse.else_leg,
+                                         preciseMemExnsFn, pxControl, newHHW());
+      }
    }
 }
 
+static void redundant_put_removal_BB(
+               IRSB* bb,
+               Bool (*preciseMemExnsFn)(Int,Int,VexRegisterUpdates),
+               VexRegisterUpdates pxControl)
+{
+   vassert(pxControl < VexRegUpdAllregsAtEachInsn);
+
+   HashHW* env = newHHW();
+
+   /* Initialise the running env with the fact that the final exit
+      writes the IP (or, whatever it claims to write.  We don't
+      care.) */
+   UInt key = mk_key_GetPut(bb->offsIP,
+                            typeOfIRExpr(bb->stmts->tyenv, bb->next));
+   addToHHW(env, (HWord)key, 0);
+
+   redundant_put_removal_IRStmtVec(bb->stmts, preciseMemExnsFn, pxControl, env);
+}
+
 
 /*---------------------------------------------------------------*/
 /*--- Constant propagation and folding                        ---*/
@@ -1043,27 +1083,30 @@
    slower out of line general case.  Saves a few insns. */
 
 __attribute__((noinline))
-static Bool sameIRExprs_aux2 ( IRExpr** env, IRExpr* e1, IRExpr* e2 );
+static Bool sameIRExprs_aux2(IRExpr* env[], IRExpr* e1, IRExpr* e2);
 
 inline
-static Bool sameIRExprs_aux ( IRExpr** env, IRExpr* e1, IRExpr* e2 )
+static Bool sameIRExprs_aux(IRExpr* env[], IRExpr* e1, IRExpr* e2)
 {
    if (e1->tag != e2->tag) return False;
    return sameIRExprs_aux2(env, e1, e2);
 }
 
 __attribute__((noinline))
-static Bool sameIRExprs_aux2 ( IRExpr** env, IRExpr* e1, IRExpr* e2 )
+static Bool sameIRExprs_aux2(IRExpr* env[], IRExpr* e1, IRExpr* e2)
 {
    if (num_nodes_visited++ > NODE_LIMIT) return False;
 
    switch (e1->tag) {
-      case Iex_RdTmp:
-         if (e1->Iex.RdTmp.tmp == e2->Iex.RdTmp.tmp) return True;
+      case Iex_RdTmp: {
+         IRTemp tmp1 = e1->Iex.RdTmp.tmp;
+         IRTemp tmp2 = e2->Iex.RdTmp.tmp;
+         vassert(tmp1.id == tmp2.id);
 
-         if (env[e1->Iex.RdTmp.tmp] && env[e2->Iex.RdTmp.tmp]) {
-            Bool same = sameIRExprs_aux(env, env[e1->Iex.RdTmp.tmp],
-                                        env[e2->Iex.RdTmp.tmp]);
+         if (tmp1.index == tmp2.index) return True;
+
+         if (env[tmp1.index] && env[tmp2.index]) {
+            Bool same = sameIRExprs_aux(env, env[tmp1.index], env[tmp2.index]);
 #if STATS_IROPT
             recursed = True;
             if (same) recursion_helped = True;
@@ -1071,6 +1114,7 @@
             return same;
          }
          return False;
+      }
 
       case Iex_Get:
       case Iex_GetI:
@@ -1131,7 +1175,7 @@
 }
 
 inline
-static Bool sameIRExprs ( IRExpr** env, IRExpr* e1, IRExpr* e2 )
+static Bool sameIRExprs(IRExpr* env[], IRExpr* e1, IRExpr* e2)
 {
    Bool same;
 
@@ -1346,29 +1390,29 @@
    return NULL if it can't resolve 'e' to a new expression, which will
    be the case if 'e' is instead defined by an IRStmt (IRDirty or
    LLSC). */
-static IRExpr* chase ( IRExpr** env, IRExpr* e )
+static IRExpr* chase(IRExpr* env[], IRExpr* e)
 {
    /* Why is this loop guaranteed to terminate?  Because all tmps must
       have definitions before use, hence a tmp cannot be bound
       (directly or indirectly) to itself. */
    while (e->tag == Iex_RdTmp) {
       if (0) { vex_printf("chase "); ppIRExpr(e); vex_printf("\n"); }
-      e = env[(Int)e->Iex.RdTmp.tmp];
+      e = env[e->Iex.RdTmp.tmp.index];
       if (e == NULL) break;
    }
    return e;
 }
 
 /* Similar to |chase|, but follows at most one level of tmp reference. */
-static IRExpr* chase1 ( IRExpr** env, IRExpr* e )
+static IRExpr* chase1(IRExpr* env[], IRExpr* e)
 {
    if (e == NULL || e->tag != Iex_RdTmp)
       return e;
    else
-      return env[(Int)e->Iex.RdTmp.tmp];
+      return env[e->Iex.RdTmp.tmp.index];
 }
 
-static IRExpr* fold_Expr ( IRExpr** env, IRExpr* e )
+static IRExpr* fold_Expr(IRExpr* env[], IRExpr* e)
 {
    Int     shift;
    IRExpr* e2 = e; /* e2 is the result of folding e, if possible */
@@ -2429,12 +2473,12 @@
 /* Apply the subst to a simple 1-level expression -- guaranteed to be
    1-level due to previous flattening pass. */
 
-static IRExpr* subst_Expr ( IRExpr** env, IRExpr* ex )
+static IRExpr* subst_Expr(IRExpr* env[], IRExpr* ex)
 {
    switch (ex->tag) {
       case Iex_RdTmp:
-         if (env[(Int)ex->Iex.RdTmp.tmp] != NULL) {
-            IRExpr *rhs = env[(Int)ex->Iex.RdTmp.tmp];
+         if (env[ex->Iex.RdTmp.tmp.index] != NULL) {
+            IRExpr *rhs = env[ex->Iex.RdTmp.tmp.index];
             if (rhs->tag == Iex_RdTmp)
                return rhs;
             if (rhs->tag == Iex_Const
@@ -2539,12 +2583,27 @@
    }
 }
 
+/* Set up the cprop env with which travels forward for the current IRStmtVec.
+   This holds a substitution, mapping IRTemp.indices to IRExprs.
+   Keys are IRTemp.indices. Values are IRExpr*s.
+*/
+static IRExpr** new_cprop_env(const IRTypeEnv* tyenv)
+{
+   UInt  n_tmps = tyenv->types_used;
+   IRExpr** env = LibVEX_Alloc_inline(n_tmps * sizeof(IRExpr*));
+   for (UInt i = 0; i < n_tmps; i++)
+      env[i] = NULL;
+   return env;
+}
+
+static IRStmtVec* subst_and_fold_Stmts(IRExpr* env[], IRStmtVec* in,
+                                       IRStmtVec* parent);
 
 /* 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.  
 */
-static IRStmt* subst_and_fold_Stmt ( IRExpr** env, IRStmt* st )
+static IRStmt* subst_and_fold_Stmt(IRExpr* env[], IRStmt* st, IRStmtVec* parent)
 {
 #  if 0
    vex_printf("\nsubst and fold stmt\n");
@@ -2748,51 +2807,75 @@
                                    st->Ist.Exit.dst, st->Ist.Exit.offsIP);
       }
 
+      case Ist_IfThenElse: {
+         vassert(isIRAtom(st->Ist.IfThenElse.cond));
+         IRExpr *fcond = fold_Expr(env,
+                                   subst_Expr(env, st->Ist.IfThenElse.cond));
+         if (fcond->tag == Iex_Const) {
+            /* Interesting. The condition on this "if-then-else" has folded down
+               to a constant. */
+            vassert(fcond->Iex.Const.con->tag == Ico_U1);
+            if (fcond->Iex.Const.con->Ico.U1 == True) {
+               /* TODO-JIT: "else" leg is never going to happen, so dump it. */
+               if (vex_control.iropt_verbosity > 0)
+                  vex_printf("vex iropt: IRStmt_IfThenElse became "
+                             "unconditional\n");
+            } else {
+               vassert(fcond->Iex.Const.con->Ico.U1 == False);
+               /* TODO-JIT: "then" leg is never going to happen, so dump it. */
+               if (vex_control.iropt_verbosity > 0)
+                  vex_printf("vex iropt: IRStmt_IfThenElse became "
+                             "unconditional\n");
+            }
+            /* TODO-JIT: Pull the only remaining leg into the current IRStmtVec.
+               It is necessary to rewrite indices of all IRTemp's in scope.
+               Not sure if this is possible or feasible. */
+         }
+         return IRStmt_IfThenElse(fcond,
+                      subst_and_fold_Stmts(
+                         new_cprop_env(st->Ist.IfThenElse.then_leg->tyenv),
+                         st->Ist.IfThenElse.then_leg,
+                         parent),
+                      subst_and_fold_Stmts(
+                         new_cprop_env(st->Ist.IfThenElse.then_leg->tyenv),
+                         st->Ist.IfThenElse.else_leg,
+                         parent),
+                      st->Ist.IfThenElse.phi_nodes);
+      }
+
    default:
       vex_printf("\n"); ppIRStmt(st);
       vpanic("subst_and_fold_Stmt");
    }
 }
 
-
-IRSB* cprop_BB ( IRSB* in )
+static
+IRStmtVec* subst_and_fold_Stmts(IRExpr* env[], IRStmtVec* in, IRStmtVec* parent)
 {
-   Int      i;
-   IRSB*    out;
-   IRStmt*  st2;
-   Int      n_tmps = in->tyenv->types_used;
-   IRExpr** env = LibVEX_Alloc_inline(n_tmps * sizeof(IRExpr*));
    /* Keep track of IRStmt_LoadGs that we need to revisit after
       processing all the other statements. */
    const Int N_FIXUPS = 16;
    Int fixups[N_FIXUPS]; /* indices in the stmt array of 'out' */
    Int n_fixups = 0;
 
-   out = emptyIRSB();
-   out->tyenv = deepCopyIRTypeEnv( in->tyenv );
-
-   /* Set up the env with which travels forward.  This holds a
-      substitution, mapping IRTemps to IRExprs. The environment
-      is to be applied as we move along.  Keys are IRTemps.
-      Values are IRExpr*s.
-   */
-   for (i = 0; i < n_tmps; i++)
-      env[i] = NULL;
+   IRStmtVec* out = emptyIRStmtVec();
+   out->tyenv     = deepCopyIRTypeEnv( in->tyenv );
+   out->parent    = parent;
 
    /* For each original SSA-form stmt ... */
-   for (i = 0; i < in->stmts_used; i++) {
+   for (UInt i = 0; i < in->stmts_used; i++) {
 
       /* First apply the substitution to the current stmt.  This
          propagates in any constants and tmp-tmp assignments
          accumulated prior to this point.  As part of the subst_Stmt
          call, also then fold any constant expressions resulting. */
 
-      st2 = in->stmts[i];
+      IRStmt* st2 = in->stmts[i];
 
       /* perhaps st2 is already a no-op? */
       if (st2->tag == Ist_NoOp) continue;
 
-      st2 = subst_and_fold_Stmt( env, st2 );
+      st2 = subst_and_fold_Stmt(env, st2, out);
 
       /* Deal with some post-folding special cases. */
       switch (st2->tag) {
@@ -2807,8 +2890,8 @@
             propagation and to allow sameIRExpr look through
             IRTemps. */
          case Ist_WrTmp: {
-            vassert(env[(Int)(st2->Ist.WrTmp.tmp)] == NULL);
-            env[(Int)(st2->Ist.WrTmp.tmp)] = st2->Ist.WrTmp.data;
+            vassert(env[st2->Ist.WrTmp.tmp.index] == NULL);
+            env[st2->Ist.WrTmp.tmp.index] = st2->Ist.WrTmp.data;
 
             /* 't1 = t2' -- don't add to BB; will be optimized out */
             if (st2->Ist.WrTmp.data->tag == Iex_RdTmp)
@@ -2844,7 +2927,7 @@
                vassert(n_fixups >= 0 && n_fixups <= N_FIXUPS);
                if (n_fixups < N_FIXUPS) {
                   fixups[n_fixups++] = out->stmts_used;
-                  addStmtToIRSB( out, IRStmt_NoOp() );
+                  addStmtToIRStmtVec(out, IRStmt_NoOp());
                }
             }
             /* And always add the LoadG to the output, regardless. */
@@ -2855,24 +2938,14 @@
          break;
       }
 
-      /* Not interesting, copy st2 into the output block. */
-      addStmtToIRSB( out, st2 );
+      /* Not interesting, copy st2 into the output vector. */
+      addStmtToIRStmtVec(out, st2);
    }
 
-#  if STATS_IROPT
-   vex_printf("sameIRExpr: invoked = %u/%u  equal = %u/%u max_nodes = %u\n",
-              invocation_count, recursion_count, success_count,
-              recursion_success_count, max_nodes_visited);
-#  endif
-
-   out->next     = subst_Expr( env, in->next );
-   out->jumpkind = in->jumpkind;
-   out->offsIP   = in->offsIP;
-
    /* Process any leftover unconditional LoadGs that we noticed
       in the main pass. */
    vassert(n_fixups >= 0 && n_fixups <= N_FIXUPS);
-   for (i = 0; i < n_fixups; i++) {
+   for (UInt i = 0; i < n_fixups; i++) {
       Int ix = fixups[i];
       /* Carefully verify that the LoadG has the expected form. */
       vassert(ix >= 0 && ix+1 < out->stmts_used);
@@ -2917,6 +2990,24 @@
    return out;
 }
 
+IRSB* cprop_BB ( IRSB* in )
+{
+   IRExpr** env  = new_cprop_env(in->stmts->tyenv);
+   IRSB* out     = emptyIRSB();
+   out->stmts    = subst_and_fold_Stmts(env, in->stmts, NULL);
+   out->next     = subst_Expr( env, in->next );
+   out->jumpkind = in->jumpkind;
+   out->offsIP   = in->offsIP;
+
+#  if STATS_IROPT
+   vex_printf("sameIRExpr: invoked = %u/%u  equal = %u/%u max_nodes = %u\n",
+              invocation_count, recursion_count, success_count,
+              recursion_success_count, max_nodes_visited);
+#  endif
+
+   return out;
+}
+
 
 /*---------------------------------------------------------------*/
 /*--- Dead code (t = E) removal                               ---*/
@@ -2932,7 +3023,7 @@
 inline
 static void addUses_Temp ( Bool* set, IRTemp tmp )
 {
-   set[(Int)tmp] = True;
+   set[tmp.index] = True;
 }
 
 static void addUses_Expr ( Bool* set, IRExpr* e )
@@ -2985,9 +3076,20 @@
    }
 }
 
+static Bool* new_deadcode_set(const IRTypeEnv* tyenv)
+{
+   UInt  n_tmps = tyenv->types_used;
+   Bool* set = LibVEX_Alloc_inline(n_tmps * sizeof(Bool));
+   for (UInt i = 0; i < n_tmps; i++)
+      set[i] = False;
+   return set;
+}
+
+static void do_deadcode_IRStmtVec(Bool* set, IRStmtVec* stmts,
+                                  Int* i_unconditional_exit);
+
 static void addUses_Stmt ( Bool* set, IRStmt* st )
 {
-   Int      i;
    IRDirty* d;
    IRCAS*   cas;
    switch (st->tag) {
@@ -3043,7 +3145,7 @@
          if (d->mFx != Ifx_None)
             addUses_Expr(set, d->mAddr);
          addUses_Expr(set, d->guard);
-         for (i = 0; d->args[i] != NULL; i++) {
+         for (UInt i = 0; d->args[i] != NULL; i++) {
             IRExpr* arg = d->args[i];
             if (LIKELY(!is_IRExpr_VECRET_or_GSPTR(arg)))
                addUses_Expr(set, arg);
@@ -3056,6 +3158,28 @@
       case Ist_Exit:
          addUses_Expr(set, st->Ist.Exit.guard);
          return;
+      case Ist_IfThenElse: {
+         addUses_Expr(set, st->Ist.IfThenElse.cond);
+
+         Bool* then_set = new_deadcode_set(st->Ist.IfThenElse.then_leg->tyenv);

[... 2320 lines stripped ...]

------------------------------------------------------------------------------
Announcing the Oxford Dictionaries API! The API offers world-renowned
dictionary content that is easy and intuitive to access. Sign up for an
account today to start using our lexical data to power your apps and
projects. Get started today and enter our developer competition.
http://sdm.link/oxford
_______________________________________________
Valgrind-developers mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/valgrind-developers
Loading...