From: Julian Seward Date: Mon, 20 Sep 2004 14:54:28 +0000 (+0000) Subject: Fully install generic IR machinery for dirty helper calls and make it X-Git-Tag: svn/VALGRIND_3_0_1^2~1060 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0a6721adf470f23745729010e1c545e6add27782;p=thirdparty%2Fvalgrind.git Fully install generic IR machinery for dirty helper calls and make it work. Use it to implement x86 10-byte loads/stores. git-svn-id: svn://svn.valgrind.org/vex/trunk@274 --- diff --git a/VEX/priv/guest-x86/ghelpers.c b/VEX/priv/guest-x86/ghelpers.c index 61272925a2..0cc3caccc4 100644 --- a/VEX/priv/guest-x86/ghelpers.c +++ b/VEX/priv/guest-x86/ghelpers.c @@ -14,11 +14,13 @@ #include "guest-x86/gdefs.h" /* --- Forwardses --- */ -UInt calculate_eflags_all ( UInt cc_op, UInt cc_src, UInt cc_dst ); -UInt calculate_eflags_c ( UInt cc_op, UInt cc_src, UInt cc_dst ); -UInt calculate_condition ( UInt/*Condcode*/ cond, - UInt cc_op, UInt cc_src, UInt cc_dst ); -UInt calculate_FXAM ( UInt tag, ULong dbl ); + UInt calculate_eflags_all ( UInt cc_op, UInt cc_src, UInt cc_dst ); +static UInt calculate_eflags_c ( UInt cc_op, UInt cc_src, UInt cc_dst ); +static UInt calculate_condition ( UInt/*Condcode*/ cond, + UInt cc_op, UInt cc_src, UInt cc_dst ); +static UInt calculate_FXAM ( UInt tag, ULong dbl ); +static ULong loadF80le ( UInt ); +static void storeF80le ( UInt, ULong ); /* This file contains helper functions for x86 guest code. @@ -576,18 +578,20 @@ static UInt calculate_eflags_c ( UInt cc_op, UInt cc_src, UInt cc_dst ) } -/* The only exported function. */ - Addr64 x86guest_findhelper ( Char* function_name ) { - if (vex_streq(function_name, "calculate_eflags_all")) - 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); + if (vex_streq(function_name, "calculate_eflags_c")) + return (Addr64)(& calculate_eflags_c); + if (vex_streq(function_name, "calculate_eflags_all")) + return (Addr64)(& calculate_eflags_all); if (vex_streq(function_name, "calculate_FXAM")) return (Addr64)(& calculate_FXAM); + if (vex_streq(function_name, "storeF80le")) + return (Addr64)(& storeF80le); + if (vex_streq(function_name, "loadF80le")) + return (Addr64)(& loadF80le); vex_printf("\nx86 guest: can't find helper: %s\n", function_name); vpanic("x86guest_findhelper"); } @@ -831,7 +835,7 @@ static inline Bool host_is_little_endian ( void ) return (*p == 0x10); } -UInt calculate_FXAM ( UInt tag, ULong dbl ) +static UInt calculate_FXAM ( UInt tag, ULong dbl ) { Bool mantissaIsZero; Int bexp; @@ -1163,6 +1167,22 @@ static void convert_f80le_to_f64le ( /*IN*/UChar* f80, /*OUT*/UChar* f64 ) } } +/* CALLED FROM GENERATED CODE */ +/* DIRTY HELPER (reads guest memory) */ +static ULong loadF80le ( UInt addrU ) +{ + ULong f64; + convert_f80le_to_f64le ( (UChar*)addrU, (UChar*)&f64 ); + return f64; +} + +/* CALLED FROM GENERATED CODE */ +/* DIRTY HELPER (writes guest memory) */ +static void storeF80le ( UInt addrU, ULong f64 ) +{ + convert_f64le_to_f80le( (UChar*)&f64, (UChar*)addrU ); +} + /*----------------------------------------------*/ /*--- The exported fns .. ---*/ diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index f3d323d00f..585e9be4c0 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -2998,11 +2998,15 @@ UInt dis_imul_I_E_G ( UChar sorb, /* --- Helper functions for dealing with the register stack. --- */ -/* --- Produce an IRExpr* denoting a 64-bit NaN. --- */ +/* --- Produce an IRExpr* denoting a 64-bit QNaN. --- */ -static IRExpr* mkNaN64 ( void ) +static IRExpr* mkQNaN64 ( void ) { - return IRExpr_Const(IRConst_NaN64()); + /* QNaN is 0 2047 1 0(51times) + == 0b 11111111111b 1 0(51times) + == 0x7FF8 0000 0000 0000 + */ + return IRExpr_Const(IRConst_F64i(0x7FF8000000000000ULL)); } /* --------- Get/set the top-of-stack pointer. --------- */ @@ -3143,7 +3147,7 @@ static void put_ST ( Int i, IRExpr* value ) /* 0 means empty */ value, /* non-0 means full */ - mkNaN64() + mkQNaN64() ) ); } @@ -3157,11 +3161,6 @@ static IRExpr* get_ST_UNCHECKED ( Int i ) IRExpr_GetI( off_ST(i), Ity_F64, OFFB_F0, OFFB_F7+8-1 ); } -static IRExpr* get_ST_UNCHECKED_as_ULong ( Int i ) -{ - return - IRExpr_GetI( off_ST(i), Ity_I64, OFFB_F0, OFFB_F7+8-1 ); -} /* Given i, generate an expression yielding is_full(i) ? ST(i) : NaN @@ -3172,7 +3171,7 @@ static IRExpr* get_ST ( Int i ) return IRExpr_Mux0X( get_ST_TAG(i), /* 0 means empty */ - mkNaN64(), + mkQNaN64(), /* non-0 means full */ get_ST_UNCHECKED(i)); } @@ -3485,7 +3484,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) DIP("fxam"); args = LibVEX_Alloc(3 * sizeof(IRExpr*)); args[0] = unop(Iop_8Uto32, get_ST_TAG(0)); - args[1] = get_ST_UNCHECKED_as_ULong(0); + args[1] = unop(Iop_ReinterpF64asI64, get_ST_UNCHECKED(0)); args[2] = NULL; put_C3210(IRExpr_CCall("calculate_FXAM", Ity_I32, args)); break; @@ -3724,32 +3723,58 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) binop(Iop_F64toI32, get_roundingmode(), get_ST(0)) ); fp_pop(); break; -#if 0 + case 5: { /* FLD extended-real */ + /* Uses dirty helper: ULong loadF80le ( UInt ) */ /* addr holds the address. First, do a dirty call to get hold of the data. */ /* give details of args, and where to call */ - IRDirty* d = emptyIRDirty(); + IRDirty* d; + DIP("fldt %s", dis_buf); + d = emptyIRDirty(); d->name = "loadF80le"; d->args = LibVEX_Alloc(2 * sizeof(IRTemp)); - d->args[0] = addr; - d->args[1] = INVALID_IRTEMP; - d->retty = Ity_I64; - d->tmp = newTmp(Ity_I64); + d->args[0] = mkexpr(addr); + d->args[1] = NULL; + d->tmp = newTemp(Ity_I64); /* declare that we're reading memory */ d->mFx = Ifx_Read; - d->mAddr = addr; + d->mAddr = mkexpr(addr); d->mSize = 10; /* declare that we don't mess with guest state */ d->nFxState = 0; /* execute the dirty call, dumping the result in d->tmp. */ stmt( IRStmt_Dirty(d) ); fp_push(); - put_ST(0, d->tmp); + put_ST(0, unop(Iop_ReinterpI64asF64, mkexpr(d->tmp))); + break; + } + + case 7: { /* FSTP extended-real */ + /* Uses dirty helper: void storeF80le ( UInt, ULong ) */ + IRDirty* d; DIP("fldt %s", dis_buf); + d = emptyIRDirty(); + d->name = "storeF80le"; + /* takes 2 args */ + d->args = LibVEX_Alloc(3 * sizeof(IRTemp)); + d->args[0] = mkexpr(addr); + d->args[1] = unop(Iop_ReinterpF64asI64, get_ST(0)); + d->args[2] = NULL; + /* returns nothing */ + d->tmp = INVALID_IRTEMP; + /* declare we're writing memory */ + d->mFx = Ifx_Write; + d->mAddr = mkexpr(addr); + d->mSize = 10; + /* declare that we don't mess with guest state */ + d->nFxState = 0; + /* execute the dirty call. */ + stmt( IRStmt_Dirty(d) ); + fp_pop(); break; } -#endif + default: vex_printf("unhandled opc_aux = 0x%2x\n", gregOfRM(modrm)); vex_printf("first_opcode == 0xDB\n"); @@ -3767,7 +3792,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) default: goto decode_fail; - } + } } } diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index e0812f9538..ad7ac90ee7 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -113,7 +113,6 @@ static Bool matchWrk ( MatchInfo* mi, IRExpr* p/*attern*/, IRExpr* e/*xpr*/ ) ? (p->Iex.Const.con->Ico.F64 == e->Iex.Const.con->Ico.F64) : False; - case Ico_NaN64: return e->Iex.Const.con->tag == Ico_NaN64; } vpanic("matchIRExpr.Iex_Const"); /*NOTREACHED*/ @@ -243,15 +242,6 @@ static HReg newVRegF ( ISelEnv* env ) return reg; } -/* Misc helpers looking for a proper home. */ - -static X86Instr* mk_MOVsd_RR ( HReg src, HReg dst ) -{ - vassert(hregClass(src) == HRcInt); - vassert(hregClass(dst) == HRcInt); - return X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(src), dst); -} - /*---------------------------------------------------------*/ /*--- ISEL: Forward declarations ---*/ @@ -289,6 +279,68 @@ static X86CondCode iselCondCode ( ISelEnv* env, IRExpr* e ); static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ); +/*---------------------------------------------------------*/ +/*--- ISEL: Misc helpers ---*/ +/*---------------------------------------------------------*/ + +/* Make a int reg-reg move. */ + +static X86Instr* mk_MOVsd_RR ( HReg src, HReg dst ) +{ + vassert(hregClass(src) == HRcInt); + vassert(hregClass(dst) == HRcInt); + return X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(src), dst); +} + +/* Push an arg onto the host stack, in preparation for a call to a + helper function of some kind. Returns the number of 32-bit words + pushed. */ + +static Int pushArg ( ISelEnv* env, IRExpr* arg ) +{ + IRType arg_ty = typeOfIRExpr(env->type_env, arg); + if (arg_ty == Ity_I32) { + addInstr(env, X86Instr_Push(iselIntExpr_RMI(env, arg))); + return 1; + } else + if (arg_ty == Ity_I64) { + HReg rHi, rLo; + iselIntExpr64(&rHi, &rLo, env, arg); + addInstr(env, X86Instr_Push(X86RMI_Reg(rHi))); + addInstr(env, X86Instr_Push(X86RMI_Reg(rLo))); + return 2; + } + ppIRExpr(arg); + vpanic("pushArg(x86): can't handle arg of this type"); +} + +/* Complete the call to a helper function, by calling the + helper and clearing the args off the stack. */ + +static +void callHelperAndClearArgs ( ISelEnv* env, Char* name, Int n_arg_ws ) +{ + Addr64 helper; + UInt target; + + /* Find the function to call. Since the host -- for which we are + generating code -- is a 32-bit machine (x86) -- the upper 32 + bits of the helper address should be zero. */ + helper = env->find_helper(name); + vassert((helper & 0xFFFFFFFF00000000LL) == 0); + target = helper & 0xFFFFFFFF; + addInstr(env, X86Instr_Alu32R( + Xalu_MOV, + X86RMI_Imm(target), + hregX86_EAX())); + addInstr(env, X86Instr_Call(hregX86_EAX())); + if (n_arg_ws > 0) + addInstr(env, X86Instr_Alu32R(Xalu_ADD, + X86RMI_Imm(4*n_arg_ws), + hregX86_ESP())); +} + + /*---------------------------------------------------------*/ /*--- ISEL: Integer expressions (32/16/8 bit) ---*/ /*---------------------------------------------------------*/ @@ -797,11 +849,7 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) /* --------- CCALL --------- */ case Iex_CCall: { - Addr64 helper; Int i, n_args, n_arg_ws; - UInt target; - IRExpr* arg; - IRType arg_ty; HReg dst = newVRegI(env); vassert(ty == Ity_I32); @@ -814,38 +862,12 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) n_arg_ws = n_args = 0; while (e->Iex.CCall.args[n_args]) n_args++; - for (i = n_args-1; i >= 0; i--) { - arg = e->Iex.CCall.args[i]; - arg_ty = typeOfIRExpr(env->type_env, arg); - if (arg_ty == Ity_I32) { - addInstr(env, X86Instr_Push(iselIntExpr_RMI(env, arg))); - n_arg_ws ++; - } else - if (arg_ty == Ity_I64) { - HReg rHi, rLo; - iselIntExpr64(&rHi, &rLo, env, arg); - addInstr(env, X86Instr_Push(X86RMI_Reg(rHi))); - addInstr(env, X86Instr_Push(X86RMI_Reg(rLo))); - n_arg_ws += 2; - } - else goto irreducible; - } + for (i = n_args-1; i >= 0; i--) + n_arg_ws += pushArg(env, e->Iex.CCall.args[i]); + + /* call the helper, and get the args off the stack afterwards. */ + callHelperAndClearArgs( env, e->Iex.CCall.name, n_arg_ws ); - /* Find the function to call. Since the host -- for which we - are generating code -- is a 32-bit machine (x86) -- the upper - 32 bit of the helper address should be zero. */ - helper = env->find_helper(e->Iex.CCall.name); - vassert((helper & 0xFFFFFFFF00000000LL) == 0); - target = helper & 0xFFFFFFFF; - addInstr(env, X86Instr_Alu32R( - Xalu_MOV, - X86RMI_Imm(target), - hregX86_EAX())); - addInstr(env, X86Instr_Call(hregX86_EAX())); - if (n_arg_ws > 0) - addInstr(env, X86Instr_Alu32R(Xalu_ADD, - X86RMI_Imm(4*n_arg_ws), - hregX86_ESP())); addInstr(env, mk_MOVsd_RR(hregX86_EAX(), dst)); return dst; } @@ -1365,6 +1387,36 @@ static void iselIntExpr64_wrk ( HReg* rHi, HReg* rLo, ISelEnv* env, IRExpr* e ) return; } + /* ReinterpF64asI64(e) */ + /* Given an IEEE754 double, produce an I64 with the same bit + pattern. */ + if (e->tag == Iex_Unop + && e->Iex.Unop.op == Iop_ReinterpF64asI64) { + HReg rf = iselDblExpr(env, e->Iex.Unop.arg); + HReg tLo = newVRegI(env); + HReg tHi = newVRegI(env); + X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP()); + X86AMode* four_esp = X86AMode_IR(4, hregX86_ESP()); + /* subl $8, %esp */ + addInstr(env, + X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(8), hregX86_ESP())); + /* gstD %rf, 0(%esp) */ + addInstr(env, + X86Instr_FpLdSt(False/*store*/, 8, rf, zero_esp)); + /* movl 0(%esp), %tLo */ + addInstr(env, + X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(zero_esp), tLo)); + /* movl 4(%esp), %tHi */ + addInstr(env, + X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(four_esp), tHi)); + /* addl $8, %esp */ + addInstr(env, + X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(8), hregX86_ESP())); + *rHi = tHi; + *rLo = tLo; + return; + } + /* 64-bit shifts */ if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_Shl64) { @@ -1617,30 +1669,24 @@ static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ) } if (e->tag == Iex_Const) { - union { UInt i64[2]; Double f64; } u; + union { UInt u32x2[2]; ULong u64; Double f64; } u; HReg freg = newVRegF(env); vassert(sizeof(u) == 8); - vassert(sizeof(u.i64) == 8); + vassert(sizeof(u.u64) == 8); vassert(sizeof(u.f64) == 8); + vassert(sizeof(u.u32x2) == 8); if (e->Iex.Const.con->tag == Ico_F64) { u.f64 = e->Iex.Const.con->Ico.F64; - } - else if (e->Iex.Const.con->tag == Ico_NaN64) { - /* QNaN is 0 2047 1 0(51times) - == 0b 11111111111b 1 0(51times) - == 0x7FF8 0000 0000 0000 - */ - /* Since we're running on a little-endian target, and - generating code for one: */ - u.i64[1] = 0x7FF80000; - u.i64[0] = 0x00000000; + } + else if (e->Iex.Const.con->tag == Ico_F64i) { + u.u64 = e->Iex.Const.con->Ico.F64i; } else vpanic("iselDblExpr(x86): const"); - addInstr(env, X86Instr_Push(X86RMI_Imm(u.i64[1]))); - addInstr(env, X86Instr_Push(X86RMI_Imm(u.i64[0]))); + addInstr(env, X86Instr_Push(X86RMI_Imm(u.u32x2[1]))); + addInstr(env, X86Instr_Push(X86RMI_Imm(u.u32x2[0]))); addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, freg, X86AMode_IR(0, hregX86_ESP()))); addInstr(env, X86Instr_Alu32R(Xalu_ADD, @@ -1818,13 +1864,28 @@ static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ) hregX86_ESP())); return dst; } + case Iop_ReinterpI64asF64: { + /* Given an I64, produce an IEEE754 double with the same + bit pattern. */ + HReg dst = newVRegF(env); + HReg rHi, rLo; + iselIntExpr64( &rHi, &rLo, env, e->Iex.Unop.arg); + addInstr(env, X86Instr_Push(X86RMI_Reg(rHi))); + addInstr(env, X86Instr_Push(X86RMI_Reg(rLo))); + addInstr(env, X86Instr_FpLdSt( + True/*load*/, 8, dst, + X86AMode_IR(0, hregX86_ESP()))); + addInstr(env, X86Instr_Alu32R(Xalu_ADD, + X86RMI_Imm(8), + hregX86_ESP())); + return dst; + } case Iop_F32toF64: /* this is a no-op */ return iselFltExpr(env, e->Iex.Unop.arg); default: break; } - } /* --------- MULTIPLEX --------- */ @@ -1959,7 +2020,7 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) /* --------- TMP --------- */ case Ist_Tmp: { IRTemp tmp = stmt->Ist.Tmp.tmp; - IRType ty = lookupIRTypeEnv(env->type_env, tmp); + IRType ty = typeOfIRTemp(env->type_env, tmp); if (ty == Ity_I32 || ty == Ity_I16 || ty == Ity_I8) { X86RMI* rmi = iselIntExpr_RMI(env, stmt->Ist.Tmp.expr); HReg dst = lookupIRTemp(env, tmp); @@ -1989,6 +2050,40 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt ) break; } + /* --------- Call to DIRTY helper --------- */ + case Ist_Dirty: { + Int i, n_arg_ws, n_args; + IRType retty; + IRDirty* d = stmt->Ist.Dirty.details; + + /* push args on the stack, right to left. */ + n_arg_ws = n_args = 0; + while (d->args[n_args] != NULL) n_args++; + + for (i = n_args-1; i >= 0; i--) + n_arg_ws += pushArg(env, d->args[i]); + + /* call the helper, and get the args off the stack afterwards. */ + callHelperAndClearArgs( env, d->name, n_arg_ws ); + + /* Now figure out what to do with the returned value, if any. */ + if (d->tmp == INVALID_IRTEMP) + /* No return value. Nothing to do. */ + return; + + retty = typeOfIRTemp(env->type_env, d->tmp); + if (retty == Ity_I64) { + HReg dstHi, dstLo; + /* The returned value is in %edx:%eax. Park it in the + register-pair associated with tmp. */ + lookupIRTemp64( &dstHi, &dstLo, env, d->tmp); + addInstr(env, mk_MOVsd_RR(hregX86_EDX(),dstHi) ); + addInstr(env, mk_MOVsd_RR(hregX86_EAX(),dstLo) ); + return; + } + break; + } + /* --------- EXIT --------- */ case Ist_Exit: { X86RI* dst; diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index 4b4b5838ba..c16aae1178 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -36,13 +36,13 @@ void ppIRType ( IRType ty ) void ppIRConst ( IRConst* con ) { switch (con->tag) { - case Ico_Bit: vex_printf( "%d:Bit", con->Ico.Bit ? 1 : 0); break; - case Ico_U8: vex_printf( "0x%x:I8", (UInt)(con->Ico.U8)); break; - case Ico_U16: vex_printf( "0x%x:I16", (UInt)(con->Ico.U16)); break; - case Ico_U32: vex_printf( "0x%x:I32", (UInt)(con->Ico.U32)); break; - case Ico_U64: vex_printf( "0x%llx:I64", (ULong)(con->Ico.U64)); break; - case Ico_F64: vex_printf( "(f64 value)"); break; - case Ico_NaN64: vex_printf( "NaN:F64"); break; + case Ico_Bit: vex_printf( "%d:Bit", con->Ico.Bit ? 1 : 0); break; + case Ico_U8: vex_printf( "0x%x:I8", (UInt)(con->Ico.U8)); break; + case Ico_U16: vex_printf( "0x%x:I16", (UInt)(con->Ico.U16)); break; + case Ico_U32: vex_printf( "0x%x:I32", (UInt)(con->Ico.U32)); break; + case Ico_U64: vex_printf( "0x%llx:I64", (ULong)(con->Ico.U64)); break; + case Ico_F64: vex_printf( "F64{0x%llx}", *(ULong*)(&con->Ico.F64)); break; + case Ico_F64i: vex_printf( "F64i{0x%llx}", con->Ico.F64i); break; default: vpanic("ppIRConst"); } } @@ -162,6 +162,9 @@ void ppIROp ( IROp op ) case Iop_F32toF64: vex_printf("F32toF64"); return; case Iop_F64toF32: vex_printf("F64toF32"); return; + case Iop_ReinterpF64asI64: vex_printf("ReinterpF64asI64"); return; + case Iop_ReinterpI64asF64: vex_printf("ReinterpI64asF64"); return; + default: vpanic("ppIROp(1)"); } @@ -243,39 +246,82 @@ void ppIRExpr ( IRExpr* e ) } } +void ppIREffect ( IREffect fx ) +{ + switch (fx) { + case Ifx_None: vex_printf("noFX"); return; + case Ifx_Read: vex_printf("RdFX"); return; + case Ifx_Write: vex_printf("WrFX"); return; + case Ifx_Modify: vex_printf("MoFX"); return; + default: vpanic("ppIREffect"); + } +} + +void ppIRDirty ( IRDirty* d ) +{ + Int i; + vex_printf("DIRTY "); + if (d->mFx != Ifx_None) { + ppIREffect(d->mFx); + vex_printf("-mem("); + ppIRExpr(d->mAddr); + vex_printf(",%d) ", d->mSize); + } + for (i = 0; i < d->nFxState; i++) { + ppIREffect(d->fxState[i].fx); + vex_printf("-gst(%d,%d) ", d->fxState[i].offset, d->fxState[i].size); + } + vex_printf("::: "); + if (d->tmp != INVALID_IRTEMP) { + ppIRTemp(d->tmp); + vex_printf(" = "); + } + vex_printf("%s(", d->name); + for (i = 0; d->args[i] != NULL; i++) { + ppIRExpr(d->args[i]); + if (d->args[i+1] != NULL) { + vex_printf(","); + } + } + vex_printf(")"); +} + void ppIRStmt ( IRStmt* s ) { - switch (s->tag) { - case Ist_Put: - vex_printf( "PUT(%d) = ", s->Ist.Put.offset); - ppIRExpr(s->Ist.Put.expr); - break; - case Ist_PutI: - vex_printf( "PUTI[%d,%d](", s->Ist.PutI.minoff, s->Ist.PutI.maxoff); - ppIRExpr(s->Ist.PutI.offset); - vex_printf( ") = " ); - ppIRExpr(s->Ist.PutI.expr); - break; - case Ist_Tmp: - ppIRTemp(s->Ist.Tmp.tmp); - vex_printf( " = " ); - ppIRExpr(s->Ist.Tmp.expr); - break; - case Ist_STle: - vex_printf( "STle("); - ppIRExpr(s->Ist.STle.addr); - vex_printf( ") = "); - ppIRExpr(s->Ist.STle.data); - break; - case Ist_Exit: - vex_printf( "if (" ); - ppIRExpr(s->Ist.Exit.cond); - vex_printf( ") goto "); - ppIRConst(s->Ist.Exit.dst); - break; - default: - vpanic("ppIRStmt"); - } + switch (s->tag) { + case Ist_Put: + vex_printf( "PUT(%d) = ", s->Ist.Put.offset); + ppIRExpr(s->Ist.Put.expr); + break; + case Ist_PutI: + vex_printf( "PUTI[%d,%d](", s->Ist.PutI.minoff, s->Ist.PutI.maxoff); + ppIRExpr(s->Ist.PutI.offset); + vex_printf( ") = " ); + ppIRExpr(s->Ist.PutI.expr); + break; + case Ist_Tmp: + ppIRTemp(s->Ist.Tmp.tmp); + vex_printf( " = " ); + ppIRExpr(s->Ist.Tmp.expr); + break; + case Ist_STle: + vex_printf( "STle("); + ppIRExpr(s->Ist.STle.addr); + vex_printf( ") = "); + ppIRExpr(s->Ist.STle.data); + break; + case Ist_Dirty: + ppIRDirty(s->Ist.Dirty.details); + break; + case Ist_Exit: + vex_printf( "if (" ); + ppIRExpr(s->Ist.Exit.cond); + vex_printf( ") goto "); + ppIRConst(s->Ist.Exit.dst); + break; + default: + vpanic("ppIRStmt"); + } } void ppIRJumpKind ( IRJumpKind kind ) @@ -288,7 +334,7 @@ void ppIRJumpKind ( IRJumpKind kind ) case Ijk_Syscall: vex_printf("Syscall"); break; case Ijk_Yield: vex_printf("Yield"); break; default: vpanic("ppIRJumpKind"); - } + } } void ppIRTypeEnv ( IRTypeEnv* env ) { @@ -308,9 +354,6 @@ void ppIRTypeEnv ( IRTypeEnv* env ) { vex_printf( "\n"); } - - - void ppIRBB ( IRBB* bb ) { Int i; @@ -381,10 +424,11 @@ IRConst* IRConst_F64 ( Double f64 ) c->Ico.F64 = f64; return c; } -IRConst* IRConst_NaN64 ( void ) +IRConst* IRConst_F64i ( ULong f64i ) { - IRConst* c = LibVEX_Alloc(sizeof(IRConst)); - c->tag = Ico_NaN64; + IRConst* c = LibVEX_Alloc(sizeof(IRConst)); + c->tag = Ico_F64i; + c->Ico.F64i = f64i; return c; } @@ -466,6 +510,22 @@ IRExpr* IRExpr_Mux0X ( IRExpr* cond, IRExpr* expr0, IRExpr* exprX ) { } +/* Constructors -- IRDirty */ + +IRDirty* emptyIRDirty ( void ) +{ + IRDirty* d = LibVEX_Alloc(sizeof(IRDirty)); + d->name = NULL; + d->args = NULL; + d->tmp = INVALID_IRTEMP; + d->mFx = Ifx_None; + d->mAddr = NULL; + d->mSize = 0; + d->nFxState = 0; + return d; +} + + /* Constructors -- IRStmt */ IRStmt* IRStmt_Put ( Int off, IRExpr* value ) { @@ -499,6 +559,13 @@ IRStmt* IRStmt_STle ( IRExpr* addr, IRExpr* value ) { s->Ist.STle.data = value; return s; } +IRStmt* IRStmt_Dirty ( IRDirty* d ) +{ + IRStmt* s = LibVEX_Alloc(sizeof(IRStmt)); + s->tag = Ist_Dirty; + s->Ist.Dirty.details = d; + return s; +} IRStmt* IRStmt_Exit ( IRExpr* cond, IRConst* dst ) { IRStmt* s = LibVEX_Alloc(sizeof(IRStmt)); s->tag = Ist_Exit; @@ -555,20 +622,20 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) *t_arg1 = Ity_INVALID; *t_arg2 = Ity_INVALID; switch (op) { - case Iop_Add8: case Iop_Sub8: //case Iop_Adc8: case Iop_Sbb8: - case Iop_Mul8: case Iop_Or8: case Iop_And8: case Iop_Xor8: + case Iop_Add8: case Iop_Sub8: case Iop_Mul8: + case Iop_Or8: case Iop_And8: case Iop_Xor8: BINARY(Ity_I8,Ity_I8,Ity_I8); - case Iop_Add16: case Iop_Sub16: //case Iop_Adc16: case Iop_Sbb16: - case Iop_Mul16: case Iop_Or16: case Iop_And16: case Iop_Xor16: + case Iop_Add16: case Iop_Sub16: case Iop_Mul16: + case Iop_Or16: case Iop_And16: case Iop_Xor16: BINARY(Ity_I16,Ity_I16,Ity_I16); - case Iop_Add32: case Iop_Sub32: //case Iop_Adc32: case Iop_Sbb32: - case Iop_Mul32: case Iop_Or32: case Iop_And32: case Iop_Xor32: + case Iop_Add32: case Iop_Sub32: case Iop_Mul32: + case Iop_Or32: case Iop_And32: case Iop_Xor32: BINARY(Ity_I32,Ity_I32,Ity_I32); - case Iop_Add64: case Iop_Sub64: //case Iop_Adc64: case Iop_Sbb64: - case Iop_Mul64: case Iop_Or64: case Iop_And64: case Iop_Xor64: + case Iop_Add64: case Iop_Sub64: case Iop_Mul64: + case Iop_Or64: case Iop_And64: case Iop_Xor64: BINARY(Ity_I64,Ity_I64,Ity_I64); case Iop_Shl8: case Iop_Shr8: case Iop_Sar8: @@ -594,10 +661,8 @@ 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: + case Iop_CmpLT32S: case Iop_CmpLE32S: + case Iop_CmpLT32U: case Iop_CmpLE32U: COMPARISON(Ity_I32); case Iop_CmpEQ64: case Iop_CmpNE64: COMPARISON(Ity_I64); @@ -609,12 +674,10 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) case Iop_MullU32: case Iop_MullS32: BINARY(Ity_I64,Ity_I32,Ity_I32); - case Iop_Clz32: - case Iop_Ctz32: + case Iop_Clz32: case Iop_Ctz32: UNARY(Ity_I32,Ity_I32); - case Iop_DivModU64to32: - case Iop_DivModS64to32: + case Iop_DivModU64to32: case Iop_DivModS64to32: BINARY(Ity_I64,Ity_I64,Ity_I32); case Iop_16HIto8: case Iop_16to8: @@ -632,29 +695,27 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) case Iop_32HLto64: 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); - - case Iop_8Uto16: UNARY(Ity_I16,Ity_I8); - case Iop_8Sto16: UNARY(Ity_I16,Ity_I8); - - case Iop_16Uto32: UNARY(Ity_I32,Ity_I16); - case Iop_16Sto32: UNARY(Ity_I32,Ity_I16); - case Iop_32Sto64: UNARY(Ity_I64,Ity_I32); - case Iop_32Uto64: UNARY(Ity_I64,Ity_I32); - case Iop_32to8: UNARY(Ity_I8,Ity_I32); - - case Iop_ScaleF64: - case Iop_PRemF64: - case Iop_AtanF64: - case Iop_Yl2xF64: - case Iop_Yl2xp1F64: - case Iop_AddF64: case Iop_SubF64: - case Iop_MulF64: case Iop_DivF64: + 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: case Iop_8Sto32: + UNARY(Ity_I32,Ity_I8); + + case Iop_8Uto16: case Iop_8Sto16: + UNARY(Ity_I16,Ity_I8); + + case Iop_16Uto32: case Iop_16Sto32: + UNARY(Ity_I32,Ity_I16); + + case Iop_32Sto64: case Iop_32Uto64: + UNARY(Ity_I64,Ity_I32); + + case Iop_32to8: UNARY(Ity_I8,Ity_I32); + + case Iop_ScaleF64: case Iop_PRemF64: + case Iop_AtanF64: case Iop_Yl2xF64: case Iop_Yl2xp1F64: + case Iop_AddF64: case Iop_SubF64: case Iop_MulF64: case Iop_DivF64: BINARY(Ity_F64,Ity_F64,Ity_F64); case Iop_PRemC3210F64: case Iop_CmpF64: @@ -664,7 +725,9 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) UNARY(Ity_F64,Ity_F64); case Iop_I32toF64: UNARY(Ity_F64,Ity_I32); - case Iop_I64toF64: UNARY(Ity_F64,Ity_I64); + case Iop_I64toF64: case Iop_ReinterpI64asF64: + UNARY(Ity_F64,Ity_I64); + case Iop_ReinterpF64asI64: UNARY(Ity_I64, Ity_F64); case Iop_F64toI64: BINARY(Ity_I64, Ity_I32,Ity_F64); case Iop_F64toI32: BINARY(Ity_I32, Ity_I32,Ity_F64); @@ -738,10 +801,12 @@ IRTemp newIRTemp ( IRTypeEnv* env, IRType ty ) } } -/* Find the type of a temporary previously allocated in an - environment. */ -IRType lookupIRTypeEnv ( IRTypeEnv* env, IRTemp tmp ) +/*---------------------------------------------------------------*/ +/*--- Helper functions for the IR -- finding types of exprs ---*/ +/*---------------------------------------------------------------*/ + +IRType typeOfIRTemp ( IRTypeEnv* env, IRTemp tmp ) { vassert(tmp >= 0); vassert(tmp < env->types_used); @@ -749,10 +814,6 @@ IRType lookupIRTypeEnv ( IRTypeEnv* env, IRTemp tmp ) } -/*---------------------------------------------------------------*/ -/*--- Helper functions for the IR -- finding types of exprs ---*/ -/*---------------------------------------------------------------*/ - IRType typeOfIRConst ( IRConst* con ) { switch (con->tag) { @@ -762,7 +823,7 @@ IRType typeOfIRConst ( IRConst* con ) case Ico_U32: return Ity_I32; case Ico_U64: return Ity_I64; case Ico_F64: return Ity_F64; - case Ico_NaN64: return Ity_F64; + case Ico_F64i: return Ity_F64; default: vpanic("typeOfIRConst"); } } @@ -778,7 +839,7 @@ IRType typeOfIRExpr ( IRTypeEnv* tyenv, IRExpr* e ) case Iex_GetI: return e->Iex.GetI.ty; case Iex_Tmp: - return lookupIRTypeEnv(tyenv, e->Iex.Tmp.tmp); + return typeOfIRTemp(tyenv, e->Iex.Tmp.tmp); case Iex_Const: return typeOfIRConst(e->Iex.Const.con); case Iex_Binop: @@ -845,6 +906,15 @@ void sanityCheckFail ( IRBB* bb, IRStmt* stmt, Char* what ) range ones. Report any which are read and for which the current def_count is zero. */ +static +void useBeforeDef_Temp ( IRBB* bb, IRStmt* stmt, IRTemp tmp, Int* def_counts ) +{ + if (tmp < 0 || tmp >= bb->tyenv->types_used) + sanityCheckFail(bb,stmt, "out of range Temp in IRExpr"); + if (def_counts[tmp] < 1) + sanityCheckFail(bb,stmt, "IRTemp use before def in IRExpr"); +} + static void useBeforeDef_Expr ( IRBB* bb, IRStmt* stmt, IRExpr* expr, Int* def_counts ) { @@ -855,11 +925,8 @@ void useBeforeDef_Expr ( IRBB* bb, IRStmt* stmt, IRExpr* expr, Int* def_counts ) case Iex_GetI: useBeforeDef_Expr(bb,stmt,expr->Iex.GetI.offset,def_counts); break; - case Iex_Tmp: - if (expr->Iex.Tmp.tmp < 0 || expr->Iex.Tmp.tmp >= bb->tyenv->types_used) - sanityCheckFail(bb,stmt, "out of range Temp in IRExpr"); - if (def_counts[expr->Iex.Tmp.tmp] < 1) - sanityCheckFail(bb,stmt, "IRTemp use before def in IRExpr"); + case Iex_Tmp: + useBeforeDef_Temp(bb,stmt,expr->Iex.Tmp.tmp,def_counts); break; case Iex_Binop: useBeforeDef_Expr(bb,stmt,expr->Iex.Binop.arg1,def_counts); @@ -890,6 +957,8 @@ void useBeforeDef_Expr ( IRBB* bb, IRStmt* stmt, IRExpr* expr, Int* def_counts ) static void useBeforeDef_Stmt ( IRBB* bb, IRStmt* stmt, Int* def_counts ) { + Int i; + IRDirty* d; switch (stmt->tag) { case Ist_Put: useBeforeDef_Expr(bb,stmt,stmt->Ist.Put.expr,def_counts); @@ -905,6 +974,13 @@ void useBeforeDef_Stmt ( IRBB* bb, IRStmt* stmt, Int* def_counts ) useBeforeDef_Expr(bb,stmt,stmt->Ist.STle.addr,def_counts); useBeforeDef_Expr(bb,stmt,stmt->Ist.STle.data,def_counts); break; + case Ist_Dirty: + d = stmt->Ist.Dirty.details; + for (i = 0; d->args[i] != NULL; i++) + useBeforeDef_Expr(bb,stmt,d->args[i],def_counts); + if (d->mFx != Ifx_None) + useBeforeDef_Expr(bb,stmt,d->mAddr,def_counts); + break; case Ist_Exit: useBeforeDef_Expr(bb,stmt,stmt->Ist.Exit.cond,def_counts); break; @@ -1007,6 +1083,8 @@ void tcExpr ( IRBB* bb, IRStmt* stmt, IRExpr* expr, IRType gWordTy ) static void tcStmt ( IRBB* bb, IRStmt* stmt, IRType gWordTy ) { + Int i; + IRDirty* d; IRTypeEnv* tyenv = bb->tyenv; switch (stmt->tag) { case Ist_Put: @@ -1024,7 +1102,7 @@ void tcStmt ( IRBB* bb, IRStmt* stmt, IRType gWordTy ) break; case Ist_Tmp: tcExpr( bb, stmt, stmt->Ist.Tmp.expr, gWordTy ); - if (lookupIRTypeEnv(tyenv, stmt->Ist.Tmp.tmp) + if (typeOfIRTemp(tyenv, stmt->Ist.Tmp.tmp) != typeOfIRExpr(tyenv, stmt->Ist.Tmp.expr)) sanityCheckFail(bb,stmt,"IRStmt.Put.Tmp: tmp and expr do not match"); break; @@ -1036,6 +1114,35 @@ void tcStmt ( IRBB* bb, IRStmt* stmt, IRType gWordTy ) if (typeOfIRExpr(tyenv, stmt->Ist.STle.data) == Ity_Bit) sanityCheckFail(bb,stmt,"IRStmt.STle.data: cannot STle :: Ity_Bit"); break; + case Ist_Dirty: + /* Mostly check for various kinds of ill-formed dirty calls. */ + d = stmt->Ist.Dirty.details; + if (d->name == NULL) goto bad_dirty; + if (d->mFx == Ifx_None) { + if (d->mAddr != NULL || d->mSize != 0) + goto bad_dirty; + } else { + if (d->mAddr == NULL || d->mSize == 0) + goto bad_dirty; + } + if (d->nFxState < 0 || d->nFxState > VEX_N_FXSTATE) + goto bad_dirty; + for (i = 0; i < d->nFxState; i++) { + if (d->fxState[i].fx == Ifx_None) goto bad_dirty; + if (d->fxState[i].size <= 0) goto bad_dirty; + } + /* check types, minimally */ + if (d->tmp != INVALID_IRTEMP + && typeOfIRTemp(tyenv, d->tmp) == Ity_Bit) + sanityCheckFail(bb,stmt,"IRStmt.Dirty.dst :: Ity_Bit"); + for (i = 0; d->args[i] != NULL; i++) { + if (typeOfIRExpr(tyenv, d->args[i]) == Ity_Bit) + sanityCheckFail(bb,stmt,"IRStmt.Dirty.arg[i] :: Ity_Bit"); + } + break; + bad_dirty: + sanityCheckFail(bb,stmt,"IRStmt.Dirty: ill-formed"); + case Ist_Exit: tcExpr( bb, stmt, stmt->Ist.Exit.cond, gWordTy ); if (typeOfIRExpr(tyenv,stmt->Ist.Exit.cond) != Ity_Bit) @@ -1065,7 +1172,7 @@ void sanityCheckIRBB ( IRBB* bb, IRType guest_word_size ) /* Ensure each temp has a plausible type. */ for (i = 0; i < n_temps; i++) { - IRType ty = lookupIRTypeEnv(bb->tyenv,(IRTemp)i); + IRType ty = typeOfIRTemp(bb->tyenv,(IRTemp)i); if (!isPlausibleType(ty)) { vex_printf("Temp t%d declared with implausible type 0x%x\n", i, (UInt)ty); @@ -1084,12 +1191,27 @@ void sanityCheckIRBB ( IRBB* bb, IRType guest_word_size ) if (!stmt) continue; useBeforeDef_Stmt(bb,stmt,def_counts); + if (stmt->tag == Ist_Tmp) { if (stmt->Ist.Tmp.tmp < 0 || stmt->Ist.Tmp.tmp >= n_temps) - sanityCheckFail(bb, stmt, "Invalid temp in Tmp assignment"); + sanityCheckFail(bb, stmt, + "IRStmt.Tmp: destination tmp is out of range"); def_counts[stmt->Ist.Tmp.tmp]++; if (def_counts[stmt->Ist.Tmp.tmp] > 1) - sanityCheckFail(bb, stmt, "Tmp assigned more than once"); + sanityCheckFail(bb, stmt, + "IRStmt.Tmp: destinatiion tmp is assigned more than once"); + } + else + if (stmt->tag == Ist_Dirty + && stmt->Ist.Dirty.details->tmp != INVALID_IRTEMP) { + IRDirty* d = stmt->Ist.Dirty.details; + if (d->tmp < 0 || d->tmp >= n_temps) + sanityCheckFail(bb, stmt, + "IRStmt.Dirty: destination tmp is out of range"); + def_counts[d->tmp]++; + if (def_counts[d->tmp] > 1) + sanityCheckFail(bb, stmt, + "IRStmt.Dirty: destination tmp is assigned more than once"); } } diff --git a/VEX/priv/ir/iropt.c b/VEX/priv/ir/iropt.c index 59ebba9c58..2369975f97 100644 --- a/VEX/priv/ir/iropt.c +++ b/VEX/priv/ir/iropt.c @@ -145,7 +145,7 @@ static void addToH64 ( Hash64* h, ULong key, ULong val ) /* Clone the NULL-terminated vector of IRExpr*s attached to a CCall. */ -static IRExpr** copyIexCCallArgs ( IRExpr** vec ) +static IRExpr** copyIRExprCallArgs ( IRExpr** vec ) { Int i; IRExpr** newvec; @@ -210,7 +210,7 @@ static IRExpr* flatten_Expr ( IRBB* bb, IRExpr* ex ) return IRExpr_Tmp(t1); case Iex_CCall: - newargs = copyIexCCallArgs(ex->Iex.CCall.args); + newargs = copyIRExprCallArgs(ex->Iex.CCall.args); for (i = 0; newargs[i]; i++) newargs[i] = flatten_Expr(bb, newargs[i]); t1 = newIRTemp(bb->tyenv, ty); @@ -245,7 +245,9 @@ static IRExpr* flatten_Expr ( IRBB* bb, IRExpr* ex ) static void flatten_Stmt ( IRBB* bb, IRStmt* st ) { - IRExpr *e1, *e2; + Int i; + IRExpr *e1, *e2; + IRDirty *d, *d2; switch (st->tag) { case Ist_Put: e1 = flatten_Expr(bb, st->Ist.Put.expr); @@ -267,6 +269,20 @@ static void flatten_Stmt ( IRBB* bb, IRStmt* st ) e2 = flatten_Expr(bb, st->Ist.STle.data); addStmtToIRBB(bb, IRStmt_STle(e1,e2)); break; + case Ist_Dirty: + d = st->Ist.Dirty.details; + d2 = emptyIRDirty(); + *d2 = *d; + d2->args = copyIRExprCallArgs(d2->args); + if (d2->mFx != Ifx_None) { + d2->mAddr = flatten_Expr(bb, d2->mAddr); + } else { + vassert(d2->mAddr == NULL); + } + for (i = 0; d2->args[i]; i++) + d2->args[i] = flatten_Expr(bb, d2->args[i]); + addStmtToIRBB(bb, IRStmt_Dirty(d2)); + break; case Ist_Exit: e1 = flatten_Expr(bb, st->Ist.Exit.cond); addStmtToIRBB(bb, IRStmt_Exit(e1, st->Ist.Exit.dst)); @@ -556,7 +572,7 @@ static IRExpr* subst_Expr ( Hash64* env, IRExpr* ex ) if (ex->tag == Iex_CCall) { Int i; - IRExpr** args2 = copyIexCCallArgs ( ex->Iex.CCall.args ); + IRExpr** args2 = copyIRExprCallArgs ( ex->Iex.CCall.args ); for (i = 0; args2[i]; i++) { vassert(isAtom(args2[i])); args2[i] = subst_Expr(env, args2[i]); @@ -634,6 +650,24 @@ static IRStmt* subst_and_fold_Stmt ( Hash64* env, IRStmt* st ) ); } + if (st->tag == Ist_Dirty) { + Int i; + IRDirty *d, *d2; + d = st->Ist.Dirty.details; + d2 = emptyIRDirty(); + *d2 = *d; + d2->args = copyIRExprCallArgs(d2->args); + if (d2->mFx != Ifx_None) { + vassert(isAtom(d2->mAddr)); + d2->mAddr = fold_Expr(subst_Expr(env, d2->mAddr)); + } + for (i = 0; d2->args[i]; i++) { + vassert(isAtom(d2->args[i])); + d2->args[i] = fold_Expr(subst_Expr(env, d2->args[i])); + } + return IRStmt_Dirty(d2); + } + if (st->tag == Ist_Exit) { IRExpr* fcond; vassert(isAtom(st->Ist.Exit.cond)); @@ -651,7 +685,7 @@ static IRStmt* subst_and_fold_Stmt ( Hash64* env, IRStmt* st ) it is for now, since we'd have to truncate the BB at this point, which is tricky. */ /* fall out into the reconstruct-the-exit code. */ - vex_printf("subst_and_fold_Stmt: IRStmt_Exit became unconditional\n"); + vex_printf("vex iropt: IRStmt_Exit became unconditional\n"); } } return IRStmt_Exit(fcond,st->Ist.Exit.dst); @@ -738,6 +772,11 @@ static IRBB* cprop_BB ( IRBB* in ) -- really just operating a set or IRTemps. */ +static void addUses_Temp ( Hash64* set, IRTemp tmp ) +{ + addToH64(set, (ULong)tmp, 0); +} + static void addUses_Expr ( Hash64* set, IRExpr* e ) { Int i; @@ -765,7 +804,7 @@ static void addUses_Expr ( Hash64* set, IRExpr* e ) addUses_Expr(set, e->Iex.Unop.arg); return; case Iex_Tmp: - addToH64(set, (ULong)(e->Iex.Tmp.tmp), 0); + addUses_Temp(set, e->Iex.Tmp.tmp); return; case Iex_Const: case Iex_Get: @@ -779,14 +818,13 @@ static void addUses_Expr ( Hash64* set, IRExpr* e ) static void addUses_Stmt ( Hash64* set, IRStmt* st ) { + Int i; + IRDirty* d; switch (st->tag) { case Ist_PutI: addUses_Expr(set, st->Ist.PutI.offset); addUses_Expr(set, st->Ist.PutI.expr); return; - case Ist_Exit: - addUses_Expr(set, st->Ist.Exit.cond); - return; case Ist_Tmp: addUses_Expr(set, st->Ist.Tmp.expr); return; @@ -797,6 +835,16 @@ static void addUses_Stmt ( Hash64* set, IRStmt* st ) addUses_Expr(set, st->Ist.STle.addr); addUses_Expr(set, st->Ist.STle.data); return; + case Ist_Dirty: + d = st->Ist.Dirty.details; + if (d->mFx != Ifx_None) + addUses_Expr(set, d->mAddr); + for (i = 0; d->args[i] != NULL; i++) + addUses_Expr(set, d->args[i]); + return; + case Ist_Exit: + addUses_Expr(set, st->Ist.Exit.cond); + return; default: vex_printf("\n"); ppIRStmt(st); @@ -1028,6 +1076,9 @@ static void handle_gets_Stmt ( Hash64* env, IRStmt* st ) vassert(isAtom(st->Ist.STle.data)); return; + case Ist_Dirty: + return; + case Ist_Exit: vassert(isAtom(st->Ist.Exit.cond)); return; @@ -1193,28 +1244,33 @@ typedef Add the use-occurrences of temps in this expression to the environment. */ -static void occCount_Expr ( Hash64* env, IRExpr* e ) +static void occCount_Temp ( Hash64* env, IRTemp tmp ) { - Int i; - TmpInfo* ti; ULong res; + TmpInfo* ti; + if (lookupH64(env, &res, (ULong)tmp)) { + ti = (TmpInfo*)res; + ti->occ++; + } else { + ti = LibVEX_Alloc(sizeof(TmpInfo)); + ti->occ = 1; + ti->expr = NULL; + ti->eDoesLoad = False; + ti->eDoesGet = False; + ti->invalidateMe = False; + ti->origPos = -1; /* filed in properly later */ + addToH64(env, (ULong)tmp, (ULong)ti ); + } +} + +static void occCount_Expr ( Hash64* env, IRExpr* e ) +{ + Int i; switch (e->tag) { case Iex_Tmp: /* the only interesting case */ - if (lookupH64(env, &res, (ULong)(e->Iex.Tmp.tmp))) { - ti = (TmpInfo*)res; - ti->occ++; - } else { - ti = LibVEX_Alloc(sizeof(TmpInfo)); - ti->occ = 1; - ti->expr = NULL; - ti->eDoesLoad = False; - ti->eDoesGet = False; - ti->invalidateMe = False; - ti->origPos = -1; /* filed in properly later */ - addToH64(env, (ULong)(e->Iex.Tmp.tmp), (ULong)ti ); - } + occCount_Temp(env, e->Iex.Tmp.tmp); return; case Iex_Mux0X: @@ -1262,6 +1318,8 @@ static void occCount_Expr ( Hash64* env, IRExpr* e ) */ static void occCount_Stmt ( Hash64* env, IRStmt* st ) { + Int i; + IRDirty* d; switch (st->tag) { case Ist_Tmp: occCount_Expr(env, st->Ist.Tmp.expr); @@ -1277,6 +1335,13 @@ static void occCount_Stmt ( Hash64* env, IRStmt* st ) occCount_Expr(env, st->Ist.STle.addr); occCount_Expr(env, st->Ist.STle.data); return; + case Ist_Dirty: + d = st->Ist.Dirty.details; + if (d->mFx != Ifx_None) + occCount_Expr(env, d->mAddr); + for (i = 0; d->args[i]; i++) + occCount_Expr(env, d->args[i]); + return; case Ist_Exit: occCount_Expr(env, st->Ist.Exit.cond); return; @@ -1286,6 +1351,28 @@ static void occCount_Stmt ( Hash64* env, IRStmt* st ) } } +/* Look up a binding for tmp in the env. If found, return the bound + expression, and set the env's binding to NULL so it is marked as + used. If not found, return NULL. */ + +static IRExpr* tbSubst_Temp ( Hash64* env, IRTemp tmp ) +{ + TmpInfo* ti; + ULong res; + IRExpr* e; + if (lookupH64(env, &res, (ULong)tmp)) { + ti = (TmpInfo*)res; + e = ti->expr; + if (e) { + ti->expr = NULL; + return e; + } else { + return NULL; + } + } else { + return NULL; + } +} /* Traverse e, looking for temps. For each observed temp, see if env contains a binding for the temp, and if so return the bound value. @@ -1295,8 +1382,6 @@ static void occCount_Stmt ( Hash64* env, IRStmt* st ) static IRExpr* tbSubst_Expr ( Hash64* env, IRExpr* e ) { - TmpInfo* ti; - ULong res; IRExpr* e2; IRExpr** args2; Int i; @@ -1304,7 +1389,7 @@ static IRExpr* tbSubst_Expr ( Hash64* env, IRExpr* e ) switch (e->tag) { case Iex_CCall: - args2 = copyIexCCallArgs(e->Iex.CCall.args); + args2 = copyIRExprCallArgs(e->Iex.CCall.args); for (i = 0; args2[i]; i++) args2[i] = tbSubst_Expr(env,args2[i]); return IRExpr_CCall(e->Iex.CCall.name, @@ -1312,18 +1397,8 @@ static IRExpr* tbSubst_Expr ( Hash64* env, IRExpr* e ) args2 ); case Iex_Tmp: - if (lookupH64(env, &res, (ULong)(e->Iex.Tmp.tmp))) { - ti = (TmpInfo*)res; - e2 = ti->expr; - if (e2) { - ti->expr = NULL; - return e2; - } else { - return e; - } - } else { - return e; - } + e2 = tbSubst_Temp(env, e->Iex.Tmp.tmp); + return e2 ? e2 : e; case Iex_Mux0X: return IRExpr_Mux0X( tbSubst_Expr(env, e->Iex.Mux0X.cond), @@ -1366,12 +1441,15 @@ static IRExpr* tbSubst_Expr ( Hash64* env, IRExpr* e ) static IRStmt* tbSubst_Stmt ( Hash64* env, IRStmt* st ) { + Int i; + IRDirty* d; + IRDirty* d2; switch (st->tag) { - case Ist_STle: - return IRStmt_STle( - tbSubst_Expr(env, st->Ist.STle.addr), - tbSubst_Expr(env, st->Ist.STle.data) - ); + case Ist_STle: + return IRStmt_STle( + tbSubst_Expr(env, st->Ist.STle.addr), + tbSubst_Expr(env, st->Ist.STle.data) + ); case Ist_Tmp: return IRStmt_Tmp( st->Ist.Tmp.tmp, @@ -1395,6 +1473,15 @@ static IRStmt* tbSubst_Stmt ( Hash64* env, IRStmt* st ) tbSubst_Expr(env, st->Ist.Exit.cond), st->Ist.Exit.dst ); + case Ist_Dirty: + d = st->Ist.Dirty.details; + d2 = emptyIRDirty(); + *d2 = *d; + if (d2->mFx != Ifx_None) + d2->mAddr = tbSubst_Expr(env, d2->mAddr); + for (i = 0; d2->args[i]; i++) + d2->args[i] = tbSubst_Expr(env, d2->args[i]); + return IRStmt_Dirty(d2); default: vex_printf("\n"); ppIRStmt(st); vex_printf("\n"); vpanic("tbSubst_Stmt"); @@ -1602,8 +1689,10 @@ static void treebuild_BB ( IRBB* bb ) appeared. (Stupid algorithm): first, mark all bindings which need to be dumped. Then, dump them in the order in which they were defined. */ - invPut = st->tag == Ist_Put || st->tag == Ist_PutI; - invStore = st->tag == Ist_STle; + invPut = st->tag == Ist_Put + || st->tag == Ist_PutI || st->tag == Ist_Dirty; + invStore = st->tag == Ist_STle + || st->tag == Ist_Dirty; for (k = 0; k < env->used; k++) { if (!env->inuse[k]) diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 5196293853..a6bfa2869b 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -33,8 +33,10 @@ extern void ppIRType ( IRType ); typedef enum { Ico_Bit=0x12000, - Ico_U8, Ico_U16, Ico_U32, Ico_U64, Ico_F64, - Ico_NaN64 /* 64-bit IEEE QNaN. */ + Ico_U8, Ico_U16, Ico_U32, Ico_U64, + Ico_F64, /* 64-bit IEEE754 floating */ + Ico_F64i /* 64-bit unsigned int to be interpreted literally + as a IEEE754 double value. */ } IRConstTag; @@ -48,17 +50,18 @@ typedef UInt U32; ULong U64; Double F64; + ULong F64i; } Ico; } IRConst; -extern IRConst* IRConst_Bit ( Bool ); -extern IRConst* IRConst_U8 ( UChar ); -extern IRConst* IRConst_U16 ( UShort ); -extern IRConst* IRConst_U32 ( UInt ); -extern IRConst* IRConst_U64 ( ULong ); -extern IRConst* IRConst_F64 ( Double ); -extern IRConst* IRConst_NaN64 ( void ); +extern IRConst* IRConst_Bit ( Bool ); +extern IRConst* IRConst_U8 ( UChar ); +extern IRConst* IRConst_U16 ( UShort ); +extern IRConst* IRConst_U32 ( UInt ); +extern IRConst* IRConst_U64 ( ULong ); +extern IRConst* IRConst_F64 ( Double ); +extern IRConst* IRConst_F64i ( ULong ); extern void ppIRConst ( IRConst* ); @@ -203,7 +206,11 @@ typedef Iop_RoundF64, /* double <-> float. What does this mean -- does it round? */ - Iop_F32toF64, Iop_F64toF32 + Iop_F32toF64, Iop_F64toF32, + + /* Reinterpretation. Take an F64 and produce an I64 with + the same bit pattern, or vice versa. */ + Iop_ReinterpF64asI64, Iop_ReinterpI64asF64 } IROp; @@ -419,10 +426,10 @@ extern void ppIRExpr ( IRExpr* ); typedef enum { - Ifx_None, /* no effect */ - Ifx_Read, /* reads the resource */ - Ifx_Write, /* writes the resource */ - Ifx_Modify, /* modifies the resource */ + Ifx_None = 0x15000, /* no effect */ + Ifx_Read, /* reads the resource */ + Ifx_Write, /* writes the resource */ + Ifx_Modify, /* modifies the resource */ } IREffect; @@ -433,17 +440,16 @@ typedef struct { /* What to call, and details of args/results */ Char* name; /* name of the function to call */ - IRTemp* args; /* arg list, ends in INVALID_IRTEMP */ - IRType retty; /* type of returned value, or IRType_INVALID if none */ + IRExpr** args; /* arg list, ends in NULL */ IRTemp tmp; /* to assign result to, or INVALID_IRTEMP if none */ /* Mem effects; we allow only one R/W/M region to be stated */ IREffect mFx; /* indicates memory effects, if any */ - IRTemp mAddr; /* of access, or INVALID_IRTEMP if mFx==Ifx_None */ + IRExpr* mAddr; /* of access, or NULL if mFx==Ifx_None */ Int mSize; /* of access, or zero if mFx==Ifx_None */ /* Guest state effects; up to N allowed */ - Int nFxState; /* must be 0 .. VEX_N_FXSTATE */ + Int nFxState; /* must be 0 .. VEX_N_FXSTATE */ struct { IREffect fx; /* read, write or modify? */ Int offset; @@ -583,11 +589,11 @@ extern void ppIRBB ( IRBB* ); /* For messing with IR type environments */ extern IRTypeEnv* emptyIRTypeEnv ( void ); extern IRTemp newIRTemp ( IRTypeEnv*, IRType ); -extern IRType lookupIRTypeEnv ( IRTypeEnv*, IRTemp ); extern IRTypeEnv* copyIRTypeEnv ( IRTypeEnv* ); /* What is the type of this expression? */ extern IRType typeOfIRConst ( IRConst* ); +extern IRType typeOfIRTemp ( IRTypeEnv*, IRTemp ); extern IRType typeOfIRExpr ( IRTypeEnv*, IRExpr* ); /* Sanity check a BB of IR */