From: Julian Seward Date: Thu, 2 Dec 2004 16:16:11 +0000 (+0000) Subject: x86 guest/host: do SSE comparisons. X-Git-Tag: svn/VALGRIND_3_0_1^2~729 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5c6c0cc4b064daa66dda3cd2e7350abe7ca45b27;p=thirdparty%2Fvalgrind.git x86 guest/host: do SSE comparisons. 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 --- diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 409cc24f33..4668a21bd1 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -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; + } //-- diff --git a/VEX/priv/host-generic/h_generic_regs.h b/VEX/priv/host-generic/h_generic_regs.h index 3ea1b73cf5..8208e82047 100644 --- a/VEX/priv/host-generic/h_generic_regs.h +++ b/VEX/priv/host-generic/h_generic_regs.h @@ -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 { diff --git a/VEX/priv/host-x86/hdefs.c b/VEX/priv/host-x86/hdefs.c index 834b638131..21fecf0942 100644 --- a/VEX/priv/host-x86/hdefs.c +++ b/VEX/priv/host-x86/hdefs.c @@ -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 ---*/ /*---------------------------------------------------------------*/ diff --git a/VEX/priv/host-x86/hdefs.h b/VEX/priv/host-x86/hdefs.h index 7aaa6a0613..ef6f6e0dd2 100644 --- a/VEX/priv/host-x86/hdefs.h +++ b/VEX/priv/host-x86/hdefs.h @@ -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 ); diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index 52dd2b8224..1bf834fb21 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -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"); } diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index 632fc8e236..f7503e94c8 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -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"); } } diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 73be6259a4..627267fb43 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -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,