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
DisResult disInstr_AMD64 ( IRSB* irbb,
Bool put_IP,
Bool (*resteerOkFn) ( void*, Addr64 ),
+ Bool resteerCisOk,
void* callback_opaque,
UChar* guest_code,
Long delta,
/*OUT*/Bool* expect_CAS,
Bool put_IP,
Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
+ Bool resteerCisOk,
void* callback_opaque,
Long delta64,
VexArchInfo* archinfo,
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);
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);
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);
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. */
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 */
DisResult disInstr_AMD64 ( IRSB* irsb_IN,
Bool put_IP,
Bool (*resteerOkFn) ( void*, Addr64 ),
+ Bool resteerCisOk,
void* callback_opaque,
UChar* guest_code_IN,
Long delta,
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;
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++) {
DisResult disInstr_ARM ( IRSB* irbb,
Bool put_IP,
Bool (*resteerOkFn) ( void*, Addr64 ),
+ Bool resteerCisOk,
void* callback_opaque,
UChar* guest_code,
Long delta,
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. */
DisResult disInstr_ARM ( IRSB* irsb_IN,
Bool put_IP,
Bool (*resteerOkFn) ( void*, Addr64 ),
+ Bool resteerCisOk,
void* callback_opaque,
UChar* guest_code_IN,
Long delta,
IRSB* irsb;
Addr64 guest_IP_curr_instr;
IRConst* guest_IP_bbstart_IRConst = NULL;
+ Int n_cond_resteers_allowed = 2;
Bool (*resteerOKfn)(void*,Addr64) = NULL;
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;
dres = dis_instr_fn ( irsb,
need_to_put_IP,
resteerOKfn,
+ toBool(n_cond_resteers_allowed > 0),
callback_opaque,
guest_code,
delta,
/* 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);
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;
/* 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). */
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,
DisResult disInstr_PPC ( IRSB* irbb,
Bool put_IP,
Bool (*resteerOkFn) ( void*, Addr64 ),
+ Bool resteerCisOk,
void* callback_opaque,
UChar* guest_code,
Long delta,
}
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;
DisResult disInstr_PPC_WRK (
Bool put_IP,
Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
+ Bool resteerCisOk,
void* callback_opaque,
Long delta64,
VexArchInfo* archinfo,
DisResult disInstr_PPC ( IRSB* irsb_IN,
Bool put_IP,
Bool (*resteerOkFn) ( void*, Addr64 ),
+ Bool resteerCisOk,
void* callback_opaque,
UChar* guest_code_IN,
Long delta,
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;
DisResult disInstr_X86 ( IRSB* irbb,
Bool put_IP,
Bool (*resteerOkFn) ( void*, Addr64 ),
+ Bool resteerCisOk,
void* callback_opaque,
UChar* guest_code,
Long delta,
/*OUT*/Bool* expect_CAS,
Bool put_IP,
Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
+ Bool resteerCisOk,
void* callback_opaque,
Long delta64,
VexArchInfo* archinfo
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);
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);
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);
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;
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 */
DisResult disInstr_X86 ( IRSB* irsb_IN,
Bool put_IP,
Bool (*resteerOkFn) ( void*, Addr64 ),
+ Bool resteerCisOk,
void* callback_opaque,
UChar* guest_code_IN,
Long delta,
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);
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");
vcon->iropt_unroll_thresh = 120;
vcon->guest_max_insns = 60;
vcon->guest_chase_thresh = 10;
+ vcon->guest_chase_cond = False;
}
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
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;