in the hope of getting specialised versions thereof.
Use this mechanism to greatly improve handling of condition
codes. Various ensuing small changes.
git-svn-id: svn://svn.valgrind.org/vex/trunk@194
extern
Addr64 x86guest_findhelper ( Char* function_name );
+/* Used by the optimiser to specialise calls to helpers. */
+extern
+IRExpr* x86guest_spechelper ( Char* function_name,
+ IRExpr** args );
+
/*---------------------------------------------------------*/
/*--- Condition code stuff ---*/
CC_OP_NUMBER
};
+typedef
+ enum {
+ CondO = 0, /* overflow */
+ CondNO = 1, /* no overflow */
+
+ CondB = 2, /* below */
+ CondNB = 3, /* not below */
+
+ CondZ = 4, /* zero */
+ CondNZ = 5, /* not zero */
+
+ CondBE = 6, /* below or equal */
+ CondNBE = 7, /* not below or equal */
+
+ CondS = 8, /* negative */
+ CondNS = 9, /* not negative */
+
+ CondP = 10, /* parity even */
+ CondNP = 11, /* not parity even */
+
+ CondL = 12, /* jump less */
+ CondNL = 13, /* not less */
+
+ CondLE = 14, /* less or equal */
+ CondNLE = 15, /* not less or equal */
+
+ CondAlways = 16 /* HACK */
+ }
+ Condcode;
+
/*---------------------------------------------------------*/
/*--- Simulated state offsets ---*/
permission.
*/
+/* Set to 1 to get detailed profiling info about use of the flag
+ machinery. */
+#define PROFILE_EFLAGS 0
+
+
typedef UChar uint8_t;
typedef UInt uint32_t;
}
+
+#define CC_SHIFT_C 0
+#define CC_SHIFT_P 2
+#define CC_SHIFT_A 4
+#define CC_SHIFT_Z 6
+#define CC_SHIFT_S 7
+#define CC_SHIFT_O 13
+
+#if PROFILE_EFLAGS
+
+static UInt tabc[CC_OP_NUMBER];
+static UInt tab[CC_OP_NUMBER][16];
+static Bool initted = False;
+static UInt n_calc_cond = 0;
+static UInt n_calc_all = 0;
+static UInt n_calc_c = 0;
+
+static void showCounts ( void )
+{
+ Int op, co;
+ Char ch;
+ vex_printf("\nALL=%d COND=%d C=%d\n",
+ n_calc_all-n_calc_cond-n_calc_c, n_calc_cond, n_calc_c);
+ vex_printf(" CARRY O NO B NB Z NZ BE NBE"
+ " S NS P NP L NL LE NLE\n");
+ vex_printf(" ----------------------------------------------"
+ "----------------------------------------\n");
+ for (op = 0; op < CC_OP_NUMBER; op++) {
+
+ ch = ' ';
+ if (op > 0 && (op-1) % 3 == 2)
+ ch = 'L';
+
+ vex_printf("%2d%c: ", op, ch);
+ vex_printf("%6d ", tabc[op]);
+ for (co = 0; co < 16; co++) {
+ Int n = tab[op][co];
+ if (n >= 1000) {
+ vex_printf(" %3dK", n / 1000);
+ } else
+ if (n >= 0) {
+ vex_printf(" %3d ", n );
+ } else {
+ vex_printf(" ");
+ }
+ }
+ vex_printf("\n");
+ }
+ vex_printf("\n");
+}
+
+static void initCounts ( void )
+{
+ Int op, co;
+ initted = True;
+ for (op = 0; op < CC_OP_NUMBER; op++) {
+ tabc[op] = 0;
+ for (co = 0; co < 16; co++)
+ tab[op][co] = 0;
+ }
+}
+
+#endif /* PROFILE_EFLAGS */
+
/* CALLED FROM GENERATED CODE */
/*static*/ UInt calculate_eflags_all ( UInt cc_op, UInt cc_src, UInt cc_dst )
{
+# if PROFILE_EFLAGS
+ n_calc_all++;
+# endif
switch (cc_op) {
case CC_OP_COPY:
return cc_src & (CC_MASK_O | CC_MASK_S | CC_MASK_Z
/* CALLED FROM GENERATED CODE */
static UInt calculate_eflags_c ( UInt cc_op, UInt cc_src, UInt cc_dst )
{
+# if PROFILE_EFLAGS
+ if (!initted)
+ initCounts();
+ tabc[cc_op]++;
+
+ n_calc_c++;
+# endif
+
return calculate_eflags_all(cc_op,cc_src,cc_dst) & CC_MASK_C;
}
+/* CALLED FROM GENERATED CODE */
+/* returns 1 or 0 */
+/*static*/ UInt calculate_condition ( UInt/*Condcode*/ cond,
+ UInt cc_op, UInt cc_src, UInt cc_dst )
+{
+ UInt eflags = calculate_eflags_all(cc_op, cc_src, cc_dst);
+ UInt of,sf,zf,cf,pf;
+ UInt inv = cond & 1;
+
+# if PROFILE_EFLAGS
+ if (!initted)
+ initCounts();
+
+ tab[cc_op][cond]++;
+ n_calc_cond++;
+
+ if (0 == ((n_calc_all+n_calc_c) & 0xFF)) showCounts();
+# endif
+
+ switch (cond) {
+ case CondNO:
+ case CondO: /* OF == 1 */
+ of = eflags >> CC_SHIFT_O;
+ return 1 & (inv ^ of);
+
+ case CondNZ:
+ case CondZ: /* ZF == 1 */
+ zf = eflags >> CC_SHIFT_Z;
+ return 1 & (inv ^ zf);
+
+ case CondNB:
+ case CondB: /* CF == 1 */
+ cf = eflags >> CC_SHIFT_C;
+ return 1 & (inv ^ cf);
+ break;
+
+ case CondNBE:
+ case CondBE: /* (CF or ZF) == 1 */
+ cf = eflags >> CC_SHIFT_C;
+ zf = eflags >> CC_SHIFT_Z;
+ return 1 & (inv ^ (cf | zf));
+ break;
+
+ case CondNS:
+ case CondS: /* SF == 1 */
+ sf = eflags >> CC_SHIFT_S;
+ return 1 & (inv ^ sf);
+
+ case CondNP:
+ case CondP: /* PF == 1 */
+ pf = eflags >> CC_SHIFT_P;
+ return 1 & (inv ^ pf);
+
+ case CondNL:
+ case CondL: /* (SF xor OF) == 1 */
+ sf = eflags >> CC_SHIFT_S;
+ of = eflags >> CC_SHIFT_O;
+ return 1 & (inv ^ (sf ^ of));
+ break;
+
+ case CondNLE:
+ case CondLE: /* ((SF xor OF) or ZF) == 1 */
+ sf = eflags >> CC_SHIFT_S;
+ of = eflags >> CC_SHIFT_O;
+ zf = eflags >> CC_SHIFT_Z;
+ return 1 & (inv ^ ((sf ^ of) | zf));
+ break;
+
+ default:
+ /* shouldn't really make these calls from generated code */
+ vex_printf("calculate_condition( %d, %d, 0x%x, 0x%x )\n",
+ cond, cc_op, cc_src, cc_dst );
+ vpanic("calculate_condition");
+ }
+}
+
+
/* The only exported function. */
Addr64 x86guest_findhelper ( Char* function_name )
return (Addr64)(& calculate_eflags_all);
if (vex_streq(function_name, "calculate_eflags_c"))
return (Addr64)(& calculate_eflags_c);
+ if (vex_streq(function_name, "calculate_condition"))
+ return (Addr64)(& calculate_condition);
vex_printf("\nx86 guest: can't find helper: %s\n", function_name);
vpanic("x86guest_findhelper");
}
+/* Used by the optimiser to try specialisations. Returns an
+ equivalent expression, or NULL if none. */
+
+static Bool isU32 ( IRExpr* e, UInt n )
+{
+ return e->tag == Iex_Const
+ && e->Iex.Const.con->tag == Ico_U32
+ && e->Iex.Const.con->Ico.U32 == n;
+}
+
+IRExpr* x86guest_spechelper ( Char* function_name,
+ IRExpr** args )
+{
+# define unop(_op,_a1) IRExpr_Unop((_op),(_a1))
+# define binop(_op,_a1,_a2) IRExpr_Binop((_op),(_a1),(_a2))
+# define mkU32(_n) IRExpr_Const(IRConst_U32(_n))
+
+ Int i, arity = 0;
+ for (i = 0; args[i]; i++)
+ arity++;
+# if 0
+ vex_printf("spec request:\n");
+ vex_printf(" %s ", function_name);
+ for (i = 0; i < arity; i++) {
+ vex_printf(" ");
+ ppIRExpr(args[i]);
+ }
+ vex_printf("\n");
+# endif
+
+ if (vex_streq(function_name, "calculate_eflags_c")) {
+ /* specialise calls to above "calculate_eflags_c" function */
+ IRExpr *cc_op, *cc_src, *cc_dst;
+ vassert(arity == 3);
+ cc_op = args[0];
+ cc_src = args[1];
+ cc_dst = args[2];
+
+ if (isU32(cc_op, CC_OP_LOGICL)) {
+ /* cflag after logic is zero */
+ return mkU32(0);
+ }
+ if (isU32(cc_op, CC_OP_DECL) || isU32(cc_op, CC_OP_INCL)) {
+ /* If the thunk is dec or inc, the cflag is supplied as CC_SRC. */
+ return cc_src;
+ }
+ if (isU32(cc_op, CC_OP_SUBL)) {
+ /* C after sub denotes unsigned less than */
+ return unop(Iop_1Uto32,
+ binop(Iop_CmpLT32U, binop(Iop_Add32,cc_src,cc_dst),
+ cc_src));
+ }
+# if 0
+ if (cc_op->tag == Iex_Const) {
+ vex_printf("CFLAG "); ppIRExpr(cc_op); vex_printf("\n");
+ }
+# endif
+
+ return NULL;
+ }
+
+ if (vex_streq(function_name, "calculate_condition")) {
+ /* specialise calls to above "calculate condition" function */
+ IRExpr *cond, *cc_op, *cc_src, *cc_dst;
+ vassert(arity == 4);
+ cond = args[0];
+ cc_op = args[1];
+ cc_src = args[2];
+ cc_dst = args[3];
+
+ if (isU32(cc_op, CC_OP_LOGICB) && isU32(cond, CondZ)) {
+ /* byte and/or/xor, then Z --> test dst==0 */
+ return unop(Iop_1Uto32,
+ binop(Iop_CmpEQ32, binop(Iop_And32,cc_dst,mkU32(255)),
+ mkU32(0)));
+ }
+
+ if (isU32(cc_op, CC_OP_SUBB) && isU32(cond, CondZ)) {
+ /* byte sub/cmp, then Z --> test dst==0 */
+ return unop(Iop_1Uto32,
+ binop(Iop_CmpEQ32, binop(Iop_And32,cc_dst,mkU32(255)),
+ mkU32(0)));
+ }
+
+ if (isU32(cc_op, CC_OP_SUBB) && isU32(cond, CondNZ)) {
+ /* byte sub/cmp, then Z --> test dst==0 */
+ return unop(Iop_1Uto32,
+ binop(Iop_CmpNE32, binop(Iop_And32,cc_dst,mkU32(255)),
+ mkU32(0)));
+ }
+
+ if (isU32(cc_op, CC_OP_LOGICL) && isU32(cond, CondZ)) {
+ /* long and/or/xor, then Z --> test dst==0 */
+ return unop(Iop_1Uto32,binop(Iop_CmpEQ32, cc_dst, mkU32(0)));
+ }
+
+ if (isU32(cc_op, CC_OP_LOGICL) && isU32(cond, CondLE)) {
+ /* long and/or/xor, then LE
+ This is pretty subtle. LOGIC sets SF and ZF according to the
+ result and makes OF be zero. LE computes (SZ ^ OF) | ZF, but
+ OF is zero, so this reduces to SZ | ZF -- which will be 1 iff
+ the result is <=signed 0. Hence ...
+ */
+ return unop(Iop_1Uto32,binop(Iop_CmpLE32S, cc_dst, mkU32(0)));
+ }
+
+ if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondZ)) {
+ /* long sub/cmp, then Z --> test dst==0 */
+ return unop(Iop_1Uto32,binop(Iop_CmpEQ32, cc_dst, mkU32(0)));
+ }
+
+ if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondL)) {
+ /* long sub/cmp, then L (signed less than) */
+ return unop(Iop_1Uto32,
+ binop(Iop_CmpLT32S, binop(Iop_Add32,cc_src,cc_dst),
+ cc_src));
+ }
+
+ if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondLE)) {
+ /* long sub/cmp, then LE (signed less than or equal) */
+ return unop(Iop_1Uto32,
+ binop(Iop_CmpLE32S, binop(Iop_Add32,cc_src,cc_dst),
+ cc_src));
+ }
+
+ if (isU32(cc_op, CC_OP_SUBL) && isU32(cond, CondBE)) {
+ /* long sub/cmp, then BE (unsigned less than or equal) */
+ return unop(Iop_1Uto32,
+ binop(Iop_CmpLE32U, binop(Iop_Add32,cc_src,cc_dst),
+ cc_src));
+ }
+
+ if (isU32(cc_op, CC_OP_DECL) && isU32(cond, CondZ)) {
+ /* dec L, then Z --> test dst == 0 */
+ return unop(Iop_1Uto32,binop(Iop_CmpEQ32, cc_dst, mkU32(0)));
+ }
+
+ return NULL;
+ }
+
+# undef unop
+# undef binop
+# undef mkU32
+
+ return NULL;
+}
+
/*---------------------------------------------------------------*/
/*--- end guest-x86/ghelpers.c ---*/
return IRExpr_CCall("calculate_eflags_all", Ity_I32, args);
}
-/* Build IR to calculate just the carry flags from stored
+/* Build IR to calculate just the carry flag from stored
CC_OP/CC_SRC/CC_DST. Returns an expression :: Ity_I32. */
static IRExpr* mk_calculate_eflags_c ( void )
{
return IRExpr_CCall("calculate_eflags_c", Ity_I32, args);
}
+/* Build IR to calculate some particular condition from stored
+ CC_OP/CC_SRC/CC_DST. Returns an expression :: Ity_Bit. */
+static IRExpr* calculate_condition ( Condcode cond )
+{
+ IRExpr** args = LibVEX_Alloc(5 * sizeof(IRExpr*));
+ args[0] = mkU32(cond);
+ args[1] = IRExpr_Get(OFFB_CC_OP, Ity_I32);
+ args[2] = IRExpr_Get(OFFB_CC_SRC, Ity_I32);
+ args[3] = IRExpr_Get(OFFB_CC_DST, Ity_I32);
+ args[4] = NULL;
+ return unop(Iop_32to1,
+ IRExpr_CCall("calculate_condition", Ity_I32, args));
+}
+
/* -------------- Building the flags-thunk. -------------- */
/* Condition codes, using the Intel encoding. */
-typedef
- enum {
- CondO = 0, /* overflow */
- CondNO = 1, /* no overflow */
-
- CondB = 2, /* below */
- CondNB = 3, /* not below */
-
- CondZ = 4, /* zero */
- CondNZ = 5, /* not zero */
-
- CondBE = 6, /* below or equal */
- CondNBE = 7, /* not below or equal */
-
- CondS = 8, /* negative */
- CondNS = 9, /* not negative */
-
- CondP = 10, /* parity even */
- CondNP = 11, /* not parity even */
-
- CondL = 12, /* jump less */
- CondNL = 13, /* not less */
-
- CondLE = 14, /* less or equal */
- CondNLE = 15, /* not less or equal */
-
- CondAlways = 16 /* HACK */
- }
- Condcode;
-
static Char* name_Condcode ( Condcode cond )
{
switch (cond) {
}
+#if 0
+/* UNUSED -- DELETE */
/* Get some particular flag to the lowest bit in a word. It's not
masked, tho. */
static IRExpr* flag_to_bit0 ( UInt ccmask, IRTemp eflags )
invert ? unop(Iop_32to1, unop(Iop_Not32, e))
: unop(Iop_32to1, e);
}
+#endif
/* -------------- Helpers for ADD/SUB with carry. -------------- */
static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e )
{
MatchInfo mi;
- DECLARE_PATTERN(p_32to1_then_1Uto8);
+ DECLARE_PATTERN(p_32to1_then_1Uto8);
IRType ty = typeOfIRExpr(env->type_env,e);
vassert(ty == Ity_I32 || Ity_I16 || Ity_I8);
addInstr(env, X86Instr_Sh32(Xsh_SHR, shift, X86RM_Reg(dst)));
return dst;
}
+ case Iop_1Uto32:
case Iop_1Uto8: {
HReg dst = newVRegI(env);
X86CondCode cond = iselCondCode(env, e->Iex.Unop.arg);
MatchInfo mi;
DECLARE_PATTERN(p_32to1);
DECLARE_PATTERN(p_eq32_zero);
+ DECLARE_PATTERN(p_ne32_zero);
+ DECLARE_PATTERN(p_1Uto32_then_32to1);
vassert(e);
vassert(typeOfIRExpr(env->type_env,e) == Ity_Bit);
+ /* 32to1(1Uto32(expr1)) -- the casts are pointless, ignore them */
+ DEFINE_PATTERN(p_1Uto32_then_32to1,
+ unop(Iop_32to1,unop(Iop_1Uto32,bind(0))));
+ if (matchIRExpr(&mi,p_1Uto32_then_32to1,e)) {
+ IRExpr* expr1 = mi.bindee[0];
+ return iselCondCode(env, expr1);
+ }
+
/* pattern: 32to1(expr32) */
DEFINE_PATTERN(p_32to1,
unop(Iop_32to1,bind(0))
return Xcc_Z;
}
+ /* pattern: CmpNE32(expr32,0) */
+ DEFINE_PATTERN(p_ne32_zero,
+ binop( Iop_CmpNE32, bind(0), IRExpr_Const(IRConst_U32(0)) )
+ );
+ if (matchIRExpr(&mi,p_ne32_zero,e)) {
+ HReg src = iselIntExpr_R(env, mi.bindee[0]);
+ addInstr(env, X86Instr_Alu32R(Xalu_CMP,X86RMI_Imm(0),src));
+ return Xcc_NZ;
+ }
+
+ /* CmpLT32S(x,y) or CmpLE32S(x,y) */
+ if (e->tag == Iex_Binop
+ && (e->Iex.Binop.op == Iop_CmpLT32S
+ || e->Iex.Binop.op == Iop_CmpLT32U
+ || e->Iex.Binop.op == Iop_CmpLE32S
+ || e->Iex.Binop.op == Iop_CmpLE32U)) {
+ HReg r1 = iselIntExpr_R(env, e->Iex.Binop.arg1);
+ X86RMI* rmi2 = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
+ addInstr(env, X86Instr_Alu32R(Xalu_CMP,rmi2,r1));
+ switch (e->Iex.Binop.op) {
+ case Iop_CmpLT32S: return Xcc_L;
+ case Iop_CmpLT32U: return Xcc_B;
+ case Iop_CmpLE32S: return Xcc_LE;
+ case Iop_CmpLE32U: return Xcc_BE;
+ default: vpanic("iselCondCode(x86): CmpXX");
+ }
+ }
+
/* var */
if (e->tag == Iex_Tmp) {
HReg r32 = lookupIRTemp(env, e->Iex.Tmp.tmp);
case Iop_32to8: vex_printf("32to8"); return;
case Iop_32to1: vex_printf("32to1"); return;
case Iop_1Uto8: vex_printf("1Uto8"); return;
+ case Iop_1Uto32: vex_printf("1Uto32"); return;
case Iop_MullS8: vex_printf("MullS8"); return;
case Iop_MullS16: vex_printf("MullS16"); return;
case Iop_MullU16: vex_printf("MullU16"); return;
case Iop_MullU32: vex_printf("MullU32"); return;
+ case Iop_CmpLT32S: vex_printf("CmpLT32S"); return;
+ case Iop_CmpLE32S: vex_printf("CmpLE32S"); return;
+ case Iop_CmpLT32U: vex_printf("CmpLT32U"); return;
+ case Iop_CmpLE32U: vex_printf("CmpLE32U"); return;
+
case Iop_DivModU64to32: vex_printf("DivModU64to32"); return;
case Iop_DivModS64to32: vex_printf("DivModS64to32"); return;
case Iop_CmpEQ16: case Iop_CmpNE16:
COMPARISON(Ity_I16);
case Iop_CmpEQ32: case Iop_CmpNE32:
+ case Iop_CmpLT32S:
+ case Iop_CmpLE32S:
+ case Iop_CmpLT32U:
+ case Iop_CmpLE32U:
COMPARISON(Ity_I32);
case Iop_CmpEQ64: case Iop_CmpNE64:
COMPARISON(Ity_I64);
BINARY(Ity_I64,Ity_I32,Ity_I32);
case Iop_1Uto8: UNARY(Ity_I8,Ity_Bit);
+ case Iop_1Uto32: UNARY(Ity_I32,Ity_Bit);
case Iop_32to1: UNARY(Ity_Bit,Ity_I32);
case Iop_8Uto32: UNARY(Ity_I32,Ity_I8);
case Iop_8Sto32: UNARY(Ity_I32,Ity_I8);
/* Work backwards through the stmts */
for (i = bb->stmts_used-1; i >= 0; i--) {
st = bb->stmts[i];
+ if (!st)
+ continue;
if (st->tag == Ist_Tmp
&& !lookupH64(set, NULL, (ULong)(st->Ist.Tmp.tmp))) {
/* it's an IRTemp which never got used. Delete it. */
}
+/*---------------------------------------------------------------*/
+/*--- Specialisation of helper function calls, in ---*/
+/*--- collaboration with the front end ---*/
+/*---------------------------------------------------------------*/
+
+static
+void spec_helpers_BB ( IRBB* bb,
+ IRExpr* (*specHelper) ( Char*, IRExpr**) )
+{
+ Int i;
+ IRStmt* st;
+ IRExpr* ex;
+
+ for (i = bb->stmts_used-1; i >= 0; i--) {
+ st = bb->stmts[i];
+
+ if (!st
+ || st->tag != Ist_Tmp
+ || st->Ist.Tmp.expr->tag != Iex_CCall)
+ continue;
+
+ ex = (*specHelper)( st->Ist.Tmp.expr->Iex.CCall.name,
+ st->Ist.Tmp.expr->Iex.CCall.args );
+ if (!ex)
+ /* the front end can't think of a suitable replacement */
+ continue;
+
+ /* We got something better. Install it in the bb. */
+ bb->stmts[i]
+ = IRStmt_Tmp(st->Ist.Tmp.tmp, ex);
+
+ if (0) {
+ vex_printf("SPEC: ");
+ ppIRExpr(st->Ist.Tmp.expr);
+ vex_printf(" --> ");
+ ppIRExpr(ex);
+ vex_printf("\n");
+ }
+ }
+}
+
/*---------------------------------------------------------------*/
/*--- The tree builder ---*/
typedef
struct {
Int occ; /* occurrence count for this tmp */
- IRExpr* expr; /* expr it is bound to, or NULL if already 'used' */
+ IRExpr* expr; /* expr it is bound to,
+ or NULL if already 'used' */
Bool eDoesLoad; /* True <=> expr reads mem */
Bool eDoesGet; /* True <=> expr reads guest state */
Bool invalidateMe; /* used when dumping bindings */
continue;
if (!lookupH64(env, &res, (ULong)(st->Ist.Tmp.tmp))) {
+ vex_printf("\n");
+ ppIRTemp(st->Ist.Tmp.tmp);
+ vex_printf("\n");
vpanic("treebuild_BB (phase 2): unmapped IRTemp");
}
ti = (TmpInfo*)res;
*/
/* exported from this file */
-IRBB* do_iropt_BB ( IRBB* bb0 )
+IRBB* do_iropt_BB ( IRBB* bb0,
+ IRExpr* (*specHelper) ( Char*, IRExpr**) )
{
Bool verbose = False;
IRBB *flat, *cpd;
}
dead_BB ( cpd );
- if (0||verbose) {
+ if (verbose) {
vex_printf("\n========= DEAD\n\n" );
ppIRBB(cpd);
}
-#if 1
+ spec_helpers_BB ( cpd, specHelper );
+ dead_BB ( cpd );
+ if (verbose) {
+ vex_printf("\n========= SPECd \n\n" );
+ ppIRBB(cpd);
+ }
+
treebuild_BB ( cpd );
- if (0||verbose) {
+ if (verbose) {
vex_printf("\n========= TREEd \n\n" );
ppIRBB(cpd);
}
-#endif
return cpd;
#include "libvex.h"
-extern IRBB* do_iropt_BB ( IRBB* );
+extern IRBB* do_iropt_BB ( IRBB* bb,
+ IRExpr* (*specHelper) ( Char*, IRExpr**) );
/*---------------------------------------------------------------*/
/*--- end ir/iropt.h ---*/
Bool(*)(Addr64), Bool );
Int (*emit) ( UChar*, Int, HInstr* );
Addr64 (*findHelper) ( Char* );
+ IRExpr* (*specHelper) ( Char*, IRExpr** );
Bool host_is_bigendian = False;
IRBB* irbb;
bbToIR = NULL;
emit = NULL;
findHelper = NULL;
+ specHelper = NULL;
saved_verbosity = vex_verbosity;
if (bb_verbosity > 0)
case InsnSetX86:
bbToIR = bbToIR_X86Instr;
findHelper = x86guest_findhelper;
+ specHelper = x86guest_spechelper;
break;
default:
vpanic("LibVEX_Translate: unsupported guest insn set");
sanityCheckIRBB(irbb, Ity_I32);
/* Clean it up, hopefully a lot. */
- irbb = do_iropt_BB ( irbb );
+ irbb = do_iropt_BB ( irbb, specHelper );
sanityCheckIRBB(irbb, Ity_I32);
if (vex_verbosity > 0) {
Iop_MullS8, Iop_MullS16, Iop_MullS32,
Iop_MullU8, Iop_MullU16, Iop_MullU32,
/* Ordering not important after here. */
+ Iop_CmpLT32S,
+ Iop_CmpLE32S,
+ Iop_CmpLT32U,
+ Iop_CmpLE32U,
/* Division */
Iop_DivModU64to32, // :: I64,I32 -> I64
// of which lo half is div and hi half is mod
Iop_64HIto32, // :: I64 -> I32, high half
Iop_32HLto64, // :: (I32,I32) -> I64
/* 1-bit stuff */
- Iop_32to1, /* :: Ity_I32 -> Ity_Bit, just select bit[0] */
- Iop_1Uto8, /* :: Ity_Bit -> Ity_I8, unsigned widen */
+ Iop_32to1, /* :: Ity_I32 -> Ity_Bit, just select bit[0] */
+ Iop_1Uto8, /* :: Ity_Bit -> Ity_I8, unsigned widen */
+ Iop_1Uto32, /* :: Ity_Bit -> Ity_I32, unsigned widen */
/* FP stuff */
Iop_AddF64, Iop_SubF64, Iop_MulF64, Iop_DivF64,
Iop_SqrtF64,
LibVEX_Init ( &failure_exit, &log_bytes,
1, /* debug_paranoia */
- 0, /* verbosity */
+ 1, /* verbosity */
//False,
True,
100 );