From: Julian Seward Date: Thu, 5 May 2005 21:34:02 +0000 (+0000) Subject: Implement a whole bunch more SSE instructions on amd64. X-Git-Tag: svn/VALGRIND_3_0_1^2~171 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b3077e202f2180372c5b074fed89b02589266cb8;p=thirdparty%2Fvalgrind.git Implement a whole bunch more SSE instructions on amd64. git-svn-id: svn://svn.valgrind.org/vex/trunk@1163 --- diff --git a/VEX/priv/guest-amd64/toIR.c b/VEX/priv/guest-amd64/toIR.c index 24207c9f7b..4fde72bae6 100644 --- a/VEX/priv/guest-amd64/toIR.c +++ b/VEX/priv/guest-amd64/toIR.c @@ -2163,7 +2163,7 @@ IRExpr* handleSegOverride ( Prefix pfx, IRExpr* virtual ) by the caller. This is needed to make sense of %rip-relative addresses. Note that the value that *len is set to is only the length of the amode itself and does not include the value supplied - in xtra_bytes. + in extra_bytes. */ static IRTemp disAMode_copy2tmp ( IRExpr* addr64 ) @@ -7443,41 +7443,41 @@ static ULong 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, ULong delta, -//.. HChar* opname, IROp op, -//.. Bool eLeft -//.. ) -//.. { -//.. HChar dis_buf[50]; -//.. Int alen; -//.. IRTemp addr; -//.. UChar rm = getUChar(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; -//.. } +/* SSE integer binary operation: + G = G `op` E (eLeft == False) + G = E `op` G (eLeft == True) +*/ +static ULong dis_SSEint_E_to_G( + Prefix pfx, ULong delta, + HChar* opname, IROp op, + Bool eLeft + ) +{ + HChar dis_buf[50]; + Int alen; + IRTemp addr; + UChar rm = getUChar(delta); + IRExpr* gpart = getXMMReg(gregOfRexRM(pfx,rm)); + IRExpr* epart = NULL; + if (epartIsReg(rm)) { + epart = getXMMReg(eregOfRexRM(pfx,rm)); + DIP("%s %s,%s\n", opname, + nameXMMReg(eregOfRexRM(pfx,rm)), + nameXMMReg(gregOfRexRM(pfx,rm)) ); + delta += 1; + } else { + addr = disAMode ( &alen, pfx, delta, dis_buf, 0 ); + epart = loadLE(Ity_V128, mkexpr(addr)); + DIP("%s %s,%s\n", opname, + dis_buf, + nameXMMReg(gregOfRexRM(pfx,rm)) ); + delta += alen; + } + putXMMReg( gregOfRexRM(pfx,rm), + eLeft ? binop(op, epart, gpart) + : binop(op, gpart, epart) ); + return delta; +} /* Helper for doing SSE FP comparisons. */ @@ -7659,60 +7659,61 @@ static ULong dis_SSEcmp_E_to_G ( Prefix pfx, ULong delta, //.. putXMMReg( gregOfRM(rm), mkexpr(g1) ); //.. return delta; //.. } -//.. -//.. -//.. /* Vector by scalar shift of E by an immediate byte. */ -//.. -//.. static -//.. UInt dis_SSE_shiftE_imm ( ULong delta, HChar* opname, IROp op ) -//.. { -//.. Bool shl, shr, sar; -//.. UChar rm = getUChar(delta); -//.. IRTemp e0 = newTemp(Ity_V128); -//.. IRTemp e1 = newTemp(Ity_V128); -//.. UChar amt, size; -//.. vassert(epartIsReg(rm)); -//.. vassert(gregOfRM(rm) == 2 -//.. || gregOfRM(rm) == 4 || gregOfRM(rm) == 6); -//.. amt = (Int)(getUChar(delta+1)); -//.. delta += 2; -//.. DIP("%s $%d,%s\n", opname, -//.. (Int)amt, -//.. nameXMMReg(eregOfRM(rm)) ); -//.. assign( e0, 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( e1, amt >= size -//.. ? mkV128(0x0000) -//.. : binop(op, mkexpr(e0), mkU8(amt)) -//.. ); -//.. } else -//.. if (sar) { -//.. assign( e1, amt >= size -//.. ? binop(op, mkexpr(e0), mkU8(size-1)) -//.. : binop(op, mkexpr(e0), mkU8(amt)) -//.. ); -//.. } else { -//.. vassert(0); -//.. } -//.. -//.. putXMMReg( eregOfRM(rm), mkexpr(e1) ); -//.. return delta; -//.. } + + +/* Vector by scalar shift of E by an immediate byte. */ + +static +ULong dis_SSE_shiftE_imm ( Prefix pfx, + ULong delta, HChar* opname, IROp op ) +{ + Bool shl, shr, sar; + UChar rm = getUChar(delta); + IRTemp e0 = newTemp(Ity_V128); + IRTemp e1 = newTemp(Ity_V128); + UChar amt, size; + vassert(epartIsReg(rm)); + vassert(gregLO3ofRM(rm) == 2 + || gregLO3ofRM(rm) == 4 || gregLO3ofRM(rm) == 6); + amt = (Int)(getUChar(delta+1)); + delta += 2; + DIP("%s $%d,%s\n", opname, + (Int)amt, + nameXMMReg(eregOfRexRM(pfx,rm)) ); + assign( e0, getXMMReg(eregOfRexRM(pfx,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( e1, amt >= size + ? mkV128(0x0000) + : binop(op, mkexpr(e0), mkU8(amt)) + ); + } else + if (sar) { + assign( e1, amt >= size + ? binop(op, mkexpr(e0), mkU8(size-1)) + : binop(op, mkexpr(e0), mkU8(amt)) + ); + } else { + vassert(0); + } + + putXMMReg( eregOfRexRM(pfx,rm), mkexpr(e1) ); + return delta; +} /* Get the current SSE rounding mode. */ @@ -7832,7 +7833,7 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, /*OUT*/ Addr64* whereNext ) { IRType ty; - IRTemp addr, /* t0, */ t1, t2, t3, t4 /*, t5, t6 */; + IRTemp addr, t0, t1, t2, t3, t4 /*, t5, t6 */; Int alen; UChar opc, modrm, /*abyte,*/ pre; Long d64; @@ -7860,7 +7861,7 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, vassert(guest_rip_next_assumed == 0); vassert(guest_rip_next_mustcheck == False); - addr = /* t0 = */ t1 = t2 = t3 = t4 = /* t5 = t6 = */ IRTemp_INVALID; + addr = t0 = t1 = t2 = t3 = t4 = /* t5 = t6 = */ IRTemp_INVALID; DIP("\t0x%llx: ", guest_rip_bbstart+delta); @@ -7966,14 +7967,48 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, /* ---------------------------------------------------- */ - /* --- The SSE decoder. --- */ + /* --- The SSE/SSE2 decoder. --- */ /* ---------------------------------------------------- */ /* What did I do to deserve SSE ? Perhaps I was really bad in a previous life? */ - /* Note, this doesn't handle SSE2 or SSE3. That is handled in a - later section, further on. */ + /* Note, this doesn't handle SSE3 right now. All amd64s support + SSE2 as a minimum so there is no point distinguishing SSE1 vs + SSE2. */ + + /* There are just so many damn SSE insns, and amongst them are a + large number of data-move insns, many of which seem almost + identical. Here's a statement of the behaviour of MOVQ, MOVSD, + MOVD, MOVSS. It doesn't help that the Intel manuals are less + than accurate about these. The AMD docs seem OK tho. + + The following is true for both x86 and amd64. MOVQ and MOVSD + shunt 64-bit things around. r is an xmm register and m is + memory. + + MOVQ r <- r lo64 moved; hi64 set to zero + MOVQ m <- r lo64 moved + MOVQ r <- m lo64 moved; hi64 set to zero + + MOVSD r <- r lo64 moved; hi64 unchanged + MOVSD m <- r lo64 moved + MOVSD r <- m lo64 moved; hi64 set to zero + + MOVD and MOVSS shunt 32-bit things around, and are exactly + analogous: + + MOVD r <- r lo32 moved; hi96 set to zero + MOVD m <- r lo32 moved + MOVD r <- m lo32 moved; hi96 set to zero + + MOVSS r <- r lo32 moved; hi96 unchanged + MOVSS m <- r lo32 moved + MOVSS r <- m lo32 moved; hi96 set to zero + + For MOVQ and MOVD, the r <- r rules apply even if the source r + is instead an integer register. + */ insn = (UChar*)&guest_code[delta]; @@ -9244,39 +9279,39 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, goto decode_success; } -//.. /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x -//.. F64 in xmm(G) */ -//.. if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0xE6) { -//.. IRTemp arg64 = newTemp(Ity_I64); -//.. vassert(sz == 4); -//.. -//.. modrm = getUChar(delta+3); -//.. if (epartIsReg(modrm)) { -//.. assign( arg64, getXMMRegLane64(eregOfRM(modrm), 0) ); -//.. delta += 3+1; -//.. DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRM(modrm)), -//.. nameXMMReg(gregOfRM(modrm))); -//.. } else { -//.. addr = disAMode ( &alen, sorb, delta+3, dis_buf ); -//.. assign( arg64, loadLE(Ity_I64, mkexpr(addr)) ); -//.. delta += 3+alen; -//.. DIP("cvtdq2pd %s,%s\n", dis_buf, -//.. nameXMMReg(gregOfRM(modrm)) ); -//.. } -//.. -//.. putXMMRegLane64F( -//.. gregOfRM(modrm), 0, -//.. unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64))) -//.. ); -//.. -//.. putXMMRegLane64F( -//.. gregOfRM(modrm), 1, -//.. unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64))) -//.. ); -//.. -//.. goto decode_success; -//.. } -//.. + /* F3 0F E6 = CVTDQ2PD -- convert 2 x I32 in mem/lo half xmm to 2 x + F64 in xmm(G) */ + if (haveF3no66noF2(pfx) && insn[0] == 0x0F && insn[1] == 0xE6) { + IRTemp arg64 = newTemp(Ity_I64); + if (sz != 4) goto decode_failure; + + modrm = getUChar(delta+2); + if (epartIsReg(modrm)) { + assign( arg64, getXMMRegLane64(eregOfRexRM(pfx,modrm), 0) ); + delta += 2+1; + DIP("cvtdq2pd %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)), + nameXMMReg(gregOfRexRM(pfx,modrm))); + } else { + addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 ); + assign( arg64, loadLE(Ity_I64, mkexpr(addr)) ); + delta += 2+alen; + DIP("cvtdq2pd %s,%s\n", dis_buf, + nameXMMReg(gregOfRexRM(pfx,modrm)) ); + } + + putXMMRegLane64F( + gregOfRexRM(pfx,modrm), 0, + unop(Iop_I32toF64, unop(Iop_64to32, mkexpr(arg64))) + ); + + putXMMRegLane64F( + gregOfRexRM(pfx,modrm), 1, + unop(Iop_I32toF64, unop(Iop_64HIto32, mkexpr(arg64))) + ); + + goto decode_success; + } + //.. /* 0F 5B = CVTDQ2PS -- convert 4 x I32 in mem/xmm to 4 x F32 in //.. xmm(G) */ //.. if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5B) { @@ -9315,52 +9350,50 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. //.. goto decode_success; //.. } -//.. -//.. /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in -//.. lo half xmm(G), and zero upper half */ -//.. if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0xE6) { -//.. IRTemp argV = newTemp(Ity_V128); -//.. IRTemp rmode = newTemp(Ity_I32); -//.. vassert(sz == 4); -//.. -//.. modrm = getUChar(delta+3); -//.. if (epartIsReg(modrm)) { -//.. assign( argV, getXMMReg(eregOfRM(modrm)) ); -//.. delta += 3+1; -//.. DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRM(modrm)), -//.. nameXMMReg(gregOfRM(modrm))); -//.. } else { -//.. addr = disAMode ( &alen, sorb, delta+3, dis_buf ); -//.. assign( argV, loadLE(Ity_V128, mkexpr(addr)) ); -//.. delta += 3+alen; -//.. DIP("cvtpd2dq %s,%s\n", dis_buf, -//.. nameXMMReg(gregOfRM(modrm)) ); -//.. } -//.. -//.. assign( rmode, get_sse_roundingmode() ); -//.. t0 = newTemp(Ity_F64); -//.. t1 = newTemp(Ity_F64); -//.. assign( t0, unop(Iop_ReinterpI64asF64, -//.. unop(Iop_128to64, mkexpr(argV))) ); -//.. assign( t1, unop(Iop_ReinterpI64asF64, -//.. unop(Iop_128HIto64, mkexpr(argV))) ); -//.. -#if 0 /* stop gcc multi-line comment warning */ -/.. # define CVT(_t) binop( Iop_F64toI32, \ -/.. mkexpr(rmode), \ -/.. mkexpr(_t) ) -#endif /* stop gcc multi-line comment warning */ -//.. -//.. putXMMRegLane32( gregOfRM(modrm), 3, mkU32(0) ); -//.. putXMMRegLane32( gregOfRM(modrm), 2, mkU32(0) ); -//.. putXMMRegLane32( gregOfRM(modrm), 1, CVT(t1) ); -//.. putXMMRegLane32( gregOfRM(modrm), 0, CVT(t0) ); -//.. -//.. # undef CVT -//.. -//.. goto decode_success; -//.. } -//.. + + /* F2 0F E6 = CVTPD2DQ -- convert 2 x F64 in mem/xmm to 2 x I32 in + lo half xmm(G), and zero upper half */ + if (haveF2no66noF3(pfx) && insn[0] == 0x0F && insn[1] == 0xE6) { + IRTemp argV = newTemp(Ity_V128); + IRTemp rmode = newTemp(Ity_I32); + if (sz != 4) goto decode_failure; + + modrm = getUChar(delta+2); + if (epartIsReg(modrm)) { + assign( argV, getXMMReg(eregOfRexRM(pfx,modrm)) ); + delta += 2+1; + DIP("cvtpd2dq %s,%s\n", nameXMMReg(eregOfRexRM(pfx,modrm)), + nameXMMReg(gregOfRexRM(pfx,modrm))); + } else { + addr = disAMode ( &alen, pfx, delta+2, dis_buf, 0 ); + assign( argV, loadLE(Ity_V128, mkexpr(addr)) ); + delta += 2+alen; + DIP("cvtpd2dq %s,%s\n", dis_buf, + nameXMMReg(gregOfRexRM(pfx,modrm)) ); + } + + assign( rmode, get_sse_roundingmode() ); + t0 = newTemp(Ity_F64); + t1 = newTemp(Ity_F64); + assign( t0, unop(Iop_ReinterpI64asF64, + unop(Iop_V128to64, mkexpr(argV))) ); + assign( t1, unop(Iop_ReinterpI64asF64, + unop(Iop_V128HIto64, mkexpr(argV))) ); + +# define CVT(_t) binop( Iop_F64toI32, \ + mkexpr(rmode), \ + mkexpr(_t) ) + + putXMMRegLane32( gregOfRexRM(pfx,modrm), 3, mkU32(0) ); + putXMMRegLane32( gregOfRexRM(pfx,modrm), 2, mkU32(0) ); + putXMMRegLane32( gregOfRexRM(pfx,modrm), 1, CVT(t1) ); + putXMMRegLane32( gregOfRexRM(pfx,modrm), 0, CVT(t0) ); + +# undef CVT + + goto decode_success; + } + //.. /* 66 0F 2D = CVTPD2PI -- convert 2 x F64 in mem/xmm to 2 x //.. I32 in mmx, according to prevailing SSE rounding mode */ //.. /* 66 0F 2C = CVTTPD2PI -- convert 2 x F64 in mem/xmm to 2 x @@ -9909,66 +9942,95 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, } } -//.. /* 66 0F 6E = MOVD from r/m32 to xmm, zeroing high 3/4 of xmm. */ -//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x6E) { -//.. modrm = getUChar(delta+2); -//.. if (epartIsReg(modrm)) { -//.. delta += 2+1; -//.. putXMMReg( -//.. gregOfRM(modrm), -//.. unop( Iop_32Uto128, getIReg(4, eregOfRM(modrm)) ) -//.. ); -//.. DIP("movd %s, %s\n", -//.. nameIReg(4,eregOfRM(modrm)), nameXMMReg(gregOfRM(modrm))); -//.. } else { -//.. addr = disAMode( &alen, sorb, delta+2, dis_buf ); -//.. delta += 2+alen; -//.. putXMMReg( -//.. gregOfRM(modrm), -//.. unop( Iop_32Uto128,loadLE(Ity_I32, mkexpr(addr)) ) -//.. ); -//.. DIP("movd %s, %s\n", dis_buf, nameXMMReg(gregOfRM(modrm))); -//.. } -//.. goto decode_success; -//.. } -//.. -//.. /* 66 0F 7E = MOVD from xmm low 1/4 to r/m32. */ -//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7E) { -//.. modrm = getUChar(delta+2); -//.. if (epartIsReg(modrm)) { -//.. delta += 2+1; -//.. putIReg( 4, eregOfRM(modrm), -//.. getXMMRegLane32(gregOfRM(modrm), 0) ); -//.. DIP("movd %s, %s\n", -//.. nameXMMReg(gregOfRM(modrm)), nameIReg(4,eregOfRM(modrm))); -//.. } else { -//.. addr = disAMode( &alen, sorb, delta+2, dis_buf ); -//.. delta += 2+alen; -//.. storeLE( mkexpr(addr), -//.. getXMMRegLane32(gregOfRM(modrm), 0) ); -//.. DIP("movd %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf); -//.. } -//.. goto decode_success; -//.. } -//.. -//.. /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */ -//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x7F) { -//.. modrm = getUChar(delta+2); -//.. if (epartIsReg(modrm)) { -//.. delta += 2+1; -//.. putXMMReg( eregOfRM(modrm), -//.. getXMMReg(gregOfRM(modrm)) ); -//.. DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), -//.. nameXMMReg(eregOfRM(modrm))); -//.. } else { -//.. addr = disAMode( &alen, sorb, delta+2, dis_buf ); -//.. delta += 2+alen; -//.. storeLE( mkexpr(addr), getXMMReg(gregOfRM(modrm)) ); -//.. DIP("movdqa %s, %s\n", nameXMMReg(gregOfRM(modrm)), dis_buf); -//.. } -//.. goto decode_success; -//.. } -//.. + /* 66 0F 6E = MOVD from ireg32/m32 to xmm lo 1/4, zeroing high 3/4 of xmm. */ + /* or from ireg64/m64 to xmm lo 1/2, zeroing high 1/2 of xmm. */ + if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x6E) { + vassert(sz == 4 || sz == 8); + modrm = getUChar(delta+2); + if (epartIsReg(modrm)) { + delta += 2+1; + if (sz == 4) { + goto decode_failure; /* awaiting test case */ + putXMMReg( + gregOfRexRM(pfx,modrm), + unop( Iop_32UtoV128, getIReg32(eregOfRexRM(pfx,modrm)) ) + ); + DIP("movd %s, %s\n", nameIReg32(eregOfRexRM(pfx,modrm)), + nameXMMReg(gregOfRexRM(pfx,modrm))); + } else { + putXMMReg( + gregOfRexRM(pfx,modrm), + unop( Iop_64UtoV128, getIReg64(eregOfRexRM(pfx,modrm)) ) + ); + DIP("movq %s, %s\n", nameIReg64(eregOfRexRM(pfx,modrm)), + nameXMMReg(gregOfRexRM(pfx,modrm))); + } + } else { + addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 ); + delta += 2+alen; + putXMMReg( + gregOfRexRM(pfx,modrm), + sz == 4 + ? unop( Iop_32UtoV128,loadLE(Ity_I32, mkexpr(addr)) ) + : unop( Iop_64UtoV128,loadLE(Ity_I64, mkexpr(addr)) ) + ); + DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q', dis_buf, + nameXMMReg(gregOfRexRM(pfx,modrm))); + } + goto decode_success; + } + + /* 66 0F 7E = MOVD from xmm low 1/4 to ireg32 or m32. */ + /* or from xmm low 1/2 to ireg64 or m64. */ + if (have66noF2noF3(pfx) && insn[0] == 0x0F && insn[1] == 0x7E) { + if (sz == 2) sz = 4; + vassert(sz == 4 || sz == 8); + modrm = getUChar(delta+2); + if (epartIsReg(modrm)) { + delta += 2+1; + if (sz == 4) { + putIReg32( eregOfRexRM(pfx,modrm), + getXMMRegLane32(gregOfRexRM(pfx,modrm), 0) ); + DIP("movd %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), + nameIReg32(eregOfRexRM(pfx,modrm))); + } else { + putIReg64( eregOfRexRM(pfx,modrm), + getXMMRegLane64(gregOfRexRM(pfx,modrm), 0) ); + DIP("movq %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), + nameIReg64(eregOfRexRM(pfx,modrm))); + } + } else { + addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 ); + delta += 2+alen; + storeLE( mkexpr(addr), + sz == 4 + ? getXMMRegLane32(gregOfRexRM(pfx,modrm),0) + : getXMMRegLane64(gregOfRexRM(pfx,modrm),0) ); + DIP("mov%c %s, %s\n", sz == 4 ? 'd' : 'q', + nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf); + } + goto decode_success; + } + + /* 66 0F 7F = MOVDQA -- move from G (xmm) to E (mem or xmm). */ + if (have66noF2noF3(pfx) && sz == 2 + && insn[0] == 0x0F && insn[1] == 0x7F) { + modrm = getUChar(delta+2); + if (epartIsReg(modrm)) { + delta += 2+1; + putXMMReg( eregOfRexRM(pfx,modrm), + getXMMReg(gregOfRexRM(pfx,modrm)) ); + DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), + nameXMMReg(eregOfRexRM(pfx,modrm))); + } else { + addr = disAMode( &alen, pfx, delta+2, dis_buf, 0 ); + delta += 2+alen; + storeLE( mkexpr(addr), getXMMReg(gregOfRexRM(pfx,modrm)) ); + DIP("movdqa %s, %s\n", nameXMMReg(gregOfRexRM(pfx,modrm)), dis_buf); + } + goto decode_success; + } + //.. /* F3 0F 6F = MOVDQU -- move from E (mem or xmm) to G (xmm). */ //.. /* Unfortunately can't simply use the MOVDQA case since the //.. prefix lengths are different (66 vs F3) */ @@ -10259,55 +10321,56 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, goto decode_success; } -//.. /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */ -//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xC6) { -//.. Int select; -//.. IRTemp sV = newTemp(Ity_V128); -//.. IRTemp dV = newTemp(Ity_V128); -//.. IRTemp s1 = newTemp(Ity_I64); -//.. IRTemp s0 = newTemp(Ity_I64); -//.. IRTemp d1 = newTemp(Ity_I64); -//.. IRTemp d0 = newTemp(Ity_I64); -//.. -//.. modrm = insn[2]; -//.. assign( dV, getXMMReg(gregOfRM(modrm)) ); -//.. -//.. if (epartIsReg(modrm)) { -//.. assign( sV, getXMMReg(eregOfRM(modrm)) ); -//.. select = (Int)insn[3]; -//.. delta += 2+2; -//.. DIP("shufpd $%d,%s,%s\n", select, -//.. nameXMMReg(eregOfRM(modrm)), -//.. nameXMMReg(gregOfRM(modrm))); -//.. } else { -//.. addr = disAMode ( &alen, sorb, delta+2, dis_buf ); -//.. assign( sV, loadLE(Ity_V128, mkexpr(addr)) ); -//.. select = (Int)insn[2+alen]; -//.. delta += 3+alen; -//.. DIP("shufpd $%d,%s,%s\n", select, -//.. dis_buf, -//.. nameXMMReg(gregOfRM(modrm))); -//.. } -//.. -//.. assign( d1, unop(Iop_128HIto64, mkexpr(dV)) ); -//.. assign( d0, unop(Iop_128to64, mkexpr(dV)) ); -//.. assign( s1, unop(Iop_128HIto64, mkexpr(sV)) ); -//.. assign( s0, unop(Iop_128to64, mkexpr(sV)) ); -//.. -//.. # define SELD(n) mkexpr((n)==0 ? d0 : d1) -//.. # define SELS(n) mkexpr((n)==0 ? s0 : s1) -//.. -//.. putXMMReg( -//.. gregOfRM(modrm), -//.. binop(Iop_64HLto128, SELS((select>>1)&1), SELD((select>>0)&1) ) -//.. ); -//.. -//.. # undef SELD -//.. # undef SELS -//.. -//.. goto decode_success; -//.. } -//.. + /* 66 0F C6 /r ib = SHUFPD -- shuffle packed F64s */ + if (have66noF2noF3(pfx) && sz == 2 + && insn[0] == 0x0F && insn[1] == 0xC6) { + Int select; + IRTemp sV = newTemp(Ity_V128); + IRTemp dV = newTemp(Ity_V128); + IRTemp s1 = newTemp(Ity_I64); + IRTemp s0 = newTemp(Ity_I64); + IRTemp d1 = newTemp(Ity_I64); + IRTemp d0 = newTemp(Ity_I64); + + modrm = insn[2]; + assign( dV, getXMMReg(gregOfRexRM(pfx,modrm)) ); + + if (epartIsReg(modrm)) { + assign( sV, getXMMReg(eregOfRexRM(pfx,modrm)) ); + select = (Int)insn[3]; + delta += 2+2; + DIP("shufpd $%d,%s,%s\n", select, + nameXMMReg(eregOfRexRM(pfx,modrm)), + nameXMMReg(gregOfRexRM(pfx,modrm))); + } else { + addr = disAMode ( &alen, pfx, delta+2, dis_buf, 1 ); + assign( sV, loadLE(Ity_V128, mkexpr(addr)) ); + select = (Int)insn[2+alen]; + delta += 3+alen; + DIP("shufpd $%d,%s,%s\n", select, + dis_buf, + nameXMMReg(gregOfRexRM(pfx,modrm))); + } + + assign( d1, unop(Iop_V128HIto64, mkexpr(dV)) ); + assign( d0, unop(Iop_V128to64, mkexpr(dV)) ); + assign( s1, unop(Iop_V128HIto64, mkexpr(sV)) ); + assign( s0, unop(Iop_V128to64, mkexpr(sV)) ); + +# define SELD(n) mkexpr((n)==0 ? d0 : d1) +# define SELS(n) mkexpr((n)==0 ? s0 : s1) + + putXMMReg( + gregOfRexRM(pfx,modrm), + binop(Iop_64HLtoV128, SELS((select>>1)&1), SELD((select>>0)&1) ) + ); + +# undef SELD +# undef SELS + + goto decode_success; + } + //.. /* 66 0F 51 = SQRTPD -- approx sqrt 64Fx2 from R/M to R */ //.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x51) { //.. delta = dis_SSE_E_to_G_unary_all( sorb, delta+2, @@ -10434,14 +10497,15 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. 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 D4 = PADDQ */ + if (have66noF2noF3(pfx) && sz == 2 + && insn[0] == 0x0F && insn[1] == 0xD4) { + delta = dis_SSEint_E_to_G( pfx, 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, @@ -10476,13 +10540,14 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. "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 DB = PAND */ + if (have66noF2noF3(pfx) && sz == 2 + && insn[0] == 0x0F && insn[1] == 0xDB) { + delta = dis_SSE_E_to_G_all( pfx, delta+2, "pand", Iop_AndV128 ); + 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 ); @@ -10745,13 +10810,14 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. putXMMRegLane64( gregOfRM(modrm), 1, mkexpr(t1) ); //.. goto decode_success; //.. } -//.. -//.. /* 66 0F EB = POR */ -//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEB) { -//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "por", Iop_Or128 ); -//.. goto decode_success; -//.. } -//.. + + /* 66 0F EB = POR */ + if (have66noF2noF3(pfx) && sz == 2 + && insn[0] == 0x0F && insn[1] == 0xEB) { + delta = dis_SSE_E_to_G_all( pfx, delta+2, "por", Iop_OrV128 ); + 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; @@ -11081,15 +11147,16 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. putXMMReg(reg, mkexpr(dV)); //.. 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( delta+2, "psrlq", Iop_ShrN64x2 ); -//.. goto decode_success; -//.. } -//.. + + /* 66 0F 73 /2 ib = PSRLQ by immediate */ + if (have66noF2noF3(pfx) && sz == 2 + && insn[0] == 0x0F && insn[1] == 0x73 + && epartIsReg(insn[2]) + && gregLO3ofRM(insn[2]) == 2) { + delta = dis_SSE_shiftE_imm( pfx, 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 ); @@ -11132,14 +11199,15 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. 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 FB = PSUBQ */ + if (have66noF2noF3(pfx) && sz == 2 + && insn[0] == 0x0F && insn[1] == 0xFB) { + delta = dis_SSEint_E_to_G( pfx, 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, @@ -11238,14 +11306,14 @@ DisResult disInstr ( /*IN*/ Bool resteerOK, //.. Iop_InterleaveLO16x8, True ); //.. goto decode_success; //.. } -//.. -//.. /* 66 0F EF = PXOR */ -//.. if (sz == 2 && insn[0] == 0x0F && insn[1] == 0xEF) { -//.. delta = dis_SSE_E_to_G_all( sorb, delta+2, "pxor", Iop_Xor128 ); -//.. goto decode_success; -//.. } -//.. -//.. + + /* 66 0F EF = PXOR */ + if (have66noF2noF3(pfx) && sz == 2 + && insn[0] == 0x0F && insn[1] == 0xEF) { + delta = dis_SSE_E_to_G_all( pfx, delta+2, "pxor", Iop_XorV128 ); + goto decode_success; + } + //.. //-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */ //.. //-- if (insn[0] == 0x0F && insn[1] == 0xAE //.. //-- && (!epartIsReg(insn[2])) diff --git a/VEX/priv/host-amd64/hdefs.c b/VEX/priv/host-amd64/hdefs.c index 42ae32c8e2..d4a7f9585c 100644 --- a/VEX/priv/host-amd64/hdefs.c +++ b/VEX/priv/host-amd64/hdefs.c @@ -606,7 +606,7 @@ HChar* showAMD64SseOp ( AMD64SseOp op ) { //.. case Xsse_ADD8: return "paddb"; //.. case Xsse_ADD16: return "paddw"; //.. case Xsse_ADD32: return "paddd"; -//.. case Xsse_ADD64: return "paddq"; + case Asse_ADD64: return "paddq"; //.. case Xsse_QADD8U: return "paddusb"; //.. case Xsse_QADD16U: return "paddusw"; //.. case Xsse_QADD8S: return "paddsb"; @@ -614,7 +614,7 @@ HChar* showAMD64SseOp ( AMD64SseOp op ) { //.. case Xsse_SUB8: return "psubb"; //.. case Xsse_SUB16: return "psubw"; //.. case Xsse_SUB32: return "psubd"; -//.. case Xsse_SUB64: return "psubq"; + case Asse_SUB64: return "psubq"; //.. case Xsse_QSUB8U: return "psubusb"; //.. case Xsse_QSUB16U: return "psubusw"; //.. case Xsse_QSUB8S: return "psubsb"; @@ -630,7 +630,7 @@ HChar* showAMD64SseOp ( AMD64SseOp op ) { //.. case Xsse_MIN8U: return "pminub"; //.. case Xsse_CMPEQ8: return "pcmpeqb"; //.. case Xsse_CMPEQ16: return "pcmpeqw"; -//.. case Xsse_CMPEQ32: return "pcmpeqd"; + case Asse_CMPEQ32: return "pcmpeqd"; //.. case Xsse_CMPGT8S: return "pcmpgtb"; //.. case Xsse_CMPGT16S: return "pcmpgtw"; //.. case Xsse_CMPGT32S: return "pcmpgtd"; @@ -639,7 +639,7 @@ HChar* showAMD64SseOp ( AMD64SseOp op ) { //.. case Xsse_SHL64: return "psllq"; //.. case Xsse_SHR16: return "psrlw"; //.. case Xsse_SHR32: return "psrld"; -//.. case Xsse_SHR64: return "psrlq"; + case Asse_SHR64: return "psrlq"; //.. case Xsse_SAR16: return "psraw"; //.. case Xsse_SAR32: return "psrad"; //.. case Xsse_PACKSSD: return "packssdw"; @@ -1001,15 +1001,15 @@ AMD64Instr* AMD64Instr_SseCMov ( AMD64CondCode cond, HReg src, HReg dst ) { vassert(cond != Acc_ALWAYS); return i; } -//.. AMD64Instr* AMD64Instr_SseShuf ( Int order, HReg src, HReg dst ) { -//.. AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr)); -//.. i->tag = Xin_SseShuf; -//.. i->Xin.SseShuf.order = order; -//.. i->Xin.SseShuf.src = src; -//.. i->Xin.SseShuf.dst = dst; -//.. vassert(order >= 0 && order <= 0xFF); -//.. return i; -//.. } +AMD64Instr* AMD64Instr_SseShuf ( Int order, HReg src, HReg dst ) { + AMD64Instr* i = LibVEX_Alloc(sizeof(AMD64Instr)); + i->tag = Ain_SseShuf; + i->Ain.SseShuf.order = order; + i->Ain.SseShuf.src = src; + i->Ain.SseShuf.dst = dst; + vassert(order >= 0 && order <= 0xFF); + return i; +} void ppAMD64Instr ( AMD64Instr* i ) { @@ -1303,12 +1303,12 @@ void ppAMD64Instr ( AMD64Instr* i ) vex_printf(","); ppHRegAMD64(i->Ain.SseCMov.dst); return; -//.. case Xin_SseShuf: -//.. vex_printf("pshufd $0x%x,", i->Xin.SseShuf.order); -//.. ppHRegAMD64(i->Xin.SseShuf.src); -//.. vex_printf(","); -//.. ppHRegAMD64(i->Xin.SseShuf.dst); -//.. return; + case Ain_SseShuf: + vex_printf("pshufd $0x%x,", i->Ain.SseShuf.order); + ppHRegAMD64(i->Ain.SseShuf.src); + vex_printf(","); + ppHRegAMD64(i->Ain.SseShuf.dst); + return; default: vpanic("ppAMD64Instr"); @@ -1572,10 +1572,10 @@ void getRegUsage_AMD64Instr ( HRegUsage* u, AMD64Instr* i ) addHRegUse(u, HRmRead, i->Ain.SseCMov.src); addHRegUse(u, HRmModify, i->Ain.SseCMov.dst); return; -//.. case Xin_SseShuf: -//.. addHRegUse(u, HRmRead, i->Xin.SseShuf.src); -//.. addHRegUse(u, HRmWrite, i->Xin.SseShuf.dst); -//.. return; + case Ain_SseShuf: + addHRegUse(u, HRmRead, i->Ain.SseShuf.src); + addHRegUse(u, HRmWrite, i->Ain.SseShuf.dst); + return; default: ppAMD64Instr(i); vpanic("getRegUsage_AMD64Instr"); @@ -1737,10 +1737,10 @@ void mapRegs_AMD64Instr ( HRegRemap* m, AMD64Instr* i ) mapReg(m, &i->Ain.SseCMov.src); mapReg(m, &i->Ain.SseCMov.dst); return; -//.. case Xin_SseShuf: -//.. mapReg(m, &i->Xin.SseShuf.src); -//.. mapReg(m, &i->Xin.SseShuf.dst); -//.. return; + case Ain_SseShuf: + mapReg(m, &i->Ain.SseShuf.src); + mapReg(m, &i->Ain.SseShuf.dst); + return; default: ppAMD64Instr(i); vpanic("mapRegs_AMD64Instr"); @@ -3203,7 +3203,7 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i ) //.. case Xsse_ADD8: XX(0x66); XX(rex); XX(0x0F); XX(0xFC); break; //.. case Xsse_ADD16: XX(0x66); XX(rex); XX(0x0F); XX(0xFD); break; //.. case Xsse_ADD32: XX(0x66); XX(rex); XX(0x0F); XX(0xFE); break; -//.. case Xsse_ADD64: XX(0x66); XX(rex); XX(0x0F); XX(0xD4); break; + case Asse_ADD64: XX(0x66); XX(rex); XX(0x0F); XX(0xD4); break; //.. case Xsse_QADD8S: XX(0x66); XX(rex); XX(0x0F); XX(0xEC); break; //.. case Xsse_QADD16S: XX(0x66); XX(rex); XX(0x0F); XX(0xED); break; //.. case Xsse_QADD8U: XX(0x66); XX(rex); XX(0x0F); XX(0xDC); break; @@ -3212,7 +3212,7 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i ) //.. case Xsse_AVG16U: XX(0x66); XX(rex); XX(0x0F); XX(0xE3); break; //.. case Xsse_CMPEQ8: XX(0x66); XX(rex); XX(0x0F); XX(0x74); break; //.. case Xsse_CMPEQ16: XX(0x66); XX(rex); XX(0x0F); XX(0x75); break; -//.. case Xsse_CMPEQ32: XX(0x66); XX(rex); XX(0x0F); XX(0x76); break; + case Asse_CMPEQ32: XX(0x66); XX(rex); XX(0x0F); XX(0x76); break; //.. case Xsse_CMPGT8S: XX(0x66); XX(rex); XX(0x0F); XX(0x64); break; //.. case Xsse_CMPGT16S: XX(0x66); XX(rex); XX(0x0F); XX(0x65); break; //.. case Xsse_CMPGT32S: XX(0x66); XX(rex); XX(0x0F); XX(0x66); break; @@ -3230,11 +3230,11 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i ) //.. case Xsse_SAR32: XX(0x66); XX(rex); XX(0x0F); XX(0xE2); break; //.. case Xsse_SHR16: XX(0x66); XX(rex); XX(0x0F); XX(0xD1); break; //.. case Xsse_SHR32: XX(0x66); XX(rex); XX(0x0F); XX(0xD2); break; -//.. case Xsse_SHR64: XX(0x66); XX(rex); XX(0x0F); XX(0xD3); break; + case Asse_SHR64: XX(0x66); XX(rex); XX(0x0F); XX(0xD3); break; //.. case Xsse_SUB8: XX(0x66); XX(rex); XX(0x0F); XX(0xF8); break; //.. case Xsse_SUB16: XX(0x66); XX(rex); XX(0x0F); XX(0xF9); break; //.. case Xsse_SUB32: XX(0x66); XX(rex); XX(0x0F); XX(0xFA); break; -//.. case Xsse_SUB64: XX(0x66); XX(rex); XX(0x0F); XX(0xFB); break; + case Asse_SUB64: XX(0x66); XX(rex); XX(0x0F); XX(0xFB); break; //.. case Xsse_QSUB8S: XX(0x66); XX(rex); XX(0x0F); XX(0xE8); break; //.. case Xsse_QSUB16S: XX(0x66); XX(rex); XX(0x0F); XX(0xE9); break; //.. case Xsse_QSUB8U: XX(0x66); XX(rex); XX(0x0F); XX(0xD8); break; @@ -3273,15 +3273,18 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i ) *(ptmp-1) = toUChar(p - ptmp); goto done; -//.. case Xin_SseShuf: -//.. *p++ = 0x66; -//.. *p++ = 0x0F; -//.. *p++ = 0x70; -//.. p = doAMode_R(p, fake(vregNo(i->Xin.SseShuf.dst)), -//.. fake(vregNo(i->Xin.SseShuf.src)) ); -//.. *p++ = (UChar)(i->Xin.SseShuf.order); -//.. goto done; -//.. + case Ain_SseShuf: + *p++ = 0x66; + *p++ = clearWBit( + rexAMode_R( vreg2ireg(i->Ain.SseShuf.dst), + vreg2ireg(i->Ain.SseShuf.src) )); + *p++ = 0x0F; + *p++ = 0x70; + p = doAMode_R(p, vreg2ireg(i->Ain.SseShuf.dst), + vreg2ireg(i->Ain.SseShuf.src) ); + *p++ = (UChar)(i->Ain.SseShuf.order); + goto done; + default: goto bad; } diff --git a/VEX/priv/host-amd64/hdefs.h b/VEX/priv/host-amd64/hdefs.h index d7d5186aff..f66c937ddd 100644 --- a/VEX/priv/host-amd64/hdefs.h +++ b/VEX/priv/host-amd64/hdefs.h @@ -322,10 +322,12 @@ typedef /* Bitwise */ Asse_AND, Asse_OR, Asse_XOR, Asse_ANDN, //.. /* Integer binary */ -//.. Xsse_ADD8, Xsse_ADD16, Xsse_ADD32, Xsse_ADD64, +//.. Xsse_ADD8, Xsse_ADD16, Xsse_ADD32, + Asse_ADD64, //.. Xsse_QADD8U, Xsse_QADD16U, //.. Xsse_QADD8S, Xsse_QADD16S, -//.. Xsse_SUB8, Xsse_SUB16, Xsse_SUB32, Xsse_SUB64, +//.. Xsse_SUB8, Xsse_SUB16, Xsse_SUB32, + Asse_SUB64, //.. Xsse_QSUB8U, Xsse_QSUB16U, //.. Xsse_QSUB8S, Xsse_QSUB16S, //.. Xsse_MUL16, @@ -336,10 +338,12 @@ typedef //.. Xsse_MAX8U, //.. Xsse_MIN16S, //.. Xsse_MIN8U, -//.. Xsse_CMPEQ8, Xsse_CMPEQ16, Xsse_CMPEQ32, +//.. Xsse_CMPEQ8, Xsse_CMPEQ16, + Asse_CMPEQ32, //.. Xsse_CMPGT8S, Xsse_CMPGT16S, Xsse_CMPGT32S, //.. Xsse_SHL16, Xsse_SHL32, Xsse_SHL64, -//.. Xsse_SHR16, Xsse_SHR32, Xsse_SHR64, +//.. Xsse_SHR16, Xsse_SHR32, + Asse_SHR64, //.. Xsse_SAR16, Xsse_SAR32, //.. Xsse_PACKSSD, Xsse_PACKSSW, Xsse_PACKUSW, //.. Xsse_UNPCKHB, Xsse_UNPCKHW, Xsse_UNPCKHD, Xsse_UNPCKHQ, @@ -397,7 +401,7 @@ typedef Ain_Sse64FLo, /* SSE binary, 64F in lowest lane only */ Ain_SseReRg, /* SSE binary general reg-reg, Re, Rg */ Ain_SseCMov, /* SSE conditional move */ -//.. Xin_SseShuf /* SSE2 shuffle (pshufd) */ + Ain_SseShuf /* SSE2 shuffle (pshufd) */ } AMD64InstrTag; @@ -642,11 +646,11 @@ typedef HReg src; HReg dst; } SseCMov; -//.. struct { -//.. Int order; /* 0 <= order <= 0xFF */ -//.. HReg src; -//.. HReg dst; -//.. } SseShuf; + struct { + Int order; /* 0 <= order <= 0xFF */ + HReg src; + HReg dst; + } SseShuf; } Ain; } @@ -695,7 +699,7 @@ extern AMD64Instr* AMD64Instr_Sse64Fx2 ( AMD64SseOp, HReg, HReg ); extern AMD64Instr* AMD64Instr_Sse64FLo ( AMD64SseOp, HReg, HReg ); extern AMD64Instr* AMD64Instr_SseReRg ( AMD64SseOp, HReg, HReg ); extern AMD64Instr* AMD64Instr_SseCMov ( AMD64CondCode, HReg src, HReg dst ); -//.. extern AMD64Instr* AMD64Instr_SseShuf ( Int order, HReg src, HReg dst ); +extern AMD64Instr* AMD64Instr_SseShuf ( Int order, HReg src, HReg dst ); extern void ppAMD64Instr ( AMD64Instr* ); diff --git a/VEX/priv/host-amd64/isel.c b/VEX/priv/host-amd64/isel.c index 2ddd8c919c..1da246ace3 100644 --- a/VEX/priv/host-amd64/isel.c +++ b/VEX/priv/host-amd64/isel.c @@ -699,19 +699,16 @@ void set_SSE_rounding_mode ( ISelEnv* env, IRExpr* mode ) //.. } -/* Generate !src into a new vector register, and be sure that the code - is SSE1 compatible. Amazing that Intel doesn't offer a less crappy - way to do this. +/* Generate !src into a new vector register. Amazing that there isn't + a less crappy way to do this. */ static HReg do_sse_NotV128 ( ISelEnv* env, HReg src ) { HReg dst = newVRegV(env); - /* Set dst to zero. Not strictly necessary, but the idea of doing - a FP comparison on whatever junk happens to be floating around - in it is just too scary. */ + /* Set dst to zero. Not strictly necessary. */ addInstr(env, AMD64Instr_SseReRg(Asse_XOR, dst, dst)); /* And now make it all 1s ... */ - addInstr(env, AMD64Instr_Sse32Fx4(Asse_CMPEQF, dst, dst)); + addInstr(env, AMD64Instr_SseReRg(Asse_CMPEQ32, dst, dst)); /* Finally, xor 'src' into it. */ addInstr(env, AMD64Instr_SseReRg(Asse_XOR, src, dst)); return dst; @@ -3049,34 +3046,33 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) return do_sse_NotV128(env, arg); } -//.. case Iop_CmpNEZ64x2: { -//.. /* We can use SSE2 instructions for this. */ -//.. /* Ideally, we want to do a 64Ix2 comparison against zero of -//.. the operand. Problem is no such insn exists. Solution -//.. therefore is to do a 32Ix4 comparison instead, and bitwise- -//.. negate (NOT) the result. Let a,b,c,d be 32-bit lanes, and -//.. let the not'd result of this initial comparison be a:b:c:d. -//.. What we need to compute is (a|b):(a|b):(c|d):(c|d). So, use -//.. pshufd to create a value b:a:d:c, and OR that with a:b:c:d, -//.. giving the required result. -//.. -//.. The required selection sequence is 2,3,0,1, which -//.. according to Intel's documentation means the pshufd -//.. literal value is 0xB1, that is, -//.. (2 << 6) | (3 << 4) | (0 << 2) | (1 << 0) -//.. */ -//.. HReg arg = iselVecExpr(env, e->Iex.Unop.arg); -//.. HReg tmp = newVRegV(env); -//.. HReg dst = newVRegV(env); -//.. REQUIRE_SSE2; -//.. addInstr(env, X86Instr_SseReRg(Xsse_XOR, tmp, tmp)); -//.. addInstr(env, X86Instr_SseReRg(Xsse_CMPEQ32, arg, tmp)); -//.. tmp = do_sse_Not128(env, tmp); -//.. addInstr(env, X86Instr_SseShuf(0xB1, tmp, dst)); -//.. addInstr(env, X86Instr_SseReRg(Xsse_OR, tmp, dst)); -//.. return dst; -//.. } -//.. + case Iop_CmpNEZ64x2: { + /* We can use SSE2 instructions for this. */ + /* Ideally, we want to do a 64Ix2 comparison against zero of + the operand. Problem is no such insn exists. Solution + therefore is to do a 32Ix4 comparison instead, and bitwise- + negate (NOT) the result. Let a,b,c,d be 32-bit lanes, and + let the not'd result of this initial comparison be a:b:c:d. + What we need to compute is (a|b):(a|b):(c|d):(c|d). So, use + pshufd to create a value b:a:d:c, and OR that with a:b:c:d, + giving the required result. + + The required selection sequence is 2,3,0,1, which + according to Intel's documentation means the pshufd + literal value is 0xB1, that is, + (2 << 6) | (3 << 4) | (0 << 2) | (1 << 0) + */ + HReg arg = iselVecExpr(env, e->Iex.Unop.arg); + HReg tmp = newVRegV(env); + HReg dst = newVRegV(env); + addInstr(env, AMD64Instr_SseReRg(Asse_XOR, tmp, tmp)); + addInstr(env, AMD64Instr_SseReRg(Asse_CMPEQ32, arg, tmp)); + tmp = do_sse_NotV128(env, tmp); + addInstr(env, AMD64Instr_SseShuf(0xB1, tmp, dst)); + addInstr(env, AMD64Instr_SseReRg(Asse_OR, tmp, dst)); + return dst; + } + //.. case Iop_CmpNEZ32x4: { //.. /* Sigh, we have to generate lousy code since this has to //.. work on SSE1 hosts */ @@ -3355,7 +3351,7 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) //.. 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_Add64x2: op = Asse_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; @@ -3378,7 +3374,7 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) //.. 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_Sub64x2: op = Asse_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; @@ -3405,24 +3401,21 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) //.. 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); -//.. REQUIRE_SSE2; -//.. 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; -//.. } + case Iop_ShrN64x2: op = Asse_SHR64; goto do_SseShift; + do_SseShift: { + HReg greg = iselVecExpr(env, e->Iex.Binop.arg1); + AMD64RMI* rmi = iselIntExpr_RMI(env, e->Iex.Binop.arg2); + AMD64AMode* rsp0 = AMD64AMode_IR(0, hregAMD64_RSP()); + HReg ereg = newVRegV(env); + HReg dst = newVRegV(env); + addInstr(env, AMD64Instr_Push(AMD64RMI_Imm(0))); + addInstr(env, AMD64Instr_Push(rmi)); + addInstr(env, AMD64Instr_SseLdSt(True/*load*/, 16, ereg, rsp0)); + addInstr(env, mk_vMOVsd_RR(greg, dst)); + addInstr(env, AMD64Instr_SseReRg(op, ereg, dst)); + add_to_rsp(env, 16); + return dst; + } default: break;