From: Julian Seward Date: Wed, 8 Dec 2004 14:37:10 +0000 (+0000) Subject: x86 guest: finish SSE2 floating point insns. X-Git-Tag: svn/VALGRIND_3_0_1^2~700 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b4c4fd0ab97197d8581b1d31e4fe58f8eef9e4d9;p=thirdparty%2Fvalgrind.git x86 guest: finish SSE2 floating point insns. git-svn-id: svn://svn.valgrind.org/vex/trunk@634 --- diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 05913d0a19..987765843e 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -7101,6 +7101,48 @@ 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 ( + UChar sorb, UInt delta, + HChar* opname, IROp op + ) +{ + /* First we need to get the old G value and patch the low 64 bits + of the E operand into it. Then apply op and write back to G. */ + HChar dis_buf[50]; + Int alen; + IRTemp addr; + UChar rm = getIByte(delta); + IRTemp oldG0 = newTemp(Ity_V128); + IRTemp oldG1 = newTemp(Ity_V128); + + assign( oldG0, getXMMReg(gregOfRM(rm)) ); + + if (epartIsReg(rm)) { + assign( oldG1, + binop( Iop_Set128lo64, + mkexpr(oldG0), + getXMMRegLane64(eregOfRM(rm), 0)) ); + putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) ); + DIP("%s %s,%s\n", opname, + nameXMMReg(eregOfRM(rm)), + nameXMMReg(gregOfRM(rm)) ); + return delta+1; + } else { + addr = disAMode ( &alen, sorb, delta, dis_buf ); + assign( oldG1, + binop( Iop_Set128lo64, + mkexpr(oldG0), + loadLE(Ity_I64, mkexpr(addr)) )); + putXMMReg( gregOfRM(rm), unop(op, mkexpr(oldG1)) ); + DIP("%s %s,%s\n", opname, + dis_buf, + nameXMMReg(gregOfRM(rm)) ); + return delta+alen; + } +} + /* Helper for doing SSE FP comparisons. */ static void findSSECmpOp ( Bool* needNot, IROp* op, @@ -7925,8 +7967,7 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, } /* 0F 59 = MULPS -- mul 32Fx4 from R/M to R */ - if (insn[0] == 0x0F && insn[1] == 0x59) { - vassert(sz == 4); + if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x59) { delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulps", Iop_Mul32Fx4 ); goto decode_success; } @@ -7939,8 +7980,7 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, } /* 0F 56 = ORPS -- G = G and E */ - if (insn[0] == 0x0F && insn[1] == 0x56) { - vassert(sz == 4); + if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x56) { delta = dis_SSE_E_to_G_all( sorb, delta+2, "orps", Iop_Or128 ); goto decode_success; } @@ -8282,14 +8322,13 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, } /* 0F C6 /r ib = SHUFPS -- shuffle packed F32s */ - if (insn[0] == 0x0F && insn[1] == 0xC6) { + if (sz == 4 && insn[0] == 0x0F && insn[1] == 0xC6) { Int select; IRTemp sV, dV; IRTemp s3, s2, s1, s0, d3, d2, d1, d0; sV = newTemp(Ity_V128); dV = newTemp(Ity_V128); s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID; - vassert(sz == 4); modrm = insn[2]; assign( dV, getXMMReg(gregOfRM(modrm)) ); @@ -8329,8 +8368,7 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, } /* 0F 51 = SQRTPS -- approx sqrt 32Fx4 from R/M to R */ - if (insn[0] == 0x0F && insn[1] == 0x51) { - vassert(sz == 4); + if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x51) { delta = dis_SSE_E_to_G_unary_all( sorb, delta+2, "sqrtps", Iop_Sqrt32Fx4 ); goto decode_success; @@ -8370,13 +8408,12 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, } /* 0F 5C = SUBPS -- sub 32Fx4 from R/M to R */ - if (insn[0] == 0x0F && insn[1] == 0x5C) { - vassert(sz == 4); + if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x5C) { delta = dis_SSE_E_to_G_all( sorb, delta+2, "subps", Iop_Sub32Fx4 ); goto decode_success; } - /* F3 0F 58 = SUBSS -- sub 32F0x4 from R/M to R */ + /* F3 0F 5C = SUBSS -- sub 32F0x4 from R/M to R */ if (insn[0] == 0xF3 && insn[1] == 0x0F && insn[2] == 0x5C) { vassert(sz == 4); delta = dis_SSE_E_to_G_lo32( sorb, delta+3, "subss", Iop_Sub32F0x4 ); @@ -8386,14 +8423,13 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, /* 0F 15 = UNPCKHPS -- unpack and interleave high part F32s */ /* 0F 14 = UNPCKLPS -- unpack and interleave low part F32s */ /* These just appear to be special cases of SHUFPS */ - if (insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) { + if (sz == 4 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) { IRTemp sV, dV; IRTemp s3, s2, s1, s0, d3, d2, d1, d0; Bool hi = insn[1] == 0x15; sV = newTemp(Ity_V128); dV = newTemp(Ity_V128); s3 = s2 = s1 = s0 = d3 = d2 = d1 = d0 = IRTemp_INVALID; - vassert(sz == 4); modrm = insn[2]; assign( dV, getXMMReg(gregOfRM(modrm)) ); @@ -8425,8 +8461,7 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, } /* 0F 57 = XORPS -- G = G and E */ - if (insn[0] == 0x0F && insn[1] == 0x57) { - vassert(sz == 4); + if (sz == 4 && insn[0] == 0x0F && insn[1] == 0x57) { delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorps", Iop_Xor128 ); goto decode_success; } @@ -9413,6 +9448,153 @@ static DisResult disInstr ( /*IN*/ Bool resteerOK, } } + /* 66 0F 59 = MULPD -- mul 64Fx2 from R/M to R */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x59) { + delta = dis_SSE_E_to_G_all( sorb, delta+2, "mulpd", Iop_Mul64Fx2 ); + goto decode_success; + } + + /* F2 0F 59 = MULSD -- mul 64F0x2 from R/M to R */ + if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x59) { + vassert(sz == 4); + delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "mulsd", Iop_Mul64F0x2 ); + goto decode_success; + } + + /* 66 0F 56 = ORPD -- G = G and E */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x56) { + delta = dis_SSE_E_to_G_all( sorb, delta+2, "orpd", Iop_Or128 ); + 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 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, + "sqrtpd", Iop_Sqrt64Fx2 ); + goto decode_success; + } + + /* F2 0F 51 = SQRTSD -- approx sqrt 64F0x2 from R/M to R */ + if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x51) { + vassert(sz == 4); + delta = dis_SSE_E_to_G_unary_lo64( sorb, delta+3, + "sqrtsd", Iop_Sqrt64F0x2 ); + goto decode_success; + } + + /* 66 0F 5C = SUBPD -- sub 64Fx2 from R/M to R */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x5C) { + delta = dis_SSE_E_to_G_all( sorb, delta+2, "subpd", Iop_Sub64Fx2 ); + goto decode_success; + } + + /* F2 0F 5C = SUBSD -- sub 64F0x2 from R/M to R */ + if (insn[0] == 0xF2 && insn[1] == 0x0F && insn[2] == 0x5C) { + vassert(sz == 4); + delta = dis_SSE_E_to_G_lo64( sorb, delta+3, "subsd", Iop_Sub64F0x2 ); + goto decode_success; + } + + /* 66 0F 15 = UNPCKHPD -- unpack and interleave high part F64s */ + /* 66 0F 14 = UNPCKLPD -- unpack and interleave low part F64s */ + /* These just appear to be special cases of SHUFPS */ + if (sz == 2 && insn[0] == 0x0F && (insn[1] == 0x15 || insn[1] == 0x14)) { + IRTemp s1 = newTemp(Ity_I64); + IRTemp s0 = newTemp(Ity_I64); + IRTemp d1 = newTemp(Ity_I64); + IRTemp d0 = newTemp(Ity_I64); + IRTemp sV = newTemp(Ity_V128); + IRTemp dV = newTemp(Ity_V128); + Bool hi = insn[1] == 0x15; + + modrm = insn[2]; + assign( dV, getXMMReg(gregOfRM(modrm)) ); + + if (epartIsReg(modrm)) { + assign( sV, getXMMReg(eregOfRM(modrm)) ); + delta += 2+1; + DIP("unpck%sps %s,%s\n", hi ? "h" : "l", + nameXMMReg(eregOfRM(modrm)), + nameXMMReg(gregOfRM(modrm))); + } else { + addr = disAMode ( &alen, sorb, delta+2, dis_buf ); + assign( sV, loadLE(Ity_V128, mkexpr(addr)) ); + delta += 2+alen; + DIP("unpck%sps %s,%s\n", hi ? "h" : "l", + 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)) ); + + if (hi) { + putXMMReg( gregOfRM(modrm), + binop(Iop_64HLto128, mkexpr(s1), mkexpr(d1)) ); + } else { + putXMMReg( gregOfRM(modrm), + binop(Iop_64HLto128, mkexpr(s0), mkexpr(d0)) ); + } + + goto decode_success; + } + + /* 66 0F 57 = XORPD -- G = G and E */ + if (sz == 2 && insn[0] == 0x0F && insn[1] == 0x57) { + delta = dis_SSE_E_to_G_all( sorb, delta+2, "xorpd", Iop_Xor128 ); + goto decode_success; + } //-- //-- /* FXSAVE/FXRSTOR m32 -- load/store the FPU/MMX/SSE state. */ diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index fb50ee6d23..b0ab1c5b52 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -2550,6 +2550,22 @@ static HReg iselVecExpr_wrk ( ISelEnv* env, IRExpr* e ) return dst; } + case Iop_Set128lo64: { + HReg dst = newVRegV(env); + HReg srcV = iselVecExpr(env, e->Iex.Binop.arg1); + HReg srcIhi, srcIlo; + X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); + X86AMode* esp4 = advance4(esp0); + iselInt64Expr(&srcIhi, &srcIlo, env, e->Iex.Binop.arg2); + sub_from_esp(env, 16); + addInstr(env, X86Instr_SseLdSt(False/*store*/, srcV, esp0)); + addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(srcIlo), esp0)); + addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(srcIhi), esp4)); + addInstr(env, X86Instr_SseLdSt(True/*load*/, dst, esp0)); + add_to_esp(env, 16); + return dst; + } + case Iop_64HLto128: { HReg r3, r2, r1, r0; X86AMode* esp0 = X86AMode_IR(0, hregX86_ESP()); diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index 85069b337f..767f8003b0 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -297,6 +297,7 @@ void ppIROp ( IROp op ) case Iop_32Uto128: vex_printf("32Uto128"); return; case Iop_64Uto128: vex_printf("64Uto128"); return; case Iop_Set128lo32: vex_printf("Set128lo32"); return; + case Iop_Set128lo64: vex_printf("Set128lo64"); return; default: vpanic("ppIROp(1)"); } @@ -1159,6 +1160,7 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) case Iop_32Uto128: UNARY(Ity_V128, Ity_I32); case Iop_64Uto128: UNARY(Ity_V128, Ity_I64); case Iop_Set128lo32: BINARY(Ity_V128, Ity_V128,Ity_I32); + case Iop_Set128lo64: BINARY(Ity_V128, Ity_V128,Ity_I64); case Iop_CmpEQ32Fx4: case Iop_CmpLT32Fx4: case Iop_CmpEQ64Fx2: case Iop_CmpLT64Fx2: diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index f0644764e6..6c7751f24d 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -388,6 +388,7 @@ typedef Iop_32Uto128, Iop_64Uto128, Iop_Set128lo32, + Iop_Set128lo64, /* 128 -> 32 bit unpack */ //Iop_128W3to32, // :: V128 -> I32, bits 127-96 //Iop_128W2to32, // :: V128 -> I32, bits 95-64