]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Add logic to allow front ends to speculatively continue adding guest
authorJulian Seward <jseward@acm.org>
Fri, 15 Jan 2010 10:53:21 +0000 (10:53 +0000)
committerJulian Seward <jseward@acm.org>
Fri, 15 Jan 2010 10:53:21 +0000 (10:53 +0000)
instructions into IRSBs (superblocks) after conditional branches.
Currently only the x86 and amd64 front ends support this.  The
assumption is that backwards conditional branches are taken and
forwards conditional branches are not taken, which is generally
regarded as plausible and is particularly effective with code compiled
by gcc at -O2, -O3 or -O -freorder-blocks (-freorder-blocks is enabled
by default at -O2 and above).

Is disabled by default.  Has been seen to provide notable speedups
(eg, --tool=none for perf/bz2), and reduces the number of
block-to-block transitions dramatically, by up to half, but usually
makes programs run more slowly.  Increases the amount of generated
code by at least 15%-20% and so is a net liability in terms of icache
misses and JIT time.

git-svn-id: svn://svn.valgrind.org/vex/trunk@1957

12 files changed:
VEX/priv/guest_amd64_defs.h
VEX/priv/guest_amd64_toIR.c
VEX/priv/guest_arm_defs.h
VEX/priv/guest_arm_toIR.c
VEX/priv/guest_generic_bb_to_IR.c
VEX/priv/guest_generic_bb_to_IR.h
VEX/priv/guest_ppc_defs.h
VEX/priv/guest_ppc_toIR.c
VEX/priv/guest_x86_defs.h
VEX/priv/guest_x86_toIR.c
VEX/priv/main_main.c
VEX/pub/libvex.h

index 6fc52e428d26a83cfac6085efe8f65f7b9c2f53d..dbc863f834a0ad2d9d3e5e74cd86115f891a52ef 100644 (file)
@@ -60,6 +60,7 @@ extern
 DisResult disInstr_AMD64 ( IRSB*        irbb,
                            Bool         put_IP,
                            Bool         (*resteerOkFn) ( void*, Addr64 ),
+                           Bool         resteerCisOk,
                            void*        callback_opaque,
                            UChar*       guest_code,
                            Long         delta,
index 2412cddeac0ba908c07f75a75f21b84c988b26e7..0eba8f06a9829efd527907fad3d659db62199b4c 100644 (file)
@@ -8828,6 +8828,7 @@ DisResult disInstr_AMD64_WRK (
              /*OUT*/Bool* expect_CAS,
              Bool         put_IP,
              Bool         (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
+             Bool         resteerCisOk,
              void*        callback_opaque,
              Long         delta64,
              VexArchInfo* archinfo,
@@ -13726,7 +13727,7 @@ DisResult disInstr_AMD64_WRK (
       make_redzone_AbiHint(vbi, t1, t2/*nia*/, "call-d32");
       if (resteerOkFn( callback_opaque, (Addr64)d64) ) {
          /* follow into the call target. */
-         dres.whatNext   = Dis_Resteer;
+         dres.whatNext   = Dis_ResteerU;
          dres.continueAt = d64;
       } else {
          jmp_lit(Ijk_Call,d64);
@@ -13956,7 +13957,7 @@ DisResult disInstr_AMD64_WRK (
       d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta); 
       delta++;
       if (resteerOkFn(callback_opaque,d64)) {
-         dres.whatNext   = Dis_Resteer;
+         dres.whatNext   = Dis_ResteerU;
          dres.continueAt = d64;
       } else {
          jmp_lit(Ijk_Boring,d64);
@@ -13972,7 +13973,7 @@ DisResult disInstr_AMD64_WRK (
       d64 = (guest_RIP_bbstart+delta+sz) + getSDisp(sz,delta); 
       delta += sz;
       if (resteerOkFn(callback_opaque,d64)) {
-         dres.whatNext   = Dis_Resteer;
+         dres.whatNext   = Dis_ResteerU;
          dres.continueAt = d64;
       } else {
          jmp_lit(Ijk_Boring,d64);
@@ -13997,15 +13998,58 @@ DisResult disInstr_AMD64_WRK (
    case 0x7D: /* JGEb/JNLb (jump greater or equal) */
    case 0x7E: /* JLEb/JNGb (jump less or equal) */
    case 0x7F: /* JGb/JNLEb (jump greater) */
+    { Long   jmpDelta;
+      HChar* comment  = "";
       if (haveF2orF3(pfx)) goto decode_failure;
-      d64 = (guest_RIP_bbstart+delta+1) + getSDisp8(delta); 
+      jmpDelta = getSDisp8(delta);
+      vassert(-128 <= jmpDelta && jmpDelta < 128);
+      d64 = (guest_RIP_bbstart+delta+1) + jmpDelta;
       delta++;
-      jcc_01( (AMD64Condcode)(opc - 0x70), 
-              guest_RIP_bbstart+delta,
-              d64 );
-      dres.whatNext = Dis_StopHere;
-      DIP("j%s-8 0x%llx\n", name_AMD64Condcode(opc - 0x70), d64);
+      if (resteerCisOk
+          && vex_control.guest_chase_cond
+          && jmpDelta < 0
+          && resteerOkFn( callback_opaque, d64) ) {
+         /* Speculation: assume this backward 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 address (d64). */
+         stmt( IRStmt_Exit( 
+                  mk_amd64g_calculate_condition(
+                     (AMD64Condcode)(1 ^ (opc - 0x70))),
+                  Ijk_Boring,
+                  IRConst_U64(guest_RIP_bbstart+delta) ) );
+         dres.whatNext   = Dis_ResteerC;
+         dres.continueAt = d64;
+         comment = "(assumed taken)";
+      }
+      else
+      if (resteerCisOk
+          && vex_control.guest_chase_cond
+          && jmpDelta >= 0
+          && resteerOkFn( callback_opaque, guest_RIP_bbstart+delta ) ) {
+         /* Speculation: assume this forward branch is not taken.  So
+            we need to emit a side-exit to d64 (the dest) and continue
+            disassembling at the insn immediately following this
+            one. */
+         stmt( IRStmt_Exit( 
+                  mk_amd64g_calculate_condition((AMD64Condcode)(opc - 0x70)),
+                  Ijk_Boring,
+                  IRConst_U64(d64) ) );
+         dres.whatNext   = Dis_ResteerC;
+         dres.continueAt = guest_RIP_bbstart+delta;
+         comment = "(assumed not taken)";
+      }
+      else {
+         /* Conservative default translation - end the block at this
+            point. */
+         jcc_01( (AMD64Condcode)(opc - 0x70), 
+                 guest_RIP_bbstart+delta,
+                 d64 );
+         dres.whatNext = Dis_StopHere;
+      }
+      DIP("j%s-8 0x%llx %s\n", name_AMD64Condcode(opc - 0x70), d64, comment);
       break;
+    }
 
    case 0xE3: 
       /* JRCXZ or JECXZ, depending address size override. */
@@ -15791,15 +15835,57 @@ DisResult disInstr_AMD64_WRK (
       case 0x8D: /* JGEb/JNLb (jump greater or equal) */
       case 0x8E: /* JLEb/JNGb (jump less or equal) */
       case 0x8F: /* JGb/JNLEb (jump greater) */
+       { Long   jmpDelta;
+         HChar* comment  = "";
          if (haveF2orF3(pfx)) goto decode_failure;
-         d64 = (guest_RIP_bbstart+delta+4) + getSDisp32(delta); 
+         jmpDelta = getSDisp32(delta);
+         d64 = (guest_RIP_bbstart+delta+4) + jmpDelta;
          delta += 4;
-         jcc_01( (AMD64Condcode)(opc - 0x80), 
-                 guest_RIP_bbstart+delta, 
-                 d64 );
-         dres.whatNext = Dis_StopHere;
-         DIP("j%s-32 0x%llx\n", name_AMD64Condcode(opc - 0x80), d64);
+         if (resteerCisOk
+             && vex_control.guest_chase_cond
+             && jmpDelta < 0
+             && resteerOkFn( callback_opaque, d64) ) {
+            /* Speculation: assume this backward 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 address (d64). */
+            stmt( IRStmt_Exit( 
+                     mk_amd64g_calculate_condition(
+                        (AMD64Condcode)(1 ^ (opc - 0x80))),
+                     Ijk_Boring,
+                     IRConst_U64(guest_RIP_bbstart+delta) ) );
+            dres.whatNext   = Dis_ResteerC;
+            dres.continueAt = d64;
+            comment = "(assumed taken)";
+         }
+         else
+         if (resteerCisOk
+             && vex_control.guest_chase_cond
+             && jmpDelta >= 0
+             && resteerOkFn( callback_opaque, guest_RIP_bbstart+delta ) ) {
+            /* Speculation: assume this forward branch is not taken.
+               So we need to emit a side-exit to d64 (the dest) and
+               continue disassembling at the insn immediately
+               following this one. */
+            stmt( IRStmt_Exit( 
+                     mk_amd64g_calculate_condition((AMD64Condcode)(opc - 0x80)),
+                     Ijk_Boring,
+                     IRConst_U64(d64) ) );
+            dres.whatNext   = Dis_ResteerC;
+            dres.continueAt = guest_RIP_bbstart+delta;
+            comment = "(assumed not taken)";
+         }
+         else {
+            /* Conservative default translation - end the block at
+               this point. */
+            jcc_01( (AMD64Condcode)(opc - 0x80), 
+                    guest_RIP_bbstart+delta,
+                    d64 );
+            dres.whatNext = Dis_StopHere;
+         }
+         DIP("j%s-32 0x%llx %s\n", name_AMD64Condcode(opc - 0x80), d64, comment);
          break;
+       }
 
       /* =-=-=-=-=-=-=-=-=- PREFETCH =-=-=-=-=-=-=-=-=-= */
       case 0x0D: /* 0F 0D /0 -- prefetch mem8 */
@@ -16112,6 +16198,7 @@ DisResult disInstr_AMD64_WRK (
 DisResult disInstr_AMD64 ( IRSB*        irsb_IN,
                            Bool         put_IP,
                            Bool         (*resteerOkFn) ( void*, Addr64 ),
+                           Bool         resteerCisOk,
                            void*        callback_opaque,
                            UChar*       guest_code_IN,
                            Long         delta,
@@ -16140,6 +16227,7 @@ DisResult disInstr_AMD64 ( IRSB*        irsb_IN,
    x1 = irsb_IN->stmts_used;
    expect_CAS = False;
    dres = disInstr_AMD64_WRK ( &expect_CAS, put_IP, resteerOkFn,
+                               resteerCisOk,
                                callback_opaque,
                                delta, archinfo, abiinfo );
    x2 = irsb_IN->stmts_used;
@@ -16172,6 +16260,7 @@ DisResult disInstr_AMD64 ( IRSB*        irsb_IN,
          to generate a useful error message; then assert. */
       vex_traceflags |= VEX_TRACE_FE;
       dres = disInstr_AMD64_WRK ( &expect_CAS, put_IP, resteerOkFn,
+                                  resteerCisOk,
                                   callback_opaque,
                                   delta, archinfo, abiinfo );
       for (i = x1; i < x2; i++) {
index 6bbda538ad7712d662d357c690b35ba8e73f51bd..184303febe2395e65d2f98297fee480b228ef85e 100644 (file)
@@ -55,6 +55,7 @@ extern
 DisResult disInstr_ARM ( IRSB*        irbb,
                          Bool         put_IP,
                          Bool         (*resteerOkFn) ( void*, Addr64 ),
+                         Bool         resteerCisOk,
                          void*        callback_opaque,
                          UChar*       guest_code,
                          Long         delta,
index 65986646a5cb0ad4e5818da461db8c48d2617fe6..7528018dd8dce84ddf5a3a7ef4cc889bc4c58587 100644 (file)
@@ -2642,7 +2642,7 @@ DisResult disInstr_ARM_WRK (
             continue tracing at the destination. */
          if (resteerOkFn( callback_opaque, (Addr64)dst )) {
             /* yes */
-            dres.whatNext   = Dis_Resteer;
+            dres.whatNext   = Dis_ResteerU;
             dres.continueAt = (Addr64)dst;
          } else {
             /* no; terminate the SB at this point. */
@@ -4756,6 +4756,7 @@ DisResult disInstr_ARM_WRK (
 DisResult disInstr_ARM ( IRSB*        irsb_IN,
                          Bool         put_IP,
                          Bool         (*resteerOkFn) ( void*, Addr64 ),
+                         Bool         resteerCisOk,
                          void*        callback_opaque,
                          UChar*       guest_code_IN,
                          Long         delta,
index 763b50f4ccb9bcc041844d5c4dfa549e20bf067a..e2255edaf5221ab3a9d9da3ee5591e15b417fa60 100644 (file)
@@ -121,6 +121,7 @@ IRSB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
    IRSB*      irsb;
    Addr64     guest_IP_curr_instr;
    IRConst*   guest_IP_bbstart_IRConst = NULL;
+   Int        n_cond_resteers_allowed = 2;
 
    Bool (*resteerOKfn)(void*,Addr64) = NULL;
 
@@ -209,6 +210,15 @@ IRSB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
       resteerOKfn
          = resteerOK ? chase_into_ok : const_False;
 
+      /* n_cond_resteers_allowed keeps track of whether we're still
+         allowing dis_instr_fn to chase conditional branches.  It
+         starts (at 2) and gets decremented each time dis_instr_fn
+         tells us it has chased a conditional branch.  We then
+         decrement it, and use it to tell later calls to dis_instr_fn
+         whether or not it is allowed to chase conditional
+         branches. */
+      vassert(n_cond_resteers_allowed >= 0 && n_cond_resteers_allowed <= 2);
+
       /* This is the IP of the instruction we're just about to deal
          with. */
       guest_IP_curr_instr = guest_IP_bbstart + delta;
@@ -231,6 +241,7 @@ IRSB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
       dres = dis_instr_fn ( irsb,
                             need_to_put_IP,
                             resteerOKfn,
+                            toBool(n_cond_resteers_allowed > 0),
                             callback_opaque,
                             guest_code,
                             delta,
@@ -243,10 +254,17 @@ IRSB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
       /* stay sane ... */
       vassert(dres.whatNext == Dis_StopHere
               || dres.whatNext == Dis_Continue
-              || dres.whatNext == Dis_Resteer);
+              || dres.whatNext == Dis_ResteerU
+              || dres.whatNext == Dis_ResteerC);
+      /* ... disassembled insn length is sane ... */
       vassert(dres.len >= 0 && dres.len <= 20);
-      if (dres.whatNext != Dis_Resteer)
+      /* ... continueAt is zero if no resteer requested ... */
+      if (dres.whatNext != Dis_ResteerU && dres.whatNext != Dis_ResteerC)
          vassert(dres.continueAt == 0);
+      /* ... if we disallowed conditional resteers, check that one
+             didn't actually happen anyway ... */
+      if (n_cond_resteers_allowed == 0)
+         vassert(dres.whatNext != Dis_ResteerC);
 
       /* Fill in the insn-mark length field. */
       vassert(first_stmt_idx >= 0 && first_stmt_idx < irsb->stmts_used);
@@ -313,10 +331,15 @@ IRSB* bb_to_IR ( /*OUT*/VexGuestExtents* vge,
          case Dis_StopHere:
             vassert(irsb->next != NULL);
             goto done;
-         case Dis_Resteer:
+         case Dis_ResteerU:
+         case Dis_ResteerC:
             /* Check that we actually allowed a resteer .. */
             vassert(resteerOK);
             vassert(irsb->next == NULL);
+            if (dres.whatNext == Dis_ResteerC) {
+               vassert(n_cond_resteers_allowed > 0);
+               n_cond_resteers_allowed--;
+            }
             /* figure out a new delta to continue at. */
             vassert(resteerOKfn(callback_opaque,dres.continueAt));
             delta = dres.continueAt - guest_IP_bbstart;
index 148346a804367934a0a1363563ee487b56951705..1aa1ef8dce6af2efbbd59d7f4105da1807d11655 100644 (file)
@@ -79,9 +79,13 @@ typedef
       /* 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
+         Dis_ResteerU:  followed an unconditional branch; continue at 
+                        'continueAt'
+         Dis_ResteerC:  (speculatively, of course) followed a
+                        conditional branch; continue at 'continueAt'
       */
-      enum { Dis_StopHere, Dis_Continue, Dis_Resteer } whatNext;
+      enum { Dis_StopHere, Dis_Continue, 
+             Dis_ResteerU, Dis_ResteerC } whatNext;
 
       /* For Dis_Resteer, this is the guest address we should continue
          at.  Otherwise ignored (should be zero). */
@@ -123,9 +127,16 @@ typedef
          or not? */
       /*IN*/  Bool         put_IP,
 
-      /* Return True iff resteering to the given addr is allowed */
+      /* Return True iff resteering to the given addr is allowed (for
+         branches/calls to destinations that are known at JIT-time) */
       /*IN*/  Bool         (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
 
+      /* Should we speculatively resteer across conditional branches?
+         (Experimental and not enabled by default).  The strategy is
+         to assume that backward branches are taken and forward
+         branches are not taken. */
+      /*IN*/  Bool         resteerCisOk,
+
       /* Vex-opaque data passed to all caller (valgrind) supplied
          callbacks. */
       /*IN*/  void*        callback_opaque,
index 73b7f6acde4b7e05f0730be30ed43d0c3a7df8c8..930f3786ae9ca6f71647fe47bae98bbe23821d3b 100644 (file)
@@ -61,6 +61,7 @@ extern
 DisResult disInstr_PPC ( IRSB*        irbb,
                          Bool         put_IP,
                          Bool         (*resteerOkFn) ( void*, Addr64 ),
+                         Bool         resteerCisOk,
                          void*        callback_opaque,
                          UChar*       guest_code,
                          Long         delta,
index 24e7dbb722424f94a8beb5ac4ea2778c19f49164..8a70b048c723a35d60a012a20b3af2c9614e5c32 100644 (file)
@@ -4324,7 +4324,7 @@ static Bool dis_branch ( UInt theInstr,
       }
 
       if (resteerOkFn( callback_opaque, tgt )) {
-         dres->whatNext   = Dis_Resteer;
+         dres->whatNext   = Dis_ResteerU;
          dres->continueAt = tgt;
       } else {
          irsb->jumpkind = flag_LK ? Ijk_Call : Ijk_Boring;
@@ -8951,6 +8951,7 @@ static
 DisResult disInstr_PPC_WRK ( 
              Bool         put_IP,
              Bool         (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
+             Bool         resteerCisOk,
              void*        callback_opaque,
              Long         delta64,
              VexArchInfo* archinfo,
@@ -9749,6 +9750,7 @@ DisResult disInstr_PPC_WRK (
 DisResult disInstr_PPC ( IRSB*        irsb_IN,
                          Bool         put_IP,
                          Bool         (*resteerOkFn) ( void*, Addr64 ),
+                         Bool         resteerCisOk,
                          void*        callback_opaque,
                          UChar*       guest_code_IN,
                          Long         delta,
@@ -9790,7 +9792,8 @@ DisResult disInstr_PPC ( IRSB*        irsb_IN,
    guest_CIA_curr_instr = mkSzAddr(ty, guest_IP);
    guest_CIA_bbstart    = mkSzAddr(ty, guest_IP - delta);
 
-   dres = disInstr_PPC_WRK ( put_IP, resteerOkFn, callback_opaque,
+   dres = disInstr_PPC_WRK ( put_IP, 
+                             resteerOkFn, resteerCisOk, callback_opaque,
                              delta, archinfo, abiinfo );
 
    return dres;
index ccee35b02389253023c8137a24d49ea8cb2b0399..8a8c848e541fcf098ec629fffc72fca6595f0dd9 100644 (file)
@@ -60,6 +60,7 @@ extern
 DisResult disInstr_X86 ( IRSB*        irbb,
                          Bool         put_IP,
                          Bool         (*resteerOkFn) ( void*, Addr64 ),
+                         Bool         resteerCisOk,
                          void*        callback_opaque,
                          UChar*       guest_code,
                          Long         delta,
index 47e8d61a62ca9089810233eafaae8d05459cbb76..7597b9eb5e7c4f02754b556170be23331ce7dc0b 100644 (file)
@@ -7805,6 +7805,7 @@ DisResult disInstr_X86_WRK (
              /*OUT*/Bool* expect_CAS,
              Bool         put_IP,
              Bool         (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
+             Bool         resteerCisOk,
              void*        callback_opaque,
              Long         delta64,
              VexArchInfo* archinfo 
@@ -12599,7 +12600,7 @@ DisResult disInstr_X86_WRK (
          storeLE( mkexpr(t1), mkU32(guest_EIP_bbstart+delta));
          if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32 )) {
             /* follow into the call target. */
-            dres.whatNext   = Dis_Resteer;
+            dres.whatNext   = Dis_ResteerU;
             dres.continueAt = (Addr64)(Addr32)d32;
          } else {
             jmp_lit(Ijk_Call,d32);
@@ -12885,7 +12886,7 @@ DisResult disInstr_X86_WRK (
       d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + getSDisp8(delta); 
       delta++;
       if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
-         dres.whatNext   = Dis_Resteer;
+         dres.whatNext   = Dis_ResteerU;
          dres.continueAt = (Addr64)(Addr32)d32;
       } else {
          jmp_lit(Ijk_Boring,d32);
@@ -12899,7 +12900,7 @@ DisResult disInstr_X86_WRK (
       d32 = (((Addr32)guest_EIP_bbstart)+delta+sz) + getSDisp(sz,delta); 
       delta += sz;
       if (resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
-         dres.whatNext   = Dis_Resteer;
+         dres.whatNext   = Dis_ResteerU;
          dres.continueAt = (Addr64)(Addr32)d32;
       } else {
          jmp_lit(Ijk_Boring,d32);
@@ -12924,28 +12925,56 @@ DisResult disInstr_X86_WRK (
    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); 
+    { Int    jmpDelta;
+      HChar* comment  = "";
+      jmpDelta = (Int)getSDisp8(delta);
+      vassert(-128 <= jmpDelta && jmpDelta < 128);
+      d32 = (((Addr32)guest_EIP_bbstart)+delta+1) + jmpDelta; 
       delta++;
-      if (0 && resteerOkFn( callback_opaque, (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
-            address (d32). */
-         if (0) vex_printf("resteer\n");
+      if (resteerCisOk
+          && vex_control.guest_chase_cond
+          && jmpDelta < 0
+          && resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
+         /* Speculation: assume this backward 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 address (d32). */
          stmt( IRStmt_Exit( 
                   mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
                   Ijk_Boring,
                   IRConst_U32(guest_EIP_bbstart+delta) ) );
-         dres.whatNext   = Dis_Resteer;
+         dres.whatNext   = Dis_ResteerC;
          dres.continueAt = (Addr64)(Addr32)d32;
-      } else {
-         jcc_01((X86Condcode)(opc - 0x70), (Addr32)(guest_EIP_bbstart+delta), d32);
+         comment = "(assumed taken)";
+      }
+      else
+      if (resteerCisOk
+          && vex_control.guest_chase_cond
+          && jmpDelta >= 0
+          && resteerOkFn( callback_opaque, 
+                          (Addr64)(Addr32)(guest_EIP_bbstart+delta)) ) {
+         /* Speculation: assume this forward branch is not taken.  So
+            we need to emit a side-exit to d32 (the dest) and continue
+            disassembling at the insn immediately following this
+            one. */
+         stmt( IRStmt_Exit( 
+                  mk_x86g_calculate_condition((X86Condcode)(opc - 0x70)),
+                  Ijk_Boring,
+                  IRConst_U32(d32) ) );
+         dres.whatNext   = Dis_ResteerC;
+         dres.continueAt = (Addr64)(Addr32)(guest_EIP_bbstart+delta);
+         comment = "(assumed not taken)";
+      }
+      else {
+         /* Conservative default translation - end the block at this
+            point. */
+         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);
+      DIP("j%s-8 0x%x %s\n", name_X86Condcode(opc - 0x70), d32, comment);
       break;
+    }
 
    case 0xE3: /* JECXZ (for JCXZ see above) */
       if (sz != 4) goto decode_failure;
@@ -14448,14 +14477,55 @@ DisResult disInstr_X86_WRK (
       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); 
+       { Int    jmpDelta;
+         HChar* comment  = "";
+         jmpDelta = (Int)getUDisp32(delta);
+         d32 = (((Addr32)guest_EIP_bbstart)+delta+4) + jmpDelta;
          delta += 4;
-         jcc_01( (X86Condcode)(opc - 0x80), 
-                 (Addr32)(guest_EIP_bbstart+delta), 
-                 d32 );
-         dres.whatNext = Dis_StopHere;
-         DIP("j%s-32 0x%x\n", name_X86Condcode(opc - 0x80), d32);
+         if (resteerCisOk
+             && vex_control.guest_chase_cond
+             && jmpDelta < 0
+             && resteerOkFn( callback_opaque, (Addr64)(Addr32)d32) ) {
+            /* Speculation: assume this backward 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 address (d32). */
+            stmt( IRStmt_Exit( 
+                     mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x80))),
+                     Ijk_Boring,
+                     IRConst_U32(guest_EIP_bbstart+delta) ) );
+            dres.whatNext   = Dis_ResteerC;
+            dres.continueAt = (Addr64)(Addr32)d32;
+            comment = "(assumed taken)";
+         }
+         else
+         if (resteerCisOk
+             && vex_control.guest_chase_cond
+             && jmpDelta >= 0
+             && resteerOkFn( callback_opaque, 
+                             (Addr64)(Addr32)(guest_EIP_bbstart+delta)) ) {
+            /* Speculation: assume this forward branch is not taken.
+               So we need to emit a side-exit to d32 (the dest) and
+               continue disassembling at the insn immediately
+               following this one. */
+            stmt( IRStmt_Exit( 
+                     mk_x86g_calculate_condition((X86Condcode)(opc - 0x80)),
+                     Ijk_Boring,
+                     IRConst_U32(d32) ) );
+            dres.whatNext   = Dis_ResteerC;
+            dres.continueAt = (Addr64)(Addr32)(guest_EIP_bbstart+delta);
+            comment = "(assumed not taken)";
+         }
+         else {
+            /* Conservative default translation - end the block at
+               this point. */
+            jcc_01( (X86Condcode)(opc - 0x80), 
+                    (Addr32)(guest_EIP_bbstart+delta), d32);
+            dres.whatNext = Dis_StopHere;
+         }
+         DIP("j%s-32 0x%x %s\n", name_X86Condcode(opc - 0x80), d32, comment);
          break;
+       }
 
       /* =-=-=-=-=-=-=-=-=- RDTSC -=-=-=-=-=-=-=-=-=-=-= */
       case 0x31: { /* RDTSC */
@@ -14752,6 +14822,7 @@ DisResult disInstr_X86_WRK (
 DisResult disInstr_X86 ( IRSB*        irsb_IN,
                          Bool         put_IP,
                          Bool         (*resteerOkFn) ( void*, Addr64 ),
+                         Bool         resteerCisOk,
                          void*        callback_opaque,
                          UChar*       guest_code_IN,
                          Long         delta,
@@ -14776,6 +14847,7 @@ DisResult disInstr_X86 ( IRSB*        irsb_IN,
    x1 = irsb_IN->stmts_used;
    expect_CAS = False;
    dres = disInstr_X86_WRK ( &expect_CAS, put_IP, resteerOkFn,
+                             resteerCisOk,
                              callback_opaque, delta, archinfo );
    x2 = irsb_IN->stmts_used;
    vassert(x2 >= x1);
@@ -14794,6 +14866,7 @@ DisResult disInstr_X86 ( IRSB*        irsb_IN,
          to generate a useful error message; then assert. */
       vex_traceflags |= VEX_TRACE_FE;
       dres = disInstr_X86_WRK ( &expect_CAS, put_IP, resteerOkFn,
+                                resteerCisOk,
                                 callback_opaque, delta, archinfo );
       for (i = x1; i < x2; i++) {
          vex_printf("\t\t");
index 7fdd6f9ea9b83f7831dcb6f678681e84eae4fee2..0b602fff26ffd509b8733858647252ce5a882461 100644 (file)
@@ -89,6 +89,7 @@ void LibVEX_default_VexControl ( /*OUT*/ VexControl* vcon )
    vcon->iropt_unroll_thresh        = 120;
    vcon->guest_max_insns            = 60;
    vcon->guest_chase_thresh         = 10;
+   vcon->guest_chase_cond           = False;
 }
 
 
@@ -128,6 +129,8 @@ void LibVEX_Init (
    vassert(vcon->guest_max_insns <= 100);
    vassert(vcon->guest_chase_thresh >= 0);
    vassert(vcon->guest_chase_thresh < vcon->guest_max_insns);
+   vassert(vcon->guest_chase_cond == True 
+           || vcon->guest_chase_cond == False);
 
    /* Check that Vex has been built with sizes of basic types as
       stated in priv/libvex_basictypes.h.  Failure of any of these is
index c86f565db002edeec6e225cb36346dca27ab80a2..0162c7085a624d83bcfe1f472b3f2d6ae5f6fec2 100644 (file)
@@ -265,6 +265,9 @@ typedef
          far, the front end(s) will attempt to chase into its
          successor. A setting of zero disables chasing.  */
       Int guest_chase_thresh;
+      /* EXPERIMENTAL: chase across conditional branches?  Not all
+         front ends honour this.  Default: NO. */
+      Bool guest_chase_cond;
    }
    VexControl;