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);
);
}
-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 ---*/
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;
+ }
//--
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 {
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");
}
}
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;
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 ) {
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) {
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,
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");
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);
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");
# 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. */
{
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);
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:
# 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 ---*/
/*---------------------------------------------------------------*/
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;
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 */
} FpCmp;
/* Simplistic SSE[123] */
+ struct {
+ UShort con;
+ HReg dst;
+ } SseConst;
struct {
Bool isLoad;
HReg reg;
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 );
/* 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);
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());
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");
}
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");
}
}
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;
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 */
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");
}
}
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:
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");
}
}
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;
ULong U64;
Double F64;
ULong F64i;
+ UShort V128;
} Ico;
}
IRConst;
extern IRConst* IRConst_U64 ( ULong );
extern IRConst* IRConst_F64 ( Double );
extern IRConst* IRConst_F64i ( ULong );
+extern IRConst* IRConst_V128 ( UShort );
extern IRConst* dopyIRConst ( IRConst* );
/* ------------------ 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,