]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
x86 guest/host: do SSE comparisons.
authorJulian Seward <jseward@acm.org>
Thu, 2 Dec 2004 16:16:11 +0000 (16:16 +0000)
committerJulian Seward <jseward@acm.org>
Thu, 2 Dec 2004 16:16:11 +0000 (16:16 +0000)
To make this easier, add to IRConst a new kind of literal --
a 128-bit literal specified by a 16-bit value.  Each bit of the
latter is defines one byte of the 128-bit value, either 0x00 or
0xFF.

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

VEX/priv/guest-x86/toIR.c
VEX/priv/host-generic/h_generic_regs.h
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 409cc24f33246d28689ee1e23114cae1f7c54833..4668a21bd145cdae9694c0e2901208a1023ab813 100644 (file)
@@ -630,6 +630,11 @@ static IRExpr* mkU ( IRType ty, UInt i )
    vpanic("mkU(x86)");
 }
 
+static IRExpr* mkV128 ( UShort mask )
+{
+   return IRExpr_Const(IRConst_V128(mask));
+}
+
 static IRExpr* loadLE ( IRType ty, IRExpr* data )
 {
    return IRExpr_LDle(ty,data);
@@ -6741,25 +6746,133 @@ static void putXMMRegHI64( Int xmmreg, IRExpr* e64 )
    );
 }
 
-static UInt dis_SSE_E_to_G ( UChar sorb, UInt delta, 
-                             HChar* opname, IROp op )
+static UInt dis_SSE_E_to_G_wrk ( 
+               UChar sorb, UInt delta, 
+               HChar* opname, IROp op,
+               Bool   invertG
+            )
 {
-   HChar dis_buf[50];
-   Int   alen;
-   UChar rm = getIByte(delta);
+   HChar   dis_buf[50];
+   Int     alen;
+   IRTemp  addr;
+   UChar   rm = getIByte(delta);
+   IRExpr* gpart
+      = invertG ? binop( Iop_Xor128, 
+                         getXMMReg(gregOfRM(rm)), 
+                         mkV128(0xFFFF) )
+                : getXMMReg(gregOfRM(rm));
    if (epartIsReg(rm)) {
       putXMMReg( gregOfRM(rm), 
-                 binop(op, getXMMReg(gregOfRM(rm)),
-                 getXMMReg(eregOfRM(rm))) );
+                 binop(op, gpart,
+                           getXMMReg(eregOfRM(rm))) );
       DIP("%s %s,%s\n", opname,
                         nameXMMReg(eregOfRM(rm)),
                         nameXMMReg(gregOfRM(rm)) );
       return delta+1;
    } else {
-      vassert(0);
+      addr = disAMode ( &alen, sorb, delta, dis_buf );
+      putXMMReg( gregOfRM(rm), 
+                 binop(op, gpart,
+                           loadLE(Ity_V128, mkexpr(addr))) );
+      DIP("%s %s,%s\n", opname,
+                        dis_buf,
+                        nameXMMReg(gregOfRM(rm)) );
+      return delta+alen;
    }
 }
 
+static
+UInt dis_SSE_E_to_G ( UChar sorb, UInt delta, HChar* opname, IROp op )
+{
+   return dis_SSE_E_to_G_wrk( sorb, delta, opname, op, False );
+}
+
+static
+UInt dis_SSE_E_to_G_invG ( UChar sorb, UInt delta, HChar* opname, IROp op )
+{
+   return dis_SSE_E_to_G_wrk( sorb, delta, opname, op, True );
+}
+
+static void findSSECmpOp ( Bool* needNot, IROp* op, 
+                           Int imm8, Bool all_lanes, Int sz )
+{
+   imm8 &= 7;
+   *needNot = False;
+   *op      = Iop_INVALID;
+   if (imm8 >= 4) {
+      *needNot = True;
+      imm8 -= 4;
+   }
+
+   if (sz == 4 && all_lanes) {
+      switch (imm8) {
+         case 0: *op = Iop_CmpEQ32Fx4; return;
+         case 1: *op = Iop_CmpLT32Fx4; return;
+         case 2: *op = Iop_CmpLE32Fx4; return;
+         case 3: *op = Iop_CmpUN32Fx4; return;
+         default: break;
+      }
+   }
+   if (sz == 4 && !all_lanes) {
+      switch (imm8) {
+         case 0: *op = Iop_CmpEQ32F0x4; return;
+         case 1: *op = Iop_CmpLT32F0x4; return;
+         case 2: *op = Iop_CmpLE32F0x4; return;
+         case 3: *op = Iop_CmpUN32F0x4; return;
+         default: break;
+      }
+   }
+   if (sz == 8) {
+   }
+   vpanic("findSSECmpOp(x86,guest)");
+}
+
+static UInt dis_SSEcmp_E_to_G ( UChar sorb, UInt delta, 
+                               HChar* opname, Bool all_lanes, Int sz )
+{
+   HChar   dis_buf[50];
+   Int     alen, imm8;
+   IRTemp  addr;
+   Bool    needNot = False;
+   IROp    op      = Iop_INVALID;
+   IRTemp  plain   = newTemp(Ity_V128);
+   UChar   rm      = getIByte(delta);
+   UShort  mask    = 0;
+   vassert(sz == 4 || sz == 8);
+   if (epartIsReg(rm)) {
+      imm8 = getIByte(delta+1);
+      findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
+      assign( plain, binop(op, getXMMReg(gregOfRM(rm)), 
+                               getXMMReg(eregOfRM(rm))) );
+      delta += 2;
+      DIP("%s $%d,%s,%s\n", opname,
+                            (Int)imm8,
+                            nameXMMReg(eregOfRM(rm)),
+                            nameXMMReg(gregOfRM(rm)) );
+   } else {
+      addr = disAMode ( &alen, sorb, delta, dis_buf );
+      imm8 = getIByte(delta+alen);
+      findSSECmpOp(&needNot, &op, imm8, all_lanes, sz);
+      assign( plain, binop(op, getXMMReg(gregOfRM(rm)), 
+                               loadLE(Ity_V128, mkexpr(addr))) );
+      delta += alen+1;
+      DIP("%s $%d,%s,%s\n", opname,
+                            (Int)imm8,
+                            dis_buf,
+                            nameXMMReg(gregOfRM(rm)) );
+   }
+
+   if (needNot && all_lanes)
+      mask = 0xFFFF;
+   if (needNot && !all_lanes)
+      mask = 0x000F;
+
+   putXMMReg( gregOfRM(rm), 
+              needNot ? binop(Iop_Xor128, mkexpr(plain), mkV128(mask))
+                      : mkexpr(plain) );
+   return delta;
+}
+
 
 /*------------------------------------------------------------*/
 /*--- Disassemble a single instruction                     ---*/
@@ -6959,6 +7072,40 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       goto decode_success;
    }
 
+   /* F3 0F 58 = ADDSS -- add 32F0x4 from R/M to R */
+   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x58) {
+      vassert(sz == 4);
+      delta = dis_SSE_E_to_G( sorb, delta+3, "addss", Iop_Add32F0x4 );
+      goto decode_success;
+   }
+
+   /* 0F 55 = ANDNPS -- G = (not G) and E */
+   if (insn[0] == 0x0F && insn[1] == 0x55) {
+      vassert(sz == 4);
+      delta = dis_SSE_E_to_G_invG( sorb, delta+2, "andnps", Iop_And128 );
+      goto decode_success;
+   }
+
+   /* 0F 54 = ANDPS -- G = G and E */
+   if (insn[0] == 0x0F && insn[1] == 0x54) {
+      vassert(sz == 4);
+      delta = dis_SSE_E_to_G( sorb, delta+2, "andps", Iop_And128 );
+      goto decode_success;
+   }
+
+   /* 0F C2 = CMPPS -- 32Fx4 comparison from R/M to R */
+   if (insn[0] == 0x0F && insn[1] == 0xC2) {
+      vassert(sz == 4);
+      delta = dis_SSEcmp_E_to_G( sorb, delta+2, "cmpps", True, 4 );
+      goto decode_success;
+   }
+
+   /* F3 0F C2 = CMPSS -- 32F0x4 comparison from R/M to R */
+   if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xC2) {
+      vassert(sz == 4);
+      delta = dis_SSEcmp_E_to_G( sorb, delta+3, "cmpss", False, 4 );
+      goto decode_success;
+   }
 
 
 //-- 
index 3ea1b73cf5a1c7973874bf19a2a6d24b9bb71d47..8208e820477d2812fcd2c2720329ce1067e60c61 100644 (file)
@@ -77,6 +77,11 @@ typedef UInt HReg;
    selectors can speak about.  We would not expect all of them to be
    available on any specific host.  For example on x86, the available
    classes are: Int32, Flt64, Vec128 only.
+
+   IMPORTANT NOTE: Vec128 is the only >= 128-bit-sized class, and
+   reg_alloc2.c handles it specially when assigning spill slots.  If
+   you add another 128-bit or larger regclass, you must remember to
+   update reg_alloc2.c accordingly.
 */
 typedef
    enum { 
index 834b638131f91d1b70329303904617816cc894c5..21fecf094270624e1b0e5dd088dd4eef38e981f5 100644 (file)
@@ -500,14 +500,18 @@ HChar* showX86FpOp ( X86FpOp op ) {
 
 HChar* showX86SseOp ( X86SseOp op ) {
    switch (op) {
-      case Xsse_MOV:  return "mov(?!)";
-      case Xsse_AND:  return "add";
-      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_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_CMPEQF: return "cmpFeq";
+      case Xsse_CMPLTF: return "cmpFlt";
+      case Xsse_CMPLEF: return "cmpFle";
+      case Xsse_CMPUNF: return "cmpFun";
       default: vpanic("showX86SseOp");
    }
 }
@@ -712,6 +716,14 @@ X86Instr* X86Instr_FpCmp ( HReg srcL, HReg srcR, HReg dst ) {
    return i;
 }
 
+X86Instr* X86Instr_SseConst ( UShort con, HReg dst ) {
+   X86Instr* i            = LibVEX_Alloc(sizeof(X86Instr));
+   i->tag                 = Xin_SseConst;
+   i->Xin.SseConst.con    = con;
+   i->Xin.SseConst.dst    = dst;
+   vassert(hregClass(dst) == HRcVec128);
+   return i;
+}
 X86Instr* X86Instr_SseLdSt ( Bool isLoad, HReg reg, X86AMode* addr ) {
    X86Instr* i           = LibVEX_Alloc(sizeof(X86Instr));
    i->tag                = Xin_SseLdSt;
@@ -726,8 +738,8 @@ X86Instr* X86Instr_Sse128 ( X86SseOp op, HReg src, HReg dst ) {
    i->Xin.Sse128.op  = op;
    i->Xin.Sse128.src = src;
    i->Xin.Sse128.dst = dst;
-   vassert(op == Xsse_MOV || op == Xsse_AND || op == Xsse_OR
-           || op == Xsse_XOR || op == Xsse_ANDN);
+   vassert(op == Xsse_MOV 
+           || op == Xsse_AND || op == Xsse_OR || op == Xsse_XOR);
    return i;
 }
 X86Instr* X86Instr_Sse32Fx4  ( X86SseOp op, HReg src, HReg dst ) {
@@ -922,6 +934,10 @@ void ppX86Instr ( X86Instr* i ) {
          vex_printf(",");
          ppHRegX86(i->Xin.FpCmp.dst);
          break;
+      case Xin_SseConst:
+         vex_printf("const $0x%04x,", (Int)i->Xin.SseConst.con);
+         ppHRegX86(i->Xin.SseConst.dst);
+         break;
       case Xin_SseLdSt:
          vex_printf("movups ");
          if (i->Xin.SseLdSt.isLoad) {
@@ -1112,6 +1128,9 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i)
          addHRegUse(u, i->Xin.SseLdSt.isLoad ? HRmWrite : HRmRead,
                        i->Xin.SseLdSt.reg);
          return;
+      case Xin_SseConst:
+         addHRegUse(u, HRmWrite, i->Xin.SseConst.dst);
+         return;
       case Xin_Sse128:
          addHRegUse(u, HRmRead, i->Xin.Sse128.src);
          addHRegUse(u, i->Xin.Sse128.op==Xsse_MOV ? HRmWrite : HRmModify,
@@ -1122,6 +1141,11 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i)
          addHRegUse(u, HRmRead,   i->Xin.Sse32Fx4.src);
          addHRegUse(u, HRmModify, i->Xin.Sse32Fx4.dst);
          return;
+      case Xin_Sse32FLo:
+         vassert(i->Xin.Sse32FLo.op != Xsse_MOV);
+         addHRegUse(u, HRmRead,   i->Xin.Sse32FLo.src);
+         addHRegUse(u, HRmModify, i->Xin.Sse32FLo.dst);
+         return;
       default:
          ppX86Instr(i);
          vpanic("getRegUsage_X86Instr");
@@ -1223,6 +1247,9 @@ void mapRegs_X86Instr (HRegRemap* m, X86Instr* i)
          mapReg(m, &i->Xin.FpCmp.srcR);
          mapReg(m, &i->Xin.FpCmp.dst);
          return;
+      case Xin_SseConst:
+         mapReg(m, &i->Xin.SseConst.dst);
+         return;
       case Xin_SseLdSt:
          mapReg(m, &i->Xin.SseLdSt.reg);
          mapRegs_X86AMode(m, i->Xin.SseLdSt.addr);
@@ -1235,6 +1262,10 @@ void mapRegs_X86Instr (HRegRemap* m, X86Instr* i)
          mapReg(m, &i->Xin.Sse32Fx4.src);
          mapReg(m, &i->Xin.Sse32Fx4.dst);
          return;
+      case Xin_Sse32FLo:
+         mapReg(m, &i->Xin.Sse32FLo.src);
+         mapReg(m, &i->Xin.Sse32FLo.dst);
+         return;
       default:
          ppX86Instr(i);
          vpanic("mapRegs_X86Instr");
@@ -1528,6 +1559,36 @@ static UChar* do_fop2_st ( UChar* p, X86FpOp op, Int i )
 #  undef fake
 }
 
+/* Push a 32-bit word on the stack.  The word depends on tags[3:0];
+each byte is either 0x00 or 0xFF depending on the corresponding bit in tags[].
+*/
+static UChar* push_word_from_tags ( UChar* p, UShort tags )
+{
+   UInt w;
+   vassert(0 == (tags & ~0xF));
+   if (tags == 0) {
+      /* pushl $0x00000000 */
+      *p++ = 0x6A;
+      *p++ = 0x00;
+   }
+   else 
+   /* pushl $0xFFFFFFFF */
+   if (tags == 0xF) {
+      *p++ = 0x6A;
+      *p++ = 0xFF;
+   } else {
+      vassert(0); /* awaiting test case */
+      w = 0;
+      if (tags & 1) w |= 0x000000FF;
+      if (tags & 2) w |= 0x0000FF00;
+      if (tags & 4) w |= 0x00FF0000;
+      if (tags & 8) w |= 0xFF000000;
+      *p++ = 0x68;
+      p = emit32(p, w);
+   }
+   return p;
+}
+
 /* Emit an instruction into buf and return the number of bytes used.
    Note that buf is not the insn's final place, and therefore it is
    imperative to emit position-independent code. */
@@ -1536,6 +1597,7 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
 {
    UInt irno, opc, opc_rr, subopc_imm, opc_imma, opc_cl, opc_imm, subopc;
 
+   UInt   xtra;
    UChar* p = &buf[0];
    UChar* ptmp;
    vassert(nbuf >= 32);
@@ -2262,17 +2324,71 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
       p = doAMode_R(p, hregX86_EAX(), i->Xin.FpCmp.dst);
       goto done;
 
+   case Xin_SseConst: {
+      UShort con = i->Xin.SseConst.con;
+      p = push_word_from_tags(p, (con >> 12) & 0xF);
+      p = push_word_from_tags(p, (con >> 8) & 0xF);
+      p = push_word_from_tags(p, (con >> 4) & 0xF);
+      p = push_word_from_tags(p, con & 0xF);
+      /* movl (%esp), %xmm-dst */
+      *p++ = 0x0F;
+      *p++ = 0x10;
+      *p++ = 0x04 + 8 * (7 & vregNo(i->Xin.SseConst.dst));
+      *p++ = 0x24;
+      /* addl $16, %esp */
+      *p++ = 0x83;
+      *p++ = 0xC4;
+      *p++ = 0x10;
+      goto done;
+   }
    case Xin_SseLdSt:
       *p++ = 0x0F; 
       *p++ = i->Xin.SseLdSt.isLoad ? 0x10 : 0x11;
       p = doAMode_M(p, fake(vregNo(i->Xin.SseLdSt.reg)), i->Xin.SseLdSt.addr);
       goto done;
 
+   case Xin_Sse128:
+      *p++ = 0x0F;
+      switch (i->Xin.Sse128.op) {
+         case Xsse_XOR: *p++ = 0x57; break;
+         case Xsse_AND: *p++ = 0x54; break;
+         default: goto bad;
+      }
+      p = doAMode_R(p, fake(vregNo(i->Xin.Sse128.dst)),
+                       fake(vregNo(i->Xin.Sse128.src)) );
+      goto done;
+
    case Xin_Sse32Fx4:
+      xtra = 0;
       *p++ = 0x0F;
-      *p++ = 0x58;
+      switch (i->Xin.Sse32Fx4.op) {
+         case Xsse_ADDF:   *p++ = 0x58; break;
+         case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
+         case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
+         case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
+         default: goto bad;
+      }
       p = doAMode_R(p, fake(vregNo(i->Xin.Sse32Fx4.dst)),
                        fake(vregNo(i->Xin.Sse32Fx4.src)) );
+      if (xtra & 0x100)
+         *p++ = (UChar)(xtra & 0xFF);
+      goto done;
+
+   case Xin_Sse32FLo:
+      xtra = 0;
+      *p++ = 0xF3;
+      *p++ = 0x0F;
+      switch (i->Xin.Sse32FLo.op) {
+         case Xsse_ADDF:   *p++ = 0x58; break;
+         case Xsse_CMPEQF: *p++ = 0xC2; xtra = 0x100; break;
+         case Xsse_CMPLTF: *p++ = 0xC2; xtra = 0x101; break;
+         case Xsse_CMPLEF: *p++ = 0xC2; xtra = 0x102; break;
+         default: goto bad;
+      }
+      p = doAMode_R(p, fake(vregNo(i->Xin.Sse32FLo.dst)),
+                       fake(vregNo(i->Xin.Sse32FLo.src)) );
+      if (xtra & 0x100)
+         *p++ = (UChar)(xtra & 0xFF);
       goto done;
 
    default: 
@@ -2291,97 +2407,6 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
 #  undef fake
 }
 
-
-#if 0
-/* Self-contained test; can be called directly from
-   main. */
-void test_asm86 ( void )
-{
-  UChar buf[32];
-  Int i, n;
-  HReg edi = hregX86_EDI();
-  HReg esi = hregX86_ESI();
-  HReg ecx = hregX86_ECX();
-  HReg ebp = hregX86_EBP();
-  HReg eax = hregX86_EAX();
-  HReg esp = hregX86_ESP();
-
-#define T(_iii)                                  \
-  do { X86Instr* iii = _iii;                     \
-       vex_printf("\n   ");                      \
-       ppX86Instr(iii);                          \
-       vex_printf("\n   ");                      \
-       n = emit_X86Instr( buf, 32, iii );        \
-       for (i = 0; i < n; i++) {                 \
-           if (buf[i] < 0x10)                    \
-              vex_printf("0%x ", (Int)buf[i]);   \
-           else                                  \
-              vex_printf("%x ", (Int)buf[i]);    \
-       }                                         \
-       vex_printf("\n");                         \
-  } while (0)
-
-#if 0
-T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Reg(esi), edi) );
-T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Imm(0x12345678), edi) );
-T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IR(0,esi)), edi) );
-T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IR(0,ebp)), edi) );
-T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IR(1,esi)), edi) );
-T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IR(1,ebp)), edi) );
-T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IR(127,esi)), edi) );
-T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IR(256,esi)), edi) );
-T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IRRS(1,esi,ecx,0)), edi) );
-T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IRRS(1,esi,ecx,3)), edi) );
-T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IRRS(127,esi,ecx,3)), edi) );
-T( X86Instr_Alu32R(Xalu_MOV, X86RMI_Mem(X86AMode_IRRS(256,esi,ecx,3)), edi) );
-#endif
-
-#if 0
-T( X86Instr_Alu32M(Xalu_MOV, X86RI_Imm(9), X86AMode_IR(0,esi)) );
-T( X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(edi), X86AMode_IR(0,esi)) );
-T( X86Instr_Alu32M(Xalu_MOV, X86RI_Imm(999), X86AMode_IRRS(256,esi,ecx,3)) );
-T( X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(ebp), X86AMode_IRRS(256,esi,ecx,3)) );
-#endif
-
-#if 0
-T( X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(0x42), eax) );
-T( X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(0x41424344), eax) );
-T( X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(0x42), esp) );
-T( X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(0x41424344), esp) );
-T( X86Instr_Alu32R(Xalu_ADD, X86RMI_Reg(esi), edi) );
-T( X86Instr_Alu32R(Xalu_ADD, X86RMI_Mem(X86AMode_IR(1,esi)), edi) );
-#endif
-
-#if 0
-T( X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(0x42), eax) );
-T( X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(0x41424344), eax) );
-T( X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(0x42), esp) );
-T( X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(0x41424344), esp) );
-T( X86Instr_Alu32R(Xalu_SUB, X86RMI_Reg(esi), edi) );
-T( X86Instr_Alu32R(Xalu_SUB, X86RMI_Mem(X86AMode_IR(1,esi)), edi) );
-#endif
-
-#if 0
-T( X86Instr_Alu32M(Xalu_ADD, X86RI_Imm(0x42), X86AMode_IR(0x99,esi)) );
-T( X86Instr_Alu32M(Xalu_ADD, X86RI_Imm(0x4243), X86AMode_IR(0x99,esi)) );
-T( X86Instr_Alu32M(Xalu_ADD, X86RI_Reg(ecx), X86AMode_IR(0x99,ebp)) );
-T( X86Instr_Alu32M(Xalu_ADD, X86RI_Reg(ecx), X86AMode_IR(0x80,ebp)) );
-T( X86Instr_Alu32M(Xalu_ADD, X86RI_Reg(ecx), X86AMode_IR(0x7F,ebp)) );
-#endif
-
-#if 1
-T( X86Instr_Alu32M(Xalu_SUB, X86RI_Imm(0x42), X86AMode_IR(0x99,esi)) );
-T( X86Instr_Alu32M(Xalu_SUB, X86RI_Imm(0x4243), X86AMode_IR(0x99,esi)) );
-T( X86Instr_Alu32M(Xalu_SUB, X86RI_Reg(ecx), X86AMode_IR(0x99,ebp)) );
-T( X86Instr_Alu32M(Xalu_SUB, X86RI_Reg(ecx), X86AMode_IR(0x80,ebp)) );
-T( X86Instr_Alu32M(Xalu_SUB, X86RI_Reg(ecx), X86AMode_IR(0x7F,ebp)) );
-#endif
-
-#undef T
-}
-#endif
-
-
 /*---------------------------------------------------------------*/
 /*--- end                                    host-x86/hdefs.c ---*/
 /*---------------------------------------------------------------*/
index 7aaa6a06135cf56b661eef6162b4f6d998ad2920..ef6f6e0dd2e92105b1c6dd672fe44c3e24f8fed2 100644 (file)
@@ -308,7 +308,8 @@ typedef
    enum {
       Xsse_INVALID,
       Xsse_MOV, Xsse_AND, Xsse_OR, Xsse_XOR, Xsse_ANDN,
-      Xsse_ADDF, Xsse_SUBF, Xsse_MULF
+      Xsse_ADDF, Xsse_SUBF, Xsse_MULF,
+      Xsse_CMPEQF, Xsse_CMPLTF, Xsse_CMPLEF, Xsse_CMPUNF
    }
    X86SseOp;
 
@@ -344,6 +345,7 @@ typedef
       Xin_FpStSW_AX, /* fstsw %ax */
       Xin_FpCmp,     /* FP compare, generating a C320 value into int reg */
 
+      Xin_SseConst,  /* Generate restricted SSE literal */
       Xin_SseLdSt,   /* SSE load/store, no alignment constraints */
       Xin_Sse128,    /* SSE binary typeless (and/or/xor/andn) */
       Xin_Sse32Fx4,  /* SSE binary, 32Fx4 */
@@ -508,6 +510,10 @@ typedef
          } FpCmp;
 
          /* Simplistic SSE[123] */
+         struct {
+            UShort  con;
+            HReg    dst;
+         } SseConst;
          struct {
             Bool      isLoad;
             HReg      reg;
@@ -560,6 +566,7 @@ extern X86Instr* X86Instr_FpLdStCW  ( Bool isLoad, X86AMode* );
 extern X86Instr* X86Instr_FpStSW_AX ( void );
 extern X86Instr* X86Instr_FpCmp     ( HReg srcL, HReg srcR, HReg dst );
 
+extern X86Instr* X86Instr_SseConst  ( UShort con, HReg dst );
 extern X86Instr* X86Instr_SseLdSt   ( Bool isLoad, HReg, X86AMode* );
 extern X86Instr* X86Instr_Sse128    ( X86SseOp, HReg, HReg );
 extern X86Instr* X86Instr_Sse32Fx4  ( X86SseOp, HReg, HReg );
index 52dd2b8224d6bea4941b694a8c4aeca017fa3df3..1bf834fb21183f72213df8423b8589abcf1fedd5 100644 (file)
@@ -2380,7 +2380,8 @@ static HReg iselVecExpr ( ISelEnv* env, IRExpr* e )
 /* DO NOT CALL THIS DIRECTLY */
 static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
 {
-   IRType ty = typeOfIRExpr(env->type_env,e);
+   X86SseOp op = Xsse_INVALID;
+   IRType   ty = typeOfIRExpr(env->type_env,e);
    vassert(e);
    vassert(ty == Ity_V128);
 
@@ -2399,8 +2400,22 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
       return dst;
    }
 
+   if (e->tag == Iex_LDle) {
+      HReg      dst = newVRegV(env);
+      X86AMode* am  = iselIntExpr_AMode(env, e->Iex.LDle.addr);
+      addInstr(env, X86Instr_SseLdSt( True/*load*/, dst, am ));
+      return dst;
+   }
+
+   if (e->tag == Iex_Const) {
+      HReg dst = newVRegV(env);
+      vassert(e->Iex.Const.con->tag == Ico_V128);
+      addInstr(env, X86Instr_SseConst(e->Iex.Const.con->Ico.V128, dst));
+      return dst;
+   }
+
    if (e->tag == Iex_Binop) {
-      switch (e->Iex.Binop.op) {
+   switch (e->Iex.Binop.op) {
       case Iop_64HLto128: {
          HReg r3, r2, r1, r0;
          X86AMode* esp0  = X86AMode_IR(0, hregX86_ESP());
@@ -2425,22 +2440,53 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
             X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(16), hregX86_ESP()));
          return dst;
       }
-      case Iop_Add32Fx4: {
+
+      case Iop_And128: op = Xsse_AND; goto do_128;
+      case Iop_Xor128: op = Xsse_XOR; goto do_128;
+      do_128: 
+      {
+         HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
+         HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
+         HReg dst = newVRegV(env);
+         addInstr(env, mk_vMOVsd_RR(argL, dst));
+         addInstr(env, X86Instr_Sse128(op, argR, dst));
+         return dst;
+      }
+
+      case Iop_CmpEQ32Fx4: op = Xsse_CMPEQF; goto do_32Fx4;
+      case Iop_CmpLT32Fx4: op = Xsse_CMPLTF; goto do_32Fx4;
+      case Iop_CmpLE32Fx4: op = Xsse_CMPLEF; goto do_32Fx4;
+      case Iop_Add32Fx4:   op = Xsse_ADDF;   goto do_32Fx4;
+      do_32Fx4:
+      {
          HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
          HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
          HReg dst = newVRegV(env);
          addInstr(env, mk_vMOVsd_RR(argL, dst));
-         addInstr(env, X86Instr_Sse32Fx4(Xsse_ADDF, argR, dst));
+         addInstr(env, X86Instr_Sse32Fx4(op, argR, dst));
          return dst;
       }
+
+      case Iop_CmpEQ32F0x4: op = Xsse_CMPEQF; goto do_32F0x4;
+      case Iop_CmpLT32F0x4: op = Xsse_CMPLTF; goto do_32F0x4;
+      case Iop_CmpLE32F0x4: op = Xsse_CMPLEF; goto do_32F0x4;
+      case Iop_Add32F0x4:   op = Xsse_ADDF;   goto do_32F0x4;
+      do_32F0x4: {
+         HReg argL = iselVecExpr(env, e->Iex.Binop.arg1);
+         HReg argR = iselVecExpr(env, e->Iex.Binop.arg2);
+         HReg dst = newVRegV(env);
+         addInstr(env, mk_vMOVsd_RR(argL, dst));
+         addInstr(env, X86Instr_Sse32FLo(op, argR, dst));
+         return dst;
+      }
+
       default:
          break;
-      } /* switch (e->Iex.Binop.op) */
-
+   } /* switch (e->Iex.Binop.op) */
    } /* if (e->tag == Iex_Binop) */
 
    ppIRExpr(e);
-   vpanic("iseVecExpr_wrk");
+   vpanic("iselVecExpr_wrk");
 }
 
 
index 632fc8e236ddf58be1ea1e5f5fa651ada2535d9f..f7503e94c8d5d037db91f084fcffc507c360e37d 100644 (file)
@@ -72,6 +72,7 @@ void ppIRConst ( IRConst* con )
       case Ico_F64:  vex_printf( "F64{0x%llx}",  *(ULong*)(&con->Ico.F64));
                      break;
       case Ico_F64i: vex_printf( "F64i{0x%llx}", con->Ico.F64i); break;
+      case Ico_V128: vex_printf( "V128{0x%04x}", (UInt)(con->Ico.V128)); break;
       default: vpanic("ppIRConst");
    }
 }
@@ -218,7 +219,22 @@ void ppIROp ( IROp op )
       case Iop_ReinterpF64asI64: vex_printf("ReinterpF64asI64"); return;
       case Iop_ReinterpI64asF64: vex_printf("ReinterpI64asF64"); return;
 
-      case Iop_Add32Fx4: vex_printf("Add32Fx4"); 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_CmpEQ32Fx4: vex_printf("CmpEQ32Fx4"); return;
+      case Iop_CmpLT32Fx4: vex_printf("CmpLT32Fx4"); return;
+      case Iop_CmpLE32Fx4: vex_printf("CmpLE32Fx4"); return;
+      case Iop_CmpUN32Fx4: vex_printf("CmpUN32Fx4"); return;
+
+      case Iop_CmpEQ32F0x4: vex_printf("CmpEQ32F0x4"); return;
+      case Iop_CmpLT32F0x4: vex_printf("CmpLT32F0x4"); return;
+      case Iop_CmpLE32F0x4: vex_printf("CmpLE32F0x4"); return;
+      case Iop_CmpUN32F0x4: vex_printf("CmpUN32F0x4"); return;
 
       case Iop_64HLto128: vex_printf("64HLto128"); return;
       case Iop_128to64:   vex_printf("128to64");   return;
@@ -505,7 +521,13 @@ IRConst* IRConst_F64i ( ULong f64i )
    c->Ico.F64i = f64i;
    return c;
 }
-
+IRConst* IRConst_V128 ( UShort con )
+{
+   IRConst* c  = LibVEX_Alloc(sizeof(IRConst));
+   c->tag      = Ico_V128;
+   c->Ico.V128 = con;
+   return c;
+}
 
 /* Constructors -- IRCallee */
 
@@ -805,6 +827,7 @@ IRConst* dopyIRConst ( IRConst* c )
       case Ico_U64:  return IRConst_U64(c->Ico.U64);
       case Ico_F64:  return IRConst_F64(c->Ico.F64);
       case Ico_F64i: return IRConst_F64i(c->Ico.F64i);
+      case Ico_V128: return IRConst_V128(c->Ico.V128);
       default: vpanic("dopyIRConst");
    }
 }
@@ -1070,7 +1093,12 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
       case Iop_128to64: case Iop_128HIto64: 
          UNARY(Ity_I64, Ity_V128);
 
-      case Iop_Add32Fx4:
+      case Iop_CmpEQ32Fx4: case Iop_CmpLT32Fx4:
+      case Iop_CmpLE32Fx4: case Iop_CmpUN32Fx4:
+      case Iop_CmpEQ32F0x4: case Iop_CmpLT32F0x4:
+      case Iop_CmpLE32F0x4: case Iop_CmpUN32F0x4:
+      case Iop_Add32Fx4: case Iop_Add32F0x4:
+      case Iop_And128: case Iop_Or128: case Iop_Xor128:
          BINARY(Ity_V128, Ity_V128,Ity_V128);
 
       default:
@@ -1155,6 +1183,7 @@ IRType typeOfIRConst ( IRConst* con )
       case Ico_U64:   return Ity_I64;
       case Ico_F64:   return Ity_F64;
       case Ico_F64i:  return Ity_F64;
+      case Ico_V128:  return Ity_V128;
       default: vpanic("typeOfIRConst");
    }
 }
index 73be6259a4ea34dcd46d1b517b3c21c58d534f99..627267fb43df0a6667c28f5126756cff1e3e3356 100644 (file)
@@ -72,9 +72,11 @@ typedef
       Ico_U16, 
       Ico_U32, 
       Ico_U64,
-      Ico_F64, /* 64-bit IEEE754 floating */
-      Ico_F64i /* 64-bit unsigned int to be interpreted literally
-                  as a IEEE754 double value. */
+      Ico_F64,   /* 64-bit IEEE754 floating */
+      Ico_F64i,  /* 64-bit unsigned int to be interpreted literally
+                    as a IEEE754 double value. */
+      Ico_V128   /* 128-bit restricted vector constant, with 1 bit for
+                    each of 16 byte lanes */
    }
    IRConstTag;
 
@@ -89,6 +91,7 @@ typedef
          ULong  U64;
          Double F64;
          ULong  F64i;
+         UShort V128;
       } Ico;
    }
    IRConst;
@@ -100,6 +103,7 @@ extern IRConst* IRConst_U32  ( UInt );
 extern IRConst* IRConst_U64  ( ULong );
 extern IRConst* IRConst_F64  ( Double );
 extern IRConst* IRConst_F64i ( ULong );
+extern IRConst* IRConst_V128 ( UShort );
 
 extern IRConst* dopyIRConst ( IRConst* );
 
@@ -318,13 +322,15 @@ typedef
       /* ------------------ 128-bit SIMD. ------------------ */
 
       /* 128-bit ops */
-      Iop_And128, Iop_Or128, Iop_Xor128, Iop_Andn128,
+      Iop_And128, Iop_Or128, Iop_Xor128, 
 
       /* --- 32x4 vector FP --- */
 
       /* binary */
       Iop_Add32Fx4, Iop_Sub32Fx4, Iop_Mul32Fx4, Iop_Div32Fx4, 
       Iop_Max32Fx4, Iop_Min32Fx4,
+      Iop_CmpEQ32Fx4, Iop_CmpLT32Fx4, Iop_CmpLE32Fx4, Iop_CmpUN32Fx4, 
+      Iop_CmpEQ32F0x4, Iop_CmpLT32F0x4, Iop_CmpLE32F0x4, Iop_CmpUN32F0x4, 
 
       /* unary */
       Iop_Recip32Fx4, Iop_Sqrt32Fx4, Iop_RSqrt32Fx4,