]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Implement support for If-Then-Else and Phi nodes into ir_defs.c.
authorIvo Raisr <ivosh@ivosh.net>
Tue, 8 Aug 2017 04:20:57 +0000 (06:20 +0200)
committerIvo Raisr <ivosh@ivosh.net>
Mon, 28 Aug 2017 21:17:10 +0000 (23:17 +0200)
VEX/priv/ir_defs.c

index 8822800f119652cf9c84684c2e9f21e86c825a59..f01eb40277f3bbae5e20208faee8f117b374e90f 100644 (file)
@@ -33,6 +33,8 @@
    without prior written permission.
 */
 
+/* Copyright (C) 2017-2017 Ivo Raisr <ivosh@ivosh.net> */
+
 #include "libvex_basictypes.h"
 #include "libvex_ir.h"
 #include "libvex.h"
@@ -114,7 +116,7 @@ void ppIRTemp ( IRTemp tmp )
    if (tmp == IRTemp_INVALID)
       vex_printf("IRTemp_INVALID");
    else
-      vex_printf( "t%u", tmp);
+      vex_printf("t%u", tmp);
 }
 
 void ppIROp ( IROp op )
@@ -1571,8 +1573,73 @@ void ppIRMBusEvent ( IRMBusEvent event )
    }
 }
 
-void ppIRStmt ( const IRStmt* s )
+void ppIRPhi(const IRPhi* phi)
+{
+   ppIRTemp(phi->dst);
+   vex_printf(" = phi(");
+   ppIRTemp(phi->srcThen);
+   vex_printf(",");
+   ppIRTemp(phi->srcElse);
+   vex_printf(")");
+}
+
+static void print_depth(UInt depth) {
+   for (UInt i = 0; i < depth; i++) {
+      vex_printf("    ");
+   }
+}
+
+void ppIRPhiVec(const IRPhiVec* phis, UInt depth)
+{
+   for (UInt i = 0; i < phis->phis_used; i++) {
+      print_depth(depth);
+      ppIRPhi(phis->phis[i]);
+      if (i < phis->phis_used - 1) {
+         vex_printf("\n");
+      }
+   }
+}
+
+void ppIRTempDefSet(const IRTempDefSet* defset, UInt depth)
+{
+   ppIRTypeEnvDefd(NULL, defset, depth);
+}
+
+void ppIRIfThenElse_Hint(IRIfThenElse_Hint hint)
 {
+   switch (hint) {
+   case IfThenElse_ThenLikely: vex_printf("IfThenElse_ThenLikely"); break;
+   case IfThenElse_ElseLikely: vex_printf("IfThenElse_ElseLikely"); break;
+   default: vpanic("ppIRIfThenElse_Hint");
+   }
+}
+
+void ppIRIfThenElseCondHint(const IRIfThenElse* ite)
+{
+   vex_printf("if (");
+   ppIRExpr(ite->cond);
+   vex_printf(") [");
+   ppIRIfThenElse_Hint(ite->hint);
+   vex_printf("]");
+}
+
+void ppIRIfThenElse(const IRIfThenElse* ite, const IRTypeEnv* tyenv, UInt depth)
+{
+   ppIRIfThenElseCondHint(ite);
+   vex_printf(" then {\n");
+   ppIRStmtVec(ite->then_leg, tyenv, depth + 1);
+   print_depth(depth);
+   vex_printf("} else {\n");
+   ppIRStmtVec(ite->else_leg, tyenv, depth + 1);
+   print_depth(depth);
+   vex_printf("}\n");
+   ppIRPhiVec(ite->phi_nodes, depth);
+}
+
+void ppIRStmt(const IRStmt* s, const IRTypeEnv* tyenv, UInt depth)
+{
+   print_depth(depth);
+
    if (!s) {
       vex_printf("!!! IRStmt* which is NULL !!!");
       return;
@@ -1653,41 +1720,83 @@ void ppIRStmt ( const IRStmt* s )
          ppIRJumpKind(s->Ist.Exit.jk);
          vex_printf(" } ");
          break;
-      default: 
+      case Ist_IfThenElse:
+         ppIRIfThenElse(s->Ist.IfThenElse.details, tyenv, depth);
+         break;
+      default:
          vpanic("ppIRStmt");
    }
 }
 
-void ppIRTypeEnv ( const IRTypeEnv* env )
+void ppIRTypeEnv(const IRTypeEnv* env)
 {
-   UInt i;
-   for (i = 0; i < env->types_used; i++) {
+   for (UInt i = 0; i < env->used; i++) {
       if (i % 8 == 0)
-         vex_printf( "   ");
+         print_depth(1);
       ppIRTemp(i);
-      vex_printf( ":");
+      vex_printf("[%u]:", env->ids[i]);
       ppIRType(env->types[i]);
       if (i % 8 == 7) 
          vex_printf( "\n"); 
       else 
          vex_printf( "   ");
    }
-   if (env->types_used > 0 && env->types_used % 8 != 7) 
+   if (env->used > 0 && env->used % 8 != 7)
       vex_printf( "\n"); 
 }
 
-void ppIRSB ( const IRSB* bb )
+void ppIRTypeEnvDefd(const IRTypeEnv* tyenv, const IRTempDefSet* defset,
+                     UInt depth)
 {
-   Int i;
-   vex_printf("IRSB {\n");
-   ppIRTypeEnv(bb->tyenv);
+   UInt tmps_printed = 0;
+
+   for (UInt slot = 0; slot < defset->slots_used; slot++) {
+      UChar slot_value = defset->set[slot];
+      for (UInt bit = 0; bit < sizeof(UChar); bit++) {
+         if (slot_value & (1 << bit)) {
+            if (tmps_printed % 8 == 0)
+               print_depth(depth);
+
+            IRTemp tmp = slot * sizeof(UChar) + bit;
+            ppIRTemp(tmp);
+            if (tyenv != NULL) {
+               vex_printf(":");
+               ppIRType(tyenv->types[tmp]);
+            }
+
+            if (tmps_printed % 8 == 7) {
+               vex_printf("\n"); 
+            } else {
+               vex_printf("   ");
+            }
+
+            tmps_printed += 1;
+         }
+      }
+   }
+
+   if (tmps_printed > 0 && tmps_printed % 8 != 7)
+      vex_printf("\n");
+}
+
+void ppIRStmtVec(const IRStmtVec* stmts, const IRTypeEnv* tyenv, UInt depth)
+{
+   ppIRTypeEnvDefd(tyenv, stmts->defset, depth);
    vex_printf("\n");
-   for (i = 0; i < bb->stmts_used; i++) {
-      vex_printf( "   ");
-      ppIRStmt(bb->stmts[i]);
-      vex_printf( "\n");
+   for (UInt i = 0; i < stmts->stmts_used; i++) {
+      ppIRStmt(stmts->stmts[i], tyenv, depth);
+      vex_printf("\n");
    }
-   vex_printf( "   PUT(%d) = ", bb->offsIP );
+}
+
+void ppIRSB ( const IRSB* bb )
+{
+   UInt depth = 0;
+
+   vex_printf("IRSB {\n");
+   ppIRStmtVec(bb->stmts, bb->tyenv, depth + 1);
+   print_depth(depth + 1);
+   vex_printf("PUT(%d) = ", bb->offsIP);
    ppIRExpr( bb->next );
    vex_printf( "; exit-");
    ppIRJumpKind(bb->jumpkind);
@@ -2132,6 +2241,49 @@ IRLoadG* mkIRLoadG ( IREndness end, IRLoadGOp cvt,
    return lg;
 }
 
+/* Constructors -- IRIfThenElse */
+
+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;
+}
+
+IRTempDefSet* emptyIRTempDefSet(void)
+{
+   IRTempDefSet* defset = LibVEX_Alloc_inline(sizeof(IRTempDefSet));
+   defset->slots_used   = 0;
+   defset->slots_size   = 8 / sizeof(UChar);
+   vassert(defset->slots_size >= 1);
+   defset->set = LibVEX_Alloc_inline(defset->slots_size * sizeof(UChar));
+   return defset;
+}
+
+IRIfThenElse* mkIRIfThenElse(IRExpr* cond, IRIfThenElse_Hint hint,
+                             IRStmtVec* then_leg, IRStmtVec* else_leg,
+                             IRPhiVec* phi_nodes)
+{
+   IRIfThenElse* ite = LibVEX_Alloc_inline(sizeof(IRIfThenElse));
+   ite->cond         = cond;
+   ite->hint         = hint;
+   ite->then_leg     = then_leg;
+   ite->else_leg     = else_leg;
+   ite->phi_nodes    = phi_nodes;
+   return ite;
+}
+
 
 /* Constructors -- IRStmt */
 
@@ -2243,40 +2395,76 @@ IRStmt* IRStmt_Exit ( IRExpr* guard, IRJumpKind jk, IRConst* dst,
    return s;
 }
 
+IRStmt* IRStmt_IfThenElse(IRExpr* cond, IRIfThenElse_Hint hint,
+                          IRStmtVec* then_leg, IRStmtVec* else_leg,
+                          IRPhiVec* phi_nodes)
+{
+   IRStmt* s                 = LibVEX_Alloc_inline(sizeof(IRStmt));
+   s->tag                    = Ist_IfThenElse;
+   s->Ist.IfThenElse.details = mkIRIfThenElse(cond, hint, then_leg, else_leg,
+                                              phi_nodes);
+   return s;
+}
+
 
 /* Constructors -- IRTypeEnv */
 
-IRTypeEnv* emptyIRTypeEnv ( void )
+static IRTypeEnv* emptyIRTypeEnv ( void )
 {
    IRTypeEnv* env   = LibVEX_Alloc_inline(sizeof(IRTypeEnv));
    env->types       = LibVEX_Alloc_inline(8 * sizeof(IRType));
-   env->types_size  = 8;
-   env->types_used  = 0;
+   env->ids         = LibVEX_Alloc_inline(8 * sizeof(IRStmtVecID));
+   env->size        = 8;
+   env->used        = 0;
    return env;
 }
 
 
+/* Constructors -- IRStmtVec */
+
+IRStmtVec* emptyIRStmtVec(void)
+{
+   IRStmtVec* stmts  = LibVEX_Alloc_inline(sizeof(IRStmtVec));
+   stmts->stmts_used = 0;
+   stmts->stmts_size = 8;
+   stmts->stmts      = LibVEX_Alloc_inline(stmts->stmts_size * sizeof(IRStmt*));
+   stmts->id         = IRStmtVecID_INVALID;
+   stmts->parent     = NULL;
+   stmts->defset     = emptyIRTempDefSet();
+   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->tyenv    = emptyIRTypeEnv();
+   bb->stmts    = emptyIRStmtVec();
+   bb->id_seq   = 0;
+   bb->next     = NULL;
+   bb->jumpkind = Ijk_Boring;
+   bb->offsIP   = 0;
+
+   bb->stmts->id = nextIRStmtVecID(bb);
    return bb;
 }
 
+IRStmtVecID nextIRStmtVecID(IRSB* irsb)
+{
+   IRStmtVecID next = irsb->id_seq;
+   irsb->id_seq += 1;
+   vassert(irsb->id_seq != IRStmtVecID_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). */
 
@@ -2441,7 +2629,35 @@ IRPutI* deepCopyIRPutI ( const IRPutI * puti )
                    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)
+{
+   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;
+}
+
+IRTempDefSet* deepCopyIRTempDefSet(const IRTempDefSet* defset)
+{
+   IRTempDefSet* defset2 = LibVEX_Alloc_inline(sizeof(IRTempDefSet));
+   defset2->slots_used   = defset2->slots_size = defset->slots_used;
+   UChar* set2 = LibVEX_Alloc_inline(defset2->slots_used * sizeof(UChar));
+   for (UInt i = 0; i < defset2->slots_used; i++) {
+      set2[i] = defset->set[i];
+   }
+   defset2->set          = set2;
+   return defset2;
+}
+
+IRStmt* deepCopyIRStmt(const IRStmt* s, IRStmtVec* parent)
 {
    switch (s->tag) {
       case Ist_NoOp:
@@ -2498,33 +2714,51 @@ IRStmt* deepCopyIRStmt ( const IRStmt* s )
                             s->Ist.Exit.jk,
                             deepCopyIRConst(s->Ist.Exit.dst),
                             s->Ist.Exit.offsIP);
+      case Ist_IfThenElse: {
+         const IRIfThenElse* ite = s->Ist.IfThenElse.details;
+         return IRStmt_IfThenElse(deepCopyIRExpr(ite->cond), ite->hint,
+                                  deepCopyIRStmtVec(ite->then_leg, parent),
+                                  deepCopyIRStmtVec(ite->else_leg, parent),
+                                  deepCopyIRPhiVec(ite->phi_nodes));
+      }
       default: 
          vpanic("deepCopyIRStmt");
    }
 }
 
-IRTypeEnv* deepCopyIRTypeEnv ( const IRTypeEnv* src )
+IRStmtVec* deepCopyIRStmtVec(const IRStmtVec* src, IRStmtVec* parent)
+{
+   IRStmtVec* vec2  = LibVEX_Alloc_inline(sizeof(IRStmtVec));
+   vec2->id         = src->id;
+   vec2->parent     = parent;
+   vec2->defset     = deepCopyIRTempDefSet(src->defset);
+   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)
 {
-   Int        i;
    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->size      = src->size;
+   dst->used      = src->used;
+   dst->types     = LibVEX_Alloc_inline(dst->size * sizeof(IRType));
+   dst->ids       = LibVEX_Alloc_inline(dst->size * sizeof(IRStmtVecID));
+   for (UInt i = 0; i < src->used; i++) {
       dst->types[i] = src->types[i];
+      dst->ids[i]   = src->ids[i];
+   }
    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;
+   bb2->stmts = deepCopyIRStmtVec(bb->stmts, NULL);
    return bb2;
 }
 
@@ -2532,6 +2766,7 @@ IRSB* deepCopyIRSBExceptStmts ( const IRSB* bb )
 {
    IRSB* bb2     = emptyIRSB();
    bb2->tyenv    = deepCopyIRTypeEnv(bb->tyenv);
+   bb2->id_seq   = bb->id_seq;
    bb2->next     = deepCopyIRExpr(bb->next);
    bb2->jumpkind = bb->jumpkind;
    bb2->offsIP   = bb->offsIP;
@@ -3549,54 +3784,148 @@ void typeOfPrimop ( IROp op,
 }
 
 
+/*---------------------------------------------------------------*/
+/*--- Helper functions for the IR -- IR Phi Nodes             ---*/
+/*---------------------------------------------------------------*/
+
+void addIRPhiToIRPhiVec(IRPhiVec* phi_nodes, IRPhi* phi)
+{
+   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 Temp Defined Set      ---*/
+/*---------------------------------------------------------------*/
+
+void setIRTempDefined(IRTempDefSet* defset, IRTemp tmp)
+{
+   UInt slots_required = (tmp + sizeof(UChar)) / sizeof(UChar);
+
+   if (slots_required >= defset->slots_size) {
+      UInt new_size  = (slots_required > 2 * defset->slots_size) ?
+                       slots_required : 2 * defset->slots_size;
+      UChar* new_set = LibVEX_Alloc_inline(new_size * sizeof(UChar));
+      for (UInt i = 0; i < defset->slots_used; i++) {
+         new_set[i] = defset->set[i];
+      }
+      defset->set        = new_set;
+      defset->slots_size = new_size;
+   }
+
+   if (slots_required > defset->slots_used) {
+      for (UInt i = defset->slots_used; i < slots_required; i++) {
+         defset->set[i] = 0;
+      }
+      defset->slots_used = slots_required;
+   }
+
+   vassert(!isIRTempDefined(defset, tmp));
+
+   UInt mask = (1 << (tmp % sizeof(UChar)));
+   defset->set[tmp / sizeof(UChar)] |= mask;
+}
+
+void clearIRTempDefSet(IRTempDefSet* defset)
+{
+   for (UInt i = 0; i < defset->slots_used; i++) {
+      defset->set[i] = 0;
+   }
+}
+
 /*---------------------------------------------------------------*/
 /*--- Helper functions for the IR -- IR Basic Blocks          ---*/
 /*---------------------------------------------------------------*/
 
-void addStmtToIRSB ( IRSB* bb, IRStmt* st )
+void addStmtToIRStmtVec(IRStmtVec* stmts, 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;
+   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(bb->stmts_used < bb->stmts_size);
-   bb->stmts[bb->stmts_used] = st;
-   bb->stmts_used++;
+   vassert(stmts->stmts_used < stmts->stmts_size);
+   stmts->stmts[stmts->stmts_used] = st;
+   stmts->stmts_used++;
+}
+
+void addStmtToIRSB ( IRSB* bb, IRStmt* st )
+{
+   addStmtToIRStmtVec(bb->stmts, st);
 }
 
+IRStmt *addEmptyIfThenElse(IRSB* bb, IRStmtVec* parent, IRExpr* cond,
+                           IRIfThenElse_Hint hint)
+{
+   IRStmtVec* then_leg = emptyIRStmtVec();
+   then_leg->id        = nextIRStmtVecID(bb);
+   then_leg->parent    = parent;
+
+   IRStmtVec* else_leg = emptyIRStmtVec();
+   else_leg->id        = nextIRStmtVecID(bb);
+   else_leg->parent    = parent;
+
+   IRStmt* st = IRStmt_IfThenElse(cond, hint, then_leg, else_leg,
+                                  emptyIRPhiVec());
+   addStmtToIRStmtVec(parent, st);
+   return st;
+}
 
 /*---------------------------------------------------------------*/
 /*--- Helper functions for the IR -- IR Type Environments     ---*/
 /*---------------------------------------------------------------*/
 
-/* Allocate a new IRTemp, given its type. */
-
-IRTemp newIRTemp ( IRTypeEnv* env, IRType ty )
+void ensureSpaceInIRTypeEnv(IRTypeEnv* env, UInt new_size)
 {
-   vassert(env);
-   vassert(env->types_used >= 0);
-   vassert(env->types_size >= 0);
-   vassert(env->types_used <= env->types_size);
-   if (env->types_used < env->types_size) {
-      env->types[env->types_used] = ty;
-      return env->types_used++;
-   } else {
-      Int i;
-      Int new_size = env->types_size==0 ? 8 : 2*env->types_size;
-      IRType* new_types 
-         = LibVEX_Alloc_inline(new_size * sizeof(IRType));
-      for (i = 0; i < env->types_used; i++)
+   vassert(env != NULL);
+
+   if (new_size > env->size) {
+      IRType*      new_types = LibVEX_Alloc_inline(new_size * sizeof(IRType));
+      IRStmtVecID* new_ids   = LibVEX_Alloc_inline(new_size * sizeof(IRStmtVecID));
+      for (UInt i = 0; i < env->used; i++) {
          new_types[i] = env->types[i];
-      env->types      = new_types;
-      env->types_size = new_size;
-      return newIRTemp(env, ty);
+         new_ids[i]   = env->ids[i];
+      }
+      env->types = new_types;
+      env->ids   = new_ids;
+      env->size  = new_size;
    }
 }
 
+IRTemp newIRTemp(IRTypeEnv* env, IRStmtVec* stmts, IRType ty)
+{
+   vassert(env != NULL);
+   vassert(stmts != NULL);
+   vassert(env->used >= 0);
+   vassert(env->size >= 0);
+   vassert(env->used <= env->size);
+
+   if (env->used == env->size) {
+      ensureSpaceInIRTypeEnv(env, 2 * env->size);
+   }
+
+   IRTemp tmp      = env->used;
+   env->used       += 1;
+   env->types[tmp] = ty;
+   env->ids[tmp]   = stmts->id;
+   setIRTempDefined(stmts->defset, tmp);
+   return tmp;
+}
+
 
 /*---------------------------------------------------------------*/
 /*--- Helper functions for the IR -- finding types of exprs   ---*/
@@ -3606,7 +3935,7 @@ inline
 IRType typeOfIRTemp ( const IRTypeEnv* env, IRTemp tmp )
 {
    vassert(tmp >= 0);
-   vassert(tmp < env->types_used);
+   vassert(tmp < env->used);
    return env->types[tmp];
 }
 
@@ -3736,6 +4065,9 @@ static inline Bool isIRAtom_or_VECRET_or_GSPTR ( const IRExpr* e )
   return UNLIKELY(is_IRExpr_VECRET_or_GSPTR(e));
 }
 
+static Bool isFlatIRStmtVec(const IRStmtVec* stmts);
+
+static
 Bool isFlatIRStmt ( const IRStmt* st )
 {
    Int      i;
@@ -3835,11 +4167,30 @@ Bool isFlatIRStmt ( const IRStmt* st )
          return True;
       case Ist_Exit:
          return isIRAtom(st->Ist.Exit.guard);
+      case Ist_IfThenElse:
+         return isIRAtom(st->Ist.IfThenElse.details->cond)
+                && isFlatIRStmtVec(st->Ist.IfThenElse.details->then_leg)
+                && isFlatIRStmtVec(st->Ist.IfThenElse.details->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;
+}
+
+Bool isFlatIRSB(const IRSB* irsb)
+{
+   return isFlatIRStmtVec(irsb->stmts);
+}
 
 /*---------------------------------------------------------------*/
 /*--- Sanity checking                                         ---*/
@@ -3852,6 +4203,10 @@ Bool isFlatIRStmt ( const IRStmt* st )
    bit expression, depending on the guest's word size.
 
    Each temp is assigned only once, before its uses.
+   Each temp assigned and referenced is in scope.
+
+   Phi functions refer to existing, already assigned temporaries from
+   [parent, then leg, else leg].
 */
 
 static inline Int countArgs ( IRExpr** args )
@@ -3870,7 +4225,7 @@ void sanityCheckFail ( const IRSB* bb, const IRStmt* stmt, const HChar* what )
    ppIRSB(bb);
    if (stmt) {
       vex_printf("\nIN STATEMENT:\n\n");
-      ppIRStmt(stmt);
+      ppIRStmt(stmt, bb->tyenv, 1);
    }
    vex_printf("\n\nERROR = %s\n\n", what );
    vpanic("sanityCheckFail: exiting due to bad IR");
@@ -3910,29 +4265,62 @@ static Bool saneIRConst ( const IRConst* con )
    }
 }
 
-/* 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 IRTypeEnv* tyenv, IRTemp tmp)
+{
+   if (tmp >= 0 || tmp < tyenv->used) {
+      return True;
+   }
+   return False;
+}
+
+static Bool inScopeIRTemp(const IRTypeEnv* tyenv, const IRStmtVec* stmts,
+                          IRTemp tmp)
+{
+   IRStmtVecID id = tyenv->ids[tmp];
+   vassert(id != IRStmtVecID_INVALID);
+
+   while (!(isIRTempDefined(stmts->defset, tmp))) {
+      stmts = stmts->parent;
+      if (stmts == NULL)
+         return False;
+   }
+
+   return True;
+}
 
 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");
+   const IRTypeEnv* tyenv = bb->tyenv;
+
+   if (!inRangeIRTemp(tyenv, tmp))
+      sanityCheckFail(bb, stmt, "out of range Temp in IRExpr");
+   if (!inScopeIRTemp(tyenv, stmts, tmp))
+      sanityCheckFail(bb, stmt, "out of scope Temp in IRExpr");
+
    if (def_counts[tmp] < 1)
-      sanityCheckFail(bb,stmt, "IRTemp use before def in IRExpr");
+      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) {
+   const IRTypeEnv* tyenv = bb->tyenv;
+
+   if (!inRangeIRTemp(tyenv, tmp))
       sanityCheckFail(bb, stmt, err_msg_out_of_range);
-   }
+   if (!inScopeIRTemp(tyenv, stmts, tmp))
+      sanityCheckFail(bb, stmt, err_msg_out_of_scope);
 
    def_counts[tmp]++;
    if (def_counts[tmp] > 1) {
@@ -3941,43 +4329,44 @@ void assignedOnce_Temp(const IRSB *bb, const IRStmt *stmt, IRTemp tmp,
 }
 
 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;
@@ -3988,24 +4377,55 @@ void useBeforeDef_Expr ( const IRSB* bb, const IRStmt* stmt,
                /* 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");
    }
 }
 
+static void useBeforeDef_IRPhi(const IRSB* bb, const IRStmtVec* stmts,
+                               const IRStmt* stmt, const IRPhi* phi,
+                               UInt def_counts[])
+{
+   vassert(stmt->tag == Ist_IfThenElse);
+
+   IRStmtVec* then_leg = stmt->Ist.IfThenElse.details->then_leg;
+   IRStmtVec* else_leg = stmt->Ist.IfThenElse.details->else_leg;
+
+   useBeforeDef_Temp(bb, then_leg, stmt, phi->srcThen, def_counts);
+   useBeforeDef_Temp(bb, else_leg, stmt, phi->srcElse, def_counts);
+
+   /* Check also that referenced IRStmtVec's actually exist and belong to
+      "parent", "then", and "else", respectively. */
+   const IRTypeEnv* tyenv = bb->tyenv;
+   if (tyenv->ids[phi->dst] != stmts->id) {
+      sanityCheckFail(bb, stmt, "Istmt.IfThenElse.Phi.dst does not "
+                                "reference parent IRStmtVec");
+   }
+   if (tyenv->ids[phi->srcThen] != then_leg->id) {
+      sanityCheckFail(bb, stmt, "Istmt.IfThenElse.Phi.srcThen does not "
+                                "reference \"then\" IRStmtVec leg");
+   }
+   if (tyenv->ids[phi->srcElse] != else_leg->id) {
+      sanityCheckFail(bb, stmt, "Istmt.IfThenElse.Phi.srcElse does not "
+                                "reference \"else\" IRStmtVec leg");
+   }
+}
+
 static
-void useBeforeDef_Stmt ( const IRSB* bb, const IRStmt* stmt, Int* def_counts )
+void useBeforeDef_Stmt(const IRSB* bb, const IRStmtVec* stmts,
+                       const IRStmt* stmt, UInt def_counts[])
 {
    Int       i;
    const IRDirty*  d;
@@ -4017,50 +4437,51 @@ void useBeforeDef_Stmt ( const IRSB* bb, const IRStmt* stmt, Int* def_counts )
       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;
@@ -4070,17 +4491,23 @@ void useBeforeDef_Stmt ( const IRSB* bb, const IRStmt* stmt, Int* def_counts )
                /* 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.details->cond,
+                           def_counts);
+         /* Traversing into legs and phi nodes driven from
+            sanityCheckIRStmtVec(). */
          break;
       default: 
          vpanic("useBeforeDef_Stmt");
@@ -4088,48 +4515,59 @@ void useBeforeDef_Stmt ( const IRSB* bb, const IRStmt* stmt, Int* def_counts )
 }
 
 static
-void assignedOnce_Stmt(const IRSB *bb, const IRStmt *stmt,
-                       Int *def_counts, UInt n_def_counts)
+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) {
          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) {
          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: {
+      /* Traversing into legs and phi nodes driven from
+         sanityCheckIRStmtVec(). */
+      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:
@@ -4139,9 +4577,19 @@ void assignedOnce_Stmt(const IRSB *bb, const IRStmt *stmt,
    }
 }
 
+static void assignedOnce_IRPhi(const IRSB* bb, const IRStmtVec* stmts,
+                               const IRStmt* stmt, const IRPhi* phi,
+                               UInt def_counts[])
+{
+   assignedOnce_Temp(bb, stmts, stmt, phi->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");
+}
+
 static
-void tcExpr ( const IRSB* bb, const IRStmt* stmt, const IRExpr* expr,
-              IRType gWordTy )
+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;
@@ -4151,8 +4599,8 @@ void tcExpr ( const IRSB* bb, const IRStmt* stmt, const IRExpr* expr,
       case Iex_RdTmp:
          break;
       case Iex_GetI:
-         tcExpr(bb,stmt, expr->Iex.GetI.ix, gWordTy );
-         if (typeOfIRExpr(tyenv,expr->Iex.GetI.ix) != Ity_I32)
+         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))
             sanityCheckFail(bb,stmt,"IRExpr.GetI.descr: invalid descr");
@@ -4160,10 +4608,10 @@ void tcExpr ( const IRSB* bb, const IRStmt* stmt, const IRExpr* expr,
       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 
@@ -4212,9 +4660,9 @@ void tcExpr ( const IRSB* bb, const IRStmt* stmt, const IRExpr* expr,
       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 
@@ -4256,8 +4704,8 @@ void tcExpr ( const IRSB* bb, const IRStmt* stmt, const IRExpr* expr,
       }
       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 
@@ -4293,7 +4741,7 @@ void tcExpr ( const IRSB* bb, const IRStmt* stmt, const IRExpr* expr,
          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
@@ -4303,7 +4751,7 @@ void tcExpr ( const IRSB* bb, const IRStmt* stmt, const IRExpr* expr,
             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)
@@ -4320,10 +4768,11 @@ void tcExpr ( const IRSB* bb, const IRStmt* stmt, const IRExpr* expr,
             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");
@@ -4333,9 +4782,9 @@ void tcExpr ( const IRSB* bb, const IRStmt* stmt, const IRExpr* expr,
             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)
@@ -4347,11 +4796,27 @@ void tcExpr ( const IRSB* bb, const IRStmt* stmt, const IRExpr* expr,
    }
 }
 
+static
+void tcPhi(const IRSB* bb, const IRStmtVec* stmts, const IRStmt* stmt,
+           const IRPhi* phi)
+{
+   vassert(stmt->tag == Ist_IfThenElse);
+   const IRTypeEnv* tyenv = bb->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 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;
    switch (stmt->tag) {
@@ -4372,35 +4837,35 @@ void tcStmt ( const IRSB* bb, const IRStmt* stmt, IRType gWordTy )
                                     "not :: guest word type");
          break;
       case Ist_Put:
-         tcExpr( bb, stmt, stmt->Ist.Put.data, gWordTy );
-         if (typeOfIRExpr(tyenv,stmt->Ist.Put.data) == Ity_I1)
+         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 );
-         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)
+         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: data ty != elem ty");
-         if (typeOfIRExpr(tyenv,puti->ix) != Ity_I32)
+         if (typeOfIRExpr(tyenv, puti->ix) != Ity_I32)
             sanityCheckFail(bb,stmt,"IRStmt.PutI.ix: not :: Ity_I32");
          if (!saneIRRegArray(puti->descr))
             sanityCheckFail(bb,stmt,"IRStmt.PutI.descr: invalid descr");
          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");
@@ -4412,9 +4877,9 @@ void tcStmt ( const IRSB* bb, const IRStmt* stmt, IRType gWordTy )
          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)
@@ -4427,9 +4892,9 @@ void tcStmt ( const IRSB* bb, const IRStmt* stmt, IRType gWordTy )
       }
       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)
@@ -4446,12 +4911,12 @@ void tcStmt ( const IRSB* bb, const IRStmt* stmt, IRType gWordTy )
       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 (cas->oldHi == IRTemp_INVALID
              && cas->expdHi == NULL && cas->dataHi == NULL) {
             /* fine; it's a single cas */
          }
          else
-         if (cas->oldHi != IRTemp_INVALID 
+         if (cas->oldHi != IRTemp_INVALID
              && cas->expdHi != NULL && cas->dataHi != NULL) {
             /* fine; it's a double cas */
          }
@@ -4460,7 +4925,7 @@ void tcStmt ( const IRSB* bb, const IRStmt* stmt, IRType gWordTy )
             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);
@@ -4533,7 +4998,7 @@ void tcStmt ( const IRSB* bb, const IRStmt* stmt, IRType gWordTy )
          }
          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) {
@@ -4548,7 +5013,7 @@ void tcStmt ( const IRSB* bb, const IRStmt* stmt, IRType gWordTy )
          }
          /* 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 */
@@ -4559,7 +5024,7 @@ void tcStmt ( const IRSB* bb, const IRStmt* stmt, IRType gWordTy )
                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];
@@ -4618,8 +5083,8 @@ void tcStmt ( const IRSB* bb, const IRStmt* stmt, IRType gWordTy )
          }
          break;
       case Ist_Exit:
-         tcExpr( bb, stmt, stmt->Ist.Exit.guard, gWordTy );
-         if (typeOfIRExpr(tyenv,stmt->Ist.Exit.guard) != Ity_I1)
+         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))
             sanityCheckFail(bb,stmt,"IRStmt.Exit.dst: bad dst");
@@ -4629,77 +5094,156 @@ void tcStmt ( const IRSB* bb, const IRStmt* stmt, IRType gWordTy )
          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.details->cond, gWordTy);
+         if (typeOfIRExpr(tyenv, stmt->Ist.IfThenElse.details->cond) != Ity_I1)
+            sanityCheckFail(bb,stmt,"IRStmt.IfThenElse.cond: not :: Ity_I1");
+         /* Traversing into legs and phi nodes driven from
+            sanityCheckIRStmtVec(). */
+         break;
       default:
          vpanic("tcStmt");
    }
 }
 
-void sanityCheckIRSB ( const IRSB* bb, const HChar* caller,
-                       Bool require_flat, IRType guest_word_size )
+static void sanityCheckIRPhiNodes(const IRSB* bb, const IRStmtVec* stmts,
+              const IRStmt* stmt, const IRPhiVec* phi_nodes, UInt def_counts[])
 {
-   Int     i;
-   Int     n_temps    = bb->tyenv->types_used;
-   Int*    def_counts = LibVEX_Alloc_inline(n_temps * sizeof(Int));
+   for (UInt i = 0; i < phi_nodes->phis_used; i++) {
+      const IRPhi* phi = phi_nodes->phis[i];
+      useBeforeDef_IRPhi(bb, stmts, stmt, phi, def_counts);
+      assignedOnce_IRPhi(bb, stmts, stmt, phi, def_counts);
+      tcPhi(bb, stmts, stmt, phi);
+   }
+}
 
-   if (0)
-      vex_printf("sanityCheck: %s\n", caller);
+static
+void sanityCheckIRStmtVec(const IRSB* bb, const IRStmtVec* stmts,
+                          Bool require_flat, UInt def_counts[],
+                          UInt id_counts[], UInt n_ids, IRType gWordTy)
+{
+   IRStmtVecID id = stmts->id;
+   if (id == IRStmtVecID_INVALID) {
+      vpanic("sanityCheckIRStmtVec: invalid IRStmtVec ID");
+   }
 
-   vassert(guest_word_size == Ity_I32
-           || guest_word_size == Ity_I64);
+   if (id >= n_ids) {
+      vex_printf("IRStmtVec's ID (%u) is larger than number of IRStmtVec's "
+                 "(%u)\n", id, n_ids);
+      sanityCheckFail(bb, NULL, "IRStmtVec's ID larger than number of "
+                                "IRStmtVec's");
+   }
 
-   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");
+   id_counts[id] += 1;
+   if (id_counts[id] > 1) {
+      sanityCheckFail(bb, NULL, "the same IRStmtVec ID used more than once");
+   }
 
-   /* Ensure each temp has a plausible type. */
-   for (i = 0; i < n_temps; i++) {
-      IRType ty = typeOfIRTemp(bb->tyenv,(IRTemp)i);
-      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");
-      }
+   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");
    }
 
-   const IRStmt* stmt;
+   for (UInt i = 0; i < stmts->stmts_used; i++) {
+      const IRStmt *stmt = stmts->stmts[i];
+      if (stmt == NULL)
+         sanityCheckFail(bb, stmt, "IRStmt: is NULL");
 
-   /* 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");
-         if (!isFlatIRStmt(stmt))
+      /* Check for flatness, if required. */
+      if (require_flat) {
+         if (!isFlatIRStmt(stmt)) {
             sanityCheckFail(bb, stmt, "IRStmt: is not flat");
+         }
+      }
+
+      /* Count the defs of each temp.  Only one def is allowed.
+         Also, check that each used temp has already been defd. */
+      useBeforeDef_Stmt(bb, stmts, stmt, def_counts);
+      assignedOnce_Stmt(bb, stmts, stmt, def_counts);
+      tcStmt(bb, stmts, stmt, require_flat, gWordTy);
+
+      if (stmt->tag == Ist_IfThenElse) {
+         const IRIfThenElse* ite = stmt->Ist.IfThenElse.details;
+         const IRStmtVec* then_leg = ite->then_leg;
+         const IRStmtVec* else_leg = ite->else_leg;
+
+         if (then_leg->parent == NULL) {
+            sanityCheckFail(bb, stmt, "IfThenElse.then.parent is NULL");
+         }
+         if (else_leg->parent == NULL) {
+            sanityCheckFail(bb, stmt, "IfThenElse.else.parent is NULL");
+         }
+         if (then_leg->parent != stmts) {
+            sanityCheckFail(bb, stmt, "IfThenElse.then.parent does not point "
+                                      "to its parent");
+         }
+         if (else_leg->parent != stmts) {
+            sanityCheckFail(bb, stmt, "IfThenElse.else.parent does not point "
+                                      "to its parent");
+         }
+
+         sanityCheckIRStmtVec(bb, then_leg, require_flat, def_counts,
+                              id_counts, n_ids, gWordTy);
+         sanityCheckIRStmtVec(bb, else_leg, require_flat, def_counts,
+                              id_counts, n_ids, gWordTy);
+         sanityCheckIRPhiNodes(bb, stmts, stmt, ite->phi_nodes, def_counts);
       }
-      if (!isIRAtom(bb->next))
-         sanityCheckFail(bb, NULL, "bb->next is not an atom");
    }
+}
 
-   /* Count the defs of each temp.  Only one def is allowed.
-      Also, check that each used temp has already been defd. */
+/* 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_ids = bb->id_seq;
+   UInt *id_counts = LibVEX_Alloc_inline(n_ids * sizeof(UInt));
+   for (UInt i = 0; i < n_ids; i++) {
+      id_counts[i] = 0;
+   }
 
-   for (i = 0; i < n_temps; i++)
+   const IRTypeEnv* tyenv = bb->tyenv;
+   UInt n_temps = tyenv->used;
+   UInt *def_counts = LibVEX_Alloc_inline(n_temps * sizeof(UInt));
+   for (UInt i = 0; i < n_temps; i++) {
       def_counts[i] = 0;
+   }
+
+   if (0)
+      vex_printf("sanityCheck: %s\n", caller);
 
-   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);
+   vassert(gWordTy == Ity_I32 || gWordTy == Ity_I64);
 
-      /* Now make note of any temps defd by this statement. */
-      assignedOnce_Stmt(bb, stmt, def_counts, n_temps);
+   /* Ensure each temp has a plausible type. */
+   for (UInt i = 0; i < n_temps; i++) {
+      IRTemp temp = (IRTemp) i;
+      IRType ty = typeOfIRTemp(tyenv, temp);
+      if (!isPlausibleIRType(ty)) {
+         vex_printf("Temp ");
+         ppIRTemp(temp);
+         vex_printf(" declared with implausible type 0x%x\n", (UInt) ty);
+         sanityCheckFail(bb, NULL, "Temp declared with implausible type");
+      }
    }
 
-   /* 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)
+   sanityCheckIRStmtVec(bb, bb->stmts, require_flat, def_counts, id_counts,
+                        n_ids, gWordTy);
+
+   if (require_flat) {
+      if (!isIRAtom(bb->next)) {
+         sanityCheckFail(bb, NULL, "bb->next is not an atom");
+      }
+   }
+
+   /* Typecheck also next destination. */
+   if (typeOfIRExpr(bb->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");
+   }
 }
 
 /*---------------------------------------------------------------*/