|
From: <sv...@va...> - 2012-04-02 21:55:00
|
sewardj 2012-04-02 22:54:49 +0100 (Mon, 02 Apr 2012)
New Revision: 2273
Log:
Add translation chaining support for amd64, x86 and ARM (VEX side).
See #296422.
Modified files:
branches/TCHAIN/Makefile-gcc
branches/TCHAIN/priv/guest_amd64_defs.h
branches/TCHAIN/priv/guest_amd64_helpers.c
branches/TCHAIN/priv/guest_amd64_toIR.c
branches/TCHAIN/priv/guest_arm_defs.h
branches/TCHAIN/priv/guest_arm_helpers.c
branches/TCHAIN/priv/guest_arm_toIR.c
branches/TCHAIN/priv/guest_generic_bb_to_IR.c
branches/TCHAIN/priv/guest_generic_bb_to_IR.h
branches/TCHAIN/priv/guest_ppc_toIR.c
branches/TCHAIN/priv/guest_s390_toIR.c
branches/TCHAIN/priv/guest_x86_defs.h
branches/TCHAIN/priv/guest_x86_helpers.c
branches/TCHAIN/priv/guest_x86_toIR.c
branches/TCHAIN/priv/host_amd64_defs.c
branches/TCHAIN/priv/host_amd64_defs.h
branches/TCHAIN/priv/host_amd64_isel.c
branches/TCHAIN/priv/host_arm_defs.c
branches/TCHAIN/priv/host_arm_defs.h
branches/TCHAIN/priv/host_arm_isel.c
branches/TCHAIN/priv/host_x86_defs.c
branches/TCHAIN/priv/host_x86_defs.h
branches/TCHAIN/priv/host_x86_isel.c
branches/TCHAIN/priv/ir_defs.c
branches/TCHAIN/priv/ir_opt.c
branches/TCHAIN/priv/ir_opt.h
branches/TCHAIN/priv/main_main.c
branches/TCHAIN/pub/libvex.h
branches/TCHAIN/pub/libvex_guest_amd64.h
branches/TCHAIN/pub/libvex_guest_arm.h
branches/TCHAIN/pub/libvex_guest_x86.h
branches/TCHAIN/pub/libvex_ir.h
branches/TCHAIN/pub/libvex_trc_values.h
branches/TCHAIN/switchback/switchback.c
branches/TCHAIN/test_main.c
branches/TCHAIN/test_main.h
Modified: branches/TCHAIN/priv/host_amd64_isel.c (+165 -29)
===================================================================
--- branches/TCHAIN/priv/host_amd64_isel.c 2012-04-02 22:24:12 +01:00 (rev 2272)
+++ branches/TCHAIN/priv/host_amd64_isel.c 2012-04-02 22:54:49 +01:00 (rev 2273)
@@ -112,30 +112,46 @@
64-bit virtual HReg, which holds the high half
of the value.
+ - The host subarchitecture we are selecting insns for.
+ This is set at the start and does not change.
+
- The code array, that is, the insns selected so far.
- A counter, for generating new virtual registers.
- - The host subarchitecture we are selecting insns for.
- This is set at the start and does not change.
+ - A Bool for indicating whether we may generate chain-me
+ instructions for control flow transfers, or whether we must use
+ XAssisted.
+ - The maximum guest address of any guest insn in this block.
+ Actually, the address of the highest-addressed byte from any insn
+ in this block. Is set at the start and does not change. This is
+ used for detecting jumps which are definitely forward-edges from
+ this block, and therefore can be made (chained) to the fast entry
+ point of the destination, thereby avoiding the destination's
+ event check.
+
Note, this is all host-independent. (JRS 20050201: well, kinda
... not completely. Compare with ISelEnv for X86.)
*/
typedef
struct {
+ /* Constant -- are set at the start and do not change. */
IRTypeEnv* type_env;
HReg* vregmap;
HReg* vregmapHI;
Int n_vregmap;
+ UInt hwcaps;
+
+ Bool chainingAllowed;
+ Addr64 max_ga;
+
+ /* These are modified as we go along. */
HInstrArray* code;
-
Int vreg_ctr;
-
- UInt hwcaps;
}
ISelEnv;
@@ -4131,14 +4147,47 @@
/* --------- EXIT --------- */
case Ist_Exit: {
- AMD64RI* dst;
- AMD64CondCode cc;
if (stmt->Ist.Exit.dst->tag != Ico_U64)
vpanic("iselStmt(amd64): Ist_Exit: dst is not a 64-bit value");
- dst = iselIntExpr_RI(env, IRExpr_Const(stmt->Ist.Exit.dst));
- cc = iselCondCode(env,stmt->Ist.Exit.guard);
- addInstr(env, AMD64Instr_Goto(stmt->Ist.Exit.jk, cc, dst));
- return;
+
+ AMD64CondCode cc = iselCondCode(env, stmt->Ist.Exit.guard);
+ AMD64AMode* amRIP = AMD64AMode_IR(stmt->Ist.Exit.offsIP,
+ hregAMD64_RBP());
+
+ /* Case: boring transfer to known address */
+ if (stmt->Ist.Exit.jk == Ijk_Boring) {
+ if (env->chainingAllowed) {
+ /* .. almost always true .. */
+ /* Skip the event check at the dst if this is a forwards
+ edge. */
+ Bool toFastEP
+ = ((Addr64)stmt->Ist.Exit.dst->Ico.U64) > env->max_ga;
+ if (0) vex_printf("%s", toFastEP ? "Y" : ",");
+ addInstr(env, AMD64Instr_XDirect(stmt->Ist.Exit.dst->Ico.U64,
+ amRIP, cc, toFastEP));
+ } else {
+ /* .. very occasionally .. */
+ /* We can't use chaining, so ask for an assisted transfer,
+ as that's the only alternative that is allowable. */
+ HReg r = iselIntExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
+ addInstr(env, AMD64Instr_XAssisted(r, amRIP, cc, Ijk_Boring));
+ }
+ return;
+ }
+
+ /* Case: assisted transfer to arbitrary address */
+ switch (stmt->Ist.Exit.jk) {
+ case Ijk_SigSEGV: case Ijk_TInval: case Ijk_EmWarn: {
+ HReg r = iselIntExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
+ addInstr(env, AMD64Instr_XAssisted(r, amRIP, cc, stmt->Ist.Exit.jk));
+ return;
+ }
+ default:
+ break;
+ }
+
+ /* Do we ever expect to see any other kind? */
+ goto stmt_fail;
}
default: break;
@@ -4153,18 +4202,83 @@
/*--- ISEL: Basic block terminators (Nexts) ---*/
/*---------------------------------------------------------*/
-static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
+static void iselNext ( ISelEnv* env,
+ IRExpr* next, IRJumpKind jk, Int offsIP )
{
- AMD64RI* ri;
if (vex_traceflags & VEX_TRACE_VCODE) {
- vex_printf("\n-- goto {");
+ vex_printf( "\n-- PUT(%d) = ", offsIP);
+ ppIRExpr( next );
+ vex_printf( "; exit-");
ppIRJumpKind(jk);
- vex_printf("} ");
- ppIRExpr(next);
- vex_printf("\n");
+ vex_printf( "\n");
}
- ri = iselIntExpr_RI(env, next);
- addInstr(env, AMD64Instr_Goto(jk, Acc_ALWAYS,ri));
+
+ /* Case: boring transfer to known address */
+ if (next->tag == Iex_Const) {
+ IRConst* cdst = next->Iex.Const.con;
+ vassert(cdst->tag == Ico_U64);
+ if (jk == Ijk_Boring || jk == Ijk_Call) {
+ /* Boring transfer to known address */
+ AMD64AMode* amRIP = AMD64AMode_IR(offsIP, hregAMD64_RBP());
+ if (env->chainingAllowed) {
+ /* .. almost always true .. */
+ /* Skip the event check at the dst if this is a forwards
+ edge. */
+ Bool toFastEP
+ = ((Addr64)cdst->Ico.U64) > env->max_ga;
+ if (0) vex_printf("%s", toFastEP ? "X" : ".");
+ addInstr(env, AMD64Instr_XDirect(cdst->Ico.U64,
+ amRIP, Acc_ALWAYS,
+ toFastEP));
+ } else {
+ /* .. very occasionally .. */
+ /* We can't use chaining, so ask for an indirect transfer,
+ as that's the cheapest alternative that is
+ allowable. */
+ HReg r = iselIntExpr_R(env, next);
+ addInstr(env, AMD64Instr_XAssisted(r, amRIP, Acc_ALWAYS,
+ Ijk_Boring));
+ }
+ return;
+ }
+ }
+
+ /* Case: call/return (==boring) transfer to any address */
+ switch (jk) {
+ case Ijk_Boring: case Ijk_Ret: case Ijk_Call: {
+ HReg r = iselIntExpr_R(env, next);
+ AMD64AMode* amRIP = AMD64AMode_IR(offsIP, hregAMD64_RBP());
+ if (env->chainingAllowed) {
+ addInstr(env, AMD64Instr_XIndir(r, amRIP, Acc_ALWAYS));
+ } else {
+ addInstr(env, AMD64Instr_XAssisted(r, amRIP, Acc_ALWAYS,
+ Ijk_Boring));
+ }
+ return;
+ }
+ default:
+ break;
+ }
+
+ /* Case: some other kind of transfer to any address */
+ switch (jk) {
+ case Ijk_Sys_syscall: case Ijk_ClientReq: case Ijk_NoRedir:
+ case Ijk_Yield: case Ijk_SigTRAP: {
+ HReg r = iselIntExpr_R(env, next);
+ AMD64AMode* amRIP = AMD64AMode_IR(offsIP, hregAMD64_RBP());
+ addInstr(env, AMD64Instr_XAssisted(r, amRIP, Acc_ALWAYS, jk));
+ return;
+ }
+ default:
+ break;
+ }
+
+ vex_printf( "\n-- PUT(%d) = ", offsIP);
+ ppIRExpr( next );
+ vex_printf( "; exit-");
+ ppIRJumpKind(jk);
+ vex_printf( "\n");
+ vassert(0); // are we expecting any other kind?
}
@@ -4174,14 +4288,21 @@
/* Translate an entire SB to amd64 code. */
-HInstrArray* iselSB_AMD64 ( IRSB* bb, VexArch arch_host,
- VexArchInfo* archinfo_host,
- VexAbiInfo* vbi/*UNUSED*/ )
+HInstrArray* iselSB_AMD64 ( IRSB* bb,
+ VexArch arch_host,
+ VexArchInfo* archinfo_host,
+ VexAbiInfo* vbi/*UNUSED*/,
+ Int offs_Host_EvC_Counter,
+ Int offs_Host_EvC_FailAddr,
+ Bool chainingAllowed,
+ Bool addProfInc,
+ Addr64 max_ga )
{
- Int i, j;
- HReg hreg, hregHI;
- ISelEnv* env;
- UInt hwcaps_host = archinfo_host->hwcaps;
+ Int i, j;
+ HReg hreg, hregHI;
+ ISelEnv* env;
+ UInt hwcaps_host = archinfo_host->hwcaps;
+ AMD64AMode *amCounter, *amFailAddr;
/* sanity ... */
vassert(arch_host == VexArchAMD64);
@@ -4207,7 +4328,9 @@
env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
/* and finally ... */
- env->hwcaps = hwcaps_host;
+ env->chainingAllowed = chainingAllowed;
+ env->hwcaps = hwcaps_host;
+ env->max_ga = max_ga;
/* For each IR temporary, allocate a suitably-kinded virtual
register. */
@@ -4233,12 +4356,25 @@
}
env->vreg_ctr = j;
+ /* The very first instruction must be an event check. */
+ amCounter = AMD64AMode_IR(offs_Host_EvC_Counter, hregAMD64_RBP());
+ amFailAddr = AMD64AMode_IR(offs_Host_EvC_FailAddr, hregAMD64_RBP());
+ addInstr(env, AMD64Instr_EvCheck(amCounter, amFailAddr));
+
+ /* Possibly a block counter increment (for profiling). At this
+ point we don't know the address of the counter, so just pretend
+ it is zero. It will have to be patched later, but before this
+ translation is used, by a call to LibVEX_patchProfCtr. */
+ if (addProfInc) {
+ addInstr(env, AMD64Instr_ProfInc());
+ }
+
/* Ok, finally we can iterate over the statements. */
for (i = 0; i < bb->stmts_used; i++)
if (bb->stmts[i])
- iselStmt(env,bb->stmts[i]);
+ iselStmt(env, bb->stmts[i]);
- iselNext(env,bb->next,bb->jumpkind);
+ iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
/* record the number of vregs we used. */
env->code->n_vregs = env->vreg_ctr;
Modified: branches/TCHAIN/priv/guest_ppc_toIR.c (+11 -11)
===================================================================
--- branches/TCHAIN/priv/guest_ppc_toIR.c 2012-04-02 22:24:12 +01:00 (rev 2272)
+++ branches/TCHAIN/priv/guest_ppc_toIR.c 2012-04-02 22:54:49 +01:00 (rev 2273)
@@ -1500,7 +1500,7 @@
if (mode64) {
vassert(typeOfIRTemp(irsb->tyenv, addr) == Ity_I64);
stmt(
- IRStmt_Exit(
+ IRStmt_Exit3(
binop(Iop_CmpNE64,
binop(Iop_And64, mkexpr(addr), mkU64(align-1)),
mkU64(0)),
@@ -1511,7 +1511,7 @@
} else {
vassert(typeOfIRTemp(irsb->tyenv, addr) == Ity_I32);
stmt(
- IRStmt_Exit(
+ IRStmt_Exit3(
binop(Iop_CmpNE32,
binop(Iop_And32, mkexpr(addr), mkU32(align-1)),
mkU32(0)),
@@ -2690,7 +2690,7 @@
so that Valgrind's dispatcher sees the warning. */
putGST( PPC_GST_EMWARN, mkU32(ew) );
stmt(
- IRStmt_Exit(
+ IRStmt_Exit3(
binop(Iop_CmpNE32, mkU32(ew), mkU32(EmWarn_NONE)),
Ijk_EmWarn,
mkSzConst( ty, nextInsnAddr()) ));
@@ -4975,7 +4975,7 @@
for (i = 0; i < maxBytes; i++) {
/* if (nBytes < (i+1)) goto NIA; */
- stmt( IRStmt_Exit( binop(Iop_CmpLT32U, e_nbytes, mkU32(i+1)),
+ stmt( IRStmt_Exit3( binop(Iop_CmpLT32U, e_nbytes, mkU32(i+1)),
Ijk_Boring,
mkSzConst( ty, nextInsnAddr()) ));
/* when crossing into a new dest register, set it to zero. */
@@ -5026,7 +5026,7 @@
for (i = 0; i < maxBytes; i++) {
/* if (nBytes < (i+1)) goto NIA; */
- stmt( IRStmt_Exit( binop(Iop_CmpLT32U, e_nbytes, mkU32(i+1)),
+ stmt( IRStmt_Exit3( binop(Iop_CmpLT32U, e_nbytes, mkU32(i+1)),
Ijk_Boring,
mkSzConst( ty, nextInsnAddr() ) ));
/* check for crossing into a new src register. */
@@ -5301,7 +5301,7 @@
cond_ok is either zero or nonzero, since that's the cheapest
way to compute it. Anding them together gives a value which
is either zero or non zero and so that's what we must test
- for in the IRStmt_Exit. */
+ for in the IRStmt_Exit3. */
assign( ctr_ok, branch_ctr_ok( BO ) );
assign( cond_ok, branch_cond_ok( BO, BI ) );
assign( do_branch,
@@ -5316,7 +5316,7 @@
if (flag_LK)
putGST( PPC_GST_LR, e_nia );
- stmt( IRStmt_Exit(
+ stmt( IRStmt_Exit3(
binop(Iop_CmpNE32, mkexpr(do_branch), mkU32(0)),
flag_LK ? Ijk_Call : Ijk_Boring,
mkSzConst(ty, tgt) ) );
@@ -5351,7 +5351,7 @@
if (flag_LK)
putGST( PPC_GST_LR, e_nia );
- stmt( IRStmt_Exit(
+ stmt( IRStmt_Exit3(
binop(Iop_CmpEQ32, mkexpr(cond_ok), mkU32(0)),
Ijk_Boring,
c_nia ));
@@ -5391,7 +5391,7 @@
if (flag_LK)
putGST( PPC_GST_LR, e_nia );
- stmt( IRStmt_Exit(
+ stmt( IRStmt_Exit3(
binop(Iop_CmpEQ32, mkexpr(do_branch), mkU32(0)),
Ijk_Boring,
c_nia ));
@@ -5558,7 +5558,7 @@
if ((TO & b11100) == b11100 || (TO & b00111) == b00111) {
/* Unconditional trap. Just do the exit without
testing the arguments. */
- stmt( IRStmt_Exit(
+ stmt( IRStmt_Exit3(
binop(opCMPEQ, const0, const0),
Ijk_SigTRAP,
mode64 ? IRConst_U64(cia) : IRConst_U32((UInt)cia)
@@ -5601,7 +5601,7 @@
tmp = binop(opAND, binop(opCMPORDU, argLe, argRe), const4);
cond = binop(opOR, tmp, cond);
}
- stmt( IRStmt_Exit(
+ stmt( IRStmt_Exit3(
binop(opCMPNE, cond, const0),
Ijk_SigTRAP,
mode64 ? IRConst_U64(cia) : IRConst_U32((UInt)cia)
Modified: branches/TCHAIN/priv/guest_amd64_defs.h (+0 -1)
===================================================================
--- branches/TCHAIN/priv/guest_amd64_defs.h 2012-04-02 22:24:12 +01:00 (rev 2272)
+++ branches/TCHAIN/priv/guest_amd64_defs.h 2012-04-02 22:54:49 +01:00 (rev 2273)
@@ -47,7 +47,6 @@
bb_to_IR.h. */
extern
DisResult disInstr_AMD64 ( IRSB* irbb,
- Bool put_IP,
Bool (*resteerOkFn) ( void*, Addr64 ),
Bool resteerCisOk,
void* callback_opaque,
Modified: branches/TCHAIN/pub/libvex_trc_values.h (+3 -0)
===================================================================
--- branches/TCHAIN/pub/libvex_trc_values.h 2012-04-02 22:24:12 +01:00 (rev 2272)
+++ branches/TCHAIN/pub/libvex_trc_values.h 2012-04-02 22:54:49 +01:00 (rev 2273)
@@ -80,6 +80,9 @@
#define VEX_TRC_JMP_SYS_SYSENTER 79 /* do syscall before continuing */
+#define VEX_TRC_JMP_BORING 95 /* return to sched, but just
+ keep going; no special action */
+
#endif /* ndef __LIBVEX_TRC_VALUES_H */
/*---------------------------------------------------------------*/
Modified: branches/TCHAIN/priv/guest_x86_toIR.c (+156 -114)
===================================================================
--- branches/TCHAIN/priv/guest_x86_toIR.c 2012-04-02 22:24:12 +01:00 (rev 2272)
+++ branches/TCHAIN/priv/guest_x86_toIR.c 2012-04-02 22:54:49 +01:00 (rev 2273)
@@ -768,7 +768,8 @@
binop( mkSizedOp(tyE,Iop_CasCmpNE8),
mkexpr(oldTmp), mkexpr(expTmp) ),
Ijk_Boring, /*Ijk_NoRedir*/
- IRConst_U32( restart_point )
+ IRConst_U32( restart_point ),
+ OFFB_EIP
));
}
@@ -1340,36 +1341,55 @@
/*--- JMP helpers ---*/
/*------------------------------------------------------------*/
-static void jmp_lit( IRJumpKind kind, Addr32 d32 )
+static void jmp_lit( /*MOD*/DisResult* dres,
+ IRJumpKind kind, Addr32 d32 )
{
- irsb->next = mkU32(d32);
- irsb->jumpkind = kind;
+ vassert(dres->whatNext == Dis_Continue);
+ vassert(dres->len == 0);
+ vassert(dres->continueAt == 0);
+ vassert(dres->jk_StopHere == Ijk_INVALID);
+ dres->whatNext = Dis_StopHere;
+ dres->jk_StopHere = kind;
+ stmt( IRStmt_Put( OFFB_EIP, mkU32(d32) ) );
}
-static void jmp_treg( IRJumpKind kind, IRTemp t )
+static void jmp_treg( /*MOD*/DisResult* dres,
+ IRJumpKind kind, IRTemp t )
{
- irsb->next = mkexpr(t);
- irsb->jumpkind = kind;
+ vassert(dres->whatNext == Dis_Continue);
+ vassert(dres->len == 0);
+ vassert(dres->continueAt == 0);
+ vassert(dres->jk_StopHere == Ijk_INVALID);
+ dres->whatNext = Dis_StopHere;
+ dres->jk_StopHere = kind;
+ stmt( IRStmt_Put( OFFB_EIP, mkexpr(t) ) );
}
static
-void jcc_01( X86Condcode cond, Addr32 d32_false, Addr32 d32_true )
+void jcc_01( /*MOD*/DisResult* dres,
+ X86Condcode cond, Addr32 d32_false, Addr32 d32_true )
{
Bool invert;
X86Condcode condPos;
+ vassert(dres->whatNext == Dis_Continue);
+ vassert(dres->len == 0);
+ vassert(dres->continueAt == 0);
+ vassert(dres->jk_StopHere == Ijk_INVALID);
+ dres->whatNext = Dis_StopHere;
+ dres->jk_StopHere = Ijk_Boring;
condPos = positiveIse_X86Condcode ( cond, &invert );
if (invert) {
stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
Ijk_Boring,
- IRConst_U32(d32_false) ) );
- irsb->next = mkU32(d32_true);
- irsb->jumpkind = Ijk_Boring;
+ IRConst_U32(d32_false),
+ OFFB_EIP ) );
+ stmt( IRStmt_Put( OFFB_EIP, mkU32(d32_true) ) );
} else {
stmt( IRStmt_Exit( mk_x86g_calculate_condition(condPos),
Ijk_Boring,
- IRConst_U32(d32_true) ) );
- irsb->next = mkU32(d32_false);
- irsb->jumpkind = Ijk_Boring;
+ IRConst_U32(d32_true),
+ OFFB_EIP ) );
+ stmt( IRStmt_Put( OFFB_EIP, mkU32(d32_false) ) );
}
}
@@ -1450,7 +1470,8 @@
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 ),
+ OFFB_EIP
)
);
@@ -3009,7 +3030,7 @@
/* Group 5 extended opcodes. */
static
UInt dis_Grp5 ( UChar sorb, Bool locked, Int sz, Int delta,
- DisResult* dres, Bool* decode_OK )
+ /*MOD*/DisResult* dres, /*OUT*/Bool* decode_OK )
{
Int len;
UChar modrm;
@@ -3054,13 +3075,13 @@
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));
- jmp_treg(Ijk_Call,t1);
- dres->whatNext = Dis_StopHere;
+ jmp_treg(dres, Ijk_Call, t1);
+ vassert(dres->whatNext == Dis_StopHere);
break;
case 4: /* jmp Ev */
vassert(sz == 4);
- jmp_treg(Ijk_Boring,t1);
- dres->whatNext = Dis_StopHere;
+ jmp_treg(dres, Ijk_Boring, t1);
+ vassert(dres->whatNext == Dis_StopHere);
break;
case 6: /* PUSH Ev */
vassert(sz == 4 || sz == 2);
@@ -3110,13 +3131,13 @@
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));
- jmp_treg(Ijk_Call,t1);
- dres->whatNext = Dis_StopHere;
+ jmp_treg(dres, Ijk_Call, t1);
+ vassert(dres->whatNext == Dis_StopHere);
break;
case 4: /* JMP Ev */
vassert(sz == 4);
- jmp_treg(Ijk_Boring,t1);
- dres->whatNext = Dis_StopHere;
+ jmp_treg(dres, Ijk_Boring, t1);
+ vassert(dres->whatNext == Dis_StopHere);
break;
case 6: /* PUSH Ev */
vassert(sz == 4 || sz == 2);
@@ -3253,7 +3274,8 @@
We assume the insn is the last one in the basic block, and so emit a jump
to the next insn, rather than just falling through. */
static
-void dis_REP_op ( X86Condcode cond,
+void dis_REP_op ( /*MOD*/DisResult* dres,
+ X86Condcode cond,
void (*dis_OP)(Int, IRTemp),
Int sz, Addr32 eip, Addr32 eip_next, HChar* name )
{
@@ -3264,7 +3286,7 @@
stmt( IRStmt_Exit( binop(Iop_CmpEQ32,mkexpr(tc),mkU32(0)),
Ijk_Boring,
- IRConst_U32(eip_next) ) );
+ IRConst_U32(eip_next), OFFB_EIP ) );
putIReg(4, R_ECX, binop(Iop_Sub32, mkexpr(tc), mkU32(1)) );
@@ -3272,12 +3294,14 @@
dis_OP (sz, t_inc);
if (cond == X86CondAlways) {
- jmp_lit(Ijk_Boring,eip);
+ jmp_lit(dres, Ijk_Boring, eip);
+ vassert(dres->whatNext == Dis_StopHere);
} else {
stmt( IRStmt_Exit( mk_x86g_calculate_condition(cond),
Ijk_Boring,
- IRConst_U32(eip) ) );
- jmp_lit(Ijk_Boring,eip_next);
+ IRConst_U32(eip), OFFB_EIP ) );
+ jmp_lit(dres, Ijk_Boring, eip_next);
+ vassert(dres->whatNext == Dis_StopHere);
}
DIP("%s%c\n", name, nameISize(sz));
}
@@ -3958,7 +3982,8 @@
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),
+ OFFB_EIP
)
);
@@ -4000,7 +4025,8 @@
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),
+ OFFB_EIP
)
);
break;
@@ -4948,7 +4974,8 @@
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),
+ OFFB_EIP
)
);
@@ -6811,13 +6838,15 @@
}
static
-void dis_ret ( UInt d32 )
+void dis_ret ( /*MOD*/DisResult* dres, UInt d32 )
{
- IRTemp t1 = newTemp(Ity_I32), t2 = newTemp(Ity_I32);
+ IRTemp t1 = newTemp(Ity_I32);
+ IRTemp t2 = newTemp(Ity_I32);
assign(t1, getIReg(4,R_ESP));
assign(t2, loadLE(Ity_I32,mkexpr(t1)));
putIReg(4, R_ESP,binop(Iop_Add32, mkexpr(t1), mkU32(4+d32)));
- jmp_treg(Ijk_Ret,t2);
+ jmp_treg(dres, Ijk_Ret, t2);
+ vassert(dres->whatNext == Dis_StopHere);
}
/*------------------------------------------------------------*/
@@ -7523,7 +7552,8 @@
binop(Iop_And32, mkexpr(t1), mkU32(1<<18)),
mkU32(0) ),
Ijk_EmWarn,
- IRConst_U32( next_insn_EIP )
+ IRConst_U32( next_insn_EIP ),
+ OFFB_EIP
)
);
}
@@ -7700,7 +7730,8 @@
binop(Iop_And32,mkexpr(effective_addr),mkU32(0xF)),
mkU32(0)),
Ijk_SigSEGV,
- IRConst_U32(guest_EIP_curr_instr)
+ IRConst_U32(guest_EIP_curr_instr),
+ OFFB_EIP
)
);
}
@@ -7854,7 +7885,6 @@
static
DisResult disInstr_X86_WRK (
/*OUT*/Bool* expect_CAS,
- Bool put_IP,
Bool (*resteerOkFn) ( /*opaque*/void*, Addr64 ),
Bool resteerCisOk,
void* callback_opaque,
@@ -7893,9 +7923,10 @@
Bool pfx_lock = False;
/* Set result defaults. */
- dres.whatNext = Dis_Continue;
- dres.len = 0;
- dres.continueAt = 0;
+ dres.whatNext = Dis_Continue;
+ dres.len = 0;
+ dres.continueAt = 0;
+ dres.jk_StopHere = Ijk_INVALID;
*expect_CAS = False;
@@ -7904,10 +7935,6 @@
vassert(guest_EIP_bbstart + delta == guest_EIP_curr_instr);
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 "Special" instructions (see comment at top of file). */
{
UChar* code = (UChar*)(guest_code + delta);
@@ -7926,8 +7953,8 @@
/* %EDX = client_request ( %EAX ) */
DIP("%%edx = client_request ( %%eax )\n");
delta += 14;
- jmp_lit(Ijk_ClientReq, guest_EIP_bbstart+delta);
- dres.whatNext = Dis_StopHere;
+ jmp_lit(&dres, Ijk_ClientReq, guest_EIP_bbstart+delta);
+ vassert(dres.whatNext == Dis_StopHere);
goto decode_success;
}
else
@@ -7949,8 +7976,8 @@
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));
- jmp_treg(Ijk_NoRedir,t1);
- dres.whatNext = Dis_StopHere;
+ jmp_treg(&dres, Ijk_NoRedir, t1);
+ vassert(dres.whatNext == Dis_StopHere);
goto decode_success;
}
/* We don't know what it is. */
@@ -8537,7 +8564,8 @@
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),
+ OFFB_EIP
)
);
goto decode_success;
@@ -12729,7 +12757,8 @@
stmt( IRStmt_Exit(
binop(Iop_CmpEQ16, getIReg(2,R_ECX), mkU16(0)),
Ijk_Boring,
- IRConst_U32(d32)
+ IRConst_U32(d32),
+ OFFB_EIP
));
DIP("jcxz 0x%x\n", d32);
goto decode_success;
@@ -12752,13 +12781,11 @@
case 0xC2: /* RET imm16 */
d32 = getUDisp16(delta);
delta += 2;
- dis_ret(d32);
- dres.whatNext = Dis_StopHere;
+ dis_ret(&dres, d32);
DIP("ret %d\n", (Int)d32);
break;
case 0xC3: /* RET */
- dis_ret(0);
- dres.whatNext = Dis_StopHere;
+ dis_ret(&dres, 0);
DIP("ret\n");
break;
@@ -12782,8 +12809,8 @@
/* set %EFLAGS */
set_EFLAGS_from_value( t4, False/*!emit_AC_emwarn*/, 0/*unused*/ );
/* goto new EIP value */
- jmp_treg(Ijk_Ret,t2);
- dres.whatNext = Dis_StopHere;
+ jmp_treg(&dres, Ijk_Ret, t2);
+ vassert(dres.whatNext == Dis_StopHere);
DIP("iret (very kludgey)\n");
break;
@@ -12815,8 +12842,8 @@
dres.whatNext = Dis_ResteerU;
dres.continueAt = (Addr64)(Addr32)d32;
} else {
- jmp_lit(Ijk_Call,d32);
- dres.whatNext = Dis_StopHere;
+ jmp_lit(&dres, Ijk_Call, d32);
+ vassert(dres.whatNext == Dis_StopHere);
}
DIP("call 0x%x\n",d32);
}
@@ -13060,8 +13087,8 @@
/* ------------------------ INT ------------------------ */
case 0xCC: /* INT 3 */
- jmp_lit(Ijk_SigTRAP,((Addr32)guest_EIP_bbstart)+delta);
- dres.whatNext = Dis_StopHere;
+ jmp_lit(&dres, Ijk_SigTRAP, ((Addr32)guest_EIP_bbstart)+delta);
+ vassert(dres.whatNext == Dis_StopHere);
DIP("int $0x3\n");
break;
@@ -13082,8 +13109,8 @@
This used to handle just 0x40-0x43; Jikes RVM uses a larger
range (0x3F-0x49), and this allows some slack as well. */
if (d32 >= 0x3F && d32 <= 0x4F) {
- jmp_lit(Ijk_SigSEGV,((Addr32)guest_EIP_bbstart)+delta-2);
- dres.whatNext = Dis_StopHere;
+ jmp_lit(&dres, Ijk_SigSEGV, ((Addr32)guest_EIP_bbstart)+delta-2);
+ vassert(dres.whatNext == Dis_StopHere);
DIP("int $0x%x\n", (Int)d32);
break;
}
@@ -13095,24 +13122,24 @@
if (d32 == 0x80) {
stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
mkU32(guest_EIP_curr_instr) ) );
- jmp_lit(Ijk_Sys_int128,((Addr32)guest_EIP_bbstart)+delta);
- dres.whatNext = Dis_StopHere;
+ jmp_lit(&dres, Ijk_Sys_int128, ((Addr32)guest_EIP_bbstart)+delta);
+ vassert(dres.whatNext == Dis_StopHere);
DIP("int $0x80\n");
break;
}
if (d32 == 0x81) {
stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
mkU32(guest_EIP_curr_instr) ) );
- jmp_lit(Ijk_Sys_int129,((Addr32)guest_EIP_bbstart)+delta);
- dres.whatNext = Dis_StopHere;
+ jmp_lit(&dres, Ijk_Sys_int129, ((Addr32)guest_EIP_bbstart)+delta);
+ vassert(dres.whatNext == Dis_StopHere);
DIP("int $0x81\n");
break;
}
if (d32 == 0x82) {
stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
mkU32(guest_EIP_curr_instr) ) );
- jmp_lit(Ijk_Sys_int130,((Addr32)guest_EIP_bbstart)+delta);
- dres.whatNext = Dis_StopHere;
+ jmp_lit(&dres, Ijk_Sys_int130, ((Addr32)guest_EIP_bbstart)+delta);
+ vassert(dres.whatNext == Dis_StopHere);
DIP("int $0x82\n");
break;
}
@@ -13129,8 +13156,8 @@
dres.whatNext = Dis_ResteerU;
dres.continueAt = (Addr64)(Addr32)d32;
} else {
- jmp_lit(Ijk_Boring,d32);
- dres.whatNext = Dis_StopHere;
+ jmp_lit(&dres, Ijk_Boring, d32);
+ vassert(dres.whatNext == Dis_StopHere);
}
DIP("jmp-8 0x%x\n", d32);
break;
@@ -13143,8 +13170,8 @@
dres.whatNext = Dis_ResteerU;
dres.continueAt = (Addr64)(Addr32)d32;
} else {
- jmp_lit(Ijk_Boring,d32);
- dres.whatNext = Dis_StopHere;
+ jmp_lit(&dres, Ijk_Boring, d32);
+ vassert(dres.whatNext == Dis_StopHere);
}
DIP("jmp 0x%x\n", d32);
break;
@@ -13185,7 +13212,8 @@
stmt( IRStmt_Exit(
mk_x86g_calculate_condition((X86Condcode)(1 ^ (opc - 0x70))),
Ijk_Boring,
- IRConst_U32(guest_EIP_bbstart+delta) ) );
+ IRConst_U32(guest_EIP_bbstart+delta),
+ OFFB_EIP ) );
dres.whatNext = Dis_ResteerC;
dres.continueAt = (Addr64)(Addr32)d32;
comment = "(assumed taken)";
@@ -13204,7 +13232,8 @@
stmt( IRStmt_Exit(
mk_x86g_calculate_condition((X86Condcode)(opc - 0x70)),
Ijk_Boring,
- IRConst_U32(d32) ) );
+ IRConst_U32(d32),
+ OFFB_EIP ) );
dres.whatNext = Dis_ResteerC;
dres.continueAt = (Addr64)(Addr32)(guest_EIP_bbstart+delta);
comment = "(assumed not taken)";
@@ -13212,9 +13241,9 @@
else {
/* Conservative default translation - end the block at this
point. */
- jcc_01( (X86Condcode)(opc - 0x70),
+ jcc_01( &dres, (X86Condcode)(opc - 0x70),
(Addr32)(guest_EIP_bbstart+delta), d32);
- dres.whatNext = Dis_StopHere;
+ vassert(dres.whatNext == Dis_StopHere);
}
DIP("j%s-8 0x%x %s\n", name_X86Condcode(opc - 0x70), d32, comment);
break;
@@ -13227,7 +13256,8 @@
stmt( IRStmt_Exit(
binop(Iop_CmpEQ32, getIReg(4,R_ECX), mkU32(0)),
Ijk_Boring,
- IRConst_U32(d32)
+ IRConst_U32(d32),
+ OFFB_EIP
));
DIP("jecxz 0x%x\n", d32);
break;
@@ -13268,7 +13298,7 @@
default:
vassert(0);
}
- stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U32(d32)) );
+ stmt( IRStmt_Exit(cond, Ijk_Boring, IRConst_U32(d32), OFFB_EIP) );
DIP("loop%s 0x%x\n", xtra, d32);
break;
@@ -13948,33 +13978,32 @@
abyte = getIByte(delta); delta++;
if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
- dres.whatNext = Dis_StopHere;
switch (abyte) {
/* According to the Intel manual, "repne movs" should never occur, but
* in practice it has happened, so allow for it here... */
case 0xA4: sz = 1; /* REPNE MOVS<sz> */
case 0xA5:
- dis_REP_op ( X86CondNZ, dis_MOVS, sz, eip_orig,
- guest_EIP_bbstart+delta, "repne movs" );
+ dis_REP_op ( &dres, X86CondNZ, dis_MOVS, sz, eip_orig,
+ guest_EIP_bbstart+delta, "repne movs" );
break;
case 0xA6: sz = 1; /* REPNE CMP<sz> */
case 0xA7:
- dis_REP_op ( X86CondNZ, dis_CMPS, sz, eip_orig,
- guest_EIP_bbstart+delta, "repne cmps" );
+ dis_REP_op ( &dres, X86CondNZ, dis_CMPS, sz, eip_orig,
+ guest_EIP_bbstart+delta, "repne cmps" );
break;
case 0xAA: sz = 1; /* REPNE STOS<sz> */
case 0xAB:
- dis_REP_op ( X86CondNZ, dis_STOS, sz, eip_orig,
- guest_EIP_bbstart+delta, "repne stos" );
+ dis_REP_op ( &dres, X86CondNZ, dis_STOS, sz, eip_orig,
+ guest_EIP_bbstart+delta, "repne stos" );
break;
case 0xAE: sz = 1; /* REPNE SCAS<sz> */
case 0xAF:
- dis_REP_op ( X86CondNZ, dis_SCAS, sz, eip_orig,
- guest_EIP_bbstart+delta, "repne scas" );
+ dis_REP_op ( &dres, X86CondNZ, dis_SCAS, sz, eip_orig,
+ guest_EIP_bbstart+delta, "repne scas" );
break;
default:
@@ -13991,37 +14020,36 @@
abyte = getIByte(delta); delta++;
if (abyte == 0x66) { sz = 2; abyte = getIByte(delta); delta++; }
- 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" );
+ dis_REP_op ( &dres, X86CondAlways, dis_MOVS, sz, eip_orig,
+ 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" );
+ dis_REP_op ( &dres, X86CondZ, dis_CMPS, sz, eip_orig,
+ 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" );
+ dis_REP_op ( &dres, X86CondAlways, dis_STOS, sz, eip_orig,
+ guest_EIP_bbstart+delta, "rep stos" );
break;
case 0xAC: sz = 1; /* REP LODS<sz> */
case 0xAD:
- dis_REP_op ( X86CondAlways, dis_LODS, sz, eip_orig,
- guest_EIP_bbstart+delta, "rep lods" );
+ dis_REP_op ( &dres, X86CondAlways, dis_LODS, sz, eip_orig,
+ guest_EIP_bbstart+delta, "rep lods" );
break;
case 0xAE: sz = 1; /* REPE SCAS<sz> */
case 0xAF:
- dis_REP_op ( X86CondZ, dis_SCAS, sz, eip_orig,
- guest_EIP_bbstart+delta, "repe scas" );
+ dis_REP_op ( &dres, X86CondZ, dis_SCAS, sz, eip_orig,
+ guest_EIP_bbstart+delta, "repe scas" );
break;
case 0x90: /* REP NOP (PAUSE) */
@@ -14029,13 +14057,12 @@
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);
- dres.whatNext = Dis_StopHere;
+ jmp_lit(&dres, Ijk_Yield, ((Addr32)guest_EIP_bbstart)+delta);
+ vassert(dres.whatNext == Dis_StopHere);
break;
case 0xC3: /* REP RET -- same as normal ret? */
- dis_ret(0);
- dres.whatNext = Dis_StopHere;
+ dis_ret(&dres, 0);
DIP("rep ret\n");
break;
@@ -14741,7 +14768,8 @@
mk_x86g_calculate_condition((X86Condcode)
(1 ^ (opc - 0x80))),
Ijk_Boring,
- IRConst_U32(guest_EIP_bbstart+delta) ) );
+ IRConst_U32(guest_EIP_bbstart+delta),
+ OFFB_EIP ) );
dres.whatNext = Dis_ResteerC;
dres.continueAt = (Addr64)(Addr32)d32;
comment = "(assumed taken)";
@@ -14760,7 +14788,8 @@
stmt( IRStmt_Exit(
mk_x86g_calculate_condition((X86Condcode)(opc - 0x80)),
Ijk_Boring,
- IRConst_U32(d32) ) );
+ IRConst_U32(d32),
+ OFFB_EIP ) );
dres.whatNext = Dis_ResteerC;
dres.continueAt = (Addr64)(Addr32)(guest_EIP_bbstart+delta);
comment = "(assumed not taken)";
@@ -14768,9 +14797,9 @@
else {
/* Conservative default translation - end the block at
this point. */
- jcc_01( (X86Condcode)(opc - 0x80),
+ jcc_01( &dres, (X86Condcode)(opc - 0x80),
(Addr32)(guest_EIP_bbstart+delta), d32);
- dres.whatNext = Dis_StopHere;
+ vassert(dres.whatNext == Dis_StopHere);
}
DIP("j%s-32 0x%x %s\n", name_X86Condcode(opc - 0x80), d32, comment);
break;
@@ -14896,8 +14925,8 @@
point if the syscall needs to be restarted. */
stmt( IRStmt_Put( OFFB_IP_AT_SYSCALL,
mkU32(guest_EIP_curr_instr) ) );
- jmp_lit(Ijk_Sys_sysenter, 0/*bogus next EIP value*/);
- dres.whatNext = Dis_StopHere;
+ jmp_lit(&dres, Ijk_Sys_sysenter, 0/*bogus next EIP value*/);
+ vassert(dres.whatNext == Dis_StopHere);
DIP("sysenter");
break;
@@ -15073,8 +15102,8 @@
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);
- dres.whatNext = Dis_StopHere;
+ jmp_lit(&dres, Ijk_NoDecode, guest_EIP_curr_instr);
+ vassert(dres.whatNext == Dis_StopHere);
dres.len = 0;
/* We also need to say that a CAS is not expected now, regardless
of what it might have been set to at the start of the function,
@@ -15088,6 +15117,20 @@
decode_success:
/* All decode successes end up here. */
+ switch (dres.whatNext) {
+ case Dis_Continue:
+ stmt( IRStmt_Put( OFFB_EIP, mkU32(guest_EIP_bbstart + delta) ) );
+ break;
+ case Dis_ResteerU:
+ case Dis_ResteerC:
+ stmt( IRStmt_Put( OFFB_EIP, mkU32(dres.continueAt) ) );
+ break;
+ case Dis_StopHere:
+ break;
+ default:
+ vassert(0);
+ }
+
DIP("\n");
dres.len = delta - delta_start;
return dres;
@@ -15105,7 +15148,6 @@
is located in host memory at &guest_code[delta]. */
DisResult disInstr_X86 ( IRSB* irsb_IN,
- Bool put_IP,
Bool (*resteerOkFn) ( void*, Addr64 ),
Bool resteerCisOk,
void* callback_opaque,
@@ -15131,7 +15173,7 @@
x1 = irsb_IN->stmts_used;
expect_CAS = False;
- dres = disInstr_X86_WRK ( &expect_CAS, put_IP, resteerOkFn,
+ dres = disInstr_X86_WRK ( &expect_CAS, resteerOkFn,
resteerCisOk,
callback_opaque,
delta, archinfo, abiinfo );
@@ -15151,7 +15193,7 @@
/* inconsistency detected. re-disassemble the instruction so as
to generate a useful error message; then assert. */
vex_traceflags |= VEX_TRACE_FE;
- dres = disInstr_X86_WRK ( &expect_CAS, put_IP, resteerOkFn,
+ dres = disInstr_X86_WRK ( &expect_CAS, resteerOkFn,
resteerCisOk,
callback_opaque,
delta, archinfo, abiinfo );
Modified: branches/TCHAIN/Makefile-gcc (+3 -1)
===================================================================
--- branches/TCHAIN/Makefile-gcc 2012-04-02 22:24:12 +01:00 (rev 2272)
+++ branches/TCHAIN/Makefile-gcc 2012-04-02 22:54:49 +01:00 (rev 2273)
@@ -88,7 +88,9 @@
-Wpointer-arith -Wbad-function-cast -Wcast-qual \
-Wcast-align -Wmissing-declarations \
-Wno-pointer-sign \
- $(EXTRA_CFLAGS) -g -O2 -fstrict-aliasing
+ $(EXTRA_CFLAGS) -g -O2 -fstrict-aliasing \
+ \
+ -O
#CC = icc
#CCFLAGS = -g -Wall -wd981 -wd279 -wd1287 -wd869 -wd111 -wd188 -wd186
Modified: branches/TCHAIN/priv/host_x86_isel.c (+164 -25)
===================================================================
--- branches/TCHAIN/priv/host_x86_isel.c 2012-04-02 22:24:12 +01:00 (rev 2272)
+++ branches/TCHAIN/priv/host_x86_isel.c 2012-04-02 22:54:49 +01:00 (rev 2273)
@@ -154,21 +154,38 @@
- The host subarchitecture we are selecting insns for.
This is set at the start and does not change.
- Note, this is all host-independent. */
+ - A Bool for indicating whether we may generate chain-me
+ instructions for control flow transfers, or whether we must use
+ XAssisted.
+ - The maximum guest address of any guest insn in this block.
+ Actually, the address of the highest-addressed byte from any insn
+ in this block. Is set at the start and does not change. This is
+ used for detecting jumps which are definitely forward-edges from
+ this block, and therefore can be made (chained) to the fast entry
+ point of the destination, thereby avoiding the destination's
+ event check.
+
+ Note, this is all (well, mostly) host-independent.
+*/
+
typedef
struct {
+ /* Constant -- are set at the start and do not change. */
IRTypeEnv* type_env;
HReg* vregmap;
HReg* vregmapHI;
Int n_vregmap;
+ UInt hwcaps;
+
+ Bool chainingAllowed;
+ Addr64 max_ga;
+
+ /* These are modified as we go along. */
HInstrArray* code;
-
Int vreg_ctr;
-
- UInt hwcaps;
}
ISelEnv;
@@ -4038,14 +4055,48 @@
/* --------- EXIT --------- */
case Ist_Exit: {
- X86RI* dst;
- X86CondCode cc;
if (stmt->Ist.Exit.dst->tag != Ico_U32)
- vpanic("isel_x86: Ist_Exit: dst is not a 32-bit value");
- dst = iselIntExpr_RI(env, IRExpr_Const(stmt->Ist.Exit.dst));
- cc = iselCondCode(env,stmt->Ist.Exit.guard);
- addInstr(env, X86Instr_Goto(stmt->Ist.Exit.jk, cc, dst));
- return;
+ vpanic("iselStmt(x86): Ist_Exit: dst is not a 32-bit value");
+
+ X86CondCode cc = iselCondCode(env, stmt->Ist.Exit.guard);
+ X86AMode* amEIP = X86AMode_IR(stmt->Ist.Exit.offsIP,
+ hregX86_EBP());
+
+ /* Case: boring transfer to known address */
+ if (stmt->Ist.Exit.jk == Ijk_Boring) {
+ if (env->chainingAllowed) {
+ /* .. almost always true .. */
+ /* Skip the event check at the dst if this is a forwards
+ edge. */
+ Bool toFastEP
+ = ((Addr32)stmt->Ist.Exit.dst->Ico.U32) > env->max_ga;
+ if (0) vex_printf("%s", toFastEP ? "Y" : ",");
+ addInstr(env, X86Instr_XDirect(stmt->Ist.Exit.dst->Ico.U32,
+ amEIP, cc, toFastEP));
+ } else {
+ /* .. very occasionally .. */
+ /* We can't use chaining, so ask for an assisted transfer,
+ as that's the only alternative that is allowable. */
+ HReg r = iselIntExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
+ addInstr(env, X86Instr_XAssisted(r, amEIP, cc, Ijk_Boring));
+ }
+ return;
+ }
+
+ /* Case: assisted transfer to arbitrary address */
+ switch (stmt->Ist.Exit.jk) {
+ case Ijk_MapFail:
+ case Ijk_SigSEGV: case Ijk_TInval: case Ijk_EmWarn: {
+ HReg r = iselIntExpr_R(env, IRExpr_Const(stmt->Ist.Exit.dst));
+ addInstr(env, X86Instr_XAssisted(r, amEIP, cc, stmt->Ist.Exit.jk));
+ return;
+ }
+ default:
+ break;
+ }
+
+ /* Do we ever expect to see any other kind? */
+ goto stmt_fail;
}
default: break;
@@ -4060,18 +4111,82 @@
/*--- ISEL: Basic block terminators (Nexts) ---*/
/*---------------------------------------------------------*/
-static void iselNext ( ISelEnv* env, IRExpr* next, IRJumpKind jk )
+static void iselNext ( ISelEnv* env,
+ IRExpr* next, IRJumpKind jk, Int offsIP )
{
- X86RI* ri;
if (vex_traceflags & VEX_TRACE_VCODE) {
- vex_printf("\n-- goto {");
+ vex_printf( "\n-- PUT(%d) = ", offsIP);
+ ppIRExpr( next );
+ vex_printf( "; exit-");
ppIRJumpKind(jk);
- vex_printf("} ");
- ppIRExpr(next);
- vex_printf("\n");
+ vex_printf( "\n");
}
- ri = iselIntExpr_RI(env, next);
- addInstr(env, X86Instr_Goto(jk, Xcc_ALWAYS,ri));
+
+ /* Case: boring transfer to known address */
+ if (next->tag == Iex_Const) {
+ IRConst* cdst = next->Iex.Const.con;
+ vassert(cdst->tag == Ico_U32);
+ if (jk == Ijk_Boring || jk == Ijk_Call) {
+ /* Boring transfer to known address */
+ X86AMode* amEIP = X86AMode_IR(offsIP, hregX86_EBP());
+ if (env->chainingAllowed) {
+ /* .. almost always true .. */
+ /* Skip the event check at the dst if this is a forwards
+ edge. */
+ Bool toFastEP
+ = ((Addr64)cdst->Ico.U32) > env->max_ga;
+ if (0) vex_printf("%s", toFastEP ? "X" : ".");
+ addInstr(env, X86Instr_XDirect(cdst->Ico.U32,
+ amEIP, Xcc_ALWAYS,
+ toFastEP));
+ } else {
+ /* .. very occasionally .. */
+ /* We can't use chaining, so ask for an assisted transfer,
+ as that's the only alternative that is allowable. */
+ HReg r = iselIntExpr_R(env, next);
+ addInstr(env, X86Instr_XAssisted(r, amEIP, Xcc_ALWAYS,
+ Ijk_Boring));
+ }
+ return;
+ }
+ }
+
+ /* Case: call/return (==boring) transfer to any address */
+ switch (jk) {
+ case Ijk_Boring: case Ijk_Ret: case Ijk_Call: {
+ HReg r = iselIntExpr_R(env, next);
+ X86AMode* amEIP = X86AMode_IR(offsIP, hregX86_EBP());
+ if (env->chainingAllowed) {
+ addInstr(env, X86Instr_XIndir(r, amEIP, Xcc_ALWAYS));
+ } else {
+ addInstr(env, X86Instr_XAssisted(r, amEIP, Xcc_ALWAYS,
+ Ijk_Boring));
+ }
+ return;
+ }
+ default:
+ break;
+ }
+
+ /* Case: some other kind of transfer to any address */
+ switch (jk) {
+ case Ijk_Sys_int128: case Ijk_ClientReq: case Ijk_NoRedir:
+ case Ijk_Yield: case Ijk_SigTRAP: {
+ HReg r = iselIntExpr_R(env, next);
+ X86AMode* amEIP = X86AMode_IR(offsIP, hregX86_EBP());
+ addInstr(env, X86Instr_XAssisted(r, amEIP, Xcc_ALWAYS, jk));
+ return;
+ }
+ default:
+ break;
+ }
+
+ vex_printf( "\n-- PUT(%d) = ", offsIP);
+ ppIRExpr( next );
+ vex_printf( "; exit-");
+ ppIRJumpKind(jk);
+ vex_printf( "\n");
+ vassert(0); // are we expecting any other kind?
}
@@ -4081,14 +4196,21 @@
/* Translate an entire SB to x86 code. */
-HInstrArray* iselSB_X86 ( IRSB* bb, VexArch arch_host,
- VexArchInfo* archinfo_host,
- VexAbiInfo* vbi/*UNUSED*/ )
+HInstrArray* iselSB_X86 ( IRSB* bb,
+ VexArch arch_host,
+ VexArchInfo* archinfo_host,
+ VexAbiInfo* vbi/*UNUSED*/,
+ Int offs_Host_EvC_Counter,
+ Int offs_Host_EvC_FailAddr,
+ Bool chainingAllowed,
+ Bool addProfInc,
+ Addr64 max_ga )
{
Int i, j;
HReg hreg, hregHI;
ISelEnv* env;
UInt hwcaps_host = archinfo_host->hwcaps;
+ X86AMode *amCounter, *amFailAddr;
/* sanity ... */
vassert(arch_host == VexArchX86);
@@ -4097,6 +4219,8 @@
| VEX_HWCAPS_X86_SSE2
| VEX_HWCAPS_X86_SSE3
| VEX_HWCAPS_X86_LZCNT)));
+ vassert(sizeof(max_ga) == 8);
+ vassert((max_ga >> 32) == 0);
/* Make up an initial environment to use. */
env = LibVEX_Alloc(sizeof(ISelEnv));
@@ -4115,7 +4239,9 @@
env->vregmapHI = LibVEX_Alloc(env->n_vregmap * sizeof(HReg));
/* and finally ... */
- env->hwcaps = hwcaps_host;
+ env->chainingAllowed = chainingAllowed;
+ env->hwcaps = hwcaps_host;
+ env->max_ga = max_ga;
/* For each IR temporary, allocate a suitably-kinded virtual
register. */
@@ -4140,11 +4266,24 @@
}
env->vreg_ctr = j;
+ /* The very first instruction must be an event check. */
+ amCounter = X86AMode_IR(offs_Host_EvC_Counter, hregX86_EBP());
+ amFailAddr = X86AMode_IR(offs_Host_EvC_FailAddr, hregX86_EBP());
+ addInstr(env, X86Instr_EvCheck(amCounter, amFailAddr));
+
+ /* Possibly a block counter increment (for profiling). At this
+ point we don't know the address of the counter, so just pretend
+ it is zero. It will have to be patched later, but before this
+ translation is used, by a call to LibVEX_patchProfCtr. */
+ if (addProfInc) {
+ addInstr(env, X86Instr_ProfInc());
+ }
+
/* Ok, finally we can iterate over the statements. */
for (i = 0; i < bb->stmts_used; i++)
- iselStmt(env,bb->stmts[i]);
+ iselStmt(env, bb->stmts[i]);
- iselNext(env,bb->next,bb->jumpkind);
+ iselNext(env, bb->next, bb->jumpkind, bb->offsIP);
/* record the number of vregs we used. */
env->code->n_vregs = env->vreg_ctr;
Modified: branches/TCHAIN/priv/host_x86_defs.h (+83 -15)
===================================================================
--- branches/TCHAIN/priv/host_x86_defs.h 2012-04-02 22:24:12 +01:00 (rev 2272)
+++ branches/TCHAIN/priv/host_x86_defs.h 2012-04-02 22:54:49 +01:00 (rev 2273)
@@ -349,7 +349,9 @@
Xin_Sh3232, /* shldl or shrdl */
Xin_Push, /* push (32-bit?) value on stack */
Xin_Call, /* call to address in register */
- Xin_Goto, /* conditional/unconditional jmp to dst */
+ Xin_XDirect, /* direct transfer to GA */
+ Xin_XIndir, /* indirect transfer to GA */
+ Xin_XAssisted, /* assisted transfer to GA */
Xin_CMov32, /* conditional move */
Xin_LoadEX, /* mov{s,z}{b,w}l from mem to reg */
Xin_Store, /* store 16/8 bit value in memory */
@@ -378,7 +380,9 @@
Xin_Sse64FLo, /* SSE binary, 64F in lowest lane only */
Xin_SseReRg, /* SSE binary general reg-reg, Re, Rg */
Xin_SseCMov, /* SSE conditional move */
- Xin_SseShuf /* SSE2 shuffle (pshufd) */
+ Xin_SseShuf, /* SSE2 shuffle (pshufd) */
+ Xin_EvCheck, /* Event check */
+ Xin_ProfInc /* 64-bit profile counter increment */
}
X86InstrTag;
@@ -444,13 +448,30 @@
Addr32 target;
Int regparms; /* 0 .. 3 */
} Call;
- /* Pseudo-insn. Goto dst, on given condition (which could be
- Xcc_ALWAYS). */
+ /* Update the guest EIP value, then exit requesting to chain
+ to it. May be conditional. Urr, use of Addr32 implicitly
+ assumes that wordsize(guest) == wordsize(host). */
struct {
+ Addr32 dstGA; /* next guest address */
+ X86AMode* amEIP; /* amode in guest state for EIP */
+ X86CondCode cond; /* can be Xcc_ALWAYS */
+ Bool toFastEP; /* chain to the slow or fast point? */
+ } XDirect;
+ /* Boring transfer to a guest address not known at JIT time.
+ Not chainable. May be conditional. */
+ struct {
+ HReg dstGA;
+ X86AMode* amEIP;
+ X86CondCode cond; /* can be Xcc_ALWAYS */
+ } XIndir;
+ /* Assisted transfer to a guest address, most general case.
+ Not chainable. May be conditional. */
+ struct {
+ HReg dstGA;
+ X86AMode* amEIP;
+ X86CondCode cond; /* can be Xcc_ALWAYS */
IRJumpKind jk;
- X86CondCode cond;
- X86RI* dst;
- } Goto;
+ } XAssisted;
/* Mov src to dst on the given condition, which may not
be the bogus Xcc_ALWAYS. */
struct {
@@ -615,6 +636,15 @@
HReg src;
HReg dst;
} SseShuf;
+ struct {
+ X86AMode* amCounter;
+ X86AMode* amFailAddr;
+ } EvCheck;
+ struct {
+ /* No fields. The address of the counter to inc is
+ installed later, post-translation, by patching it in,
+ as it is not known at translation time. */
+ } ProfInc;
} Xin;
}
@@ -632,7 +662,12 @@
extern X86Instr* X86Instr_Sh3232 ( X86ShiftOp, UInt amt, HReg src, HReg dst );
extern X86Instr* X86Instr_Push ( X86RMI* );
extern X86Instr* X86Instr_Call ( X86CondCode, Addr32, Int );
-extern X86Instr* X86Instr_Goto ( IRJumpKind, X86CondCode cond, X86RI* dst );
+extern X86Instr* X86Instr_XDirect ( Addr32 dstGA, X86AMode* amEIP,
+ X86CondCode cond, Bool toFastEP );
+extern X86Instr* X86Instr_XIndir ( HReg dstGA, X86AMode* amEIP,
+ X86CondCode cond );
+extern X86Instr* X86Instr_XAssisted ( HReg dstGA, X86AMode* amEIP,
+ X86CondCode cond, IRJumpKind jk );
extern X86Instr* X86Instr_CMov32 ( X86CondCode, X86RM* src, HReg dst );
extern X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned,
X86AMode* src, HReg dst );
@@ -663,6 +698,9 @@
extern X86Instr* X86Instr_SseReRg ( X86SseOp, HReg, HReg );
extern X86Instr* X86Instr_SseCMov ( X86CondCode, HReg src, HReg dst );
extern X86Instr* X86Instr_SseShuf ( Int order, HReg src, HReg dst );
+extern X86Instr* X86Instr_EvCheck ( X86AMode* amCounter,
+ X86AMode* amFailAddr );
+extern X86Instr* X86Instr_ProfInc ( void );
extern void ppX86Instr ( X86Instr*, Bool );
@@ -672,10 +710,13 @@
extern void getRegUsage_X86Instr ( HRegUsage*, X86Instr*, Bool );
extern void mapRegs_X86Instr ( HRegRemap*, X86Instr*, Bool );
extern Bool isMove_X86Instr ( X86Instr*, HReg*, HReg* );
-extern Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr*,
- Bool,
- void* dispatch_unassisted,
- void* dispatch_assisted );
+extern Int emit_X86Instr ( /*MB_MOD*/Bool* is_profInc,
+ UChar* buf, Int nbuf, X86Instr* i,
+ Bool mode64,
+ void* disp_cp_chain_me_to_slowEP,
+ void* disp_cp_chain_me_to_fastEP,
+ void* disp_cp_xindir,
+ void* disp_cp_xassisted );
extern void genSpill_X86 ( /*OUT*/HInstr** i1, /*OUT*/HInstr** i2,
HReg rreg, Int offset, Bool );
@@ -685,10 +726,37 @@
extern X86Instr* directReload_X86 ( X86Instr* i,
HReg vreg, Short spill_off );
extern void getAllocableRegs_X86 ( Int*, HReg** );
-extern HInstrArray* iselSB_X86 ( IRSB*, VexArch,
- VexArchInfo*,
- VexAbiInfo* );
+extern HInstrArray* iselSB_X86 ( IRSB*,
+ VexArch,
+ VexArchInfo*,
+ VexAbiInfo*,
+ Int offs_Host_EvC_Counter,
+ Int offs_Host_EvC_FailAddr,
+ Bool chainingAllowed,
+ Bool addProfInc,
+ Addr64 max_ga );
+/* How big is an event check? This is kind of a kludge because it
+ depends on the offsets of host_EvC_FAILADDR and host_EvC_COUNTER,
+ and so assumes that they are both <= 128, and so can use the short
+ offset encoding. This is all checked with assertions, so in the
+ worst case we will merely assert at startup. */
+extern Int evCheckSzB_X86 ( void );
+
+/* Perform a chaining and unchaining of an XDirect jump. */
+extern VexInvalRange chainXDirect_X86 ( void* place_to_chain,
+ void* disp_cp_chain_me_EXPECTED,
+ void* place_to_jump_to );
+
+extern VexInvalRange unchainXDirect_X86 ( void* place_to_unchain,
+ void* place_to_jump_to_EXPECTED,
+ void* disp_cp_chain_me );
+
+/* Patch the counter location into an existing ProfInc point. */
+extern VexInvalRange patchProfInc_X86 ( void* place_to_patch,
+ ULong* location_of_counter );
+
+
#endif /* ndef __VEX_HOST_X86_DEFS_H */
/*---------------------------------------------------------------*/
Modified...
[truncated message content] |