]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Make Memcheck compilable.
authorJulian Seward <jseward@acm.org>
Mon, 22 Nov 2004 20:19:51 +0000 (20:19 +0000)
committerJulian Seward <jseward@acm.org>
Mon, 22 Nov 2004 20:19:51 +0000 (20:19 +0000)
git-svn-id: svn://svn.valgrind.org/valgrind/trunk@3065

memcheck/mac_shared.h
memcheck/mc_from_ucode.c
memcheck/mc_include.h
memcheck/mc_main.c
memcheck/mc_translate.c

index f9a6e30910e2486ae8b06d25a4491d927408bed8..2b57a5e7421bb1793c6cacca30fb2ab66755f8ed 100644 (file)
@@ -234,8 +234,8 @@ extern UInt MAC_(event_ctr)[N_PROF_EVENTS];
 #define VGM_WORD_VALID     0
 #define VGM_WORD_INVALID   0xFFFFFFFF
 
-#define VGM_EFLAGS_VALID   0xFFFFFFFE
-#define VGM_EFLAGS_INVALID 0xFFFFFFFF     /* not used */
+#define VGM_WORD64_VALID     0x0ULL
+#define VGM_WORD64_INVALID   0xFFFFFFFFFFFFFFFFULL
 
 /*------------------------------------------------------------*/
 /*--- Command line options + defaults                      ---*/
index 0680effc88635991885373312e9bef5f98eeeb46..705849db63f1916e10e28b5db99a5fc824cabf5c 100644 (file)
    The GNU General Public License is contained in the file COPYING.
 */
 
-#include "mc_include.h"
-
-/*------------------------------------------------------------*/
-/*--- Renamings of frequently-used global functions.       ---*/
-/*------------------------------------------------------------*/
-
-#define dis       VG_(print_codegen)
-
-/*------------------------------------------------------------*/
-/*--- Instruction emission -- turning final uinstrs back   ---*/
-/*--- into x86 code.                                       ---*/
-/*------------------------------------------------------------*/
-
-/* See the corresponding comment at the top of vg_from_ucode.c to find out
- * how all this works */
-
-/*----------------------------------------------------*/
-/*--- v-size (4, or 2 with OSO) insn emitters      ---*/
-/*----------------------------------------------------*/
-
-static void emit_testv_lit_reg ( Int sz, UInt lit, Int reg )
-{
-   VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP);
-   if (sz == 2) {
-      VG_(emitB) ( 0x66 );
-   } else {
-      tl_assert(sz == 4);
-   }
-   VG_(emitB) ( 0xF7 ); /* Grp3 Ev */
-   VG_(emit_amode_ereg_greg) ( reg, 0 /* Grp3 subopcode for TEST */ );
-   if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
-   if (dis)
-      VG_(printf)("\n\t\ttest%c $0x%x, %s\n", nameISize(sz), 
-                                            lit, nameIReg(sz,reg));
-}
-
-static void emit_testv_lit_offregmem ( Int sz, UInt lit, Int off, Int reg )
-{
-   VG_(new_emit)(False, FlagsEmpty, FlagsOSZACP);
-   if (sz == 2) {
-      VG_(emitB) ( 0x66 );
-   } else {
-      tl_assert(sz == 4);
-   }
-   VG_(emitB) ( 0xF7 ); /* Grp3 Ev */
-   VG_(emit_amode_offregmem_reg) ( off, reg, 0 /* Grp3 subopcode for TEST */ );
-   if (sz == 2) VG_(emitW) ( lit ); else VG_(emitL) ( lit );
-   if (dis)
-      VG_(printf)("\n\t\ttest%c $%d, 0x%x(%s)\n", 
-                  nameISize(sz), lit, off, nameIReg(4,reg) );
-}
-
-/*----------------------------------------------------*/
-/*--- Instruction synthesisers                     ---*/
-/*----------------------------------------------------*/
-
-/* Synthesise a minimal test (and which discards result) of reg32
-   against lit.  It's always safe do simply
-      emit_testv_lit_reg ( 4, lit, reg32 )
-   but we try to do better when possible.
-*/
-static void synth_minimal_test_lit_reg ( UInt lit, Int reg32 )
-{
-   if ((lit & 0xFFFFFF00) == 0 && reg32 < 4) {
-      /* We can get away with a byte insn. */
-      VG_(emit_testb_lit_reg) ( False, lit, reg32 );
-   }
-   else 
-   if ((lit & 0xFFFF0000) == 0) {
-      /* Literal fits in 16 bits; do a word insn. */
-      emit_testv_lit_reg ( 2, lit, reg32 );
-   }
-   else {
-      /* Totally general ... */
-      emit_testv_lit_reg ( 4, lit, reg32 );
-   }
-}
-
-/*----------------------------------------------------*/
-/*--- Top level of the uinstr -> x86 translation.  ---*/
-/*----------------------------------------------------*/
-
-static void synth_LOADV ( Int sz, Int a_reg, Int tv_reg,
-                          RRegSet regs_live_before,
-                          RRegSet regs_live_after )
-{
-   Addr helper;
-   UInt argv[] = { a_reg };
-   UInt tagv[] = { RealReg };
-
-   switch (sz) {
-      case 4: helper = (Addr) & MC_(helperc_LOADV4); break;
-      case 2: helper = (Addr) & MC_(helperc_LOADV2); break;
-      case 1: helper = (Addr) & MC_(helperc_LOADV1); break;
-      default: VG_(tool_panic)("synth_LOADV");
-   }
-   VG_(synth_ccall) ( helper, 1, 1, argv, tagv, tv_reg,
-                      regs_live_before, regs_live_after );
-}
-
-
-static void synth_STOREV ( Int sz, Int tv_tag, Int tv_val, Int a_reg,
-                           RRegSet regs_live_before,
-                           RRegSet regs_live_after )
-{
-   Addr helper;
-   UInt argv[] = { a_reg,   tv_val };
-   Tag  tagv[] = { RealReg, tv_tag };
-
-   tl_assert(tv_tag == RealReg || tv_tag == Literal);
-   switch (sz) {
-      case 4: helper = (Addr) MC_(helperc_STOREV4); break;
-      case 2: helper = (Addr) MC_(helperc_STOREV2); break;
-      case 1: helper = (Addr) MC_(helperc_STOREV1); break;
-      default: VG_(tool_panic)("synth_STOREV");
-   }
-   VG_(synth_ccall) ( helper, 2, 2, argv, tagv, INVALID_REALREG,
-                      regs_live_before, regs_live_after );
-}
-
-
-static void synth_SETV ( Int sz, Int reg )
-{
-   UInt val;
-   switch (sz) {
-      case 4: val = 0x00000000; break;
-      case 2: val = 0xFFFF0000; break;
-      case 1: val = 0xFFFFFF00; break;
-      case 0: val = 0xFFFFFFFE; break;
-      default: VG_(tool_panic)("synth_SETV");
-   }
-   VG_(emit_movv_lit_reg) ( 4, val, reg );
-}
-
-
-static void synth_TESTV ( Int sz, Int tag, Int val )
-{
-   Int tgt;                    /* jump target */
-
-   /* Important note.  Note that that the calls to
-      MC_(helper_value_check[0124]_fail) must be compact helpers due to
-      the codegen scheme used below.  Since there are a shortage of
-      compact helper slots, and since the size==1 case is never
-      actually used, we assert against it. */
-   tl_assert(sz == 0 || sz == 2 || sz == 4);
-
-   VG_(init_target)(&tgt);
-
-   tl_assert(tag == ArchReg || tag == RealReg);
-   if (tag == ArchReg) {
-      switch (sz) {
-         case 4: 
-            emit_testv_lit_offregmem ( 
-               4, 0xFFFFFFFF, VG_(shadow_reg_offset)(val), R_EBP );
-            break;
-         case 2: 
-            emit_testv_lit_offregmem ( 
-               4, 0x0000FFFF, VG_(shadow_reg_offset)(val), R_EBP );
-            break;
-         case 1:
-            if (val < 4) {
-               emit_testv_lit_offregmem ( 
-                  4, 0x000000FF, VG_(shadow_reg_offset)(val), R_EBP );
-            } else {
-               emit_testv_lit_offregmem ( 
-                  4, 0x0000FF00, VG_(shadow_reg_offset)(val-4), R_EBP );
-            }
-            break;
-         case 0: 
-            /* should never happen */
-         default: 
-            VG_(tool_panic)("synth_TESTV(ArchReg)");
-      }
-   } else {
-      switch (sz) {
-         case 4:
-            /* Works, but holds the entire 32-bit literal, hence
-               generating a 6-byte insn.  We want to know if any bits
-               in the reg are set, but since this is for the full reg,
-               we might as well compare it against zero, which can be
-               done with a shorter insn. */
-            /* synth_minimal_test_lit_reg ( 0xFFFFFFFF, val ); */
-            VG_(emit_cmpl_zero_reg) ( False, val );
-            break;
-         case 2:
-            synth_minimal_test_lit_reg ( 0x0000FFFF, val );
-            break;
-         case 1:
-            synth_minimal_test_lit_reg ( 0x000000FF, val );
-            break;
-         case 0:
-            synth_minimal_test_lit_reg ( 0x00000001, val );
-            break;
-         default: 
-            VG_(tool_panic)("synth_TESTV(RealReg)");
-      }
-   }
-   
-   /* predict taken because we assume failures are rare */
-   VG_(emit_jcondshort_target) ( False, CondZ, &tgt, JP_TAKEN );
-
-   VG_(synth_call) (
-      False,
-      ( sz==4 
-      ? VG_(helper_offset)((Addr) & MC_(helper_value_check4_fail))
-      : ( sz==2 
-        ? VG_(helper_offset)((Addr) & MC_(helper_value_check2_fail))
-        : ( sz==1 
-          ? VG_(helper_offset)((Addr) & MC_(helper_value_check1_fail))
-         : VG_(helper_offset)((Addr) & MC_(helper_value_check0_fail))))),
-      False, FlagsEmpty, FlagsOSZACP /* helpers don't preserve flags */
-   );
-   VG_(target_forward)(&tgt);
-}
-
-
-static void synth_GETV ( Int sz, Int arch, Int reg )
-{
-   /* VG_(printf)("synth_GETV %d of Arch %s\n", sz, nameIReg(sz, arch)); */
-   switch (sz) {
-      case 4: 
-         VG_(emit_movv_offregmem_reg) ( 4, VG_(shadow_reg_offset)(arch),
-                                        R_EBP, reg );
-         break;
-      case 2: 
-         VG_(emit_movzwl_offregmem_reg) ( False, VG_(shadow_reg_offset)(arch),
-                                          R_EBP, reg );
-         VG_(emit_nonshiftopv_lit_reg) ( False, 4, OR, 0xFFFF0000, reg );
-         break;
-      case 1: 
-         if (arch < 4) {
-            VG_(emit_movzbl_offregmem_reg) ( False, VG_(shadow_reg_offset)(arch),
-                                             R_EBP, reg );
-         } else {
-            VG_(emit_movzbl_offregmem_reg) ( False, VG_(shadow_reg_offset)(arch-4)+1,
-                                             R_EBP, reg );
-         }
-         VG_(emit_nonshiftopv_lit_reg) ( False, 4, OR, 0xFFFFFF00, reg );
-         break;
-      default: 
-         VG_(tool_panic)("synth_GETV");
-   }
-}
-
-
-static void synth_PUTV ( Int sz, Int srcTag, UInt lit_or_reg, Int arch )
-{
-   if (srcTag == Literal) {
-     /* PUTV with a Literal is only ever used to set the corresponding
-        ArchReg to `all valid'.  Should really be a kind of SETV. */
-      UInt lit = lit_or_reg;
-      switch (sz) {
-         case 4:
-            tl_assert(lit == 0x00000000);
-            VG_(emit_movv_lit_offregmem) ( 4, 0x00000000, 
-                                      VG_(shadow_reg_offset)(arch), R_EBP );
-            break;
-         case 2:
-            tl_assert(lit == 0xFFFF0000);
-            VG_(emit_movv_lit_offregmem) ( 2, 0x0000, 
-                                      VG_(shadow_reg_offset)(arch), R_EBP );
-            break;
-         case 1:
-            tl_assert(lit == 0xFFFFFF00);
-            if (arch < 4) {
-               VG_(emit_movb_lit_offregmem) ( 0x00, 
-                                         VG_(shadow_reg_offset)(arch), R_EBP );
-            } else {
-               VG_(emit_movb_lit_offregmem) ( 0x00, 
-                                              VG_(shadow_reg_offset)(arch-4)+1,
-                                              R_EBP );
-            }
-            break;
-         default: 
-            VG_(tool_panic)("synth_PUTV(lit)");
-      }
-
-   } else {
-
-      UInt reg;
-      tl_assert(srcTag == RealReg);
-
-      if (sz == 1 && lit_or_reg >= 4) {
-         VG_(emit_swapl_reg_EAX) ( lit_or_reg );
-         reg = R_EAX;
-      } else {
-         reg = lit_or_reg;
-      }
-
-      if (sz == 1) tl_assert(reg < 4);
-
-      switch (sz) {
-         case 4:
-            VG_(emit_movv_reg_offregmem) ( 4, reg,
-                                      VG_(shadow_reg_offset)(arch), R_EBP );
-            break;
-         case 2:
-            VG_(emit_movv_reg_offregmem) ( 2, reg,
-                                      VG_(shadow_reg_offset)(arch), R_EBP );
-            break;
-         case 1:
-            if (arch < 4) {
-               VG_(emit_movb_reg_offregmem) ( reg,
-                                      VG_(shadow_reg_offset)(arch), R_EBP );
-           } else {
-               VG_(emit_movb_reg_offregmem) ( reg,
-                                      VG_(shadow_reg_offset)(arch-4)+1, R_EBP );
-            }
-            break;
-         default: 
-            VG_(tool_panic)("synth_PUTV(reg)");
-      }
-
-      if (sz == 1 && lit_or_reg >= 4) {
-         VG_(emit_swapl_reg_EAX) ( lit_or_reg );
-      }
-   }
-}
-
-
-static void synth_GETVF ( Int reg )
-{
-   VG_(emit_movv_offregmem_reg) ( 4, VG_(shadow_flags_offset)(), R_EBP, reg );
-   /* paranoia only; should be unnecessary ... */
-   /* VG_(emit_nonshiftopv_lit_reg) ( 4, OR, 0xFFFFFFFE, reg ); */
-}
-
-
-static void synth_PUTVF ( UInt reg )
-{
-   VG_(emit_movv_reg_offregmem) ( 4, reg, VG_(shadow_flags_offset)(), R_EBP );
-}
-
-
-static void synth_TAG1_op ( TagOp op, Int reg, RRegSet regs_live_after )
-{
-   switch (op) {
-
-      /* Scheme is
-            neg<sz> %reg          -- CF = %reg==0 ? 0 : 1
-            sbbl %reg, %reg       -- %reg = -CF
-            or 0xFFFFFFFE, %reg   -- invalidate all bits except lowest
-      */
-      case Tag_PCast40:
-         VG_(emit_unaryopv_reg)(False, 4, NEG, reg);
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, SBB, reg, reg);
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, OR, 0xFFFFFFFE, reg);
-         break;
-      case Tag_PCast20:
-         VG_(emit_unaryopv_reg)(False, 2, NEG, reg);
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, SBB, reg, reg);
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, OR, 0xFFFFFFFE, reg);
-         break;
-      case Tag_PCast10:
-         if (reg >= 4) {
-            VG_(emit_swapl_reg_EAX)(reg);
-            VG_(emit_unaryopb_reg)(False, NEG, R_EAX);
-            VG_(emit_swapl_reg_EAX)(reg);
-         } else {
-            VG_(emit_unaryopb_reg)(False, NEG, reg);
-         }
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, SBB, reg, reg);
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, OR, 0xFFFFFFFE, reg);
-         break;
-
-      /* Scheme is
-            andl $1, %reg -- %reg is 0 or 1
-            negl %reg -- %reg is 0 or 0xFFFFFFFF
-            and possibly an OR to invalidate unused bits.
-      */
-      case Tag_PCast04:
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, AND, 0x00000001, reg);
-         VG_(emit_unaryopv_reg)(False, 4, NEG, reg);
-         break;
-      case Tag_PCast02:
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, AND, 0x00000001, reg);
-         VG_(emit_unaryopv_reg)(False, 4, NEG, reg);
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, OR, 0xFFFF0000, reg);
-         break;
-      case Tag_PCast01:
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, AND, 0x00000001, reg);
-         VG_(emit_unaryopv_reg)(False, 4, NEG, reg);
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, OR, 0xFFFFFF00, reg);
-         break;
-
-      /* Scheme is
-            shl $24, %reg -- make irrelevant bits disappear
-            negl %reg             -- CF = %reg==0 ? 0 : 1
-            sbbl %reg, %reg       -- %reg = -CF
-            and possibly an OR to invalidate unused bits.
-      */
-      case Tag_PCast14:
-         VG_(emit_shiftopv_lit_reg)(False, 4, SHL, 24, reg);
-         VG_(emit_unaryopv_reg)(False, 4, NEG, reg);
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, SBB, reg, reg);
-         break;
-      case Tag_PCast12:
-         VG_(emit_shiftopv_lit_reg)(False, 4, SHL, 24, reg);
-         VG_(emit_unaryopv_reg)(False, 4, NEG, reg);
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, SBB, reg, reg);
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, OR, 0xFFFF0000, reg);
-         break;
-      case Tag_PCast11:
-         VG_(emit_shiftopv_lit_reg)(False, 4, SHL, 24, reg);
-         VG_(emit_unaryopv_reg)(False, 4, NEG, reg);
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, SBB, reg, reg);
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, OR, 0xFFFFFF00, reg);
-         break;
-
-      /* We use any non-live reg (except %reg) as a temporary,
-         or push/pop %ebp if none available:
-            (%dead_reg = any dead reg, else choose anything other than %reg)
-            (pushl %dead_reg if live)
-            movl %reg, %dead_reg
-            negl %dead_reg
-            orl %dead_reg, %reg
-            (popl %dead_reg if live)
-         This sequence turns out to be correct regardless of the 
-         operation width.
-      */
-      case Tag_Left4:
-      case Tag_Left2:
-      case Tag_Left1: {
-        Bool push = True;
-         UInt dead_reg = R_ESP;
-         Int  i, reg_of_i;
-
-         for (i = 0; i < VG_MAX_REALREGS; i++) {
-            if (! IS_RREG_LIVE(i, regs_live_after)) {
-               reg_of_i = VG_(rank_to_realreg)(i);
-               if (reg != reg_of_i) {
-                  dead_reg = reg_of_i;
-                 push = False;
-                  break;
-               }
-            }
-         }
-        
-         if (push) {
-           dead_reg = (reg != R_EAX) ? R_EAX : R_EBX;
-            VG_(emit_pushv_reg)(4, dead_reg);
-        }
-
-         VG_(emit_movv_reg_reg)(4, reg, dead_reg);
-         VG_(emit_unaryopv_reg)(False, 4, NEG, dead_reg);
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, OR, dead_reg, reg);
-
-         if (push)
-            VG_(emit_popv_reg)(4, dead_reg);
-         break;
-      }
-
-      /* These are all fairly obvious; do the op and then, if
-         necessary, invalidate unused bits. */
-      case Tag_SWiden14:
-         VG_(emit_shiftopv_lit_reg)(False, 4, SHL, 24, reg);
-         VG_(emit_shiftopv_lit_reg)(False, 4, SAR, 24, reg);
-         break;
-      case Tag_SWiden24:
-         VG_(emit_shiftopv_lit_reg)(False, 4, SHL, 16, reg);
-         VG_(emit_shiftopv_lit_reg)(False, 4, SAR, 16, reg);
-         break;
-      case Tag_SWiden12:
-         VG_(emit_shiftopv_lit_reg)(False, 4, SHL, 24, reg);
-         VG_(emit_shiftopv_lit_reg)(False, 4, SAR, 24, reg);
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, OR, 0xFFFF0000, reg);
-         break;
-      case Tag_ZWiden14:
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, AND, 0x000000FF, reg);
-         break;
-      case Tag_ZWiden24:
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, AND, 0x0000FFFF, reg);
-         break;
-      case Tag_ZWiden12:
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, AND, 0x000000FF, reg);
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, OR, 0xFFFF0000, reg);
-         break;
-
-      default:
-         VG_(tool_panic)("synth_TAG1_op");
-   }
-}
-
-
-static void synth_TAG2_op ( TagOp op, Int regs, Int regd )
-{
-   switch (op) {
-
-      /* UifU is implemented by OR, since 1 means Undefined. */
-      case Tag_UifU4:
-      case Tag_UifU2:
-      case Tag_UifU1:
-      case Tag_UifU0:
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, OR, regs, regd);
-         break;
-
-      /* DifD is implemented by AND, since 0 means Defined. */
-      case Tag_DifD4:
-      case Tag_DifD2:
-      case Tag_DifD1:
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, AND, regs, regd);
-         break;
-
-      /* ImproveAND(value, tags) = value OR tags.
-        Defined (0) value 0s give defined (0); all other -> undefined (1).
-         value is in regs; tags is in regd. 
-         Be paranoid and invalidate unused bits; I don't know whether 
-         or not this is actually necessary. */
-      case Tag_ImproveAND4_TQ:
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, OR, regs, regd);
-         break;
-      case Tag_ImproveAND2_TQ:
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, OR, regs, regd);
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, OR, 0xFFFF0000, regd);
-         break;
-      case Tag_ImproveAND1_TQ:
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, OR, regs, regd);
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, OR, 0xFFFFFF00, regd);
-         break;
-
-      /* ImproveOR(value, tags) = (not value) OR tags.
-        Defined (0) value 1s give defined (0); all other -> undefined (1).
-         value is in regs; tags is in regd. 
-         To avoid trashing value, this is implemented (re de Morgan) as
-               not (value AND (not tags))
-         Be paranoid and invalidate unused bits; I don't know whether 
-         or not this is actually necessary. */
-      case Tag_ImproveOR4_TQ:
-         VG_(emit_unaryopv_reg)(False, 4, NOT, regd);
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, AND, regs, regd);
-         VG_(emit_unaryopv_reg)(False, 4, NOT, regd);
-         break;
-      case Tag_ImproveOR2_TQ:
-         VG_(emit_unaryopv_reg)(False, 4, NOT, regd);
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, AND, regs, regd);
-         VG_(emit_unaryopv_reg)(False, 4, NOT, regd);
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, OR, 0xFFFF0000, regd);
-         break;
-      case Tag_ImproveOR1_TQ:
-         VG_(emit_unaryopv_reg)(False, 4, NOT, regd);
-         VG_(emit_nonshiftopv_reg_reg)(False, 4, AND, regs, regd);
-         VG_(emit_unaryopv_reg)(False, 4, NOT, regd);
-         VG_(emit_nonshiftopv_lit_reg)(False, 4, OR, 0xFFFFFF00, regd);
-         break;
-
-      default:
-         VG_(tool_panic)("synth_TAG2_op");
-   }
-}
-
-/*----------------------------------------------------*/
-/*--- Generate code for a single UInstr.           ---*/
-/*----------------------------------------------------*/
-
-void TL_(emit_XUInstr) ( UInstr* u, RRegSet regs_live_before )
-{
-   switch (u->opcode) {
-
-      case SETV:
-         tl_assert(u->tag1 == RealReg);
-         synth_SETV ( u->size, u->val1 );
-         break;
-
-      case STOREV:
-         tl_assert(u->tag1 == RealReg || u->tag1 == Literal);
-         tl_assert(u->tag2 == RealReg);
-         synth_STOREV ( u->size, u->tag1, 
-                                 u->tag1==Literal ? u->lit32 : u->val1, 
-                                 u->val2,
-                        regs_live_before, u->regs_live_after );
-         break;
-
-      case LOADV:
-         tl_assert(u->tag1 == RealReg);
-         tl_assert(u->tag2 == RealReg);
-         if (0)
-            VG_(emit_AMD_prefetch_reg) ( u->val1 );
-         synth_LOADV ( u->size, u->val1, u->val2,
-                       regs_live_before, u->regs_live_after );
-         break;
-
-      case TESTV:
-         tl_assert(u->tag1 == RealReg || u->tag1 == ArchReg);
-         synth_TESTV(u->size, u->tag1, u->val1);
-         break;
-
-      case GETV:
-         tl_assert(u->tag1 == ArchReg);
-         tl_assert(u->tag2 == RealReg);
-         synth_GETV(u->size, u->val1, u->val2);
-         break;
-
-      case GETVF:
-         tl_assert(u->tag1 == RealReg);
-         tl_assert(u->size == 0);
-         synth_GETVF(u->val1);
-         break;
-
-      case PUTV:
-         tl_assert(u->tag1 == RealReg || u->tag1 == Literal);
-         tl_assert(u->tag2 == ArchReg);
-         synth_PUTV(u->size, u->tag1, 
-                             u->tag1==Literal ? u->lit32 : u->val1, 
-                             u->val2 );
-         break;
-
-      case PUTVF:
-         tl_assert(u->tag1 == RealReg);
-         tl_assert(u->size == 0);
-         synth_PUTVF(u->val1);
-         break;
-
-      case TAG1:
-         synth_TAG1_op ( u->val3, u->val1, u->regs_live_after );
-         break;
-
-      case TAG2:
-         synth_TAG2_op ( u->val3, u->val1, u->val2 );
-         break;
-
-      default: 
-         VG_(printf)("emit_XUInstr: unhandled extension insn:\n");
-         VG_(pp_UInstr)(0,u);
-         VG_(tool_panic)("emit_XUInstr: unhandled extension opcode");
-   }
-}
-
 /*--------------------------------------------------------------------*/
 /*--- end                                          mc_from_ucode.c ---*/
 /*--------------------------------------------------------------------*/
index 01fbbfea916e379a2545c3c7dcc8ba95559209f7..f19b0244b810b8c21c6b726e0aeb7dcfa9b3f558 100644 (file)
 #include "mac_shared.h"
 #include "mc_asm.h"
 
-/*------------------------------------------------------------*/
-/*--- Types                                                ---*/
-/*------------------------------------------------------------*/
-
-/* UCode extension for efficient memory checking operations */
-typedef
-   enum {
-      /* uinstrs which are not needed for mere translation of x86 code,
-         only for instrumentation of it. */
-      LOADV = DUMMY_FINAL_UOPCODE + 1,
-      STOREV,
-      GETV,
-      PUTV,
-      TESTV,
-      SETV, 
-      /* Get/set the v-bit (and it is only one bit) for the simulated
-         %eflags register. */
-      GETVF,
-      PUTVF,
-
-      /* Do a unary or binary tag op.  Only for post-instrumented
-         code.  For TAG1, first and only arg is a TempReg, and is both
-         arg and result reg.  For TAG2, first arg is src, second is
-         dst, in the normal way; both are TempRegs.  In both cases,
-         3rd arg is a RiCHelper with a Lit16 tag.  This indicates
-         which tag op to do. */
-      TAG1,
-      TAG2
-   }
-   MemCheckOpcode;
-
-
-/* Lists the names of value-tag operations used in instrumented
-   code.  These are the third argument to TAG1 and TAG2 uinsns. */
-typedef
-   enum { 
-     /* Unary. */
-     Tag_PCast40, Tag_PCast20, Tag_PCast10,
-     Tag_PCast01, Tag_PCast02, Tag_PCast04,
-
-     Tag_PCast14, Tag_PCast12, Tag_PCast11,
-
-     Tag_Left4, Tag_Left2, Tag_Left1,
-
-     Tag_SWiden14, Tag_SWiden24, Tag_SWiden12,
-     Tag_ZWiden14, Tag_ZWiden24, Tag_ZWiden12,
-
-     /* Binary; 1st is rd; 2nd is rd+wr */
-     Tag_UifU4, Tag_UifU2, Tag_UifU1, Tag_UifU0,
-     Tag_DifD4, Tag_DifD2, Tag_DifD1,
-
-     Tag_ImproveAND4_TQ, Tag_ImproveAND2_TQ, Tag_ImproveAND1_TQ,
-     Tag_ImproveOR4_TQ, Tag_ImproveOR2_TQ, Tag_ImproveOR1_TQ,
-     Tag_DebugFn
-   }
-   TagOp;
-
 
 /*------------------------------------------------------------*/
 /*--- Command line options                                 ---*/
@@ -113,20 +56,21 @@ extern Bool MC_(clo_avoid_strlen_errors);
 /*--- Functions                                            ---*/
 /*------------------------------------------------------------*/
 
-/* Functions defined in mc_helpers.S */
-extern void MC_(helper_value_check4_fail) ( void );
-extern void MC_(helper_value_check2_fail) ( void );
-extern void MC_(helper_value_check1_fail) ( void );
-extern void MC_(helper_value_check0_fail) ( void );
-
 /* Functions defined in mc_main.c */
+extern REGPARM(1) void MC_(helperc_complain_undef) ( HWord );
+extern void MC_(helperc_value_check4_fail) ( void );
+extern void MC_(helperc_value_check1_fail) ( void );
+extern void MC_(helperc_value_check0_fail) ( void );
+
+extern REGPARM(1) void MC_(helperc_STOREV8) ( Addr, ULong );
 extern REGPARM(2) void MC_(helperc_STOREV4) ( Addr, UInt );
 extern REGPARM(2) void MC_(helperc_STOREV2) ( Addr, UInt );
 extern REGPARM(2) void MC_(helperc_STOREV1) ( Addr, UInt );
-   
+
 extern REGPARM(1) UInt MC_(helperc_LOADV1)  ( Addr );
 extern REGPARM(1) UInt MC_(helperc_LOADV2)  ( Addr );
 extern REGPARM(1) UInt MC_(helperc_LOADV4)  ( Addr );
+extern REGPARM(1) ULong MC_(helperc_LOADV8)  ( Addr );
 
 extern REGPARM(2) void MC_(fpu_write_check) ( Addr addr, SizeT size );
 extern REGPARM(2) void MC_(fpu_read_check)  ( Addr addr, SizeT size );
index 7a3007536efe47efa7c9d4ef1790f8f8c356d52b..9bca42d457904af7aad59357ea75b00d8bfd9db1 100644 (file)
 /*--- Function declarations.                               ---*/
 /*------------------------------------------------------------*/
 
-static UInt mc_rd_V4_SLOWLY ( Addr a );
-static UInt mc_rd_V2_SLOWLY ( Addr a );
-static UInt mc_rd_V1_SLOWLY ( Addr a );
+static ULong mc_rd_V8_SLOWLY ( Addr a );
+static UInt  mc_rd_V4_SLOWLY ( Addr a );
+static UInt  mc_rd_V2_SLOWLY ( Addr a );
+static UInt  mc_rd_V1_SLOWLY ( Addr a );
+
+static void mc_wr_V8_SLOWLY ( Addr a, ULong vbytes );
 static void mc_wr_V4_SLOWLY ( Addr a, UInt vbytes );
 static void mc_wr_V2_SLOWLY ( Addr a, UInt vbytes );
 static void mc_wr_V1_SLOWLY ( Addr a, UInt vbytes );
+
 static void mc_fpu_read_check_SLOWLY  ( Addr addr, SizeT size );
 static void mc_fpu_write_check_SLOWLY ( Addr addr, SizeT size );
 
@@ -746,10 +750,12 @@ void mc_set_perms (Addr a, SizeT len, Bool rr, Bool ww, Bool xx)
 
 static void mc_post_regs_write_init ( void )
 {
+#if 0
    UInt i;
    for (i = FIRST_ARCH_REG; i <= LAST_ARCH_REG; i++)
       VG_(set_shadow_archreg)( i, VGM_WORD_VALID );
    VG_(set_shadow_eflags)( VGM_EFLAGS_VALID );
+#endif
 }
 
 static void mc_post_reg_write(ThreadId tid, UInt reg)
@@ -798,13 +804,90 @@ static __inline__ UInt shiftRight16 ( UInt x )
 }
 
 
-/* Read/write 1/2/4 sized V bytes, and emit an address error if
+/* Read/write 1/2/4/8 sized V bytes, and emit an address error if
    needed. */
 
-/* VG_(helperc_{LD,ST}V{1,2,4}) handle the common case fast.
+/* MC_(helperc_{LD,ST}V{1,2,4,8}) handle the common case fast.
    Under all other circumstances, it defers to the relevant _SLOWLY
    function, which can handle all situations.
 */
+
+/* ------------------------ Size = 8 ------------------------ */
+
+REGPARM(1)
+ULong MC_(helperc_LOADV8) ( Addr a )
+{
+#  ifdef VG_DEBUG_MEMORY
+   return mc_rd_V8_SLOWLY(a);
+#  else
+   if (IS_ALIGNED8_ADDR(a)) {
+      UInt    sec_no = shiftRight16(a) & 0xFFFF;
+      SecMap* sm     = primary_map[sec_no];
+      UInt    a_off  = (a & 0xFFFF) >> 3;
+      UChar   abits  = sm->abits[a_off];
+      if (abits == VGM_BYTE_VALID) {
+         /* a is 8-aligned, mapped, and addressible. */
+         UInt v_off = a & 0xFFFF;
+         /* LITTLE-ENDIAN */
+         UInt vLo   = ((UInt*)(sm->vbyte))[ (v_off >> 2) ];
+         UInt vHi   = ((UInt*)(sm->vbyte))[ (v_off >> 2) + 1 ];
+         return ( ((ULong)vHi) << 32 ) | ((ULong)vLo);
+      } else {
+         return mc_rd_V8_SLOWLY(a);
+      }
+   }
+   else
+   if (IS_ALIGNED4_ADDR(a)) {
+      /* LITTLE-ENDIAN */
+      UInt vLo =  MC_(helperc_LOADV4)(a+0);
+      UInt vHi =  MC_(helperc_LOADV4)(a+4);
+      return ( ((ULong)vHi) << 32 ) | ((ULong)vLo);
+   }
+   else
+      return mc_rd_V8_SLOWLY(a);
+#  endif
+}
+
+REGPARM(1)
+void MC_(helperc_STOREV8) ( Addr a, ULong vbytes )
+{
+#  ifdef VG_DEBUG_MEMORY
+   mc_wr_V8_SLOWLY(a, vbytes);
+#  else
+   if (IS_ALIGNED8_ADDR(a)) {
+      UInt    sec_no = shiftRight16(a) & 0xFFFF;
+      SecMap* sm     = primary_map[sec_no];
+      UInt    a_off  = (a & 0xFFFF) >> 3;
+      UChar   abits  = sm->abits[a_off];
+      if (abits == VGM_BYTE_VALID) {
+         /* a is 8-aligned, mapped, and addressible. */
+         UInt v_off = a & 0xFFFF;
+         UInt vHi = (UInt)(vbytes >> 32);
+         UInt vLo = (UInt)vbytes;
+         /* LITTLE-ENDIAN */
+         ((UInt*)(sm->vbyte))[ (v_off >> 2) ]     = vLo;
+         ((UInt*)(sm->vbyte))[ (v_off >> 2) + 1 ] = vHi;
+      } else {
+         mc_wr_V8_SLOWLY(a, vbytes);
+      }
+      return;
+   }
+   else
+   if (IS_ALIGNED4_ADDR(a)) {
+      UInt vHi = (UInt)(vbytes >> 32);
+      UInt vLo = (UInt)vbytes;
+      /* LITTLE-ENDIAN */
+      MC_(helperc_STOREV4)(a+0, vLo);
+      MC_(helperc_STOREV4)(a+4, vHi);
+      return;
+   }
+   else
+      mc_wr_V8_SLOWLY(a, vbytes);
+#  endif
+}
+
+/* ------------------------ Size = 4 ------------------------ */
+
 REGPARM(1)
 UInt MC_(helperc_LOADV4) ( Addr a )
 {
@@ -855,6 +938,8 @@ void MC_(helperc_STOREV4) ( Addr a, UInt vbytes )
 #  endif
 }
 
+/* ------------------------ Size = 2 ------------------------ */
+
 REGPARM(1)
 UInt MC_(helperc_LOADV2) ( Addr a )
 {
@@ -899,6 +984,8 @@ void MC_(helperc_STOREV2) ( Addr a, UInt vbytes )
 #  endif
 }
 
+/* ------------------------ Size = 1 ------------------------ */
+
 REGPARM(1)
 UInt MC_(helperc_LOADV1) ( Addr a )
 {
@@ -946,9 +1033,129 @@ void MC_(helperc_STOREV1) ( Addr a, UInt vbytes )
 
 /*------------------------------------------------------------*/
 /*--- Fallback functions to handle cases that the above    ---*/
-/*--- VG_(helperc_{LD,ST}V{1,2,4}) can't manage.           ---*/
+/*--- VG_(helperc_{LD,ST}V{1,2,4,8}) can't manage.         ---*/
 /*------------------------------------------------------------*/
 
+/* ------------------------ Size = 8 ------------------------ */
+
+static ULong mc_rd_V8_SLOWLY ( Addr a )
+{
+   Bool a0ok, a1ok, a2ok, a3ok, a4ok, a5ok, a6ok, a7ok;
+   UInt vb0,  vb1,  vb2,  vb3,  vb4,  vb5,  vb6,  vb7;
+
+   PROF_EVENT(70);
+
+   /* First establish independently the addressibility of the 4 bytes
+      involved. */
+   a0ok = get_abit(a+0) == VGM_BIT_VALID;
+   a1ok = get_abit(a+1) == VGM_BIT_VALID;
+   a2ok = get_abit(a+2) == VGM_BIT_VALID;
+   a3ok = get_abit(a+3) == VGM_BIT_VALID;
+   a4ok = get_abit(a+4) == VGM_BIT_VALID;
+   a5ok = get_abit(a+5) == VGM_BIT_VALID;
+   a6ok = get_abit(a+6) == VGM_BIT_VALID;
+   a7ok = get_abit(a+7) == VGM_BIT_VALID;
+
+   /* Also get the validity bytes for the address. */
+   vb0 = (UInt)get_vbyte(a+0);
+   vb1 = (UInt)get_vbyte(a+1);
+   vb2 = (UInt)get_vbyte(a+2);
+   vb3 = (UInt)get_vbyte(a+3);
+   vb4 = (UInt)get_vbyte(a+4);
+   vb5 = (UInt)get_vbyte(a+5);
+   vb6 = (UInt)get_vbyte(a+6);
+   vb7 = (UInt)get_vbyte(a+7);
+
+   /* Now distinguish 3 cases */
+
+   /* Case 1: the address is completely valid, so:
+      - no addressing error
+      - return V bytes as read from memory
+   */
+   if (a0ok && a1ok && a2ok && a3ok && a4ok && a5ok && a6ok && a7ok) {
+      ULong vw = VGM_WORD64_INVALID;
+      vw <<= 8; vw |= vb7;
+      vw <<= 8; vw |= vb6;
+      vw <<= 8; vw |= vb5;
+      vw <<= 8; vw |= vb4;
+      vw <<= 8; vw |= vb3;
+      vw <<= 8; vw |= vb2;
+      vw <<= 8; vw |= vb1;
+      vw <<= 8; vw |= vb0;
+      return vw;
+   }
+
+   /* Case 2: the address is completely invalid.  
+      - emit addressing error
+      - return V word indicating validity.  
+      This sounds strange, but if we make loads from invalid addresses 
+      give invalid data, we also risk producing a number of confusing
+      undefined-value errors later, which confuses the fact that the
+      error arose in the first place from an invalid address. 
+   */
+   /* VG_(printf)("%p (%d %d %d %d)\n", a, a0ok, a1ok, a2ok, a3ok); */
+   if (!MAC_(clo_partial_loads_ok) 
+       || ((a & 7) != 0)
+       || (!a0ok && !a1ok && !a2ok && !a3ok && !a4ok && !a5ok && !a6ok && !a7ok)) {
+      MAC_(record_address_error)( VG_(get_current_tid)(), a, 8, False );
+      return VGM_WORD64_VALID;
+   }
+
+   /* Case 3: the address is partially valid.  
+      - no addressing error
+      - returned V word is invalid where the address is invalid, 
+        and contains V bytes from memory otherwise. 
+      Case 3 is only allowed if MC_(clo_partial_loads_ok) is True
+      (which is the default), and the address is 4-aligned.  
+      If not, Case 2 will have applied.
+   */
+   tl_assert(MAC_(clo_partial_loads_ok));
+   {
+      ULong vw = VGM_WORD64_INVALID;
+      vw <<= 8; vw |= (a7ok ? vb7 : VGM_BYTE_INVALID);
+      vw <<= 8; vw |= (a6ok ? vb6 : VGM_BYTE_INVALID);
+      vw <<= 8; vw |= (a5ok ? vb5 : VGM_BYTE_INVALID);
+      vw <<= 8; vw |= (a4ok ? vb4 : VGM_BYTE_INVALID);
+      vw <<= 8; vw |= (a3ok ? vb3 : VGM_BYTE_INVALID);
+      vw <<= 8; vw |= (a2ok ? vb2 : VGM_BYTE_INVALID);
+      vw <<= 8; vw |= (a1ok ? vb1 : VGM_BYTE_INVALID);
+      vw <<= 8; vw |= (a0ok ? vb0 : VGM_BYTE_INVALID);
+      return vw;
+   }
+}
+
+static void mc_wr_V8_SLOWLY ( Addr a, ULong vbytes )
+{
+   /* Check the address for validity. */
+   Bool aerr = False;
+   PROF_EVENT(71);
+
+   if (get_abit(a+0) != VGM_BIT_VALID) aerr = True;
+   if (get_abit(a+1) != VGM_BIT_VALID) aerr = True;
+   if (get_abit(a+2) != VGM_BIT_VALID) aerr = True;
+   if (get_abit(a+3) != VGM_BIT_VALID) aerr = True;
+   if (get_abit(a+4) != VGM_BIT_VALID) aerr = True;
+   if (get_abit(a+5) != VGM_BIT_VALID) aerr = True;
+   if (get_abit(a+6) != VGM_BIT_VALID) aerr = True;
+   if (get_abit(a+7) != VGM_BIT_VALID) aerr = True;
+
+   /* Store the V bytes, remembering to do it little-endian-ly. */
+   set_vbyte( a+0, vbytes & 0x000000FF ); vbytes >>= 8;
+   set_vbyte( a+1, vbytes & 0x000000FF ); vbytes >>= 8;
+   set_vbyte( a+2, vbytes & 0x000000FF ); vbytes >>= 8;
+   set_vbyte( a+3, vbytes & 0x000000FF ); vbytes >>= 8;
+   set_vbyte( a+4, vbytes & 0x000000FF ); vbytes >>= 8;
+   set_vbyte( a+5, vbytes & 0x000000FF ); vbytes >>= 8;
+   set_vbyte( a+6, vbytes & 0x000000FF ); vbytes >>= 8;
+   set_vbyte( a+7, vbytes & 0x000000FF );
+
+   /* If an address error has happened, report it. */
+   if (aerr)
+      MAC_(record_address_error)( VG_(get_current_tid)(), a, 8, True );
+}
+
+/* ------------------------ Size = 4 ------------------------ */
+
 static UInt mc_rd_V4_SLOWLY ( Addr a )
 {
    Bool a0ok, a1ok, a2ok, a3ok;
@@ -1042,6 +1249,8 @@ static void mc_wr_V4_SLOWLY ( Addr a, UInt vbytes )
       MAC_(record_address_error)( VG_(get_current_tid)(), a, 4, True );
 }
 
+/* ------------------------ Size = 2 ------------------------ */
+
 static UInt mc_rd_V2_SLOWLY ( Addr a )
 {
    /* Check the address for validity. */
@@ -1083,6 +1292,8 @@ static void mc_wr_V2_SLOWLY ( Addr a, UInt vbytes )
       MAC_(record_address_error)( VG_(get_current_tid)(), a, 2, True );
 }
 
+/* ------------------------ Size = 1 ------------------------ */
+
 static UInt mc_rd_V1_SLOWLY ( Addr a )
 {
    /* Check the address for validity. */
@@ -1145,6 +1356,11 @@ void MC_(helperc_value_check4_fail) ( void )
    MC_(record_value_error) ( VG_(get_current_tid)(), 4 );
 }
 
+REGPARM(1) void MC_(helperc_complain_undef) ( HWord sz )
+{
+   MC_(record_value_error) ( VG_(get_current_tid)(), (Int)sz );
+}
+
 
 /* ---------------------------------------------------------------------
    FPU load and store checks, called from generated code.
@@ -1987,22 +2203,6 @@ void TL_(pre_clo_init)(void)
    VG_(init_post_reg_write_clientreq_return)  ( & mc_post_reg_write );
    VG_(init_post_reg_write_clientcall_return) ( & mc_post_reg_write_clientcall );
 
-   /* Three compact slots taken up by stack memory helpers */
-   VG_(register_compact_helper)((Addr) & MC_(helper_value_check4_fail));
-   VG_(register_compact_helper)((Addr) & MC_(helper_value_check0_fail));
-   VG_(register_compact_helper)((Addr) & MC_(helper_value_check2_fail));
-   VG_(register_compact_helper)((Addr) & MC_(helperc_STOREV4));
-   VG_(register_compact_helper)((Addr) & MC_(helperc_LOADV4));
-
-   /* These two made non-compact because 2-byte transactions are rare. */
-   VG_(register_noncompact_helper)((Addr) & MC_(helperc_STOREV2));
-   VG_(register_noncompact_helper)((Addr) & MC_(helperc_STOREV1));
-   VG_(register_noncompact_helper)((Addr) & MC_(helperc_LOADV2));
-   VG_(register_noncompact_helper)((Addr) & MC_(helperc_LOADV1));
-   VG_(register_noncompact_helper)((Addr) & MC_(fpu_write_check));
-   VG_(register_noncompact_helper)((Addr) & MC_(fpu_read_check));
-   VG_(register_noncompact_helper)((Addr) & MC_(helper_value_check1_fail));
-
    VGP_(register_profile_event) ( VgpSetMem,   "set-mem-perms" );
    VGP_(register_profile_event) ( VgpCheckMem, "check-mem-perms" );
    VGP_(register_profile_event) ( VgpESPAdj,   "adjust-ESP" );
index 8d03ed79bdfd0c66c0d351da75a4f990199e085b..a8723efe83fadc49a79629517dab006459e00c2a 100644 (file)
@@ -1,6 +1,6 @@
 
 /*--------------------------------------------------------------------*/
-/*--- Instrument UCode to perform memory checking operations.      ---*/
+/*--- Instrument IR to perform memory checking operations.         ---*/
 /*---                                               mc_translate.c ---*/
 /*--------------------------------------------------------------------*/
 
 
 #include "mc_include.h"
 
-/* ---------------------------------------------------------------------
-   Template functions for extending UCode
-   ------------------------------------------------------------------ */
 
-/* Compare this with the restrictions on core instructions in
-   vg_translate.c:is_sane_UInstr().  Everything general said there
-   applies here too.
-*/
-Bool TL_(sane_XUInstr)(Bool beforeRA, Bool beforeLiveness, UInstr* u)
-{
-// SSS: duplicating these macros really sucks
-#  define LIT0 (u->lit32 == 0)
-#  define LIT1 (!(LIT0))
-#  define LITm (u->tag1 == Literal ? True : LIT0 )
-#  define SZ0 (u->size == 0)
-#  define SZi (u->size == 4 || u->size == 2 || u->size == 1)
-#  define SZj (u->size == 4 || u->size == 2 || u->size == 1 || u->size == 0)
-#  define CC0 (u->flags_r == FlagsEmpty && u->flags_w == FlagsEmpty)
-#  define TR1 (beforeRA ? (u->tag1 == TempReg) : (u->tag1 == RealReg))
-#  define TR2 (beforeRA ? (u->tag2 == TempReg) : (u->tag2 == RealReg))
-#  define A1  (u->tag1 == ArchReg)
-#  define A2  (u->tag2 == ArchReg)
-#  define L1  (u->tag1 == Literal && u->val1 == 0)
-#  define Ls1 (u->tag1 == Lit16)
-#  define Ls3 (u->tag3 == Lit16)
-#  define TRL1 (TR1 || L1)
-#  define N2  (u->tag2 == NoValue)
-#  define N3  (u->tag3 == NoValue)
-#  define COND0    (u->cond         == 0)
-#  define EXTRA4b0 (u->extra4b      == 0)
-#  define SG_WD0   (u->signed_widen == 0)
-#  define JMPKIND0 (u->jmpkind      == 0)
-#  define CCALL0   (u->argc==0 && u->regparms_n==0 && u->has_ret_val==0 && \
-                    ( beforeLiveness                                       \
-                    ? u->regs_live_after == ALL_RREGS_LIVE                 \
-                    : True ))
-#  define XOTHER   (COND0 && EXTRA4b0 && SG_WD0 && JMPKIND0 && CCALL0)
-
-   Int n_lits = 0;
-   if (u->tag1 == Literal) n_lits++;
-   if (u->tag2 == Literal) n_lits++;
-   if (u->tag3 == Literal) n_lits++;
-   if (n_lits > 1) 
-      return False;
+/*------------------------------------------------------------*/
+/*--- Forward decls                                        ---*/
+/*------------------------------------------------------------*/
+
+struct _MCEnv;
+
+static IRType  shadowType ( IRType ty );
+static IRExpr* expr2vbits ( struct _MCEnv* mce, IRExpr* e );
+
+
+/*------------------------------------------------------------*/
+/*--- Memcheck running state, and tmp management.          ---*/
+/*------------------------------------------------------------*/
 
-   /* Fields not checked: val1, val2, val3 */
-
-   switch (u->opcode) {
-
-   /* Fields checked: lit32   size flags_r/w tag1   tag2   tag3    (rest) */
-   case LOADV:  return LIT0 && SZi && CC0 &&  TR1 && TR2 &&  N3 && XOTHER;
-   case STOREV: return LITm && SZi && CC0 && TRL1 && TR2 &&  N3 && XOTHER;
-   case GETV:   return LIT0 && SZi && CC0 &&   A1 && TR2 &&  N3 && XOTHER;
-   case PUTV:   return LITm && SZi && CC0 && TRL1 &&  A2 &&  N3 && XOTHER;
-   case GETVF: 
-   case PUTVF:  return LIT0 && SZ0 && CC0 &&  TR1 &&  N2 &&  N3 && XOTHER;
-   case TESTV: 
-   case SETV:   return LIT0 && SZj && CC0 &&  TR1 &&  N2 &&  N3 && XOTHER;
-   case TAG1:   return LIT0 && SZ0 && CC0 &&  TR1 &&  N2 && Ls3 && XOTHER;
-   case TAG2:   return LIT0 && SZ0 && CC0 &&  TR1 && TR2 && Ls3 && XOTHER;
-   default:
-      VG_(printf)("unhandled opcode: %u\n", u->opcode);
-      VG_(tool_panic)("TL_(sane_XUInstr): unhandled opcode");
+/* Carries around state during memcheck instrumentation. */
+typedef
+   struct _MCEnv {
+      /* MODIFIED: the bb being constructed.  IRStmts are added. */
+      IRBB* bb;
+
+      /* MODIFIED: a table [0 .. #temps_in_original_bb-1] which maps
+         original temps to their current their current shadow temp.
+         Initially all entries are IRTemp_INVALID.  Entries are added
+         lazily since many original temps are not used due to
+         optimisation prior to instrumentation.  Note that floating
+         point original tmps are shadowed by integer tmps of the same
+         size, and Bit-typed original tmps are shadowed by the type
+         Ity_I8.  See comment below. */
+      IRTemp* tmpMap;
+      Int     n_originalTmps; /* for range checking */
+
+      /* READONLY: the guest layout.  This indicates which parts of
+         the guest state should be regarded as 'always defined'. */
+      VexGuestLayout* layout;
+      /* READONLY: the host word type.  Needed for constructing
+         arguments of type 'HWord' to be passed to helper functions.
+         Ity_I32 or Ity_I64 only. */
+      IRType hWordTy;
    }
-#  undef LIT0
-#  undef LIT1
-#  undef LITm
-#  undef SZ0
-#  undef SZi
-#  undef SZj
-#  undef CC0
-#  undef TR1
-#  undef TR2
-#  undef A1
-#  undef A2
-#  undef L1
-#  undef Ls1
-#  undef Ls3
-#  undef TRL1
-#  undef N2
-#  undef N3
-#  undef COND0
-#  undef EXTRA4b0
-#  undef JMPKIND0
-#  undef CCALL0
-#  undef XOTHER
-}
+   MCEnv;
+
+/* SHADOW TMP MANAGEMENT.  Shadow tmps are allocated lazily (on
+   demand), as they are encountered.  This is for two reasons.
+
+   (1) (less important reason): Many original tmps are unused due to
+   initial IR optimisation, and we do not want to spaces in tables
+   tracking them.
+
+   Shadow IRTemps are therefore allocated on demand.  mce.tmpMap is a
+   table indexed [0 .. n_types-1], which gives the current shadow for
+   each original tmp, or INVALID_IRTEMP if none is so far assigned.
+   It is necessary to support making multiple assignments to a shadow
+   -- specifically, after testing a shadow for definedness, it needs
+   to be made defined.  But IR's SSA property disallows this.  
+
+   (2) (more important reason): Therefore, when a shadow needs to get
+   a new value, a new temporary is created, the value is assigned to
+   that, and the tmpMap is updated to reflect the new binding.
+
+   A corollary is that if the tmpMap maps a given tmp to
+   INVALID_IRTEMP and we are hoping to read that shadow tmp, it means
+   there's a read-before-write error in the original tmps.  The IR
+   sanity checker should catch all such anomalies, however.  
+*/
 
-static Char* nameOfTagOp ( TagOp h )
+/* Find the tmp currently shadowing the given original tmp.  If none
+   so far exists, allocate one.  */
+static IRTemp findShadowTmp ( MCEnv* mce, IRTemp orig )
 {
-   switch (h) {
-      case Tag_PCast40:        return "PCast40";
-      case Tag_PCast20:        return "PCast20";
-      case Tag_PCast10:        return "PCast10";
-      case Tag_PCast01:        return "PCast01";
-      case Tag_PCast02:        return "PCast02";
-      case Tag_PCast04:        return "PCast04";
-      case Tag_PCast14:        return "PCast14";
-      case Tag_PCast12:        return "PCast12";
-      case Tag_PCast11:        return "PCast11";
-      case Tag_Left4:          return "Left4";
-      case Tag_Left2:          return "Left2";
-      case Tag_Left1:          return "Left1";
-      case Tag_SWiden14:       return "SWiden14";
-      case Tag_SWiden24:       return "SWiden24";
-      case Tag_SWiden12:       return "SWiden12";
-      case Tag_ZWiden14:       return "ZWiden14";
-      case Tag_ZWiden24:       return "ZWiden24";
-      case Tag_ZWiden12:       return "ZWiden12";
-      case Tag_UifU4:          return "UifU4";
-      case Tag_UifU2:          return "UifU2";
-      case Tag_UifU1:          return "UifU1";
-      case Tag_UifU0:          return "UifU0";
-      case Tag_DifD4:          return "DifD4";
-      case Tag_DifD2:          return "DifD2";
-      case Tag_DifD1:          return "DifD1";
-      case Tag_ImproveAND4_TQ: return "ImproveAND4_TQ";
-      case Tag_ImproveAND2_TQ: return "ImproveAND2_TQ";
-      case Tag_ImproveAND1_TQ: return "ImproveAND1_TQ";
-      case Tag_ImproveOR4_TQ:  return "ImproveOR4_TQ";
-      case Tag_ImproveOR2_TQ:  return "ImproveOR2_TQ";
-      case Tag_ImproveOR1_TQ:  return "ImproveOR1_TQ";
-      case Tag_DebugFn:        return "DebugFn";
-      default: VG_(tool_panic)("vg_nameOfTagOp");
+   tl_assert(orig < mce->n_originalTmps);
+   if (mce->tmpMap[orig] == IRTemp_INVALID) {
+      mce->tmpMap[orig] 
+         = newIRTemp(mce->bb->tyenv, 
+                     shadowType(mce->bb->tyenv->types[orig]));
    }
+   return mce->tmpMap[orig];
 }
 
-
-Char* TL_(name_XUOpcode)(Opcode opc)
+/* Allocate a new shadow for the given original tmp.  This means any
+   previous shadow is abandoned.  This is needed because it is
+   necessary to give a new value to a shadow once it has been tested
+   for undefinedness, but unfortunately IR's SSA property disallows
+   this.  Instead we must abandon the old shadow, allocate a new one
+   and use that instead. */
+static void newShadowTmp ( MCEnv* mce, IRTemp orig )
 {
-   switch (opc) {
-      case GETVF:   return "GETVF";
-      case PUTVF:   return "PUTVF";
-      case TAG1:    return "TAG1";
-      case TAG2:    return "TAG2";
-      case LOADV:   return "LOADV";
-      case STOREV:  return "STOREV";
-      case GETV:    return "GETV";
-      case PUTV:    return "PUTV";
-      case TESTV:   return "TESTV";
-      case SETV:    return "SETV";
-      default:      
-         VG_(printf)("unhandled opcode: %u\n", opc);
-         VG_(tool_panic)("TL_(name_XUOpcode): unhandled case");
-   }
+   tl_assert(orig < mce->n_originalTmps);
+   mce->tmpMap[orig] 
+      = newIRTemp(mce->bb->tyenv, 
+                  shadowType(mce->bb->tyenv->types[orig]));
 }
 
-/* ---------------------------------------------------------------------
-   Debugging stuff.
-   ------------------------------------------------------------------ */
 
-void TL_(pp_XUInstr)(UInstr* u)
+/*------------------------------------------------------------*/
+/*--- IRAtoms -- a subset of IRExprs                       ---*/
+/*------------------------------------------------------------*/
+
+/* An atom is either an IRExpr_Const or an IRExpr_Tmp, as defined by
+   isAtom() in libvex_ir.h.  Because this instrumenter expects flat
+   input, most of this code deals in atoms.  Usefully, a value atom
+   always has a V-value which is also an atom: constants are shadowed
+   by constants, and temps are shadowed by the corresponding shadow
+   temporary. */
+
+typedef  IRExpr  IRAtom;
+
+/* (used for sanity checks only): is this an atom which looks
+   like it's from original code? */
+static Bool isOriginalAtom ( MCEnv* mce, IRAtom* a1 )
 {
-   switch (u->opcode) {
-      case TAG1:
-         VG_(pp_UOperand)(u, 1, 4, False);
-         VG_(printf)(" = %s ( ", nameOfTagOp( u->val3 ));
-         VG_(pp_UOperand)(u, 1, 4, False);
-         VG_(printf)(" )");
-         break;
+   if (a1->tag == Iex_Const)
+      return True;
+   if (a1->tag == Iex_Tmp && a1->Iex.Tmp.tmp < mce->n_originalTmps)
+      return True;
+   return False;
+}
 
-      case TAG2:
-         VG_(pp_UOperand)(u, 2, 4, False);
-         VG_(printf)(" = %s ( ", nameOfTagOp( u->val3 ));
-         VG_(pp_UOperand)(u, 1, 4, False);
-         VG_(printf)(", ");
-         VG_(pp_UOperand)(u, 2, 4, False);
-         VG_(printf)(" )");
-         break;
+/* (used for sanity checks only): is this an atom which looks
+   like it's from shadow code? */
+static Bool isShadowAtom ( MCEnv* mce, IRAtom* a1 )
+{
+   if (a1->tag == Iex_Const)
+      return True;
+   if (a1->tag == Iex_Tmp && a1->Iex.Tmp.tmp >= mce->n_originalTmps)
+      return True;
+   return False;
+}
 
-      case STOREV: case LOADV:
-         VG_(pp_UOperand)(u, 1, u->size, u->opcode==LOADV);
-         VG_(printf)(", ");
-         VG_(pp_UOperand)(u, 2, u->size, u->opcode==STOREV);
-         break;
+/* (used for sanity checks only): check that both args are atoms and
+   are identically-kinded. */
+static Bool sameKindedAtoms ( IRAtom* a1, IRAtom* a2 )
+{
+   if (a1->tag == Iex_Tmp && a1->tag == Iex_Tmp)
+      return True;
+   if (a1->tag == Iex_Const && a1->tag == Iex_Const)
+      return True;
+   return False;
+}
 
-      case PUTVF: case GETVF:
-         VG_(pp_UOperand)(u, 1, 0, False);
-         break;
 
-      case GETV: case PUTV:
-         VG_(pp_UOperand)(u, 1, u->opcode==PUTV ? 4 : u->size, False);
-         VG_(printf)(", ");
-         VG_(pp_UOperand)(u, 2, u->opcode==GETV ? 4 : u->size, False);
-         break;
+/*------------------------------------------------------------*/
+/*--- Type management                                      ---*/
+/*------------------------------------------------------------*/
 
-      case TESTV: case SETV:
-         VG_(pp_UOperand)(u, 1, u->size, False);
-         break;
+/* Shadow state is always accessed using integer types.  This returns
+   an integer type with the same size (as per sizeofIRType) as the
+   given type.  The only valid shadow types are Bit, I8, I16, I32,
+   I64. */
 
-      default:
-         VG_(printf)("unhandled opcode: %u\n", u->opcode);
-         VG_(tool_panic)("TL_(pp_XUInstr): unhandled opcode");
+static IRType shadowType ( IRType ty )
+{
+   switch (ty) {
+      case Ity_I1:
+      case Ity_I8:
+      case Ity_I16:
+      case Ity_I32: 
+      case Ity_I64: return ty;
+      case Ity_F32: return Ity_I32;
+      case Ity_F64: return Ity_I64;
+      default: ppIRType(ty); 
+               VG_(tool_panic)("memcheck:shadowType");
    }
+}
 
+/* Produce a 'defined' value of the given shadow type.  Should only be
+   supplied shadow types (Bit/I8/I16/I32/UI64). */
+static IRExpr* definedOfType ( IRType ty ) {
+   switch (ty) {
+      case Ity_I1:  return IRExpr_Const(IRConst_U1(False));
+      case Ity_I8:  return IRExpr_Const(IRConst_U8(0));
+      case Ity_I16: return IRExpr_Const(IRConst_U16(0));
+      case Ity_I32: return IRExpr_Const(IRConst_U32(0));
+      case Ity_I64: return IRExpr_Const(IRConst_U64(0));
+      default:      VG_(tool_panic)("memcheck:definedOfType");
+   }
 }
 
-Int TL_(get_Xreg_usage)(UInstr* u, Tag tag, Int* regs, Bool* isWrites)
-{
-#  define RD(ono)    VG_UINSTR_READS_REG(ono, regs, isWrites)
-#  define WR(ono)    VG_UINSTR_WRITES_REG(ono, regs, isWrites)
-
-   Int n = 0;
-   switch (u->opcode) {        
-      case TAG1:    RD(1); WR(1);        break;
-      case TAG2:    RD(1); RD(2); WR(2); break;
-      case LOADV:   RD(1); WR(2);        break;
-      case STOREV:  RD(1); RD(2);        break;
-      case GETV:    WR(2);               break;
-      case PUTV:    RD(1);               break;
-      case TESTV:   RD(1);               break;
-      case SETV:    WR(1);               break;
-      case PUTVF:   RD(1);               break;
-      case GETVF:   WR(1);               break;
 
-      default: 
-         VG_(printf)("unhandled opcode: %u\n", u->opcode);
-         VG_(tool_panic)("TL_(get_Xreg_usage): unhandled opcode");
-   }
-   return n;
+/*------------------------------------------------------------*/
+/*--- Constructing IR fragments                            ---*/
+/*------------------------------------------------------------*/
 
-#  undef RD
-#  undef WR
+/* assign value to tmp */
+#define assign(_bb,_tmp,_expr)   \
+   addStmtToIRBB((_bb), IRStmt_Tmp((_tmp),(_expr)))
+
+/* add stmt to a bb */
+#define stmt(_bb,_stmt)    \
+   addStmtToIRBB((_bb), (_stmt))
+
+/* build various kinds of expressions */
+#define binop(_op, _arg1, _arg2) IRExpr_Binop((_op),(_arg1),(_arg2))
+#define unop(_op, _arg)          IRExpr_Unop((_op),(_arg))
+#define mkU8(_n)                 IRExpr_Const(IRConst_U8(_n))
+#define mkU16(_n)                IRExpr_Const(IRConst_U16(_n))
+#define mkU32(_n)                IRExpr_Const(IRConst_U32(_n))
+#define mkU64(_n)                IRExpr_Const(IRConst_U64(_n))
+#define mkexpr(_tmp)             IRExpr_Tmp((_tmp))
+
+/* bind the given expression to a new temporary, and return the
+   temporary.  This effectively converts an arbitrary expression into
+   an atom. */
+static IRAtom* assignNew ( MCEnv* mce, IRType ty, IRExpr* e ) {
+   IRTemp t = newIRTemp(mce->bb->tyenv, ty);
+   assign(mce->bb, t, e);
+   return mkexpr(t);
 }
 
+
 /*------------------------------------------------------------*/
-/*--- New instrumentation machinery.                       ---*/
+/*--- Constructing definedness primitive ops               ---*/
 /*------------------------------------------------------------*/
 
-static
-TagOp get_Tag_ImproveOR_TQ ( Int sz )
-{
-   switch (sz) {
-      case 4: return Tag_ImproveOR4_TQ;
-      case 2: return Tag_ImproveOR2_TQ;
-      case 1: return Tag_ImproveOR1_TQ;
-      default: VG_(tool_panic)("get_Tag_ImproveOR_TQ");
-   }
+/* --------- Defined-if-either-defined --------- */
+
+static IRAtom* mkDifD8 ( MCEnv* mce, IRAtom* a1, IRAtom* a2 ) {
+   tl_assert(isShadowAtom(mce,a1));
+   tl_assert(isShadowAtom(mce,a2));
+   return assignNew(mce, Ity_I8, binop(Iop_And8, a1, a2));
 }
 
+static IRAtom* mkDifD16 ( MCEnv* mce, IRAtom* a1, IRAtom* a2 ) {
+   tl_assert(isShadowAtom(mce,a1));
+   tl_assert(isShadowAtom(mce,a2));
+   return assignNew(mce, Ity_I16, binop(Iop_And16, a1, a2));
+}
 
-static
-TagOp get_Tag_ImproveAND_TQ ( Int sz )
-{
-   switch (sz) {
-      case 4: return Tag_ImproveAND4_TQ;
-      case 2: return Tag_ImproveAND2_TQ;
-      case 1: return Tag_ImproveAND1_TQ;
-      default: VG_(tool_panic)("get_Tag_ImproveAND_TQ");
-   }
+static IRAtom* mkDifD32 ( MCEnv* mce, IRAtom* a1, IRAtom* a2 ) {
+   tl_assert(isShadowAtom(mce,a1));
+   tl_assert(isShadowAtom(mce,a2));
+   return assignNew(mce, Ity_I32, binop(Iop_And32, a1, a2));
 }
 
+/* --------- Undefined-if-either-undefined --------- */
 
-static
-TagOp get_Tag_Left ( Int sz )
-{
-   switch (sz) {
-      case 4: return Tag_Left4;
-      case 2: return Tag_Left2;
-      case 1: return Tag_Left1;
-      default: VG_(tool_panic)("get_Tag_Left");
-   }
+static IRAtom* mkUifU8 ( MCEnv* mce, IRAtom* a1, IRAtom* a2 ) {
+   tl_assert(isShadowAtom(mce,a1));
+   tl_assert(isShadowAtom(mce,a2));
+   return assignNew(mce, Ity_I8, binop(Iop_Or8, a1, a2));
 }
 
+static IRAtom* mkUifU16 ( MCEnv* mce, IRAtom* a1, IRAtom* a2 ) {
+   tl_assert(isShadowAtom(mce,a1));
+   tl_assert(isShadowAtom(mce,a2));
+   return assignNew(mce, Ity_I16, binop(Iop_Or16, a1, a2));
+}
 
-static
-TagOp get_Tag_UifU ( Int sz )
-{
-   switch (sz) {
-      case 4: return Tag_UifU4;
-      case 2: return Tag_UifU2;
-      case 1: return Tag_UifU1;
-      case 0: return Tag_UifU0;
-      default: VG_(tool_panic)("get_Tag_UifU");
-   }
+static IRAtom* mkUifU32 ( MCEnv* mce, IRAtom* a1, IRAtom* a2 ) {
+   tl_assert(isShadowAtom(mce,a1));
+   tl_assert(isShadowAtom(mce,a2));
+   return assignNew(mce, Ity_I32, binop(Iop_Or32, a1, a2));
 }
 
+static IRAtom* mkUifU64 ( MCEnv* mce, IRAtom* a1, IRAtom* a2 ) {
+   tl_assert(isShadowAtom(mce,a1));
+   tl_assert(isShadowAtom(mce,a2));
+   return assignNew(mce, Ity_I64, binop(Iop_Or64, a1, a2));
+}
 
-static
-TagOp get_Tag_DifD ( Int sz )
-{
-   switch (sz) {
-      case 4: return Tag_DifD4;
-      case 2: return Tag_DifD2;
-      case 1: return Tag_DifD1;
-      default: VG_(tool_panic)("get_Tag_DifD");
+static IRAtom* mkUifU ( MCEnv* mce, IRType vty,  IRAtom* a1, IRAtom* a2 ) {
+   switch (vty) {
+      case Ity_I16: return mkUifU16(mce, a1, a2);
+      case Ity_I32: return mkUifU32(mce, a1, a2);
+      case Ity_I64: return mkUifU64(mce, a1, a2);
+      default:
+         VG_(printf)("\n"); ppIRType(vty); VG_(printf)("\n");
+         VG_(tool_panic)("memcheck:mkUifU");
    }
 }
 
+/* --------- The Left-family of operations. --------- */
 
-static 
-TagOp get_Tag_PCast ( Int szs, Int szd )
-{
-   if (szs == 4 && szd == 0) return Tag_PCast40;
-   if (szs == 2 && szd == 0) return Tag_PCast20;
-   if (szs == 1 && szd == 0) return Tag_PCast10;
-   if (szs == 0 && szd == 1) return Tag_PCast01;
-   if (szs == 0 && szd == 2) return Tag_PCast02;
-   if (szs == 0 && szd == 4) return Tag_PCast04;
-   if (szs == 1 && szd == 4) return Tag_PCast14;
-   if (szs == 1 && szd == 2) return Tag_PCast12;
-   if (szs == 1 && szd == 1) return Tag_PCast11;
-   VG_(printf)("get_Tag_PCast(%d,%d)\n", szs, szd);
-   VG_(tool_panic)("get_Tag_PCast");
+static IRAtom* mkLeft8 ( MCEnv* mce, IRAtom* a1 ) {
+   tl_assert(isShadowAtom(mce,a1));
+   /* It's safe to duplicate a1 since it's only an atom */
+   return assignNew(mce, Ity_I8, 
+                    binop(Iop_Or8, a1, 
+                          assignNew(mce, Ity_I8,
+                                    /* unop(Iop_Neg8, a1)))); */
+                                    binop(Iop_Sub8, mkU8(0), a1) )));
 }
 
+static IRAtom* mkLeft16 ( MCEnv* mce, IRAtom* a1 ) {
+   tl_assert(isShadowAtom(mce,a1));
+   /* It's safe to duplicate a1 since it's only an atom */
+   return assignNew(mce, Ity_I16, 
+                    binop(Iop_Or16, a1, 
+                          assignNew(mce, Ity_I16,
+                                    /* unop(Iop_Neg16, a1)))); */
+                                    binop(Iop_Sub16, mkU16(0), a1) )));
+}
 
-static 
-TagOp get_Tag_Widen ( Bool syned, Int szs, Int szd )
-{
-   if (szs == 1 && szd == 2 && syned)  return Tag_SWiden12;
-   if (szs == 1 && szd == 2 && !syned) return Tag_ZWiden12;
-
-   if (szs == 1 && szd == 4 && syned)  return Tag_SWiden14;
-   if (szs == 1 && szd == 4 && !syned) return Tag_ZWiden14;
+static IRAtom* mkLeft32 ( MCEnv* mce, IRAtom* a1 ) {
+   tl_assert(isShadowAtom(mce,a1));
+   /* It's safe to duplicate a1 since it's only an atom */
+   return assignNew(mce, Ity_I32, 
+                    binop(Iop_Or32, a1, 
+                          assignNew(mce, Ity_I32,
+                                    /* unop(Iop_Neg32, a1)))); */
+                                    binop(Iop_Sub32, mkU32(0), a1) )));
+}
 
-   if (szs == 2 && szd == 4 && syned)  return Tag_SWiden24;
-   if (szs == 2 && szd == 4 && !syned) return Tag_ZWiden24;
+/* --------- 'Improvement' functions for AND/OR. --------- */
 
-   VG_(printf)("get_Tag_Widen(%d,%d,%d)\n", (Int)syned, szs, szd);
-   VG_(tool_panic)("get_Tag_Widen");
+/* ImproveAND(data, vbits) = data OR vbits.  Defined (0) data 0s give
+   defined (0); all other -> undefined (1).
+*/
+static IRAtom* mkImproveAND8 ( MCEnv* mce, IRAtom* data, IRAtom* vbits )
+{
+   tl_assert(isOriginalAtom(mce, data));
+   tl_assert(isShadowAtom(mce, vbits));
+   tl_assert(sameKindedAtoms(data, vbits));
+   return assignNew(mce, Ity_I8, binop(Iop_Or8, data, vbits));
 }
 
-/* Pessimally cast the spec'd shadow from one size to another. */
-static 
-void create_PCast ( UCodeBlock* cb, Int szs, Int szd, Int tempreg )
+static IRAtom* mkImproveAND16 ( MCEnv* mce, IRAtom* data, IRAtom* vbits )
 {
-   if (szs == 0 && szd == 0)
-      return;
-   uInstr3(cb, TAG1, 0, TempReg, tempreg, 
-                        NoValue, 0, 
-                        Lit16,   get_Tag_PCast(szs,szd));
+   tl_assert(isOriginalAtom(mce, data));
+   tl_assert(isShadowAtom(mce, vbits));
+   tl_assert(sameKindedAtoms(data, vbits));
+   return assignNew(mce, Ity_I16, binop(Iop_Or16, data, vbits));
 }
 
+static IRAtom* mkImproveAND32 ( MCEnv* mce, IRAtom* data, IRAtom* vbits )
+{
+   tl_assert(isOriginalAtom(mce, data));
+   tl_assert(isShadowAtom(mce, vbits));
+   tl_assert(sameKindedAtoms(data, vbits));
+   return assignNew(mce, Ity_I32, binop(Iop_Or32, data, vbits));
+}
 
-/* Create a signed or unsigned widen of the spec'd shadow from one
-   size to another.  The only allowed size transitions are 1->2, 1->4
-   and 2->4. */
-static 
-void create_Widen ( UCodeBlock* cb, Bool signed_widen,
-                    Int szs, Int szd, Int tempreg )
+/* ImproveOR(data, vbits) = ~data OR vbits.  Defined (0) data 1s give
+   defined (0); all other -> undefined (1).
+*/
+static IRAtom* mkImproveOR8 ( MCEnv* mce, IRAtom* data, IRAtom* vbits )
 {
-   if (szs == szd) return;
-   uInstr3(cb, TAG1, 0, TempReg, tempreg, 
-                        NoValue, 0, 
-                        Lit16,   get_Tag_Widen(signed_widen,szs,szd));
+   tl_assert(isOriginalAtom(mce, data));
+   tl_assert(isShadowAtom(mce, vbits));
+   tl_assert(sameKindedAtoms(data, vbits));
+   return assignNew(
+             mce, Ity_I8, 
+             binop(Iop_Or8, 
+                   assignNew(mce, Ity_I8, unop(Iop_Not8, data)), 
+                   vbits) );
 }
 
+static IRAtom* mkImproveOR16 ( MCEnv* mce, IRAtom* data, IRAtom* vbits )
+{
+   tl_assert(isOriginalAtom(mce, data));
+   tl_assert(isShadowAtom(mce, vbits));
+   tl_assert(sameKindedAtoms(data, vbits));
+   return assignNew(
+             mce, Ity_I16, 
+             binop(Iop_Or16, 
+                   assignNew(mce, Ity_I16, unop(Iop_Not16, data)), 
+                   vbits) );
+}
 
-/* Get the condition codes into a new shadow, at the given size. */
-static
-Int create_GETVF ( UCodeBlock* cb, Int sz )
+static IRAtom* mkImproveOR32 ( MCEnv* mce, IRAtom* data, IRAtom* vbits )
 {
-   Int tt = newShadow(cb);
-   uInstr1(cb, GETVF, 0, TempReg, tt);
-   create_PCast(cb, 0, sz, tt);
-   return tt;
+   tl_assert(isOriginalAtom(mce, data));
+   tl_assert(isShadowAtom(mce, vbits));
+   tl_assert(sameKindedAtoms(data, vbits));
+   return assignNew(
+             mce, Ity_I32, 
+             binop(Iop_Or32, 
+                   assignNew(mce, Ity_I32, unop(Iop_Not32, data)), 
+                   vbits) );
 }
 
+/* --------- Pessimising casts. --------- */
 
-/* Save the condition codes from the spec'd shadow. */
-static
-void create_PUTVF ( UCodeBlock* cb, Int sz, Int tempreg )
+static IRAtom* mkPCastTo( MCEnv* mce, IRType dst_ty, IRAtom* vbits ) 
 {
-   if (sz == 0) {
-      uInstr1(cb, PUTVF, 0, TempReg, tempreg);
-   } else { 
-      Int tt = newShadow(cb);
-      uInstr2(cb, MOV, 4, TempReg, tempreg, TempReg, tt);
-      create_PCast(cb, sz, 0, tt);
-      uInstr1(cb, PUTVF, 0, TempReg, tt);
+   /* Note, dst_ty is a shadow type, not an original type. */
+   /* First of all, collapse vbits down to a single bit. */
+   tl_assert(isShadowAtom(mce,vbits));
+   IRType  ty   = typeOfIRExpr(mce->bb->tyenv, vbits);
+   IRAtom* tmp1 = NULL;
+   switch (ty) {
+      case Ity_I1:
+         tmp1 = vbits;
+         break;
+      case Ity_I8: 
+         tmp1 = assignNew(mce, Ity_I1, binop(Iop_CmpNE8, vbits, mkU8(0)));
+         break;
+      case Ity_I16: 
+         tmp1 = assignNew(mce, Ity_I1, binop(Iop_CmpNE16, vbits, mkU16(0)));
+         break;
+      case Ity_I32: 
+         tmp1 = assignNew(mce, Ity_I1, binop(Iop_CmpNE32, vbits, mkU32(0)));
+         break;
+      case Ity_I64: 
+         tmp1 = assignNew(mce, Ity_I1, binop(Iop_CmpNE64, vbits, mkU64(0)));
+         break;
+      default:
+         VG_(tool_panic)("mkPCastTo(1)");
+   }
+   tl_assert(tmp1);
+   /* Now widen up to the dst type. */
+   switch (dst_ty) {
+      case Ity_I1:
+         return tmp1;
+      case Ity_I8: 
+         return assignNew(mce, Ity_I8, unop(Iop_1Sto8, tmp1));
+      case Ity_I16: 
+         return assignNew(mce, Ity_I16, unop(Iop_1Sto16, tmp1));
+      case Ity_I32: 
+         return assignNew(mce, Ity_I32, unop(Iop_1Sto32, tmp1));
+      case Ity_I64: 
+         return assignNew(mce, Ity_I64, unop(Iop_1Sto64, tmp1));
+      default: 
+         ppIRType(dst_ty);
+         VG_(tool_panic)("mkPCastTo(2)");
    }
 }
 
 
-/* Do Left on the spec'd shadow. */
-static 
-void create_Left ( UCodeBlock* cb, Int sz, Int tempreg )
-{
-   uInstr3(cb, TAG1, 0, 
-               TempReg, tempreg,
-               NoValue, 0, 
-               Lit16, get_Tag_Left(sz));
+/*------------------------------------------------------------*/
+/*--- Emit a test and complaint if something is undefined. ---*/
+/*------------------------------------------------------------*/
+
+/* Set the annotations on a dirty helper to indicate that the stack
+   pointer and instruction pointers might be read.  This is the
+   behaviour of all 'emit-a-complaint' style functions we might
+   call. */
+
+static void setHelperAnns ( MCEnv* mce, IRDirty* di ) {
+   di->nFxState = 2;
+   di->fxState[0].fx     = Ifx_Read;
+   di->fxState[0].offset = mce->layout->offset_SP;
+   di->fxState[0].size   = mce->layout->sizeof_SP;
+   di->fxState[1].fx     = Ifx_Read;
+   di->fxState[1].offset = mce->layout->offset_IP;
+   di->fxState[1].size   = mce->layout->sizeof_IP;
 }
 
 
-/* Do UifU on ts and td, putting the result in td. */
-static 
-void create_UifU ( UCodeBlock* cb, Int sz, Int ts, Int td )
+/* Check the supplied **original** atom for undefinedness, and emit a
+   complaint if so.  Once that happens, mark it as defined.  This is
+   possible because the atom is either a tmp or literal.  If it's a
+   tmp, it will be shadowed by a tmp, and so we can set the shadow to
+   be defined.  In fact as mentioned above, we will have to allocate a
+   new tmp to carry the new 'defined' shadow value, and update the
+   original->tmp mapping accordingly; we cannot simply assign a new
+   value to an existing shadow tmp as this breaks SSAness -- resulting
+   in the post-instrumentation sanity checker spluttering in disapproval. 
+*/
+static void complainIfUndefined ( MCEnv* mce, IRAtom* atom )
 {
-   uInstr3(cb, TAG2, 0, TempReg, ts, TempReg, td,
-               Lit16, get_Tag_UifU(sz));
-}
+   /* Since the original expression is atomic, there's no duplicated
+      work generated by making multiple V-expressions for it.  So we
+      don't really care about the possibility that someone else may
+      also create a V-interpretion for it. */
+   tl_assert(isOriginalAtom(mce, atom));
+   IRAtom* vatom = expr2vbits( mce, atom );
+   tl_assert(isShadowAtom(mce, vatom));
+   tl_assert(sameKindedAtoms(atom, vatom));
 
+   IRType ty = typeOfIRExpr(mce->bb->tyenv, vatom);
 
-/* Do DifD on ts and td, putting the result in td. */
-static 
-void create_DifD ( UCodeBlock* cb, Int sz, Int ts, Int td )
-{
-   uInstr3(cb, TAG2, 0, TempReg, ts, TempReg, td,
-               Lit16, get_Tag_DifD(sz));
-}
+   /* sz is only used for constructing the error message */
+   Int    sz = ty==Ity_I1 ? 0 : sizeofIRType(ty);
 
+   IRAtom* cond = mkPCastTo( mce, Ity_I1, vatom );
+   /* cond will be 0 if all defined, and 1 if any not defined. */
 
-/* Do HelpAND on value tval and tag tqqq, putting the result in
-   tqqq. */
-static 
-void create_ImproveAND_TQ ( UCodeBlock* cb, Int sz, Int tval, Int tqqq )
-{
-   uInstr3(cb, TAG2, 0, TempReg, tval, TempReg, tqqq,
-               Lit16, get_Tag_ImproveAND_TQ(sz));
+   IRDirty* di;
+   switch (sz) {
+      case 0:
+         di = unsafeIRDirty_0_N( 0/*regparms*/, 
+                                 "MC_(helperc_value_check0_fail)",
+                                 &MC_(helperc_value_check0_fail),
+                                 mkIRExprVec_0() 
+                               );
+         break;
+      case 1:
+         di = unsafeIRDirty_0_N( 0/*regparms*/, 
+                                 "MC_(helperc_value_check1_fail)",
+                                 &MC_(helperc_value_check1_fail),
+                                 mkIRExprVec_0() 
+                               );
+         break;
+      case 4:
+         di = unsafeIRDirty_0_N( 0/*regparms*/, 
+                                 "MC_(helperc_value_check4_fail)",
+                                 &MC_(helperc_value_check4_fail),
+                                 mkIRExprVec_0() 
+                               );
+         break;
+      default:
+         di = unsafeIRDirty_0_N( 1/*regparms*/, 
+                                 "MC_(helperc_complain_undef)",
+                                 &MC_(helperc_complain_undef),
+                                 mkIRExprVec_1( mkIRExpr_HWord( sz ))
+                               );
+         break;
+   }
+   di->guard = cond;
+   setHelperAnns( mce, di );
+   stmt( mce->bb, IRStmt_Dirty(di));
+
+   /* Set the shadow tmp to be defined.  First, update the
+      orig->shadow tmp mapping to reflect the fact that this shadow is
+      getting a new value. */
+   tl_assert(isAtom(vatom));
+   /* sameKindedAtoms ... */
+   if (vatom->tag == Iex_Tmp) {
+      tl_assert(atom->tag == Iex_Tmp);
+      newShadowTmp(mce, atom->Iex.Tmp.tmp);
+      assign(mce->bb, findShadowTmp(mce, atom->Iex.Tmp.tmp), 
+                      definedOfType(ty));
+   }
 }
 
 
-/* Do HelpOR on value tval and tag tqqq, putting the result in
-   tqqq. */
-static 
-void create_ImproveOR_TQ ( UCodeBlock* cb, Int sz, Int tval, Int tqqq )
+/*------------------------------------------------------------*/
+/*--- Shadowing PUTs/GETs, and indexed variants thereof    ---*/
+/*------------------------------------------------------------*/
+
+/* Examine the always-defined sections declared in layout to see if
+   the (offset,size) section is within one.  Note, is is an error to
+   partially fall into such a region: (offset,size) should either be
+   completely in such a region or completely not-in such a region.  
+*/
+static Bool isAlwaysDefd ( MCEnv* mce, Int offset, Int size )
 {
-   uInstr3(cb, TAG2, 0, TempReg, tval, TempReg, tqqq,
-               Lit16, get_Tag_ImproveOR_TQ(sz));
+   Int minoffD, maxoffD, i;
+   Int minoff = offset;
+   Int maxoff = minoff + size - 1;
+   tl_assert((minoff & ~0xFFFF) == 0);
+   tl_assert((maxoff & ~0xFFFF) == 0);
+
+   for (i = 0; i < mce->layout->n_alwaysDefd; i++) {
+      minoffD = mce->layout->alwaysDefd[i].offset;
+      maxoffD = minoffD + mce->layout->alwaysDefd[i].size - 1;
+      tl_assert((minoffD & ~0xFFFF) == 0);
+      tl_assert((maxoffD & ~0xFFFF) == 0);
+
+      if (maxoff < minoffD || maxoffD < minoff)
+         continue; /* no overlap */
+      if (minoff >= minoffD && maxoff <= maxoffD)
+         return True; /* completely contained in an always-defd section */
+
+      VG_(tool_panic)("memcheck:isAlwaysDefd:partial overlap");
+   }
+   return False; /* could not find any containing section */
 }
 
 
-/* Get the shadow for an operand described by (tag, val).  Emit code
-   to do this and return the identity of the shadow holding the
-   result.  The result tag is always copied into a new shadow, so it
-   can be modified without trashing the original.*/
+/* Generate into bb suitable actions to shadow this Put.  If the state
+   slice is marked 'always defined', do nothing.  Otherwise, write the
+   supplied V bits to the shadow state.  We can pass in either an
+   original atom or a V-atom, but not both.  In the former case the
+   relevant V-bits are then generated from the original.
+*/
 static
-Int /* TempReg */ getOperandShadow ( UCodeBlock* cb
-                                     Int sz, Int tag, Int val )
+void do_shadow_PUT ( MCEnv* mce,  Int offset
+                     IRAtom* atom, IRAtom* vatom )
 {
-   Int sh;
-   sh = newShadow(cb);
-   if (tag == TempReg) {
-      uInstr2(cb, MOV, 4, TempReg, SHADOW(val), TempReg, sh);
-      return sh;
+   if (atom) {
+      tl_assert(!vatom);
+      tl_assert(isOriginalAtom(mce, atom));
+      vatom = expr2vbits( mce, atom );
+   } else {
+      tl_assert(vatom);
+      tl_assert(isShadowAtom(mce, vatom));
    }
-   if (tag == Literal) {
-      uInstr1(cb, SETV, sz, TempReg, sh);
-      return sh;
-   }
-   if (tag == ArchReg) {
-      uInstr2(cb, GETV, sz, ArchReg, val, TempReg, sh);
-      return sh;
+
+   IRType ty = typeOfIRExpr(mce->bb->tyenv, vatom);
+   tl_assert(ty != Ity_I1);
+   if (isAlwaysDefd(mce, offset, sizeofIRType(ty))) {
+      /* later: no ... */
+      /* emit code to emit a complaint if any of the vbits are 1. */
+      /* complainIfUndefined(mce, atom); */
+   } else {
+      /* Do a plain shadow Put. */
+      stmt( mce->bb, IRStmt_Put( offset + mce->layout->total_sizeB, vatom ) );
    }
-   VG_(tool_panic)("getOperandShadow");
 }
 
-/* Create and return an instrumented version of cb_in.  Free cb_in
-   before returning. */
-static UCodeBlock* memcheck_instrument ( UCodeBlock* cb_in )
+
+/* Return an expression which contains the V bits corresponding to the
+   given GETI (passed in in pieces). 
+*/
+static
+void do_shadow_PUTI ( MCEnv* mce, 
+                      IRArray* descr, IRAtom* ix, Int bias, IRAtom* atom )
 {
-   UCodeBlock* cb;
-   Int         i, j;
-   UInstr*     u_in;
-   Int         qs, qd, qt, qtt;
-   Bool        bogusLiterals;
-
-   cb = VG_(setup_UCodeBlock)(cb_in);
-
-   /* Scan the block to look for bogus literals.  These are magic
-      numbers which particularly appear in hand-optimised / inlined
-      implementations of strlen() et al which cause so much trouble
-      (spurious reports of uninit-var uses).  Purpose of this horrible
-      hack is to disable some checks any such literals are present in
-      this basic block. */
-   bogusLiterals = False;
-
-   if (MC_(clo_avoid_strlen_errors)) {
-      for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
-         u_in = VG_(get_instr)(cb_in, i);
-         switch (u_in->opcode) {
-            case ADD: case SUB: case MOV: 
-               if (u_in->size == 4 && u_in->tag1 == Literal)
-                  goto literal;
-               break;
-            case LEA1: 
-               tl_assert(u_in->size == 4);
-               goto literal;
-            default: 
-               break;
-         }     
-         continue;
-        literal:
-         if (u_in->lit32 == 0xFEFEFEFF ||
-             u_in->lit32 == 0x80808080 ||
-             u_in->lit32 == 0x00008080) {
-            bogusLiterals = True;
-            break;
-         }
-      }
+   tl_assert(isOriginalAtom(mce,atom));
+   IRAtom* vatom = expr2vbits( mce, atom );
+   tl_assert(sameKindedAtoms(atom, vatom));
+   IRType ty   = descr->elemTy;
+   IRType tyS  = shadowType(ty);
+   Int arrSize = descr->nElems * sizeofIRType(ty);
+   tl_assert(ty != Ity_I1);
+   tl_assert(isOriginalAtom(mce,ix));
+   complainIfUndefined(mce,ix);
+   if (isAlwaysDefd(mce, descr->base, arrSize)) {
+      /* later: no ... */
+      /* emit code to emit a complaint if any of the vbits are 1. */
+      /* complainIfUndefined(mce, atom); */
+   } else {
+      /* Do a cloned version of the Put that refers to the shadow
+         area. */
+      IRArray* new_descr 
+         = mkIRArray( descr->base + mce->layout->total_sizeB, 
+                      tyS, descr->nElems);
+      stmt( mce->bb, IRStmt_PutI( new_descr, ix, bias, vatom ));
    }
+}
 
-   for (i = 0; i < VG_(get_num_instrs)(cb_in); i++) {
-      u_in = VG_(get_instr)(cb_in, i);
-      qs = qd = qt = qtt = INVALID_TEMPREG;
 
-      switch (u_in->opcode) {
+/* Return an expression which contains the V bits corresponding to the
+   given GET (passed in in pieces). 
+*/
+static 
+IRExpr* shadow_GET ( MCEnv* mce, Int offset, IRType ty )
+{
+   IRType tyS = shadowType(ty);
+   tl_assert(ty != Ity_I1);
+   if (isAlwaysDefd(mce, offset, sizeofIRType(ty))) {
+      /* Always defined, return all zeroes of the relevant type */
+      return definedOfType(tyS);
+   } else {
+      /* return a cloned version of the Get that refers to the shadow
+         area. */
+      return IRExpr_Get( offset + mce->layout->total_sizeB, tyS );
+   }
+}
 
-         case LOCK:
-         case NOP:
-            break;
 
-         case INCEIP:
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+/* Return an expression which contains the V bits corresponding to the
+   given GETI (passed in in pieces). 
+*/
+static
+IRExpr* shadow_GETI ( MCEnv* mce, IRArray* descr, IRAtom* ix, Int bias )
+{
+   IRType ty   = descr->elemTy;
+   IRType tyS  = shadowType(ty);
+   Int arrSize = descr->nElems * sizeofIRType(ty);
+   tl_assert(ty != Ity_I1);
+   tl_assert(isOriginalAtom(mce,ix));
+   complainIfUndefined(mce,ix);
+   if (isAlwaysDefd(mce, descr->base, arrSize)) {
+      /* Always defined, return all zeroes of the relevant type */
+      return definedOfType(tyS);
+   } else {
+      /* return a cloned version of the Get that refers to the shadow
+         area. */
+      IRArray* new_descr 
+         = mkIRArray( descr->base + mce->layout->total_sizeB, 
+                      tyS, descr->nElems);
+      return IRExpr_GetI( new_descr, ix, bias );
+   }
+}
 
-         /* The segment registers do not have their definedness
-            tracked.  We therefore make fake shadows on GETSEG and
-            test them on PUTSEG.  This will catch writing garbage to a
-            segment register; therefore we can assume it to be defined
-            when read (GETSEGd).  Since the first arg of USESEG is
-            fetched by GETSEG, we can assume it to be defined, and so
-            the definedness of the result is simply the definedness of
-            the second (virtual_address) arg of USESEG.  The upshot of
-            all this is that instrumentation of USESEG is a no-op! */
-
-         case PUTSEG:
-            tl_assert(u_in->tag1 == TempReg);
-            uInstr1(cb, TESTV, 2, TempReg, SHADOW(u_in->val1));
-            uInstr1(cb, SETV,  2, TempReg, SHADOW(u_in->val1));
-            VG_(copy_UInstr)(cb, u_in);
-            break;
 
-         case GETSEG:
-            tl_assert(u_in->tag2 == TempReg);
-            uInstr1(cb, SETV,  2, TempReg, SHADOW(u_in->val2));
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+/*------------------------------------------------------------*/
+/*--- Generating approximations for unknown operations,    ---*/
+/*--- using lazy-propagate semantics                       ---*/
+/*------------------------------------------------------------*/
 
-         case USESEG:
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+/* Lazy propagation of undefinedness from two values, resulting in the
+   specified shadow type. 
+*/
+static
+IRAtom* mkLazy2 ( MCEnv* mce, IRType finalVty, IRAtom* va1, IRAtom* va2 )
+{
+   /* force everything via 32-bit intermediaries. */
+   IRAtom* at;
+   tl_assert(isShadowAtom(mce,va1));
+   tl_assert(isShadowAtom(mce,va2));
+   at = mkPCastTo(mce, Ity_I32, va1);
+   at = mkUifU(mce, Ity_I32, at, mkPCastTo(mce, Ity_I32, va2));
+   at = mkPCastTo(mce, finalVty, at);
+   return at;
+}
 
-         /* Loads and stores.  Test the V bits for the address.  24
-            Mar 02: since the address is A-checked anyway, there's not
-            really much point in doing the V-check too, unless you
-            think that you might use addresses which are undefined but
-            still addressible.  Hence the optionalisation of the V
-            check.  15 Dec 02: optionalisation removed, since it no
-            longer makes much sense given we also have an addrcheck
-            tool.
-
-            The LOADV/STOREV does an addressibility check for the
-            address. */
-
-         case LOAD: 
-            uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val1));
-            uInstr1(cb, SETV,  4, TempReg, SHADOW(u_in->val1));
-            uInstr2(cb, LOADV, u_in->size, 
-                        TempReg, u_in->val1,
-                        TempReg, SHADOW(u_in->val2));
-            VG_(copy_UInstr)(cb, u_in);
-            break;
 
-         case STORE:
-            uInstr1(cb, TESTV,  4, TempReg, SHADOW(u_in->val2));
-            uInstr1(cb, SETV,   4, TempReg, SHADOW(u_in->val2));
-            uInstr2(cb, STOREV, u_in->size,
-                        TempReg, SHADOW(u_in->val1), 
-                        TempReg, u_in->val2);
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+/* Do the lazy propagation game from a null-terminated vector of
+   atoms.  This is presumably the arguments to a helper call, so the
+   IRCallee info is also supplied in order that we can know which
+   arguments should be ignored (via the .mcx_mask field). 
+*/
+static
+IRAtom* mkLazyN ( MCEnv* mce, 
+                  IRAtom** exprvec, IRType finalVtype, IRCallee* cee )
+{
+   Int i;
+   IRAtom* here;
+   IRAtom* curr = definedOfType(Ity_I32);
+   for (i = 0; exprvec[i]; i++) {
+      tl_assert(i < 32);
+      tl_assert(isOriginalAtom(mce, exprvec[i]));
+      /* Only take notice of this arg if the callee's mc-exclusion
+         mask does not say it is to be excluded. */
+      if (cee->mcx_mask & (1<<i)) {
+         /* the arg is to be excluded from definedness checking.  Do
+            nothing. */
+         if (0) VG_(printf)("excluding %s(%d)\n", cee->name, i);
+      } else {
+         /* calculate the arg's definedness, and pessimistically merge
+            it in. */
+         here = mkPCastTo( mce, Ity_I32, expr2vbits(mce, exprvec[i]) );
+         curr = mkUifU32(mce, here, curr);
+      }
+   }
+   return mkPCastTo(mce, finalVtype, curr );
+}
 
-         /* Moving stuff around.  Make the V bits follow accordingly,
-            but don't do anything else.  */
 
-         case GET:
-            uInstr2(cb, GETV, u_in->size,
-                        ArchReg, u_in->val1,
-                        TempReg, SHADOW(u_in->val2));
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+/*------------------------------------------------------------*/
+/*--- Generating expensive sequences for exact carry-chain ---*/
+/*--- propagation in add/sub and related operations.       ---*/
+/*------------------------------------------------------------*/
 
-         case PUT:
-            uInstr2(cb, PUTV, u_in->size, 
-                        TempReg, SHADOW(u_in->val1),
-                        ArchReg, u_in->val2);
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+static
+IRAtom* expensiveAdd32 ( MCEnv* mce, IRAtom* qaa, IRAtom* qbb, 
+                                     IRAtom* aa,  IRAtom* bb )
+{
+   tl_assert(isShadowAtom(mce,qaa));
+   tl_assert(isShadowAtom(mce,qbb));
+   tl_assert(isOriginalAtom(mce,aa));
+   tl_assert(isOriginalAtom(mce,bb));
+   tl_assert(sameKindedAtoms(qaa,aa));
+   tl_assert(sameKindedAtoms(qbb,bb));
+
+   IRType ty  = Ity_I32;
+   IROp opAND = Iop_And32;
+   IROp opOR  = Iop_Or32;
+   IROp opXOR = Iop_Xor32;
+   IROp opNOT = Iop_Not32;
+   IROp opADD = Iop_Add32;
+
+   IRAtom *a_min, *b_min, *a_max, *b_max;
+
+   // a_min = aa & ~qaa
+   a_min = assignNew(mce,ty, 
+                     binop(opAND, aa,
+                                  assignNew(mce,ty, unop(opNOT, qaa))));
+
+   // b_min = bb & ~qbb
+   b_min = assignNew(mce,ty, 
+                     binop(opAND, bb,
+                                  assignNew(mce,ty, unop(opNOT, qbb))));
+
+   // a_max = aa | qaa
+   a_max = assignNew(mce,ty, binop(opOR, aa, qaa));
+
+   // b_max = bb | qbb
+   b_max = assignNew(mce,ty, binop(opOR, bb, qbb));
+
+   // result = (qaa | qbb) | ((a_min + b_min) ^ (a_max + b_max))
+   return
+   assignNew(mce,ty,
+      binop( opOR,
+             assignNew(mce,ty, binop(opOR, qaa, qbb)),
+             assignNew(mce,ty, 
+                binop(opXOR, assignNew(mce,ty, binop(opADD, a_min, b_min)),
+                             assignNew(mce,ty, binop(opADD, a_max, b_max))
+                )
+             )
+      )
+   );
+}
 
-         case GETF:
-            /* This is not the smartest way to do it, but should work. */
-            qd = create_GETVF(cb, u_in->size);
-            uInstr2(cb, MOV, 4, TempReg, qd, TempReg, SHADOW(u_in->val1));
-            VG_(copy_UInstr)(cb, u_in);
-            break;
 
-         case PUTF:
-            create_PUTVF(cb, u_in->size, SHADOW(u_in->val1));
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+/*------------------------------------------------------------*/
+/*--- Generate shadow values from all kinds of IRExprs.    ---*/
+/*------------------------------------------------------------*/
 
-         case MOV:
-            switch (u_in->tag1) {
-               case TempReg: 
-                  uInstr2(cb, MOV, 4,
-                              TempReg, SHADOW(u_in->val1),
-                              TempReg, SHADOW(u_in->val2));
-                  break;
-               case Literal: 
-                  uInstr1(cb, SETV, u_in->size, 
-                              TempReg, SHADOW(u_in->val2));
-                  break;
-               default: 
-                  VG_(tool_panic)("memcheck_instrument: MOV");
-            }
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+static 
+IRAtom* expr2vbits_Binop ( MCEnv* mce,
+                           IROp op,
+                           IRAtom* atom1, IRAtom* atom2 )
+{
+   IRType  and_or_ty;
+   IRAtom* (*uifu)    (MCEnv*, IRAtom*, IRAtom*);
+   IRAtom* (*difd)    (MCEnv*, IRAtom*, IRAtom*);
+   IRAtom* (*improve) (MCEnv*, IRAtom*, IRAtom*);
+
+   IRAtom* vatom1 = expr2vbits( mce, atom1 );
+   IRAtom* vatom2 = expr2vbits( mce, atom2 );
+
+   tl_assert(isOriginalAtom(mce,atom1));
+   tl_assert(isOriginalAtom(mce,atom2));
+   tl_assert(isShadowAtom(mce,vatom1));
+   tl_assert(isShadowAtom(mce,vatom2));
+   tl_assert(sameKindedAtoms(atom1,vatom1));
+   tl_assert(sameKindedAtoms(atom2,vatom2));
+   switch (op) {
+
+      case Iop_RoundF64:
+      case Iop_F64toI64:
+         /* First arg is I32 (rounding mode), second is F64 (data). */
+         return mkLazy2(mce, Ity_I64, vatom1, vatom2);
+
+      case Iop_PRemC3210F64: case Iop_PRem1C3210F64:
+         /* Takes two F64 args. */
+      case Iop_F64toI32:
+         /* First arg is I32 (rounding mode), second is F64 (data). */
+         return mkLazy2(mce, Ity_I32, vatom1, vatom2);
+
+      case Iop_F64toI16:
+         /* First arg is I32 (rounding mode), second is F64 (data). */
+         return mkLazy2(mce, Ity_I16, vatom1, vatom2);
+
+      case Iop_ScaleF64:
+      case Iop_Yl2xF64:
+      case Iop_Yl2xp1F64:
+      case Iop_PRemF64:
+      case Iop_AtanF64:
+      case Iop_AddF64:
+      case Iop_DivF64:
+      case Iop_SubF64:
+      case Iop_MulF64:
+         return mkLazy2(mce, Ity_I64, vatom1, vatom2);
+
+      case Iop_CmpF64:
+         return mkLazy2(mce, Ity_I32, vatom1, vatom2);
+
+      /* non-FP after here */
+
+      case Iop_DivModU64to32:
+      case Iop_DivModS64to32:
+         return mkLazy2(mce, Ity_I64, vatom1, vatom2);
+
+      case Iop_16HLto32:
+         return assignNew(mce, Ity_I32,
+                          binop(Iop_16HLto32, vatom1, vatom2));
+      case Iop_32HLto64:
+         return assignNew(mce, Ity_I64,
+                          binop(Iop_32HLto64, vatom1, vatom2));
+
+      case Iop_MullS32:
+      case Iop_MullU32: {
+         IRAtom* vLo32 = mkLeft32(mce, mkUifU32(mce, vatom1,vatom2));
+         IRAtom* vHi32 = mkPCastTo(mce, Ity_I32, vLo32);
+         return assignNew(mce, Ity_I64, binop(Iop_32HLto64, vHi32, vLo32));
+      }
 
-         /* Special case of add, where one of the operands is a literal.
-            lea1(t) = t + some literal.
-            Therefore: lea1#(qa) = left(qa) 
-         */
-         case LEA1:
-            tl_assert(u_in->size == 4 && !VG_(any_flag_use)(u_in));
-            qs = SHADOW(u_in->val1);
-            qd = SHADOW(u_in->val2);
-            uInstr2(cb, MOV, 4, TempReg, qs, TempReg, qd);
-            create_Left(cb, u_in->size, qd);
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+      case Iop_MullS16:
+      case Iop_MullU16: {
+         IRAtom* vLo16 = mkLeft16(mce, mkUifU16(mce, vatom1,vatom2));
+         IRAtom* vHi16 = mkPCastTo(mce, Ity_I16, vLo16);
+         return assignNew(mce, Ity_I32, binop(Iop_16HLto32, vHi16, vLo16));
+      }
 
-         /* Another form of add.  
-            lea2(ts,tt,shift) = ts + (tt << shift); shift is a literal
-                                and is 0,1,2 or 3.
-            lea2#(qs,qt) = left(qs `UifU` (qt << shift)).
-            Note, subtly, that the shift puts zeroes at the bottom of qt,
-            meaning Valid, since the corresponding shift of tt puts 
-            zeroes at the bottom of tb.
-         */
-         case LEA2: {
-            Int shift;
-            tl_assert(u_in->size == 4 && !VG_(any_flag_use)(u_in));
-            switch (u_in->extra4b) {
-               case 1: shift = 0; break;
-               case 2: shift = 1; break;
-               case 4: shift = 2; break;
-               case 8: shift = 3; break;
-               default: VG_(tool_panic)( "memcheck_instrument(LEA2)" );
-            }
-            qs = SHADOW(u_in->val1);
-            qt = SHADOW(u_in->val2);
-            qd = SHADOW(u_in->val3);
-            uInstr2(cb, MOV, 4, TempReg, qt, TempReg, qd);
-            if (shift > 0) {
-               uInstr2(cb, SHL, 4, Literal, 0, TempReg, qd);
-               uLiteral(cb, shift);
-            }
-            create_UifU(cb, 4, qs, qd);
-            create_Left(cb, u_in->size, qd);
-            VG_(copy_UInstr)(cb, u_in);
-            break;
-         }
+      case Iop_MullS8:
+      case Iop_MullU8: {
+         IRAtom* vLo8 = mkLeft8(mce, mkUifU8(mce, vatom1,vatom2));
+         IRAtom* vHi8 = mkPCastTo(mce, Ity_I8, vLo8);
+         return assignNew(mce, Ity_I16, binop(Iop_8HLto16, vHi8, vLo8));
+      }
 
-         /* inc#/dec#(qd) = q `UifU` left(qd) = left(qd) */
-         case INC: case DEC:
-            qd = SHADOW(u_in->val1);
-            create_Left(cb, u_in->size, qd);
-            if (u_in->flags_w != FlagsEmpty)
-               create_PUTVF(cb, u_in->size, qd);
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+      case Iop_Add32:
+#        if 0
+         return expensiveAdd32(mce, vatom1,vatom2, atom1,atom2);
+#        endif
+      case Iop_Sub32:
+      case Iop_Mul32:
+         return mkLeft32(mce, mkUifU32(mce, vatom1,vatom2));
+
+      case Iop_Mul16:
+      case Iop_Add16:
+      case Iop_Sub16:
+         return mkLeft16(mce, mkUifU16(mce, vatom1,vatom2));
+
+      case Iop_Sub8:
+      case Iop_Add8:
+         return mkLeft8(mce, mkUifU8(mce, vatom1,vatom2));
+
+      case Iop_CmpLE32S: case Iop_CmpLE32U: 
+      case Iop_CmpLT32U: case Iop_CmpLT32S:
+      case Iop_CmpEQ32: case Iop_CmpNE32:
+         return mkPCastTo(mce, Ity_I1, mkUifU32(mce, vatom1,vatom2));
+
+      case Iop_CmpEQ16: case Iop_CmpNE16:
+         return mkPCastTo(mce, Ity_I1, mkUifU16(mce, vatom1,vatom2));
+
+      case Iop_CmpEQ8: case Iop_CmpNE8:
+         return mkPCastTo(mce, Ity_I1, mkUifU8(mce, vatom1,vatom2));
+
+      case Iop_Shl32: case Iop_Shr32: case Iop_Sar32:
+         /* Complain if the shift amount is undefined.  Then simply
+            shift the first arg's V bits by the real shift amount. */
+         complainIfUndefined(mce, atom2);
+         return assignNew(mce, Ity_I32, binop(op, vatom1, atom2));
+
+      case Iop_Shl16: case Iop_Shr16:
+         /* Same scheme as with 32-bit shifts. */
+         complainIfUndefined(mce, atom2);
+         return assignNew(mce, Ity_I16, binop(op, vatom1, atom2));
+
+      case Iop_Shl8: case Iop_Shr8:
+         /* Same scheme as with 32-bit shifts. */
+         complainIfUndefined(mce, atom2);
+         return assignNew(mce, Ity_I8, binop(op, vatom1, atom2));
+
+      case Iop_Shl64: case Iop_Shr64: 
+         /* Same scheme as with 32-bit shifts. */
+         complainIfUndefined(mce, atom2);
+         return assignNew(mce, Ity_I64, binop(op, vatom1, atom2));
+
+      case Iop_And32:
+         uifu = mkUifU32; difd = mkDifD32; 
+         and_or_ty = Ity_I32; improve = mkImproveAND32; goto do_And_Or;
+      case Iop_And16:
+         uifu = mkUifU16; difd = mkDifD16; 
+         and_or_ty = Ity_I16; improve = mkImproveAND16; goto do_And_Or;
+      case Iop_And8:
+         uifu = mkUifU8; difd = mkDifD8; 
+         and_or_ty = Ity_I8; improve = mkImproveAND8; goto do_And_Or;
+
+      case Iop_Or32:
+         uifu = mkUifU32; difd = mkDifD32; 
+         and_or_ty = Ity_I32; improve = mkImproveOR32; goto do_And_Or;
+      case Iop_Or16:
+         uifu = mkUifU16; difd = mkDifD16; 
+         and_or_ty = Ity_I16; improve = mkImproveOR16; goto do_And_Or;
+      case Iop_Or8:
+         uifu = mkUifU8; difd = mkDifD8; 
+         and_or_ty = Ity_I8; improve = mkImproveOR8; goto do_And_Or;
+
+      do_And_Or:
+         return
+         assignNew(
+            mce, 
+            and_or_ty,
+            difd(mce, uifu(mce, vatom1, vatom2),
+                      difd(mce, improve(mce, atom1, vatom1),
+                                improve(mce, atom2, vatom2) ) ) );
+
+      case Iop_Xor8:
+         return mkUifU8(mce, vatom1, vatom2);
+      case Iop_Xor16:
+         return mkUifU16(mce, vatom1, vatom2);
+      case Iop_Xor32:
+         return mkUifU32(mce, vatom1, vatom2);
 
-         /* This is a HACK (approximation :-) */
-         /* rcl#/rcr#(qs,qd) 
-               = let q0 = pcast-sz-0(qd) `UifU` pcast-sz-0(qs) `UifU` eflags#
-                 eflags# = q0
-                 qd =pcast-0-sz(q0)
-            Ie, cast everything down to a single bit, then back up.
-            This assumes that any bad bits infect the whole word and 
-            the eflags.
-         */
-         case RCL: case RCR:
-           tl_assert(u_in->flags_r != FlagsEmpty);
-            /* The following assertion looks like it makes sense, but is
-               actually wrong.  Consider this:
-                  rcll    %eax
-                  imull   %eax, %eax
-               The rcll writes O and C but so does the imull, so the O and C 
-               write of the rcll is annulled by the prior improvement pass.
-               Noticed by Kevin Ryde <user42@zip.com.au>
-            */
-           /* tl_assert(u_in->flags_w != FlagsEmpty); */
-            qs = getOperandShadow(cb, 1, u_in->tag1, u_in->val1);
-            /* We can safely modify qs; cast it to 0-size. */
-            create_PCast(cb, 1, 0, qs);
-            qd = SHADOW(u_in->val2);
-            create_PCast(cb, u_in->size, 0, qd);
-            /* qs is cast-to-0(shift count#), and qd is cast-to-0(value#). */
-            create_UifU(cb, 0, qs, qd);
-            /* qs is now free; reuse it for the flag definedness. */
-            qs = create_GETVF(cb, 0);
-            create_UifU(cb, 0, qs, qd);
-            create_PUTVF(cb, 0, qd);
-            create_PCast(cb, 0, u_in->size, qd);
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+      default:
+         ppIROp(op);
+         VG_(tool_panic)("memcheck:expr2vbits_Binop");
+   }
+}
 
-         /* for OP in shl shr sar rol ror
-            (qs is shift count#, qd is value to be OP#d)
-            OP(ts,td)
-            OP#(qs,qd)
-               = pcast-1-sz(qs) `UifU` OP(ts,qd)
-            So we apply OP to the tag bits too, and then UifU with
-            the shift count# to take account of the possibility of it
-            being undefined.
-            
-            A bit subtle:
-               ROL/ROR rearrange the tag bits as per the value bits.
-               SHL/SHR shifts zeroes into the value, and corresponding 
-                  zeroes indicating Definedness into the tag.
-               SAR copies the top bit of the value downwards, and therefore
-                  SAR also copies the definedness of the top bit too.
-            So in all five cases, we just apply the same op to the tag 
-            bits as is applied to the value bits.  Neat!
-         */
-         case SHL:
-         case SHR: case SAR:
-         case ROL: case ROR: {
-            Int t_amount = INVALID_TEMPREG;
-            tl_assert(u_in->tag1 == TempReg || u_in->tag1 == Literal);
-            tl_assert(u_in->tag2 == TempReg);
-            qd = SHADOW(u_in->val2);
-
-            /* Make qs hold shift-count# and make
-               t_amount be a TempReg holding the shift count. */
-            if (u_in->tag1 == Literal) {
-               t_amount = newTemp(cb);
-               uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_amount);
-               uLiteral(cb, u_in->lit32);
-               qs = SHADOW(t_amount);
-               uInstr1(cb, SETV, 1, TempReg, qs);
-            } else {
-               t_amount = u_in->val1;
-               qs = SHADOW(u_in->val1);
-            }
-
-            uInstr2(cb, u_in->opcode, 
-                        u_in->size, 
-                        TempReg, t_amount, 
-                        TempReg, qd);
-            qt = newShadow(cb);
-            uInstr2(cb, MOV, 4, TempReg, qs, TempReg, qt);
-            create_PCast(cb, 1, u_in->size, qt);
-            create_UifU(cb, u_in->size, qt, qd);
-            VG_(copy_UInstr)(cb, u_in);
-            break;
-         }
 
-         /* One simple tag operation. */
-         case WIDEN:
-            tl_assert(u_in->tag1 == TempReg);
-            create_Widen(cb, u_in->signed_widen, u_in->extra4b, u_in->size, 
-                             SHADOW(u_in->val1));
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+static 
+IRExpr* expr2vbits_Unop ( MCEnv* mce, IROp op, IRAtom* atom )
+{
+   IRAtom* vatom = expr2vbits( mce, atom );
+   tl_assert(isOriginalAtom(mce,atom));
+   switch (op) {
+
+      case Iop_F32toF64: 
+      case Iop_I32toF64:
+      case Iop_I64toF64:
+      case Iop_NegF64:
+      case Iop_SinF64:
+      case Iop_CosF64:
+      case Iop_TanF64:
+      case Iop_SqrtF64:
+      case Iop_AbsF64:
+      case Iop_2xm1F64:
+         return mkPCastTo(mce, Ity_I64, vatom);
+
+      case Iop_F64toF32:
+      case Iop_Clz32:
+      case Iop_Ctz32:
+         return mkPCastTo(mce, Ity_I32, vatom);
+
+      case Iop_32Sto64:
+      case Iop_32Uto64:
+         return assignNew(mce, Ity_I64, unop(op, vatom));
+
+      case Iop_64to32:
+      case Iop_64HIto32:
+      case Iop_1Uto32:
+      case Iop_8Uto32:
+      case Iop_16Uto32:
+      case Iop_16Sto32:
+      case Iop_8Sto32:
+         return assignNew(mce, Ity_I32, unop(op, vatom));
+
+      case Iop_8Sto16:
+      case Iop_8Uto16:
+      case Iop_32to16:
+      case Iop_32HIto16:
+         return assignNew(mce, Ity_I16, unop(op, vatom));
+
+      case Iop_1Uto8:
+      case Iop_16to8:
+      case Iop_32to8:
+         return assignNew(mce, Ity_I8, unop(op, vatom));
+
+      case Iop_32to1:
+         return assignNew(mce, Ity_I1, unop(Iop_32to1, vatom));
+
+      case Iop_ReinterpF64asI64:
+      case Iop_ReinterpI64asF64:
+      case Iop_Not32:
+      case Iop_Not16:
+      case Iop_Not8:
+      case Iop_Not1:
+         return vatom;
+      default:
+         ppIROp(op);
+         VG_(tool_panic)("memcheck:expr2vbits_Unop");
+   }
+}
 
-         /* not#(x) = x (since bitwise independent) */
-         case NOT:
-            tl_assert(u_in->tag1 == TempReg);
-            VG_(copy_UInstr)(cb, u_in);
-            break;
 
-         /* neg#(x) = left(x) (derivable from case for SUB) */
-         case NEG:
-            tl_assert(u_in->tag1 == TempReg);
-            create_Left(cb, u_in->size, SHADOW(u_in->val1));
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+static
+IRAtom* expr2vbits_LDle ( MCEnv* mce, IRType ty, IRAtom* addr, UInt bias )
+{
+   void*    helper;
+   Char*    hname;
+   IRDirty* di;
+   IRTemp   datavbits;
+   IRAtom*  addrAct;
+
+   tl_assert(isOriginalAtom(mce,addr));
+
+   /* First, emit a definedness test for the address.  This also sets
+      the address (shadow) to 'defined' following the test. */
+   complainIfUndefined( mce, addr );
+
+   /* Now cook up a call to the relevant helper function, to read the
+      data V bits from shadow memory. */
+   ty = shadowType(ty);
+   switch (ty) {
+      case Ity_I64: helper = &MC_(helperc_LOADV8);
+                    hname = "MC_(helperc_LOADV8)";
+                    break;
+      case Ity_I32: helper = &MC_(helperc_LOADV4);
+                    hname = "MC_(helperc_LOADV4)";
+                    break;
+      case Ity_I16: helper = &MC_(helperc_LOADV2);
+                    hname = "MC_(helperc_LOADV2)";
+                    break;
+      case Ity_I8:  helper = &MC_(helperc_LOADV1);
+                    hname = "MC_(helperc_LOADV1)";
+                    break;
+      default:      ppIRType(ty);
+                    VG_(tool_panic)("memcheck:do_shadow_LDle");
+   }
 
-         /* bswap#(x) = bswap(x) */
-         case BSWAP:
-            tl_assert(u_in->tag1 == TempReg);
-            tl_assert(u_in->size == 4);
-            qd = SHADOW(u_in->val1);
-            uInstr1(cb, BSWAP, 4, TempReg, qd);
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+   /* Generate the actual address into addrAct. */
+   if (bias == 0) {
+      addrAct = addr;
+   } else {
+      IRType  tyAddr  = mce->hWordTy;
+      tl_assert( tyAddr == Ity_I32 || tyAddr == Ity_I64 );
+      IROp    mkAdd   = tyAddr==Ity_I32 ? Iop_Add32 : Iop_Add64;
+      IRAtom* eBias   = tyAddr==Ity_I32 ? mkU32(bias) : mkU64(bias);
+      addrAct = assignNew(mce, tyAddr, binop(mkAdd, addr, eBias) );
+   }
 
-         /* cc2val#(qd) = pcast-0-to-size(eflags#) */
-         case CC2VAL:
-            tl_assert(u_in->tag1 == TempReg);
-            tl_assert(u_in->flags_r != FlagsEmpty);
-            qt = create_GETVF(cb, u_in->size);
-            uInstr2(cb, MOV, 4, TempReg, qt, TempReg, SHADOW(u_in->val1));
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+   /* We need to have a place to park the V bits we're just about to
+      read. */
+   datavbits = newIRTemp(mce->bb->tyenv, ty);
+   di = unsafeIRDirty_1_N( datavbits, 
+                           1/*regparms*/, hname, helper, 
+                           mkIRExprVec_1( addrAct ));
+   setHelperAnns( mce, di );
+   stmt( mce->bb, IRStmt_Dirty(di) );
 
-         /* cmov#(qs,qd) = cmov(qs,qd)
-            That is, do the cmov of tags using the same flags as for
-            the data (obviously).  However, first do a test on the 
-            validity of the flags.
-         */
-         case CMOV:
-            tl_assert(u_in->size == 4);
-            tl_assert(u_in->tag1 == TempReg);
-            tl_assert(u_in->tag2 == TempReg);
-            tl_assert(u_in->flags_r != FlagsEmpty);
-            tl_assert(u_in->flags_w == FlagsEmpty);
-            qs = SHADOW(u_in->val1);
-            qd = SHADOW(u_in->val2);
-            qt = create_GETVF(cb, 0);
-            uInstr1(cb, TESTV, 0, TempReg, qt);
-            /* qt should never be referred to again.  Nevertheless
-               ... */
-            uInstr1(cb, SETV, 0, TempReg, qt);
-
-            uInstr2(cb, CMOV, 4, TempReg, qs, TempReg, qd);
-            uCond(cb, u_in->cond);         
-            uFlagsRWU(cb, u_in->flags_r, u_in->flags_w, FlagsEmpty);
-
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+   return mkexpr(datavbits);
+}
 
-         /* add#/sub#(qs,qd) 
-               = qs `UifU` qd `UifU` left(qs) `UifU` left(qd)
-               = left(qs) `UifU` left(qd)
-               = left(qs `UifU` qd)
-            adc#/sbb#(qs,qd)
-               = left(qs `UifU` qd) `UifU` pcast(eflags#)
-            Second arg (dest) is TempReg.
-            First arg (src) is Literal or TempReg or ArchReg. 
-         */
-         case ADD: case SUB:
-         case ADC: case SBB:
-         case MUL:
-            qd = SHADOW(u_in->val2);
-            qs = getOperandShadow(cb, u_in->size, u_in->tag1, u_in->val1);
-            create_UifU(cb, u_in->size, qs, qd);
-            create_Left(cb, u_in->size, qd);
-            if (u_in->opcode == ADC || u_in->opcode == SBB) {
-               tl_assert(u_in->flags_r != FlagsEmpty);
-               qt = create_GETVF(cb, u_in->size);
-               create_UifU(cb, u_in->size, qt, qd);
-            }
-            if (u_in->flags_w != FlagsEmpty) {
-               create_PUTVF(cb, u_in->size, qd);
-            }
-            VG_(copy_UInstr)(cb, u_in);
-            break;
 
-         /* xor#(qs,qd) = qs `UifU` qd */
-         case XOR:
-            qd = SHADOW(u_in->val2);
-            qs = getOperandShadow(cb, u_in->size, u_in->tag1, u_in->val1);
-            create_UifU(cb, u_in->size, qs, qd);
-            if (u_in->flags_w != FlagsEmpty) {
-               create_PUTVF(cb, u_in->size, qd);
-            }
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+static
+IRAtom* expr2vbits_Mux0X ( MCEnv* mce, 
+                           IRAtom* cond, IRAtom* expr0, IRAtom* exprX )
+{
+   IRAtom *vbitsC, *vbits0, *vbitsX;
+   IRType ty;
+   /* Given Mux0X(cond,expr0,exprX), generate
+         Mux0X(cond,expr0#,exprX#) `UifU` PCast(cond#)
+      That is, steer the V bits like the originals, but trash the 
+      result if the steering value is undefined.  This gives 
+      lazy propagation. */
+   tl_assert(isOriginalAtom(mce, cond));
+   tl_assert(isOriginalAtom(mce, expr0));
+   tl_assert(isOriginalAtom(mce, exprX));
+
+   vbitsC = expr2vbits(mce, cond);
+   vbits0 = expr2vbits(mce, expr0);
+   vbitsX = expr2vbits(mce, exprX);
+   ty = typeOfIRExpr(mce->bb->tyenv, vbits0);
+
+   return
+      mkUifU(mce, ty, assignNew(mce, ty, IRExpr_Mux0X(cond, vbits0, vbitsX)),
+                      mkPCastTo(mce, ty, vbitsC) );
+}      
+
+/* --------- This is the main expression-handling function. --------- */
 
-         /* and#/or#(qs,qd) 
-               = (qs `UifU` qd) `DifD` improve(vs,qs) 
-                                `DifD` improve(vd,qd)
-            where improve is the relevant one of
-                Improve{AND,OR}_TQ
-            Use the following steps, with qt as a temp:
-               qt = improve(vd,qd)
-               qd = qs `UifU` qd
-               qd = qt `DifD` qd
-               qt = improve(vs,qs)
-               qd = qt `DifD` qd
-         */
-         case AND: case OR:
-            tl_assert(u_in->tag1 == TempReg);
-            tl_assert(u_in->tag2 == TempReg);
-            qd = SHADOW(u_in->val2);
-            qs = SHADOW(u_in->val1);
-            qt = newShadow(cb);
-
-            /* qt = improve(vd,qd) */
-            uInstr2(cb, MOV, 4, TempReg, qd, TempReg, qt);
-            if (u_in->opcode == AND)
-               create_ImproveAND_TQ(cb, u_in->size, u_in->val2, qt);
-            else
-               create_ImproveOR_TQ(cb, u_in->size, u_in->val2, qt);
-            /* qd = qs `UifU` qd */
-            create_UifU(cb, u_in->size, qs, qd);
-            /* qd = qt `DifD` qd */
-            create_DifD(cb, u_in->size, qt, qd);
-            /* qt = improve(vs,qs) */
-            uInstr2(cb, MOV, 4, TempReg, qs, TempReg, qt);
-            if (u_in->opcode == AND)
-               create_ImproveAND_TQ(cb, u_in->size, u_in->val1, qt);
-            else
-               create_ImproveOR_TQ(cb, u_in->size, u_in->val1, qt);
-            /* qd = qt `DifD` qd */
-               create_DifD(cb, u_in->size, qt, qd);
-            /* So, finally qd is the result tag. */
-            if (u_in->flags_w != FlagsEmpty) {
-               create_PUTVF(cb, u_in->size, qd);
-            }
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+static
+IRExpr* expr2vbits ( MCEnv* mce, IRExpr* e )
+{
+   switch (e->tag) {
 
-         /* Machinery to do with supporting CALLM.  Copy the start and
-            end markers only to make the result easier to read
-            (debug); they generate no code and have no effect. 
-         */
-         case CALLM_S: case CALLM_E:
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+      case Iex_Get:
+         return shadow_GET( mce, e->Iex.Get.offset, e->Iex.Get.ty );
 
-         /* Copy PUSH and POP verbatim.  Arg/result absval
-            calculations are done when the associated CALL is
-            processed.  CLEAR has no effect on absval calculations but
-            needs to be copied.  
-         */
-         case PUSH: case POP: case CLEAR:
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+      case Iex_GetI:
+         return shadow_GETI( mce, e->Iex.GetI.descr, 
+                                  e->Iex.GetI.ix, e->Iex.GetI.bias );
 
-         /* In short:
-               callm#(a1# ... an#) = (a1# `UifU` ... `UifU` an#)
-            We have to decide on a size to do the computation at,
-            although the choice doesn't affect correctness.  We will
-            do a pcast to the final size anyway, so the only important
-            factor is to choose a size which minimises the total
-            number of casts needed.  Valgrind: just use size 0,
-            regardless.  It may not be very good for performance
-            but does simplify matters, mainly by reducing the number
-            of different pessimising casts which have to be implemented.
-         */
-         case CALLM: {
-            UInstr* uu;
-            Bool res_used;
-
-            /* Now generate the code.  Get the final result absval
-               into qt. */
-            qt  = newShadow(cb);
-            qtt = newShadow(cb);
-            uInstr1(cb, SETV, 0, TempReg, qt);
-            for (j = i-1; VG_(get_instr)(cb_in, j)->opcode != CALLM_S; j--) {
-               uu = VG_(get_instr)(cb_in, j);
-               if (uu->opcode != PUSH) continue;
-               /* cast via a temporary */
-               uInstr2(cb, MOV, 4, TempReg, SHADOW(uu->val1),
-                                   TempReg, qtt);
-               create_PCast(cb, uu->size, 0, qtt);
-               create_UifU(cb, 0, qtt, qt);
-            }
-            /* Remembering also that flags read count as inputs. */
-            if (u_in->flags_r != FlagsEmpty) {
-               qtt = create_GETVF(cb, 0);
-               create_UifU(cb, 0, qtt, qt);
-            }
-
-            /* qt now holds the result tag.  If any results from the
-               call are used, either by fetching with POP or
-               implicitly by writing the flags, we copy the result
-               absval to the relevant location.  If not used, the call
-               must have been for its side effects, so we test qt here
-               and now.  Note that this assumes that all values
-               removed by POP continue to be live.  So dead args
-               *must* be removed with CLEAR, not by POPping them into
-               a dummy tempreg. 
-            */
-            res_used = False;
-            for (j = i+1; VG_(get_instr)(cb_in, j)->opcode != CALLM_E; j++) {
-               uu = VG_(get_instr)(cb_in, j);
-               if (uu->opcode != POP) continue;
-               /* Cast via a temp. */
-               uInstr2(cb, MOV, 4, TempReg, qt, TempReg, qtt);
-               create_PCast(cb, 0, uu->size, qtt);
-               uInstr2(cb, MOV, 4, TempReg, qtt, 
-                                   TempReg, SHADOW(uu->val1));
-               res_used = True;
-            }
-            if (u_in->flags_w != FlagsEmpty) {
-               create_PUTVF(cb, 0, qt);
-               res_used = True;
-            }
-            if (!res_used) {
-               uInstr1(cb, TESTV, 0, TempReg, qt);
-               /* qt should never be referred to again.  Nevertheless
-                  ... */
-               uInstr1(cb, SETV, 0, TempReg, qt);
-            }
-            VG_(copy_UInstr)(cb, u_in);
-            break;
-         }
-         /* Whew ... */
-
-         case JMP:
-            if (u_in->tag1 == TempReg) {
-               uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val1));
-               uInstr1(cb, SETV,  4, TempReg, SHADOW(u_in->val1));
-            } else {
-               tl_assert(u_in->tag1 == Literal);
-            }
-            if (u_in->cond != CondAlways) {
-               tl_assert(u_in->flags_r != FlagsEmpty);
-               qt = create_GETVF(cb, 0);
-               if (/* HACK */ bogusLiterals) {
-                  if (0) 
-                     VG_(printf)("ignore TESTV due to bogus literal\n");
-               } else {
-                  uInstr1(cb, TESTV, 0, TempReg, qt);
-               }
-               /* qt should never be referred to again.  Nevertheless
-                  ... */
-               uInstr1(cb, SETV, 0, TempReg, qt);
-            }
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+      case Iex_Tmp:
+         return IRExpr_Tmp( findShadowTmp(mce, e->Iex.Tmp.tmp) );
 
-         case JIFZ:
-            uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val1));
-            uInstr1(cb, SETV,  4, TempReg, SHADOW(u_in->val1));
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+      case Iex_Const:
+         return definedOfType(shadowType(typeOfIRExpr(mce->bb->tyenv, e)));
 
-         /* Emit a check on the address used.  The value loaded into the 
-            FPU is checked by the call to fpu_{read/write}_check().  */
-         case MMX2_MemRd: case MMX2_MemWr:
-         case FPU_R: case FPU_W: {
-            Int t_size = INVALID_TEMPREG;
-            Bool is_load;
-
-            if (u_in->opcode == MMX2_MemRd || u_in->opcode == MMX2_MemWr)
-               tl_assert(u_in->size == 4 || u_in->size == 8);
-
-            is_load = u_in->opcode==FPU_R || u_in->opcode==MMX2_MemRd;
-            tl_assert(u_in->tag2 == TempReg);
-            uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val2));
-            uInstr1(cb, SETV,  4, TempReg, SHADOW(u_in->val2));
-
-            t_size = newTemp(cb);
-            uInstr2(cb, MOV,   4, Literal, 0, TempReg, t_size);
-            uLiteral(cb, u_in->size);
-            uInstr2(cb, CCALL, 0, TempReg, u_in->val2, TempReg, t_size);
-            uCCall(cb, is_load ? (Addr) & MC_(fpu_read_check) 
-                               : (Addr) & MC_(fpu_write_check),
-                   2, 2, False);
-
-            VG_(copy_UInstr)(cb, u_in);
-            break;
-         }
+      case Iex_Binop:
+         return expr2vbits_Binop(
+                   mce,
+                   e->Iex.Binop.op,
+                   e->Iex.Binop.arg1, e->Iex.Binop.arg2
+                );
 
-         case MMX2a1_MemRd: {
-            Int t_size = INVALID_TEMPREG;
+      case Iex_Unop:
+         return expr2vbits_Unop( mce, e->Iex.Unop.op, e->Iex.Unop.arg );
 
-            tl_assert(u_in->size == 8);
+      case Iex_LDle:
+         return expr2vbits_LDle( mce, e->Iex.LDle.ty, 
+                                      e->Iex.LDle.addr, 0/*addr bias*/ );
 
-            tl_assert(u_in->tag3 == TempReg);
-            uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val3));
-            uInstr1(cb, SETV,  4, TempReg, SHADOW(u_in->val3));
+      case Iex_CCall:
+         return mkLazyN( mce, e->Iex.CCall.args, 
+                              e->Iex.CCall.retty,
+                              e->Iex.CCall.cee );
 
-            t_size = newTemp(cb);
-            uInstr2(cb, MOV,   4, Literal, 0, TempReg, t_size);
-            uLiteral(cb, u_in->size);
-            uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
-            uCCall(cb, (Addr) & MC_(fpu_read_check), 2, 2, False);
-            
-            VG_(copy_UInstr)(cb, u_in);
-            break;
-         }
+      case Iex_Mux0X:
+         return expr2vbits_Mux0X( mce, e->Iex.Mux0X.cond, e->Iex.Mux0X.expr0, 
+                                       e->Iex.Mux0X.exprX);
 
-        /* SSE ins referencing scalar integer registers */
-         case SSE2g_RegWr:
-         case SSE2g1_RegWr:
-         case SSE2e1_RegRd:
-         case SSE3g_RegWr:
-         case SSE3e_RegRd:
-         case SSE3e_RegWr: 
-         case SSE3g1_RegWr:
-         case SSE3e1_RegRd:
-            tl_assert(u_in->tag3 == TempReg);
-
-            if (u_in->opcode == SSE2e1_RegRd || u_in->opcode == SSE3e1_RegRd) {
-               tl_assert(u_in->size == 2);
-            } else {
-               tl_assert(u_in->size == 4);
-            }
-
-            /* Is it a read ?  Better check the V bits right now. */
-            if ( u_in->opcode == SSE2e1_RegRd
-                 || u_in->opcode == SSE3e_RegRd
-                 || u_in->opcode == SSE3e1_RegRd )
-              uInstr1(cb, TESTV, u_in->size, 
-                           TempReg, SHADOW(u_in->val3));
-
-           /* And for both read and write, set the register to be
-              defined. */
-           uInstr1(cb, SETV, u_in->size, 
-                        TempReg, SHADOW(u_in->val3));
-
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+      default: 
+         VG_(printf)("\n");
+         ppIRExpr(e);
+         VG_(printf)("\n");
+         VG_(tool_panic)("memcheck: expr2vbits");
+   }
+}
 
-         /* ... and the same deal for SSE insns referencing memory */
-         case SSE3a_MemRd:
-         case SSE3a_MemWr:
-         case SSE2a_MemWr:
-         case SSE2a_MemRd:
-         case SSE3a1_MemRd:
-         case SSE2a1_MemRd: { 
-            Bool is_load;
-            Int t_size;
-
-            tl_assert(u_in->size == 4 || u_in->size == 8
-                      || u_in->size == 16 || u_in->size == 512);
-
-            t_size = INVALID_TEMPREG;
-            is_load = u_in->opcode==SSE2a_MemRd 
-                      || u_in->opcode==SSE3a_MemRd
-                      || u_in->opcode==SSE2a1_MemRd
-                      || u_in->opcode==SSE3a1_MemRd;
-
-            tl_assert(u_in->tag3 == TempReg);
-
-           uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val3));
-           uInstr1(cb, SETV,  4, TempReg, SHADOW(u_in->val3));
-           t_size = newTemp(cb);
-           uInstr2(cb, MOV,   4, Literal, 0, TempReg, t_size);
-           uLiteral(cb, u_in->size);
-           uInstr2(cb, CCALL, 0, TempReg, u_in->val3, TempReg, t_size);
-           uCCall(cb, is_load ? (Addr) & MC_(fpu_read_check) 
-                  : (Addr) & MC_(fpu_write_check),
-                  2, 2, False);
-
-            VG_(copy_UInstr)(cb, u_in);
-            break;
-         }
+/*------------------------------------------------------------*/
+/*--- Generate shadow stmts from all kinds of IRStmts.     ---*/
+/*------------------------------------------------------------*/
 
-        case SSE3ag_MemRd_RegWr:
-        {
-           Int t_size;
-
-            tl_assert(u_in->size == 4 || u_in->size == 8);
-           tl_assert(u_in->tag1 == TempReg);
-           uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val1));
-           uInstr1(cb, SETV,  4, TempReg, SHADOW(u_in->val1));
-            t_size = newTemp(cb);
-           uInstr2(cb, MOV, 4, Literal, 0, TempReg, t_size);
-           uLiteral(cb, u_in->size);
-            uInstr2(cb, CCALL, 0, TempReg, u_in->val1, TempReg, t_size);
-            uCCall(cb, (Addr) MC_(fpu_read_check), 2, 2, False );
-           uInstr1(cb, SETV, 4, TempReg, SHADOW(u_in->val2));
-            VG_(copy_UInstr)(cb, u_in);
-           break;
-         }
-         
-         /* For MMX and SSE insns not referencing memory, just
-            make sure the eflags are defined if the instruction
-            read them, and make them defined it it writes them. */
-         case SSE5: case SSE4: case SSE3:
-         case MMX1: case MMX2: case MMX3:
-         case FPU:
-            if (u_in->flags_r != FlagsEmpty) {
-               qt = create_GETVF(cb, 0);
-               uInstr1(cb, TESTV, 0, TempReg, qt);
-               /* qt should never be referred to again.  Nevertheless
-                  ... */
-               uInstr1(cb, SETV, 0, TempReg, qt);
-            }
-            if (u_in->flags_w != FlagsEmpty) {
-               qd = newTemp(cb);
-               uInstr2(cb, MOV, 4, Literal, 0, TempReg, qd);
-               uLiteral(cb, 0);
-               create_PUTVF(cb, 0, qd);
-            }
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+/* Widen a value to the host word size. */
 
-         /* Since we don't track definedness of values inside the
-            MMX state, we'd better check that the (int) reg being
-            read here is defined. */
-         case MMX2_ERegRd: 
-            tl_assert(u_in->tag2 == TempReg);
-            tl_assert(u_in->size == 4);
-            uInstr1(cb, TESTV, 4, TempReg, SHADOW(u_in->val2));
-            uInstr1(cb, SETV,  4, TempReg, SHADOW(u_in->val2));
-            VG_(copy_UInstr)(cb, u_in);
-            break;
+static
+IRExpr* zwidenToHostWord ( MCEnv* mce, IRAtom* vatom )
+{
+   /* vatom is vbits-value and as such can only have a shadow type. */
+   tl_assert(isShadowAtom(mce,vatom));
+
+   IRType ty  = typeOfIRExpr(mce->bb->tyenv, vatom);
+   IRType tyH = mce->hWordTy;
+
+   if (tyH == Ity_I32) {
+      switch (ty) {
+         case Ity_I32: return vatom;
+         case Ity_I16: return assignNew(mce, tyH, unop(Iop_16Uto32, vatom));
+         case Ity_I8:  return assignNew(mce, tyH, unop(Iop_8Uto32, vatom));
+         default:      goto unhandled;
+      }
+   } else {
+      goto unhandled;
+   }
+  unhandled:
+   VG_(printf)("\nty = "); ppIRType(ty); VG_(printf)("\n");
+   VG_(tool_panic)("zwidenToHostWord");
+}
 
-        /* The MMX register is assumed to be fully defined, so
-           that's what this register becomes. */
-         case MMX2_ERegWr:
-            tl_assert(u_in->tag2 == TempReg);
-            tl_assert(u_in->size == 4);
-            uInstr1(cb, SETV,  4, TempReg, SHADOW(u_in->val2));
-            VG_(copy_UInstr)(cb, u_in);         
-            break;
 
-         default:
-            VG_(pp_UInstr)(0, u_in);
-            VG_(tool_panic)( "memcheck_instrument: unhandled case");
+/* Generate a shadow store.  addr is always the original address atom.
+   You can pass in either originals or V-bits for the data atom, but
+   obviously not both.  */
 
-      } /* end of switch (u_in->opcode) */
+static 
+void do_shadow_STle ( MCEnv* mce, 
+                      IRAtom* addr, UInt bias,
+                      IRAtom* data, IRAtom* vdata )
+{
+   IRType   ty;
+   IRDirty* di;
+   void*    helper = NULL;
+   Char*    hname = NULL;
+   IRAtom*  addrAct;
+
+   if (data) {
+      tl_assert(!vdata);
+      tl_assert(isOriginalAtom(mce, data));
+      tl_assert(bias == 0);
+      vdata = expr2vbits( mce, data );
+   } else {
+      tl_assert(vdata);
+   }
 
-   } /* end of for loop */
+   tl_assert(isOriginalAtom(mce,addr));
+   tl_assert(isShadowAtom(mce,vdata));
+
+   ty = typeOfIRExpr(mce->bb->tyenv, vdata);
+
+   /* First, emit a definedness test for the address.  This also sets
+      the address (shadow) to 'defined' following the test. */
+   complainIfUndefined( mce, addr );
+
+   /* Now cook up a call to the relevant helper function, to write the
+      data V bits into shadow memory. */
+   switch (ty) {
+      case Ity_I64: helper = &MC_(helperc_STOREV8);
+                    hname = "MC_(helperc_STOREV8)";
+                    break;
+      case Ity_I32: helper = &MC_(helperc_STOREV4);
+                    hname = "MC_(helperc_STOREV4)";
+                    break;
+      case Ity_I16: helper = &MC_(helperc_STOREV2);
+                    hname = "MC_(helperc_STOREV2)";
+                    break;
+      case Ity_I8:  helper = &MC_(helperc_STOREV1);
+                    hname = "MC_(helperc_STOREV1)";
+                    break;
+      default:      VG_(tool_panic)("memcheck:do_shadow_STle");
+   }
+
+   /* Generate the actual address into addrAct. */
+   if (bias == 0) {
+      addrAct = addr;
+   } else {
+      IRType  tyAddr  = mce->hWordTy;
+      tl_assert( tyAddr == Ity_I32 || tyAddr == Ity_I64 );
+      IROp    mkAdd   = tyAddr==Ity_I32 ? Iop_Add32 : Iop_Add64;
+      IRAtom* eBias   = tyAddr==Ity_I32 ? mkU32(bias) : mkU64(bias);
+      addrAct = assignNew(mce, tyAddr, binop(mkAdd, addr, eBias) );
+   }
 
-   VG_(free_UCodeBlock)(cb_in);
-   return cb;
+   if (ty == Ity_I64) {
+      /* We can't do this with regparm 2 on 32-bit platforms, since
+         the back ends aren't clever enough to handle 64-bit regparm
+         args.  Therefore be different. */
+      di = unsafeIRDirty_0_N( 
+              1/*regparms*/, hname, helper, 
+              mkIRExprVec_2( addrAct, vdata ));
+   } else {
+      di = unsafeIRDirty_0_N( 
+              2/*regparms*/, hname, helper, 
+              mkIRExprVec_2( addrAct,
+                             zwidenToHostWord( mce, vdata )));
+   }
+   setHelperAnns( mce, di );
+   stmt( mce->bb, IRStmt_Dirty(di) );
 }
 
-/*------------------------------------------------------------*/
-/*--- Clean up mem check instrumentation.                  ---*/
-/*------------------------------------------------------------*/
 
-#define dis    VG_(print_codegen)
+/* Do lazy pessimistic propagation through a dirty helper call, by
+   looking at the annotations on it.  This is the most complex part of
+   Memcheck. */
 
+static IRType szToITy ( Int n )
+{
+   switch (n) {
+      case 1: return Ity_I8;
+      case 2: return Ity_I16;
+      case 4: return Ity_I32;
+      case 8: return Ity_I64;
+      default: VG_(tool_panic)("szToITy(memcheck)");
+   }
+}
 
-#define VGC_IS_SHADOW(tempreg) ((tempreg % 2) == 1)
-#define VGC_UNDEF ((UChar)100)
-#define VGC_VALUE ((UChar)101)
+static
+void do_shadow_Dirty ( MCEnv* mce, IRDirty* d )
+{
+   Int     i, offset, toDo;
+   IRAtom* src;
+   IRType  tyAddr, tySrc, tyDst;
+   IRTemp  dst;
+
+   /* First check the guard. */
+   complainIfUndefined(mce, d->guard);
+
+   /* Now round up all inputs and PCast over them. */
+   IRAtom* here;
+   IRAtom* curr = definedOfType(Ity_I32);
+
+   /* Inputs: unmasked args */
+   for (i = 0; d->args[i]; i++) {
+      if (d->cee->mcx_mask & (1<<i)) {
+         /* ignore this arg */
+      } else {
+         here = mkPCastTo( mce, Ity_I32, expr2vbits(mce, d->args[i]) );
+         curr = mkUifU32(mce, here, curr);
+      }
+   }
 
-#define NOP_no_msg(uu)                                            \
-   do { VG_(new_NOP)(uu); } while (False)
+   /* Inputs: guest state that we read. */
+   for (i = 0; i < d->nFxState; i++) {
+      tl_assert(d->fxState[i].fx != Ifx_None);
+      if (d->fxState[i].fx == Ifx_Write)
+         continue;
+      /* This state element is read or modified.  So we need to
+         consider it. */
+      tySrc = szToITy( d->fxState[i].size );
+      src   = assignNew( mce, tySrc, 
+                         shadow_GET(mce, d->fxState[i].offset, tySrc ) );
+      here = mkPCastTo( mce, Ity_I32, src );
+      curr = mkUifU32(mce, here, curr);
+   }
 
-#define NOP_tag1_op(uu)                                           \
-   do { VG_(new_NOP)(uu);                                         \
-        if (dis)                                                  \
-           VG_(printf)("   at %2d: delete %s due to defd arg\n",  \
-                       i, nameOfTagOp(u->val3));                  \
-   } while (False)
+   /* Inputs: memory.  First set up some info needed regardless of
+      whether we're doing reads or writes. */
+   tyAddr = Ity_INVALID;
+
+   if (d->mFx != Ifx_None) {
+      /* Because we may do multiple shadow loads/stores from the same
+         base address, it's best to do a single test of its
+         definedness right now.  Post-instrumentation optimisation
+         should remove all but this test. */
+      tl_assert(d->mAddr);
+      complainIfUndefined(mce, d->mAddr);
+
+      tyAddr = typeOfIRExpr(mce->bb->tyenv, d->mAddr);
+      tl_assert(tyAddr == Ity_I32 || tyAddr == Ity_I64);
+      tl_assert(tyAddr == mce->hWordTy); /* not really right */
+   }
 
-#define SETV_tag1_op(uu,newsz)                                    \
-   do { uu->opcode = SETV;                                        \
-        uu->size = newsz;                                         \
-        uu->tag2 = uu->tag3 = NoValue;                            \
-        if (dis)                                                  \
-           VG_(printf)("   at %2d: convert %s to SETV%d "         \
-                       "due to defd arg\n",                       \
-                       i, nameOfTagOp(u->val3), newsz);           \
-   } while (False)
+   /* Deal with memory inputs (reads or modifies) */
+   if (d->mFx == Ifx_Read || d->mFx == Ifx_Modify) {
+      offset = 0;
+      toDo   = d->mSize;
+      /* chew off 32-bit chunks */
+      while (toDo >= 4) {
+         here = mkPCastTo( 
+                   mce, Ity_I32,
+                   expr2vbits_LDle ( mce, Ity_I32, 
+                                     d->mAddr, d->mSize - toDo )
+                );
+         curr = mkUifU32(mce, here, curr);
+         toDo -= 4;
+      }
+      /* chew off 16-bit chunks */
+      while (toDo >= 2) {
+         here = mkPCastTo( 
+                   mce, Ity_I32,
+                   expr2vbits_LDle ( mce, Ity_I16, 
+                                     d->mAddr, d->mSize - toDo )
+                );
+         curr = mkUifU32(mce, here, curr);
+         toDo -= 2;
+      }
+      tl_assert(toDo == 0); /* also need to handle 1-byte excess */
+   }
 
+   /* Whew!  So curr is a 32-bit V-value summarising pessimistically
+      all the inputs to the helper.  Now we need to re-distribute the
+      results to all destinations. */
 
+   /* Outputs: the destination temporary, if there is one. */
+   if (d->tmp != IRTemp_INVALID) {
+      dst   = findShadowTmp(mce, d->tmp);
+      tyDst = typeOfIRTemp(mce->bb->tyenv, d->tmp);
+      assign( mce->bb, dst, mkPCastTo( mce, tyDst, curr) );
+   }
 
-/* Run backwards and delete SETVs on shadow temps for which the next
-   action is a write.  Needs an env saying whether or not the next
-   action is a write.  The supplied UCodeBlock is destructively
-   modified.
-*/
-static void vg_delete_redundant_SETVs ( UCodeBlock* cb )
-{
-   Int     i, j, k;
-   Int     n_temps = VG_(get_num_temps)(cb);
-   Bool*   next_is_write;
-   UInstr* u;
-   Int     tempUse[VG_MAX_REGS_USED];
-   Bool    isWrites[VG_MAX_REGS_USED];
-
-   if (n_temps == 0) return;
-
-   next_is_write = VG_(malloc)(n_temps * sizeof(Bool));
-
-   for (i = 0; i < n_temps; i++) next_is_write[i] = True;
-
-   for (i = VG_(get_num_instrs)(cb) - 1; i >= 0; i--) {
-      u = VG_(get_instr)(cb, i);
-
-      /* Occasionally there will be GETVs, TAG1s and TAG2s calculating
-         values which are never used.  These first three cases get rid
-         of them. */
-
-      if (u->opcode == GETV && VGC_IS_SHADOW(u->val2) 
-                            && next_is_write[u->val2]) {
-         tl_assert(u->val2 < n_temps);
-         VG_(new_NOP)(u);
-         if (dis) 
-            VG_(printf)("   at %2d: delete GETV\n", i);
-      } else
-
-      if (u->opcode == TAG1 && VGC_IS_SHADOW(u->val1) 
-                            && next_is_write[u->val1]) {
-         tl_assert(u->val1 < n_temps);
-         VG_(new_NOP)(u);
-         if (dis) 
-            VG_(printf)("   at %2d: delete TAG1\n", i);
-      } else
-
-      if (u->opcode == TAG2 && VGC_IS_SHADOW(u->val2) 
-                            && next_is_write[u->val2]) {
-         tl_assert(u->val2 < n_temps);
-         VG_(new_NOP)(u);
-         if (dis) 
-            VG_(printf)("   at %2d: delete TAG2\n", i);
-      } else
-
-      /* The bulk of the cleanup work of this function is done by
-         the code from here downwards. */
-
-      if (u->opcode == MOV && VGC_IS_SHADOW(u->val2) 
-                           && next_is_write[u->val2]) {
-         /* This MOV is pointless because the target is dead at this
-            point.  Delete it. */
-         VG_(new_NOP)(u);
-         if (dis) 
-            VG_(printf)("   at %2d: delete MOV\n", i);
-      } else
-
-      if (u->opcode == SETV) {
-         if (u->tag1 == TempReg) {
-            tl_assert(VGC_IS_SHADOW(u->val1));
-            if (next_is_write[u->val1]) {
-               /* This write is pointless, so annul it. */
-               VG_(new_NOP)(u);
-               if (dis) 
-                  VG_(printf)("   at %2d: delete SETV\n", i);
-            } else {
-               /* This write has a purpose; don't annul it, but do
-                  notice that we did it. */
-               next_is_write[u->val1] = True;
-            }
-              
-         }
+   /* Outputs: guest state that we write or modify. */
+   for (i = 0; i < d->nFxState; i++) {
+      tl_assert(d->fxState[i].fx != Ifx_None);
+      if (d->fxState[i].fx == Ifx_Read)
+         continue;
+      /* this state element is written or modified.  So we need to
+         consider it. */
+      tyDst = szToITy( d->fxState[i].size );
+      do_shadow_PUT( mce, d->fxState[i].offset,
+                          NULL, /* original atom */
+                          mkPCastTo( mce, tyDst, curr ) );
+   }
 
-      } else {
-         /* Find out what this insn does to the temps. */
-         k = VG_(get_reg_usage)(u, TempReg, &tempUse[0], &isWrites[0]);
-         tl_assert(0 <= k && k <= VG_MAX_REGS_USED);
-         for (j = k-1; j >= 0; j--) {
-            next_is_write[ tempUse[j] ] = isWrites[j];
-         }
+   /* Outputs: memory that we write or modify. */
+   if (d->mFx == Ifx_Write || d->mFx == Ifx_Modify) {
+      offset = 0;
+      toDo   = d->mSize;
+      /* chew off 32-bit chunks */
+      while (toDo >= 4) {
+         do_shadow_STle( mce, d->mAddr, d->mSize - toDo,
+                         NULL, /* original data */
+                         mkPCastTo( mce, Ity_I32, curr ) );
+         toDo -= 4;
+      }
+      /* chew off 16-bit chunks */
+      while (toDo >= 2) {
+         do_shadow_STle( mce, d->mAddr, d->mSize - toDo,
+                         NULL, /* original data */
+                         mkPCastTo( mce, Ity_I16, curr ) );
+         toDo -= 2;
       }
+      tl_assert(toDo == 0); /* also need to handle 1-byte excess */
    }
-}
 
+}
 
-/* Run forwards, propagating and using the is-completely-defined
-   property.  This removes a lot of redundant tag-munging code.
-   Unfortunately it requires intimate knowledge of how each uinstr and
-   tagop modifies its arguments.  This duplicates knowledge of uinstr
-   tempreg uses embodied in VG_(get_reg_usage)(), which is unfortunate. 
-   The supplied UCodeBlock* is modified in-place.
 
-   For each value temp, def[] should hold VGC_VALUE.
+/*------------------------------------------------------------*/
+/*--- Memcheck main                                        ---*/
+/*------------------------------------------------------------*/
 
-   For each shadow temp, def[] may hold 4,2,1 or 0 iff that shadow is
-   definitely known to be fully defined at that size.  In all other
-   circumstances a shadow's def[] entry is VGC_UNDEF, meaning possibly
-   undefined.  In cases of doubt, VGC_UNDEF is always safe.
-*/
-static void vg_propagate_definedness ( UCodeBlock* cb )
+#if 0 /* UNUSED */
+static Bool isBogusAtom ( IRAtom* at )
 {
-   Int     i, j, k, t;
-   Int     n_temps = VG_(get_num_temps)(cb);
-   UChar*  def;
-   UInstr* u;
-   Int     tempUse[VG_MAX_REGS_USED];
-   Bool    isWrites[VG_MAX_REGS_USED];
-
-   if (n_temps == 0) return;
-
-   def = VG_(malloc)(n_temps * sizeof(UChar));
-
-   for (i = 0; i < n_temps; i++) 
-      def[i] = VGC_IS_SHADOW(i) ? VGC_UNDEF : VGC_VALUE;
-
-   /* Run forwards, detecting and using the all-defined property. */
+   ULong n = 0;
+   IRConst* con;
+   tl_assert(isAtom(at));
+   if (at->tag == Iex_Tmp)
+      return False;
+   tl_assert(at->tag == Iex_Const);
+   con = at->Iex.Const.con;
+   switch (con->tag) {
+      case Ico_U8:  n = (ULong)con->Ico.U8; break;
+      case Ico_U16: n = (ULong)con->Ico.U16; break;
+      case Ico_U32: n = (ULong)con->Ico.U32; break;
+      case Ico_U64: n = (ULong)con->Ico.U64; break;
+      default: ppIRExpr(at); tl_assert(0);
+   }
+   /* VG_(printf)("%llx\n", n); */
+   return (n == 0xFEFEFEFF
+           || n == 0x80808080
+           || n == 0x1010101
+           || n == 1010100);
+}
 
-   for (i = 0; i < VG_(get_num_instrs)(cb); i++) {
-      u = VG_(get_instr)(cb, i);
-      switch (u->opcode) {
+static Bool checkForBogusLiterals ( /*FLAT*/ IRStmt* st )
+{
+   Int     i;
+   IRExpr* e;
+   switch (st->tag) {
+      case Ist_Tmp:
+         e = st->Ist.Tmp.data;
+         switch (e->tag) {
+            case Iex_Get:
+            case Iex_Tmp:
+               return False;
+            case Iex_Unop: 
+               return isBogusAtom(e->Iex.Unop.arg);
+            case Iex_Binop: 
+               return isBogusAtom(e->Iex.Binop.arg1)
+                      || isBogusAtom(e->Iex.Binop.arg2);
+            case Iex_Mux0X:
+               return isBogusAtom(e->Iex.Mux0X.cond)
+                      || isBogusAtom(e->Iex.Mux0X.expr0)
+                      || isBogusAtom(e->Iex.Mux0X.exprX);
+            case Iex_LDle: 
+               return isBogusAtom(e->Iex.LDle.addr);
+            case Iex_CCall:
+               for (i = 0; e->Iex.CCall.args[i]; i++)
+                  if (isBogusAtom(e->Iex.CCall.args[i]))
+                     return True;
+               return False;
+            default: 
+               goto unhandled;
+         }
+      case Ist_Put:
+         return isBogusAtom(st->Ist.Put.data);
+      case Ist_STle:
+         return isBogusAtom(st->Ist.STle.addr) 
+                || isBogusAtom(st->Ist.STle.data);
+      case Ist_Exit:
+         return isBogusAtom(st->Ist.Exit.cond);
+      default: 
+      unhandled:
+         ppIRStmt(st);
+         VG_(tool_panic)("hasBogusLiterals");
+   }
+}
+#endif /* UNUSED */
 
-      /* Tag-handling uinstrs. */
 
-         /* Deal with these quickly. */
-         case NOP:
-         case LOCK:
-         case INCEIP:
-            break;
+IRBB* TL_(instrument) ( IRBB* bb_in, VexGuestLayout* layout, IRType hWordTy )
+{
+   Bool verboze = False; //True; 
+
+   /* Bool hasBogusLiterals = False; */
+
+   Int i, j, first_stmt;
+   IRStmt* st;
+   MCEnv mce;
+
+   /* Set up BB */
+   IRBB* bb     = emptyIRBB();
+   bb->tyenv    = dopyIRTypeEnv(bb_in->tyenv);
+   bb->next     = dopyIRExpr(bb_in->next);
+   bb->jumpkind = bb_in->jumpkind;
+
+   /* Set up the running environment.  Only .bb is modified as we go
+      along. */
+   mce.bb             = bb;
+   mce.layout         = layout;
+   mce.n_originalTmps = bb->tyenv->types_used;
+   mce.hWordTy        = hWordTy;
+   mce.tmpMap         = LibVEX_Alloc(mce.n_originalTmps * sizeof(IRTemp));
+   for (i = 0; i < mce.n_originalTmps; i++)
+      mce.tmpMap[i] = IRTemp_INVALID;
+
+   /* Iterate over the stmts. */
+
+   for (i = 0; i <  bb_in->stmts_used; i++) {
+      st = bb_in->stmts[i];
+      if (!st) continue;
+
+      tl_assert(isFlatIRStmt(st));
+
+      /*
+      if (!hasBogusLiterals) {
+         hasBogusLiterals = checkForBogusLiterals(st);
+         if (hasBogusLiterals) {
+            VG_(printf)("bogus: ");
+            ppIRStmt(st);
+            VG_(printf)("\n");
+         }
+      }
+      */
+      first_stmt = bb->stmts_used;
 
-         /* Make a tag defined. */
-         case SETV:
-            tl_assert(u->tag1 == TempReg && VGC_IS_SHADOW(u->val1));
-            def[u->val1] = u->size;
-            break;
+      if (verboze) {
+         ppIRStmt(st);
+         VG_(printf)("\n\n");
+      }
 
-         /* Check definedness of a tag. */
-         case TESTV:
-            tl_assert(u->tag1 == TempReg && VGC_IS_SHADOW(u->val1));
-            if (def[u->val1] <= 4) { 
-               tl_assert(def[u->val1] == u->size); 
-               NOP_no_msg(u);
-               if (dis) 
-                  VG_(printf)("   at %2d: delete TESTV on defd arg\n", i);
-            }
-            break;
+      switch (st->tag) {
 
-         /* Applies to both values and tags.  Propagate Definedness
-            property through copies.  Note that this isn't optional;
-            we *have* to do this to keep def[] correct. */
-         case MOV:
-            tl_assert(u->tag2 == TempReg);
-            if (u->tag1 == TempReg) {
-               if (VGC_IS_SHADOW(u->val1)) {
-                  tl_assert(VGC_IS_SHADOW(u->val2));
-                  def[u->val2] = def[u->val1];
-               }
-            }
+         case Ist_Tmp:
+            assign( bb, findShadowTmp(&mce, st->Ist.Tmp.tmp), 
+                        expr2vbits( &mce, st->Ist.Tmp.data) );
             break;
 
-         case PUTV:
-            tl_assert(u->tag1 == TempReg && VGC_IS_SHADOW(u->val1));
-            if (def[u->val1] <= 4) {
-               tl_assert(def[u->val1] == u->size);
-               u->tag1 = Literal;
-               u->val1 = 0;
-               switch (u->size) {
-                  case 4: u->lit32 = 0x00000000; break;
-                  case 2: u->lit32 = 0xFFFF0000; break;
-                  case 1: u->lit32 = 0xFFFFFF00; break;
-                  default: VG_(tool_panic)("vg_cleanup(PUTV)");
-               }
-               if (dis) 
-                  VG_(printf)(
-                     "   at %2d: propagate definedness into PUTV\n", i);
-            }
+         case Ist_Put:
+            do_shadow_PUT( &mce, 
+                           st->Ist.Put.offset,
+                           st->Ist.Put.data,
+                           NULL /* shadow atom */ );
             break;
 
-         case STOREV:
-            tl_assert(u->tag1 == TempReg && VGC_IS_SHADOW(u->val1));
-            if (def[u->val1] <= 4) {
-               tl_assert(def[u->val1] == u->size);
-               u->tag1 = Literal;
-               u->val1 = 0;
-               switch (u->size) {
-                  case 4: u->lit32 = 0x00000000; break;
-                  case 2: u->lit32 = 0xFFFF0000; break;
-                  case 1: u->lit32 = 0xFFFFFF00; break;
-                  default: VG_(tool_panic)("vg_cleanup(STOREV)");
-               }
-               if (dis) 
-                  VG_(printf)(
-                     "   at %2d: propagate definedness into STandV\n", i);
-            }
+         case Ist_PutI:
+            do_shadow_PUTI( &mce, 
+                            st->Ist.PutI.descr,
+                            st->Ist.PutI.ix,
+                            st->Ist.PutI.bias,
+                            st->Ist.PutI.data );
             break;
 
-         /* Nothing interesting we can do with this, I think. */
-         case PUTVF:
+         case Ist_STle:
+            do_shadow_STle( &mce, st->Ist.STle.addr, 0/* addr bias */,
+                                  st->Ist.STle.data,
+                                  NULL /* shadow data */ );
             break;
 
-         /* Tag handling operations. */
-         case TAG2:
-            tl_assert(u->tag2 == TempReg && VGC_IS_SHADOW(u->val2));
-            tl_assert(u->tag3 == Lit16);
-            /* Ultra-paranoid "type" checking. */
-            switch (u->val3) {
-               case Tag_ImproveAND4_TQ: case Tag_ImproveAND2_TQ:
-               case Tag_ImproveAND1_TQ: case Tag_ImproveOR4_TQ:
-               case Tag_ImproveOR2_TQ: case Tag_ImproveOR1_TQ:
-                  tl_assert(u->tag1 == TempReg && !VGC_IS_SHADOW(u->val1));
-                  break;
-               default:
-                  tl_assert(u->tag1 == TempReg && VGC_IS_SHADOW(u->val1));
-                  break;
-            }
-            switch (u->val3) {
-               Int sz;
-               case Tag_UifU4: 
-                  sz = 4; goto do_UifU;
-               case Tag_UifU2: 
-                  sz = 2; goto do_UifU;
-               case Tag_UifU1:
-                  sz = 1; goto do_UifU;
-               case Tag_UifU0:
-                  sz = 0; goto do_UifU;
-               do_UifU:
-                  tl_assert(u->tag1 == TempReg && VGC_IS_SHADOW(u->val1));
-                  tl_assert(u->tag2 == TempReg && VGC_IS_SHADOW(u->val2));
-                  if (def[u->val1] <= 4) {
-                     /* UifU.  The first arg is defined, so result is
-                        simply second arg.  Delete this operation. */
-                     tl_assert(def[u->val1] == sz);
-                     NOP_no_msg(u);
-                     if (dis) 
-                        VG_(printf)(
-                           "   at %2d: delete UifU%d due to defd arg1\n", 
-                           i, sz);
-                  }
-                  else 
-                  if (def[u->val2] <= 4) {
-                     /* UifU.  The second arg is defined, so result is
-                        simply first arg.  Copy to second. */
-                     tl_assert(def[u->val2] == sz);
-                     u->opcode = MOV; 
-                     u->size = 4;
-                     u->tag3 = NoValue;
-                     def[u->val2] = def[u->val1];
-                     if (dis) 
-                        VG_(printf)(
-                           "   at %2d: change UifU%d to MOV due to defd"
-                           " arg2\n", 
-                           i, sz);
-                  }
-                  break;
-               case Tag_ImproveAND4_TQ:
-                  sz = 4; goto do_ImproveAND;
-               case Tag_ImproveAND1_TQ:
-                  sz = 1; goto do_ImproveAND;
-               do_ImproveAND:
-                  /* Implements Q = T AND Q.  So if Q is entirely defined,
-                     ie all 0s, we get MOV T, Q. */
-                 if (def[u->val2] <= 4) {
-                     tl_assert(def[u->val2] == sz);
-                     u->size = 4; /* Regardless of sz */
-                     u->opcode = MOV;
-                     u->tag3 = NoValue;
-                     def[u->val2] = VGC_UNDEF;
-                     if (dis) 
-                        VG_(printf)(
-                            "   at %2d: change ImproveAND%d_TQ to MOV due "
-                            "to defd arg2\n", 
-                            i, sz);
-                  }
-                  break;
-               default: 
-                  goto unhandled;
-            }
+         case Ist_Exit:
+            /* if (!hasBogusLiterals) */
+               complainIfUndefined( &mce, st->Ist.Exit.guard );
             break;
 
-         case TAG1:
-            tl_assert(u->tag1 == TempReg && VGC_IS_SHADOW(u->val1));
-            if (def[u->val1] > 4) break;
-            /* We now know that the arg to the op is entirely defined.
-               If the op changes the size of the arg, we must replace
-               it with a SETV at the new size.  If it doesn't change
-               the size, we can delete it completely. */
-            switch (u->val3) {
-               /* Maintain the same size ... */
-               case Tag_Left4: 
-                  tl_assert(def[u->val1] == 4);
-                  NOP_tag1_op(u);
-                  break;
-               case Tag_PCast11: 
-                  tl_assert(def[u->val1] == 1);
-                  NOP_tag1_op(u);
-                  break;
-               /* Change size ... */
-               case Tag_PCast40: 
-                  tl_assert(def[u->val1] == 4);
-                  SETV_tag1_op(u,0);
-                  def[u->val1] = 0;
-                  break;
-               case Tag_PCast14: 
-                  tl_assert(def[u->val1] == 1);
-                  SETV_tag1_op(u,4);
-                  def[u->val1] = 4;
-                  break;
-               case Tag_PCast12: 
-                  tl_assert(def[u->val1] == 1);
-                  SETV_tag1_op(u,2);
-                  def[u->val1] = 2;
-                  break;
-               case Tag_PCast10: 
-                  tl_assert(def[u->val1] == 1);
-                  SETV_tag1_op(u,0);
-                  def[u->val1] = 0;
-                  break;
-               case Tag_PCast02: 
-                  tl_assert(def[u->val1] == 0);
-                  SETV_tag1_op(u,2);
-                  def[u->val1] = 2;
-                  break;
-               default: 
-                  goto unhandled;
-            }
-            if (dis) 
-               VG_(printf)(
-                  "   at %2d: delete TAG1 %s due to defd arg\n",
-                  i, nameOfTagOp(u->val3));
+         case Ist_Dirty:
+            do_shadow_Dirty( &mce, st->Ist.Dirty.details );
             break;
 
          default:
-         unhandled:
-            /* We don't know how to handle this uinstr.  Be safe, and 
-               set to VGC_VALUE or VGC_UNDEF all temps written by it. */
-            k = VG_(get_reg_usage)(u, TempReg, &tempUse[0], &isWrites[0]);
-            tl_assert(0 <= k && k <= VG_MAX_REGS_USED);
-            for (j = 0; j < k; j++) {
-               t = tempUse[j];
-               tl_assert(t >= 0 && t < n_temps);
-               if (!isWrites[j]) {
-                  /* t is read; ignore it. */
-                  if (0&& VGC_IS_SHADOW(t) && def[t] <= 4)
-                     VG_(printf)("ignoring def %d at %s %s\n", 
-                                 def[t], 
-                                 VG_(name_UOpcode)(True, u->opcode),
-                                 (u->opcode == TAG1 || u->opcode == TAG2)
-                                    ? nameOfTagOp(u->val3) 
-                                    : (Char*)"");
-               } else {
-                  /* t is written; better nullify it. */
-                  def[t] = VGC_IS_SHADOW(t) ? VGC_UNDEF : VGC_VALUE;
-               }
-            }
+            VG_(printf)("\n");
+            ppIRStmt(st);
+            VG_(printf)("\n");
+            VG_(tool_panic)("memcheck: unhandled IRStmt");
+
+      } /* switch (st->tag) */
+
+      if (verboze) {
+         for (j = first_stmt; j < bb->stmts_used; j++) {
+            VG_(printf)("   ");
+            ppIRStmt(bb->stmts[j]);
+            VG_(printf)("\n");
+         }
+         VG_(printf)("\n");
       }
+
+      addStmtToIRBB(bb, st);
+
    }
-}
 
+   /* Now we need to complain if the jump target is undefined. */
+   first_stmt = bb->stmts_used;
 
-/* Top level post-MemCheck-instrumentation cleanup function. */
-static void vg_cleanup ( UCodeBlock* cb )
-{
-   vg_propagate_definedness ( cb );
-   vg_delete_redundant_SETVs ( cb );
-}
+   if (verboze) {
+      VG_(printf)("bb->next = ");
+      ppIRExpr(bb->next);
+      VG_(printf)("\n\n");
+   }
 
+   complainIfUndefined( &mce, bb->next );
 
-/* Caller will print out final instrumented code if necessary;  we
-   print out intermediate instrumented code here if necessary. */
-UCodeBlock* TL_(instrument) ( UCodeBlock* cb, Addr not_used )
-{
-   cb = memcheck_instrument ( cb );
-   if (MC_(clo_cleanup)) {
-      if (dis) {
-         VG_(pp_UCodeBlock) ( cb, "Unimproved instrumented UCode:" );
-         VG_(printf)("Instrumentation improvements:\n");
+   if (verboze) {
+      for (j = first_stmt; j < bb->stmts_used; j++) {
+         VG_(printf)("   ");
+         ppIRStmt(bb->stmts[j]);
+         VG_(printf)("\n");
       }
-      vg_cleanup(cb);
-      if (dis) VG_(printf)("\n");
+      VG_(printf)("\n");
    }
-   return cb;
-}
 
-#undef dis
+   return bb;
+}
 
 /*--------------------------------------------------------------------*/
 /*--- end                                           mc_translate.c ---*/