]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
x86 guest: Implement a whole bunch of SSE2 instructions, mostly
authorJulian Seward <jseward@acm.org>
Tue, 7 Dec 2004 19:02:18 +0000 (19:02 +0000)
committerJulian Seward <jseward@acm.org>
Tue, 7 Dec 2004 19:02:18 +0000 (19:02 +0000)
int-float conversions.  Very repetitive.

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

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

index 72c2c99956478b2ce495e18a8430bdf5d970831c..f7c7ca0208398e6e373938d03117605ab7e0d2eb 100644 (file)
@@ -598,9 +598,9 @@ static IRExpr* getXMMRegLane64 ( UInt xmmreg, Int laneno )
    return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_I64 );
 }
 
-static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
+static IRExpr* getXMMRegLane64F ( UInt xmmreg, Int laneno )
 {
-   return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
+   return IRExpr_Get( xmmGuestRegLane64offset(xmmreg,laneno), Ity_F64 );
 }
 
 static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
@@ -608,6 +608,11 @@ static IRExpr* getXMMRegLane32 ( UInt xmmreg, Int laneno )
    return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_I32 );
 }
 
+static IRExpr* getXMMRegLane32F ( UInt xmmreg, Int laneno )
+{
+   return IRExpr_Get( xmmGuestRegLane32offset(xmmreg,laneno), Ity_F32 );
+}
+
 static void putXMMReg ( UInt xmmreg, IRExpr* e )
 {
    vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_V128);
@@ -620,6 +625,12 @@ static void putXMMRegLane64 ( UInt xmmreg, Int laneno, IRExpr* e )
    stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
 }
 
+static void putXMMRegLane64F ( UInt xmmreg, Int laneno, IRExpr* e )
+{
+   vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F64);
+   stmt( IRStmt_Put( xmmGuestRegLane64offset(xmmreg,laneno), e ) );
+}
+
 static void putXMMRegLane32F ( UInt xmmreg, Int laneno, IRExpr* e )
 {
    vassert(typeOfIRExpr(irbb->tyenv,e) == Ity_F32);
@@ -7096,7 +7107,7 @@ static UInt dis_SSE_E_to_G_unary_lo32 (
    }
 }
 
-/* Helper for doing SSE 32Fx4 comparisons. */
+/* Helper for doing SSE FP comparisons. */
 
 static void findSSECmpOp ( Bool* needNot, IROp* op, 
                            Int imm8, Bool all_lanes, Int sz )
@@ -7127,7 +7138,23 @@ static void findSSECmpOp ( Bool* needNot, IROp* op,
          default: break;
       }
    }
-   if (sz == 8) {
+   if (sz == 8 && all_lanes) {
+      switch (imm8) {
+         case 0: *op = Iop_CmpEQ64Fx2; return;
+         case 1: *op = Iop_CmpLT64Fx2; return;
+         case 2: *op = Iop_CmpLE64Fx2; return;
+         case 3: *op = Iop_CmpUN64Fx2; return;
+         default: break;
+      }
+   }
+   if (sz == 8 && !all_lanes) {
+      switch (imm8) {
+         case 0: *op = Iop_CmpEQ64F0x2; return;
+         case 1: *op = Iop_CmpLT64F0x2; return;
+         case 2: *op = Iop_CmpLE64F0x2; return;
+         case 3: *op = Iop_CmpUN64F0x2; return;
+         default: break;
+      }
    }
    vpanic("findSSECmpOp(x86,guest)");
 }
@@ -7172,7 +7199,7 @@ static UInt dis_SSEcmp_E_to_G ( UChar sorb, UInt delta,
    if (needNot && all_lanes)
       mask = 0xFFFF;
    if (needNot && !all_lanes)
-      mask = 0x000F;
+      mask = sz==4 ? 0x000F : 0x00FF;
 
    putXMMReg( gregOfRM(rm), 
               needNot ? binop(Iop_Xor128, mkexpr(plain), mkV128(mask))
@@ -7403,12 +7430,11 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       goto decode_success;
    }
 
-   /* 0F 2F = COMISS -- 32F0x4 comparison G,E, and set ZCP */
+   /* 0F 2F = COMISS  -- 32F0x4 comparison G,E, and set ZCP */
    /* 0F 2E = UCOMISS -- 32F0x4 comparison G,E, and set ZCP */
-   if (insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
+   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
       IRTemp argL = newTemp(Ity_F32);
       IRTemp argR = newTemp(Ity_F32);
-      vassert(sz == 4);
       modrm = getIByte(delta+2);
       if (epartIsReg(modrm)) {
          assign( argR, getXMMRegLane32F( eregOfRM(modrm), 0/*lowest lane*/ ) );
@@ -7440,7 +7466,7 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
 
    /* 0F 2A = CVTPI2PS -- convert 2 x I32 in mem/mmx to 2 x F32 in low
       half xmm */
-   if (insn[0] == 0x0F && insn[1] == 0x2A) {
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x2A) {
       IRTemp arg64 = newTemp(Ity_I64);
       IRTemp rmode = newTemp(Ity_I32);
       vassert(sz == 4);
@@ -7516,13 +7542,12 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       I32 in mmx, according to prevailing SSE rounding mode */
    /* 0F 2C = CVTTPS2PI -- convert 2 x F32 in mem/low half xmm to 2 x
       I32 in mmx, rounding towards zero */
-   if (insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
+   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
       IRTemp dst64  = newTemp(Ity_I64);
       IRTemp rmode  = newTemp(Ity_I32);
       IRTemp f32lo  = newTemp(Ity_F32);
       IRTemp f32hi  = newTemp(Ity_F32);
       Bool   r2zero = insn[1] == 0x2C;
-      vassert(sz == 4);
 
       do_MMX_preamble();
       modrm = getIByte(delta+2);
@@ -7579,9 +7604,7 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       Bool   r2zero = insn[2] == 0x2C;
       vassert(sz == 4);
 
-      do_MMX_preamble();
       modrm = getIByte(delta+3);
-
       if (epartIsReg(modrm)) {
          delta += 3+1;
         assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
@@ -7613,8 +7636,7 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
    }
 
    /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
-   if (insn[0] == 0x0F && insn[1] == 0x5E) {
-      vassert(sz == 4);
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5E) {
       delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
       goto decode_success;
    }
@@ -8457,6 +8479,580 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       goto decode_success;
    }
 
+   /* 66 0F C2 = CMPPD -- 64Fx2 comparison from R/M to R */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC2) {
+      delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmppd", True, 8 );
+      goto decode_success;
+   }
+
+   /* F2 0F C2 = CMPSD -- 64F0x2 comparison from R/M to R */
+   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xC2) {
+      vassert(sz == 4);
+      delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpsd", False, 8 );
+      goto decode_success;
+   }
+
+   /* 66 0F 2F = COMISD  -- 64F0x2 comparison G,E, and set ZCP */
+   /* 66 0F 2E = UCOMISD -- 64F0x2 comparison G,E, and set ZCP */
+   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2F || insn[1] == 0x2E)) {
+      IRTemp argL = newTemp(Ity_F64);
+      IRTemp argR = newTemp(Ity_F64);
+      modrm = getIByte(delta+2);
+      if (epartIsReg(modrm)) {
+         assign( argR, getXMMRegLane64F( eregOfRM(modrm), 0/*lowest lane*/ ) );
+         delta += 2+1;
+         DIP("[u]comisd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
+                                  nameXMMReg(gregOfRM(modrm)) );
+      } else {
+         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
+        assign( argR, loadLE(Ity_F64, mkexpr(addr)) );
+         delta += 2+alen;
+         DIP("[u]comisd %s,%s\n", dis_buf,
+                                  nameXMMReg(gregOfRM(modrm)) );
+      }
+      assign( argL, getXMMRegLane64F( gregOfRM(modrm), 0/*lowest lane*/ ) );
+
+      stmt( IRStmt_Put( OFFB_CC_OP,   mkU32(X86G_CC_OP_COPY) ));
+      stmt( IRStmt_Put( OFFB_CC_DEP2, mkU32(0) ));
+      stmt( IRStmt_Put( 
+               OFFB_CC_DEP1,
+               binop( Iop_And32,
+                      binop(Iop_CmpF64, mkexpr(argL), mkexpr(argR)),
+                      mkU32(0x45)
+          )));
+
+      goto decode_success;
+   }
+
+   /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x
+      F64 in xmm(G) */
+   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) {
+      IRTemp arg64 = newTemp(Ity_I64);
+      vassert(sz == 4);
+
+      modrm = getIByte(delta+3);
+      if (epartIsReg(modrm)) {
+         assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) );
+         delta += 3+1;
+         DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
+                                 nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
+        assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
+         delta += 3+alen;
+         DIP("cvtdq2pd %s,%s\n", dis_buf,
+                                 nameXMMReg(gregOfRM(modrm)) );
+      }
+
+      putXMMRegLane64F( 
+         gregOfRM(modrm), 0,
+         unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)))
+      );
+
+      putXMMRegLane64F(
+         gregOfRM(modrm), 1, 
+         unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)))
+      );
+
+      goto decode_success;
+   }
+
+   /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in
+      xmm(G) */
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) {
+      IRTemp argV  = newTemp(Ity_V128);
+      IRTemp rmode = newTemp(Ity_I32);
+
+      modrm = getIByte(delta+2);
+      if (epartIsReg(modrm)) {
+         assign( argV, getXMMReg(eregOfRM(modrm)) );
+         delta += 2+1;
+         DIP("cvtdq2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
+                                 nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
+        assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
+         delta += 2+alen;
+         DIP("cvtdq2ps %s,%s\n", dis_buf,
+                                 nameXMMReg(gregOfRM(modrm)) );
+      }
+         
+      assign( rmode, get_sse_roundingmode() );
+      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
+
+#     define CVT(_t)  binop( Iop_F64toF32,                    \
+                             mkexpr(rmode),                   \
+                             unop(Iop_I32toF64,mkexpr(_t)))
+      
+      putXMMRegLane32F( gregOfRM(modrm), 3, CVT(t3) );
+      putXMMRegLane32F( gregOfRM(modrm), 2, CVT(t2) );
+      putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
+      putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
+
+#     undef CVT
+
+      goto decode_success;
+   }
+
+   /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
+      lo half xmm(G), and zero upper half */
+   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) {
+      IRTemp argV  = newTemp(Ity_V128);
+      IRTemp rmode = newTemp(Ity_I32);
+      vassert(sz == 4);
+
+      modrm = getIByte(delta+3);
+      if (epartIsReg(modrm)) {
+         assign( argV, getXMMReg(eregOfRM(modrm)) );
+         delta += 3+1;
+         DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
+                                 nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
+        assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
+         delta += 3+alen;
+         DIP("cvtpd2dq %s,%s\n", dis_buf,
+                                 nameXMMReg(gregOfRM(modrm)) );
+      }
+         
+      assign( rmode, get_sse_roundingmode() );
+      t0 = newTemp(Ity_F64);
+      t1 = newTemp(Ity_F64);
+      assign( t0, unop(Iop_ReinterpI64asF64, 
+                       unop(Iop_128to64, mkexpr(argV))) );
+      assign( t1, unop(Iop_ReinterpI64asF64, 
+                       unop(Iop_128HIto64, mkexpr(argV))) );
+      
+#     define CVT(_t)  binop( Iop_F64toI32,                    \
+                             mkexpr(rmode),                   \
+                             mkexpr(_t) )
+      
+      putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
+      putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
+      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
+      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
+
+#     undef CVT
+
+      goto decode_success;
+   }
+
+   /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
+      I32 in mmx, according to prevailing SSE rounding mode */
+   /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x
+      I32 in mmx, rounding towards zero */
+   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x2D || insn[1] == 0x2C)) {
+      IRTemp dst64  = newTemp(Ity_I64);
+      IRTemp rmode  = newTemp(Ity_I32);
+      IRTemp f64lo  = newTemp(Ity_F64);
+      IRTemp f64hi  = newTemp(Ity_F64);
+      Bool   r2zero = insn[1] == 0x2C;
+
+      do_MMX_preamble();
+      modrm = getIByte(delta+2);
+
+      if (epartIsReg(modrm)) {
+         delta += 2+1;
+        assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
+        assign(f64hi, getXMMRegLane64F(eregOfRM(modrm), 1));
+         DIP("cvt%spd2pi %s,%s\n", r2zero ? "t" : "",
+                                   nameXMMReg(eregOfRM(modrm)),
+                                   nameMMXReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
+        assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
+        assign(f64hi, loadLE(Ity_F64, binop( Iop_Add32, 
+                                              mkexpr(addr), 
+                                              mkU32(8) )));
+         delta += 2+alen;
+         DIP("cvt%spf2pi %s,%s\n", r2zero ? "t" : "",
+                                   dis_buf,
+                                   nameMMXReg(gregOfRM(modrm)));
+      }
+
+      if (r2zero) {
+         assign(rmode, mkU32((UInt)Irrm_ZERO) );
+      } else {
+         assign( rmode, get_sse_roundingmode() );
+      }
+
+      assign( 
+         dst64,
+         binop( Iop_32HLto64,
+                binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64hi) ),
+                binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo) )
+              )
+      );
+
+      putMMXReg(gregOfRM(modrm), mkexpr(dst64));
+      goto decode_success;
+   }
+
+   /* 66 0F 5A = CVTPD2PS -- convert 2 x F64 in mem/xmm to 2 x F32 in
+      lo half xmm(G), and zero upper half */
+   /* Note, this is practically identical to CVTPD2DQ.  It would have
+      been nicer to merge them together, but the insn[] offsets differ
+      by one. */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5A) {
+      IRTemp argV  = newTemp(Ity_V128);
+      IRTemp rmode = newTemp(Ity_I32);
+
+      modrm = getIByte(delta+2);
+      if (epartIsReg(modrm)) {
+         assign( argV, getXMMReg(eregOfRM(modrm)) );
+         delta += 2+1;
+         DIP("cvtpd2ps %s,%s\n", nameXMMReg(eregOfRM(modrm)),
+                                 nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
+        assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
+         delta += 2+alen;
+         DIP("cvtpd2ps %s,%s\n", dis_buf,
+                                 nameXMMReg(gregOfRM(modrm)) );
+      }
+         
+      assign( rmode, get_sse_roundingmode() );
+      t0 = newTemp(Ity_F64);
+      t1 = newTemp(Ity_F64);
+      assign( t0, unop(Iop_ReinterpI64asF64, 
+                       unop(Iop_128to64, mkexpr(argV))) );
+      assign( t1, unop(Iop_ReinterpI64asF64, 
+                       unop(Iop_128HIto64, mkexpr(argV))) );
+      
+#     define CVT(_t)  binop( Iop_F64toF32,                    \
+                             mkexpr(rmode),                   \
+                             mkexpr(_t) )
+      
+      putXMMRegLane32(  gregOfRM(modrm), 3, mkU32(0) );
+      putXMMRegLane32(  gregOfRM(modrm), 2, mkU32(0) );
+      putXMMRegLane32F( gregOfRM(modrm), 1, CVT(t1) );
+      putXMMRegLane32F( gregOfRM(modrm), 0, CVT(t0) );
+
+#     undef CVT
+
+      goto decode_success;
+   }
+
+   /* 66 0F 2A = CVTPI2PD -- convert 2 x I32 in mem/mmx to 2 x F64 in
+      xmm(G) */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x2A) {
+      IRTemp arg64 = newTemp(Ity_I64);
+
+      modrm = getIByte(delta+2);
+      do_MMX_preamble();
+      if (epartIsReg(modrm)) {
+         assign( arg64, getMMXReg(eregOfRM(modrm)) );
+         delta += 2+1;
+         DIP("cvtpi2pd %s,%s\n", nameMMXReg(eregOfRM(modrm)),
+                                 nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
+        assign( arg64, loadLE(Ity_I64, mkexpr(addr)) );
+         delta += 2+alen;
+         DIP("cvtpi2pd %s,%s\n", dis_buf,
+                                 nameXMMReg(gregOfRM(modrm)) );
+      }
+
+      putXMMRegLane64F( 
+         gregOfRM(modrm), 0,
+         unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64)) )
+      );
+
+      putXMMRegLane64F( 
+         gregOfRM(modrm), 1,
+         unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64)) )
+      );
+
+      goto decode_success;
+   }
+
+   /* 66 0F 5B = CVTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
+      xmm(G) */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5B) {
+      IRTemp argV  = newTemp(Ity_V128);
+      IRTemp rmode = newTemp(Ity_I32);
+
+      modrm = getIByte(delta+2);
+      if (epartIsReg(modrm)) {
+         assign( argV, getXMMReg(eregOfRM(modrm)) );
+         delta += 2+1;
+         DIP("cvtps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
+                                 nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
+        assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
+         delta += 2+alen;
+         DIP("cvtps2dq %s,%s\n", dis_buf,
+                                 nameXMMReg(gregOfRM(modrm)) );
+      }
+         
+      assign( rmode, get_sse_roundingmode() );
+      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
+
+      /* This is less than ideal.  If it turns out to be a performance
+        bottleneck it can be improved. */
+#     define CVT(_t)                            \
+        binop( Iop_F64toI32,                    \
+               mkexpr(rmode),                   \
+               unop( Iop_F32toF64,              \
+                     unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
+      
+      putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
+      putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
+      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
+      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
+
+#     undef CVT
+
+      goto decode_success;
+   }
+
+   /* 0F 5A = CVTPS2PD -- convert 2 x F32 in low half mem/xmm to 2 x
+      F64 in xmm(G). */
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5A) {
+      IRTemp f32lo = newTemp(Ity_F32);
+      IRTemp f32hi = newTemp(Ity_F32);
+
+      modrm = getIByte(delta+2);
+      if (epartIsReg(modrm)) {
+         assign( f32lo, getXMMRegLane32F(eregOfRM(modrm), 0) );
+         assign( f32hi, getXMMRegLane32F(eregOfRM(modrm), 1) );
+         delta += 2+1;
+         DIP("cvtps2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
+                                 nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
+        assign( f32lo, loadLE(Ity_F32, mkexpr(addr)) );
+        assign( f32hi, loadLE(Ity_F32, 
+                               binop(Iop_Add32,mkexpr(addr),mkU32(4))) );
+         delta += 2+alen;
+         DIP("cvtps2pd %s,%s\n", dis_buf,
+                                 nameXMMReg(gregOfRM(modrm)) );
+      }
+
+      putXMMRegLane64F( gregOfRM(modrm), 1,
+                        unop(Iop_F32toF64, mkexpr(f32hi)) );
+      putXMMRegLane64F( gregOfRM(modrm), 0,
+                        unop(Iop_F32toF64, mkexpr(f32lo)) );
+
+      goto decode_success;
+   }
+
+   /* F2 0F 2D = CVTSD2SI -- convert F64 in mem/low half xmm to
+      I32 in ireg, according to prevailing SSE rounding mode */
+   /* F2 0F 2C = CVTTSD2SI -- convert F64 in mem/low half xmm to
+      I32 in ireg, according to prevailing SSE rounding mode */
+   if (insn[0] == 0xF2 && insn[1] == 0x0F 
+       && (insn[2] == 0x2D || insn[2] == 0x2C)) {
+      IRTemp rmode = newTemp(Ity_I32);
+      IRTemp f64lo = newTemp(Ity_F64);
+      Bool   r2zero = insn[2] == 0x2C;
+      vassert(sz == 4);
+
+      modrm = getIByte(delta+3);
+      if (epartIsReg(modrm)) {
+         delta += 3+1;
+        assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
+         DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
+                                   nameXMMReg(eregOfRM(modrm)),
+                                   nameIReg(4, gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
+        assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
+         delta += 3+alen;
+         DIP("cvt%ssd2si %s,%s\n", r2zero ? "t" : "",
+                                   dis_buf,
+                                   nameIReg(4, gregOfRM(modrm)));
+      }
+
+      if (r2zero) {
+         assign( rmode, mkU32((UInt)Irrm_ZERO) );
+      } else {
+         assign( rmode, get_sse_roundingmode() );
+      }
+
+      putIReg(4, gregOfRM(modrm),
+                 binop( Iop_F64toI32, mkexpr(rmode), mkexpr(f64lo)) );
+
+      goto decode_success;
+   }
+
+   /* F2 0F 5A = CVTSD2SS -- convert F64 in mem/low half xmm to F32 in
+      low 1/4 xmm(G), according to prevailing SSE rounding mode */
+   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5A) {
+      IRTemp rmode = newTemp(Ity_I32);
+      IRTemp f64lo = newTemp(Ity_F64);
+      vassert(sz == 4);
+
+      modrm = getIByte(delta+3);
+      if (epartIsReg(modrm)) {
+         delta += 3+1;
+        assign(f64lo, getXMMRegLane64F(eregOfRM(modrm), 0));
+         DIP("cvtsd2ss %s,%s\n", nameXMMReg(eregOfRM(modrm)),
+                                 nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
+        assign(f64lo, loadLE(Ity_F64, mkexpr(addr)));
+         delta += 3+alen;
+         DIP("cvtsd2ss %s,%s\n", dis_buf,
+                                 nameXMMReg(gregOfRM(modrm)));
+      }
+
+      assign( rmode, get_sse_roundingmode() );
+      putXMMRegLane32F( 
+         gregOfRM(modrm), 0, 
+         binop( Iop_F64toF32, mkexpr(rmode), mkexpr(f64lo) )
+      );
+
+      goto decode_success;
+   }
+
+   /* F2 0F 2A = CVTSI2SD -- convert I32 in mem/ireg to F64 in low
+      half xmm */
+   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x2A) {
+      IRTemp arg32 = newTemp(Ity_I32);
+      vassert(sz == 4);
+
+      modrm = getIByte(delta+3);
+      do_MMX_preamble();
+      if (epartIsReg(modrm)) {
+         assign( arg32, getIReg(4, eregOfRM(modrm)) );
+         delta += 3+1;
+         DIP("cvtsi2sd %s,%s\n", nameIReg(4, eregOfRM(modrm)),
+                                 nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
+        assign( arg32, loadLE(Ity_I32, mkexpr(addr)) );
+         delta += 3+alen;
+         DIP("cvtsi2sd %s,%s\n", dis_buf,
+                                 nameXMMReg(gregOfRM(modrm)) );
+      }
+
+      putXMMRegLane64F( 
+         gregOfRM(modrm), 0,
+         unop(Iop_I32toF64, mkexpr(arg32)) );
+
+      goto decode_success;
+   }
+
+   /* F3 0F 5A = CVTSS2SD -- convert F32 in mem/low 1/4 xmm to F64 in
+      low half xmm(G) */
+   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5A) {
+      IRTemp f32lo = newTemp(Ity_F32);
+      vassert(sz == 4);
+
+      modrm = getIByte(delta+3);
+      if (epartIsReg(modrm)) {
+         delta += 3+1;
+        assign(f32lo, getXMMRegLane32F(eregOfRM(modrm), 0));
+         DIP("cvtss2sd %s,%s\n", nameXMMReg(eregOfRM(modrm)),
+                                 nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
+        assign(f32lo, loadLE(Ity_F32, mkexpr(addr)));
+         delta += 3+alen;
+         DIP("cvtss2sd %s,%s\n", dis_buf,
+                                 nameXMMReg(gregOfRM(modrm)));
+      }
+
+      putXMMRegLane64F( gregOfRM(modrm), 0, 
+                        unop( Iop_F32toF64, mkexpr(f32lo) ) );
+
+      goto decode_success;
+   }
+
+   /* 66 0F E6 = CVTTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in
+      lo half xmm(G), and zero upper half, rounding towards zero */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE6) {
+      IRTemp argV  = newTemp(Ity_V128);
+      IRTemp rmode = newTemp(Ity_I32);
+
+      modrm = getIByte(delta+2);
+      if (epartIsReg(modrm)) {
+         assign( argV, getXMMReg(eregOfRM(modrm)) );
+         delta += 2+1;
+         DIP("cvttpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
+                                  nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
+        assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
+         delta += 2+alen;
+         DIP("cvttpd2dq %s,%s\n", dis_buf,
+                                  nameXMMReg(gregOfRM(modrm)) );
+      }
+
+      assign( rmode, mkU32((UInt)Irrm_ZERO) );
+
+      t0 = newTemp(Ity_F64);
+      t1 = newTemp(Ity_F64);
+      assign( t0, unop(Iop_ReinterpI64asF64, 
+                       unop(Iop_128to64, mkexpr(argV))) );
+      assign( t1, unop(Iop_ReinterpI64asF64, 
+                       unop(Iop_128HIto64, mkexpr(argV))) );
+      
+#     define CVT(_t)  binop( Iop_F64toI32,                    \
+                             mkexpr(rmode),                   \
+                             mkexpr(_t) )
+      
+      putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) );
+      putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) );
+      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
+      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
+
+#     undef CVT
+
+      goto decode_success;
+   }
+
+   /* F3 0F 5B = CVTTPS2DQ -- convert 4 x F32 in mem/xmm to 4 x I32 in
+      xmm(G), rounding towards zero */
+   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5B) {
+      IRTemp argV  = newTemp(Ity_V128);
+      IRTemp rmode = newTemp(Ity_I32);
+      vassert(sz == 4);
+
+      modrm = getIByte(delta+3);
+      if (epartIsReg(modrm)) {
+         assign( argV, getXMMReg(eregOfRM(modrm)) );
+         delta += 3+1;
+         DIP("cvttps2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)),
+                                  nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
+        assign( argV, loadLE(Ity_V128, mkexpr(addr)) );
+         delta += 3+alen;
+         DIP("cvttps2dq %s,%s\n", dis_buf,
+                                  nameXMMReg(gregOfRM(modrm)) );
+      }
+         
+      assign( rmode, mkU32((UInt)Irrm_ZERO) );
+      breakup128to32s( argV, &t3, &t2, &t1, &t0 );
+
+      /* This is less than ideal.  If it turns out to be a performance
+        bottleneck it can be improved. */
+#     define CVT(_t)                            \
+        binop( Iop_F64toI32,                    \
+               mkexpr(rmode),                   \
+               unop( Iop_F32toF64,              \
+                     unop( Iop_ReinterpI32asF32, mkexpr(_t))) )
+      
+      putXMMRegLane32( gregOfRM(modrm), 3, CVT(t3) );
+      putXMMRegLane32( gregOfRM(modrm), 2, CVT(t2) );
+      putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) );
+      putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) );
+
+#     undef CVT
+
+      goto decode_success;
+   }
+
+   /* 66 0F 5E = DIVPD -- div 64Fx2 from R/M to R */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5E) {
+      delta = dis_SSE_E_to_G_all( sorb, delta+2, "divpd", Iop_Div64Fx2 );
+      goto decode_success;
+   }
+
+
 
 //-- 
 //--    /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
index 94467b3dfaf47b6c3c4b32efdf442c81a08e5976..fb50ee6d23604932fa5ed1d4e6713095fad79cc1 100644 (file)
@@ -2131,6 +2131,21 @@ static HReg iselFltExpr_wrk ( ISelEnv* env, IRExpr* e )
       return res;
    }
 
+   if (e->tag == Iex_Unop
+       && e->Iex.Unop.op == Iop_ReinterpI32asF32) {
+       /* Given an I32, produce an IEEE754 float with the same bit
+          pattern. */
+      HReg    dst = newVRegF(env);
+      X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Unop.arg);
+      /* paranoia */
+      addInstr(env, X86Instr_Push(rmi));
+      addInstr(env, X86Instr_FpLdSt(
+                       True/*load*/, 4, dst, 
+                       X86AMode_IR(0, hregX86_ESP())));
+      add_to_esp(env, 4);
+      return dst;
+   }
+
    ppIRExpr(e);
    vpanic("iselFltExpr_wrk");
 }
@@ -2219,6 +2234,14 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
       return res;
    }
 
+   if (e->tag == Iex_Get) {
+      X86AMode* am = X86AMode_IR( e->Iex.Get.offset,
+                                  hregX86_EBP() );
+      HReg res = newVRegF(env);
+      addInstr(env, X86Instr_FpLdSt( True/*load*/, 8, res, am ));
+      return res;
+   }
+
    if (e->tag == Iex_GetI) {
       X86AMode* am 
          = genGuestArrayOffset(
@@ -2753,6 +2776,13 @@ static void iselStmt ( ISelEnv* env, IRStmt* stmt )
          addInstr(env, X86Instr_FpLdSt( False/*store*/, 4, f32, am ));
          return;
       }
+      if (ty == Ity_F64) {
+         HReg f64 = iselDblExpr(env, stmt->Ist.Put.data);
+         X86AMode* am  = X86AMode_IR(stmt->Ist.Put.offset, hregX86_EBP());
+         set_FPU_rounding_default(env); /* paranoia */
+         addInstr(env, X86Instr_FpLdSt( False/*store*/, 8, f64, am ));
+         return;
+      }
       break;
    }
 
index 696143d789a1352ec247f79e39a4df3fa4835277..85069b337f0fdaba5da4a6ef41ee3e0c89921bef 100644 (file)
@@ -220,6 +220,8 @@ void ppIROp ( IROp op )
 
       case Iop_ReinterpF64asI64: vex_printf("ReinterpF64asI64"); return;
       case Iop_ReinterpI64asF64: vex_printf("ReinterpI64asF64"); return;
+      case Iop_ReinterpF32asI32: vex_printf("ReinterpF32asI32"); return;
+      case Iop_ReinterpI32asF32: vex_printf("ReinterpI32asF32"); return;
 
       case Iop_And128:  vex_printf("And128"); return;
       case Iop_Or128:   vex_printf("Or128");  return;
@@ -1134,6 +1136,8 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
 
       case Iop_ReinterpI64asF64: UNARY(Ity_F64, Ity_I64);
       case Iop_ReinterpF64asI64: UNARY(Ity_I64, Ity_F64);
+      case Iop_ReinterpI32asF32: UNARY(Ity_F32, Ity_I32);
+      case Iop_ReinterpF32asI32: UNARY(Ity_I32, Ity_F32);
 
       case Iop_F64toI16: BINARY(Ity_I16, Ity_I32,Ity_F64);
       case Iop_F64toI32: BINARY(Ity_I32, Ity_I32,Ity_F64);
index fe3b1b201554b9facf0222b2dfafbbb2a6249d13..f0644764e60498c6cd9dff2dd38758d1799724ad 100644 (file)
@@ -325,6 +325,7 @@ typedef
       /* Reinterpretation.  Take an F64 and produce an I64 with 
          the same bit pattern, or vice versa. */
       Iop_ReinterpF64asI64, Iop_ReinterpI64asF64,
+      Iop_ReinterpF32asI32, Iop_ReinterpI32asF32,
 
       /* ------------------ 128-bit SIMD. ------------------ */