]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
x86 guest: finish SSE2 floating point insns.
authorJulian Seward <jseward@acm.org>
Wed, 8 Dec 2004 14:37:10 +0000 (14:37 +0000)
committerJulian Seward <jseward@acm.org>
Wed, 8 Dec 2004 14:37:10 +0000 (14:37 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@634

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

index 05913d0a1910bd624adf146a41b7e941dcc3d4c5..987765843e05713280cb2e7e83be5afbfeee875c 100644 (file)
@@ -7101,6 +7101,48 @@ static UInt dis_SSE_E_to_G_unary_lo32 (
    }
 }
 
+/* Lowest 64-bit lane only unary SSE operation, G = op(E). */
+
+static UInt dis_SSE_E_to_G_unary_lo64 ( 
+               UChar sorb, UInt delta, 
+               HChar* opname, IROp op
+            )
+{
+   /* First we need to get the old G value and patch the low 64 bits
+      of the E operand into it.  Then apply op and write back to G. */
+   HChar   dis_buf[50];
+   Int     alen;
+   IRTemp  addr;
+   UChar   rm = getIByte(delta);
+   IRTemp  oldG0 = newTemp(Ity_V128);
+   IRTemp  oldG1 = newTemp(Ity_V128);
+
+   assign( oldG0, getXMMReg(gregOfRM(rm)) );
+
+   if (epartIsReg(rm)) {
+      assign( oldG1, 
+              binop( Iop_Set128lo64,
+                     mkexpr(oldG0),
+                     getXMMRegLane64(eregOfRM(rm), 0)) );
+      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
+      DIP("%s %s,%s\n", opname,
+                        nameXMMReg(eregOfRM(rm)),
+                        nameXMMReg(gregOfRM(rm)) );
+      return delta+1;
+   } else {
+      addr = disAMode ( &alen, sorb, delta, dis_buf );
+      assign( oldG1, 
+              binop( Iop_Set128lo64,
+                     mkexpr(oldG0),
+                     loadLE(Ity_I64, mkexpr(addr)) ));
+      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
+      DIP("%s %s,%s\n", opname,
+                        dis_buf,
+                        nameXMMReg(gregOfRM(rm)) );
+      return delta+alen;
+   }
+}
+
 /* Helper for doing SSE FP comparisons. */
 
 static void findSSECmpOp ( Bool* needNot, IROp* op, 
@@ -7925,8 +7967,7 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
    }
 
    /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
-   if (insn[0] == 0x0F && insn[1] == 0x59) {
-      vassert(sz == 4);
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) {
       delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
       goto decode_success;
    }
@@ -7939,8 +7980,7 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
    }
 
    /* 0F 56 = ORPS -- G = G and E */
-   if (insn[0] == 0x0F && insn[1] == 0x56) {
-      vassert(sz == 4);
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) {
       delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_Or128 );
       goto decode_success;
    }
@@ -8282,14 +8322,13 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
    }
 
    /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */
-   if (insn[0] == 0x0F && insn[1] == 0xC6) {
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) {
       Int    select;
       IRTemp sV, dV;
       IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
       sV = newTemp(Ity_V128);
       dV = newTemp(Ity_V128);
       s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
-      vassert(sz == 4);
       modrm = insn[2];
       assign( dV, getXMMReg(gregOfRM(modrm)) );
 
@@ -8329,8 +8368,7 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
    }
 
    /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */
-   if (insn[0] == 0x0F && insn[1] == 0x51) {
-      vassert(sz == 4);
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) {
       delta = dis_SSE_E_to_G_unary_all( sorb, delta+2, 
                                         "sqrtps", Iop_Sqrt32Fx4 );
       goto decode_success;
@@ -8370,13 +8408,12 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
    }
 
    /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */
-   if (insn[0] == 0x0F && insn[1] == 0x5C) {
-      vassert(sz == 4);
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) {
       delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 );
       goto decode_success;
    }
 
-   /* F3 0F 58 = SUBSS -- sub 32F0x4 from R/M to R */
+   /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */
    if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) {
       vassert(sz == 4);
       delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 );
@@ -8386,14 +8423,13 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
    /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */
    /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */
    /* These just appear to be special cases of SHUFPS */
-   if (insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
+   if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
       IRTemp sV, dV;
       IRTemp s3, s2, s1, s0, d3, d2, d1, d0;
       Bool hi = insn[1] == 0x15;
       sV = newTemp(Ity_V128);
       dV = newTemp(Ity_V128);
       s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID;
-      vassert(sz == 4);
       modrm = insn[2];
       assign( dV, getXMMReg(gregOfRM(modrm)) );
 
@@ -8425,8 +8461,7 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
    }
 
    /* 0F 57 = XORPS -- G = G and E */
-   if (insn[0] == 0x0F && insn[1] == 0x57) {
-      vassert(sz == 4);
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) {
       delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_Xor128 );
       goto decode_success;
    }
@@ -9413,6 +9448,153 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       }
    }
 
+   /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) {
+      delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 );
+      goto decode_success;
+   }
+
+   /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */
+   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) {
+      vassert(sz == 4);
+      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 );
+      goto decode_success;
+   }
+
+   /* 66 0F 56 = ORPD -- G = G and E */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) {
+      delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_Or128 );
+      goto decode_success;
+   }
+
+   /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) {
+      Int    select;
+      IRTemp sV = newTemp(Ity_V128);
+      IRTemp dV = newTemp(Ity_V128);
+      IRTemp s1 = newTemp(Ity_I64);
+      IRTemp s0 = newTemp(Ity_I64);
+      IRTemp d1 = newTemp(Ity_I64);
+      IRTemp d0 = newTemp(Ity_I64);
+
+      modrm = insn[2];
+      assign( dV, getXMMReg(gregOfRM(modrm)) );
+
+      if (epartIsReg(modrm)) {
+         assign( sV, getXMMReg(eregOfRM(modrm)) );
+         select = (Int)insn[3];
+         delta += 2+2;
+         DIP("shufpd $%d,%s,%s\n", select, 
+                                   nameXMMReg(eregOfRM(modrm)),
+                                   nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
+         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
+         select = (Int)insn[2+alen];
+         delta += 3+alen;
+         DIP("shufpd $%d,%s,%s\n", select, 
+                                   dis_buf,
+                                   nameXMMReg(gregOfRM(modrm)));
+      }
+
+      assign( d1, unop(Iop_128HIto64, mkexpr(dV)) );
+      assign( d0, unop(Iop_128to64,   mkexpr(dV)) );
+      assign( s1, unop(Iop_128HIto64, mkexpr(sV)) );
+      assign( s0, unop(Iop_128to64,   mkexpr(sV)) );
+
+#     define SELD(n) mkexpr((n)==0 ? d0 : d1)
+#     define SELS(n) mkexpr((n)==0 ? s0 : s1)
+
+      putXMMReg(
+         gregOfRM(modrm), 
+         binop(Iop_64HLto128, SELS((select>>1)&1), SELD((select>>0)&1) )
+      );
+
+#     undef SELD
+#     undef SELS
+
+      goto decode_success;
+   }
+
+   /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) {
+      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2, 
+                                        "sqrtpd", Iop_Sqrt64Fx2 );
+      goto decode_success;
+   }
+
+   /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */
+   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) {
+      vassert(sz == 4);
+      delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3, 
+                                         "sqrtsd", Iop_Sqrt64F0x2 );
+      goto decode_success;
+   }
+
+   /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) {
+      delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 );
+      goto decode_success;
+   }
+
+   /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */
+   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) {
+      vassert(sz == 4);
+      delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 );
+      goto decode_success;
+   }
+
+   /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */
+   /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */
+   /* These just appear to be special cases of SHUFPS */
+   if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) {
+      IRTemp s1 = newTemp(Ity_I64);
+      IRTemp s0 = newTemp(Ity_I64);
+      IRTemp d1 = newTemp(Ity_I64);
+      IRTemp d0 = newTemp(Ity_I64);
+      IRTemp sV = newTemp(Ity_V128);
+      IRTemp dV = newTemp(Ity_V128);
+      Bool   hi = insn[1] == 0x15;
+
+      modrm = insn[2];
+      assign( dV, getXMMReg(gregOfRM(modrm)) );
+
+      if (epartIsReg(modrm)) {
+         assign( sV, getXMMReg(eregOfRM(modrm)) );
+         delta += 2+1;
+         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
+                                  nameXMMReg(eregOfRM(modrm)),
+                                  nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
+         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
+         delta += 2+alen;
+         DIP("unpck%sps %s,%s\n", hi ? "h" : "l",
+                                  dis_buf,
+                                  nameXMMReg(gregOfRM(modrm)));
+      }
+
+      assign( d1, unop(Iop_128HIto64, mkexpr(dV)) );
+      assign( d0, unop(Iop_128to64,   mkexpr(dV)) );
+      assign( s1, unop(Iop_128HIto64, mkexpr(sV)) );
+      assign( s0, unop(Iop_128to64,   mkexpr(sV)) );
+
+      if (hi) {
+         putXMMReg( gregOfRM(modrm), 
+                    binop(Iop_64HLto128, mkexpr(s1), mkexpr(d1)) );
+      } else {
+         putXMMReg( gregOfRM(modrm), 
+                    binop(Iop_64HLto128, mkexpr(s0), mkexpr(d0)) );
+      }
+
+      goto decode_success;
+   }
+
+   /* 66 0F 57 = XORPD -- G = G and E */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) {
+      delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_Xor128 );
+      goto decode_success;
+   }
 
 //-- 
 //--    /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
index fb50ee6d23604932fa5ed1d4e6713095fad79cc1..b0ab1c5b523f9ab668f8f5e8c437f632c081228f 100644 (file)
@@ -2550,6 +2550,22 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
          return dst;
       }
 
+      case Iop_Set128lo64: {
+         HReg dst = newVRegV(env);
+         HReg srcV = iselVecExpr(env, e->Iex.Binop.arg1);
+         HReg srcIhi, srcIlo;
+         X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
+         X86AMode* esp4 = advance4(esp0);
+         iselInt64Expr(&srcIhi, &srcIlo, env, e->Iex.Binop.arg2);
+         sub_from_esp(env, 16);
+         addInstr(env, X86Instr_SseLdSt(False/*store*/, srcV, esp0));
+         addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(srcIlo), esp0));
+         addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(srcIhi), esp4));
+         addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0));
+         add_to_esp(env, 16);
+         return dst;
+      }
+
       case Iop_64HLto128: {
          HReg r3, r2, r1, r0;
          X86AMode* esp0  = X86AMode_IR(0, hregX86_ESP());
index 85069b337f0fdaba5da4a6ef41ee3e0c89921bef..767f8003b09beaa6718932c13e26518319a7777d 100644 (file)
@@ -297,6 +297,7 @@ void ppIROp ( IROp op )
       case Iop_32Uto128:   vex_printf("32Uto128"); return;
       case Iop_64Uto128:   vex_printf("64Uto128"); return;
       case Iop_Set128lo32: vex_printf("Set128lo32"); return;
+      case Iop_Set128lo64: vex_printf("Set128lo64"); return;
 
       default: vpanic("ppIROp(1)");
    }
@@ -1159,6 +1160,7 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
       case Iop_32Uto128:   UNARY(Ity_V128, Ity_I32);
       case Iop_64Uto128:   UNARY(Ity_V128, Ity_I64);
       case Iop_Set128lo32: BINARY(Ity_V128, Ity_V128,Ity_I32);
+      case Iop_Set128lo64: BINARY(Ity_V128, Ity_V128,Ity_I64);
 
       case Iop_CmpEQ32Fx4: case Iop_CmpLT32Fx4:
       case Iop_CmpEQ64Fx2: case Iop_CmpLT64Fx2:
index f0644764e60498c6cd9dff2dd38758d1799724ad..6c7751f24d45aec4538da55083ce540497f5aef3 100644 (file)
@@ -388,6 +388,7 @@ typedef
       Iop_32Uto128,
       Iop_64Uto128,
       Iop_Set128lo32,
+      Iop_Set128lo64,
       /* 128 -> 32 bit unpack */
       //Iop_128W3to32,   // :: V128 -> I32, bits 127-96
       //Iop_128W2to32,   // :: V128 -> I32, bits 95-64