From: Julian Seward Date: Mon, 23 Aug 2004 16:16:08 +0000 (+0000) Subject: Allow iropt to pass helper function calls back to the front end X-Git-Tag: svn/VALGRIND_3_0_1^2~1140 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=b7e7be78db4d2c255c052d4317015df670b819e4;p=thirdparty%2Fvalgrind.git Allow iropt to pass helper function calls back to the front end 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 --- diff --git a/VEX/priv/guest-x86/gdefs.h b/VEX/priv/guest-x86/gdefs.h index 4e29f4e638..0c9ecb91be 100644 --- a/VEX/priv/guest-x86/gdefs.h +++ b/VEX/priv/guest-x86/gdefs.h @@ -31,6 +31,11 @@ IRBB* bbToIR_X86Instr ( UChar* x86code, 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 ---*/ @@ -103,6 +108,36 @@ enum { 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 ---*/ diff --git a/VEX/priv/guest-x86/ghelpers.c b/VEX/priv/guest-x86/ghelpers.c index d9ef4d91a6..3199ff620c 100644 --- a/VEX/priv/guest-x86/ghelpers.c +++ b/VEX/priv/guest-x86/ghelpers.c @@ -30,6 +30,11 @@ 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; @@ -293,9 +298,76 @@ static inline int lshift(int x, int n) } + +#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 @@ -364,10 +436,95 @@ static inline int lshift(int x, int n) /* 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 ) @@ -376,10 +533,159 @@ 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 ---*/ diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 6047173cb8..58ac0aea30 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -358,7 +358,7 @@ static IRExpr* mk_calculate_eflags_all ( void ) 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 ) { @@ -370,6 +370,20 @@ 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. -------------- */ @@ -539,36 +553,6 @@ void setFlags_MUL ( IRType ty, IRTemp src1, IRTemp src2, UInt base_op ) /* 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) { @@ -607,6 +591,8 @@ static Condcode positiveIse_Condcode ( Condcode 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 ) @@ -691,6 +677,7 @@ static IRExpr* calculate_condition ( Condcode cond ) invert ? unop(Iop_32to1, unop(Iop_Not32, e)) : unop(Iop_32to1, e); } +#endif /* -------------- Helpers for ADD/SUB with carry. -------------- */ diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index 9cf821ae8c..045eeb09ce 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -257,7 +257,7 @@ static X86Instr* mk_MOVsd_RR ( HReg src, HReg dst ) 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); @@ -504,6 +504,7 @@ static HReg iselIntExpr_R ( ISelEnv* env, IRExpr* e ) 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); @@ -773,10 +774,20 @@ static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e ) 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)) @@ -797,6 +808,34 @@ static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e ) 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); diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index 7ff7bcfd27..2efb84440c 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -96,6 +96,7 @@ void ppIROp ( IROp op ) 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; @@ -104,6 +105,11 @@ void ppIROp ( IROp op ) 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; @@ -548,6 +554,10 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) 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); @@ -579,6 +589,7 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) 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); diff --git a/VEX/priv/ir/iropt.c b/VEX/priv/ir/iropt.c index 3268d73cbd..cbb70c2a70 100644 --- a/VEX/priv/ir/iropt.c +++ b/VEX/priv/ir/iropt.c @@ -770,6 +770,8 @@ static void dead_BB ( IRBB* bb ) /* 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. */ @@ -1067,6 +1069,47 @@ static void redundant_put_removal_BB ( IRBB* bb ) } +/*---------------------------------------------------------------*/ +/*--- 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 ---*/ @@ -1075,7 +1118,8 @@ static void redundant_put_removal_BB ( IRBB* bb ) 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 */ @@ -1401,6 +1445,9 @@ static void treebuild_BB ( IRBB* bb ) 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; @@ -1515,7 +1562,8 @@ static void treebuild_BB ( IRBB* bb ) */ /* 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; @@ -1545,18 +1593,23 @@ IRBB* do_iropt_BB ( IRBB* bb0 ) } 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; diff --git a/VEX/priv/ir/iropt.h b/VEX/priv/ir/iropt.h index d086765c50..1a6831ce29 100644 --- a/VEX/priv/ir/iropt.h +++ b/VEX/priv/ir/iropt.h @@ -11,7 +11,8 @@ #include "libvex.h" -extern IRBB* do_iropt_BB ( IRBB* ); +extern IRBB* do_iropt_BB ( IRBB* bb, + IRExpr* (*specHelper) ( Char*, IRExpr**) ); /*---------------------------------------------------------------*/ /*--- end ir/iropt.h ---*/ diff --git a/VEX/priv/main/vex_main.c b/VEX/priv/main/vex_main.c index fb88ae4cc0..1becac351b 100644 --- a/VEX/priv/main/vex_main.c +++ b/VEX/priv/main/vex_main.c @@ -99,6 +99,7 @@ TranslateResult LibVEX_Translate ( Bool(*)(Addr64), Bool ); Int (*emit) ( UChar*, Int, HInstr* ); Addr64 (*findHelper) ( Char* ); + IRExpr* (*specHelper) ( Char*, IRExpr** ); Bool host_is_bigendian = False; IRBB* irbb; @@ -120,6 +121,7 @@ TranslateResult LibVEX_Translate ( bbToIR = NULL; emit = NULL; findHelper = NULL; + specHelper = NULL; saved_verbosity = vex_verbosity; if (bb_verbosity > 0) @@ -153,6 +155,7 @@ TranslateResult LibVEX_Translate ( case InsnSetX86: bbToIR = bbToIR_X86Instr; findHelper = x86guest_findhelper; + specHelper = x86guest_spechelper; break; default: vpanic("LibVEX_Translate: unsupported guest insn set"); @@ -173,7 +176,7 @@ TranslateResult LibVEX_Translate ( 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) { diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 3bb2be19d4..c048144d7d 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -96,6 +96,10 @@ typedef 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 @@ -118,8 +122,9 @@ typedef 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, diff --git a/VEX/test_main.c b/VEX/test_main.c index 4482e9b424..736ac7e4bd 100644 --- a/VEX/test_main.c +++ b/VEX/test_main.c @@ -65,7 +65,7 @@ int main ( int argc, char** argv ) LibVEX_Init ( &failure_exit, &log_bytes, 1, /* debug_paranoia */ - 0, /* verbosity */ + 1, /* verbosity */ //False, True, 100 );