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