]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
x86 host/guest: SSE2 integer shifts and subtracts
authorJulian Seward <jseward@acm.org>
Thu, 9 Dec 2004 23:25:14 +0000 (23:25 +0000)
committerJulian Seward <jseward@acm.org>
Thu, 9 Dec 2004 23:25:14 +0000 (23:25 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@639

VEX/priv/guest-x86/gdefs.h
VEX/priv/guest-x86/ghelpers.c
VEX/priv/guest-x86/toIR.c
VEX/priv/host-x86/hdefs.c
VEX/priv/host-x86/hdefs.h
VEX/priv/host-x86/isel.c

index 19fd1a3ef905cbd58215d488f9ce7b52b2a4ce6f..298e6539b169de5823beb0d8174aeefa20225152 100644 (file)
@@ -116,6 +116,7 @@ extern ULong x86g_calculate_qadd8Sx8  ( ULong, ULong );
 extern ULong x86g_calculate_qadd16Ux4 ( ULong, ULong );
 extern ULong x86g_calculate_qadd8Ux8  ( ULong, ULong );
 
+extern ULong x86g_calculate_sub64x1 ( ULong, ULong );
 extern ULong x86g_calculate_sub32x2 ( ULong, ULong );
 extern ULong x86g_calculate_sub16x4 ( ULong, ULong );
 extern ULong x86g_calculate_sub8x8  ( ULong, ULong );
index e241d08718b705b24a5ec12afde5cb237489d29a..5b2140025cc70970be702493ba51540da28267eb 100644 (file)
@@ -2185,6 +2185,12 @@ ULong x86g_calculate_qadd8Ux8 ( ULong xx, ULong yy )
 
 /* ------------ Normal subtraction ------------ */
 
+ULong x86g_calculate_sub64x1 ( ULong xx, ULong yy )
+{
+   /* should really be done in-line */
+   return xx - yy;
+}
+
 ULong x86g_calculate_sub32x2 ( ULong xx, ULong yy )
 {
    return mk32x2(
index c7278e28af79be1d65235c4facd3ca33ebf57f02..be26775793f543d337e4f64876aed52770bc4c65 100644 (file)
@@ -5100,6 +5100,7 @@ UInt dis_MMXop_regmem_to_reg ( UChar sorb,
 
       /* Introduced in SSE2 */
       case 0xD4: XXX(x86g_calculate_add64x1); break;
+      case 0xFB: XXX(x86g_calculate_sub64x1); break;
 
       default: 
          vex_printf("\n0x%x\n", (Int)opc);
@@ -6648,6 +6649,135 @@ static UInt dis_SSEcmp_E_to_G ( UChar sorb, UInt delta,
    return delta;
 }
 
+
+/* Vector by scalar shift of G by the amount specified at the bottom
+   of E. */
+
+static UInt dis_SSE_shiftG_byE ( UChar sorb, UInt delta, 
+                                 HChar* opname, IROp op )
+{
+   HChar   dis_buf[50];
+   Int     alen, size;
+   IRTemp  addr;
+   Bool    shl, shr, sar;
+   UChar   rm   = getIByte(delta);
+   IRTemp  g0   = newTemp(Ity_V128);
+   IRTemp  g1   = newTemp(Ity_V128);
+   IRTemp  amt  = newTemp(Ity_I32);
+   IRTemp  amt8 = newTemp(Ity_I8);
+   if (epartIsReg(rm)) {
+      assign( amt, getXMMRegLane32(eregOfRM(rm), 0) );
+      DIP("%s %s,%s\n", opname,
+                        nameXMMReg(eregOfRM(rm)),
+                        nameXMMReg(gregOfRM(rm)) );
+      delta++;
+   } else {
+      addr = disAMode ( &alen, sorb, delta, dis_buf );
+      assign( amt, loadLE(Ity_I32, mkexpr(addr)) );
+      DIP("%s %s,%s\n", opname,
+                        dis_buf,
+                        nameXMMReg(gregOfRM(rm)) );
+      delta += alen;
+   }
+   assign( g0,   getXMMReg(gregOfRM(rm)) );
+   assign( amt8, unop(Iop_32to8, mkexpr(amt)) );
+
+   shl = shr = sar = False;
+   size = 0;
+   switch (op) {
+      case Iop_ShlN16x8: shl = True; size = 32; break;
+      case Iop_ShlN32x4: shl = True; size = 32; break;
+      case Iop_ShlN64x2: shl = True; size = 64; break;
+      case Iop_SarN16x8: sar = True; size = 16; break;
+      case Iop_SarN32x4: sar = True; size = 32; break;
+      case Iop_ShrN16x8: shr = True; size = 16; break;
+      case Iop_ShrN32x4: shr = True; size = 32; break;
+      case Iop_ShrN64x2: shr = True; size = 64; break;
+      default: vassert(0);
+   }
+
+   if (shl || shr) {
+     assign( 
+        g1,
+        IRExpr_Mux0X(
+           unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
+           mkV128(0x0000),
+           binop(op, mkexpr(g0), mkexpr(amt8))
+        )
+     );
+   } else 
+   if (sar) {
+     assign( 
+        g1,
+        IRExpr_Mux0X(
+           unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))),
+           binop(op, mkexpr(g0), mkU8(size-1)),
+           binop(op, mkexpr(g0), mkexpr(amt8))
+        )
+     );
+   } else {
+      vassert(0);
+   }
+
+   putXMMReg( gregOfRM(rm), mkexpr(g1) );
+   return delta;
+}
+
+
+/* Vector by scalar shift of E by an immediate byte. */
+
+static UInt dis_SSE_shiftE_imm ( UChar sorb, UInt delta, 
+                                 HChar* opname, IROp op )
+{
+   Bool    shl, shr, sar;
+   UChar   rm   = getIByte(delta);
+   IRTemp  g0   = newTemp(Ity_V128);
+   IRTemp  g1   = newTemp(Ity_V128);
+   UChar   amt, size;
+   vassert(epartIsReg(rm));
+   vassert(gregOfRM(rm) == 2 
+           || gregOfRM(rm) == 4 || gregOfRM(rm) == 6);
+   amt = (Int)(getIByte(delta+1));
+   delta += 2;
+   DIP("%s $%d,%s\n", opname,
+                      (Int)amt,
+                      nameXMMReg(eregOfRM(rm)) );
+   assign( g0, getXMMReg(eregOfRM(rm)) );
+
+   shl = shr = sar = False;
+   size = 0;
+   switch (op) {
+      case Iop_ShlN16x8: shl = True; size = 16; break;
+      case Iop_ShlN32x4: shl = True; size = 32; break;
+      case Iop_ShlN64x2: shl = True; size = 64; break;
+      case Iop_SarN16x8: sar = True; size = 16; break;
+      case Iop_SarN32x4: sar = True; size = 32; break;
+      case Iop_ShrN16x8: shr = True; size = 16; break;
+      case Iop_ShrN32x4: shr = True; size = 32; break;
+      case Iop_ShrN64x2: shr = True; size = 64; break;
+      default: vassert(0);
+   }
+
+   if (shl || shr) {
+     assign( g1, amt >= size 
+                    ? mkV128(0x0000)
+                    : binop(op, mkexpr(g0), mkU8(amt))
+     );
+   } else 
+   if (sar) {
+     assign( g1, amt >= size 
+                    ? binop(op, mkexpr(g0), mkU8(size-1))
+                    : binop(op, mkexpr(g0), mkU8(amt))
+     );
+   } else {
+      vassert(0);
+   }
+
+   putXMMReg( eregOfRM(rm), mkexpr(g1) );
+   return delta;
+}
+
+
 /* Get the current SSE rounding mode. */
 
 static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void )
@@ -6702,6 +6832,45 @@ static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2,
    );
 }
 
+/* Break a 64-bit value up into four 16-bit ints. */
+
+static void breakup64to16s ( IRTemp t64,
+                             /*OUTs*/
+                             IRTemp* t3, IRTemp* t2,
+                             IRTemp* t1, IRTemp* t0 )
+{
+   IRTemp hi32 = newTemp(Ity_I32);
+   IRTemp lo32 = newTemp(Ity_I32);
+   assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) );
+   assign( lo32, unop(Iop_64to32,   mkexpr(t64)) );
+
+   vassert(t0 && *t0 == IRTemp_INVALID);
+   vassert(t1 && *t1 == IRTemp_INVALID);
+   vassert(t2 && *t2 == IRTemp_INVALID);
+   vassert(t3 && *t3 == IRTemp_INVALID);
+
+   *t0 = newTemp(Ity_I16);
+   *t1 = newTemp(Ity_I16);
+   *t2 = newTemp(Ity_I16);
+   *t3 = newTemp(Ity_I16);
+   assign( *t0, unop(Iop_32to16,   mkexpr(lo32)) );
+   assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) );
+   assign( *t2, unop(Iop_32to16,   mkexpr(hi32)) );
+   assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) );
+}
+
+/* Construct a 64-bit value from four 16-bit ints. */
+
+static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2,
+                             IRTemp t1, IRTemp t0 )
+{
+   return
+      binop( Iop_32HLto64,
+             binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
+             binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
+   );
+}
+
 
 /*------------------------------------------------------------*/
 /*--- Disassemble a single instruction                     ---*/
@@ -7414,27 +7583,19 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
    if (insn[0] == 0x0F && insn[1] == 0xC5) {
       modrm = insn[2];
       if (sz == 4 && epartIsReg(modrm)) {
+         IRTemp sV = newTemp(Ity_I64);
+         t5 = newTemp(Ity_I16);
          do_MMX_preamble();
-         t0 = newTemp(Ity_I64);
-         t1 = newTemp(Ity_I16);
-         assign(t0, getMMXReg(eregOfRM(modrm)));
+         assign(sV, getMMXReg(eregOfRM(modrm)));
+         breakup64to16s( sV, &t3, &t2, &t1, &t0 );
          switch (insn[3] & 3) {
-            case 0: 
-               assign(t1, unop(Iop_32to16, 
-                               unop(Iop_64to32, mkexpr(t0)))); break;
-            case 1:
-               assign(t1, unop(Iop_32HIto16, 
-                               unop(Iop_64to32, mkexpr(t0)))); break;
-            case 2: 
-               assign(t1, unop(Iop_32to16, 
-                               unop(Iop_64HIto32, mkexpr(t0)))); break;
-            case 3: 
-               assign(t1, unop(Iop_32HIto16, 
-                               unop(Iop_64HIto32, mkexpr(t0)))); break;
-            default: 
-               vassert(0);
+            case 0:  assign(t5, mkexpr(t0)); break;
+            case 1:  assign(t5, mkexpr(t1)); break;
+            case 2:  assign(t5, mkexpr(t2)); break;
+            case 3:  assign(t5, mkexpr(t3)); break;
+            default: vassert(0);
          }
-         putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t1)));
+         putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5)));
          DIP("pextrw $%d,%s,%s\n",
              (Int)insn[3], nameMMXReg(eregOfRM(modrm)),
                            nameIReg(4,gregOfRM(modrm)));
@@ -7452,10 +7613,6 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
          mmx reg.  t4 is the new lane value.  t5 is the original
          mmx value. t6 is the new mmx value. */
       Int lane;
-      t0 = newTemp(Ity_I16);
-      t1 = newTemp(Ity_I16);
-      t2 = newTemp(Ity_I16);
-      t3 = newTemp(Ity_I16);
       t4 = newTemp(Ity_I16);
       t5 = newTemp(Ity_I64);
       t6 = newTemp(Ity_I64);
@@ -7463,11 +7620,7 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       do_MMX_preamble();
 
       assign(t5, getMMXReg(gregOfRM(modrm)));
-
-      assign(t0, unop(Iop_32to16,   unop(Iop_64to32,   mkexpr(t5))));
-      assign(t1, unop(Iop_32HIto16, unop(Iop_64to32,   mkexpr(t5))));
-      assign(t2, unop(Iop_32to16,   unop(Iop_64HIto32, mkexpr(t5))));
-      assign(t3, unop(Iop_32HIto16, unop(Iop_64HIto32, mkexpr(t5))));
+      breakup64to16s( t5, &t3, &t2, &t1, &t0 );
 
       if (epartIsReg(modrm)) {
          assign(t4, getIReg(2, eregOfRM(modrm)));
@@ -7482,36 +7635,11 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       }
 
       switch (lane & 3) {
-         case 0: 
-            assign(t6, binop(Iop_32HLto64,
-                          binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
-                          binop(Iop_16HLto32, mkexpr(t1), mkexpr(t4))
-                       )
-                  );
-            break;
-         case 1: 
-            assign(t6, binop(Iop_32HLto64,
-                          binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)),
-                          binop(Iop_16HLto32, mkexpr(t4), mkexpr(t0))
-                       )
-                  );
-            break;
-         case 2: 
-            assign(t6, binop(Iop_32HLto64,
-                          binop(Iop_16HLto32, mkexpr(t3), mkexpr(t4)),
-                          binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
-                      )
-                  );
-            break;
-         case 3: 
-            assign(t6, binop(Iop_32HLto64,
-                          binop(Iop_16HLto32, mkexpr(t4), mkexpr(t2)),
-                          binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0))
-                       )
-                  );
-            break;
-         default: 
-            vassert(0);
+         case 0:  assign(t6, mk64from16s(t3,t2,t1,t4)); break;
+         case 1:  assign(t6, mk64from16s(t3,t2,t4,t0)); break;
+         case 2:  assign(t6, mk64from16s(t3,t4,t1,t0)); break;
+         case 3:  assign(t6, mk64from16s(t4,t2,t1,t0)); break;
+         default: vassert(0);
       }
       putMMXReg(gregOfRM(modrm), mkexpr(t6));
       goto decode_success;
@@ -7626,15 +7754,16 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
 
    /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
    /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */
-   if (insn[0] == 0x0F && insn[1] == 0x70) {
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) {
       Int order;
-      vassert(sz == 4);
-      t0 = newTemp(Ity_I64);
-      t1 = newTemp(Ity_I64);
+      IRTemp sV, dV, s3, s2, s1, s0;
+      s3 = s2 = s1 = s0 = IRTemp_INVALID;
+      sV = newTemp(Ity_I64);
+      dV = newTemp(Ity_I64);
       do_MMX_preamble();
       modrm = insn[2];
       if (epartIsReg(modrm)) {
-         assign( t0, getMMXReg(eregOfRM(modrm)) );
+         assign( sV, getMMXReg(eregOfRM(modrm)) );
          order = (Int)insn[3];
          delta += 2+2;
          DIP("pshufw $%d,%s,%s\n", order, 
@@ -7642,34 +7771,23 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
                                    nameMMXReg(gregOfRM(modrm)));
       } else {
          addr = disAMode ( &alen, sorb, delta+2, dis_buf );
-         assign( t0, loadLE(Ity_I64, mkexpr(addr)) );
+         assign( sV, loadLE(Ity_I64, mkexpr(addr)) );
         order = (Int)insn[2+alen];
          delta += 3+alen;
          DIP("pshufw $%d,%s,%s\n", order, 
                                    dis_buf,
                                    nameMMXReg(gregOfRM(modrm)));
       }
+      breakup64to16s( sV, &s3, &s2, &s1, &s0 );
 
-#     define WORD0 unop(Iop_32to16,unop(Iop_64to32,mkexpr(t0)))
-#     define WORD1 unop(Iop_32HIto16,unop(Iop_64to32,mkexpr(t0)))
-#     define WORD2 unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(t0)))
-#     define WORD3 unop(Iop_32HIto16,unop(Iop_64HIto32,mkexpr(t0)))
-#     define SEL(n) ((n)==0 ? WORD0                  \
-                     : ((n)==1 ? WORD1               \
-                     : ((n)==2 ? WORD2 : WORD3)))
-      assign(t1,
-         binop(Iop_32HLto64,
-               binop(Iop_16HLto32,SEL((order>>6)&3),SEL((order>>4)&3)),
-               binop(Iop_16HLto32,SEL((order>>2)&3),SEL((order>>0)&3))
-              )
+#     define SEL(n) \
+                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
+      assign(dV,
+            mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
+                          SEL((order>>2)&3), SEL((order>>0)&3) )
       );
-      putMMXReg(gregOfRM(modrm), mkexpr(t1));
-
+      putMMXReg(gregOfRM(modrm), mkexpr(dV));
 #     undef SEL
-#     undef WORD0
-#     undef WORD1
-#     undef WORD2
-#     undef WORD3
       goto decode_success;
    }
 
@@ -9353,6 +9471,318 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       goto decode_success;
    }
 
+   /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) {
+      Int order;
+      IRTemp sV, dV, s3, s2, s1, s0;
+      s3 = s2 = s1 = s0 = IRTemp_INVALID;
+      sV = newTemp(Ity_V128);
+      dV = newTemp(Ity_V128);
+      modrm = insn[2];
+      if (epartIsReg(modrm)) {
+         assign( sV, getXMMReg(eregOfRM(modrm)) );
+         order = (Int)insn[3];
+         delta += 2+2;
+         DIP("pshufd $%d,%s,%s\n", order, 
+                                   nameXMMReg(eregOfRM(modrm)),
+                                   nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+2, dis_buf );
+         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
+        order = (Int)insn[2+alen];
+         delta += 3+alen;
+         DIP("pshufd $%d,%s,%s\n", order, 
+                                   dis_buf,
+                                   nameXMMReg(gregOfRM(modrm)));
+      }
+      breakup128to32s( sV, &s3, &s2, &s1, &s0 );
+
+#     define SEL(n) \
+                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
+      assign(dV,
+            mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3),
+                           SEL((order>>2)&3), SEL((order>>0)&3) )
+      );
+      putXMMReg(gregOfRM(modrm), mkexpr(dV));
+#     undef SEL
+      goto decode_success;
+   }
+
+   /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or
+      mem) to G(xmm), and copy lower half */
+   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) {
+      Int order;
+      IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0;
+      s3 = s2 = s1 = s0 = IRTemp_INVALID;
+      sV   = newTemp(Ity_V128);
+      dV   = newTemp(Ity_V128);
+      sVhi = newTemp(Ity_I64);
+      dVhi = newTemp(Ity_I64);
+      modrm = insn[3];
+      if (epartIsReg(modrm)) {
+         assign( sV, getXMMReg(eregOfRM(modrm)) );
+         order = (Int)insn[4];
+         delta += 4+1;
+         DIP("pshufhw $%d,%s,%s\n", order, 
+                                    nameXMMReg(eregOfRM(modrm)),
+                                    nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
+         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
+        order = (Int)insn[3+alen];
+         delta += 4+alen;
+         DIP("pshufhw $%d,%s,%s\n", order, 
+                                    dis_buf,
+                                    nameXMMReg(gregOfRM(modrm)));
+      }
+      assign( sVhi, unop(Iop_128HIto64, mkexpr(sV)) );
+      breakup64to16s( sVhi, &s3, &s2, &s1, &s0 );
+
+#     define SEL(n) \
+                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
+      assign(dVhi,
+            mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
+                          SEL((order>>2)&3), SEL((order>>0)&3) )
+      );
+      assign(dV, binop( Iop_64HLto128, 
+                        mkexpr(dVhi),
+                        unop(Iop_128to64, mkexpr(sV))) );
+      putXMMReg(gregOfRM(modrm), mkexpr(dV));
+#     undef SEL
+      goto decode_success;
+   }
+
+   /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or
+      mem) to G(xmm), and copy upper half */
+   if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) {
+      Int order;
+      IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0;
+      s3 = s2 = s1 = s0 = IRTemp_INVALID;
+      sV   = newTemp(Ity_V128);
+      dV   = newTemp(Ity_V128);
+      sVlo = newTemp(Ity_I64);
+      dVlo = newTemp(Ity_I64);
+      modrm = insn[3];
+      if (epartIsReg(modrm)) {
+         assign( sV, getXMMReg(eregOfRM(modrm)) );
+         order = (Int)insn[4];
+         delta += 4+1;
+         DIP("pshuflw $%d,%s,%s\n", order, 
+                                    nameXMMReg(eregOfRM(modrm)),
+                                    nameXMMReg(gregOfRM(modrm)));
+      } else {
+         addr = disAMode ( &alen, sorb, delta+3, dis_buf );
+         assign( sV, loadLE(Ity_V128, mkexpr(addr)) );
+        order = (Int)insn[3+alen];
+         delta += 4+alen;
+         DIP("pshuflw $%d,%s,%s\n", order, 
+                                    dis_buf,
+                                    nameXMMReg(gregOfRM(modrm)));
+      }
+      assign( sVlo, unop(Iop_128to64, mkexpr(sV)) );
+      breakup64to16s( sVlo, &s3, &s2, &s1, &s0 );
+
+#     define SEL(n) \
+                ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3)))
+      assign(dVlo,
+            mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3),
+                          SEL((order>>2)&3), SEL((order>>0)&3) )
+      );
+      assign(dV, binop( Iop_64HLto128,
+                        unop(Iop_128HIto64, mkexpr(sV)),
+                        mkexpr(dVlo) ) );
+      putXMMReg(gregOfRM(modrm), mkexpr(dV));
+#     undef SEL
+      goto decode_success;
+   }
+
+   /* 66 0F 72 /6 ib = PSLLD by immediate */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
+       && epartIsReg(insn[2])
+       && gregOfRM(insn[2]) == 6) {
+      delta = dis_SSE_shiftE_imm( sorb, delta+2, "pslld", Iop_ShlN32x4 );
+      goto decode_success;
+   }
+
+   /* 66 0F F2 = PSLLD by E */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) {
+      delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 );
+      goto decode_success;
+   }
+
+#if 0
+   /* 66 0F 73 /7 ib = PSLLDQ by immediate */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
+       && epartIsReg(insn[2])
+       && gregOfRM(insn[2]) == 7) {
+      delta = dis_SSE_shiftE_imm( sorb, delta+2, "pslldq", Iop_ShlN64x2 );
+      goto decode_success;
+   }
+#endif
+
+   /* 66 0F 73 /6 ib = PSLLQ by immediate */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
+       && epartIsReg(insn[2])
+       && gregOfRM(insn[2]) == 6) {
+      delta = dis_SSE_shiftE_imm( sorb, delta+2, "psllq", Iop_ShlN64x2 );
+      goto decode_success;
+   }
+
+   /* 66 0F F3 = PSLLQ by E */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) {
+      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 );
+      goto decode_success;
+   }
+
+   /* 66 0F 71 /6 ib = PSLLW by immediate */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
+       && epartIsReg(insn[2])
+       && gregOfRM(insn[2]) == 6) {
+      delta = dis_SSE_shiftE_imm( sorb, delta+2, "psllw", Iop_ShlN16x8 );
+      goto decode_success;
+   }
+
+   /* 66 0F F1 = PSLLW by E */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) {
+      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 );
+      goto decode_success;
+   }
+
+   /* 66 0F 72 /4 ib = PSRAD by immediate */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
+       && epartIsReg(insn[2])
+       && gregOfRM(insn[2]) == 4) {
+      delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrad", Iop_SarN32x4 );
+      goto decode_success;
+   }
+
+   /* 66 0F E2 = PSRAD by E */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) {
+      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 );
+      goto decode_success;
+   }
+
+   /* 66 0F 71 /4 ib = PSRAW by immediate */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
+       && epartIsReg(insn[2])
+       && gregOfRM(insn[2]) == 4) {
+      delta = dis_SSE_shiftE_imm( sorb, delta+2, "psraw", Iop_SarN16x8 );
+      goto decode_success;
+   }
+
+   /* 66 0F E1 = PSRAW by E */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) {
+      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 );
+      goto decode_success;
+   }
+
+   /* 66 0F 72 /2 ib = PSRLD by immediate */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72
+       && epartIsReg(insn[2])
+       && gregOfRM(insn[2]) == 2) {
+      delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrld", Iop_ShrN32x4 );
+      goto decode_success;
+   }
+
+   /* 66 0F D2 = PSRLD by E */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) {
+      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 );
+      goto decode_success;
+   }
+
+   /* 66 0F 73 /2 ib = PSRLQ by immediate */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73
+       && epartIsReg(insn[2])
+       && gregOfRM(insn[2]) == 2) {
+      delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
+      goto decode_success;
+   }
+
+   /* 66 0F D3 = PSRLQ by E */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) {
+      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 );
+      goto decode_success;
+   }
+
+   /* 66 0F 71 /2 ib = PSRLW by immediate */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71
+       && epartIsReg(insn[2])
+       && gregOfRM(insn[2]) == 2) {
+      delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
+      goto decode_success;
+   }
+
+   /* 66 0F D1 = PSRLW by E */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) {
+      delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 );
+      goto decode_success;
+   }
+
+   /* 66 0F F8 = PSUBB */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "psubb", Iop_Sub8x16, False );
+      goto decode_success;
+   }
+
+   /* 66 0F FA = PSUBD */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "psubd", Iop_Sub32x4, False );
+      goto decode_success;
+   }
+
+   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
+   /* 0F FB = PSUBQ -- sub 64x1 */
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) {
+      do_MMX_preamble();
+      delta = dis_MMXop_regmem_to_reg ( 
+                sorb, delta+2, insn[1], "psubq", False );
+      goto decode_success;
+   }
+
+   /* 66 0F FB = PSUBQ */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "psubq", Iop_Sub64x2, False );
+      goto decode_success;
+   }
+
+   /* 66 0F F9 = PSUBW */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "psubw", Iop_Sub16x8, False );
+      goto decode_success;
+   }
+
+   /* 66 0F E8 = PSUBSB */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "psubsb", Iop_QSub8Sx16, False );
+      goto decode_success;
+   }
+
+   /* 66 0F E9 = PSUBSW */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "psubsw", Iop_QSub16Sx8, False );
+      goto decode_success;
+   }
+
+   /* 66 0F D8 = PSUBSB */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "psubusb", Iop_QSub8Ux16, False );
+      goto decode_success;
+   }
+
+   /* 66 0F D9 = PSUBSW */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "psubusw", Iop_QSub16Ux8, False );
+      goto decode_success;
+   }
+
 
 //-- 
 //--    /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
@@ -12335,7 +12765,8 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       case 0x73: /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */
                  /* If sz==2 this is SSE, and we assume sse idec has
                     already spotted those cases by now. */
-         vassert(sz == 4);
+         if (sz == 2)
+            goto decode_failure;
 
       case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */
       case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */
index 74e3df309b14de3f769386f80e0447c117cfdd82..00de9e1262d300a516e761a709c67d12f6b14671 100644 (file)
@@ -858,6 +858,15 @@ X86Instr* X86Instr_SseReRg ( X86SseOp op, HReg re, HReg rg ) {
    vassert(op != Xsse_MOV);
    return i;
 }
+X86Instr* X86Instr_SseCMov ( X86CondCode cond, HReg src, HReg dst ) {
+   X86Instr* i         = LibVEX_Alloc(sizeof(X86Instr));
+   i->tag              = Xin_SseCMov;
+   i->Xin.SseCMov.cond = cond;
+   i->Xin.SseCMov.src  = src;
+   i->Xin.SseCMov.dst  = dst;
+   vassert(cond != Xcc_ALWAYS);
+   return i;
+}
 
 void ppX86Instr ( X86Instr* i ) {
    switch (i->tag) {
@@ -1102,6 +1111,12 @@ void ppX86Instr ( X86Instr* i ) {
          vex_printf(",");
          ppHRegX86(i->Xin.SseReRg.dst);
          return;
+      case Xin_SseCMov:
+         vex_printf("cmov%s ", showX86CondCode(i->Xin.SseCMov.cond));
+         ppHRegX86(i->Xin.SseCMov.src);
+         vex_printf(",");
+         ppHRegX86(i->Xin.SseCMov.dst);
+         return;
 
       default:
          vpanic("ppX86Instr");
@@ -1243,7 +1258,7 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i)
          addHRegUse(u, HRmWrite, i->Xin.Fp64to32.dst);
          return;
       case Xin_FpCMov:
-         addHRegUse(u, HRmRead, i->Xin.FpCMov.src);
+         addHRegUse(u, HRmRead,   i->Xin.FpCMov.src);
          addHRegUse(u, HRmModify, i->Xin.FpCMov.dst);
          return;
       case Xin_FpLdStCW:
@@ -1316,6 +1331,10 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i)
          addHRegUse(u, HRmRead,   i->Xin.SseReRg.src);
          addHRegUse(u, HRmModify, i->Xin.SseReRg.dst);
          return;
+      case Xin_SseCMov:
+         addHRegUse(u, HRmRead,   i->Xin.SseCMov.src);
+         addHRegUse(u, HRmModify, i->Xin.SseCMov.dst);
+         return;
       default:
          ppX86Instr(i);
          vpanic("getRegUsage_X86Instr");
@@ -1456,6 +1475,10 @@ void mapRegs_X86Instr (HRegRemap* m, X86Instr* i)
          mapReg(m, &i->Xin.SseReRg.src);
          mapReg(m, &i->Xin.SseReRg.dst);
          return;
+      case Xin_SseCMov:
+         mapReg(m, &i->Xin.SseCMov.src);
+         mapReg(m, &i->Xin.SseCMov.dst);
+         return;
       default:
          ppX86Instr(i);
          vpanic("mapRegs_X86Instr");
@@ -2707,6 +2730,22 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
          case Xsse_MULHI16U: XX(0x66); XX(0x0F); XX(0xE4); break;
          case Xsse_MULHI16S: XX(0x66); XX(0x0F); XX(0xE5); break;
          case Xsse_MUL16:    XX(0x66); XX(0x0F); XX(0xD5); break;
+         case Xsse_SHL16:    XX(0x66); XX(0x0F); XX(0xF1); break;
+         case Xsse_SHL32:    XX(0x66); XX(0x0F); XX(0xF2); break;
+         case Xsse_SHL64:    XX(0x66); XX(0x0F); XX(0xF3); break;
+         case Xsse_SAR16:    XX(0x66); XX(0x0F); XX(0xE1); break;
+         case Xsse_SAR32:    XX(0x66); XX(0x0F); XX(0xE2); break;
+         case Xsse_SHR16:    XX(0x66); XX(0x0F); XX(0xD1); break;
+         case Xsse_SHR32:    XX(0x66); XX(0x0F); XX(0xD2); break;
+         case Xsse_SHR64:    XX(0x66); XX(0x0F); XX(0xD3); break;
+         case Xsse_SUB8:     XX(0x66); XX(0x0F); XX(0xF8); break;
+         case Xsse_SUB16:    XX(0x66); XX(0x0F); XX(0xF9); break;
+         case Xsse_SUB32:    XX(0x66); XX(0x0F); XX(0xFA); break;
+         case Xsse_SUB64:    XX(0x66); XX(0x0F); XX(0xFB); break;
+         case Xsse_QSUB8S:   XX(0x66); XX(0x0F); XX(0xE8); break;
+         case Xsse_QSUB16S:  XX(0x66); XX(0x0F); XX(0xE9); break;
+         case Xsse_QSUB8U:   XX(0x66); XX(0x0F); XX(0xD8); break;
+         case Xsse_QSUB16U:  XX(0x66); XX(0x0F); XX(0xD9); break;
          default: goto bad;
       }
       p = doAMode_R(p, fake(vregNo(i->Xin.SseReRg.dst)),
@@ -2714,6 +2753,22 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
 #     undef XX
       goto done;
 
+   case Xin_SseCMov:
+      /* jmp fwds if !condition */
+      *p++ = 0x70 + (i->Xin.SseCMov.cond ^ 1);
+      *p++ = 0; /* # of bytes in the next bit, which we don't know yet */
+      ptmp = p;
+
+      /* movaps %src, %dst */
+      *p++ = 0x0F; 
+      *p++ = 0x28; 
+      p = doAMode_R(p, fake(vregNo(i->Xin.SseCMov.dst)),
+                       fake(vregNo(i->Xin.SseCMov.src)) );
+
+      /* Fill in the jump offset. */
+      *(ptmp-1) = p - ptmp;
+      goto done;
+
    default: 
       goto bad;
    }
index 63e50a466c377e1e718891f06217cddcf5b2ca77..415b1ea6bfab177c2d44c596145bb6c2793b9821 100644 (file)
@@ -371,7 +371,7 @@ typedef
       Xin_FpLdSt,    /* FP fake load/store */
       Xin_FpLdStI,   /* FP fake load/store, converting to/from Int */
       Xin_Fp64to32,  /* FP round IEEE754 double to IEEE754 single */
-      Xin_FpCMov,    /* FP fake floating point (un)conditional move */
+      Xin_FpCMov,    /* FP fake floating point conditional move */
       Xin_FpLdStCW,  /* fldcw / fstcw */
       Xin_FpStSW_AX, /* fstsw %ax */
       Xin_FpCmp,     /* FP compare, generating a C320 value into int reg */
@@ -384,7 +384,8 @@ typedef
       Xin_Sse32FLo,  /* SSE binary, 32F in lowest lane only */
       Xin_Sse64Fx2,  /* SSE binary, 64Fx2 */
       Xin_Sse64FLo,  /* SSE binary, 64F in lowest lane only */
-      Xin_SseReRg    /* SSE binary general reg-reg, Re, Rg */
+      Xin_SseReRg,   /* SSE binary general reg-reg, Re, Rg */
+      Xin_SseCMov    /* SSE conditional move */
    }
    X86InstrTag;
 
@@ -594,6 +595,13 @@ typedef
             HReg     src;
             HReg     dst;
          } SseReRg;
+         /* Mov src to dst on the given condition, which may not
+            be the bogus Xcc_ALWAYS. */
+         struct {
+            X86CondCode cond;
+            HReg        src;
+            HReg        dst;
+         } SseCMov;
 
       } Xin;
    }
@@ -636,6 +644,7 @@ extern X86Instr* X86Instr_Sse32FLo  ( X86SseOp, HReg, HReg );
 extern X86Instr* X86Instr_Sse64Fx2  ( X86SseOp, HReg, HReg );
 extern X86Instr* X86Instr_Sse64FLo  ( X86SseOp, HReg, HReg );
 extern X86Instr* X86Instr_SseReRg   ( X86SseOp, HReg, HReg );
+extern X86Instr* X86Instr_SseCMov   ( X86CondCode, HReg src, HReg dst );
 
 
 extern void ppX86Instr ( X86Instr* );
index 1e2fcc3e8d64c15ad5f60c149daeb00aa2e09940..11ae76938c821a163b000affe7bde7e3be8efd69 100644 (file)
@@ -2706,6 +2706,14 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
       case Iop_MulHi16Ux8: op = Xsse_MULHI16U; goto do_SseReRg;
       case Iop_MulHi16Sx8: op = Xsse_MULHI16S; goto do_SseReRg;
       case Iop_Mul16x8:    op = Xsse_MUL16;    goto do_SseReRg;
+      case Iop_Sub8x16:    op = Xsse_SUB8;     goto do_SseReRg;
+      case Iop_Sub16x8:    op = Xsse_SUB16;    goto do_SseReRg;
+      case Iop_Sub32x4:    op = Xsse_SUB32;    goto do_SseReRg;
+      case Iop_Sub64x2:    op = Xsse_SUB64;    goto do_SseReRg;
+      case Iop_QSub8Sx16:  op = Xsse_QSUB8S;   goto do_SseReRg;
+      case Iop_QSub16Sx8:  op = Xsse_QSUB16S;  goto do_SseReRg;
+      case Iop_QSub8Ux16:  op = Xsse_QSUB8U;   goto do_SseReRg;
+      case Iop_QSub16Ux8:  op = Xsse_QSUB16U;  goto do_SseReRg;
       do_SseReRg: {
          HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
          HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
@@ -2720,11 +2728,47 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
          return dst;
       }
 
+      case Iop_ShlN16x8: op = Xsse_SHL16; goto do_SseShift;
+      case Iop_ShlN32x4: op = Xsse_SHL32; goto do_SseShift;
+      case Iop_ShlN64x2: op = Xsse_SHL64; goto do_SseShift;
+      case Iop_SarN16x8: op = Xsse_SAR16; goto do_SseShift;
+      case Iop_SarN32x4: op = Xsse_SAR32; goto do_SseShift;
+      case Iop_ShrN16x8: op = Xsse_SHR16; goto do_SseShift;
+      case Iop_ShrN32x4: op = Xsse_SHR32; goto do_SseShift;
+      case Iop_ShrN64x2: op = Xsse_SHR64; goto do_SseShift;
+      do_SseShift: {
+         HReg      greg = iselVecExpr(env, e->Iex.Binop.arg1);
+         X86RMI*   rmi  = iselIntExpr_RMI(env, e->Iex.Binop.arg2);
+         X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
+         HReg      ereg = newVRegV(env);
+         HReg      dst  = newVRegV(env);
+         addInstr(env, X86Instr_Push(X86RMI_Imm(0)));
+         addInstr(env, X86Instr_Push(X86RMI_Imm(0)));
+         addInstr(env, X86Instr_Push(X86RMI_Imm(0)));
+         addInstr(env, X86Instr_Push(rmi));
+         addInstr(env, X86Instr_SseLdSt(True/*load*/, ereg, esp0));
+        addInstr(env, mk_vMOVsd_RR(greg, dst));
+         addInstr(env, X86Instr_SseReRg(op, ereg, dst));
+         add_to_esp(env, 16);
+         return dst;
+      }
+
       default:
          break;
    } /* switch (e->Iex.Binop.op) */
    } /* if (e->tag == Iex_Binop) */
 
+   if (e->tag == Iex_Mux0X) {
+      HReg r8  = iselIntExpr_R(env, e->Iex.Mux0X.cond);
+      HReg rX  = iselVecExpr(env, e->Iex.Mux0X.exprX);
+      HReg r0  = iselVecExpr(env, e->Iex.Mux0X.expr0);
+      HReg dst = newVRegV(env);
+      addInstr(env, mk_vMOVsd_RR(rX,dst));
+      addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8)));
+      addInstr(env, X86Instr_SseCMov(Xcc_Z,r0,dst));
+      return dst;
+   }
+
    ppIRExpr(e);
    vpanic("iselVecExpr_wrk");
 }