The logic that drove basic block to IR disassembly had been duplicated
over the 3 front ends (x86, amd64, ppc32).  Given the need to take
into account basic block chasing, adding of instruction marks, etc,
the logic is not completely straightforward, and so commoning it up is
a good thing.



git-svn-id: svn://svn.valgrind.org/vex/trunk@1247 8f6e269a-dfd6-0310-a8e1-e2731360e62c
diff --git a/Makefile b/Makefile
index 5b06d76..cfdff11 100644
--- a/Makefile
+++ b/Makefile
@@ -19,6 +19,7 @@
 		priv/main/vex_globals.h			\
 		priv/main/vex_util.h			\
 		priv/guest-generic/g_generic_x87.h	\
+		priv/guest-generic/bb_to_IR.h		\
 		priv/guest-x86/gdefs.h			\
 		priv/guest-amd64/gdefs.h		\
 		priv/guest-arm/gdefs.h			\
@@ -44,6 +45,7 @@
 		priv/host-generic/h_generic_simd64.o	\
 		priv/host-generic/reg_alloc2.o		\
 		priv/guest-generic/g_generic_x87.o	\
+		priv/guest-generic/bb_to_IR.o		\
 		priv/guest-x86/ghelpers.o		\
 		priv/guest-amd64/ghelpers.o		\
 		priv/guest-arm/ghelpers.o		\
@@ -203,6 +205,10 @@
 	$(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/guest-generic/g_generic_x87.o \
 					 -c priv/guest-generic/g_generic_x87.c
 
+priv/guest-generic/bb_to_IR.o: $(ALL_HEADERS) priv/guest-generic/bb_to_IR.c
+	$(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/guest-generic/bb_to_IR.o \
+					 -c priv/guest-generic/bb_to_IR.c
+
 priv/guest-x86/ghelpers.o: $(ALL_HEADERS) priv/guest-x86/ghelpers.c
 	$(CC) $(CCFLAGS) $(ALL_INCLUDES) -o priv/guest-x86/ghelpers.o \
 					 -c priv/guest-x86/ghelpers.c
diff --git a/priv/guest-amd64/gdefs.h b/priv/guest-amd64/gdefs.h
index d1f9c20..9e613b3 100644
--- a/priv/guest-amd64/gdefs.h
+++ b/priv/guest-amd64/gdefs.h
@@ -43,14 +43,17 @@
 /*--- amd64 to IR conversion                            ---*/
 /*---------------------------------------------------------*/
 
+/* Convert one amd64 insn to IR.  See the type DisOneInstrFn in
+   bb_to_IR.h. */
 extern
-IRBB* bbToIR_AMD64 ( UChar*           amd64code, 
-                     Addr64           guest_rip_start, 
-                     VexGuestExtents* vge,
-                     Bool             (*byte_accessible)(Addr64),
-                     Bool             (*resteerOkFn)(Addr64),
-                     Bool             host_bigendian,
-                     VexArchInfo*     archinfo_guest );
+DisResult disInstr_AMD64 ( IRBB*        irbb,
+                           Bool         put_IP,
+                           Bool         (*resteerOkFn) ( Addr64 ),
+                           UChar*       guest_code,
+                           Long         delta,
+                           Addr64       guest_IP,
+                           VexArchInfo* archinfo,
+                           Bool         host_bigendian );
 
 /* Used by the optimiser to specialise calls to helpers. */
 extern
diff --git a/priv/guest-amd64/ghelpers.c b/priv/guest-amd64/ghelpers.c
index c504fcc..24c5ed0 100644
--- a/priv/guest-amd64/ghelpers.c
+++ b/priv/guest-amd64/ghelpers.c
@@ -40,6 +40,7 @@
 #include "libvex.h"
 
 #include "main/vex_util.h"
+#include "guest-generic/bb_to_IR.h"
 #include "guest-amd64/gdefs.h"
 #include "guest-generic/g_generic_x87.h"
 
diff --git a/priv/guest-amd64/toIR.c b/priv/guest-amd64/toIR.c
index d5a2e10..0a5d7f2 100644
--- a/priv/guest-amd64/toIR.c
+++ b/priv/guest-amd64/toIR.c
@@ -91,6 +91,7 @@
 
 #include "main/vex_util.h"
 #include "main/vex_globals.h"
+#include "guest-generic/bb_to_IR.h"
 #include "guest-amd64/gdefs.h"
 
 
@@ -98,38 +99,30 @@
 /*--- Globals                                              ---*/
 /*------------------------------------------------------------*/
 
-/* ------ CONST for entire BB ------ */
+/* These are set at the start of the translation of an insn, right
+   down in disInstr_AMD64, so that we don't have to pass them around
+   endlessly.  They are all constant during the translation of any
+   given insn. */
 
 /* These are set at the start of the translation of a BB, so
    that we don't have to pass them around endlessly. */
 
 /* We need to know this to do sub-register accesses correctly. */
-/* CONST for entire BB */
 static Bool host_is_bigendian;
 
-/* Pointer to the guest code area. */
-/* CONST for entire BB  */
+/* Pointer to the guest code area (points to start of BB, not to the
+   insn being processed). */
 static UChar* guest_code;
 
 /* The guest address corresponding to guest_code[0]. */
-/* CONST for entire BB  */
-static Addr64 guest_rip_bbstart;
-
-/* The IRBB* into which we're generating code. */
-/* CONST for entire BB  */
-static IRBB* irbb;
-
-
-/* ------ CONST for each instruction ------ */
+static Addr64 guest_RIP_bbstart;
 
 /* The guest address for the instruction currently being
    translated. */
-/* CONST for any specific insn, not for the entire BB */
-static Addr64 guest_rip_curr_instr;
+static Addr64 guest_RIP_curr_instr;
 
-/* Emergency verboseness just for this insn?  DEBUG ONLY */
-static Bool  insn_verbose = False;
-
+/* The IRBB* into which we're generating code. */
+static IRBB* irbb;
 
 /* For ensuring that %rip-relative addressing is done right.  A read
    of %rip generates the address of the next instruction.  It may be
@@ -143,8 +136,8 @@
    After the decode, if _mustcheck is now True, _assumed is
    checked. */
 
-static Addr64 guest_rip_next_assumed;
-static Bool   guest_rip_next_mustcheck;
+static Addr64 guest_RIP_next_assumed;
+static Bool   guest_RIP_next_mustcheck;
 
 
 /*------------------------------------------------------------*/
@@ -288,11 +281,11 @@
 }
 
 #define DIP(format, args...)           \
-   if (insn_verbose || (vex_traceflags & VEX_TRACE_FE))  \
+   if (vex_traceflags & VEX_TRACE_FE)  \
       vex_printf(format, ## args)
 
 #define DIS(buf, format, args...)      \
-   if (insn_verbose || (vex_traceflags & VEX_TRACE_FE))  \
+   if (vex_traceflags & VEX_TRACE_FE)  \
       vex_sprintf(buf, format, ## args)
 
 
@@ -365,232 +358,6 @@
 
 
 /*------------------------------------------------------------*/
-/*--- Disassemble an entire basic block                    ---*/
-/*------------------------------------------------------------*/
-
-/* The results of disassembling an instruction.  There are three
-   possible outcomes.  For Dis_Resteer, the disassembler _must_
-   continue at the specified address.  For Dis_StopHere, the
-   disassembler _must_ terminate the BB.  For Dis_Continue, we may at
-   our option either disassemble the next insn, or terminate the BB;
-   but in the latter case we must set the bb's ->next field to point
-   to the next instruction.  */
-
-typedef
-   enum { 
-      Dis_StopHere, /* this insn terminates the BB; we must stop. */
-      Dis_Continue, /* we can optionally continue into the next insn */
-      Dis_Resteer   /* followed a branch; continue at the spec'd addr */
-   }
-   DisResult;
-
-
-/* forward decls .. */
-//.. static IRExpr* mkU32 ( UInt i );
-//.. static void stmt ( IRStmt* st );
-//.. 
-//.. 
-/* disInstr disassembles an instruction located at &guest_code[delta],
-   and sets *size to its size.  If the returned value is Dis_Resteer,
-   the next guest address is assigned to *whereNext.  disInstr is not
-   permitted to return Dis_Resteer if either (1) resteerOK is False,
-   or (2) resteerOkFn, when applied to the address which it wishes to
-   resteer into, returns False.  */
-   
-static 
-DisResult disInstr ( /*IN*/  Bool         resteerOK,
-                     /*IN*/  Bool         (*resteerOkFn) ( Addr64 ),
-                     /*IN*/  ULong        delta, 
-                     /*IN*/  VexArchInfo* archinfo,
-                     /*OUT*/ Long*        size,
-                     /*OUT*/ Addr64*      whereNext );
-
-
-/* This is the main (only, in fact) entry point for this module. */
-
-/* Disassemble a complete basic block, starting at eip, and dumping
-   the ucode into cb.  Returns the size, in bytes, of the basic
-   block. */
-IRBB* bbToIR_AMD64 ( UChar*           amd64code, 
-                     Addr64           guest_rip_start, 
-                     VexGuestExtents* vge, 
-                     Bool             (*byte_accessible)(Addr64),
-                     Bool             (*chase_into_ok)(Addr64),
-                     Bool             host_bigendian,
-                     VexArchInfo*     archinfo_guest )
-{
-   Long       delta, size;
-   Int        i, n_instrs, first_stmt_idx;
-   Addr64     guest_next;
-   Bool       resteerOK;
-   DisResult  dres;
-   IRStmt*    imark;
-   static Int n_resteers = 0;
-   Int        d_resteers = 0;
-
-   /* check sanity .. */
-   vassert(vex_control.guest_max_insns >= 1);
-   vassert(vex_control.guest_max_insns < 500);
-   vassert(vex_control.guest_chase_thresh >= 0);
-   vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns);
-
-   vassert(archinfo_guest->subarch == VexSubArch_NONE);
-
-   /* Start a new, empty extent. */
-   vge->n_used  = 1;
-   vge->base[0] = guest_rip_start;
-   vge->len[0]  = 0;
-
-   /* Set up globals. */
-   host_is_bigendian = host_bigendian;
-   guest_code        = amd64code;
-   guest_rip_bbstart = guest_rip_start;
-   irbb              = emptyIRBB();
-   insn_verbose      = False;
-
-   /* Delta keeps track of how far along the amd64code array we
-      have so far gone. */
-   delta             = 0;
-   n_instrs          = 0;
-
-   while (True) {
-      vassert(n_instrs < vex_control.guest_max_insns);
-
-      guest_next = 0;
-      resteerOK 
-         = toBool(
-              n_instrs < vex_control.guest_chase_thresh
-              /* we can't afford to have a resteer once we're on the
-                 last extent slot. */
-              && vge->n_used < 3
-           );
-
-      /* This is the %RIP of the instruction we're just about to deal
-         with. */
-      guest_rip_curr_instr = guest_rip_bbstart + delta;
-
-      /* This is the irbb statement array index of the first stmt in
-         this insn.  That will always be the instruction-mark
-         descriptor. */
-      first_stmt_idx = irbb->stmts_used;
-
-      /* Add an instruction-mark statement.  We won't know until after
-         disInstr how long the instruction is, so just put in a zero
-         length and we'll fix it up later. */
-      stmt( IRStmt_IMark( guest_rip_curr_instr, 0 ));
-
-      if (n_instrs > 0) {
-         /* for the first insn, the dispatch loop will have set
-            %RIP, but for all the others we have to do it ourselves. */
-         stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_rip_curr_instr)) );
-      }
-
-      /* Do the instruction.  This may set insn_verbose to True, which
-         needs to be annulled. */
-      size = 0; /* just in case disInstr doesn't set it */
-      guest_rip_next_assumed = 0;
-      guest_rip_next_mustcheck = False;
-      dres = disInstr( resteerOK, chase_into_ok, 
-                       delta, archinfo_guest, &size, &guest_next );
-      insn_verbose = False;
-
-      /* stay sane ... */
-      vassert(size >= 0 && size <= 18);
-
-      /* Fill in the insn-mark length field. */
-      vassert(first_stmt_idx >= 0 && first_stmt_idx < irbb->stmts_used);
-      imark = irbb->stmts[first_stmt_idx];
-      vassert(imark);
-      vassert(imark->tag == Ist_IMark);
-      vassert(imark->Ist.IMark.len == 0);
-      imark->Ist.IMark.len = toUInt(size);
-
-      /* Print the resulting IR, if needed. */
-      if (vex_traceflags & VEX_TRACE_FE) {
-         for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
-            vex_printf("              ");
-            ppIRStmt(irbb->stmts[i]);
-            vex_printf("\n");
-         }
-      }
-
-      /* If disInstr tried to figure out the next rip, check it got it
-	 right.  Failure of this assertion is serious and denotes a
-	 bug in disInstr. */
-      if (guest_rip_next_mustcheck 
-          && guest_rip_next_assumed != guest_rip_curr_instr+size) {
-         vex_printf("\n");
-         vex_printf("assumed next %%rip = 0x%llx\n", 
-                    guest_rip_next_assumed );
-         vex_printf(" actual next %%rip = 0x%llx\n", 
-                    guest_rip_curr_instr+size );
-         vpanic("bbToIR_AMD64: disInstr miscalculated next %rip");
-      }
-
-      if (dres == Dis_StopHere) {
-         vassert(irbb->next != NULL);
-         if (vex_traceflags & VEX_TRACE_FE) {
-            vex_printf("              ");
-            vex_printf( "goto {");
-            ppIRJumpKind(irbb->jumpkind);
-            vex_printf( "} ");
-            ppIRExpr( irbb->next );
-            vex_printf( "\n");
-         }
-      }
-
-      delta += size;
-      /* If vex_control.guest_max_insns is required to be < 500 and
-	 each insn is at max 15 bytes long, this limit of 10000 then
-	 seems reasonable since the max possible extent length will be
-	 500 * 15 == 7500. */
-      vassert(vge->len[vge->n_used-1] < 10000);
-      vge->len[vge->n_used-1] 
-         = toUShort(toUInt( vge->len[vge->n_used-1] + size ));
-      n_instrs++;
-      DIP("\n");
-
-      if (!resteerOK) 
-         vassert(dres != Dis_Resteer);
-      if (dres != Dis_Resteer) 
-         vassert(guest_next == 0);
-
-      switch (dres) {
-         case Dis_Continue:
-            vassert(irbb->next == NULL);
-            if (n_instrs < vex_control.guest_max_insns) {
-               /* keep going */
-            } else {
-               irbb->next = mkU64(guest_rip_start+delta);
-               return irbb;
-            }
-            break;
-         case Dis_StopHere:
-            vassert(irbb->next != NULL);
-            return irbb;
-         case Dis_Resteer:
-            vassert(irbb->next == NULL);
-            /* figure out a new delta to continue at. */
-            vassert(chase_into_ok(guest_next));
-            delta = guest_next - guest_rip_start;
-            /* we now have to start a new extent slot. */
-	    vge->n_used++;
-	    vassert(vge->n_used <= 3);
-            vge->base[vge->n_used-1] = guest_next;
-            vge->len[vge->n_used-1] = 0;
-            n_resteers++;
-            d_resteers++;
-            if (0 && (n_resteers & 0xFF) == 0)
-            vex_printf("resteer[%d,%d] to 0x%llx (delta = %lld)\n",
-                       n_resteers, d_resteers,
-                       guest_next, delta);
-            break;
-      }
-   }
-}
-
-
-/*------------------------------------------------------------*/
 /*--- Helper bits and pieces for deconstructing the        ---*/
 /*--- amd64 insn stream.                                   ---*/
 /*------------------------------------------------------------*/
@@ -2278,7 +2045,7 @@
       case 0x1C: case 0x1D: case 0x1E: case 0x1F:
          vpanic("disAMode(amd64): not an addr!");
 
-      /* RIP + disp32.  This assumes that guest_rip_curr_instr is set
+      /* RIP + disp32.  This assumes that guest_RIP_curr_instr is set
          correctly at the start of handling each instruction. */
       case 0x05: 
          { Long d = getSDisp32(delta);
@@ -2289,12 +2056,12 @@
               the top-level driver logic (bbToIR_AMD64) to check we
               guessed right, after the instruction is completely
               decoded. */
-           guest_rip_next_mustcheck = True;
-           guest_rip_next_assumed = guest_rip_bbstart 
+           guest_RIP_next_mustcheck = True;
+           guest_RIP_next_assumed = guest_RIP_bbstart 
                                     + delta+4 + extra_bytes;
            return disAMode_copy2tmp( 
                      handleSegOverride(pfx, 
-                        binop(Iop_Add64, mkU64(guest_rip_next_assumed), 
+                        binop(Iop_Add64, mkU64(guest_RIP_next_assumed), 
                                          mkU64(d))));
          }
 
@@ -3724,7 +3491,7 @@
 
 /* Group 5 extended opcodes. */
 static
-ULong dis_Grp5 ( Prefix pfx, Int sz, ULong delta, DisResult* whatNext )
+ULong dis_Grp5 ( Prefix pfx, Int sz, ULong delta, DisResult* dres )
 {
    Int     len;
    UChar   modrm;
@@ -3763,10 +3530,10 @@
             t2 = newTemp(Ity_I64);
             assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
             putIReg64(R_RSP, mkexpr(t2));
-            storeLE( mkexpr(t2), mkU64(guest_rip_bbstart+delta+1));
+            storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+1));
             make_redzone_AbiHint(t2, "call-Ev(reg)");
             jmp_treg(Ijk_Call,t3);
-            *whatNext = Dis_StopHere;
+            dres->whatNext = Dis_StopHere;
             showSz = False;
             break;
          case 4: /* jmp Ev */
@@ -3776,7 +3543,7 @@
             t3 = newTemp(Ity_I64);
             assign(t3, getIRegE(sz,pfx,modrm));
             jmp_treg(Ijk_Boring,t3);
-            *whatNext = Dis_StopHere;
+            dres->whatNext = Dis_StopHere;
             showSz = False;
             break;
          default: 
@@ -3818,10 +3585,10 @@
             t2 = newTemp(Ity_I64);
             assign(t2, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
             putIReg64(R_RSP, mkexpr(t2));
-            storeLE( mkexpr(t2), mkU64(guest_rip_bbstart+delta+len));
+            storeLE( mkexpr(t2), mkU64(guest_RIP_bbstart+delta+len));
             make_redzone_AbiHint(t2, "call-Ev(mem)");
             jmp_treg(Ijk_Call,t3);
-            *whatNext = Dis_StopHere;
+            dres->whatNext = Dis_StopHere;
             showSz = False;
             break;
          case 4: /* JMP Ev */
@@ -3831,7 +3598,7 @@
             t3 = newTemp(Ity_I64);
             assign(t3, loadLE(Ity_I64,mkexpr(addr)));
             jmp_treg(Ijk_Boring,t3);
-            *whatNext = Dis_StopHere;
+            dres->whatNext = Dis_StopHere;
             showSz = False;
             break;
          case 6: /* PUSH Ev */
@@ -4645,7 +4412,7 @@
                   IRStmt_Exit(
                      binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
                      Ijk_EmWarn,
-                     IRConst_U64( guest_rip_bbstart+delta )
+                     IRConst_U64( guest_RIP_bbstart+delta )
                   )
                );
 
@@ -4687,7 +4454,7 @@
                   IRStmt_Exit(
                      binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
                      Ijk_EmWarn,
-                     IRConst_U64( guest_rip_bbstart+delta )
+                     IRConst_U64( guest_RIP_bbstart+delta )
                   )
                );
                break;
@@ -7919,20 +7686,16 @@
 /*--- Disassemble a single instruction                     ---*/
 /*------------------------------------------------------------*/
 
-/* Disassemble a single instruction into IR.  The instruction
-   is located in host memory at &guest_code[delta].
-   Set *size to be the size of the instruction.
-   If the returned value is Dis_Resteer,
-   the next guest address is assigned to *whereNext.  If resteerOK
-   is False, disInstr may not return Dis_Resteer. */
+/* Disassemble a single instruction into IR.  The instruction is
+   located in host memory at &guest_code[delta]. */
    
-static 
-DisResult disInstr ( /*IN*/  Bool         resteerOK,
-                     /*IN*/  Bool         (*resteerOkFn) ( Addr64 ),
-                     /*IN*/  ULong        delta, 
-                     /*IN*/  VexArchInfo* archinfo,
-                     /*OUT*/ Long*        size,
-                     /*OUT*/ Addr64*      whereNext )
+static
+DisResult disInstr_AMD64_WRK ( 
+             Bool         put_IP,
+             Bool         (*resteerOkFn) ( Addr64 ),
+             Long         delta64,
+             VexArchInfo* archinfo 
+          )
 {
    IRType    ty;
    IRTemp    addr, t0, t1, t2, t3, t4, t5, t6;
@@ -7941,9 +7704,12 @@
    Long      d64;
    HChar     dis_buf[50];
    Int       am_sz, d_sz, n, n_prefixes;
-   DisResult whatNext = Dis_Continue;
+   DisResult dres;
    UChar*    insn; /* used in SSE decoders */
 
+   /* The running delta */
+   Long delta = delta64;
+
    /* Holds eip at the start of the insn, so that we can print
       consistent error messages for unimplemented insns. */
    ULong delta_start = delta;
@@ -7956,16 +7722,21 @@
    /* pfx holds the summary of prefixes. */
    Prefix pfx = PFX_EMPTY;
 
-   /* If we don't set *size properly, this causes bbToIR_AMD64Instr to
-      assert. */
-   *size = 0;
+   /* Set result defaults. */
+   dres.whatNext   = Dis_Continue;
+   dres.len        = 0;
+   dres.continueAt = 0;
 
-   vassert(guest_rip_next_assumed == 0);
-   vassert(guest_rip_next_mustcheck == False);
+   vassert(guest_RIP_next_assumed == 0);
+   vassert(guest_RIP_next_mustcheck == False);
 
    addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID; 
 
-   DIP("\t0x%llx:  ", guest_rip_bbstart+delta);
+   DIP("\t0x%llx:  ", guest_RIP_bbstart+delta);
+
+   /* We may be asked to update the guest RIP before going further. */
+   if (put_IP)
+      stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr)) );
 
    /* Spot the client-request magic sequence. */
    {
@@ -7987,8 +7758,8 @@
          ) {
          DIP("%%edx = client_request ( %%eax )\n");         
          delta += 18;
-         jmp_lit(Ijk_ClientReq, guest_rip_bbstart+delta);
-         whatNext = Dis_StopHere;
+         jmp_lit(Ijk_ClientReq, guest_RIP_bbstart+delta);
+         dres.whatNext = Dis_StopHere;
          goto decode_success;
       }
    }
@@ -8512,7 +8283,7 @@
          IRStmt_Exit(
             binop(Iop_CmpNE64, unop(Iop_32Uto64,mkexpr(ew)), mkU64(0)),
             Ijk_EmWarn,
-            IRConst_U64(guest_rip_bbstart+delta)
+            IRConst_U64(guest_RIP_bbstart+delta)
          )
       );
       goto decode_success;
@@ -11473,27 +11244,27 @@
       if (haveF2(pfx)) goto decode_failure;
       /* F3 is acceptable on AMD. */
       dis_ret(0);
-      whatNext = Dis_StopHere;
+      dres.whatNext = Dis_StopHere;
       DIP(haveF3(pfx) ? "rep ; ret\n" : "ret\n");
       break;
       
    case 0xE8: /* CALL J4 */
       if (haveF2orF3(pfx)) goto decode_failure;
       d64 = getSDisp32(delta); delta += 4;
-      d64 += (guest_rip_bbstart+delta); 
-      /* (guest_rip_bbstart+delta) == return-to addr, d64 == call-to addr */
+      d64 += (guest_RIP_bbstart+delta); 
+      /* (guest_RIP_bbstart+delta) == return-to addr, d64 == call-to addr */
       t1 = newTemp(Ity_I64); 
       assign(t1, binop(Iop_Sub64, getIReg64(R_RSP), mkU64(8)));
       putIReg64(R_RSP, mkexpr(t1));
-      storeLE( mkexpr(t1), mkU64(guest_rip_bbstart+delta));
+      storeLE( mkexpr(t1), mkU64(guest_RIP_bbstart+delta));
       make_redzone_AbiHint(t1, "call-d32");
-      if (resteerOK && resteerOkFn((Addr64)d64)) {
+      if (resteerOkFn((Addr64)d64)) {
          /* follow into the call target. */
-         whatNext = Dis_Resteer;
-         *whereNext = d64;
+         dres.whatNext   = Dis_Resteer;
+         dres.continueAt = d64;
       } else {
          jmp_lit(Ijk_Call,d64);
-         whatNext = Dis_StopHere;
+         dres.whatNext = Dis_StopHere;
       }
       DIP("call 0x%llx\n",d64);
       break;
@@ -11676,14 +11447,14 @@
       if (haveF2orF3(pfx)) goto decode_failure;
       if (sz != 4) 
          goto decode_failure; /* JRS added 2004 July 11 */
-      d64 = (guest_rip_bbstart+delta+1) + getSDisp8(delta); 
+      d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta); 
       delta++;
-      if (resteerOK && resteerOkFn(d64)) {
-         whatNext   = Dis_Resteer;
-         *whereNext = d64;
+      if (resteerOkFn(d64)) {
+         dres.whatNext   = Dis_Resteer;
+         dres.continueAt = d64;
       } else {
          jmp_lit(Ijk_Boring,d64);
-         whatNext = Dis_StopHere;
+         dres.whatNext = Dis_StopHere;
       }
       DIP("jmp-8 0x%llx\n", d64);
       break;
@@ -11692,14 +11463,14 @@
       if (haveF2orF3(pfx)) goto decode_failure;
       if (sz != 4) 
          goto decode_failure; /* JRS added 2004 July 11 */
-      d64 = (guest_rip_bbstart+delta+sz) + getSDisp(sz,delta); 
+      d64 = (guest_RIP_bbstart+delta+sz) + getSDisp(sz,delta); 
       delta += sz;
-      if (resteerOK && resteerOkFn(d64)) {
-         whatNext   = Dis_Resteer;
-         *whereNext = d64;
+      if (resteerOkFn(d64)) {
+         dres.whatNext   = Dis_Resteer;
+         dres.continueAt = d64;
       } else {
          jmp_lit(Ijk_Boring,d64);
-         whatNext = Dis_StopHere;
+         dres.whatNext = Dis_StopHere;
       }
       DIP("jmp 0x%llx\n", d64);
       break;
@@ -11721,12 +11492,12 @@
    case 0x7E: /* JLEb/JNGb (jump less or equal) */
    case 0x7F: /* JGb/JNLEb (jump greater) */
       if (haveF2orF3(pfx)) goto decode_failure;
-      d64 = (guest_rip_bbstart+delta+1) + getSDisp8(delta); 
+      d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta); 
       delta++;
       jcc_01( (AMD64Condcode)(opc - 0x70), 
-              guest_rip_bbstart+delta,
+              guest_RIP_bbstart+delta,
               d64 );
-      whatNext = Dis_StopHere;
+      dres.whatNext = Dis_StopHere;
       DIP("j%s-8 0x%llx\n", name_AMD64Condcode(opc - 0x70), d64);
       break;
 
@@ -12587,9 +12358,9 @@
          if (opc == 0xAE)
             sz = 1;
          dis_REP_op ( AMD64CondNZ, dis_SCAS, sz, 
-                      guest_rip_curr_instr,
-                      guest_rip_bbstart+delta, "repne scas", pfx );
-         whatNext = Dis_StopHere;
+                      guest_RIP_curr_instr,
+                      guest_RIP_bbstart+delta, "repne scas", pfx );
+         dres.whatNext = Dis_StopHere;
          break;
       }
       /* AE/AF: scasb/scas{w,l,q} */
@@ -12609,9 +12380,9 @@
          if (opc == 0xA6)
             sz = 1;
          dis_REP_op ( AMD64CondZ, dis_CMPS, sz, 
-                      guest_rip_curr_instr,
-                      guest_rip_bbstart+delta, "repe cmps", pfx );
-         whatNext = Dis_StopHere;
+                      guest_RIP_curr_instr,
+                      guest_RIP_bbstart+delta, "repe cmps", pfx );
+         dres.whatNext = Dis_StopHere;
          break;
       }
       goto decode_failure;
@@ -12624,9 +12395,9 @@
          if (opc == 0xAA)
             sz = 1;
          dis_REP_op ( AMD64CondAlways, dis_STOS, sz,
-                      guest_rip_curr_instr,
-                      guest_rip_bbstart+delta, "rep stos", pfx );
-        whatNext = Dis_StopHere;
+                      guest_RIP_curr_instr,
+                      guest_RIP_bbstart+delta, "rep stos", pfx );
+        dres.whatNext = Dis_StopHere;
         break;
       }
       /* AA/AB: stosb/stos{w,l,q} */
@@ -12646,9 +12417,9 @@
          if (opc == 0xA4)
             sz = 1;
          dis_REP_op ( AMD64CondAlways, dis_MOVS, sz,
-                      guest_rip_curr_instr,
-                      guest_rip_bbstart+delta, "rep movs", pfx );
-        whatNext = Dis_StopHere;
+                      guest_RIP_curr_instr,
+                      guest_RIP_bbstart+delta, "rep movs", pfx );
+        dres.whatNext = Dis_StopHere;
         break;
       }
       /* A4: movsb */
@@ -12982,7 +12753,7 @@
 
    case 0xFF: /* Grp5 Ev */
       if (haveF2orF3(pfx)) goto decode_failure;
-      delta = dis_Grp5 ( pfx, sz, delta, &whatNext );
+      delta = dis_Grp5 ( pfx, sz, delta, &dres );
       break;
 
    /* ------------------------ Escapes to 2-byte opcodes -- */
@@ -13218,12 +12989,12 @@
       case 0x8E: /* JLEb/JNGb (jump less or equal) */
       case 0x8F: /* JGb/JNLEb (jump greater) */
          if (haveF2orF3(pfx)) goto decode_failure;
-         d64 = (guest_rip_bbstart+delta+4) + getSDisp32(delta); 
+         d64 = (guest_RIP_bbstart+delta+4) + getSDisp32(delta); 
          delta += 4;
          jcc_01( (AMD64Condcode)(opc - 0x80), 
-                 guest_rip_bbstart+delta, 
+                 guest_RIP_bbstart+delta, 
                  d64 );
-         whatNext = Dis_StopHere;
+         dres.whatNext = Dis_StopHere;
          DIP("j%s-32 0x%llx\n", name_AMD64Condcode(opc - 0x80), d64);
          break;
 
@@ -13342,14 +13113,14 @@
 
       /* =-=-=-=-=-=-=-=-=- SYSCALL -=-=-=-=-=-=-=-=-=-= */
       case 0x05: /* SYSCALL */
-         guest_rip_next_mustcheck = True;
-         guest_rip_next_assumed = guest_rip_bbstart + delta;
-         putIReg64( R_RCX, mkU64(guest_rip_next_assumed) );
+         guest_RIP_next_mustcheck = True;
+         guest_RIP_next_assumed = guest_RIP_bbstart + delta;
+         putIReg64( R_RCX, mkU64(guest_RIP_next_assumed) );
          /* It's important that all guest state is up-to-date
             at this point.  So we declare an end-of-block here, which
             forces any cached guest state to be flushed. */
-        jmp_lit(Ijk_Syscall, guest_rip_next_assumed);
-        whatNext = Dis_StopHere;
+        jmp_lit(Ijk_Syscall, guest_RIP_next_assumed);
+        dres.whatNext = Dis_StopHere;
         DIP("syscall\n");
         break;
 
@@ -13488,24 +13259,75 @@
       RIP should be up-to-date since it made so at the start of each
       insn, but nevertheless be paranoid and update it again right
       now. */
-   stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_rip_curr_instr) ) );
-   jmp_lit(Ijk_NoDecode, guest_rip_curr_instr);
-   whatNext = Dis_StopHere;
-   *size = 0;
-   return whatNext;
+   stmt( IRStmt_Put( OFFB_RIP, mkU64(guest_RIP_curr_instr) ) );
+   jmp_lit(Ijk_NoDecode, guest_RIP_curr_instr);
+   dres.whatNext = Dis_StopHere;
+   dres.len      = 0;
+   return dres;
 
    } /* switch (opc) for the main (primary) opcode switch. */
 
   decode_success:
    /* All decode successes end up here. */
    DIP("\n");
-   *size = delta - delta_start;
-   return whatNext;
+   dres.len = (Int)toUInt(delta - delta_start);
+   return dres;
 }
 
 #undef DIP
 #undef DIS
 
+
+/*------------------------------------------------------------*/
+/*--- Top-level fn                                         ---*/
+/*------------------------------------------------------------*/
+
+/* Disassemble a single instruction into IR.  The instruction
+   is located in host memory at &guest_code[delta]. */
+
+DisResult disInstr_AMD64 ( IRBB*        irbb_IN,
+                           Bool         put_IP,
+                           Bool         (*resteerOkFn) ( Addr64 ),
+                           UChar*       guest_code_IN,
+                           Long         delta,
+                           Addr64       guest_IP,
+                           VexArchInfo* archinfo,
+                           Bool         host_bigendian_IN )
+{
+   DisResult dres;
+
+   /* Set globals (see top of this file) */
+   guest_code           = guest_code_IN;
+   irbb                 = irbb_IN;
+   host_is_bigendian    = host_bigendian_IN;
+   guest_RIP_curr_instr = guest_IP;
+   guest_RIP_bbstart    = guest_IP - delta;
+
+   /* We'll consult these after doing disInstr_AMD64_WRK. */
+   guest_RIP_next_assumed   = 0;
+   guest_RIP_next_mustcheck = False;
+
+   dres = disInstr_AMD64_WRK ( put_IP, resteerOkFn,
+                               delta, archinfo );
+
+   /* If disInstr_AMD64_WRK tried to figure out the next rip, check it
+      got it right.  Failure of this assertion is serious and denotes
+      a bug in disInstr. */
+   if (guest_RIP_next_mustcheck 
+       && guest_RIP_next_assumed != guest_RIP_curr_instr + dres.len) {
+      vex_printf("\n");
+      vex_printf("assumed next %%rip = 0x%llx\n", 
+                 guest_RIP_next_assumed );
+      vex_printf(" actual next %%rip = 0x%llx\n", 
+                 guest_RIP_curr_instr + dres.len );
+      vpanic("bbToIR_AMD64: disInstr miscalculated next %rip");
+   }
+
+   return dres;
+}
+
+
+
 /*--------------------------------------------------------------------*/
 /*--- end                                       guest-amd64/toIR.c ---*/
 /*--------------------------------------------------------------------*/
diff --git a/priv/guest-generic/bb_to_IR.c b/priv/guest-generic/bb_to_IR.c
new file mode 100644
index 0000000..d8dfae0
--- /dev/null
+++ b/priv/guest-generic/bb_to_IR.c
@@ -0,0 +1,247 @@
+
+/*--------------------------------------------------------------------*/
+/*---                                                              ---*/
+/*--- This file (guest-generic/bb_to_IR.c) is                      ---*/
+/*--- Copyright (c) OpenWorks LLP.  All rights reserved.           ---*/
+/*---                                                              ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of LibVEX, a library for dynamic binary
+   instrumentation and translation.
+
+   Copyright (C) 2004-2005 OpenWorks LLP.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; Version 2 dated June 1991 of the
+   license.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability
+   for damages.  See the GNU General Public License for more details.
+
+   Neither the names of the U.S. Department of Energy nor the
+   University of California nor the names of its contributors may be
+   used to endorse or promote products derived from this software
+   without prior written permission.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+   USA.
+*/
+
+#include "libvex_basictypes.h"
+#include "libvex_ir.h"
+#include "libvex.h"
+#include "main/vex_util.h"
+#include "main/vex_globals.h"
+#include "guest-generic/bb_to_IR.h"
+
+
+/* Disassemble a complete basic block, starting at guest_IP_start, 
+   returning a new IRBB.  The disassembler may chase across basic
+   block boundaries if it wishes and if chase_into_ok allows it.
+   The precise guest address ranges from which code has been taken
+   are written into vge.  guest_IP_start is taken to be the IP in
+   the guest's address space corresponding to the instruction at
+   &guest_code[0].  
+
+   dis_instr_fn is the arch-specific fn to disassemble on function; it
+   is this that does the real work.
+*/
+
+static Bool const_False ( Addr64 a ) { return False; }
+
+IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
+                 /*IN*/ DisOneInstrFn    dis_instr_fn,
+                 /*IN*/ UChar*           guest_code,
+                 /*IN*/ Addr64           guest_IP_bbstart,
+                 /*IN*/ Bool             (*chase_into_ok)(Addr64),
+                 /*IN*/ Bool             host_bigendian,
+                 /*IN*/ VexArchInfo*     archinfo_guest,
+                 /*IN*/ IRType           guest_word_type )
+{
+   Long       delta;
+   Int        i, n_instrs, first_stmt_idx;
+   Bool       resteerOK, need_to_put_IP, debug_print;
+   DisResult  dres;
+   IRStmt*    imark;
+   static Int n_resteers = 0;
+   Int        d_resteers = 0;
+   IRBB*      irbb;
+   Addr64     guest_IP_curr_instr;
+
+   Bool (*resteerOKfn)(Addr64) = NULL;
+
+   debug_print = toBool(vex_traceflags & VEX_TRACE_FE);
+
+   /* check sanity .. */
+   vassert(vex_control.guest_max_insns >= 1);
+   vassert(vex_control.guest_max_insns < 500);
+   vassert(vex_control.guest_chase_thresh >= 0);
+   vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns);
+   vassert(guest_word_type == Ity_I32 || guest_word_type == Ity_I64);
+
+   /* Start a new, empty extent. */
+   vge->n_used  = 1;
+   vge->base[0] = guest_IP_bbstart;
+   vge->len[0]  = 0;
+
+   /* And a new IR BB to dump the result into. */
+   irbb = emptyIRBB();
+
+   /* Delta keeps track of how far along the guest_code array we have
+      so far gone. */
+   delta    = 0;
+   n_instrs = 0;
+
+   while (True) {
+      vassert(n_instrs < vex_control.guest_max_insns);
+
+      /* Regardless of what chase_into_ok says, is chasing permissible
+         at all right now?  Set resteerOKfn accordingly. */
+      resteerOK 
+         = toBool(
+              n_instrs < vex_control.guest_chase_thresh
+              /* we can't afford to have a resteer once we're on the
+                 last extent slot. */
+              && vge->n_used < 3
+           );
+
+      resteerOKfn
+         = resteerOK ? chase_into_ok : const_False;
+
+      /* This is the IP of the instruction we're just about to deal
+         with. */
+      guest_IP_curr_instr = guest_IP_bbstart + delta;
+
+      /* This is the irbb statement array index of the first stmt in
+         this insn.  That will always be the instruction-mark
+         descriptor. */
+      first_stmt_idx = irbb->stmts_used;
+
+      /* Add an instruction-mark statement.  We won't know until after
+         disassembling the instruction how long it instruction is, so
+         just put in a zero length and we'll fix it up later. */
+      addStmtToIRBB( irbb, IRStmt_IMark( guest_IP_curr_instr, 0 ));
+
+      /* for the first insn, the dispatch loop will have set
+         %IP, but for all the others we have to do it ourselves. */
+      need_to_put_IP = toBool(n_instrs > 0);
+
+      /* Finally, actually disassemble an instruction. */
+      dres = dis_instr_fn ( irbb,
+                            need_to_put_IP,
+                            resteerOKfn,
+                            guest_code,
+                            delta,
+                            guest_IP_curr_instr,
+                            archinfo_guest,
+                            host_bigendian );
+
+      /* stay sane ... */
+      vassert(dres.whatNext == Dis_StopHere
+              || dres.whatNext == Dis_Continue
+              || dres.whatNext == Dis_Resteer);
+      vassert(dres.len >= 0 && dres.len <= 18);
+      if (dres.whatNext != Dis_Resteer)
+         vassert(dres.continueAt == 0);
+
+      /* Fill in the insn-mark length field. */
+      vassert(first_stmt_idx >= 0 && first_stmt_idx < irbb->stmts_used);
+      imark = irbb->stmts[first_stmt_idx];
+      vassert(imark);
+      vassert(imark->tag == Ist_IMark);
+      vassert(imark->Ist.IMark.len == 0);
+      imark->Ist.IMark.len = toUInt(dres.len);
+
+      /* Print the resulting IR, if needed. */
+      if (vex_traceflags & VEX_TRACE_FE) {
+         for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
+            vex_printf("              ");
+            ppIRStmt(irbb->stmts[i]);
+            vex_printf("\n");
+         }
+      }
+
+      /* If dis_instr_fn terminated the BB at this point, check it
+	 also filled in the irbb->next field. */
+      if (dres.whatNext == Dis_StopHere) {
+         vassert(irbb->next != NULL);
+         if (debug_print) {
+            vex_printf("              ");
+            vex_printf( "goto {");
+            ppIRJumpKind(irbb->jumpkind);
+            vex_printf( "} ");
+            ppIRExpr( irbb->next );
+            vex_printf( "\n");
+         }
+      }
+
+      /* Update the VexGuestExtents we are constructing. */
+      /* If vex_control.guest_max_insns is required to be < 500 and
+	 each insn is at max 15 bytes long, this limit of 10000 then
+	 seems reasonable since the max possible extent length will be
+	 500 * 15 == 7500. */
+      vassert(vge->len[vge->n_used-1] < 10000);
+      vge->len[vge->n_used-1] 
+         = toUShort(toUInt( vge->len[vge->n_used-1] + dres.len ));
+      n_instrs++;
+      if (debug_print) 
+         vex_printf("\n");
+
+      /* Advance delta (inconspicuous but very important :-) */
+      delta += (Long)dres.len;
+
+      switch (dres.whatNext) {
+         case Dis_Continue:
+            vassert(irbb->next == NULL);
+            if (n_instrs < vex_control.guest_max_insns) {
+               /* keep going */
+            } else {
+               /* We have to stop. */
+               irbb->next 
+                  = IRExpr_Const(
+                       guest_word_type == Ity_I32
+                          ? IRConst_U32(toUInt(guest_IP_bbstart+delta))
+                          : IRConst_U64(guest_IP_bbstart+delta)
+                    );
+               return irbb;
+            }
+            break;
+         case Dis_StopHere:
+            vassert(irbb->next != NULL);
+            return irbb;
+         case Dis_Resteer:
+            /* Check that we actually allowed a resteer .. */
+            vassert(resteerOK);
+            vassert(irbb->next == NULL);
+            /* figure out a new delta to continue at. */
+            vassert(resteerOKfn(dres.continueAt));
+            delta = dres.continueAt - guest_IP_bbstart;
+            /* we now have to start a new extent slot. */
+	    vge->n_used++;
+	    vassert(vge->n_used <= 3);
+            vge->base[vge->n_used-1] = dres.continueAt;
+            vge->len[vge->n_used-1] = 0;
+            n_resteers++;
+            d_resteers++;
+            if (0 && (n_resteers & 0xFF) == 0)
+            vex_printf("resteer[%d,%d] to 0x%llx (delta = %lld)\n",
+                       n_resteers, d_resteers,
+                       dres.continueAt, delta);
+            break;
+         default:
+            vpanic("bb_to_IR");
+      }
+   }
+}
+
+
+
+/*--------------------------------------------------------------------*/
+/*--- end                                 guest-generic/bb_to_IR.c ---*/
+/*--------------------------------------------------------------------*/
diff --git a/priv/guest-generic/bb_to_IR.h b/priv/guest-generic/bb_to_IR.h
new file mode 100644
index 0000000..3d26938
--- /dev/null
+++ b/priv/guest-generic/bb_to_IR.h
@@ -0,0 +1,156 @@
+
+/*--------------------------------------------------------------------*/
+/*---                                                              ---*/
+/*--- This file (guest-generic/bb_to_IR.h) is                      ---*/
+/*--- Copyright (c) OpenWorks LLP.  All rights reserved.           ---*/
+/*---                                                              ---*/
+/*--------------------------------------------------------------------*/
+
+/*
+   This file is part of LibVEX, a library for dynamic binary
+   instrumentation and translation.
+
+   Copyright (C) 2004-2005 OpenWorks LLP.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; Version 2 dated June 1991 of the
+   license.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or liability
+   for damages.  See the GNU General Public License for more details.
+
+   Neither the names of the U.S. Department of Energy nor the
+   University of California nor the names of its contributors may be
+   used to endorse or promote products derived from this software
+   without prior written permission.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+   USA.
+*/
+
+#ifndef __LIBVEX_GENERIC_BB_TO_IR_H
+#define __LIBVEX_GENERIC_BB_TO_IR_H
+
+
+/* This defines stuff needed by the guest insn disassemblers.
+   It's a bit circular; is imported by
+   - the guest-specific toIR.c files (guest-{x86,amd64,ppc32,arm}/toIR.c)
+   - the generic disassembly driver (bb_to_IR.c)
+   - vex_main.c
+*/
+
+
+/* ---------------------------------------------------------------
+   Result of disassembling an instruction
+   --------------------------------------------------------------- */
+
+/* The results of disassembling an instruction.  There are three
+   possible outcomes.  For Dis_Resteer, the disassembler _must_
+   continue at the specified address.  For Dis_StopHere, the
+   disassembler _must_ terminate the BB.  For Dis_Continue, we may at
+   our option either disassemble the next insn, or terminate the BB;
+   but in the latter case we must set the bb's ->next field to point
+   to the next instruction.  */
+
+typedef
+
+   struct {
+
+      /* The disassembled insn has this length.  Must always be
+         set. */
+      Int len;
+
+      /* What happens next?
+         Dis_StopHere:  this insn terminates the BB; we must stop.
+         Dis_Continue:  we can optionally continue into the next insn
+         Dis_Resteer:   followed a branch; continue at the spec'd addr
+      */
+      enum { Dis_StopHere, Dis_Continue, Dis_Resteer } whatNext;
+
+      /* For Dis_Resteer, this is the guest address we should continue
+         at.  Otherwise ignored (should be zero). */
+      Addr64 continueAt;
+
+   }
+
+   DisResult;
+
+
+/* ---------------------------------------------------------------
+   The type of a function which disassembles one instruction.
+   C's function-type syntax is really astonishing bizarre.
+   --------------------------------------------------------------- */
+
+/* A function of this type (DisOneInstrFn) disassembles an instruction
+   located at host address &guest_code[delta], whose guest IP is
+   guest_IP (this may be entirely unrelated to where the insn is
+   actually located in the host's address space.).  The returned
+   DisResult.len field carries its size.  If the returned
+   DisResult.whatNext field is Dis_Resteer then DisResult.continueAt
+   should hold the guest IP of the next insn to disassemble.
+
+   disInstr is not permitted to return Dis_Resteer if resteerOkFn,
+   when applied to the address which it wishes to resteer into,
+   returns False.  
+
+   The resulting IR is added to the end of irbb.
+*/
+
+typedef
+
+   DisResult (*DisOneInstrFn) ( 
+
+      /* This is the IRBB to which the resulting IR is to be appended. */
+      /*OUT*/ IRBB*        irbb,
+
+      /* Do we need to generate IR to set the guest IP for this insn,
+         or not? */
+      /*IN*/  Bool         put_IP,
+
+      /* Return True iff resteering to the given addr is allowed */
+      /*IN*/  Bool         (*resteerOkFn) ( Addr64 ),
+
+      /* Where is the guest code? */
+      /*IN*/  UChar*       guest_code,
+
+      /* Where is the actual insn?  Note: it's at &guest_code[delta] */
+      /*IN*/  Long         delta,
+
+      /* What is the guest IP of the insn? */
+      /*IN*/  Addr64       guest_IP,
+
+      /* Info about the guest architecture */
+      /*IN*/  VexArchInfo* archinfo,
+
+      /* Is the host bigendian? */
+      /*IN*/  Bool         host_bigendian
+
+   );
+
+
+/* ---------------------------------------------------------------
+   Top-level BB to IR conversion fn.
+   --------------------------------------------------------------- */
+
+/* See detailed comment in bb_to_IR.c. */
+extern
+IRBB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
+                 /*IN*/ DisOneInstrFn    dis_instr_fn,
+                 /*IN*/ UChar*           guest_code,
+                 /*IN*/ Addr64           guest_IP_bbstart,
+                 /*IN*/ Bool             (*chase_into_ok)(Addr64),
+                 /*IN*/ Bool             host_bigendian,
+                 /*IN*/ VexArchInfo*     archinfo_guest,
+                 /*IN*/ IRType           guest_word_type );
+
+
+#endif /* ndef GENERIC_BB_TO_IR_H */
+
+/*--------------------------------------------------------------------*/
+/*--- end                                 guest-generic/bb_to_IR.h ---*/
+/*--------------------------------------------------------------------*/
diff --git a/priv/guest-ppc32/gdefs.h b/priv/guest-ppc32/gdefs.h
index 4a8161f..7fc3e75 100644
--- a/priv/guest-ppc32/gdefs.h
+++ b/priv/guest-ppc32/gdefs.h
@@ -39,6 +39,38 @@
 #ifndef __LIBVEX_GUEST_PPC32_DEFS_H
 #define __LIBVEX_GUEST_PPC32_DEFS_H
 
+
+/*---------------------------------------------------------*/
+/*--- ppc32 to IR conversion                            ---*/
+/*---------------------------------------------------------*/
+
+/* Convert one ppc32 insn to IR.  See the type DisOneInstrFn in
+   bb_to_IR.h. */
+extern
+DisResult disInstr_PPC32 ( IRBB*        irbb,
+                           Bool         put_IP,
+                           Bool         (*resteerOkFn) ( Addr64 ),
+                           UChar*       guest_code,
+                           Long         delta,
+                           Addr64       guest_IP,
+                           VexArchInfo* archinfo,
+                           Bool         host_bigendian );
+
+/* Used by the optimiser to specialise calls to helpers. */
+extern
+IRExpr* guest_ppc32_spechelper ( HChar* function_name,
+                                 IRExpr** args );
+
+/* 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_ppc32_state_requires_precise_mem_exns ( Int, Int );
+
+extern
+VexGuestLayout ppc32Guest_layout;
+
+
 /* FP Rounding mode - different encoding to IR */
 typedef
    enum {
@@ -58,33 +90,6 @@
    }
    PPC32CmpF64Result;
 
-/*---------------------------------------------------------*/
-/*--- ppc32 to IR conversion                            ---*/
-/*---------------------------------------------------------*/
-
-extern
-IRBB* bbToIR_PPC32 ( UChar*           ppc32code, 
-                     Addr64           eip, 
-                     VexGuestExtents* vge,
-                     Bool             (*byte_accessible)(Addr64),
-                     Bool             (*resteerOkFn)(Addr64),
-                     Bool             host_bigendian,
-                     VexArchInfo*     archinfo_guest );
-
-/* Used by the optimiser to specialise calls to helpers. */
-extern
-IRExpr* guest_ppc32_spechelper ( HChar* function_name,
-                                 IRExpr** args );
-
-/* 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_ppc32_state_requires_precise_mem_exns ( Int, Int );
-
-extern
-VexGuestLayout ppc32Guest_layout;
-
 
 /*---------------------------------------------------------*/
 /*--- ppc32 guest helpers                                 ---*/
diff --git a/priv/guest-ppc32/ghelpers.c b/priv/guest-ppc32/ghelpers.c
index fb38a2e..70480ee 100644
--- a/priv/guest-ppc32/ghelpers.c
+++ b/priv/guest-ppc32/ghelpers.c
@@ -40,6 +40,7 @@
 #include "libvex.h"
 
 #include "main/vex_util.h"
+#include "guest-generic/bb_to_IR.h"
 #include "guest-ppc32/gdefs.h"
 
 
diff --git a/priv/guest-ppc32/toIR.c b/priv/guest-ppc32/toIR.c
index 92e8a68..5ea9644 100644
--- a/priv/guest-ppc32/toIR.c
+++ b/priv/guest-ppc32/toIR.c
@@ -64,6 +64,7 @@
 
 #include "main/vex_util.h"
 #include "main/vex_globals.h"
+#include "guest-generic/bb_to_IR.h"
 #include "guest-ppc32/gdefs.h"
 
 
@@ -71,27 +72,23 @@
 /*--- Globals                                              ---*/
 /*------------------------------------------------------------*/
 
-/* These are set at the start of the translation of a BB, so that we
-   don't have to pass them around endlessly.  CONST means does not
-   change during translation of a bb. 
-*/
+/* These are set at the start of the translation of an insn, right
+   down in disInstr_PPC32, so that we don't have to pass them around
+   endlessly.  They are all constant during the translation of any
+   given insn. */
 
 /* We need to know this to do sub-register accesses correctly. */
-/* CONST */
 static Bool host_is_bigendian;
 
 /* Pointer to the guest code area. */
-/* CONST */
 static UChar* guest_code;
 
 /* The guest address corresponding to guest_code[0]. */
-/* CONST */
-static Addr32 guest_pc_bbstart;
+static Addr32 guest_CIA_bbstart;
 
 /* The guest address for the instruction currently being
    translated. */
-/* CONST for any specific insn, not for the entire BB */
-static Addr32 guest_cia_curr_instr;
+static Addr32 guest_CIA_curr_instr;
 
 /* The IRBB* into which we're generating code. */
 static IRBB* irbb;
@@ -245,179 +242,6 @@
 #endif
 
 
-
-/*------------------------------------------------------------*/
-/*--- Disassemble an entire basic block                    ---*/
-/*------------------------------------------------------------*/
-
-/* The results of disassembling an instruction.  There are three
-   possible outcomes.  For Dis_Resteer, the disassembler _must_
-   continue at the specified address.  For Dis_StopHere, the
-   disassembler _must_ terminate the BB.  For Dis_Continue, we may at
-   our option either disassemble the next insn, or terminate the BB;
-   but in the latter case we must set the bb's ->next field to point
-   to the next instruction.  */
-
-typedef
-   enum { 
-      Dis_StopHere, /* this insn terminates the BB; we must stop. */
-      Dis_Continue, /* we can optionally continue into the next insn */
-      Dis_Resteer   /* followed a branch; continue at the spec'd addr */
-   }
-   DisResult;
-
-
-/* forward decls .. */
-static IRExpr* mkU32 ( UInt i );
-static void stmt ( IRStmt* st );
-
-
-/* disInstr disassembles an instruction located at &guest_code[delta],
-   and sets *size to its size.  If the returned value is Dis_Resteer,
-   the next guest address is assigned to *whereNext.  disInstr is not
-   permitted to return Dis_Resteer if either (1) resteerOK is False,
-   or (2) resteerOkFn, when applied to the address which it wishes to
-   resteer into, returns False.  */
-   
-static DisResult disInstr ( /*IN*/  Bool    resteerOK,
-                            /*IN*/  Bool    (*resteerOkFn) ( Addr64 ),
-                            /*IN*/  UInt    delta, 
-                            /*IN*/  VexArchInfo* archinfo,
-                            /*OUT*/ Int*    size,
-                            /*OUT*/ Addr64* whereNext );
-
-
-/* This is the main (only, in fact) entry point for this module. */
-
-/* Disassemble a complete basic block, starting at guest_pc_start, and
-   dumping the IR into global irbb.  Returns the size, in bytes, of
-   the basic block.  
-*/
-IRBB* bbToIR_PPC32 ( UChar*           ppc32code, 
-                     Addr64           guest_pc_start, 
-                     VexGuestExtents* vge, 
-                     Bool             (*byte_accessible)(Addr64),
-                     Bool             (*chase_into_ok)(Addr64),
-                     Bool             host_bigendian,
-                     VexArchInfo*     archinfo_guest )
-{
-   UInt       delta;
-   Int        i, n_instrs, size, first_stmt_idx;
-   Addr64     guest_next;
-   Bool       resteerOK;
-   DisResult  dres;
-   static Int n_resteers = 0;
-   Int        d_resteers = 0;
-
-   /* check sanity .. */
-   vassert(vex_control.guest_max_insns >= 1);
-   vassert(vex_control.guest_max_insns < 1000);
-   vassert(vex_control.guest_chase_thresh >= 0);
-   vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns);
-
-   vassert(archinfo_guest->subarch == VexSubArchPPC32_noAV
-           || archinfo_guest->subarch == VexSubArchPPC32_AV);
-
-   /* Start a new, empty extent. */
-   vge->n_used  = 1;
-   vge->base[0] = guest_pc_start;
-   vge->len[0]  = 0;
-
-   /* Set up globals. */
-   host_is_bigendian = host_bigendian;
-   guest_code        = ppc32code;
-   guest_pc_bbstart  = (Addr32)guest_pc_start;
-   irbb              = emptyIRBB();
-
-   vassert((guest_pc_start >> 32) == 0);
-
-   /* Delta keeps track of how far along the ppc32code array we
-      have so far gone. */
-   delta             = 0;
-   n_instrs          = 0;
-
-   while (True) {
-      vassert(n_instrs < vex_control.guest_max_insns);
-
-      guest_next = 0;
-      resteerOK = toBool(n_instrs < vex_control.guest_chase_thresh);
-      first_stmt_idx = irbb->stmts_used;
-
-      guest_cia_curr_instr = guest_pc_bbstart + delta;
-
-      if (n_instrs > 0) {
-         /* for the first insn, the dispatch loop will have set
-            CIA, but for all the others we have to do it ourselves. */
-         putReg( PPC32_SPR_CIA, mkU32(guest_cia_curr_instr) );
-      }
-
-      dres = disInstr( resteerOK, chase_into_ok, 
-                       delta, archinfo_guest, &size, &guest_next );
-
-      /* Print the resulting IR, if needed. */
-      if (vex_traceflags & VEX_TRACE_FE) {
-         for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
-            vex_printf("              ");
-            ppIRStmt(irbb->stmts[i]);
-            vex_printf("\n");
-         }
-      }
-   
-      if (dres == Dis_StopHere) {
-         vassert(irbb->next != NULL);
-         if (vex_traceflags & VEX_TRACE_FE) {
-            vex_printf("              ");
-            vex_printf( "goto {");
-            ppIRJumpKind(irbb->jumpkind);
-            vex_printf( "} ");
-            ppIRExpr( irbb->next );
-            vex_printf( "\n");
-         }
-      }
-
-      delta += size;
-      vge->len[vge->n_used-1] += size;
-      n_instrs++;
-      DIP("\n");
-
-      vassert(size == 0 || size == 4);
-      if (!resteerOK) 
-         vassert(dres != Dis_Resteer);
-      if (dres != Dis_Resteer) 
-         vassert(guest_next == 0);
-
-      switch (dres) {
-      case Dis_Continue:
-         vassert(irbb->next == NULL);
-         if (n_instrs < vex_control.guest_max_insns) {
-            /* keep going */
-         } else {
-            irbb->next = mkU32(((Addr32)guest_pc_start)+delta);
-            return irbb;
-         }
-         break;
-      case Dis_StopHere:
-         vassert(irbb->next != NULL);
-         return irbb;
-      case Dis_Resteer:
-         vassert(irbb->next == NULL);
-         /* figure out a new delta to continue at. */
-         vassert(chase_into_ok(guest_next));
-         delta = (UInt)(guest_next - guest_pc_start);
-         n_resteers++;
-         d_resteers++;
-         if (0 && (n_resteers & 0xFF) == 0)
-            vex_printf("resteer[%d,%d] to %p (delta = %d)\n",
-                       n_resteers, d_resteers,
-                       ULong_to_Ptr(guest_next), (Int)delta);
-         break;
-
-      default: vpanic("bbToIR_PPC32(ppc32)");
-      }
-   }
-}
-
-
 /*------------------------------------------------------------*/
 /*--- Helper bits and pieces for deconstructing the        ---*/
 /*--- ppc32 insn stream.                                   ---*/
@@ -491,9 +315,10 @@
 {
    vassert(archreg < 32);
    
-//   vassert(!host_is_bigendian);
    // jrs: probably not necessary; only matters if we reference sub-parts
    // of the ppc32 registers, but that isn't the case
+   // later: this might affect Altivec though?
+   vassert(host_is_bigendian);
 
    switch (archreg) {
    case  0: return offsetof(VexGuestPPC32State, guest_GPR0);
@@ -1083,7 +908,7 @@
             IRStmt_Exit(
                binop(Iop_CmpNE32, mkU32(ew), mkU32(EmWarn_NONE)),
                Ijk_EmWarn,
-               IRConst_U32(guest_cia_curr_instr + 4)
+               IRConst_U32(guest_CIA_curr_instr + 4)
                )
             );
       }
@@ -2483,7 +2308,7 @@
 /*
   Integer Branch Instructions
 */
-static Bool dis_branch ( UInt theInstr, DisResult *whatNext )
+static Bool dis_branch ( UInt theInstr, DisResult* dres )
 {
    UChar opc1     = toUChar((theInstr >> 26) & 0x3F);    /* theInstr[26:31] */
    UChar BO       = toUChar((theInstr >> 21) & 0x1F);    /* theInstr[21:25] */
@@ -2512,7 +2337,7 @@
    /* Hack to pass through code that just wants to read the PC */
    if (theInstr == 0x429F0005) {
       DIP("bcl 0x%x, 0x%x,\n", BO, BI);
-      putReg( PPC32_SPR_LR, mkU32(guest_cia_curr_instr + 4) );
+      putReg( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr + 4) );
       return True;
     }
     
@@ -2521,12 +2346,12 @@
       if (flag_AA) {
          nia = (UInt)exts_LI;
       } else {
-         nia = (UInt)((Int)guest_cia_curr_instr + exts_LI);
+         nia = (UInt)((Int)guest_CIA_curr_instr + exts_LI);
       }
       DIP("b%s%s 0x%x\n", flag_LK ? "l" : "", flag_AA ? "a" : "", nia);
 
       if (flag_LK) {
-         putReg( PPC32_SPR_LR, mkU32(guest_cia_curr_instr+4) );
+         putReg( PPC32_SPR_LR, mkU32(guest_CIA_curr_instr+4) );
       }      
       irbb->jumpkind = flag_LK ? Ijk_Call : Ijk_Boring;
       irbb->next     = mkU32(nia);
@@ -2548,12 +2373,12 @@
       if (flag_AA) {
          nia = (UInt)exts_BD;
       } else {
-         nia = (UInt)((Int)guest_cia_curr_instr + exts_BD);
+         nia = (UInt)((Int)guest_CIA_curr_instr + exts_BD);
       }
       if (flag_LK) {
          assign( lr, IRExpr_Mux0X( unop(Iop_32to8, mkexpr(do_branch)),
                                    getReg( PPC32_SPR_LR ),
-                                   mkU32(guest_cia_curr_instr + 4)));
+                                   mkU32(guest_CIA_curr_instr + 4)));
          putReg( PPC32_SPR_LR, mkexpr(lr) );
       }
       
@@ -2562,7 +2387,7 @@
                          IRConst_U32(nia) ));
       
       irbb->jumpkind = Ijk_Boring;
-      irbb->next     = mkU32(guest_cia_curr_instr + 4);
+      irbb->next     = mkU32(guest_CIA_curr_instr + 4);
       break;
       
    case 0x13:
@@ -2586,13 +2411,13 @@
          if (flag_LK) {
             assign( lr, IRExpr_Mux0X( unop(Iop_1Uto8, mkexpr(cond_ok)),
                                       getReg( PPC32_SPR_LR ),
-                                      mkU32(guest_cia_curr_instr + 4)));
+                                      mkU32(guest_CIA_curr_instr + 4)));
             putReg( PPC32_SPR_LR, mkexpr(lr) );
          }
          
          stmt( IRStmt_Exit( unop(Iop_Not1, mkexpr(cond_ok)),
                             Ijk_Boring,
-                            IRConst_U32(guest_cia_curr_instr + 4) ));
+                            IRConst_U32(guest_CIA_curr_instr + 4) ));
          
          irbb->jumpkind = flag_LK ? Ijk_Call : Ijk_Boring;
          irbb->next     = mkexpr(ir_nia);
@@ -2618,13 +2443,13 @@
          if (flag_LK) {
             assign( lr, IRExpr_Mux0X( unop(Iop_32to8, mkexpr(do_branch)),
                                       getReg( PPC32_SPR_LR ),
-                                      mkU32(guest_cia_curr_instr + 4)) );
+                                      mkU32(guest_CIA_curr_instr + 4)) );
             putReg( PPC32_SPR_LR, mkexpr(lr) );
          }
          
          stmt( IRStmt_Exit( unop(Iop_Not1, unop(Iop_32to1, mkexpr(do_branch))),
                             Ijk_Boring,
-                            IRConst_U32(guest_cia_curr_instr + 4) ));
+                            IRConst_U32(guest_CIA_curr_instr + 4) ));
          
          irbb->jumpkind = flag_LK ? Ijk_Call : Ijk_Boring;
          irbb->next     = mkexpr(ir_nia);
@@ -2640,7 +2465,7 @@
       return False;
    }
     
-   *whatNext = Dis_StopHere;
+   dres->whatNext = Dis_StopHere;
    return True;
 }
 
@@ -2740,7 +2565,7 @@
 /*
   System Linkage Instructions
 */
-static Bool dis_syslink ( UInt theInstr, DisResult *whatNext )
+static Bool dis_syslink ( UInt theInstr, DisResult* dres )
 {
    if (theInstr != 0x44000002) {
       vex_printf("dis_int_syslink(PPC32)(theInstr)\n");
@@ -2753,10 +2578,10 @@
    /* It's important that all ArchRegs carry their up-to-date value
       at this point.  So we declare an end-of-block here, which
       forces any TempRegs caching ArchRegs to be flushed. */
-   irbb->next     = mkU32( guest_cia_curr_instr + 4 );
+   irbb->next     = mkU32( guest_CIA_curr_instr + 4 );
    irbb->jumpkind = Ijk_Syscall;
    
-   *whatNext = Dis_StopHere;
+   dres->whatNext = Dis_StopHere;
    return True;
 }
 
@@ -3280,7 +3105,7 @@
   Cache Management Instructions
 */
 static Bool dis_cache_manage ( UInt         theInstr, 
-                               DisResult*   whatNext,
+                               DisResult*   dres,
                                VexArchInfo* guest_archinfo )
 {
    /* X-Form */
@@ -3377,8 +3202,8 @@
       stmt( IRStmt_MFence() );
 
       irbb->jumpkind = Ijk_TInval;
-      irbb->next     = mkU32(guest_cia_curr_instr + 4);
-      *whatNext      = Dis_StopHere;
+      irbb->next     = mkU32(guest_CIA_curr_instr + 4);
+      dres->whatNext = Dis_StopHere;
       break;
    }
 
@@ -5636,38 +5461,35 @@
 /*------------------------------------------------------------*/
 
 /* Disassemble a single instruction into IR.  The instruction
-   is located in host memory at &guest_code[delta].
-   Set *size to be the size of the instruction.
-   If the returned value is Dis_Resteer,
-   the next guest address is assigned to *whereNext.  If resteerOK
-   is False, disInstr may not return Dis_Resteer. */
-   
-static DisResult disInstr ( /*IN*/  Bool    resteerOK,
-                            /*IN*/  Bool    (*resteerOkFn) ( Addr64 ),
-                            /*IN*/  UInt    delta, 
-                            /*IN*/  VexArchInfo* archinfo,
-                            /*OUT*/ Int*    size,
-                            /*OUT*/ Addr64* whereNext )
+   is located in host memory at &guest_code[delta]. */
+
+static   
+DisResult disInstr_PPC32_WRK ( 
+             Bool         put_IP,
+             Bool         (*resteerOkFn) ( Addr64 ),
+             Long         delta64,
+             VexArchInfo* archinfo 
+          )
 {
-   UChar opc1;
-   UInt  opc2;
-   DisResult whatNext = Dis_Continue;
+   UChar     opc1;
+   UInt      opc2;
+   DisResult dres;
    UInt      theInstr;
 
+   /* The running delta */
+   Int delta = (Int)delta64;
+
+   /* Set result defaults. */
+   dres.whatNext   = Dis_Continue;
+   dres.len        = 0;
+   dres.continueAt = 0;
 
    /* At least this is simple on PPC32: insns are all 4 bytes long, and
       4-aligned.  So just fish the whole thing out of memory right now
       and have done. */
-
-   /* We will set *size to 4 if the insn is successfully decoded.
-      Setting it to 0 by default makes bbToIR_PPC32 abort if we fail the
-      decode. */
-   *size = 0;
-
    theInstr = getUIntBigendianly( (UChar*)(&guest_code[delta]) );
 
-   DIP("\t0x%x:  ", guest_pc_bbstart+delta);
-
+   DIP("\t0x%x:  ", guest_CIA_bbstart+delta);
 
    /* Spot the client-request magic sequence. */
    // Essentially a v. unlikely sequence of noops that we can catch
@@ -5689,12 +5511,12 @@
           code[4] == 0x54009800 &&
           code[5] == 0x60000000) {
          DIP("%%r3 = client_request ( %%r31 )\n");
-         *size = 24;
+         dres.len = 24;
          delta += 24;
 
-         irbb->next     = mkU32(guest_pc_bbstart+delta);
+         irbb->next     = mkU32(guest_CIA_bbstart+delta);
          irbb->jumpkind = Ijk_ClientReq;
-         whatNext       = Dis_StopHere;
+         dres.whatNext  = Dis_StopHere;
          goto decode_success;
       }
    }
@@ -5756,12 +5578,12 @@
 
    /* Branch Instructions */
    case 0x12: case 0x10: // b, bc
-      if (dis_branch(theInstr, &whatNext)) goto decode_success;
+      if (dis_branch(theInstr, &dres)) goto decode_success;
       goto decode_failure;
 
    /* System Linkage Instructions */
    case 0x11: // sc
-      if (dis_syslink(theInstr, &whatNext)) goto decode_success;
+      if (dis_syslink(theInstr, &dres)) goto decode_success;
       goto decode_failure;
 
    /* Trap Instructions */
@@ -5874,7 +5696,7 @@
 
       /* Branch Instructions */
       case 0x210: case 0x010: // bcctr, bclr
-         if (dis_branch(theInstr, &whatNext)) goto decode_success;
+         if (dis_branch(theInstr, &dres)) goto decode_success;
          goto decode_failure;
 
       /* Memory Synchronization Instructions */
@@ -5973,7 +5795,7 @@
       case 0x2F6: case 0x056: case 0x036: // dcba, dcbf,   dcbst
       case 0x116: case 0x0F6: case 0x3F6: // dcbt, dcbtst, dcbz
       case 0x3D6:                         // icbi
-         if (dis_cache_manage( theInstr, &whatNext, archinfo )) 
+         if (dis_cache_manage( theInstr, &dres, archinfo )) 
             goto decode_success;
          goto decode_failure;
 
@@ -6191,27 +6013,59 @@
       CIA should be up-to-date since it made so at the start of each
       insn, but nevertheless be paranoid and update it again right
       now. */
-   putReg( PPC32_SPR_CIA, mkU32(guest_cia_curr_instr) );
-   irbb->next = mkU32(guest_cia_curr_instr);
+   putReg( PPC32_SPR_CIA, mkU32(guest_CIA_curr_instr) );
+   irbb->next = mkU32(guest_CIA_curr_instr);
    irbb->jumpkind = Ijk_NoDecode;
-   whatNext = Dis_StopHere;
-   *size = 0;
-   return whatNext;
+   dres.whatNext = Dis_StopHere;
+   dres.len = 0;
+   return dres;
 
    } /* switch (opc) for the main (primary) opcode switch. */
 
   decode_success:
    /* All decode successes end up here. */
-//   vex_printf("disInstr(ppc32): success");
    DIP("\n");
 
-   *size = 4;
-   return whatNext;
+   dres.len = 4;
+   return dres;
 }
 
 #undef DIP
 #undef DIS
 
+
+/*------------------------------------------------------------*/
+/*--- Top-level fn                                         ---*/
+/*------------------------------------------------------------*/
+
+/* Disassemble a single instruction into IR.  The instruction
+   is located in host memory at &guest_code[delta]. */
+
+DisResult disInstr_PPC32 ( IRBB*        irbb_IN,
+                           Bool         put_IP,
+                           Bool         (*resteerOkFn) ( Addr64 ),
+                           UChar*       guest_code_IN,
+                           Long         delta,
+                           Addr64       guest_IP,
+                           VexArchInfo* archinfo,
+                           Bool         host_bigendian_IN )
+{
+   DisResult dres;
+
+   /* Set globals (see top of this file) */
+   guest_code           = guest_code_IN;
+   irbb                 = irbb_IN;
+   host_is_bigendian    = host_bigendian_IN;
+   guest_CIA_curr_instr = (Addr32)guest_IP;
+   guest_CIA_bbstart    = (Addr32)toUInt(guest_IP - delta);
+
+   dres = disInstr_PPC32_WRK ( put_IP, resteerOkFn,
+                               delta, archinfo );
+
+   return dres;
+}
+
+
 /*--------------------------------------------------------------------*/
 /*--- end                                       guest-ppc32/toIR.c ---*/
 /*--------------------------------------------------------------------*/
diff --git a/priv/guest-x86/gdefs.h b/priv/guest-x86/gdefs.h
index 29a1fab..8c147aa 100644
--- a/priv/guest-x86/gdefs.h
+++ b/priv/guest-x86/gdefs.h
@@ -43,14 +43,17 @@
 /*--- x86 to IR conversion                              ---*/
 /*---------------------------------------------------------*/
 
+/* Convert one x86 insn to IR.  See the type DisOneInstrFn in
+   bb_to_IR.h. */
 extern
-IRBB* bbToIR_X86 ( UChar*           x86code, 
-                   Addr64           eip, 
-                   VexGuestExtents* vge,
-                   Bool             (*byte_accessible)(Addr64),
-                   Bool             (*resteerOkFn)(Addr64),
-                   Bool             host_bigendian,
-                   VexArchInfo*     archinfo_guest );
+DisResult disInstr_X86 ( IRBB*        irbb,
+                         Bool         put_IP,
+                         Bool         (*resteerOkFn) ( Addr64 ),
+                         UChar*       guest_code,
+                         Long         delta,
+                         Addr64       guest_IP,
+                         VexArchInfo* archinfo,
+                         Bool         host_bigendian );
 
 /* Used by the optimiser to specialise calls to helpers. */
 extern
diff --git a/priv/guest-x86/ghelpers.c b/priv/guest-x86/ghelpers.c
index d395459..f64b445 100644
--- a/priv/guest-x86/ghelpers.c
+++ b/priv/guest-x86/ghelpers.c
@@ -40,6 +40,7 @@
 #include "libvex.h"
 
 #include "main/vex_util.h"
+#include "guest-generic/bb_to_IR.h"
 #include "guest-x86/gdefs.h"
 #include "guest-generic/g_generic_x87.h"
 
diff --git a/priv/guest-x86/toIR.c b/priv/guest-x86/toIR.c
index b6199d7..712af4e 100644
--- a/priv/guest-x86/toIR.c
+++ b/priv/guest-x86/toIR.c
@@ -102,6 +102,7 @@
 
 #include "main/vex_util.h"
 #include "main/vex_globals.h"
+#include "guest-generic/bb_to_IR.h"
 #include "guest-x86/gdefs.h"
 
 
@@ -109,43 +110,39 @@
 /*--- Globals                                              ---*/
 /*------------------------------------------------------------*/
 
-/* These are set at the start of the translation of a BB, so
-   that we don't have to pass them around endlessly. */
+/* These are set at the start of the translation of an insn, right
+   down in disInstr_X86, so that we don't have to pass them around
+   endlessly.  They are all constant during the translation of any
+   given insn. */
 
 /* We need to know this to do sub-register accesses correctly. */
-/* CONST */
 static Bool host_is_bigendian;
 
-/* Pointer to the guest code area. */
-/* CONST */
+/* Pointer to the guest code area (points to start of BB, not to the
+   insn being processed). */
 static UChar* guest_code;
 
 /* The guest address corresponding to guest_code[0]. */
-/* CONST */
-static Addr32 guest_eip_bbstart;
+static Addr32 guest_EIP_bbstart;
 
 /* The guest address for the instruction currently being
    translated. */
-/* CONST for any specific insn, not for the entire BB */
-static Addr32 guest_eip_curr_instr;
+static Addr32 guest_EIP_curr_instr;
 
 /* The IRBB* into which we're generating code. */
 static IRBB* irbb;
 
-/* Emergency verboseness just for this insn?  DEBUG ONLY */
-static Bool  insn_verbose = False;
-
 
 /*------------------------------------------------------------*/
 /*--- Debugging output                                     ---*/
 /*------------------------------------------------------------*/
 
 #define DIP(format, args...)           \
-   if (insn_verbose || (vex_traceflags & VEX_TRACE_FE))  \
+   if (vex_traceflags & VEX_TRACE_FE)  \
       vex_printf(format, ## args)
 
 #define DIS(buf, format, args...)      \
-   if (insn_verbose || (vex_traceflags & VEX_TRACE_FE))  \
+   if (vex_traceflags & VEX_TRACE_FE)  \
       vex_sprintf(buf, format, ## args)
 
 
@@ -200,221 +197,6 @@
 
 
 /*------------------------------------------------------------*/
-/*--- Disassemble an entire basic block                    ---*/
-/*------------------------------------------------------------*/
-
-/* The results of disassembling an instruction.  There are three
-   possible outcomes.  For Dis_Resteer, the disassembler _must_
-   continue at the specified address.  For Dis_StopHere, the
-   disassembler _must_ terminate the BB.  For Dis_Continue, we may at
-   our option either disassemble the next insn, or terminate the BB;
-   but in the latter case we must set the bb's ->next field to point
-   to the next instruction.  */
-
-typedef
-   enum { 
-      Dis_StopHere, /* this insn terminates the BB; we must stop. */
-      Dis_Continue, /* we can optionally continue into the next insn */
-      Dis_Resteer   /* followed a branch; continue at the spec'd addr */
-   }
-   DisResult;
-
-
-/* forward decls .. */
-static IRExpr* mkU32 ( UInt i );
-static void stmt ( IRStmt* st );
-
-
-/* disInstr disassembles an instruction located at &guest_code[delta],
-   and sets *size to its size.  If the returned value is Dis_Resteer,
-   the next guest address is assigned to *whereNext.  disInstr is not
-   permitted to return Dis_Resteer if either (1) resteerOK is False,
-   or (2) resteerOkFn, when applied to the address which it wishes to
-   resteer into, returns False.  */
-   
-static 
-DisResult disInstr ( /*IN*/  Bool         resteerOK,
-                     /*IN*/  Bool         (*resteerOkFn) ( Addr64 ),
-                     /*IN*/  UInt         delta, 
-                     /*IN*/  VexArchInfo* archinfo,
-                     /*OUT*/ Int*         size,
-                     /*OUT*/ Addr64*      whereNext );
-
-
-/* This is the main (only, in fact) entry point for this module. */
-
-/* Disassemble a complete basic block, starting at eip, and dumping
-   the ucode into cb.  Returns the size, in bytes, of the basic
-   block. */
-IRBB* bbToIR_X86 ( UChar*           x86code, 
-                   Addr64           guest_eip_start, 
-                   VexGuestExtents* vge, 
-                   Bool             (*byte_accessible)(Addr64),
-                   Bool             (*chase_into_ok)(Addr64),
-                   Bool             host_bigendian,
-                   VexArchInfo*     archinfo_guest )
-{
-   UInt       delta;
-   Int        i, n_instrs, size, first_stmt_idx;
-   Addr64     guest_next;
-   Bool       resteerOK;
-   DisResult  dres;
-   IRStmt*    imark;
-   static Int n_resteers = 0;
-   Int        d_resteers = 0;
-
-   /* check sanity .. */
-   vassert(vex_control.guest_max_insns >= 1);
-   vassert(vex_control.guest_max_insns < 500);
-   vassert(vex_control.guest_chase_thresh >= 0);
-   vassert(vex_control.guest_chase_thresh < vex_control.guest_max_insns);
-
-   vassert(archinfo_guest->subarch == VexSubArchX86_sse0
-           || archinfo_guest->subarch == VexSubArchX86_sse1
-           || archinfo_guest->subarch == VexSubArchX86_sse2);
-
-   vassert((guest_eip_start >> 32) == 0);
-
-   /* Start a new, empty extent. */
-   vge->n_used  = 1;
-   vge->base[0] = guest_eip_start;
-   vge->len[0]  = 0;
-
-   /* Set up globals. */
-   host_is_bigendian = host_bigendian;
-   guest_code        = x86code;
-   guest_eip_bbstart = (Addr32)guest_eip_start;
-   irbb              = emptyIRBB();
-   insn_verbose      = False;
-
-   /* Delta keeps track of how far along the x86code array we
-      have so far gone. */
-   delta             = 0;
-   n_instrs          = 0;
-
-   while (True) {
-      vassert(n_instrs < vex_control.guest_max_insns);
-
-      guest_next = 0;
-      resteerOK 
-         = toBool(
-              n_instrs < vex_control.guest_chase_thresh
-              /* we can't afford to have a resteer once we're on the
-                 last extent slot. */
-              && vge->n_used < 3
-           );
-
-      /* This is the %EIP of the instruction we're just about to deal
-         with. */
-      guest_eip_curr_instr = guest_eip_bbstart + delta;
-
-      /* This is the irbb statement array index of the first stmt in
-         this insn.  That will always be the instruction-mark
-         descriptor. */
-      first_stmt_idx = irbb->stmts_used;
-
-      /* Add an instruction-mark statement.  We won't know until after
-         disInstr how long the instruction is, so just put in a zero
-         length and we'll fix it up later. */
-      stmt( IRStmt_IMark( (Addr64)guest_eip_curr_instr, 0 ));
-
-      if (n_instrs > 0) {
-         /* for the first insn, the dispatch loop will have set
-            %EIP, but for all the others we have to do it ourselves. */
-         stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_eip_curr_instr)) );
-      }
-
-      /* Do the instruction.  This may set insn_verbose to True, which
-         needs to be annulled. */
-      size = 0; /* just in case disInstr doesn't set it */
-      dres = disInstr( resteerOK, chase_into_ok, 
-                       delta, archinfo_guest, &size, &guest_next );
-      insn_verbose = False;
-
-      /* stay sane ... */
-      vassert(size >= 0 && size <= 18);
-
-      /* Fill in the insn-mark length field. */
-      vassert(first_stmt_idx >= 0 && first_stmt_idx < irbb->stmts_used);
-      imark = irbb->stmts[first_stmt_idx];
-      vassert(imark);
-      vassert(imark->tag == Ist_IMark);
-      vassert(imark->Ist.IMark.len == 0);
-      imark->Ist.IMark.len = size;
-
-      /* Print the resulting IR, if needed. */
-      if (vex_traceflags & VEX_TRACE_FE) {
-         for (i = first_stmt_idx; i < irbb->stmts_used; i++) {
-            vex_printf("              ");
-            ppIRStmt(irbb->stmts[i]);
-            vex_printf("\n");
-         }
-      }
-   
-      if (dres == Dis_StopHere) {
-         vassert(irbb->next != NULL);
-         if (vex_traceflags & VEX_TRACE_FE) {
-            vex_printf("              ");
-            vex_printf( "goto {");
-            ppIRJumpKind(irbb->jumpkind);
-            vex_printf( "} ");
-            ppIRExpr( irbb->next );
-            vex_printf( "\n");
-         }
-      }
-
-      delta += size;
-      /* If vex_control.guest_max_insns is required to be < 500 and
-	 each insn is at max 15 bytes long, this limit of 10000 then
-	 seems reasonable since the max possible extent length will be
-	 500 * 15 == 7500. */
-      vassert(vge->len[vge->n_used-1] < 10000);
-      vge->len[vge->n_used-1] 
-         = toUShort(toUInt( vge->len[vge->n_used-1] + size ));
-      n_instrs++;
-      DIP("\n");
-
-      if (!resteerOK) 
-         vassert(dres != Dis_Resteer);
-      if (dres != Dis_Resteer) 
-         vassert(guest_next == 0);
-
-      switch (dres) {
-         case Dis_Continue:
-            vassert(irbb->next == NULL);
-            if (n_instrs < vex_control.guest_max_insns) {
-               /* keep going */
-            } else {
-               irbb->next = mkU32(((Addr32)guest_eip_start)+delta);
-               return irbb;
-            }
-            break;
-         case Dis_StopHere:
-            vassert(irbb->next != NULL);
-            return irbb;
-         case Dis_Resteer:
-            vassert(irbb->next == NULL);
-            /* figure out a new delta to continue at. */
-            vassert(chase_into_ok(guest_next));
-            delta = toUInt(guest_next - guest_eip_start);
-            /* we now have to start a new extent slot. */
-	    vge->n_used++;
-	    vassert(vge->n_used <= 3);
-            vge->base[vge->n_used-1] = guest_next;
-            vge->len[vge->n_used-1] = 0;
-            n_resteers++;
-            d_resteers++;
-            if (0 && (n_resteers & 0xFF) == 0)
-            vex_printf("resteer[%d,%d] to %p (delta = %d)\n",
-                       n_resteers, d_resteers,
-                       ULong_to_Ptr(guest_next), (Int)delta);
-            break;
-      }
-   }
-}
-
-
-/*------------------------------------------------------------*/
 /*--- Helper bits and pieces for deconstructing the        ---*/
 /*--- x86 insn stream.                                     ---*/
 /*------------------------------------------------------------*/
@@ -1488,7 +1270,7 @@
       IRStmt_Exit(
          binop(Iop_CmpNE32, unop(Iop_64HIto32, mkexpr(r64)), mkU32(0)),
          Ijk_MapFail,
-         IRConst_U32( guest_eip_curr_instr )
+         IRConst_U32( guest_EIP_curr_instr )
       )
    );
 
@@ -2908,7 +2690,7 @@
 
 /* Group 5 extended opcodes. */
 static
-UInt dis_Grp5 ( UChar sorb, Int sz, UInt delta, DisResult* whatNext )
+UInt dis_Grp5 ( UChar sorb, Int sz, UInt delta, DisResult* dres )
 {
    Int     len;
    UChar   modrm;
@@ -2937,14 +2719,14 @@
             t2 = newTemp(Ity_I32);
             assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
             putIReg(4, R_ESP, mkexpr(t2));
-            storeLE( mkexpr(t2), mkU32(guest_eip_bbstart+delta+1));
+            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+1));
             jmp_treg(Ijk_Call,t1);
-            *whatNext = Dis_StopHere;
+            dres->whatNext = Dis_StopHere;
             break;
          case 4: /* jmp Ev */
             vassert(sz == 4);
             jmp_treg(Ijk_Boring,t1);
-            *whatNext = Dis_StopHere;
+            dres->whatNext = Dis_StopHere;
             break;
          default: 
             vex_printf(
@@ -2977,14 +2759,14 @@
             t2 = newTemp(Ity_I32);
             assign(t2, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
             putIReg(4, R_ESP, mkexpr(t2));
-            storeLE( mkexpr(t2), mkU32(guest_eip_bbstart+delta+len));
+            storeLE( mkexpr(t2), mkU32(guest_EIP_bbstart+delta+len));
             jmp_treg(Ijk_Call,t1);
-            *whatNext = Dis_StopHere;
+            dres->whatNext = Dis_StopHere;
             break;
          case 4: /* JMP Ev */
             vassert(sz == 4);
             jmp_treg(Ijk_Boring,t1);
-            *whatNext = Dis_StopHere;
+            dres->whatNext = Dis_StopHere;
             break;
          case 6: /* PUSH Ev */
             vassert(sz == 4 || sz == 2);
@@ -3778,7 +3560,7 @@
                   IRStmt_Exit(
                      binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
                      Ijk_EmWarn,
-                     IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
+                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
                   )
                );
 
@@ -3820,7 +3602,7 @@
                   IRStmt_Exit(
                      binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
                      Ijk_EmWarn,
-                     IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
+                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
                   )
                );
                break;
@@ -4616,7 +4398,7 @@
                   IRStmt_Exit(
                      binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
                      Ijk_EmWarn,
-                     IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
+                     IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
                   )
                );
 
@@ -6990,19 +6772,15 @@
 /*------------------------------------------------------------*/
 
 /* Disassemble a single instruction into IR.  The instruction
-   is located in host memory at &guest_code[delta].
-   Set *size to be the size of the instruction.
-   If the returned value is Dis_Resteer,
-   the next guest address is assigned to *whereNext.  If resteerOK
-   is False, disInstr may not return Dis_Resteer. */
-   
-static 
-DisResult disInstr ( /*IN*/  Bool         resteerOK,
-                     /*IN*/  Bool         (*resteerOkFn) ( Addr64 ),
-                     /*IN*/  UInt         delta, 
-                     /*IN*/  VexArchInfo* archinfo,
-                     /*OUT*/ Int*         size,
-                     /*OUT*/ Addr64*      whereNext )
+   is located in host memory at &guest_code[delta]. */
+
+static
+DisResult disInstr_X86_WRK ( 
+             Bool         put_IP,
+             Bool         (*resteerOkFn) ( Addr64 ),
+             Long         delta64,
+             VexArchInfo* archinfo 
+          )
 {
    IRType    ty;
    IRTemp    addr, t0, t1, t2, t3, t4, t5, t6;
@@ -7011,12 +6789,15 @@
    UInt      d32;
    HChar     dis_buf[50];
    Int       am_sz, d_sz;
-   DisResult whatNext = Dis_Continue;
+   DisResult dres;
    UChar*    insn; /* used in SSE decoders */
 
+   /* The running delta */
+   Int delta = (Int)delta64;
+
    /* Holds eip at the start of the insn, so that we can print
       consistent error messages for unimplemented insns. */
-   UInt delta_start = delta;
+   Int delta_start = delta;
 
    /* sz denotes the nominal data-op size of the insn; we change it to
       2 if an 0x66 prefix is seen */
@@ -7027,13 +6808,18 @@
       indicating the prefix.  */
    UChar sorb = 0;
 
-   /* If we don't set *size properly, this causes bbToIR_X86Instr to
-      assert. */
-   *size = 0;
+   /* Set result defaults. */
+   dres.whatNext   = Dis_Continue;
+   dres.len        = 0;
+   dres.continueAt = 0;
 
    addr = t0 = t1 = t2 = t3 = t4 = t5 = t6 = IRTemp_INVALID; 
 
-   DIP("\t0x%x:  ", guest_eip_bbstart+delta);
+   DIP("\t0x%x:  ", guest_EIP_bbstart+delta);
+
+   /* We may be asked to update the guest EIP before going further. */
+   if (put_IP)
+      stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr)) );
 
    /* Spot the client-request magic sequence. */
    {
@@ -7055,8 +6841,8 @@
          ) {
          DIP("%%edx = client_request ( %%eax )\n");         
          delta += 18;
-         jmp_lit(Ijk_ClientReq, guest_eip_bbstart+delta);
-         whatNext = Dis_StopHere;
+         jmp_lit(Ijk_ClientReq, guest_EIP_bbstart+delta);
+         dres.whatNext = Dis_StopHere;
          goto decode_success;
       }
    }
@@ -7087,7 +6873,7 @@
       else
       if (0) {
          vex_printf("vex x86->IR: ignoring LOCK prefix on: ");
-         insn_verbose = True;
+         /* insn_verbose = True; */
       }
 
       /* In any case, skip the prefix. */
@@ -7526,7 +7312,7 @@
          IRStmt_Exit(
             binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)),
             Ijk_EmWarn,
-            IRConst_U32( ((Addr32)guest_eip_bbstart)+delta)
+            IRConst_U32( ((Addr32)guest_EIP_bbstart)+delta)
          )
       );
       goto decode_success;
@@ -10331,20 +10117,20 @@
       d32 = getUDisp16(delta); 
       delta += 2;
       dis_ret(d32);
-      whatNext = Dis_StopHere;
+      dres.whatNext = Dis_StopHere;
       DIP("ret %d\n", (Int)d32);
       break;
    case 0xC3: /* RET */
       dis_ret(0);
-      whatNext = Dis_StopHere;
+      dres.whatNext = Dis_StopHere;
       DIP("ret\n");
       break;
       
    case 0xE8: /* CALL J4 */
       d32 = getUDisp32(delta); delta += 4;
-      d32 += (guest_eip_bbstart+delta); 
+      d32 += (guest_EIP_bbstart+delta); 
       /* (guest_eip_bbstart+delta) == return-to addr, d32 == call-to addr */
-      if (d32 == guest_eip_bbstart+delta && getIByte(delta) >= 0x58 
+      if (d32 == guest_EIP_bbstart+delta && getIByte(delta) >= 0x58 
                                          && getIByte(delta) <= 0x5F) {
          /* Specially treat the position-independent-code idiom 
                  call X
@@ -10354,7 +10140,7 @@
             since this generates better code, but for no other reason. */
          Int archReg = getIByte(delta) - 0x58;
          /* vex_printf("-- fPIC thingy\n"); */
-         putIReg(4, archReg, mkU32(guest_eip_bbstart+delta));
+         putIReg(4, archReg, mkU32(guest_EIP_bbstart+delta));
          delta++; /* Step over the POP */
          DIP("call 0x%x ; popl %s\n",d32,nameIReg(4,archReg));
       } else {
@@ -10362,14 +10148,14 @@
          t1 = newTemp(Ity_I32); 
          assign(t1, binop(Iop_Sub32, getIReg(4,R_ESP), mkU32(4)));
          putIReg(4, R_ESP, mkexpr(t1));
-         storeLE( mkexpr(t1), mkU32(guest_eip_bbstart+delta));
-         if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
+         storeLE( mkexpr(t1), mkU32(guest_EIP_bbstart+delta));
+         if (resteerOkFn((Addr64)(Addr32)d32)) {
             /* follow into the call target. */
-            whatNext = Dis_Resteer;
-            *whereNext = d32;
+            dres.whatNext   = Dis_Resteer;
+            dres.continueAt = (Addr64)(Addr32)d32;
          } else {
             jmp_lit(Ijk_Call,d32);
-            whatNext = Dis_StopHere;
+            dres.whatNext = Dis_StopHere;
          }
          DIP("call 0x%x\n",d32);
       }
@@ -10574,36 +10360,36 @@
       /* It's important that all ArchRegs carry their up-to-date value
          at this point.  So we declare an end-of-block here, which
          forces any TempRegs caching ArchRegs to be flushed. */
-      jmp_lit(Ijk_Syscall,((Addr32)guest_eip_bbstart)+delta);
-      whatNext = Dis_StopHere;
+      jmp_lit(Ijk_Syscall,((Addr32)guest_EIP_bbstart)+delta);
+      dres.whatNext = Dis_StopHere;
       DIP("int $0x80\n");
       break;
 
    /* ------------------------ Jcond, byte offset --------- */
 
    case 0xEB: /* Jb (jump, byte offset) */
-      d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta); 
+      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta); 
       delta++;
-      if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
-         whatNext   = Dis_Resteer;
-         *whereNext = d32;
+      if (resteerOkFn((Addr64)(Addr32)d32)) {
+         dres.whatNext   = Dis_Resteer;
+         dres.continueAt = (Addr64)(Addr32)d32;
       } else {
          jmp_lit(Ijk_Boring,d32);
-         whatNext = Dis_StopHere;
+         dres.whatNext = Dis_StopHere;
       }
       DIP("jmp-8 0x%x\n", d32);
       break;
 
    case 0xE9: /* Jv (jump, 16/32 offset) */
       vassert(sz == 4); /* JRS added 2004 July 11 */
-      d32 = (((Addr32)guest_eip_bbstart)+delta+sz) + getSDisp(sz,delta); 
+      d32 = (((Addr32)guest_EIP_bbstart)+delta+sz) + getSDisp(sz,delta); 
       delta += sz;
-      if (resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
-         whatNext   = Dis_Resteer;
-         *whereNext = d32;
+      if (resteerOkFn((Addr64)(Addr32)d32)) {
+         dres.whatNext   = Dis_Resteer;
+         dres.continueAt = (Addr64)(Addr32)d32;
       } else {
          jmp_lit(Ijk_Boring,d32);
-         whatNext = Dis_StopHere;
+         dres.whatNext = Dis_StopHere;
       }
       DIP("jmp 0x%x\n", d32);
       break;
@@ -10624,9 +10410,11 @@
    case 0x7D: /* JGEb/JNLb (jump greater or equal) */
    case 0x7E: /* JLEb/JNGb (jump less or equal) */
    case 0x7F: /* JGb/JNLEb (jump greater) */
-      d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta); 
+      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta); 
       delta++;
-      if (0 && resteerOK && resteerOkFn((Addr64)(Addr32)d32)) {
+      if (0 && resteerOkFn((Addr64)(Addr32)d32)) {
+         /* Unused experimental hack: speculatively follow one arm
+            of a conditional branch. */
          /* Assume the branch is taken.  So we need to emit a
             side-exit to the insn following this one, on the negation
             of the condition, and continue at the branch target
@@ -10635,12 +10423,12 @@
          stmt( IRStmt_Exit( 
                   mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
                   Ijk_Boring,
-                  IRConst_U32(guest_eip_bbstart+delta) ) );
-         whatNext   = Dis_Resteer;
-         *whereNext = d32;
+                  IRConst_U32(guest_EIP_bbstart+delta) ) );
+         dres.whatNext   = Dis_Resteer;
+         dres.continueAt = (Addr64)(Addr32)d32;
       } else {
-         jcc_01((X86Condcode)(opc - 0x70), (Addr32)(guest_eip_bbstart+delta), d32);
-         whatNext = Dis_StopHere;
+         jcc_01((X86Condcode)(opc - 0x70), (Addr32)(guest_EIP_bbstart+delta), d32);
+         dres.whatNext = Dis_StopHere;
       }
       DIP("j%s-8 0x%x\n", name_X86Condcode(opc - 0x70), d32);
       break;
@@ -10649,7 +10437,7 @@
                  manual says it depends on address size override,
                  which doesn't sound right to me. */
       vassert(sz==4); /* possibly also OK for sz==2 */
-      d32 = (((Addr32)guest_eip_bbstart)+delta+1) + getSDisp8(delta);
+      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta);
       delta++;
       ty = szToITy(sz);
       stmt( IRStmt_Exit(
@@ -11320,12 +11108,12 @@
 
    /* REPNE prefix insn */
    case 0xF2: { 
-      Addr32 eip_orig = guest_eip_bbstart + delta - 1;
+      Addr32 eip_orig = guest_EIP_bbstart + delta - 1;
       vassert(sorb == 0);
       abyte = getIByte(delta); delta++;
 
       if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
-      whatNext = Dis_StopHere;         
+      dres.whatNext = Dis_StopHere;         
 
       switch (abyte) {
       /* According to the Intel manual, "repne movs" should never occur, but
@@ -11345,7 +11133,7 @@
       case 0xAE: sz = 1;   /* REPNE SCAS<sz> */
       case 0xAF:
          dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
-                                 guest_eip_bbstart+delta, "repne scas" );
+                                 guest_EIP_bbstart+delta, "repne scas" );
          break;
 
       default:
@@ -11357,30 +11145,30 @@
    /* REP/REPE prefix insn (for SCAS and CMPS, 0xF3 means REPE,
       for the rest, it means REP) */
    case 0xF3: { 
-      Addr32 eip_orig = guest_eip_bbstart + delta - 1;
+      Addr32 eip_orig = guest_EIP_bbstart + delta - 1;
       vassert(sorb == 0);
       abyte = getIByte(delta); delta++;
 
       if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
-      whatNext = Dis_StopHere;
+      dres.whatNext = Dis_StopHere;
 
       switch (abyte) {
       case 0xA4: sz = 1;   /* REP MOVS<sz> */
       case 0xA5:
          dis_REP_op ( X86CondAlways, dis_MOVS, sz, eip_orig, 
-                                     guest_eip_bbstart+delta, "rep movs" );
+                                     guest_EIP_bbstart+delta, "rep movs" );
          break;
 
       case 0xA6: sz = 1;   /* REPE CMP<sz> */
       case 0xA7:
          dis_REP_op ( X86CondZ, dis_CMPS, sz, eip_orig, 
-                                guest_eip_bbstart+delta, "repe cmps" );
+                                guest_EIP_bbstart+delta, "repe cmps" );
          break;
 
       case 0xAA: sz = 1;   /* REP STOS<sz> */
       case 0xAB:
          dis_REP_op ( X86CondAlways, dis_STOS, sz, eip_orig, 
-                                     guest_eip_bbstart+delta, "rep stos" );
+                                     guest_EIP_bbstart+delta, "rep stos" );
          break;
 //-- 
 //--       case 0xAE: sz = 1;   /* REPE SCAS<sz> */
@@ -11393,8 +11181,8 @@
          DIP("rep nop (P4 pause)\n");
          /* "observe" the hint.  The Vex client needs to be careful not
             to cause very long delays as a result, though. */
-         jmp_lit(Ijk_Yield, ((Addr32)guest_eip_bbstart)+delta);
-         whatNext = Dis_StopHere;
+         jmp_lit(Ijk_Yield, ((Addr32)guest_EIP_bbstart)+delta);
+         dres.whatNext = Dis_StopHere;
          break;
 
 //--       case 0xC3:           /* REP RET */
@@ -11643,7 +11431,7 @@
    /* ------------------------ (Grp5 extensions) ---------- */
 
    case 0xFF: /* Grp5 Ev */
-      delta = dis_Grp5 ( sorb, sz, delta, &whatNext );
+      delta = dis_Grp5 ( sorb, sz, delta, &dres );
       break;
 
    /* ------------------------ Escapes to 2-byte opcodes -- */
@@ -11907,12 +11695,12 @@
       case 0x8D: /* JGEb/JNLb (jump greater or equal) */
       case 0x8E: /* JLEb/JNGb (jump less or equal) */
       case 0x8F: /* JGb/JNLEb (jump greater) */
-         d32 = (((Addr32)guest_eip_bbstart)+delta+4) + getUDisp32(delta); 
+         d32 = (((Addr32)guest_EIP_bbstart)+delta+4) + getUDisp32(delta); 
          delta += 4;
          jcc_01( (X86Condcode)(opc - 0x80), 
-                 (Addr32)(guest_eip_bbstart+delta), 
+                 (Addr32)(guest_EIP_bbstart+delta), 
                  d32 );
-         whatNext = Dis_StopHere;
+         dres.whatNext = Dis_StopHere;
          DIP("j%s-32 0x%x\n", name_X86Condcode(opc - 0x80), d32);
          break;
 
@@ -12156,11 +11944,11 @@
       EIP should be up-to-date since it made so at the start of each
       insn, but nevertheless be paranoid and update it again right
       now. */
-   stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_eip_curr_instr) ) );
-   jmp_lit(Ijk_NoDecode, guest_eip_curr_instr);
-   whatNext = Dis_StopHere;
-   *size = 0;
-   return whatNext;
+   stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_curr_instr) ) );
+   jmp_lit(Ijk_NoDecode, guest_EIP_curr_instr);
+   dres.whatNext = Dis_StopHere;
+   dres.len = 0;
+   return dres;
 
    } /* switch (opc) for the main (primary) opcode switch. */
 
@@ -12168,13 +11956,46 @@
    /* All decode successes end up here. */
    DIP("\n");
 
-   *size = delta - delta_start;
-   return whatNext;
+   dres.len = delta - delta_start;
+   return dres;
 }
 
 #undef DIP
 #undef DIS
 
+
+/*------------------------------------------------------------*/
+/*--- Top-level fn                                         ---*/
+/*------------------------------------------------------------*/
+
+/* Disassemble a single instruction into IR.  The instruction
+   is located in host memory at &guest_code[delta]. */
+
+DisResult disInstr_X86 ( IRBB*        irbb_IN,
+                         Bool         put_IP,
+                         Bool         (*resteerOkFn) ( Addr64 ),
+                         UChar*       guest_code_IN,
+                         Long         delta,
+                         Addr64       guest_IP,
+                         VexArchInfo* archinfo,
+                         Bool         host_bigendian_IN )
+{
+   DisResult dres;
+
+   /* Set globals (see top of this file) */
+   guest_code           = guest_code_IN;
+   irbb                 = irbb_IN;
+   host_is_bigendian    = host_bigendian_IN;
+   guest_EIP_curr_instr = (Addr32)guest_IP;
+   guest_EIP_bbstart    = (Addr32)toUInt(guest_IP - delta);
+
+   dres = disInstr_X86_WRK ( put_IP, resteerOkFn,
+                             delta, archinfo );
+
+   return dres;
+}
+
+
 /*--------------------------------------------------------------------*/
 /*--- end                                         guest-x86/toIR.c ---*/
 /*--------------------------------------------------------------------*/
diff --git a/priv/main/vex_main.c b/priv/main/vex_main.c
index 3d345fd..52e66b0 100644
--- a/priv/main/vex_main.c
+++ b/priv/main/vex_main.c
@@ -49,6 +49,7 @@
 #include "host-amd64/hdefs.h"
 #include "host-ppc32/hdefs.h"
 
+#include "guest-generic/bb_to_IR.h"
 #include "guest-x86/gdefs.h"
 #include "guest-amd64/gdefs.h"
 #include "guest-arm/gdefs.h"
@@ -208,15 +209,12 @@
    void         (*ppInstr)     ( HInstr* );
    void         (*ppReg)       ( HReg );
    HInstrArray* (*iselBB)      ( IRBB*, VexArchInfo* );
-   IRBB*        (*bbToIR)      ( UChar*, Addr64, 
-                                 VexGuestExtents*, 
-                                 Bool(*)(Addr64), 
-                                 Bool(*)(Addr64), 
-                                 Bool, VexArchInfo* );
    Int          (*emit)        ( UChar*, Int, HInstr* );
    IRExpr*      (*specHelper)  ( HChar*, IRExpr** );
    Bool         (*preciseMemExnsFn) ( Int, Int );
 
+   DisOneInstrFn disInstrFn;
+
    VexGuestLayout* guest_layout;
    Bool            host_is_bigendian = False;
    IRBB*           irbb;
@@ -238,10 +236,10 @@
    ppInstr                = NULL;
    ppReg                  = NULL;
    iselBB                 = NULL;
-   bbToIR                 = NULL;
    emit                   = NULL;
    specHelper             = NULL;
    preciseMemExnsFn       = NULL;
+   disInstrFn             = NULL;
    guest_word_type        = Ity_INVALID;
    host_word_type         = Ity_INVALID;
 
@@ -319,7 +317,7 @@
 
       case VexArchX86:
          preciseMemExnsFn = guest_x86_state_requires_precise_mem_exns;
-         bbToIR           = bbToIR_X86;
+         disInstrFn       = disInstr_X86;
          specHelper       = guest_x86_spechelper;
          guest_sizeB      = sizeof(VexGuestX86State);
          guest_word_type  = Ity_I32;
@@ -331,7 +329,7 @@
 
       case VexArchAMD64:
          preciseMemExnsFn = guest_amd64_state_requires_precise_mem_exns;
-         bbToIR           = bbToIR_AMD64;
+         disInstrFn       = disInstr_AMD64;
          specHelper       = guest_amd64_spechelper;
          guest_sizeB      = sizeof(VexGuestAMD64State);
          guest_word_type  = Ity_I64;
@@ -341,7 +339,7 @@
 
       case VexArchARM:
          preciseMemExnsFn = guest_arm_state_requires_precise_mem_exns;
-         bbToIR           = bbToIR_ARM;
+         disInstrFn       = NULL; /* HACK */
          specHelper       = guest_arm_spechelper;
          guest_sizeB      = sizeof(VexGuestARMState);
          guest_word_type  = Ity_I32;
@@ -351,7 +349,7 @@
 
       case VexArchPPC32:
          preciseMemExnsFn = guest_ppc32_state_requires_precise_mem_exns;
-         bbToIR           = bbToIR_PPC32;
+         disInstrFn       = disInstr_PPC32;
          specHelper       = guest_ppc32_spechelper;
          guest_sizeB      = sizeof(VexGuestPPC32State);
          guest_word_type  = Ity_I32;
@@ -377,13 +375,14 @@
                    " Front end "
                    "------------------------\n\n");
 
-   irbb = bbToIR ( guest_bytes, 
-                   guest_bytes_addr,
-                   guest_extents,
-                   byte_accessible,
-                   chase_into_ok,
-                   host_is_bigendian,
-                   archinfo_guest );
+   irbb = bb_to_IR ( guest_extents,
+                     disInstrFn,
+                     guest_bytes, 
+                     guest_bytes_addr,
+                     chase_into_ok,
+                     host_is_bigendian,
+                     archinfo_guest,
+                     guest_word_type );
 
    if (irbb == NULL) {
       /* Access failure. */
diff --git a/test_main.c b/test_main.c
index 854dbbf..dc5f054 100644
--- a/test_main.c
+++ b/test_main.c
@@ -66,7 +66,7 @@
    VexTranslateResult tres;
    VexControl vcon;
    VexGuestExtents vge;
-   VexArchInfo vai;
+   VexArchInfo vai_x86, vai_amd64, vai_ppc32;
 
    if (argc != 2) {
       fprintf(stderr, "usage: vex file.org\n");
@@ -123,29 +123,31 @@
          origbuf[i] = (UChar)u;
       }
 
-      LibVEX_default_VexArchInfo(&vai);
-      vai.subarch = VexSubArchX86_sse1;
+      LibVEX_default_VexArchInfo(&vai_x86);
+      vai_x86.subarch = VexSubArchX86_sse1;
+
+      LibVEX_default_VexArchInfo(&vai_amd64);
+      vai_amd64.subarch = VexSubArch_NONE;
+
+      LibVEX_default_VexArchInfo(&vai_ppc32);
+      vai_ppc32.subarch = VexSubArchPPC32_AV;
+      vai_ppc32.ppc32_cache_line_szB = 128;
 
       for (i = 0; i < TEST_N_ITERS; i++)
          tres
             = LibVEX_Translate ( 
-#if 0 /* ppc32 -> ppc32 */
-                 VexArchPPC32, VexSubArchPPC32_noAV,
-                 VexArchPPC32, VexSubArchPPC32_noAV,
-#endif
-#if 0 /* ppc32 -> x86 */
-                 VexArchPPC32, VexSubArchPPC32_noAV,
-                 VexArchX86, VexSubArchX86_sse2,
+#if 1 /* ppc32 -> ppc32 */
+                 VexArchPPC32, &vai_ppc32,
+                 VexArchPPC32, &vai_ppc32,
 #endif
 #if 0 /* amd64 -> amd64 */
-                 VexArchAMD64, VexSubArch_NONE, 
-                 VexArchAMD64, VexSubArch_NONE, 
+                 VexArchAMD64, &vai_amd64, 
+                 VexArchAMD64, &vai_amd64, 
 #endif
-#if 1 /* x86 -> x86 */
-                 VexArchX86, &vai, 
-                 VexArchX86, &vai, 
+#if 0 /* x86 -> x86 */
+                 VexArchX86, &vai_x86, 
+                 VexArchX86, &vai_x86, 
 #endif
-
                  origbuf, (Addr64)orig_addr, chase_into_not_ok,
                  &vge,
                  transbuf, N_TRANSBUF, &trans_used,
diff --git a/test_main.h b/test_main.h
index 6bd5e0f..0005fd6 100644
--- a/test_main.h
+++ b/test_main.h
@@ -2,7 +2,7 @@
 /* Copy this file (test_main.h.in) to test_main.h, and edit */
 
 /* DEBUG RUN, ON V */
-#if 1
+#if 0
 #define TEST_VSUPPORT  True
 #define TEST_N_ITERS   1
 #define TEST_N_BBS     1
@@ -10,7 +10,7 @@
 #endif
 
 /* CHECKING RUN, ON V */
-#if 0
+#if 1
 #define TEST_VSUPPORT  True
 #define TEST_N_ITERS   1
 #define TEST_N_BBS     100000