]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Fix a load of confusion with SSE scalar float insns and memory.
authorJulian Seward <jseward@acm.org>
Sun, 5 Dec 2004 15:42:05 +0000 (15:42 +0000)
committerJulian Seward <jseward@acm.org>
Sun, 5 Dec 2004 15:42:05 +0000 (15:42 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@619

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 30c5de5d7c3c3a210ffa3831e51575032ca670dd..e4bc2131c4a6ae00d0ff6e2850aba14de343636e 100644 (file)
@@ -6797,7 +6797,11 @@ void dis_ret ( UInt d32 )
 /*--- SSE/SSE2/SSE3 helpers                                ---*/
 /*------------------------------------------------------------*/
 
-static UInt dis_SSE_E_to_G_wrk ( 
+/* Worker function; do not call directly. 
+   Handles full width G = G `op` E   and   G = (not G) `op` E.
+*/
+
+static UInt dis_SSE_E_to_G_all_wrk ( 
                UChar sorb, UInt delta, 
                HChar* opname, IROp op,
                Bool   invertG
@@ -6832,19 +6836,61 @@ static UInt dis_SSE_E_to_G_wrk (
    }
 }
 
+
+/* All lanes SSE binary operation, G = G `op` E. */
+
 static
-UInt dis_SSE_E_to_G ( UChar sorb, UInt delta, HChar* opname, IROp op )
+UInt dis_SSE_E_to_G_all ( UChar sorb, UInt delta, HChar* opname, IROp op )
 {
-   return dis_SSE_E_to_G_wrk( sorb, delta, opname, op, False );
+   return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, False );
 }
 
+/* All lanes SSE binary operation, G = (not G) `op` E. */
+
 static
-UInt dis_SSE_E_to_G_invG ( UChar sorb, UInt delta, HChar* opname, IROp op )
+UInt dis_SSE_E_to_G_all_invG ( UChar sorb, UInt delta, 
+                               HChar* opname, IROp op )
 {
-   return dis_SSE_E_to_G_wrk( sorb, delta, opname, op, True );
+   return dis_SSE_E_to_G_all_wrk( sorb, delta, opname, op, True );
 }
 
-static UInt dis_SSE_E_to_G_unary ( 
+/* Lowest 32-bit lane only SSE binary operation, G = G `op` E. */
+
+static UInt dis_SSE_E_to_G_lo32 ( UChar sorb, UInt delta, 
+                                  HChar* opname, IROp op )
+{
+   HChar   dis_buf[50];
+   Int     alen;
+   IRTemp  addr;
+   UChar   rm = getIByte(delta);
+   IRExpr* gpart = getXMMReg(gregOfRM(rm));
+   if (epartIsReg(rm)) {
+      putXMMReg( gregOfRM(rm), 
+                 binop(op, gpart,
+                           getXMMReg(eregOfRM(rm))) );
+      DIP("%s %s,%s\n", opname,
+                        nameXMMReg(eregOfRM(rm)),
+                        nameXMMReg(gregOfRM(rm)) );
+      return delta+1;
+   } else {
+      /* We can only do a 32-bit memory read, so the upper 3/4 of the
+         E operand needs to be made simply of zeroes. */
+      IRTemp epart = newTemp(Ity_V128);
+      addr = disAMode ( &alen, sorb, delta, dis_buf );
+      assign( epart, unop( Iop_32Uto128,
+                           loadLE(Ity_I32, mkexpr(addr))) );
+      putXMMReg( gregOfRM(rm), 
+                 binop(op, gpart, mkexpr(epart)) );
+      DIP("%s %s,%s\n", opname,
+                        dis_buf,
+                        nameXMMReg(gregOfRM(rm)) );
+      return delta+alen;
+   }
+}
+
+/* All lanes unary SSE operation, G = op(E). */
+
+static UInt dis_SSE_E_to_G_unary_all ( 
                UChar sorb, UInt delta, 
                HChar* opname, IROp op
             )
@@ -6871,7 +6917,49 @@ static UInt dis_SSE_E_to_G_unary (
    }
 }
 
+/* Lowest 32-bit lane only unary SSE operation, G = op(E). */
 
+static UInt dis_SSE_E_to_G_unary_lo32 ( 
+               UChar sorb, UInt delta, 
+               HChar* opname, IROp op
+            )
+{
+   /* First we need to get the old G value and patch the low 32 bits
+      of the E operand into it.  Then apply op and write back to G. */
+   HChar   dis_buf[50];
+   Int     alen;
+   IRTemp  addr;
+   UChar   rm = getIByte(delta);
+   IRTemp  oldG0 = newTemp(Ity_V128);
+   IRTemp  oldG1 = newTemp(Ity_V128);
+
+   assign( oldG0, getXMMReg(gregOfRM(rm)) );
+
+   if (epartIsReg(rm)) {
+      assign( oldG1, 
+              binop( Iop_Set128lo32,
+                     mkexpr(oldG0),
+                     getXMMRegLane32(0, eregOfRM(rm))) );
+      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
+      DIP("%s %s,%s\n", opname,
+                        nameXMMReg(eregOfRM(rm)),
+                        nameXMMReg(gregOfRM(rm)) );
+      return delta+1;
+   } else {
+      addr = disAMode ( &alen, sorb, delta, dis_buf );
+      assign( oldG1, 
+              binop( Iop_Set128lo32,
+                     mkexpr(oldG0),
+                     loadLE(Ity_I32, mkexpr(addr)) ));
+      putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) );
+      DIP("%s %s,%s\n", opname,
+                        dis_buf,
+                        nameXMMReg(gregOfRM(rm)) );
+      return delta+alen;
+   }
+}
+
+/* Helper for doing SSE 32Fx4 comparisons. */
 
 static void findSSECmpOp ( Bool* needNot, IROp* op, 
                            Int imm8, Bool all_lanes, Int sz )
@@ -6907,6 +6995,8 @@ static void findSSECmpOp ( Bool* needNot, IROp* op,
    vpanic("findSSECmpOp(x86,guest)");
 }
 
+/* Handles SSE 32F comparisons. */
+
 static UInt dis_SSEcmp_E_to_G ( UChar sorb, UInt delta, 
                                HChar* opname, Bool all_lanes, Int sz )
 {
@@ -7095,28 +7185,28 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
    /* 0F 58 = ADDPS -- add 32Fx4 from R/M to R */
    if (insn[0] == 0x0F && insn[1] == 0x58) {
       vassert(sz == 4);
-      delta = dis_SSE_E_to_G( sorb, delta+2, "addps", Iop_Add32Fx4 );
+      delta = dis_SSE_E_to_G_all( sorb, delta+2, "addps", Iop_Add32Fx4 );
       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 );
+      delta = dis_SSE_E_to_G_lo32( 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 );
+      delta = dis_SSE_E_to_G_all_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 );
+      delta = dis_SSE_E_to_G_all( sorb, delta+2, "andps", Iop_And128 );
       goto decode_success;
    }
 
@@ -7345,42 +7435,42 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
    /* 0F 5E = DIVPS -- div 32Fx4 from R/M to R */
    if (insn[0] == 0x0F && insn[1] == 0x5E) {
       vassert(sz == 4);
-      delta = dis_SSE_E_to_G( sorb, delta+2, "divps", Iop_Div32Fx4 );
+      delta = dis_SSE_E_to_G_all( sorb, delta+2, "divps", Iop_Div32Fx4 );
       goto decode_success;
    }
 
    /* F3 0F 5E = DIVSS -- div 32F0x4 from R/M to R */
    if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5E) {
       vassert(sz == 4);
-      delta = dis_SSE_E_to_G( sorb, delta+3, "divss", Iop_Div32F0x4 );
+      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "divss", Iop_Div32F0x4 );
       goto decode_success;
    }
 
    /* 0F 5F = MAXPS -- max 32Fx4 from R/M to R */
    if (insn[0] == 0x0F && insn[1] == 0x5F) {
       vassert(sz == 4);
-      delta = dis_SSE_E_to_G( sorb, delta+2, "maxps", Iop_Max32Fx4 );
+      delta = dis_SSE_E_to_G_all( sorb, delta+2, "maxps", Iop_Max32Fx4 );
       goto decode_success;
    }
 
    /* F3 0F 5F = MAXSS -- max 32F0x4 from R/M to R */
    if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5F) {
       vassert(sz == 4);
-      delta = dis_SSE_E_to_G( sorb, delta+3, "maxss", Iop_Max32F0x4 );
+      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "maxss", Iop_Max32F0x4 );
       goto decode_success;
    }
 
    /* 0F 5D = MINPS -- min 32Fx4 from R/M to R */
    if (insn[0] == 0x0F && insn[1] == 0x5D) {
       vassert(sz == 4);
-      delta = dis_SSE_E_to_G( sorb, delta+2, "minps", Iop_Min32Fx4 );
+      delta = dis_SSE_E_to_G_all( sorb, delta+2, "minps", Iop_Min32Fx4 );
       goto decode_success;
    }
 
    /* F3 0F 5D = MINSS -- min 32F0x4 from R/M to R */
    if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5D) {
       vassert(sz == 4);
-      delta = dis_SSE_E_to_G( sorb, delta+3, "minss", Iop_Min32F0x4 );
+      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "minss", Iop_Min32F0x4 );
       goto decode_success;
    }
 
@@ -7494,31 +7584,34 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
       t2 = newTemp(Ity_I32);
       t3 = newTemp(Ity_I32);
       Int src;
-      vassert(sz == 4);
       modrm = getIByte(delta+2);
-      delta += 2+1;
-      src = eregOfRM(modrm);
-      assign( t0, binop( Iop_And32,
-                         binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
-                         mkU32(1) ));
-      assign( t1, binop( Iop_And32,
-                         binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
-                         mkU32(2) ));
-      assign( t2, binop( Iop_And32,
-                         binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
-                         mkU32(4) ));
-      assign( t3, binop( Iop_And32,
-                         binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
-                         mkU32(8) ));
-      putIReg(4, gregOfRM(modrm),
-                 binop(Iop_Or32,
-                       binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
-                       binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
-                      )
-              );
-      DIP("movmskps %s,%s\n", nameXMMReg(src), 
-                              nameIReg(4, gregOfRM(modrm)));
-      goto decode_success;
+      if (epartIsReg(modrm)) {
+         vassert(sz == 4);
+         delta += 2+1;
+         src = eregOfRM(modrm);
+         assign( t0, binop( Iop_And32,
+                            binop(Iop_Shr32, getXMMRegLane32(src,0), mkU8(31)),
+                            mkU32(1) ));
+         assign( t1, binop( Iop_And32,
+                            binop(Iop_Shr32, getXMMRegLane32(src,1), mkU8(30)),
+                            mkU32(2) ));
+         assign( t2, binop( Iop_And32,
+                            binop(Iop_Shr32, getXMMRegLane32(src,2), mkU8(29)),
+                            mkU32(4) ));
+         assign( t3, binop( Iop_And32,
+                            binop(Iop_Shr32, getXMMRegLane32(src,3), mkU8(28)),
+                            mkU32(8) ));
+         putIReg(4, gregOfRM(modrm),
+                    binop(Iop_Or32,
+                          binop(Iop_Or32, mkexpr(t0), mkexpr(t1)),
+                          binop(Iop_Or32, mkexpr(t2), mkexpr(t3))
+                         )
+                 );
+         DIP("movmskps %s,%s\n", nameXMMReg(src), 
+                                 nameIReg(4, gregOfRM(modrm)));
+         goto decode_success;
+      }
+      /* else fall through */
    }
 
    /* 0F 2B = MOVNTPS -- for us, just a plain SSE store. */
@@ -7597,21 +7690,21 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
    /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */
    if (insn[0] == 0x0F && insn[1] == 0x59) {
       vassert(sz == 4);
-      delta = dis_SSE_E_to_G( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
+      delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 );
       goto decode_success;
    }
 
    /* F3 0F 59 = MULSS -- mul 32F0x4 from R/M to R */
    if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x59) {
       vassert(sz == 4);
-      delta = dis_SSE_E_to_G( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
+      delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "mulss", Iop_Mul32F0x4 );
       goto decode_success;
    }
 
    /* 0F 56 = ORPS -- G = G and E */
    if (insn[0] == 0x0F && insn[1] == 0x56) {
       vassert(sz == 4);
-      delta = dis_SSE_E_to_G( sorb, delta+2, "orps", Iop_Or128 );
+      delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_Or128 );
       goto decode_success;
    }
 
@@ -7885,16 +7978,16 @@ static DisResult disInstr ( /*IN*/  Bool    resteerOK,
    /* 0F 53 = RCPPS -- approx reciprocal 32Fx4 from R/M to R */
    if (insn[0] == 0x0F && insn[1] == 0x53) {
       vassert(sz == 4);
-      delta = dis_SSE_E_to_G_unary( sorb, delta+2, 
-                                    "rcpps", Iop_Recip32Fx4 );
+      delta = dis_SSE_E_to_G_unary_all( sorb, delta+2, 
+                                        "rcpps", Iop_Recip32Fx4 );
       goto decode_success;
    }
 
    /* F3 0F 53 = RCPSS -- approx reciprocal 32F0x4 from R/M to R */
    if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x53) {
       vassert(sz == 4);
-      delta = dis_SSE_E_to_G_unary( sorb, delta+3, 
-                                    "rcpss", Iop_Recip32F0x4 );
+      delta = dis_SSE_E_to_G_unary_lo32( sorb, delta+3, 
+                                         "rcpss", Iop_Recip32F0x4 );
       goto decode_success;
    }
 
index 78f2956f24542b327969015597fc5ed108ed7001..f4a5cb23d60d147197204ac18140a73e29f448bd 100644 (file)
@@ -743,6 +743,16 @@ X86Instr* X86Instr_SseLdSt ( Bool isLoad, HReg reg, X86AMode* addr ) {
    i->Xin.SseLdSt.addr   = addr;
    return i;
 }
+X86Instr* X86Instr_SseLdzLO  ( Int sz, HReg reg, X86AMode* addr )
+{
+   X86Instr* i           = LibVEX_Alloc(sizeof(X86Instr));
+   i->tag                = Xin_SseLdzLO;
+   i->Xin.SseLdzLO.sz    = sz;
+   i->Xin.SseLdzLO.reg   = reg;
+   i->Xin.SseLdzLO.addr  = addr;
+   vassert(sz == 4 || sz == 8);
+   return i;
+}
 X86Instr* X86Instr_Sse128 ( X86SseOp op, HReg src, HReg dst ) {
    X86Instr* i       = LibVEX_Alloc(sizeof(X86Instr));
    i->tag            = Xin_Sse128;
@@ -967,6 +977,12 @@ void ppX86Instr ( X86Instr* i ) {
             ppX86AMode(i->Xin.SseLdSt.addr);
          }
          return;
+      case Xin_SseLdzLO:
+         vex_printf("movs%s ", i->Xin.SseLdzLO.sz==4 ? "s" : "d");
+         ppX86AMode(i->Xin.SseLdzLO.addr);
+         vex_printf(",");
+         ppHRegX86(i->Xin.SseLdzLO.reg);
+         return;
       case Xin_Sse128:
          if (i->Xin.Sse128.op == Xsse_MOV) {
             vex_printf("mov ");
@@ -1150,6 +1166,10 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i)
          addHRegUse(u, i->Xin.SseLdSt.isLoad ? HRmWrite : HRmRead,
                        i->Xin.SseLdSt.reg);
          return;
+      case Xin_SseLdzLO:
+         addRegUsage_X86AMode(u, i->Xin.SseLdzLO.addr);
+         addHRegUse(u, HRmWrite, i->Xin.SseLdzLO.reg);
+         return;
       case Xin_SseConst:
          addHRegUse(u, HRmWrite, i->Xin.SseConst.dst);
          return;
@@ -1284,6 +1304,10 @@ void mapRegs_X86Instr (HRegRemap* m, X86Instr* i)
          mapReg(m, &i->Xin.SseLdSt.reg);
          mapRegs_X86AMode(m, i->Xin.SseLdSt.addr);
          break;
+      case Xin_SseLdzLO:
+         mapReg(m, &i->Xin.SseLdzLO.reg);
+         mapRegs_X86AMode(m, i->Xin.SseLdzLO.addr);
+         break;
       case Xin_Sse128:
          mapReg(m, &i->Xin.Sse128.src);
          mapReg(m, &i->Xin.Sse128.dst);
@@ -2389,18 +2413,32 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
       *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_SseLdzLO:
+      if (i->Xin.SseLdzLO.sz == 4) {
+         /* movss amode, %xmm-dst */
+         *p++ = 0xF3; 
+         *p++ = 0x0F; 
+         *p++ = 0x10; 
+         p = doAMode_M(p, fake(vregNo(i->Xin.SseLdzLO.reg)), 
+                          i->Xin.SseLdzLO.addr);
+         goto done;
+      }
+      break;
+
    case Xin_Sse128:
       *p++ = 0x0F;
       switch (i->Xin.Sse128.op) {
          case Xsse_OR:  *p++ = 0x56; break;
          case Xsse_XOR: *p++ = 0x57; break;
          case Xsse_AND: *p++ = 0x54; break;
+         case Xsse_MOV: *p++ = 0x10; break;
          default: goto bad;
       }
       p = doAMode_R(p, fake(vregNo(i->Xin.Sse128.dst)),
index 7e478997141e7cd8a81e637ad8a1eccc9194c83f..1a3aa36bcb04e5cc380658f402a88c9f67fda6ac 100644 (file)
@@ -350,6 +350,7 @@ typedef
 
       Xin_SseConst,  /* Generate restricted SSE literal */
       Xin_SseLdSt,   /* SSE load/store, no alignment constraints */
+      Xin_SseLdzLO,  /* SSE load low 32/64 bits, zero remainder of reg */
       Xin_Sse128,    /* SSE binary typeless (and/or/xor/andn) */
       Xin_Sse32Fx4,  /* SSE binary, 32Fx4 */
       Xin_Sse32FLo   /* SSE binary, 32F in lowest lane only */
@@ -530,6 +531,11 @@ typedef
             HReg      reg;
             X86AMode* addr;
          } SseLdSt;
+         struct {
+            Int       sz; /* 4 or 8 only */
+            HReg      reg;
+            X86AMode* addr;
+         } SseLdzLO;
          struct {
             X86SseOp op;  /* MOV/AND/OR/XOR/ANDN only */
             HReg     src;
@@ -580,6 +586,7 @@ 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_SseLdzLO  ( Int sz, HReg, X86AMode* );
 extern X86Instr* X86Instr_Sse128    ( X86SseOp, HReg, HReg );
 extern X86Instr* X86Instr_Sse32Fx4  ( X86SseOp, HReg, HReg );
 extern X86Instr* X86Instr_Sse32FLo  ( X86SseOp, HReg, HReg );
index 3b33caf0e0f5a073df2e4a91390f6a5136b22fe4..baeb7a23419a1d199768e67e57b738662bb0b015 100644 (file)
@@ -327,6 +327,22 @@ static X86Instr* mk_vMOVsd_RR ( HReg src, HReg dst )
    return X86Instr_Sse128(Xsse_MOV, src, dst);
 }
 
+/* Advance/retreat %esp by n. */
+
+static void move_esp_up ( ISelEnv* env, Int n )
+{
+   vassert(n > 0 && n < 256 && (n%4) == 0);
+   addInstr(env, 
+            X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(n), hregX86_ESP()));
+}
+
+static void move_esp_down ( ISelEnv* env, Int n )
+{
+   vassert(n > 0 && n < 256 && (n%4) == 0);
+   addInstr(env, 
+            X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(n), hregX86_ESP()));
+}
+
 
 /* Given an amode, return one which references 4 bytes further
    along. */
@@ -2441,12 +2457,29 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
       case Iop_Recip32F0x4: op = Xsse_RCPF; goto do_32F0x4_unary;
       do_32F0x4_unary:
       {
+         /* A bit subtle.  We have to copy the arg to the result
+            register first, because actually doing the SSE scalar insn
+            leaves the upper 3/4 of the destination register
+            unchanged.  Whereas the required semantics of these
+            primops is that the upper 3/4 is simply copied in from the
+            argument. */
          HReg arg = iselVecExpr(env, e->Iex.Unop.arg);
          HReg dst = newVRegV(env);
+         addInstr(env, mk_vMOVsd_RR(arg, dst));
          addInstr(env, X86Instr_Sse32FLo(op, arg, dst));
          return dst;
       }
 
+      case Iop_32Uto128: {
+         HReg      dst  = newVRegV(env);
+         X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
+         X86RMI*   rmi  = iselIntExpr_RMI(env, e->Iex.Unop.arg);
+         addInstr(env, X86Instr_Push(rmi));
+        addInstr(env, X86Instr_SseLdzLO(4, dst, esp0));
+         move_esp_up(env, 4);
+         return dst;
+      }
+
       default:
          break;
    } /* switch (e->Iex.Unop.op) */
@@ -2454,6 +2487,20 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
 
    if (e->tag == Iex_Binop) {
    switch (e->Iex.Binop.op) {
+
+      case Iop_Set128lo32: {
+         HReg dst = newVRegV(env);
+         HReg srcV = iselVecExpr(env, e->Iex.Binop.arg1);
+         HReg srcI = iselIntExpr_R(env, e->Iex.Binop.arg2);
+         X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP());
+         move_esp_down(env, 16);
+         addInstr(env, X86Instr_SseLdSt(False/*store*/, srcV, esp0));
+         addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(srcI), esp0));
+         addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0));
+         move_esp_up(env, 16);
+         return dst;
+      }
+
       case Iop_64HLto128: {
          HReg r3, r2, r1, r0;
          X86AMode* esp0  = X86AMode_IR(0, hregX86_ESP());
@@ -2462,8 +2509,7 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
          X86AMode* esp12 = advance4(esp8);
          HReg dst = newVRegV(env);
         /* do this via the stack (easy, convenient, etc) */
-         addInstr(env, 
-            X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(16), hregX86_ESP()));
+         move_esp_down(env, 16);
          /* Do the less significant 64 bits */
          iselInt64Expr(&r1, &r0, env, e->Iex.Binop.arg2);
          addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r0), esp0));
@@ -2474,8 +2520,7 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e )
          addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(r3), esp12));
         /* Fetch result back from stack. */
          addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0));
-         addInstr(env, 
-            X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(16), hregX86_ESP()));
+         move_esp_up(env, 16);
          return dst;
       }
 
index 8e7f5fbc3906dfd256fa02fc0e453ee8e6c8ca6f..e1749f53e986180af6a841a25f48b0d122ffa5c0 100644 (file)
@@ -257,6 +257,9 @@ void ppIROp ( IROp op )
       case Iop_128to64:   vex_printf("128to64");   return;
       case Iop_128HIto64: vex_printf("128HIto64"); return;
 
+      case Iop_32Uto128:   vex_printf("32Uto128"); return;
+      case Iop_Set128lo32: vex_printf("Set128lo32"); return;
+
       default: vpanic("ppIROp(1)");
    }
   
@@ -1113,6 +1116,9 @@ 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_32Uto128:   UNARY(Ity_V128, Ity_I32);
+      case Iop_Set128lo32: BINARY(Ity_V128, Ity_V128,Ity_I32);
+
       case Iop_CmpEQ32Fx4: case Iop_CmpLT32Fx4:
       case Iop_CmpLE32Fx4: case Iop_CmpUN32Fx4:
       case Iop_CmpEQ32F0x4: case Iop_CmpLT32F0x4:
index 0ff7bb286cba14fe0b7d62c3ba5f20e2515198a8..581ecbcd5934914e123607b39d8f014915af450c 100644 (file)
@@ -365,11 +365,13 @@ typedef
       Iop_128HIto64,   // :: V128 -> I64, high half
       Iop_64HLto128,   // :: (I64,I64) -> V128
 
+      Iop_32Uto128,
+      Iop_Set128lo32,
       /* 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
+      //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
    }
    IROp;