work. Use it to implement x86 10-byte loads/stores.
git-svn-id: svn://svn.valgrind.org/vex/trunk@274
#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.
}
-/* 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");
}
return (*p == 0x10);
}
-UInt calculate_FXAM ( UInt tag, ULong dbl )
+static UInt calculate_FXAM ( UInt tag, ULong dbl )
{
Bool mantissaIsZero;
Int bexp;
}
}
+/* 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 .. ---*/
/* --- 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. --------- */
/* 0 means empty */
value,
/* non-0 means full */
- mkNaN64()
+ mkQNaN64()
)
);
}
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
return
IRExpr_Mux0X( get_ST_TAG(i),
/* 0 means empty */
- mkNaN64(),
+ mkQNaN64(),
/* non-0 means full */
get_ST_UNCHECKED(i));
}
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;
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");
default:
goto decode_fail;
- }
+ }
}
}
? (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*/
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 ---*/
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) ---*/
/*---------------------------------------------------------*/
/* --------- 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);
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;
}
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) {
}
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,
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 --------- */
/* --------- 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);
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;
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");
}
}
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)");
}
}
}
+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 )
case Ijk_Syscall: vex_printf("Syscall"); break;
case Ijk_Yield: vex_printf("Yield"); break;
default: vpanic("ppIRJumpKind");
- }
+ }
}
void ppIRTypeEnv ( IRTypeEnv* env ) {
vex_printf( "\n");
}
-
-
-
void ppIRBB ( IRBB* bb )
{
Int i;
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;
}
}
+/* 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 ) {
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;
*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:
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);
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:
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:
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);
}
}
-/* 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);
}
-/*---------------------------------------------------------------*/
-/*--- Helper functions for the IR -- finding types of exprs ---*/
-/*---------------------------------------------------------------*/
-
IRType typeOfIRConst ( IRConst* con )
{
switch (con->tag) {
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");
}
}
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:
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 )
{
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);
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);
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;
static
void tcStmt ( IRBB* bb, IRStmt* stmt, IRType gWordTy )
{
+ Int i;
+ IRDirty* d;
IRTypeEnv* tyenv = bb->tyenv;
switch (stmt->tag) {
case Ist_Put:
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;
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)
/* 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);
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");
}
}
/* 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;
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);
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);
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));
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]);
);
}
+ 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));
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);
-- 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;
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:
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;
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);
vassert(isAtom(st->Ist.STle.data));
return;
+ case Ist_Dirty:
+ return;
+
case Ist_Exit:
vassert(isAtom(st->Ist.Exit.cond));
return;
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:
*/
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);
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;
}
}
+/* 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.
static IRExpr* tbSubst_Expr ( Hash64* env, IRExpr* e )
{
- TmpInfo* ti;
- ULong res;
IRExpr* e2;
IRExpr** args2;
Int i;
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,
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),
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,
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");
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])
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;
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* );
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;
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;
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;
/* 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 */