From: Julian Seward Date: Mon, 9 May 2005 02:57:08 +0000 (+0000) Subject: Even more x87 instructions. X-Git-Tag: svn/VALGRIND_3_0_1^2~163 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5e893029980be4e1179573e1725bb1ce02931c06;p=thirdparty%2Fvalgrind.git Even more x87 instructions. git-svn-id: svn://svn.valgrind.org/vex/trunk@1171 --- diff --git a/VEX/priv/guest-amd64/gdefs.h b/VEX/priv/guest-amd64/gdefs.h index 80cc455fc8..77175cef5c 100644 --- a/VEX/priv/guest-amd64/gdefs.h +++ b/VEX/priv/guest-amd64/gdefs.h @@ -97,9 +97,9 @@ extern ULong amd64g_calculate_condition ( // UInt arg, UInt rot_amt, UInt eflags_in, UInt sz // ); -//extern ULong amd64g_check_fldcw ( ULong fpucw ); +extern ULong amd64g_check_fldcw ( ULong fpucw ); -//extern ULong amd64g_create_fpucw ( ULong fpround ); +extern ULong amd64g_create_fpucw ( ULong fpround ); extern ULong amd64g_check_ldmxcsr ( ULong mxcsr ); diff --git a/VEX/priv/guest-amd64/ghelpers.c b/VEX/priv/guest-amd64/ghelpers.c index abd672b1be..4685e78a22 100644 --- a/VEX/priv/guest-amd64/ghelpers.c +++ b/VEX/priv/guest-amd64/ghelpers.c @@ -1268,6 +1268,43 @@ ULong amd64g_create_mxcsr ( ULong sseround ) } +/* CLEAN HELPER */ +/* fpucw[15:0] contains a x87 native format FPU control word. + Extract from it the required FPROUND value and any resulting + emulation warning, and return (warn << 32) | fpround value. +*/ +ULong amd64g_check_fldcw ( ULong fpucw ) +{ + /* Decide on a rounding mode. fpucw[11:10] holds it. */ + /* NOTE, encoded exactly as per enum IRRoundingMode. */ + ULong rmode = (fpucw >> 10) & 3; + + /* Detect any required emulation warnings. */ + VexEmWarn ew = EmWarn_NONE; + + if ((fpucw & 0x3F) != 0x3F) { + /* unmasked exceptions! */ + ew = EmWarn_X86_x87exns; + } + else + if (((fpucw >> 8) & 3) != 3) { + /* unsupported precision */ + ew = EmWarn_X86_x87precision; + } + + return (((ULong)ew) << 32) | ((ULong)rmode); +} + + +/* CLEAN HELPER */ +/* Given fpround as an IRRoundingMode value, create a suitable x87 + native format FPU control word. */ +ULong amd64g_create_fpucw ( ULong fpround ) +{ + fpround &= 3; + return 0x037F | (fpround << 10); +} + /*---------------------------------------------------------------*/ /*--- Misc integer helpers, including rotates and CPUID. ---*/ diff --git a/VEX/priv/guest-amd64/toIR.c b/VEX/priv/guest-amd64/toIR.c index a87fb857b7..a51bcce102 100644 --- a/VEX/priv/guest-amd64/toIR.c +++ b/VEX/priv/guest-amd64/toIR.c @@ -4143,11 +4143,11 @@ static IRExpr* /* :: Ity_I32 */ get_fpround ( void ) return unop(Iop_64to32, IRExpr_Get( OFFB_FPROUND, Ity_I64 )); } -//.. static void put_fpround ( IRExpr* /* :: Ity_I32 */ e ) -//.. { -//.. vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32); -//.. stmt( IRStmt_Put( OFFB_FPROUND, unop(Iop_32Uto64,e) ) ); -//.. } +static void put_fpround ( IRExpr* /* :: Ity_I32 */ e ) +{ + vassert(typeOfIRExpr(irbb->tyenv, e) == Ity_I32); + stmt( IRStmt_Put( OFFB_FPROUND, unop(Iop_32Uto64,e) ) ); +} /* --------- Synthesise a 2-bit FPU rounding mode. --------- */ @@ -4617,47 +4617,47 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok, //.. DIP("fldenv %s\n", dis_buf); //.. break; //.. } -//.. -//.. case 5: {/* FLDCW */ -//.. /* The only thing we observe in the control word is the -//.. rounding mode. Therefore, pass the 16-bit value -//.. (x87 native-format control word) to a clean helper, -//.. getting back a 64-bit value, the lower half of which -//.. is the FPROUND value to store, and the upper half of -//.. which is the emulation-warning token which may be -//.. generated. -//.. */ -//.. /* ULong x86h_check_fldcw ( UInt ); */ -//.. IRTemp t64 = newTemp(Ity_I64); -//.. IRTemp ew = newTemp(Ity_I32); -//.. DIP("fldcw %s\n", dis_buf); -//.. assign( t64, mkIRExprCCall( -//.. Ity_I64, 0/*regparms*/, -//.. "x86g_check_fldcw", -//.. &x86g_check_fldcw, -//.. mkIRExprVec_1( -//.. unop( Iop_16Uto32, -//.. loadLE(Ity_I16, mkexpr(addr))) -//.. ) -//.. ) -//.. ); -//.. -//.. put_fpround( unop(Iop_64to32, mkexpr(t64)) ); -//.. assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) ); -//.. put_emwarn( mkexpr(ew) ); -//.. /* Finally, if an emulation warning was reported, -//.. side-exit to the next insn, reporting the warning, -//.. so that Valgrind's dispatcher sees the warning. */ -//.. stmt( -//.. IRStmt_Exit( -//.. binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)), -//.. Ijk_EmWarn, -//.. IRConst_U32( ((Addr32)guest_eip_bbstart)+delta) -//.. ) -//.. ); -//.. break; -//.. } -//.. + + case 5: {/* FLDCW */ + /* The only thing we observe in the control word is the + rounding mode. Therefore, pass the 16-bit value + (x87 native-format control word) to a clean helper, + getting back a 64-bit value, the lower half of which + is the FPROUND value to store, and the upper half of + which is the emulation-warning token which may be + generated. + */ + /* ULong amd64h_check_fldcw ( ULong ); */ + IRTemp t64 = newTemp(Ity_I64); + IRTemp ew = newTemp(Ity_I32); + DIP("fldcw %s\n", dis_buf); + assign( t64, mkIRExprCCall( + Ity_I64, 0/*regparms*/, + "amd64g_check_fldcw", + &amd64g_check_fldcw, + mkIRExprVec_1( + unop( Iop_16Uto64, + loadLE(Ity_I16, mkexpr(addr))) + ) + ) + ); + + put_fpround( unop(Iop_64to32, mkexpr(t64)) ); + assign( ew, unop(Iop_64HIto32, mkexpr(t64) ) ); + put_emwarn( mkexpr(ew) ); + /* Finally, if an emulation warning was reported, + side-exit to the next insn, reporting the warning, + so that Valgrind's dispatcher sees the warning. */ + stmt( + IRStmt_Exit( + binop(Iop_CmpNE32, mkexpr(ew), mkU32(0)), + Ijk_EmWarn, + IRConst_U64( guest_rip_bbstart+delta ) + ) + ); + break; + } + //.. case 6: { /* FNSTENV m28 */ //.. /* Uses dirty helper: //.. void x86g_do_FSTENV ( VexGuestX86State*, UInt ) */ @@ -4697,24 +4697,24 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok, //.. DIP("fnstenv %s\n", dis_buf); //.. break; //.. } -//.. -//.. case 7: /* FNSTCW */ -//.. /* Fake up a native x87 FPU control word. The only -//.. thing it depends on is FPROUND[1:0], so call a clean -//.. helper to cook it up. */ -//.. /* UInt x86h_create_fpucw ( UInt fpround ) */ -//.. DIP("fnstcw %s\n", dis_buf); -//.. storeLE( -//.. mkexpr(addr), -//.. unop( Iop_32to16, -//.. mkIRExprCCall( -//.. Ity_I32, 0/*regp*/, -//.. "x86g_create_fpucw", &x86g_create_fpucw, -//.. mkIRExprVec_1( get_fpround() ) -//.. ) -//.. ) -//.. ); -//.. break; + + case 7: /* FNSTCW */ + /* Fake up a native x87 FPU control word. The only + thing it depends on is FPROUND[1:0], so call a clean + helper to cook it up. */ + /* ULong x86h_create_fpucw ( ULong fpround ) */ + DIP("fnstcw %s\n", dis_buf); + storeLE( + mkexpr(addr), + unop( Iop_64to16, + mkIRExprCCall( + Ity_I64, 0/*regp*/, + "amd64g_create_fpucw", &amd64g_create_fpucw, + mkIRExprVec_1( unop(Iop_32Uto64, get_fpround()) ) + ) + ) + ); + break; default: vex_printf("unhandled opc_aux = 0x%2x\n", gregLO3ofRM(modrm)); @@ -4837,13 +4837,13 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok, fp_pop(); break; -//.. case 0xF2: /* FPTAN */ -//.. DIP("ftan\n"); -//.. put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0))); -//.. fp_push(); -//.. put_ST(0, IRExpr_Const(IRConst_F64(1.0))); -//.. clear_C2(); /* HACK */ -//.. break; + case 0xF2: /* FPTAN */ + DIP("ftan\n"); + put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0))); + fp_push(); + put_ST(0, IRExpr_Const(IRConst_F64(1.0))); + clear_C2(); /* HACK */ + break; case 0xF3: /* FPATAN */ DIP("fpatan\n"); @@ -4885,12 +4885,12 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok, //.. break; //.. } //.. -//.. case 0xF9: /* FYL2XP1 */ -//.. DIP("fyl2xp1\n"); -//.. put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64, -//.. get_ST(1), get_ST(0))); -//.. fp_pop(); -//.. break; + case 0xF9: /* FYL2XP1 */ + DIP("fyl2xp1\n"); + put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64, + get_ST(1), get_ST(0))); + fp_pop(); + break; case 0xFA: /* FSQRT */ DIP("fsqrt\n"); diff --git a/VEX/priv/host-amd64/hdefs.c b/VEX/priv/host-amd64/hdefs.c index 90c65c61c2..1652599a99 100644 --- a/VEX/priv/host-amd64/hdefs.c +++ b/VEX/priv/host-amd64/hdefs.c @@ -567,7 +567,7 @@ HChar* showA87FpOp ( A87FpOp op ) { case Afp_SCALE: return "scale"; case Afp_ATAN: return "atan"; case Afp_YL2X: return "yl2x"; -//.. case Xfp_YL2XP1: return "yl2xp1"; + case Afp_YL2XP1: return "yl2xp1"; //.. case Xfp_PREM: return "prem"; //.. case Xfp_PREM1: return "prem1"; case Afp_SQRT: return "sqrt"; @@ -576,7 +576,7 @@ HChar* showA87FpOp ( A87FpOp op ) { //.. case Xfp_MOV: return "mov"; case Afp_SIN: return "sin"; case Afp_COS: return "cos"; -//.. case Xfp_TAN: return "tan"; + case Afp_TAN: return "tan"; case Afp_ROUND: return "round"; case Afp_2XM1: return "2xm1"; default: vpanic("showA87FpOp"); @@ -2836,14 +2836,16 @@ Int emit_AMD64Instr ( UChar* buf, Int nbuf, AMD64Instr* i ) case Ain_A87FpOp: switch (i->Ain.A87FpOp.op) { - case Afp_SQRT: *p++ = 0xD9; *p++ = 0xFA; break; - case Afp_SIN: *p++ = 0xD9; *p++ = 0xFE; break; - case Afp_COS: *p++ = 0xD9; *p++ = 0xFF; break; - case Afp_ROUND: *p++ = 0xD9; *p++ = 0xFC; break; - case Afp_2XM1: *p++ = 0xD9; *p++ = 0xF0; break; - case Afp_SCALE: *p++ = 0xD9; *p++ = 0xFD; break; - case Afp_ATAN: *p++ = 0xD9; *p++ = 0xF3; break; - case Afp_YL2X: *p++ = 0xD9; *p++ = 0xF1; break; + case Afp_SQRT: *p++ = 0xD9; *p++ = 0xFA; break; + case Afp_SIN: *p++ = 0xD9; *p++ = 0xFE; break; + case Afp_COS: *p++ = 0xD9; *p++ = 0xFF; break; + case Afp_TAN: *p++ = 0xD9; *p++ = 0xF2; break; + case Afp_ROUND: *p++ = 0xD9; *p++ = 0xFC; break; + case Afp_2XM1: *p++ = 0xD9; *p++ = 0xF0; break; + case Afp_SCALE: *p++ = 0xD9; *p++ = 0xFD; break; + case Afp_ATAN: *p++ = 0xD9; *p++ = 0xF3; break; + case Afp_YL2X: *p++ = 0xD9; *p++ = 0xF1; break; + case Afp_YL2XP1: *p++ = 0xD9; *p++ = 0xF9; break; default: goto bad; } goto done; diff --git a/VEX/priv/host-amd64/hdefs.h b/VEX/priv/host-amd64/hdefs.h index 5507785b1c..9df3f3ea0c 100644 --- a/VEX/priv/host-amd64/hdefs.h +++ b/VEX/priv/host-amd64/hdefs.h @@ -297,10 +297,10 @@ typedef Afp_INVALID, /* Binary */ //.. Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV, - Afp_SCALE, Afp_ATAN, Afp_YL2X, //Xfp_YL2XP1, Xfp_PREM, Xfp_PREM1, + Afp_SCALE, Afp_ATAN, Afp_YL2X, Afp_YL2XP1, //Xfp_PREM, Xfp_PREM1, /* Unary */ Afp_SQRT, //Xfp_ABS, Xfp_NEG, Xfp_MOV, - Afp_SIN, Afp_COS, //Xfp_TAN, + Afp_SIN, Afp_COS, Afp_TAN, Afp_ROUND, Afp_2XM1 } A87FpOp; diff --git a/VEX/priv/host-amd64/isel.c b/VEX/priv/host-amd64/isel.c index 3b15c4a700..ccf3b41c49 100644 --- a/VEX/priv/host-amd64/isel.c +++ b/VEX/priv/host-amd64/isel.c @@ -2838,7 +2838,8 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) if (e->tag == Iex_Binop && (e->Iex.Binop.op == Iop_ScaleF64 || e->Iex.Binop.op == Iop_AtanF64 - || e->Iex.Binop.op == Iop_Yl2xF64) + || e->Iex.Binop.op == Iop_Yl2xF64 + || e->Iex.Binop.op == Iop_Yl2xp1F64) ) { AMD64AMode* m8_rsp = AMD64AMode_IR(-8, hregAMD64_RSP()); HReg arg1 = iselDblExpr(env, e->Iex.Binop.arg1); @@ -2868,6 +2869,9 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) case Iop_Yl2xF64: addInstr(env, AMD64Instr_A87FpOp(Afp_YL2X)); break; + case Iop_Yl2xp1F64: + addInstr(env, AMD64Instr_A87FpOp(Afp_YL2XP1)); + break; default: vassert(0); } @@ -2927,9 +2931,9 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) //.. case Iop_NegF64: fpop = Xfp_NEG; break; //.. case Iop_AbsF64: fpop = Xfp_ABS; break; case Iop_SqrtF64: fpop = Afp_SQRT; break; - case Iop_SinF64: fpop = Afp_SIN; break; - case Iop_CosF64: fpop = Afp_COS; break; -//.. case Iop_TanF64: fpop = Xfp_TAN; break; + case Iop_SinF64: fpop = Afp_SIN; break; + case Iop_CosF64: fpop = Afp_COS; break; + case Iop_TanF64: fpop = Afp_TAN; break; case Iop_2xm1F64: fpop = Afp_2XM1; break; default: break; } @@ -2937,10 +2941,15 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) AMD64AMode* m8_rsp = AMD64AMode_IR(-8, hregAMD64_RSP()); HReg arg = iselDblExpr(env, e->Iex.Unop.arg); HReg dst = newVRegV(env); + Int nNeeded = e->Iex.Unop.op==Iop_TanF64 ? 2 : 1; addInstr(env, AMD64Instr_SseLdSt(False/*store*/, 8, arg, m8_rsp)); - addInstr(env, AMD64Instr_A87Free(1)); + addInstr(env, AMD64Instr_A87Free(nNeeded)); addInstr(env, AMD64Instr_A87PushPop(m8_rsp, True/*push*/)); addInstr(env, AMD64Instr_A87FpOp(fpop)); + if (e->Iex.Unop.op==Iop_TanF64) { + /* get rid of the extra 1.0 that fptan pushes */ + addInstr(env, AMD64Instr_A87PushPop(m8_rsp, False/*pop*/)); + } addInstr(env, AMD64Instr_A87PushPop(m8_rsp, False/*pop*/)); addInstr(env, AMD64Instr_SseLdSt(True/*load*/, 8, dst, m8_rsp)); return dst;