Make a very minor change to the LibVEX_Translate interface (sub-arg of
needs_self_check) which allows VEX's user to selectively override, on
a per-translation basis, the default precise-exception control setting
that is specified in VexControl::iropt_register_updates.  Fix up
plumbing inside iropt so as to used passed-in values rather than the
default one.



git-svn-id: svn://svn.valgrind.org/vex/trunk@3084 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/priv/guest_amd64_defs.h b/priv/guest_amd64_defs.h
index 8ccce6f..003ebde 100644
--- a/priv/guest_amd64_defs.h
+++ b/priv/guest_amd64_defs.h
@@ -74,7 +74,8 @@
    precise memory exceptions.  This is logically part of the guest
    state description. */
 extern 
-Bool guest_amd64_state_requires_precise_mem_exns ( Int, Int );
+Bool guest_amd64_state_requires_precise_mem_exns ( Int, Int,
+                                                   VexRegisterUpdates );
 
 extern
 VexGuestLayout amd64guest_layout;
diff --git a/priv/guest_amd64_helpers.c b/priv/guest_amd64_helpers.c
index 680a207..aa1f2d5 100644
--- a/priv/guest_amd64_helpers.c
+++ b/priv/guest_amd64_helpers.c
@@ -3988,8 +3988,9 @@
 
    Only %RSP is needed in mode VexRegUpdSpAtMemAccess.   
 */
-Bool guest_amd64_state_requires_precise_mem_exns ( Int minoff,
-                                                   Int maxoff)
+Bool guest_amd64_state_requires_precise_mem_exns (
+        Int minoff, Int maxoff, VexRegisterUpdates pxControl
+     )
 {
    Int rbp_min = offsetof(VexGuestAMD64State, guest_RBP);
    Int rbp_max = rbp_min + 8 - 1;
@@ -4000,7 +4001,7 @@
 
    if (maxoff < rsp_min || minoff > rsp_max) {
       /* no overlap with rsp */
-      if (vex_control.iropt_register_updates == VexRegUpdSpAtMemAccess)
+      if (pxControl == VexRegUpdSpAtMemAccess)
          return False; // We only need to check stack pointer.
    } else {
       return True;
diff --git a/priv/guest_arm64_defs.h b/priv/guest_arm64_defs.h
index 8910cad..a3431f0 100644
--- a/priv/guest_arm64_defs.h
+++ b/priv/guest_arm64_defs.h
@@ -64,7 +64,8 @@
    precise memory exceptions.  This is logically part of the guest
    state description. */
 extern 
-Bool guest_arm64_state_requires_precise_mem_exns ( Int, Int );
+Bool guest_arm64_state_requires_precise_mem_exns ( Int, Int,
+                                                   VexRegisterUpdates );
 
 extern
 VexGuestLayout arm64Guest_layout;
diff --git a/priv/guest_arm64_helpers.c b/priv/guest_arm64_helpers.c
index 5d2080e..e8dda64 100644
--- a/priv/guest_arm64_helpers.c
+++ b/priv/guest_arm64_helpers.c
@@ -1317,8 +1317,9 @@
    We enforce precise exns for guest SP, PC, 29(FP), 30(LR).
    That might be overkill (for 29 and 30); I don't know.
 */
-Bool guest_arm64_state_requires_precise_mem_exns ( Int minoff, 
-                                                   Int maxoff)
+Bool guest_arm64_state_requires_precise_mem_exns (
+        Int minoff, Int maxoff, VexRegisterUpdates pxControl
+     )
 {
    Int xsp_min = offsetof(VexGuestARM64State, guest_XSP);
    Int xsp_max = xsp_min + 8 - 1;
@@ -1327,7 +1328,7 @@
 
    if (maxoff < xsp_min || minoff > xsp_max) {
       /* no overlap with xsp */
-      if (vex_control.iropt_register_updates == VexRegUpdSpAtMemAccess)
+      if (pxControl == VexRegUpdSpAtMemAccess)
          return False; // We only need to check stack pointer.
    } else {
       return True;
diff --git a/priv/guest_arm_defs.h b/priv/guest_arm_defs.h
index abefb64..b5b012b 100644
--- a/priv/guest_arm_defs.h
+++ b/priv/guest_arm_defs.h
@@ -66,7 +66,8 @@
    precise memory exceptions.  This is logically part of the guest
    state description. */
 extern 
-Bool guest_arm_state_requires_precise_mem_exns ( Int, Int );
+Bool guest_arm_state_requires_precise_mem_exns ( Int, Int,
+                                                 VexRegisterUpdates );
 
 extern
 VexGuestLayout armGuest_layout;
diff --git a/priv/guest_arm_helpers.c b/priv/guest_arm_helpers.c
index 2eeb13a..8a9b7f9 100644
--- a/priv/guest_arm_helpers.c
+++ b/priv/guest_arm_helpers.c
@@ -1047,8 +1047,9 @@
 
    Only R13(sp) is needed in mode VexRegUpdSpAtMemAccess.   
 */
-Bool guest_arm_state_requires_precise_mem_exns ( Int minoff, 
-                                                 Int maxoff)
+Bool guest_arm_state_requires_precise_mem_exns (
+        Int minoff, Int maxoff, VexRegisterUpdates pxControl
+     )
 {
    Int sp_min = offsetof(VexGuestARMState, guest_R13);
    Int sp_max = sp_min + 4 - 1;
@@ -1057,7 +1058,7 @@
 
    if (maxoff < sp_min || minoff > sp_max) {
       /* no overlap with sp */
-      if (vex_control.iropt_register_updates == VexRegUpdSpAtMemAccess)
+      if (pxControl == VexRegUpdSpAtMemAccess)
          return False; // We only need to check stack pointer.
    } else {
       return True;
diff --git a/priv/guest_generic_bb_to_IR.c b/priv/guest_generic_bb_to_IR.c
index 1b6a063..bb37d96 100644
--- a/priv/guest_generic_bb_to_IR.c
+++ b/priv/guest_generic_bb_to_IR.c
@@ -181,6 +181,7 @@
          /*OUT*/VexGuestExtents* vge,
          /*OUT*/UInt*            n_sc_extents,
          /*OUT*/UInt*            n_guest_instrs, /* stats only */
+         /*MOD*/VexRegisterUpdates* pxControl,
          /*IN*/ void*            callback_opaque,
          /*IN*/ DisOneInstrFn    dis_instr_fn,
          /*IN*/ const UChar*     guest_code,
@@ -192,7 +193,9 @@
          /*IN*/ const VexArchInfo* archinfo_guest,
          /*IN*/ const VexAbiInfo*  abiinfo_both,
          /*IN*/ IRType           guest_word_type,
-         /*IN*/ UInt             (*needs_self_check)(void*,const VexGuestExtents*),
+         /*IN*/ UInt             (*needs_self_check)
+                                    (void*, /*MB_MOD*/VexRegisterUpdates*,
+                                            const VexGuestExtents*),
          /*IN*/ Bool             (*preamble_function)(void*,IRSB*),
          /*IN*/ Int              offB_GUEST_CMSTART,
          /*IN*/ Int              offB_GUEST_CMLEN,
@@ -528,7 +531,7 @@
       IRType   host_word_type = Ity_INVALID;
 
       UInt extents_needing_check
-         = needs_self_check(callback_opaque, vge);
+         = needs_self_check(callback_opaque, pxControl, vge);
 
       if (host_word_szB == 4) host_word_type = Ity_I32;
       if (host_word_szB == 8) host_word_type = Ity_I64;
diff --git a/priv/guest_generic_bb_to_IR.h b/priv/guest_generic_bb_to_IR.h
index 7a7c136..49c94d7 100644
--- a/priv/guest_generic_bb_to_IR.h
+++ b/priv/guest_generic_bb_to_IR.h
@@ -165,12 +165,13 @@
    Top-level BB to IR conversion fn.
    --------------------------------------------------------------- */
 
-/* See detailed comment in bb_to_IR.c. */
+/* See detailed comment in guest_generic_bb_to_IR.c. */
 extern
 IRSB* bb_to_IR ( 
          /*OUT*/VexGuestExtents* vge,
          /*OUT*/UInt*            n_sc_extents,
          /*OUT*/UInt*            n_guest_instrs, /* stats only */
+         /*MOD*/VexRegisterUpdates* pxControl,
          /*IN*/ void*            callback_opaque,
          /*IN*/ DisOneInstrFn    dis_instr_fn,
          /*IN*/ const UChar*     guest_code,
@@ -182,7 +183,9 @@
          /*IN*/ const VexArchInfo* archinfo_guest,
          /*IN*/ const VexAbiInfo*  abiinfo_both,
          /*IN*/ IRType           guest_word_type,
-         /*IN*/ UInt             (*needs_self_check)(void*,const VexGuestExtents*),
+         /*IN*/ UInt             (*needs_self_check)
+                                    (void*, /*MB_MOD*/VexRegisterUpdates*,
+                                            const VexGuestExtents*),
          /*IN*/ Bool             (*preamble_function)(void*,IRSB*),
          /*IN*/ Int              offB_GUEST_CMSTART,
          /*IN*/ Int              offB_GUEST_CMLEN,
diff --git a/priv/guest_mips_defs.h b/priv/guest_mips_defs.h
index 757211d..c60e026 100644
--- a/priv/guest_mips_defs.h
+++ b/priv/guest_mips_defs.h
@@ -68,9 +68,13 @@
 /* Describes to the optimser which part of the guest state require
    precise memory exceptions.  This is logically part of the guest
    state description. */
-extern Bool guest_mips32_state_requires_precise_mem_exns ( Int, Int );
+extern
+Bool guest_mips32_state_requires_precise_mem_exns ( Int, Int,
+                                                    VexRegisterUpdates );
 
-extern Bool guest_mips64_state_requires_precise_mem_exns ( Int, Int );
+extern
+Bool guest_mips64_state_requires_precise_mem_exns ( Int, Int,
+                                                    VexRegisterUpdates );
 
 extern VexGuestLayout mips32Guest_layout;
 extern VexGuestLayout mips64Guest_layout;
diff --git a/priv/guest_mips_helpers.c b/priv/guest_mips_helpers.c
index 0b10208..863efda 100644
--- a/priv/guest_mips_helpers.c
+++ b/priv/guest_mips_helpers.c
@@ -287,7 +287,9 @@
 
    Only SP is needed in mode VexRegUpdSpAtMemAccess.
 */
-Bool guest_mips32_state_requires_precise_mem_exns(Int minoff, Int maxoff)
+Bool guest_mips32_state_requires_precise_mem_exns (
+        Int minoff, Int maxoff, VexRegisterUpdates pxControl
+     )
 {
    Int sp_min = offsetof(VexGuestMIPS32State, guest_r29);
    Int sp_max = sp_min + 4 - 1;
@@ -296,7 +298,7 @@
 
    if (maxoff < sp_min || minoff > sp_max) {
       /* no overlap with sp */
-      if (vex_control.iropt_register_updates == VexRegUpdSpAtMemAccess)
+      if (pxControl == VexRegUpdSpAtMemAccess)
          return False;  /* We only need to check stack pointer. */
    } else {
       return True;
@@ -322,7 +324,9 @@
    return False;
 }
 
-Bool guest_mips64_state_requires_precise_mem_exns ( Int minoff, Int maxoff )
+Bool guest_mips64_state_requires_precise_mem_exns (
+        Int minoff, Int maxoff, VexRegisterUpdates pxControl
+     )
 {
    Int sp_min = offsetof(VexGuestMIPS64State, guest_r29);
    Int sp_max = sp_min + 8 - 1;
@@ -331,7 +335,7 @@
 
    if ( maxoff < sp_min || minoff > sp_max ) {
       /* no overlap with sp */
-      if (vex_control.iropt_register_updates == VexRegUpdSpAtMemAccess)
+      if (pxControl == VexRegUpdSpAtMemAccess)
          return False;  /* We only need to check stack pointer. */
    } else {
       return True;
diff --git a/priv/guest_ppc_defs.h b/priv/guest_ppc_defs.h
index 55bb656..8ef1706 100644
--- a/priv/guest_ppc_defs.h
+++ b/priv/guest_ppc_defs.h
@@ -81,10 +81,12 @@
    precise memory exceptions.  This is logically part of the guest
    state description. */
 extern 
-Bool guest_ppc32_state_requires_precise_mem_exns ( Int, Int );
+Bool guest_ppc32_state_requires_precise_mem_exns ( Int, Int,
+                                                   VexRegisterUpdates );
 
 extern 
-Bool guest_ppc64_state_requires_precise_mem_exns ( Int, Int );
+Bool guest_ppc64_state_requires_precise_mem_exns ( Int, Int,
+                                                   VexRegisterUpdates );
 
 extern
 VexGuestLayout ppc32Guest_layout;
diff --git a/priv/guest_ppc_helpers.c b/priv/guest_ppc_helpers.c
index 18a1ac3..dc36818 100644
--- a/priv/guest_ppc_helpers.c
+++ b/priv/guest_ppc_helpers.c
@@ -711,8 +711,9 @@
 
    Only R1 is needed in mode VexRegUpdSpAtMemAccess.   
 */
-Bool guest_ppc32_state_requires_precise_mem_exns ( Int minoff, 
-                                                   Int maxoff )
+Bool guest_ppc32_state_requires_precise_mem_exns (
+        Int minoff, Int maxoff, VexRegisterUpdates pxControl
+     )
 {
    Int lr_min  = offsetof(VexGuestPPC32State, guest_LR);
    Int lr_max  = lr_min + 4 - 1;
@@ -723,7 +724,7 @@
 
    if (maxoff < r1_min || minoff > r1_max) {
       /* no overlap with R1 */
-      if (vex_control.iropt_register_updates == VexRegUpdSpAtMemAccess)
+      if (pxControl == VexRegUpdSpAtMemAccess)
          return False; // We only need to check stack pointer.
    } else {
       return True;
@@ -744,8 +745,9 @@
    return False;
 }
 
-Bool guest_ppc64_state_requires_precise_mem_exns ( Int minoff, 
-                                                   Int maxoff )
+Bool guest_ppc64_state_requires_precise_mem_exns (
+        Int minoff, Int maxoff, VexRegisterUpdates pxControl
+     )
 {
    /* Given that R2 is a Big Deal in the ELF ppc64 ABI, it seems
       prudent to be conservative with it, even though thus far there
@@ -762,7 +764,7 @@
 
    if (maxoff < r1_min || minoff > r1_max) {
       /* no overlap with R1 */
-      if (vex_control.iropt_register_updates == VexRegUpdSpAtMemAccess)
+      if (pxControl == VexRegUpdSpAtMemAccess)
          return False; // We only need to check stack pointer.
    } else {
       return True;
diff --git a/priv/guest_s390_defs.h b/priv/guest_s390_defs.h
index 2e482f5..758cf91 100644
--- a/priv/guest_s390_defs.h
+++ b/priv/guest_s390_defs.h
@@ -60,10 +60,11 @@
                                  Int n_precedingStmts);
 
 
-/* Describes to the optimser which part of the guest state require
+/* Describes to the optimiser which part of the guest state require
    precise memory exceptions.  This is logically part of the guest
    state description. */
-Bool guest_s390x_state_requires_precise_mem_exns ( Int, Int );
+Bool guest_s390x_state_requires_precise_mem_exns ( Int, Int,
+                                                   VexRegisterUpdates );
 
 extern VexGuestLayout s390xGuest_layout;
 
diff --git a/priv/guest_s390_helpers.c b/priv/guest_s390_helpers.c
index df1f24b..cf223c4 100644
--- a/priv/guest_s390_helpers.c
+++ b/priv/guest_s390_helpers.c
@@ -152,7 +152,9 @@
    .. maxoff requires precise memory exceptions.  If in doubt return
    True (but this generates significantly slower code).  */
 Bool
-guest_s390x_state_requires_precise_mem_exns(Int minoff, Int maxoff)
+guest_s390x_state_requires_precise_mem_exns (
+   Int minoff, Int maxoff, VexRegisterUpdates pxControl
+)
 {
    Int lr_min = S390X_GUEST_OFFSET(guest_LR);
    Int lr_max = lr_min + 8 - 1;
@@ -165,7 +167,7 @@
 
    if (maxoff < sp_min || minoff > sp_max) {
       /* No overlap with SP */
-      if (vex_control.iropt_register_updates == VexRegUpdSpAtMemAccess)
+      if (pxControl == VexRegUpdSpAtMemAccess)
          return False; // We only need to check stack pointer.
    } else {
       return True;
diff --git a/priv/guest_x86_defs.h b/priv/guest_x86_defs.h
index 3dc34c8..412ee94 100644
--- a/priv/guest_x86_defs.h
+++ b/priv/guest_x86_defs.h
@@ -74,7 +74,8 @@
    precise memory exceptions.  This is logically part of the guest
    state description. */
 extern 
-Bool guest_x86_state_requires_precise_mem_exns ( Int, Int );
+Bool guest_x86_state_requires_precise_mem_exns ( Int, Int,
+                                                 VexRegisterUpdates );
 
 extern
 VexGuestLayout x86guest_layout;
diff --git a/priv/guest_x86_helpers.c b/priv/guest_x86_helpers.c
index ef5e09e..66a571f 100644
--- a/priv/guest_x86_helpers.c
+++ b/priv/guest_x86_helpers.c
@@ -2778,8 +2778,9 @@
 
    Only %ESP is needed in mode VexRegUpdSpAtMemAccess.   
 */
-Bool guest_x86_state_requires_precise_mem_exns ( Int minoff, 
-                                                 Int maxoff)
+Bool guest_x86_state_requires_precise_mem_exns (
+        Int minoff, Int maxoff, VexRegisterUpdates pxControl
+     )
 {
    Int ebp_min = offsetof(VexGuestX86State, guest_EBP);
    Int ebp_max = ebp_min + 4 - 1;
@@ -2790,7 +2791,7 @@
 
    if (maxoff < esp_min || minoff > esp_max) {
       /* no overlap with esp */
-      if (vex_control.iropt_register_updates == VexRegUpdSpAtMemAccess)
+      if (pxControl == VexRegUpdSpAtMemAccess)
          return False; // We only need to check stack pointer.
    } else {
       return True;
diff --git a/priv/ir_opt.c b/priv/ir_opt.c
index 86bd646..ffd18f9 100644
--- a/priv/ir_opt.c
+++ b/priv/ir_opt.c
@@ -716,7 +716,8 @@
 static void handle_gets_Stmt ( 
                HashHW* env, 
                IRStmt* st,
-               Bool (*preciseMemExnsFn)(Int,Int)
+               Bool (*preciseMemExnsFn)(Int,Int,VexRegisterUpdates),
+               VexRegisterUpdates pxControl
             )
 {
    Int     j;
@@ -828,7 +829,7 @@
          of the environment corresponding to guest state that may not
          be reordered with respect to memory references.  That means
          at least the stack pointer. */
-      switch (vex_control.iropt_register_updates) {
+      switch (pxControl) {
          case VexRegUpdAllregsAtMemAccess:
             /* Precise exceptions required at mem access.
                Flush all guest state. */
@@ -849,13 +850,14 @@
                   preciseMemExnsFn. */
                HWord k_lo = (env->key[j] >> 16) & 0xFFFF;
                HWord k_hi = env->key[j] & 0xFFFF;
-               if (preciseMemExnsFn( k_lo, k_hi ))
+               if (preciseMemExnsFn( k_lo, k_hi, pxControl ))
                   env->inuse[j] = False;
             }
             break;
          case VexRegUpdAllregsAtEachInsn:
             // VexRegUpdAllregsAtEachInsn cannot happen here.
             // fall through
+         case VexRegUpd_INVALID:
          default:
             vassert(0);
       }
@@ -882,7 +884,8 @@
 
 static void redundant_put_removal_BB ( 
                IRSB* bb,
-               Bool (*preciseMemExnsFn)(Int,Int)
+               Bool (*preciseMemExnsFn)(Int,Int,VexRegisterUpdates),
+               VexRegisterUpdates pxControl
             )
 {
    Int     i, j;
@@ -890,7 +893,7 @@
    IRStmt* st;
    UInt    key = 0; /* keep gcc -O happy */
 
-   vassert(vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn);
+   vassert(pxControl < VexRegUpdAllregsAtEachInsn);
 
    HashHW* env = newHHW();
 
@@ -982,7 +985,7 @@
          of the guest state is no longer a write, but a read.  Also
          deals with implicit reads of guest state needed to maintain
          precise exceptions. */
-      handle_gets_Stmt( env, st, preciseMemExnsFn );
+      handle_gets_Stmt( env, st, preciseMemExnsFn, pxControl );
    }
 }
 
@@ -4392,13 +4395,13 @@
    bb is modified in-place. */
 
 static
-void do_redundant_PutI_elimination ( IRSB* bb )
+void do_redundant_PutI_elimination ( IRSB* bb, VexRegisterUpdates pxControl )
 {
    Int    i, j;
    Bool   delete;
    IRStmt *st, *stj;
 
-   vassert(vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn);
+   vassert(pxControl < VexRegUpdAllregsAtEachInsn);
 
    for (i = 0; i < bb->stmts_used; i++) {
       st = bb->stmts[i];
@@ -5524,9 +5527,12 @@
 }
 
 inline
-static Interval dirty_helper_puts ( const IRDirty *d,
-                                    Bool (*preciseMemExnsFn)(Int, Int),
-                                    Bool *requiresPreciseMemExns )
+static Interval dirty_helper_puts (
+                   const IRDirty *d,
+                   Bool (*preciseMemExnsFn)(Int,Int,VexRegisterUpdates),
+                   VexRegisterUpdates pxControl,
+                   /*OUT*/Bool *requiresPreciseMemExns
+                )
 {
    Int i;
    Interval interval;
@@ -5558,7 +5564,8 @@
          Int repeatLen = d->fxState[i].repeatLen;
 
          if (preciseMemExnsFn(offset,
-                              offset + nRepeats * repeatLen + size - 1)) {
+                              offset + nRepeats * repeatLen + size - 1,
+                              pxControl)) {
             *requiresPreciseMemExns = True;
          }
          update_interval(&interval, offset,
@@ -5569,11 +5576,15 @@
    return interval;
 }
 
-/* Return an interval if st modifies the guest state. Via requiresPreciseMemExns
-   return whether or not that modification requires precise exceptions. */
-static Interval stmt_modifies_guest_state ( IRSB *bb, const IRStmt *st,
-                                            Bool (*preciseMemExnsFn)(Int,Int),
-                                            Bool *requiresPreciseMemExns )
+/* Return an interval if st modifies the guest state.  Via
+   requiresPreciseMemExns return whether or not that modification
+   requires precise exceptions. */
+static Interval stmt_modifies_guest_state ( 
+                   IRSB *bb, const IRStmt *st,
+                   Bool (*preciseMemExnsFn)(Int,Int,VexRegisterUpdates),
+                   VexRegisterUpdates pxControl,
+                   /*OUT*/Bool *requiresPreciseMemExns
+                )
 {
    Interval interval;
 
@@ -5582,7 +5593,8 @@
       Int offset = st->Ist.Put.offset;
       Int size = sizeofIRType(typeOfIRExpr(bb->tyenv, st->Ist.Put.data));
 
-      *requiresPreciseMemExns = preciseMemExnsFn(offset, offset + size - 1);
+      *requiresPreciseMemExns
+         = preciseMemExnsFn(offset, offset + size - 1, pxControl);
       interval.present = True;
       interval.low  = offset;
       interval.high = offset + size - 1;
@@ -5598,8 +5610,9 @@
          are no holes. This is to avoid a loop. The assumption is conservative
          in the sense that we might report that precise memory exceptions are
          needed when in fact they are not. */
-      *requiresPreciseMemExns = 
-         preciseMemExnsFn(offset, offset + descr->nElems * size - 1);
+      *requiresPreciseMemExns
+         = preciseMemExnsFn(offset, offset + descr->nElems * size - 1,
+                            pxControl);
       interval.present = True;
       interval.low  = offset;
       interval.high = offset + descr->nElems * size - 1;
@@ -5607,7 +5620,8 @@
    }
 
    case Ist_Dirty:
-      return dirty_helper_puts(st->Ist.Dirty.details, preciseMemExnsFn,
+      return dirty_helper_puts(st->Ist.Dirty.details,
+                               preciseMemExnsFn, pxControl,
                                requiresPreciseMemExns);
 
    default:
@@ -5619,8 +5633,11 @@
    }
 }
 
-/* notstatic */ Addr ado_treebuild_BB ( IRSB* bb,
-                                        Bool (*preciseMemExnsFn)(Int,Int) )
+/* notstatic */ Addr ado_treebuild_BB (
+                        IRSB* bb,
+                        Bool (*preciseMemExnsFn)(Int,Int,VexRegisterUpdates),
+                        VexRegisterUpdates pxControl
+                     )
 {
    Int      i, j, k, m;
    Bool     stmtStores, invalidateMe;
@@ -5759,8 +5776,10 @@
          consideration does, or might do (sidely safe @ True). */
 
       Bool putRequiresPreciseMemExns;
-      putInterval = stmt_modifies_guest_state( bb, st, preciseMemExnsFn,
-                                               &putRequiresPreciseMemExns);
+      putInterval = stmt_modifies_guest_state(
+                       bb, st, preciseMemExnsFn, pxControl,
+                       &putRequiresPreciseMemExns
+                    );
 
       /* be True if this stmt writes memory or might do (==> we don't
          want to reorder other loads or stores relative to it).  Also,
@@ -5860,7 +5879,8 @@
 IRSB* cheap_transformations ( 
          IRSB* bb,
          IRExpr* (*specHelper) (const HChar*, IRExpr**, IRStmt**, Int),
-         Bool (*preciseMemExnsFn)(Int,Int)
+         Bool (*preciseMemExnsFn)(Int,Int,VexRegisterUpdates),
+         VexRegisterUpdates pxControl
       )
 {
    redundant_get_removal_BB ( bb );
@@ -5869,8 +5889,8 @@
       ppIRSB(bb);
    }
 
-   if (vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn) {
-      redundant_put_removal_BB ( bb, preciseMemExnsFn );
+   if (pxControl < VexRegUpdAllregsAtEachInsn) {
+      redundant_put_removal_BB ( bb, preciseMemExnsFn, pxControl );
    }
    if (iropt_verbose) {
       vex_printf("\n========= REDUNDANT PUT\n\n" );
@@ -5904,13 +5924,13 @@
    optimising as much as possible in the presence of GetI and PutI.  */
 
 static
-IRSB* expensive_transformations( IRSB* bb )
+IRSB* expensive_transformations( IRSB* bb, VexRegisterUpdates pxControl )
 {
    (void)do_cse_BB( bb );
    collapse_AddSub_chains_BB( bb );
    do_redundant_GetI_elimination( bb );
-   if (vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn) {
-      do_redundant_PutI_elimination( bb );
+   if (pxControl < VexRegUpdAllregsAtEachInsn) {
+      do_redundant_PutI_elimination( bb, pxControl );
    }
    do_deadcode_BB( bb );
    return bb;
@@ -6038,7 +6058,8 @@
 IRSB* do_iropt_BB(
          IRSB* bb0,
          IRExpr* (*specHelper) (const HChar*, IRExpr**, IRStmt**, Int),
-         Bool (*preciseMemExnsFn)(Int,Int),
+         Bool (*preciseMemExnsFn)(Int,Int,VexRegisterUpdates),
+         VexRegisterUpdates pxControl,
          Addr    guest_addr,
          VexArch guest_arch
       )
@@ -6070,15 +6091,15 @@
       If needed, do expensive transformations and then another cheap
       cleanup pass. */
 
-   bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
+   bb = cheap_transformations( bb, specHelper, preciseMemExnsFn, pxControl );
 
    if (guest_arch == VexArchARM) {
       /* Translating Thumb2 code produces a lot of chaff.  We have to
          work extra hard to get rid of it. */
       bb = cprop_BB(bb);
       bb = spec_helpers_BB ( bb, specHelper );
-      if (vex_control.iropt_register_updates < VexRegUpdAllregsAtEachInsn) {
-         redundant_put_removal_BB ( bb, preciseMemExnsFn );
+      if (pxControl < VexRegUpdAllregsAtEachInsn) {
+         redundant_put_removal_BB ( bb, preciseMemExnsFn, pxControl );
       }
       do_cse_BB( bb );
       do_deadcode_BB( bb );
@@ -6105,12 +6126,14 @@
          n_expensive++;
          if (DEBUG_IROPT)
             vex_printf("***** EXPENSIVE %d %d\n", n_total, n_expensive);
-         bb = expensive_transformations( bb );
-         bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
+         bb = expensive_transformations( bb, pxControl );
+         bb = cheap_transformations( bb, specHelper,
+                                     preciseMemExnsFn, pxControl );
          /* Potentially common up GetIs */
          cses = do_cse_BB( bb );
          if (cses)
-            bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
+            bb = cheap_transformations( bb, specHelper,
+                                        preciseMemExnsFn, pxControl );
       }
 
       /* Now have a go at unrolling simple (single-BB) loops.  If
@@ -6118,10 +6141,12 @@
 
       bb2 = maybe_loop_unroll_BB( bb, guest_addr );
       if (bb2) {
-         bb = cheap_transformations( bb2, specHelper, preciseMemExnsFn );
+         bb = cheap_transformations( bb2, specHelper,
+                                     preciseMemExnsFn, pxControl );
          if (hasGetIorPutI) {
-            bb = expensive_transformations( bb );
-            bb = cheap_transformations( bb, specHelper, preciseMemExnsFn );
+            bb = expensive_transformations( bb, pxControl );
+            bb = cheap_transformations( bb, specHelper,
+                                        preciseMemExnsFn, pxControl );
          } else {
             /* at least do CSE and dead code removal */
             do_cse_BB( bb );
diff --git a/priv/ir_opt.h b/priv/ir_opt.h
index 07cee63..43b2a47 100644
--- a/priv/ir_opt.h
+++ b/priv/ir_opt.h
@@ -41,12 +41,14 @@
 #include "libvex.h"
 
 /* Top level optimiser entry point.  Returns a new BB.  Operates
-   under the control of the global "vex_control" struct. */
+   under the control of the global "vex_control" struct and of the
+   supplied |pxControl| argument. */
 extern 
-IRSB* do_iropt_BB(
+IRSB* do_iropt_BB (
          IRSB* bb,
          IRExpr* (*specHelper) (const HChar*, IRExpr**, IRStmt**, Int),
-         Bool (*preciseMemExnsFn)(Int,Int),
+         Bool (*preciseMemExnsFn)(Int,Int,VexRegisterUpdates),
+         VexRegisterUpdates pxControl,
          Addr    guest_addr,
          VexArch guest_arch
       );
@@ -62,9 +64,13 @@
 /* The tree-builder.  Make (approximately) maximal safe trees.  bb is
    destructively modified.  Returns (unrelatedly, but useful later on)
    the guest address of the highest addressed byte from any insn in
-   this block, or Addr64_MAX if unknown (can that ever happen?) */
+   this block, or Addr_MAX if unknown (can that ever happen?) */
 extern
-Addr ado_treebuild_BB ( IRSB* bb, Bool (*preciseMemExnsFn)(Int,Int) );
+Addr ado_treebuild_BB (
+        IRSB* bb,
+        Bool (*preciseMemExnsFn)(Int,Int,VexRegisterUpdates),
+        VexRegisterUpdates pxControl
+     );
 
 #endif /* ndef __VEX_IR_OPT_H */
 
diff --git a/priv/main_main.c b/priv/main_main.c
index 71c8bf6..e76a5e4 100644
--- a/priv/main_main.c
+++ b/priv/main_main.c
@@ -94,13 +94,13 @@
 void LibVEX_default_VexControl ( /*OUT*/ VexControl* vcon )
 {
    vex_bzero(vcon, sizeof(*vcon));
-   vcon->iropt_verbosity            = 0;
-   vcon->iropt_level                = 2;
-   vcon->iropt_register_updates     = VexRegUpdUnwindregsAtMemAccess;
-   vcon->iropt_unroll_thresh        = 120;
-   vcon->guest_max_insns            = 60;
-   vcon->guest_chase_thresh         = 10;
-   vcon->guest_chase_cond           = False;
+   vcon->iropt_verbosity                = 0;
+   vcon->iropt_level                    = 2;
+   vcon->iropt_register_updates_default = VexRegUpdUnwindregsAtMemAccess;
+   vcon->iropt_unroll_thresh            = 120;
+   vcon->guest_max_insns                = 60;
+   vcon->guest_chase_thresh             = 10;
+   vcon->guest_chase_cond               = False;
 }
 
 
@@ -229,7 +229,7 @@
                                   const void*, const void*, const void*,
                                   const void* );
    IRExpr*      (*specHelper)   ( const HChar*, IRExpr**, IRStmt**, Int );
-   Bool         (*preciseMemExnsFn) ( Int, Int );
+   Bool         (*preciseMemExnsFn) ( Int, Int, VexRegisterUpdates );
 
    DisOneInstrFn disInstrFn;
 
@@ -683,9 +683,14 @@
                    " Front end "
                    "------------------------\n\n");
 
+   VexRegisterUpdates pxControl = vex_control.iropt_register_updates_default;
+   vassert(pxControl >= VexRegUpdSpAtMemAccess
+           && pxControl <= VexRegUpdAllregsAtEachInsn);
+
    irsb = bb_to_IR ( vta->guest_extents,
                      &res.n_sc_extents,
                      &res.n_guest_instrs,
+                     &pxControl,
                      vta->callback_opaque,
                      disInstrFn,
                      vta->guest_bytes, 
@@ -719,6 +724,10 @@
       vassert(vta->guest_extents->len[i] < 10000); /* sanity */
    }
 
+   /* bb_to_IR() could have caused pxControl to change. */
+   vassert(pxControl >= VexRegUpdSpAtMemAccess
+           && pxControl <= VexRegUpdAllregsAtEachInsn);
+
    /* If debugging, show the raw guest bytes for this bb. */
    if (0 || (vex_traceflags & VEX_TRACE_FE)) {
       if (vta->guest_extents->n_used > 1) {
@@ -746,7 +755,7 @@
    vexAllocSanityCheck();
 
    /* Clean it up, hopefully a lot. */
-   irsb = do_iropt_BB ( irsb, specHelper, preciseMemExnsFn, 
+   irsb = do_iropt_BB ( irsb, specHelper, preciseMemExnsFn, pxControl,
                               vta->guest_bytes_addr,
                               vta->arch_guest );
    sanityCheckIRSB( irsb, "after initial iropt", 
@@ -811,7 +820,7 @@
 
    /* Turn it into virtual-registerised code.  Build trees -- this
       also throws away any dead bindings. */
-   max_ga = ado_treebuild_BB( irsb, preciseMemExnsFn );
+   max_ga = ado_treebuild_BB( irsb, preciseMemExnsFn, pxControl );
 
    if (vta->finaltidy) {
       irsb = vta->finaltidy(irsb);
diff --git a/pub/libvex.h b/pub/libvex.h
index 3e99d47..0138999 100644
--- a/pub/libvex.h
+++ b/pub/libvex.h
@@ -386,25 +386,37 @@
 
 
 /* VexRegisterUpdates specifies when to ensure that the guest state is
-   up to date.
+   up to date, in order of increasing accuracy but increasing expense.
 
-   VexRegUpdSpAtMemAccess : all registers are updated at superblock
-   exits, SP is up to date at memory exception points. The SP is described
-   by the arch specific functions guest_<arch>_state_requires_precise_mem_exns.
+     VexRegUpdSpAtMemAccess: all registers are updated at superblock
+     exits, and SP is also up to date at memory exception points.  The
+     SP is described by the arch specific functions
+     guest_<arch>_state_requires_precise_mem_exns.
 
-   VexRegUpdUnwindregsAtMemAccess : registers needed to make a stack trace are
-   up to date at memory exception points.  Typically, these are PC/SP/FP. The
-   minimal registers are described by the arch specific functions
-   guest_<arch>_state_requires_precise_mem_exns.
+     VexRegUpdUnwindregsAtMemAccess: registers needed to make a stack
+     trace are up to date at memory exception points.  Typically,
+     these are PC/SP/FP.  The minimal registers are described by the
+     arch specific functions guest_<arch>_state_requires_precise_mem_exns.
+     This is what Valgrind sets as the default.
 
-   VexRegUpdAllregsAtMemAccess : all registers up to date at memory exception
-   points.
+     VexRegUpdAllregsAtMemAccess: all registers up to date at memory
+     exception points.  This is what normally might be considered as
+     providing "precise exceptions for memory", but does not
+     necessarily provide precise register values at any other kind of
+     exception.
 
-   VexRegUpdAllregsAtEachInsn : all registers up to date at each instruction. */
-typedef enum { VexRegUpdSpAtMemAccess=0x700,
-               VexRegUpdUnwindregsAtMemAccess,
-               VexRegUpdAllregsAtMemAccess,
-               VexRegUpdAllregsAtEachInsn } VexRegisterUpdates;
+     VexRegUpdAllregsAtEachInsn: all registers up to date at each
+     instruction. 
+*/
+typedef
+   enum {
+      VexRegUpd_INVALID=0x700,
+      VexRegUpdSpAtMemAccess,
+      VexRegUpdUnwindregsAtMemAccess,
+      VexRegUpdAllregsAtMemAccess,
+      VexRegUpdAllregsAtEachInsn
+   }
+   VexRegisterUpdates;
 
 /* Control of Vex's optimiser. */
 
@@ -415,8 +427,14 @@
       /* Control aggressiveness of iropt.  0 = no opt, 1 = simple
          opts, 2 (default) = max optimisation. */
       Int iropt_level;
-      /* Controls when registers are updated in guest state. */
-      VexRegisterUpdates iropt_register_updates;
+      /* Controls when registers are updated in guest state.  Note
+         that this is the default value.  The VEX client can override
+         this on a per-IRSB basis if it wants.  bb_to_IR() will query
+         the client to ask if it wants a different setting for the
+         block under construction, and that new setting is transported
+         back to LibVEX_Translate, which feeds it to iropt via the
+         various do_iropt_BB calls. */
+      VexRegisterUpdates iropt_register_updates_default;
       /* How aggressive should iropt be in unrolling loops?  Higher
          numbers make it more enthusiastic about loop unrolling.
          Default=120.  A setting of zero disables unrolling.  */
@@ -642,8 +660,19 @@
          if any, a self check is required for.  Must not be NULL.
          The returned value is a bitmask with a 1 in position i indicating
          that the i'th extent needs a check.  Since there can be at most
-         3 extents, the returned values must be between 0 and 7. */
+         3 extents, the returned values must be between 0 and 7.
+
+         This call also gives the VEX client the opportunity to change
+         the precision of register update preservation as performed by
+         the IR optimiser.  Before the call, VEX will set *pxControl
+         to hold the default register-update status value as specified
+         by VexControl::iropt_register_updates_default as passed to
+         LibVEX_Init at library initialisation time.  The client (in
+         this callback) can if it wants, inspect the value and change
+         it to something different, and that value will be used for
+         subsequent IR optimisation of the block. */
       UInt (*needs_self_check)( /*callback_opaque*/void*,
+                                /*MAYBE_MOD*/VexRegisterUpdates* pxControl,
                                 const VexGuestExtents* );
 
       /* IN: optionally, a callback which allows the caller to add its