From: Julian Seward Date: Thu, 9 Dec 2004 23:25:14 +0000 (+0000) Subject: x86 host/guest: SSE2 integer shifts and subtracts X-Git-Tag: svn/VALGRIND_3_0_1^2~695 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=e5119dcd20bb2df3121ae643d0aec9e737d80d9b;p=thirdparty%2Fvalgrind.git x86 host/guest: SSE2 integer shifts and subtracts git-svn-id: svn://svn.valgrind.org/vex/trunk@639 --- diff --git a/VEX/priv/guest-x86/gdefs.h b/VEX/priv/guest-x86/gdefs.h index 19fd1a3ef9..298e6539b1 100644 --- a/VEX/priv/guest-x86/gdefs.h +++ b/VEX/priv/guest-x86/gdefs.h @@ -116,6 +116,7 @@ extern ULong x86g_calculate_qadd8Sx8 ( ULong, ULong ); extern ULong x86g_calculate_qadd16Ux4 ( ULong, ULong ); extern ULong x86g_calculate_qadd8Ux8 ( ULong, ULong ); +extern ULong x86g_calculate_sub64x1 ( ULong, ULong ); extern ULong x86g_calculate_sub32x2 ( ULong, ULong ); extern ULong x86g_calculate_sub16x4 ( ULong, ULong ); extern ULong x86g_calculate_sub8x8 ( ULong, ULong ); diff --git a/VEX/priv/guest-x86/ghelpers.c b/VEX/priv/guest-x86/ghelpers.c index e241d08718..5b2140025c 100644 --- a/VEX/priv/guest-x86/ghelpers.c +++ b/VEX/priv/guest-x86/ghelpers.c @@ -2185,6 +2185,12 @@ ULong x86g_calculate_qadd8Ux8 ( ULong xx, ULong yy ) /* ------------ Normal subtraction ------------ */ +ULong x86g_calculate_sub64x1 ( ULong xx, ULong yy ) +{ + /* should really be done in-line */ + return xx - yy; +} + ULong x86g_calculate_sub32x2 ( ULong xx, ULong yy ) { return mk32x2( diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index c7278e28af..be26775793 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -5100,6 +5100,7 @@ UInt dis_MMXop_regmem_to_reg ( UChar sorb, /* Introduced in SSE2 */ case 0xD4: XXX(x86g_calculate_add64x1); break; + case 0xFB: XXX(x86g_calculate_sub64x1); break; default: vex_printf("\n0x%x\n", (Int)opc); @@ -6648,6 +6649,135 @@ static UInt dis_SSEcmp_E_to_G ( UChar sorb, UInt delta, return delta; } + +/* Vector by scalar shift of G by the amount specified at the bottom + of E. */ + +static UInt dis_SSE_shiftG_byE ( UChar sorb, UInt delta, + HChar* opname, IROp op ) +{ + HChar dis_buf[50]; + Int alen, size; + IRTemp addr; + Bool shl, shr, sar; + UChar rm = getIByte(delta); + IRTemp g0 = newTemp(Ity_V128); + IRTemp g1 = newTemp(Ity_V128); + IRTemp amt = newTemp(Ity_I32); + IRTemp amt8 = newTemp(Ity_I8); + if (epartIsReg(rm)) { + assign( amt, getXMMRegLane32(eregOfRM(rm), 0) ); + DIP("%s %s,%s\n", opname, + nameXMMReg(eregOfRM(rm)), + nameXMMReg(gregOfRM(rm)) ); + delta++; + } else { + addr = disAMode ( &alen, sorb, delta, dis_buf ); + assign( amt, loadLE(Ity_I32, mkexpr(addr)) ); + DIP("%s %s,%s\n", opname, + dis_buf, + nameXMMReg(gregOfRM(rm)) ); + delta += alen; + } + assign( g0, getXMMReg(gregOfRM(rm)) ); + assign( amt8, unop(Iop_32to8, mkexpr(amt)) ); + + shl = shr = sar = False; + size = 0; + switch (op) { + case Iop_ShlN16x8: shl = True; size = 32; break; + case Iop_ShlN32x4: shl = True; size = 32; break; + case Iop_ShlN64x2: shl = True; size = 64; break; + case Iop_SarN16x8: sar = True; size = 16; break; + case Iop_SarN32x4: sar = True; size = 32; break; + case Iop_ShrN16x8: shr = True; size = 16; break; + case Iop_ShrN32x4: shr = True; size = 32; break; + case Iop_ShrN64x2: shr = True; size = 64; break; + default: vassert(0); + } + + if (shl || shr) { + assign( + g1, + IRExpr_Mux0X( + unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))), + mkV128(0x0000), + binop(op, mkexpr(g0), mkexpr(amt8)) + ) + ); + } else + if (sar) { + assign( + g1, + IRExpr_Mux0X( + unop(Iop_1Uto8,binop(Iop_CmpLT32U,mkexpr(amt),mkU32(size))), + binop(op, mkexpr(g0), mkU8(size-1)), + binop(op, mkexpr(g0), mkexpr(amt8)) + ) + ); + } else { + vassert(0); + } + + putXMMReg( gregOfRM(rm), mkexpr(g1) ); + return delta; +} + + +/* Vector by scalar shift of E by an immediate byte. */ + +static UInt dis_SSE_shiftE_imm ( UChar sorb, UInt delta, + HChar* opname, IROp op ) +{ + Bool shl, shr, sar; + UChar rm = getIByte(delta); + IRTemp g0 = newTemp(Ity_V128); + IRTemp g1 = newTemp(Ity_V128); + UChar amt, size; + vassert(epartIsReg(rm)); + vassert(gregOfRM(rm) == 2 + || gregOfRM(rm) == 4 || gregOfRM(rm) == 6); + amt = (Int)(getIByte(delta+1)); + delta += 2; + DIP("%s $%d,%s\n", opname, + (Int)amt, + nameXMMReg(eregOfRM(rm)) ); + assign( g0, getXMMReg(eregOfRM(rm)) ); + + shl = shr = sar = False; + size = 0; + switch (op) { + case Iop_ShlN16x8: shl = True; size = 16; break; + case Iop_ShlN32x4: shl = True; size = 32; break; + case Iop_ShlN64x2: shl = True; size = 64; break; + case Iop_SarN16x8: sar = True; size = 16; break; + case Iop_SarN32x4: sar = True; size = 32; break; + case Iop_ShrN16x8: shr = True; size = 16; break; + case Iop_ShrN32x4: shr = True; size = 32; break; + case Iop_ShrN64x2: shr = True; size = 64; break; + default: vassert(0); + } + + if (shl || shr) { + assign( g1, amt >= size + ? mkV128(0x0000) + : binop(op, mkexpr(g0), mkU8(amt)) + ); + } else + if (sar) { + assign( g1, amt >= size + ? binop(op, mkexpr(g0), mkU8(size-1)) + : binop(op, mkexpr(g0), mkU8(amt)) + ); + } else { + vassert(0); + } + + putXMMReg( eregOfRM(rm), mkexpr(g1) ); + return delta; +} + + /* Get the current SSE rounding mode. */ static IRExpr* /* :: Ity_I32 */ get_sse_roundingmode ( void ) @@ -6702,6 +6832,45 @@ static IRExpr* mk128from32s ( IRTemp t3, IRTemp t2, ); } +/* Break a 64-bit value up into four 16-bit ints. */ + +static void breakup64to16s ( IRTemp t64, + /*OUTs*/ + IRTemp* t3, IRTemp* t2, + IRTemp* t1, IRTemp* t0 ) +{ + IRTemp hi32 = newTemp(Ity_I32); + IRTemp lo32 = newTemp(Ity_I32); + assign( hi32, unop(Iop_64HIto32, mkexpr(t64)) ); + assign( lo32, unop(Iop_64to32, mkexpr(t64)) ); + + vassert(t0 && *t0 == IRTemp_INVALID); + vassert(t1 && *t1 == IRTemp_INVALID); + vassert(t2 && *t2 == IRTemp_INVALID); + vassert(t3 && *t3 == IRTemp_INVALID); + + *t0 = newTemp(Ity_I16); + *t1 = newTemp(Ity_I16); + *t2 = newTemp(Ity_I16); + *t3 = newTemp(Ity_I16); + assign( *t0, unop(Iop_32to16, mkexpr(lo32)) ); + assign( *t1, unop(Iop_32HIto16, mkexpr(lo32)) ); + assign( *t2, unop(Iop_32to16, mkexpr(hi32)) ); + assign( *t3, unop(Iop_32HIto16, mkexpr(hi32)) ); +} + +/* Construct a 64-bit value from four 16-bit ints. */ + +static IRExpr* mk64from16s ( IRTemp t3, IRTemp t2, + IRTemp t1, IRTemp t0 ) +{ + return + binop( Iop_32HLto64, + binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)), + binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0)) + ); +} + /*------------------------------------------------------------*/ /*--- Disassemble a single instruction ---*/ @@ -7414,27 +7583,19 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, if (insn[0] == 0x0F && insn[1] == 0xC5) { modrm = insn[2]; if (sz == 4 && epartIsReg(modrm)) { + IRTemp sV = newTemp(Ity_I64); + t5 = newTemp(Ity_I16); do_MMX_preamble(); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I16); - assign(t0, getMMXReg(eregOfRM(modrm))); + assign(sV, getMMXReg(eregOfRM(modrm))); + breakup64to16s( sV, &t3, &t2, &t1, &t0 ); switch (insn[3] & 3) { - case 0: - assign(t1, unop(Iop_32to16, - unop(Iop_64to32, mkexpr(t0)))); break; - case 1: - assign(t1, unop(Iop_32HIto16, - unop(Iop_64to32, mkexpr(t0)))); break; - case 2: - assign(t1, unop(Iop_32to16, - unop(Iop_64HIto32, mkexpr(t0)))); break; - case 3: - assign(t1, unop(Iop_32HIto16, - unop(Iop_64HIto32, mkexpr(t0)))); break; - default: - vassert(0); + case 0: assign(t5, mkexpr(t0)); break; + case 1: assign(t5, mkexpr(t1)); break; + case 2: assign(t5, mkexpr(t2)); break; + case 3: assign(t5, mkexpr(t3)); break; + default: vassert(0); } - putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t1))); + putIReg(4, gregOfRM(modrm), unop(Iop_16Uto32, mkexpr(t5))); DIP("pextrw $%d,%s,%s\n", (Int)insn[3], nameMMXReg(eregOfRM(modrm)), nameIReg(4,gregOfRM(modrm))); @@ -7452,10 +7613,6 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, mmx reg. t4 is the new lane value. t5 is the original mmx value. t6 is the new mmx value. */ Int lane; - t0 = newTemp(Ity_I16); - t1 = newTemp(Ity_I16); - t2 = newTemp(Ity_I16); - t3 = newTemp(Ity_I16); t4 = newTemp(Ity_I16); t5 = newTemp(Ity_I64); t6 = newTemp(Ity_I64); @@ -7463,11 +7620,7 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, do_MMX_preamble(); assign(t5, getMMXReg(gregOfRM(modrm))); - - assign(t0, unop(Iop_32to16, unop(Iop_64to32, mkexpr(t5)))); - assign(t1, unop(Iop_32HIto16, unop(Iop_64to32, mkexpr(t5)))); - assign(t2, unop(Iop_32to16, unop(Iop_64HIto32, mkexpr(t5)))); - assign(t3, unop(Iop_32HIto16, unop(Iop_64HIto32, mkexpr(t5)))); + breakup64to16s( t5, &t3, &t2, &t1, &t0 ); if (epartIsReg(modrm)) { assign(t4, getIReg(2, eregOfRM(modrm))); @@ -7482,36 +7635,11 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, } switch (lane & 3) { - case 0: - assign(t6, binop(Iop_32HLto64, - binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)), - binop(Iop_16HLto32, mkexpr(t1), mkexpr(t4)) - ) - ); - break; - case 1: - assign(t6, binop(Iop_32HLto64, - binop(Iop_16HLto32, mkexpr(t3), mkexpr(t2)), - binop(Iop_16HLto32, mkexpr(t4), mkexpr(t0)) - ) - ); - break; - case 2: - assign(t6, binop(Iop_32HLto64, - binop(Iop_16HLto32, mkexpr(t3), mkexpr(t4)), - binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0)) - ) - ); - break; - case 3: - assign(t6, binop(Iop_32HLto64, - binop(Iop_16HLto32, mkexpr(t4), mkexpr(t2)), - binop(Iop_16HLto32, mkexpr(t1), mkexpr(t0)) - ) - ); - break; - default: - vassert(0); + case 0: assign(t6, mk64from16s(t3,t2,t1,t4)); break; + case 1: assign(t6, mk64from16s(t3,t2,t4,t0)); break; + case 2: assign(t6, mk64from16s(t3,t4,t1,t0)); break; + case 3: assign(t6, mk64from16s(t4,t2,t1,t0)); break; + default: vassert(0); } putMMXReg(gregOfRM(modrm), mkexpr(t6)); goto decode_success; @@ -7626,15 +7754,16 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, /* ***--- this is an MMX class insn introduced in SSE1 ---*** */ /* 0F 70 = PSHUFW -- rearrange 4x16 from E(mmx or mem) to G(mmx) */ - if (insn[0] == 0x0F && insn[1] == 0x70) { + if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x70) { Int order; - vassert(sz == 4); - t0 = newTemp(Ity_I64); - t1 = newTemp(Ity_I64); + IRTemp sV, dV, s3, s2, s1, s0; + s3 = s2 = s1 = s0 = IRTemp_INVALID; + sV = newTemp(Ity_I64); + dV = newTemp(Ity_I64); do_MMX_preamble(); modrm = insn[2]; if (epartIsReg(modrm)) { - assign( t0, getMMXReg(eregOfRM(modrm)) ); + assign( sV, getMMXReg(eregOfRM(modrm)) ); order = (Int)insn[3]; delta += 2+2; DIP("pshufw $%d,%s,%s\n", order, @@ -7642,34 +7771,23 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, nameMMXReg(gregOfRM(modrm))); } else { addr = disAMode ( &alen, sorb, delta+2, dis_buf ); - assign( t0, loadLE(Ity_I64, mkexpr(addr)) ); + assign( sV, loadLE(Ity_I64, mkexpr(addr)) ); order = (Int)insn[2+alen]; delta += 3+alen; DIP("pshufw $%d,%s,%s\n", order, dis_buf, nameMMXReg(gregOfRM(modrm))); } + breakup64to16s( sV, &s3, &s2, &s1, &s0 ); -# define WORD0 unop(Iop_32to16,unop(Iop_64to32,mkexpr(t0))) -# define WORD1 unop(Iop_32HIto16,unop(Iop_64to32,mkexpr(t0))) -# define WORD2 unop(Iop_32to16,unop(Iop_64HIto32,mkexpr(t0))) -# define WORD3 unop(Iop_32HIto16,unop(Iop_64HIto32,mkexpr(t0))) -# define SEL(n) ((n)==0 ? WORD0 \ - : ((n)==1 ? WORD1 \ - : ((n)==2 ? WORD2 : WORD3))) - assign(t1, - binop(Iop_32HLto64, - binop(Iop_16HLto32,SEL((order>>6)&3),SEL((order>>4)&3)), - binop(Iop_16HLto32,SEL((order>>2)&3),SEL((order>>0)&3)) - ) +# define SEL(n) \ + ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3))) + assign(dV, + mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3), + SEL((order>>2)&3), SEL((order>>0)&3) ) ); - putMMXReg(gregOfRM(modrm), mkexpr(t1)); - + putMMXReg(gregOfRM(modrm), mkexpr(dV)); # undef SEL -# undef WORD0 -# undef WORD1 -# undef WORD2 -# undef WORD3 goto decode_success; } @@ -9353,6 +9471,318 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, goto decode_success; } + /* 66 0F 70 = PSHUFD -- rearrange 4x32 from E(xmm or mem) to G(xmm) */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x70) { + Int order; + IRTemp sV, dV, s3, s2, s1, s0; + s3 = s2 = s1 = s0 = IRTemp_INVALID; + sV = newTemp(Ity_V128); + dV = newTemp(Ity_V128); + modrm = insn[2]; + if (epartIsReg(modrm)) { + assign( sV, getXMMReg(eregOfRM(modrm)) ); + order = (Int)insn[3]; + delta += 2+2; + DIP("pshufd $%d,%s,%s\n", order, + nameXMMReg(eregOfRM(modrm)), + nameXMMReg(gregOfRM(modrm))); + } else { + addr = disAMode ( &alen, sorb, delta+2, dis_buf ); + assign( sV, loadLE(Ity_V128, mkexpr(addr)) ); + order = (Int)insn[2+alen]; + delta += 3+alen; + DIP("pshufd $%d,%s,%s\n", order, + dis_buf, + nameXMMReg(gregOfRM(modrm))); + } + breakup128to32s( sV, &s3, &s2, &s1, &s0 ); + +# define SEL(n) \ + ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3))) + assign(dV, + mk128from32s( SEL((order>>6)&3), SEL((order>>4)&3), + SEL((order>>2)&3), SEL((order>>0)&3) ) + ); + putXMMReg(gregOfRM(modrm), mkexpr(dV)); +# undef SEL + goto decode_success; + } + + /* F3 0F 70 = PSHUFHW -- rearrange upper half 4x16 from E(xmm or + mem) to G(xmm), and copy lower half */ + if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x70) { + Int order; + IRTemp sVhi, dVhi, sV, dV, s3, s2, s1, s0; + s3 = s2 = s1 = s0 = IRTemp_INVALID; + sV = newTemp(Ity_V128); + dV = newTemp(Ity_V128); + sVhi = newTemp(Ity_I64); + dVhi = newTemp(Ity_I64); + modrm = insn[3]; + if (epartIsReg(modrm)) { + assign( sV, getXMMReg(eregOfRM(modrm)) ); + order = (Int)insn[4]; + delta += 4+1; + DIP("pshufhw $%d,%s,%s\n", order, + nameXMMReg(eregOfRM(modrm)), + nameXMMReg(gregOfRM(modrm))); + } else { + addr = disAMode ( &alen, sorb, delta+3, dis_buf ); + assign( sV, loadLE(Ity_V128, mkexpr(addr)) ); + order = (Int)insn[3+alen]; + delta += 4+alen; + DIP("pshufhw $%d,%s,%s\n", order, + dis_buf, + nameXMMReg(gregOfRM(modrm))); + } + assign( sVhi, unop(Iop_128HIto64, mkexpr(sV)) ); + breakup64to16s( sVhi, &s3, &s2, &s1, &s0 ); + +# define SEL(n) \ + ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3))) + assign(dVhi, + mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3), + SEL((order>>2)&3), SEL((order>>0)&3) ) + ); + assign(dV, binop( Iop_64HLto128, + mkexpr(dVhi), + unop(Iop_128to64, mkexpr(sV))) ); + putXMMReg(gregOfRM(modrm), mkexpr(dV)); +# undef SEL + goto decode_success; + } + + /* F2 0F 70 = PSHUFLW -- rearrange lower half 4x16 from E(xmm or + mem) to G(xmm), and copy upper half */ + if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x70) { + Int order; + IRTemp sVlo, dVlo, sV, dV, s3, s2, s1, s0; + s3 = s2 = s1 = s0 = IRTemp_INVALID; + sV = newTemp(Ity_V128); + dV = newTemp(Ity_V128); + sVlo = newTemp(Ity_I64); + dVlo = newTemp(Ity_I64); + modrm = insn[3]; + if (epartIsReg(modrm)) { + assign( sV, getXMMReg(eregOfRM(modrm)) ); + order = (Int)insn[4]; + delta += 4+1; + DIP("pshuflw $%d,%s,%s\n", order, + nameXMMReg(eregOfRM(modrm)), + nameXMMReg(gregOfRM(modrm))); + } else { + addr = disAMode ( &alen, sorb, delta+3, dis_buf ); + assign( sV, loadLE(Ity_V128, mkexpr(addr)) ); + order = (Int)insn[3+alen]; + delta += 4+alen; + DIP("pshuflw $%d,%s,%s\n", order, + dis_buf, + nameXMMReg(gregOfRM(modrm))); + } + assign( sVlo, unop(Iop_128to64, mkexpr(sV)) ); + breakup64to16s( sVlo, &s3, &s2, &s1, &s0 ); + +# define SEL(n) \ + ((n)==0 ? s0 : ((n)==1 ? s1 : ((n)==2 ? s2 : s3))) + assign(dVlo, + mk64from16s( SEL((order>>6)&3), SEL((order>>4)&3), + SEL((order>>2)&3), SEL((order>>0)&3) ) + ); + assign(dV, binop( Iop_64HLto128, + unop(Iop_128HIto64, mkexpr(sV)), + mkexpr(dVlo) ) ); + putXMMReg(gregOfRM(modrm), mkexpr(dV)); +# undef SEL + goto decode_success; + } + + /* 66 0F 72 /6 ib = PSLLD by immediate */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72 + && epartIsReg(insn[2]) + && gregOfRM(insn[2]) == 6) { + delta = dis_SSE_shiftE_imm( sorb, delta+2, "pslld", Iop_ShlN32x4 ); + goto decode_success; + } + + /* 66 0F F2 = PSLLD by E */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF2) { + delta = dis_SSE_shiftG_byE( sorb, delta+2, "pslld", Iop_ShlN32x4 ); + goto decode_success; + } + +#if 0 + /* 66 0F 73 /7 ib = PSLLDQ by immediate */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73 + && epartIsReg(insn[2]) + && gregOfRM(insn[2]) == 7) { + delta = dis_SSE_shiftE_imm( sorb, delta+2, "pslldq", Iop_ShlN64x2 ); + goto decode_success; + } +#endif + + /* 66 0F 73 /6 ib = PSLLQ by immediate */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73 + && epartIsReg(insn[2]) + && gregOfRM(insn[2]) == 6) { + delta = dis_SSE_shiftE_imm( sorb, delta+2, "psllq", Iop_ShlN64x2 ); + goto decode_success; + } + + /* 66 0F F3 = PSLLQ by E */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF3) { + delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllq", Iop_ShlN64x2 ); + goto decode_success; + } + + /* 66 0F 71 /6 ib = PSLLW by immediate */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71 + && epartIsReg(insn[2]) + && gregOfRM(insn[2]) == 6) { + delta = dis_SSE_shiftE_imm( sorb, delta+2, "psllw", Iop_ShlN16x8 ); + goto decode_success; + } + + /* 66 0F F1 = PSLLW by E */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF1) { + delta = dis_SSE_shiftG_byE( sorb, delta+2, "psllw", Iop_ShlN16x8 ); + goto decode_success; + } + + /* 66 0F 72 /4 ib = PSRAD by immediate */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72 + && epartIsReg(insn[2]) + && gregOfRM(insn[2]) == 4) { + delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrad", Iop_SarN32x4 ); + goto decode_success; + } + + /* 66 0F E2 = PSRAD by E */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE2) { + delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrad", Iop_SarN32x4 ); + goto decode_success; + } + + /* 66 0F 71 /4 ib = PSRAW by immediate */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71 + && epartIsReg(insn[2]) + && gregOfRM(insn[2]) == 4) { + delta = dis_SSE_shiftE_imm( sorb, delta+2, "psraw", Iop_SarN16x8 ); + goto decode_success; + } + + /* 66 0F E1 = PSRAW by E */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE1) { + delta = dis_SSE_shiftG_byE( sorb, delta+2, "psraw", Iop_SarN16x8 ); + goto decode_success; + } + + /* 66 0F 72 /2 ib = PSRLD by immediate */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x72 + && epartIsReg(insn[2]) + && gregOfRM(insn[2]) == 2) { + delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrld", Iop_ShrN32x4 ); + goto decode_success; + } + + /* 66 0F D2 = PSRLD by E */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD2) { + delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrld", Iop_ShrN32x4 ); + goto decode_success; + } + + /* 66 0F 73 /2 ib = PSRLQ by immediate */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x73 + && epartIsReg(insn[2]) + && gregOfRM(insn[2]) == 2) { + delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrlq", Iop_ShrN64x2 ); + goto decode_success; + } + + /* 66 0F D3 = PSRLQ by E */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD3) { + delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlq", Iop_ShrN64x2 ); + goto decode_success; + } + + /* 66 0F 71 /2 ib = PSRLW by immediate */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x71 + && epartIsReg(insn[2]) + && gregOfRM(insn[2]) == 2) { + delta = dis_SSE_shiftE_imm( sorb, delta+2, "psrlw", Iop_ShrN16x8 ); + goto decode_success; + } + + /* 66 0F D1 = PSRLW by E */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD1) { + delta = dis_SSE_shiftG_byE( sorb, delta+2, "psrlw", Iop_ShrN16x8 ); + goto decode_success; + } + + /* 66 0F F8 = PSUBB */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF8) { + delta = dis_SSEint_E_to_G( sorb, delta+2, + "psubb", Iop_Sub8x16, False ); + goto decode_success; + } + + /* 66 0F FA = PSUBD */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFA) { + delta = dis_SSEint_E_to_G( sorb, delta+2, + "psubd", Iop_Sub32x4, False ); + goto decode_success; + } + + /* ***--- this is an MMX class insn introduced in SSE2 ---*** */ + /* 0F FB = PSUBQ -- sub 64x1 */ + if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xFB) { + do_MMX_preamble(); + delta = dis_MMXop_regmem_to_reg ( + sorb, delta+2, insn[1], "psubq", False ); + goto decode_success; + } + + /* 66 0F FB = PSUBQ */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xFB) { + delta = dis_SSEint_E_to_G( sorb, delta+2, + "psubq", Iop_Sub64x2, False ); + goto decode_success; + } + + /* 66 0F F9 = PSUBW */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xF9) { + delta = dis_SSEint_E_to_G( sorb, delta+2, + "psubw", Iop_Sub16x8, False ); + goto decode_success; + } + + /* 66 0F E8 = PSUBSB */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE8) { + delta = dis_SSEint_E_to_G( sorb, delta+2, + "psubsb", Iop_QSub8Sx16, False ); + goto decode_success; + } + + /* 66 0F E9 = PSUBSW */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xE9) { + delta = dis_SSEint_E_to_G( sorb, delta+2, + "psubsw", Iop_QSub16Sx8, False ); + goto decode_success; + } + + /* 66 0F D8 = PSUBSB */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD8) { + delta = dis_SSEint_E_to_G( sorb, delta+2, + "psubusb", Iop_QSub8Ux16, False ); + goto decode_success; + } + + /* 66 0F D9 = PSUBSW */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xD9) { + delta = dis_SSEint_E_to_G( sorb, delta+2, + "psubusw", Iop_QSub16Ux8, False ); + goto decode_success; + } + //-- //-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */ @@ -12335,7 +12765,8 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, case 0x73: /* (sz==4): PSLLgg/PSRAgg/PSRLgg mmxreg by imm8 */ /* If sz==2 this is SSE, and we assume sse idec has already spotted those cases by now. */ - vassert(sz == 4); + if (sz == 2) + goto decode_failure; case 0x6E: /* MOVD (src)ireg-or-mem, (dst)mmxreg */ case 0x7E: /* MOVD (src)mmxreg, (dst)ireg-or-mem */ diff --git a/VEX/priv/host-x86/hdefs.c b/VEX/priv/host-x86/hdefs.c index 74e3df309b..00de9e1262 100644 --- a/VEX/priv/host-x86/hdefs.c +++ b/VEX/priv/host-x86/hdefs.c @@ -858,6 +858,15 @@ X86Instr* X86Instr_SseReRg ( X86SseOp op, HReg re, HReg rg ) { vassert(op != Xsse_MOV); return i; } +X86Instr* X86Instr_SseCMov ( X86CondCode cond, HReg src, HReg dst ) { + X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); + i->tag = Xin_SseCMov; + i->Xin.SseCMov.cond = cond; + i->Xin.SseCMov.src = src; + i->Xin.SseCMov.dst = dst; + vassert(cond != Xcc_ALWAYS); + return i; +} void ppX86Instr ( X86Instr* i ) { switch (i->tag) { @@ -1102,6 +1111,12 @@ void ppX86Instr ( X86Instr* i ) { vex_printf(","); ppHRegX86(i->Xin.SseReRg.dst); return; + case Xin_SseCMov: + vex_printf("cmov%s ", showX86CondCode(i->Xin.SseCMov.cond)); + ppHRegX86(i->Xin.SseCMov.src); + vex_printf(","); + ppHRegX86(i->Xin.SseCMov.dst); + return; default: vpanic("ppX86Instr"); @@ -1243,7 +1258,7 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i) addHRegUse(u, HRmWrite, i->Xin.Fp64to32.dst); return; case Xin_FpCMov: - addHRegUse(u, HRmRead, i->Xin.FpCMov.src); + addHRegUse(u, HRmRead, i->Xin.FpCMov.src); addHRegUse(u, HRmModify, i->Xin.FpCMov.dst); return; case Xin_FpLdStCW: @@ -1316,6 +1331,10 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i) addHRegUse(u, HRmRead, i->Xin.SseReRg.src); addHRegUse(u, HRmModify, i->Xin.SseReRg.dst); return; + case Xin_SseCMov: + addHRegUse(u, HRmRead, i->Xin.SseCMov.src); + addHRegUse(u, HRmModify, i->Xin.SseCMov.dst); + return; default: ppX86Instr(i); vpanic("getRegUsage_X86Instr"); @@ -1456,6 +1475,10 @@ void mapRegs_X86Instr (HRegRemap* m, X86Instr* i) mapReg(m, &i->Xin.SseReRg.src); mapReg(m, &i->Xin.SseReRg.dst); return; + case Xin_SseCMov: + mapReg(m, &i->Xin.SseCMov.src); + mapReg(m, &i->Xin.SseCMov.dst); + return; default: ppX86Instr(i); vpanic("mapRegs_X86Instr"); @@ -2707,6 +2730,22 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) case Xsse_MULHI16U: XX(0x66); XX(0x0F); XX(0xE4); break; case Xsse_MULHI16S: XX(0x66); XX(0x0F); XX(0xE5); break; case Xsse_MUL16: XX(0x66); XX(0x0F); XX(0xD5); break; + case Xsse_SHL16: XX(0x66); XX(0x0F); XX(0xF1); break; + case Xsse_SHL32: XX(0x66); XX(0x0F); XX(0xF2); break; + case Xsse_SHL64: XX(0x66); XX(0x0F); XX(0xF3); break; + case Xsse_SAR16: XX(0x66); XX(0x0F); XX(0xE1); break; + case Xsse_SAR32: XX(0x66); XX(0x0F); XX(0xE2); break; + case Xsse_SHR16: XX(0x66); XX(0x0F); XX(0xD1); break; + case Xsse_SHR32: XX(0x66); XX(0x0F); XX(0xD2); break; + case Xsse_SHR64: XX(0x66); XX(0x0F); XX(0xD3); break; + case Xsse_SUB8: XX(0x66); XX(0x0F); XX(0xF8); break; + case Xsse_SUB16: XX(0x66); XX(0x0F); XX(0xF9); break; + case Xsse_SUB32: XX(0x66); XX(0x0F); XX(0xFA); break; + case Xsse_SUB64: XX(0x66); XX(0x0F); XX(0xFB); break; + case Xsse_QSUB8S: XX(0x66); XX(0x0F); XX(0xE8); break; + case Xsse_QSUB16S: XX(0x66); XX(0x0F); XX(0xE9); break; + case Xsse_QSUB8U: XX(0x66); XX(0x0F); XX(0xD8); break; + case Xsse_QSUB16U: XX(0x66); XX(0x0F); XX(0xD9); break; default: goto bad; } p = doAMode_R(p, fake(vregNo(i->Xin.SseReRg.dst)), @@ -2714,6 +2753,22 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) # undef XX goto done; + case Xin_SseCMov: + /* jmp fwds if !condition */ + *p++ = 0x70 + (i->Xin.SseCMov.cond ^ 1); + *p++ = 0; /* # of bytes in the next bit, which we don't know yet */ + ptmp = p; + + /* movaps %src, %dst */ + *p++ = 0x0F; + *p++ = 0x28; + p = doAMode_R(p, fake(vregNo(i->Xin.SseCMov.dst)), + fake(vregNo(i->Xin.SseCMov.src)) ); + + /* Fill in the jump offset. */ + *(ptmp-1) = p - ptmp; + goto done; + default: goto bad; } diff --git a/VEX/priv/host-x86/hdefs.h b/VEX/priv/host-x86/hdefs.h index 63e50a466c..415b1ea6bf 100644 --- a/VEX/priv/host-x86/hdefs.h +++ b/VEX/priv/host-x86/hdefs.h @@ -371,7 +371,7 @@ typedef Xin_FpLdSt, /* FP fake load/store */ Xin_FpLdStI, /* FP fake load/store, converting to/from Int */ Xin_Fp64to32, /* FP round IEEE754 double to IEEE754 single */ - Xin_FpCMov, /* FP fake floating point (un)conditional move */ + Xin_FpCMov, /* FP fake floating point conditional move */ Xin_FpLdStCW, /* fldcw / fstcw */ Xin_FpStSW_AX, /* fstsw %ax */ Xin_FpCmp, /* FP compare, generating a C320 value into int reg */ @@ -384,7 +384,8 @@ typedef Xin_Sse32FLo, /* SSE binary, 32F in lowest lane only */ Xin_Sse64Fx2, /* SSE binary, 64Fx2 */ Xin_Sse64FLo, /* SSE binary, 64F in lowest lane only */ - Xin_SseReRg /* SSE binary general reg-reg, Re, Rg */ + Xin_SseReRg, /* SSE binary general reg-reg, Re, Rg */ + Xin_SseCMov /* SSE conditional move */ } X86InstrTag; @@ -594,6 +595,13 @@ typedef HReg src; HReg dst; } SseReRg; + /* Mov src to dst on the given condition, which may not + be the bogus Xcc_ALWAYS. */ + struct { + X86CondCode cond; + HReg src; + HReg dst; + } SseCMov; } Xin; } @@ -636,6 +644,7 @@ 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 X86Instr* X86Instr_SseCMov ( X86CondCode, HReg src, HReg dst ); extern void ppX86Instr ( X86Instr* ); diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index 1e2fcc3e8d..11ae76938c 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -2706,6 +2706,14 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) case Iop_MulHi16Ux8: op = Xsse_MULHI16U; goto do_SseReRg; case Iop_MulHi16Sx8: op = Xsse_MULHI16S; goto do_SseReRg; case Iop_Mul16x8: op = Xsse_MUL16; goto do_SseReRg; + case Iop_Sub8x16: op = Xsse_SUB8; goto do_SseReRg; + case Iop_Sub16x8: op = Xsse_SUB16; goto do_SseReRg; + case Iop_Sub32x4: op = Xsse_SUB32; goto do_SseReRg; + case Iop_Sub64x2: op = Xsse_SUB64; goto do_SseReRg; + case Iop_QSub8Sx16: op = Xsse_QSUB8S; goto do_SseReRg; + case Iop_QSub16Sx8: op = Xsse_QSUB16S; goto do_SseReRg; + case Iop_QSub8Ux16: op = Xsse_QSUB8U; goto do_SseReRg; + case Iop_QSub16Ux8: op = Xsse_QSUB16U; goto do_SseReRg; do_SseReRg: { HReg arg1 = iselVecExpr(env, e->Iex.Binop.arg1); HReg arg2 = iselVecExpr(env, e->Iex.Binop.arg2); @@ -2720,11 +2728,47 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) return dst; } + case Iop_ShlN16x8: op = Xsse_SHL16; goto do_SseShift; + case Iop_ShlN32x4: op = Xsse_SHL32; goto do_SseShift; + case Iop_ShlN64x2: op = Xsse_SHL64; goto do_SseShift; + case Iop_SarN16x8: op = Xsse_SAR16; goto do_SseShift; + case Iop_SarN32x4: op = Xsse_SAR32; goto do_SseShift; + case Iop_ShrN16x8: op = Xsse_SHR16; goto do_SseShift; + case Iop_ShrN32x4: op = Xsse_SHR32; goto do_SseShift; + case Iop_ShrN64x2: op = Xsse_SHR64; goto do_SseShift; + do_SseShift: { + HReg greg = iselVecExpr(env, e->Iex.Binop.arg1); + X86RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2); + X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); + HReg ereg = newVRegV(env); + HReg dst = newVRegV(env); + addInstr(env, X86Instr_Push(X86RMI_Imm(0))); + addInstr(env, X86Instr_Push(X86RMI_Imm(0))); + addInstr(env, X86Instr_Push(X86RMI_Imm(0))); + addInstr(env, X86Instr_Push(rmi)); + addInstr(env, X86Instr_SseLdSt(True/*load*/, ereg, esp0)); + addInstr(env, mk_vMOVsd_RR(greg, dst)); + addInstr(env, X86Instr_SseReRg(op, ereg, dst)); + add_to_esp(env, 16); + return dst; + } + default: break; } /* switch (e->Iex.Binop.op) */ } /* if (e->tag == Iex_Binop) */ + if (e->tag == Iex_Mux0X) { + HReg r8 = iselIntExpr_R(env, e->Iex.Mux0X.cond); + HReg rX = iselVecExpr(env, e->Iex.Mux0X.exprX); + HReg r0 = iselVecExpr(env, e->Iex.Mux0X.expr0); + HReg dst = newVRegV(env); + addInstr(env, mk_vMOVsd_RR(rX,dst)); + addInstr(env, X86Instr_Test32(X86RI_Imm(0xFF), X86RM_Reg(r8))); + addInstr(env, X86Instr_SseCMov(Xcc_Z,r0,dst)); + return dst; + } + ppIRExpr(e); vpanic("iselVecExpr_wrk"); }