]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
IR level for support of 128 integer SIMD operations. Use this to do
authorJulian Seward <jseward@acm.org>
Thu, 9 Dec 2004 00:39:32 +0000 (00:39 +0000)
committerJulian Seward <jseward@acm.org>
Thu, 9 Dec 2004 00:39:32 +0000 (00:39 +0000)
SSE2 integer operations (x86 guest/host).

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

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
VEX/priv/ir/irdefs.c
VEX/pub/libvex_ir.h

index dd058f543f14b57ba0ae948ae2148a4e1851a649..a92637d08c19fa443875534bf1e142978047e2b3 100644 (file)
@@ -105,6 +105,7 @@ extern UInt x86h_create_mxcsr ( UInt sseround );
 
 /* --- Clean helpers for MMX --- */
 
+extern ULong x86g_calculate_add64x1 ( ULong, ULong );
 extern ULong x86g_calculate_add32x2 ( ULong, ULong );
 extern ULong x86g_calculate_add16x4 ( ULong, ULong );
 extern ULong x86g_calculate_add8x8  ( ULong, ULong );
index 34410f2a9bb6fe895d53650dbffaa6d824a5a462..7134e69118641bff895f76eb736ac090b2284d7b 100644 (file)
@@ -2095,6 +2095,12 @@ static inline UChar abdU8 ( UChar xx, UChar yy )
 
 /* ------------ Normal addition ------------ */
 
+ULong x86g_calculate_add64x1 ( ULong xx, ULong yy )
+{
+   /* uh, why, exactly, is this not done in-line??? */
+   return xx + yy;
+}
+
 ULong x86g_calculate_add32x2 ( ULong xx, ULong yy )
 {
    return mk32x2(
index ef6224f83bd83fa638f8eccef0c91fa879fa04ee..a0b6dcb767f59c1881d99719f53958b56e09fb77 100644 (file)
@@ -5084,6 +5084,9 @@ UInt dis_MMXop_regmem_to_reg ( UChar sorb,
       case 0xE4: XXX(x86g_calculate_mull16uHIx4); break;
       case 0xF6: XXX(x86g_calculate_psadbw); break;
 
+      /* Introduced in SSE2 */
+      case 0xD4: XXX(x86g_calculate_add64x1); break;
+
       default: 
          vex_printf("\n0x%x\n", (Int)opc);
          vpanic("dis_MMXop_regmem_to_reg");
@@ -6307,6 +6310,7 @@ UInt dis_SSE_E_to_G_all_invG ( UChar sorb, UInt delta,
    return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
 }
 
+
 /* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
 
 static UInt dis_SSE_E_to_G_lo32 ( UChar sorb, UInt delta, 
@@ -6341,6 +6345,7 @@ static UInt dis_SSE_E_to_G_lo32 ( UChar sorb, UInt delta,
    }
 }
 
+
 /* Lower 64-bit lane only SSE binary operation, G = G `op` E. */
 
 static UInt dis_SSE_E_to_G_lo64 ( UChar sorb, UInt delta, 
@@ -6375,6 +6380,7 @@ static UInt dis_SSE_E_to_G_lo64 ( UChar sorb, UInt delta,
    }
 }
 
+
 /* All lanes unary SSE operation, G = op(E). */
 
 static UInt dis_SSE_E_to_G_unary_all ( 
@@ -6404,6 +6410,7 @@ static UInt dis_SSE_E_to_G_unary_all (
    }
 }
 
+
 /* Lowest 32-bit lane only unary SSE operation, G = op(E). */
 
 static UInt dis_SSE_E_to_G_unary_lo32 ( 
@@ -6446,6 +6453,7 @@ 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 ( 
@@ -6488,6 +6496,44 @@ static UInt dis_SSE_E_to_G_unary_lo64 (
    }
 }
 
+
+/* SSE integer binary operation:
+      G = G `op` E   (eLeft == False)
+      G = E `op` G   (eLeft == True)
+*/
+static UInt dis_SSEint_E_to_G( 
+               UChar sorb, UInt delta, 
+               HChar* opname, IROp op,
+               Bool   eLeft
+            )
+{
+   HChar   dis_buf[50];
+   Int     alen;
+   IRTemp  addr;
+   UChar   rm = getIByte(delta);
+   IRExpr* gpart = getXMMReg(gregOfRM(rm));
+   IRExpr* epart = NULL;
+   if (epartIsReg(rm)) {
+      epart = getXMMReg(eregOfRM(rm));
+      DIP("%s %s,%s\n", opname,
+                        nameXMMReg(eregOfRM(rm)),
+                        nameXMMReg(gregOfRM(rm)) );
+      delta += 1;
+   } else {
+      addr  = disAMode ( &alen, sorb, delta, dis_buf );
+      epart = loadLE(Ity_V128, mkexpr(addr));
+      DIP("%s %s,%s\n", opname,
+                        dis_buf,
+                        nameXMMReg(gregOfRM(rm)) );
+      delta += alen;
+   }
+   putXMMReg( gregOfRM(rm), 
+              eLeft ? binop(op, epart, gpart)
+                   : binop(op, gpart, epart) );
+   return delta;
+}
+
+
 /* Helper for doing SSE FP comparisons. */
 
 static void findSSECmpOp ( Bool* needNot, IROp* op, 
@@ -7332,8 +7378,7 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
 
    /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
    /* 0F E0 = PAVGB -- 8x8 unsigned Packed Average, with rounding */
-   if (insn[0] == 0x0F && insn[1] == 0xE0) {
-      vassert(sz == 4);
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE0) {
       do_MMX_preamble();
       delta = dis_MMXop_regmem_to_reg ( 
                 sorb, delta+2, insn[1], "pavgb", False );
@@ -7342,8 +7387,7 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
 
    /* ***--- this is an MMX class insn introduced in SSE1 ---*** */
    /* 0F E3 = PAVGW -- 16x4 unsigned Packed Average, with rounding */
-   if (insn[0] == 0x0F && insn[1] == 0xE3) {
-      vassert(sz == 4);
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xE3) {
       do_MMX_preamble();
       delta = dis_MMXop_regmem_to_reg ( 
                 sorb, delta+2, insn[1], "pavgw", False );
@@ -8941,6 +8985,121 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       goto decode_success;
    }
 
+   ///////////////////////////////////////////////////////////////////
+
+   /* 66 0F 6B = PACKSSDW */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6B) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "packssdw", Iop_QNarrow32Sx4, True );
+      goto decode_success;
+   }
+
+   /* 66 0F 63 = PACKSSWB */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x63) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "packsswb", Iop_QNarrow16Sx8, True );
+      goto decode_success;
+   }
+
+   /* 66 0F 67 = PACKUSWB */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x67) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "packuswb", Iop_QNarrow16Ux8, True );
+      goto decode_success;
+   }
+
+   /* 66 0F FC = PADDB */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFC) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "paddb", Iop_Add8x16, False );
+      goto decode_success;
+   }
+
+   /* 66 0F FE = PADDD */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFE) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "paddd", Iop_Add32x4, False );
+      goto decode_success;
+   }
+
+   /* ***--- this is an MMX class insn introduced in SSE2 ---*** */
+   /* 0F D4 = PADDQ -- add 64x1 */
+   if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xD4) {
+      do_MMX_preamble();
+      delta = dis_MMXop_regmem_to_reg ( 
+                sorb, delta+2, insn[1], "paddq", False );
+      goto decode_success;
+   }
+
+   /* 66 0F D4 = PADDQ */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD4) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "paddq", Iop_Add64x2, False );
+      goto decode_success;
+   }
+
+   /* 66 0F FD = PADDW */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFD) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "paddw", Iop_Add16x8, False );
+      goto decode_success;
+   }
+
+   /* 66 0F EC = PADDSB */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEC) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "paddsb", Iop_QAdd8Sx16, False );
+      goto decode_success;
+   }
+
+   /* 66 0F ED = PADDSW */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xED) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "paddsw", Iop_QAdd16Sx8, False );
+      goto decode_success;
+   }
+
+   /* 66 0F DC = PADDUSB */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDC) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "paddusb", Iop_QAdd8Ux16, False );
+      goto decode_success;
+   }
+
+   /* 66 0F DD = PADDUSW */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDD) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "paddusw", Iop_QAdd16Ux8, False );
+      goto decode_success;
+   }
+
+   /* 66 0F DB = PAND */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDB) {
+      delta = dis_SSE_E_to_G_all( sorb, delta+2, "pand", Iop_And128 );
+      goto decode_success;
+   }
+
+   /* 66 0F DF = PANDN */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xDF) {
+      delta = dis_SSE_E_to_G_all_invG( sorb, delta+2, "pandn", Iop_And128 );
+      goto decode_success;
+   }
+
+   /* 66 0F E0 = PAVGB */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE0) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "pavgb", Iop_Avg8Ux16, False );
+      goto decode_success;
+   }
+
+   /* 66 0F E3 = PAVGW */
+   if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE3) {
+      delta = dis_SSEint_E_to_G( sorb, delta+2, 
+                                 "pavgw", Iop_Avg16Ux8, False );
+      goto decode_success;
+   }
+
+
 //-- 
 //--    /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */
 //--    if (insn[0] == 0x0F && insn[1] == 0xAE 
index 380ac563188e8b796cb0b8790f272449aa037a08..b57032bff1feae76a12c4e60b85f23ab2547aba6 100644 (file)
@@ -500,24 +500,72 @@ HChar* showX86FpOp ( X86FpOp op ) {
 
 HChar* showX86SseOp ( X86SseOp op ) {
    switch (op) {
-      case Xsse_MOV:    return "mov(?!)";
-      case Xsse_AND:    return "and";
-      case Xsse_OR:     return "or";
-      case Xsse_XOR:    return "xor";
-      case Xsse_ANDN:   return "andn";
-      case Xsse_ADDF:   return "add";
-      case Xsse_SUBF:   return "sub";
-      case Xsse_MULF:   return "mul";
-      case Xsse_DIVF:   return "div";
-      case Xsse_MAXF:   return "max";
-      case Xsse_MINF:   return "min";
-      case Xsse_RCPF:   return "rcp";
-      case Xsse_RSQRTF: return "rsqrt";
-      case Xsse_SQRTF:  return "sqrt";
-      case Xsse_CMPEQF: return "cmpFeq";
-      case Xsse_CMPLTF: return "cmpFlt";
-      case Xsse_CMPLEF: return "cmpFle";
-      case Xsse_CMPUNF: return "cmpFun";
+      case Xsse_MOV:      return "mov(?!)";
+      case Xsse_ADDF:     return "add";
+      case Xsse_SUBF:     return "sub";
+      case Xsse_MULF:     return "mul";
+      case Xsse_DIVF:     return "div";
+      case Xsse_MAXF:     return "max";
+      case Xsse_MINF:     return "min";
+      case Xsse_CMPEQF:   return "cmpFeq";
+      case Xsse_CMPLTF:   return "cmpFlt";
+      case Xsse_CMPLEF:   return "cmpFle";
+      case Xsse_CMPUNF:   return "cmpFun";
+      case Xsse_RCPF:     return "rcp";
+      case Xsse_RSQRTF:   return "rsqrt";
+      case Xsse_SQRTF:    return "sqrt";
+      case Xsse_AND:      return "and";
+      case Xsse_OR:       return "or";
+      case Xsse_XOR:      return "xor";
+      case Xsse_ANDN:     return "andn";
+      case Xsse_ADD8:     return "paddb";
+      case Xsse_ADD16:    return "paddw";
+      case Xsse_ADD32:    return "paddd";
+      case Xsse_ADD64:    return "paddq";
+      case Xsse_QADD8U:   return "paddusb";
+      case Xsse_QADD16U:  return "paddusw";
+      case Xsse_QADD8S:   return "paddsb";
+      case Xsse_QADD16S:  return "paddsw";
+      case Xsse_SUB8:     return "psubb";
+      case Xsse_SUB16:    return "psubw";
+      case Xsse_SUB32:    return "psubd";
+      case Xsse_SUB64:    return "psubq";
+      case Xsse_QSUB8U:   return "psubusb";
+      case Xsse_QSUB16U:  return "psubusw";
+      case Xsse_QSUB8S:   return "psubsb";
+      case Xsse_QSUB16S:  return "psubsw";
+      case Xsse_MUL16:    return "pmullw";
+      case Xsse_MULHI16U: return "pmulhuw";
+      case Xsse_MULHI16S: return "pmulhw";
+      case Xsse_AVG8U:    return "pavgb";
+      case Xsse_AVG16U:   return "pavgw";
+      case Xsse_MAX16S:   return "pmaxw";
+      case Xsse_MAX8U:    return "pmaxub";
+      case Xsse_MIN16S:   return "pminw";
+      case Xsse_MIN8U:    return "pminub";
+      case Xsse_CMPEQ8:   return "pcmpeqb";
+      case Xsse_CMPEQ16:  return "pcmpeqw";
+      case Xsse_CMPEQ32:  return "pcmpeqd";
+      case Xsse_CMPGT8S:  return "pcmpgtb";
+      case Xsse_CMPGT16S: return "pcmpgtw";
+      case Xsse_CMPGT32S: return "pcmpgtd";
+      case Xsse_SHL16:    return "psllw";
+      case Xsse_SHL32:    return "pslld";
+      case Xsse_SHL64:    return "psllq";
+      case Xsse_SHR16:    return "psrlw";
+      case Xsse_SHR32:    return "psrld";
+      case Xsse_SHR64:    return "psrlq";
+      case Xsse_SAR16:    return "psraw";
+      case Xsse_SAR32:    return "psrad";
+      case Xsse_PACKSSD:  return "packssdw";
+      case Xsse_PACKSSW:  return "packsswb";
+      case Xsse_PACKUSW:  return "packuswb";
+      case Xsse_PUNPCKHB: return "punpckhb";
+      case Xsse_PUNPCKHW: return "punpckhw";
+      case Xsse_PUNPCKHD: return "punpckhd";
+      case Xsse_PUNPCKLB: return "punpcklb";
+      case Xsse_PUNPCKLW: return "punpcklw";
+      case Xsse_PUNPCKLD: return "punpckld";
       default: vpanic("showX86SseOp");
    }
 }
@@ -771,6 +819,7 @@ X86Instr* X86Instr_Sse32Fx4 ( X86SseOp op, HReg src, HReg dst ) {
    i->Xin.Sse32Fx4.op  = op;
    i->Xin.Sse32Fx4.src = src;
    i->Xin.Sse32Fx4.dst = dst;
+   vassert(op != Xsse_MOV);
    return i;
 }
 X86Instr* X86Instr_Sse32FLo ( X86SseOp op, HReg src, HReg dst ) {
@@ -779,6 +828,7 @@ X86Instr* X86Instr_Sse32FLo ( X86SseOp op, HReg src, HReg dst ) {
    i->Xin.Sse32FLo.op  = op;
    i->Xin.Sse32FLo.src = src;
    i->Xin.Sse32FLo.dst = dst;
+   vassert(op != Xsse_MOV);
    return i;
 }
 X86Instr* X86Instr_Sse64Fx2 ( X86SseOp op, HReg src, HReg dst ) {
@@ -787,6 +837,7 @@ X86Instr* X86Instr_Sse64Fx2 ( X86SseOp op, HReg src, HReg dst ) {
    i->Xin.Sse64Fx2.op  = op;
    i->Xin.Sse64Fx2.src = src;
    i->Xin.Sse64Fx2.dst = dst;
+   vassert(op != Xsse_MOV);
    return i;
 }
 X86Instr* X86Instr_Sse64FLo ( X86SseOp op, HReg src, HReg dst ) {
@@ -795,6 +846,16 @@ X86Instr* X86Instr_Sse64FLo ( X86SseOp op, HReg src, HReg dst ) {
    i->Xin.Sse64FLo.op  = op;
    i->Xin.Sse64FLo.src = src;
    i->Xin.Sse64FLo.dst = dst;
+   vassert(op != Xsse_MOV);
+   return i;
+}
+X86Instr* X86Instr_SseReRg ( X86SseOp op, HReg re, HReg rg ) {
+   X86Instr* i        = LibVEX_Alloc(sizeof(X86Instr));
+   i->tag             = Xin_SseReRg;
+   i->Xin.SseReRg.op  = op;
+   i->Xin.SseReRg.src = re;
+   i->Xin.SseReRg.dst = rg;
+   vassert(op != Xsse_MOV);
    return i;
 }
 
@@ -1035,6 +1096,12 @@ void ppX86Instr ( X86Instr* i ) {
          vex_printf(",");
          ppHRegX86(i->Xin.Sse64FLo.dst);
          return;
+      case Xin_SseReRg:
+         vex_printf("%s ", showX86SseOp(i->Xin.SseReRg.op));
+         ppHRegX86(i->Xin.SseReRg.src);
+         vex_printf(",");
+         ppHRegX86(i->Xin.SseReRg.dst);
+         return;
 
       default:
          vpanic("ppX86Instr");
@@ -1244,6 +1311,11 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i)
          addHRegUse(u, unary ? HRmWrite : HRmModify, 
                        i->Xin.Sse64FLo.dst);
          return;
+      case Xin_SseReRg:
+         vassert(i->Xin.SseReRg.op != Xsse_MOV);
+         addHRegUse(u, HRmRead,   i->Xin.SseReRg.src);
+         addHRegUse(u, HRmModify, i->Xin.SseReRg.dst);
+         return;
       default:
          ppX86Instr(i);
          vpanic("getRegUsage_X86Instr");
@@ -1380,6 +1452,10 @@ void mapRegs_X86Instr (HRegRemap* m, X86Instr* i)
          mapReg(m, &i->Xin.Sse64FLo.src);
          mapReg(m, &i->Xin.Sse64FLo.dst);
          return;
+      case Xin_SseReRg:
+         mapReg(m, &i->Xin.SseReRg.src);
+         mapReg(m, &i->Xin.SseReRg.dst);
+         return;
       default:
          ppX86Instr(i);
          vpanic("mapRegs_X86Instr");
@@ -2602,6 +2678,29 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
          *p++ = (UChar)(xtra & 0xFF);
       goto done;
 
+   case Xin_SseReRg:
+#     define XX(_n) *p++ = (_n)
+      switch (i->Xin.SseReRg.op) {
+         case Xsse_PACKSSD: XX(0x66); XX(0x0F); XX(0x6B); break;
+         case Xsse_PACKSSW: XX(0x66); XX(0x0F); XX(0x63); break;
+         case Xsse_PACKUSW: XX(0x66); XX(0x0F); XX(0x67); break;
+         case Xsse_ADD8:    XX(0x66); XX(0x0F); XX(0xFC); break;
+         case Xsse_ADD16:   XX(0x66); XX(0x0F); XX(0xFD); break;
+         case Xsse_ADD32:   XX(0x66); XX(0x0F); XX(0xFE); break;
+         case Xsse_ADD64:   XX(0x66); XX(0x0F); XX(0xD4); break;
+         case Xsse_QADD8S:  XX(0x66); XX(0x0F); XX(0xEC); break;
+         case Xsse_QADD16S: XX(0x66); XX(0x0F); XX(0xED); break;
+         case Xsse_QADD8U:  XX(0x66); XX(0x0F); XX(0xDC); break;
+         case Xsse_QADD16U: XX(0x66); XX(0x0F); XX(0xDD); break;
+         case Xsse_AVG8U:   XX(0x66); XX(0x0F); XX(0xE0); break;
+         case Xsse_AVG16U:  XX(0x66); XX(0x0F); XX(0xE3); break;
+         default: goto bad;
+      }
+      p = doAMode_R(p, fake(vregNo(i->Xin.SseReRg.dst)),
+                       fake(vregNo(i->Xin.SseReRg.src)) );
+#     undef XX
+      goto done;
+
    default: 
       goto bad;
    }
index 7c16b86472cf96fa69388027d5690eb5928d1e54..63e50a466c377e1e718891f06217cddcf5b2ca77 100644 (file)
@@ -307,11 +307,39 @@ extern HChar* showX86FpOp ( X86FpOp );
 typedef
    enum {
       Xsse_INVALID,
-      Xsse_MOV, Xsse_AND, Xsse_OR, Xsse_XOR, Xsse_ANDN,
+      /* mov */
+      Xsse_MOV,
+      /* Floating point binary */
       Xsse_ADDF, Xsse_SUBF, Xsse_MULF, Xsse_DIVF,
       Xsse_MAXF, Xsse_MINF,
+      Xsse_CMPEQF, Xsse_CMPLTF, Xsse_CMPLEF, Xsse_CMPUNF,
+      /* Floating point unary */
       Xsse_RCPF, Xsse_RSQRTF, Xsse_SQRTF, 
-      Xsse_CMPEQF, Xsse_CMPLTF, Xsse_CMPLEF, Xsse_CMPUNF
+      /* Bitwise */
+      Xsse_AND, Xsse_OR, Xsse_XOR, Xsse_ANDN,
+      /* Integer binary */
+      Xsse_ADD8,   Xsse_ADD16,   Xsse_ADD32,   Xsse_ADD64,
+      Xsse_QADD8U, Xsse_QADD16U,
+      Xsse_QADD8S, Xsse_QADD16S,
+      Xsse_SUB8,   Xsse_SUB16,   Xsse_SUB32,   Xsse_SUB64,
+      Xsse_QSUB8U, Xsse_QSUB16U,
+      Xsse_QSUB8S, Xsse_QSUB16S,
+      Xsse_MUL16,
+      Xsse_MULHI16U,
+      Xsse_MULHI16S,
+      Xsse_AVG8U, Xsse_AVG16U,
+      Xsse_MAX16S,
+      Xsse_MAX8U,
+      Xsse_MIN16S,
+      Xsse_MIN8U,
+      Xsse_CMPEQ8,  Xsse_CMPEQ16,  Xsse_CMPEQ32,
+      Xsse_CMPGT8S, Xsse_CMPGT16S, Xsse_CMPGT32S,
+      Xsse_SHL16, Xsse_SHL32, Xsse_SHL64,
+      Xsse_SHR16, Xsse_SHR32, Xsse_SHR64,
+      Xsse_SAR16, Xsse_SAR32, 
+      Xsse_PACKSSD,  Xsse_PACKSSW, Xsse_PACKUSW,
+      Xsse_PUNPCKHB, Xsse_PUNPCKHW, Xsse_PUNPCKHD,
+      Xsse_PUNPCKLB, Xsse_PUNPCKLW, Xsse_PUNPCKLD
    }
    X86SseOp;
 
@@ -355,8 +383,8 @@ typedef
       Xin_Sse32Fx4,  /* SSE binary, 32Fx4 */
       Xin_Sse32FLo,  /* SSE binary, 32F in lowest lane only */
       Xin_Sse64Fx2,  /* SSE binary, 64Fx2 */
-      Xin_Sse64FLo   /* SSE binary, 64F in lowest lane only */
-      /* Xin_SseUn32Fx4 */
+      Xin_Sse64FLo,  /* SSE binary, 64F in lowest lane only */
+      Xin_SseReRg    /* SSE binary general reg-reg, Re, Rg */
    }
    X86InstrTag;
 
@@ -561,6 +589,11 @@ typedef
             HReg     src;
             HReg     dst;
          } Sse64FLo;
+         struct {
+            X86SseOp op;
+            HReg     src;
+            HReg     dst;
+         } SseReRg;
 
       } Xin;
    }
@@ -602,6 +635,7 @@ extern X86Instr* X86Instr_Sse32Fx4  ( X86SseOp, HReg, HReg );
 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 void ppX86Instr ( X86Instr* );
index b0ab1c5b523f9ab668f8f5e8c437f632c081228f..344a012801431f605c762d308cc5da1d64abde2b 100644 (file)
@@ -2412,6 +2412,7 @@ static HReg iselVecExpr ( ISelEnv* env, IRExpr* e )
 /* DO NOT CALL THIS DIRECTLY */
 static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
 {
+   Bool     arg1isEReg = False;
    X86SseOp op = Xsse_INVALID;
    IRType   ty = typeOfIRExpr(env->type_env,e);
    vassert(e);
@@ -2676,6 +2677,36 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
          return dst;
       }
 
+      case Iop_QNarrow32Sx4: op = Xsse_PACKSSD; 
+                             arg1isEReg = True; goto do_SseReRg;
+      case Iop_QNarrow16Sx8: op = Xsse_PACKSSW; 
+                             arg1isEReg = True; goto do_SseReRg;
+      case Iop_QNarrow16Ux8: op = Xsse_PACKUSW; 
+                             arg1isEReg = True; goto do_SseReRg;
+      case Iop_Add8x16:   op = Xsse_ADD8;    goto do_SseReRg;
+      case Iop_Add16x8:   op = Xsse_ADD16;   goto do_SseReRg;
+      case Iop_Add32x4:   op = Xsse_ADD32;   goto do_SseReRg;
+      case Iop_Add64x2:   op = Xsse_ADD64;   goto do_SseReRg;
+      case Iop_QAdd8Sx16: op = Xsse_QADD8S;  goto do_SseReRg;
+      case Iop_QAdd16Sx8: op = Xsse_QADD16S; goto do_SseReRg;
+      case Iop_QAdd8Ux16: op = Xsse_QADD8U;  goto do_SseReRg;
+      case Iop_QAdd16Ux8: op = Xsse_QADD16U; goto do_SseReRg;
+      case Iop_Avg8Ux16:  op = Xsse_AVG8U;   goto do_SseReRg;
+      case Iop_Avg16Ux8:  op = Xsse_AVG16U;  goto do_SseReRg;
+      do_SseReRg: {
+         HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1);
+         HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2);
+         HReg dst = newVRegV(env);
+         if (arg1isEReg) {
+            addInstr(env, mk_vMOVsd_RR(arg2, dst));
+            addInstr(env, X86Instr_SseReRg(op, arg1, dst));
+         } else {
+            addInstr(env, mk_vMOVsd_RR(arg1, dst));
+            addInstr(env, X86Instr_SseReRg(op, arg2, dst));
+         }
+         return dst;
+      }
+
       default:
          break;
    } /* switch (e->Iex.Binop.op) */
index 767f8003b09beaa6718932c13e26518319a7777d..1308c64e514f820edf1ec84cbcce2e0ee1e38f96 100644 (file)
@@ -223,10 +223,6 @@ void ppIROp ( IROp op )
       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;
-      case Iop_Xor128:  vex_printf("Xor128"); return;
-
       case Iop_Add32Fx4:  vex_printf("Add32Fx4"); return;
       case Iop_Add32F0x4: vex_printf("Add32F0x4"); return;
       case Iop_Add64Fx2:  vex_printf("Add64Fx2"); return;
@@ -299,6 +295,69 @@ void ppIROp ( IROp op )
       case Iop_Set128lo32: vex_printf("Set128lo32"); return;
       case Iop_Set128lo64: vex_printf("Set128lo64"); return;
 
+      case Iop_And128:  vex_printf("And128"); return;
+      case Iop_Or128:   vex_printf("Or128");  return;
+      case Iop_Xor128:  vex_printf("Xor128"); return;
+
+      case Iop_Add8x16:   vex_printf("Add8x16"); return;
+      case Iop_Add16x8:   vex_printf("Add16x8"); return;
+      case Iop_Add32x4:   vex_printf("Add32x4"); return;
+      case Iop_Add64x2:   vex_printf("Add64x2"); return;
+      case Iop_QAdd8Ux16: vex_printf("QAdd8Ux16"); return;
+      case Iop_QAdd16Ux8: vex_printf("QAdd16Ux8"); return;
+      case Iop_QAdd8Sx16: vex_printf("QAdd8Sx16"); return;
+      case Iop_QAdd16Sx8: vex_printf("QAdd16Sx8"); return;
+
+      case Iop_Sub8x16:   vex_printf("Sub8x16"); return;
+      case Iop_Sub16x8:   vex_printf("Sub16x8"); return;
+      case Iop_Sub32x4:   vex_printf("Sub32x4"); return;
+      case Iop_Sub64x2:   vex_printf("Sub64x2"); return;
+      case Iop_QSub8Ux16: vex_printf("QSub8Ux16"); return;
+      case Iop_QSub16Ux8: vex_printf("QSub16Ux8"); return;
+      case Iop_QSub8Sx16: vex_printf("QSub8Sx16"); return;
+      case Iop_QSub16Sx8: vex_printf("QSub16Sx8"); return;
+
+      case Iop_Mul16x8:    vex_printf("Mul16x8"); return;
+      case Iop_MulHi16Ux8: vex_printf("MulHi16Ux8"); return;
+      case Iop_MulHi16Sx8: vex_printf("MulHi16Sx8"); return;
+
+      case Iop_Avg8Ux16: vex_printf("Avg8Ux16"); return;
+      case Iop_Avg16Ux8: vex_printf("Avg16Ux8"); return;
+
+      case Iop_Max16Sx8: vex_printf("Max16Sx8"); return;
+      case Iop_Max8Ux16: vex_printf("Max8Ux16"); return;
+      case Iop_Min16Sx8: vex_printf("Min16Sx8"); return;
+      case Iop_Min8Ux16: vex_printf("Min8Ux16"); return;
+
+      case Iop_CmpEQ8x16:  vex_printf("CmpEQ8x16"); return;
+      case Iop_CmpEQ16x8:  vex_printf("CmpEQ16x8"); return;
+      case Iop_CmpEQ32x4:  vex_printf("CmpEQ32x4"); return;
+      case Iop_CmpGT8Sx16: vex_printf("CmpGT8Sx16"); return;
+      case Iop_CmpGT16Sx8: vex_printf("CmpGT16Sx8"); return;
+      case Iop_CmpGT32Sx4: vex_printf("CmpGT32Sx4"); return;
+
+      case Iop_ShlN16x8: vex_printf("ShlN16x8"); return;
+      case Iop_ShlN32x4: vex_printf("ShlN32x4"); return;
+      case Iop_ShlN64x2: vex_printf("ShlN64x2"); return;
+      case Iop_ShrN16x8: vex_printf("ShrN16x8"); return;
+      case Iop_ShrN32x4: vex_printf("ShrN32x4"); return;
+      case Iop_ShrN64x2: vex_printf("ShrN64x2"); return;
+      case Iop_SarN16x8: vex_printf("SarN16x8"); return;
+      case Iop_SarN32x4: vex_printf("SarN32x4"); return;
+
+      case Iop_QNarrow16Ux8: vex_printf("QNarrow16Ux8"); return;
+      case Iop_QNarrow16Sx8: vex_printf("QNarrow16Sx8"); return;
+      case Iop_QNarrow32Sx4: vex_printf("QNarrow32Sx4"); return;
+
+      case Iop_InterleaveHI8x16: vex_printf("InterleaveHI8x16"); return;
+      case Iop_InterleaveHI16x8: vex_printf("InterleaveHI16x8"); return;
+      case Iop_InterleaveHI32x4: vex_printf("InterleaveHI32x4"); return;
+      case Iop_InterleaveHI64x2: vex_printf("InterleaveHI64x2"); return;
+      case Iop_InterleaveLO8x16: vex_printf("InterleaveLO8x16"); return;
+      case Iop_InterleaveLO16x8: vex_printf("InterleaveLO16x8"); return;
+      case Iop_InterleaveLO32x4: vex_printf("InterleaveLO32x4"); return;
+      case Iop_InterleaveLO64x2: vex_printf("InterleaveLO64x2"); return;
+
       default: vpanic("ppIROp(1)");
    }
   
@@ -1183,6 +1242,31 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
       case Iop_Sub32Fx4: case Iop_Sub32F0x4:
       case Iop_Sub64Fx2: case Iop_Sub64F0x2:
       case Iop_And128: case Iop_Or128: case Iop_Xor128:
+      case Iop_Add8x16:   case Iop_Add16x8:   
+      case Iop_Add32x4:   case Iop_Add64x2:
+      case Iop_QAdd8Ux16: case Iop_QAdd16Ux8:
+      case Iop_QAdd8Sx16: case Iop_QAdd16Sx8:
+      case Iop_Sub8x16:   case Iop_Sub16x8:
+      case Iop_Sub32x4:   case Iop_Sub64x2:
+      case Iop_QSub8Ux16: case Iop_QSub16Ux8:
+      case Iop_QSub8Sx16: case Iop_QSub16Sx8:
+      case Iop_Mul16x8:
+      case Iop_MulHi16Ux8:
+      case Iop_MulHi16Sx8:
+      case Iop_Avg8Ux16:
+      case Iop_Avg16Ux8:
+      case Iop_Max16Sx8:
+      case Iop_Max8Ux16:
+      case Iop_Min16Sx8:
+      case Iop_Min8Ux16:
+      case Iop_CmpEQ8x16:  case Iop_CmpEQ16x8:  case Iop_CmpEQ32x4:
+      case Iop_CmpGT8Sx16: case Iop_CmpGT16Sx8: case Iop_CmpGT32Sx4:
+      case Iop_QNarrow16Ux8:
+      case Iop_QNarrow16Sx8: case Iop_QNarrow32Sx4:
+      case Iop_InterleaveHI8x16: case Iop_InterleaveHI16x8:
+      case Iop_InterleaveHI32x4: case Iop_InterleaveHI64x2:
+      case Iop_InterleaveLO8x16: case Iop_InterleaveLO16x8: 
+      case Iop_InterleaveLO32x4: case Iop_InterleaveLO64x2:
          BINARY(Ity_V128, Ity_V128,Ity_V128);
 
       case Iop_Recip32Fx4: case Iop_Recip32F0x4:
@@ -1193,6 +1277,11 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
       case Iop_Sqrt64Fx2:  case Iop_Sqrt64F0x2:
          UNARY(Ity_V128, Ity_V128);
 
+      case Iop_ShlN16x8: case Iop_ShlN32x4: case Iop_ShlN64x2:
+      case Iop_ShrN16x8: case Iop_ShrN32x4: case Iop_ShrN64x2:
+      case Iop_SarN16x8: case Iop_SarN32x4:
+        BINARY(Ity_V128, Ity_V128, Ity_I8);
+
       default:
          ppIROp(op);
          vpanic("typeOfPrimop");
index 6c7751f24d45aec4538da55083ce540497f5aef3..d8d8cc58ad9f6a1f3189968386340ba8665e8759 100644 (file)
@@ -327,10 +327,7 @@ typedef
       Iop_ReinterpF64asI64, Iop_ReinterpI64asF64,
       Iop_ReinterpF32asI32, Iop_ReinterpI32asF32,
 
-      /* ------------------ 128-bit SIMD. ------------------ */
-
-      /* 128-bit ops */
-      Iop_And128, Iop_Or128, Iop_Xor128, 
+      /* ------------------ 128-bit SIMD FP. ------------------ */
 
       /* --- 32x4 vector FP --- */
 
@@ -389,11 +386,58 @@ typedef
       Iop_64Uto128,
       Iop_Set128lo32,
       Iop_Set128lo64,
-      /* 128 -> 32 bit unpack */
-      //Iop_128W3to32,   // :: V128 -> I32, bits 127-96
-      //Iop_128W2to32,   // :: V128 -> I32, bits 95-64
-      //Iop_128W1to32,   // :: V128 -> I32, bits 63-32
-      //Iop_128W0to32    // :: V128 -> I32, bits 31-0
+
+      /* ------------------ 128-bit SIMD Integer. ------------------ */
+
+      /* BITWISE OPS */
+      Iop_And128, Iop_Or128, Iop_Xor128, 
+
+      /* ADDITION (normal / unsigned sat / signed sat) */
+      Iop_Add8x16,   Iop_Add16x8,   Iop_Add32x4,  Iop_Add64x2,
+      Iop_QAdd8Ux16, Iop_QAdd16Ux8,
+      Iop_QAdd8Sx16, Iop_QAdd16Sx8,
+
+      /* SUBTRACTION (normal / unsigned sat / signed sat) */
+      Iop_Sub8x16,   Iop_Sub16x8,   Iop_Sub32x4,  Iop_Sub64x2,
+      Iop_QSub8Ux16, Iop_QSub16Ux8,
+      Iop_QSub8Sx16, Iop_QSub16Sx8,
+
+      /* MULTIPLICATION (normal / high half of signed/unsigned) */
+      Iop_Mul16x8,
+      Iop_MulHi16Ux8,
+      Iop_MulHi16Sx8,
+
+      /* AVERAGING: note: (arg1 + arg2 + 1) >> 1 */
+      Iop_Avg8Ux16,
+      Iop_Avg16Ux8,
+
+      /* MIN/MAX */
+      Iop_Max16Sx8,
+      Iop_Max8Ux16,
+      Iop_Min16Sx8,
+      Iop_Min8Ux16,
+
+      /* COMPARISON */
+      Iop_CmpEQ8x16,  Iop_CmpEQ16x8,  Iop_CmpEQ32x4,
+      Iop_CmpGT8Sx16, Iop_CmpGT16Sx8, Iop_CmpGT32Sx4,
+
+      /* VECTOR x SCALAR SHIFT (shift amt :: Ity_I8) */
+      Iop_ShlN16x8, Iop_ShlN32x4, Iop_ShlN64x2,
+      Iop_ShrN16x8, Iop_ShrN32x4, Iop_ShrN64x2,
+      Iop_SarN16x8, Iop_SarN32x4,
+
+      /* NARROWING -- narrow 2xV128 into 1xV128, hi half from left arg */
+      Iop_QNarrow16Ux8,
+      Iop_QNarrow16Sx8,
+      Iop_QNarrow32Sx4,
+
+      /* INTERLEAVING -- interleave lanes from low or high halves of
+         operands.  Most-significant result lane is from the left
+         arg. */
+      Iop_InterleaveHI8x16, Iop_InterleaveHI16x8,
+      Iop_InterleaveHI32x4, Iop_InterleaveHI64x2,
+      Iop_InterleaveLO8x16, Iop_InterleaveLO16x8, 
+      Iop_InterleaveLO32x4, Iop_InterleaveLO64x2
    }
    IROp;