From: Julian Seward Date: Fri, 15 Oct 2004 22:57:13 +0000 (+0000) Subject: Implement IEEE754-compliant fprem1. X-Git-Tag: svn/VALGRIND_3_0_1^2~980 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bba0f58236f487ec0ea613f55ec9f1f33ce5ae23;p=thirdparty%2Fvalgrind.git Implement IEEE754-compliant fprem1. git-svn-id: svn://svn.valgrind.org/vex/trunk@354 --- diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index d1757d58b5..82c6175e35 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -3529,6 +3529,20 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) fp_pop(); break; + case 0xF5: { /* FPREM1 -- IEEE compliant */ + IRTemp a1 = newTemp(Ity_F64); + IRTemp a2 = newTemp(Ity_F64); + DIP("fprem1\n"); + /* Do FPREM1 twice, once to get the remainder, and once + to get the C3210 flag values. */ + assign( a1, get_ST(0) ); + assign( a2, get_ST(1) ); + put_ST_UNCHECKED(0, binop(Iop_PRem1F64, + mkexpr(a1), mkexpr(a2))); + put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) ); + break; + } + case 0xF8: { /* FPREM -- not IEEE compliant */ IRTemp a1 = newTemp(Ity_F64); IRTemp a2 = newTemp(Ity_F64); diff --git a/VEX/priv/host-x86/hdefs.c b/VEX/priv/host-x86/hdefs.c index 7be97274ff..c79e490c2b 100644 --- a/VEX/priv/host-x86/hdefs.c +++ b/VEX/priv/host-x86/hdefs.c @@ -427,6 +427,8 @@ Char* showX86FpOp ( X86FpOp op ) { case Xfp_TAN: return "tan"; case Xfp_2XM1: return "2xm1"; case Xfp_ATAN: return "atan"; + case Xfp_PREM: return "prem"; + case Xfp_PREM1: return "prem1"; default: vpanic("showX86FpOp"); } } @@ -1878,17 +1880,23 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) goto done; } if (i->Xin.FpBinary.op == Xfp_PREM + || i->Xin.FpBinary.op == Xfp_PREM1 || i->Xin.FpBinary.op == Xfp_SCALE) { /* Have to do this specially. */ /* ffree %st7 ; fld %st(srcR) ; - ffree %st7 ; fld %st(srcL+1) ; fprem/fscale ; fstp(2+dst) ; + ffree %st7 ; fld %st(srcL+1) ; fprem/fprem1/fscale ; fstp(2+dst) ; fincstp ; ffree %st7 */ p = do_ffree_st7(p); p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcR)); p = do_ffree_st7(p); p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcL)); - *p++ = 0xD9; - *p++ = i->Xin.FpBinary.op==Xfp_PREM ? 0xF8 : 0xFD; + *p++ = 0xD9; + switch (i->Xin.FpBinary.op) { + case Xfp_PREM: *p++ = 0xF8; break; + case Xfp_PREM1: *p++ = 0xF5; break; + case Xfp_SCALE: *p++ = 0xFD; break; + default: vpanic("emitX86Instr(FpBinary,PREM/PREM1/SCALE)"); + } p = do_fstp_st(p, 2+hregNumber(i->Xin.FpBinary.dst)); *p++ = 0xD9; *p++ = 0xF7; p = do_ffree_st7(p); diff --git a/VEX/priv/host-x86/hdefs.h b/VEX/priv/host-x86/hdefs.h index 9c47410301..12a6fb8a0a 100644 --- a/VEX/priv/host-x86/hdefs.h +++ b/VEX/priv/host-x86/hdefs.h @@ -248,7 +248,7 @@ typedef Xfp_INVALID, /* Binary */ Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV, - Xfp_SCALE, Xfp_ATAN, Xfp_YL2X, Xfp_YL2XP1, Xfp_PREM, + Xfp_SCALE, Xfp_ATAN, Xfp_YL2X, Xfp_YL2XP1, Xfp_PREM, Xfp_PREM1, /* Unary */ Xfp_SQRT, Xfp_ABS, Xfp_NEG, Xfp_MOV, Xfp_SIN, Xfp_COS, Xfp_TAN, Xfp_ROUND, Xfp_2XM1 diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index b302f9b2a8..4421ed4b11 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -664,13 +664,18 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e ) return dst; } - /* C3210 flags following FPU partial remainder (fprem). */ - if (e->Iex.Binop.op == Iop_PRemC3210F64) { + /* C3210 flags following FPU partial remainder (fprem), both + IEEE compliant (PREM1) and non-IEEE compliant (PREM). */ + if (e->Iex.Binop.op == Iop_PRemC3210F64 + || e->Iex.Binop.op == Iop_PRem1C3210F64) { HReg junk = newVRegF(env); HReg dst = newVRegI(env); HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1); HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2); - addInstr(env, X86Instr_FpBinary(Xfp_PREM,srcL,srcR,junk)); + addInstr(env, X86Instr_FpBinary( + e->Iex.Binop.op==Iop_PRemC3210F64 ? Xfp_PREM : Xfp_PREM1, + srcL,srcR,junk + )); /* The previous pseudo-insn will have left the FPU's C3210 flags set correctly. So bag them. */ addInstr(env, X86Instr_FpStSW_AX()); @@ -1786,6 +1791,7 @@ static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ) case Iop_Yl2xF64: fpop = Xfp_YL2X; break; case Iop_Yl2xp1F64: fpop = Xfp_YL2XP1; break; case Iop_PRemF64: fpop = Xfp_PREM; break; + case Iop_PRem1F64: fpop = Xfp_PREM1; break; default: break; } if (fpop != Xfp_INVALID) { diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index 2c3377e969..162ec50f2a 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -145,14 +145,16 @@ void ppIROp ( IROp op ) case Iop_MulF64: vex_printf("MulF64"); return; case Iop_DivF64: vex_printf("DivF64"); return; - case Iop_ScaleF64: vex_printf("ScaleF64"); return; - case Iop_AtanF64: vex_printf("AtanF64"); return; - case Iop_Yl2xF64: vex_printf("Yl2xF64"); return; - case Iop_Yl2xp1F64: vex_printf("Yl2xp1F64"); return; - case Iop_PRemF64: vex_printf("PRemF64"); return; - case Iop_PRemC3210F64: vex_printf("PRemC3210F64"); return; - case Iop_NegF64: vex_printf("NegF64"); return; - case Iop_SqrtF64: vex_printf("SqrtF64"); return; + case Iop_ScaleF64: vex_printf("ScaleF64"); return; + case Iop_AtanF64: vex_printf("AtanF64"); return; + case Iop_Yl2xF64: vex_printf("Yl2xF64"); return; + case Iop_Yl2xp1F64: vex_printf("Yl2xp1F64"); return; + case Iop_PRemF64: vex_printf("PRemF64"); return; + case Iop_PRemC3210F64: vex_printf("PRemC3210F64"); return; + case Iop_PRem1F64: vex_printf("PRem1F64"); return; + case Iop_PRem1C3210F64: vex_printf("PRem1C3210F64"); return; + case Iop_NegF64: vex_printf("NegF64"); return; + case Iop_SqrtF64: vex_printf("SqrtF64"); return; case Iop_AbsF64: vex_printf("AbsF64"); return; case Iop_SinF64: vex_printf("SinF64"); return; @@ -903,11 +905,11 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) case Iop_32to8: UNARY(Ity_I8,Ity_I32); - case Iop_ScaleF64: case Iop_PRemF64: + case Iop_ScaleF64: case Iop_PRemF64: case Iop_PRem1F64: case Iop_AtanF64: case Iop_Yl2xF64: case Iop_Yl2xp1F64: case Iop_AddF64: case Iop_SubF64: case Iop_MulF64: case Iop_DivF64: BINARY(Ity_F64,Ity_F64,Ity_F64); - case Iop_PRemC3210F64: + case Iop_PRemC3210F64: case Iop_PRem1C3210F64: case Iop_CmpF64: BINARY(Ity_I32,Ity_F64,Ity_F64); case Iop_NegF64: case Iop_AbsF64: case Iop_SqrtF64: diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index e617237b4c..bc2e880420 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -173,12 +173,17 @@ typedef Iop_AddF64, Iop_SubF64, Iop_MulF64, Iop_DivF64, /* Iop_RemF64, */ /* Binary ops supported by IA32 but not mandated by 754. */ - Iop_AtanF64, /* FPATAN, arctan(arg1/arg2) */ - Iop_Yl2xF64, /* FYL2X, arg1 * log2(arg2) */ - Iop_Yl2xp1F64, /* FYL2XP1, arg1 * log2(arg2+1.0) */ - Iop_PRemF64, /* FPREM, remainder(arg1/arg2) */ - Iop_PRemC3210F64, /* C3210 flags resulting from FPREM, :: I32 */ - Iop_ScaleF64, /* FSCALE, arg1 * (2^RoundTowardsZero(arg2)) */ + Iop_AtanF64, /* FPATAN, arctan(arg1/arg2) */ + Iop_Yl2xF64, /* FYL2X, arg1 * log2(arg2) */ + Iop_Yl2xp1F64, /* FYL2XP1, arg1 * log2(arg2+1.0) */ + Iop_PRemF64, /* FPREM, non-IEEE remainder(arg1/arg2) */ + Iop_PRemC3210F64, /* C3210 flags resulting from FPREM, :: I32 */ + Iop_PRem1F64, /* FPREM1, IEEE remainder(arg1/arg2) */ + Iop_PRem1C3210F64, /* C3210 flags resulting from FPREM1, :: I32 */ + Iop_ScaleF64, /* FSCALE, arg1 * (2^RoundTowardsZero(arg2)) */ + /* Note that on x86 guest, PRem1{C3210} has the same behaviour + as the IEEE mandated RemF64, except it is limited in the + range of its operand. Hence the partialness. */ /* Unary operations mandated by IEEE754. */ Iop_NegF64, Iop_SqrtF64,