]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Fully install generic IR machinery for dirty helper calls and make it
authorJulian Seward <jseward@acm.org>
Mon, 20 Sep 2004 14:54:28 +0000 (14:54 +0000)
committerJulian Seward <jseward@acm.org>
Mon, 20 Sep 2004 14:54:28 +0000 (14:54 +0000)
work.  Use it to implement x86 10-byte loads/stores.

git-svn-id: svn://svn.valgrind.org/vex/trunk@274

VEX/priv/guest-x86/ghelpers.c
VEX/priv/guest-x86/toIR.c
VEX/priv/host-x86/isel.c
VEX/priv/ir/irdefs.c
VEX/priv/ir/iropt.c
VEX/pub/libvex_ir.h

index 61272925a200cb172e70278cfa8a3a8a359e6aa8..0cc3caccc48e72216af975fc5e75b7a1e91cd0fb 100644 (file)
 #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 ..                    ---*/
index f3d323d00f0b8469736211d20688a0a4eb26fd7d..585e9be4c0bed765408f74c435f481037a835fa3 100644 (file)
@@ -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;
-        }
+         }
       }
    }
 
index e0812f9538192c78e318431c64d9d8f06d8a6f90..ad7ac90ee718ec3224123c6782cc6137e0c76567 100644 (file)
@@ -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;
index 4b4b5838bab2b8b8968f9b36b84deee989f5cedd..c16aae1178c2086397b8d4135e62b4247e7a3e79 100644 (file)
@@ -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");
       }
    }
 
index 59ebba9c58f8bf422759146da225a34176908451..2369975f97985149f782d7bc9f73dbb9b88fd2d1 100644 (file)
@@ -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])
index 5196293853c9651618b2bd417d7d7e44f63b4684..a6bfa2869bf29ed00504e29d17373d12395e331d 100644 (file)
@@ -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 */