From: Julian Seward Date: Sat, 11 Sep 2004 19:23:24 +0000 (+0000) Subject: x86: implement FPREM (sigh, nasty, complicated) X-Git-Tag: svn/VALGRIND_3_0_1^2~1076 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f16efe4f64b5e141161d45aa39a9dd8bc90b071d;p=thirdparty%2Fvalgrind.git x86: implement FPREM (sigh, nasty, complicated) git-svn-id: svn://svn.valgrind.org/vex/trunk@258 --- diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 745f48cc09..79edaa7dc5 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -3580,6 +3580,20 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) fp_pop(); break; + case 0xF8: { /* FPREM -- not IEEE compliant */ + IRTemp a1 = newTemp(Ity_F64); + IRTemp a2 = newTemp(Ity_F64); + DIP("fprem\n"); + /* Do FPREM 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_PRemF64, + mkexpr(a1), mkexpr(a2))); + put_C3210( binop(Iop_PRemC3210F64, mkexpr(a1), mkexpr(a2)) ); + break; + } + case 0xFA: /* FSQRT */ DIP("fsqrt\n"); put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0))); diff --git a/VEX/priv/host-x86/hdefs.c b/VEX/priv/host-x86/hdefs.c index e205de301b..02bf85ce7d 100644 --- a/VEX/priv/host-x86/hdefs.c +++ b/VEX/priv/host-x86/hdefs.c @@ -610,6 +610,12 @@ X86Instr* X86Instr_FpLdStCW ( Bool isLoad, X86AMode* addr ) i->Xin.FpLdStCW.addr = addr; return i; } +X86Instr* X86Instr_FpStSW_AX ( void ) +{ + X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); + i->tag = Xin_FpStSW_AX; + return i; +} X86Instr* X86Instr_FpCmp ( HReg srcL, HReg srcR, HReg dst ) { X86Instr* i = LibVEX_Alloc(sizeof(X86Instr)); @@ -783,6 +789,9 @@ void ppX86Instr ( X86Instr* i ) { vex_printf(i->Xin.FpLdStCW.isLoad ? "fldcw " : "fstcw "); ppX86AMode(i->Xin.FpLdStCW.addr); return; + case Xin_FpStSW_AX: + vex_printf("fstsw %%ax"); + return; case Xin_FpCmp: vex_printf("gcmp "); ppHRegX86(i->Xin.FpCmp.srcL); @@ -910,6 +919,9 @@ void getRegUsage_X86Instr (HRegUsage* u, X86Instr* i) case Xin_FpLdStCW: addRegUsage_X86AMode(u, i->Xin.FpLdStCW.addr); return; + case Xin_FpStSW_AX: + addHRegUse(u, HRmWrite, hregX86_EAX()); + return; case Xin_FpCmp: addHRegUse(u, HRmRead, i->Xin.FpCmp.srcL); addHRegUse(u, HRmRead, i->Xin.FpCmp.srcR); @@ -1011,6 +1023,8 @@ void mapRegs_X86Instr (HRegRemap* m, X86Instr* i) case Xin_FpLdStCW: mapRegs_X86AMode(m, i->Xin.FpLdStCW.addr); return; + case Xin_FpStSW_AX: + return; case Xin_FpCmp: mapReg(m, &i->Xin.FpCmp.srcL); mapReg(m, &i->Xin.FpCmp.srcR); @@ -1822,14 +1836,31 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) case Xin_FpBinary: if (i->Xin.FpBinary.op == Xfp_ATAN) { /* Have to do this specially. */ - /* ffree %st7 ; fld %st(srcL) ; fld %st(srcR+1) ; fpatan ; fstp(1+dst) */ + /* ffree %st7 ; fld %st(srcL) ; + ffree %st7 ; fld %st(srcR+1) ; fpatan ; fstp(1+dst) */ p = do_ffree_st7(p); p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcL)); + p = do_ffree_st7(p); p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR)); *p++ = 0xD9; *p++ = 0xF3; p = do_fstp_st(p, 1+hregNumber(i->Xin.FpBinary.dst)); goto done; } + if (i->Xin.FpBinary.op == Xfp_PREM) { + /* Have to do this specially. */ + /* ffree %st7 ; fld %st(srcR) ; + ffree %st7 ; fld %st(srcL+1) ; fprem ; 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++ = 0xF8; + p = do_fstp_st(p, 2+hregNumber(i->Xin.FpBinary.dst)); + *p++ = 0xD9; *p++ = 0xF7; + p = do_ffree_st7(p); + goto done; + } /* General case */ /* gop %srcL, %srcR, %dst --> ffree %st7 ; fld %st(srcL) ; fop %st(1+srcR) ; fstp %st(1+dst) @@ -1920,6 +1951,11 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) } goto done; + case Xin_FpStSW_AX: + /* note, this emits fnstsw %ax, not fstsw %ax */ + *p++ = 0xDF; + *p++ = 0xE0; + goto done; case Xin_FpCmp: /* gcmp %fL, %fR, %dst diff --git a/VEX/priv/host-x86/hdefs.h b/VEX/priv/host-x86/hdefs.h index ea681a0ae0..aa5061e7d9 100644 --- a/VEX/priv/host-x86/hdefs.h +++ b/VEX/priv/host-x86/hdefs.h @@ -247,7 +247,8 @@ typedef enum { Xfp_INVALID, /* Binary */ - Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV, Xfp_ATAN, Xfp_YL2X, + Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV, + Xfp_ATAN, Xfp_YL2X, Xfp_PREM, /* Unary */ Xfp_SQRT, Xfp_ABS, Xfp_NEG, Xfp_MOV, Xfp_SIN, Xfp_COS, Xfp_ROUND @@ -282,6 +283,7 @@ typedef Xin_FpLdStI, /* FP fake load/store, converting to/from Int */ Xin_FpCMov, /* FP fake floating point (un)conditional move */ Xin_FpLdStCW, /* fldcw / fstcw */ + Xin_FpStSW_AX, /* fstsw %ax */ Xin_FpCmp /* FP compare, generating a C320 value into int reg */ } X86InstrTag; @@ -422,6 +424,11 @@ typedef X86AMode* addr; } FpLdStCW; + /* fstsw %ax */ + struct { + /* no fields */ + } + FpStSW_AX; /* Do a compare, generating the C320 bits into the dst. */ struct { HReg srcL; @@ -432,30 +439,31 @@ typedef } X86Instr; -extern X86Instr* X86Instr_Alu32R ( X86AluOp, X86RMI*, HReg ); -extern X86Instr* X86Instr_Alu32M ( X86AluOp, X86RI*, X86AMode* ); -extern X86Instr* X86Instr_Unary32 ( X86UnaryOp op, X86RM* dst ); -extern X86Instr* X86Instr_Sh32 ( X86ShiftOp, UInt, X86RM* ); -extern X86Instr* X86Instr_Test32 ( X86RI* src, X86RM* dst ); -extern X86Instr* X86Instr_MulL ( Bool syned, X86ScalarSz, X86RM* ); -extern X86Instr* X86Instr_Div ( Bool syned, X86ScalarSz, X86RM* ); -extern X86Instr* X86Instr_Sh3232 ( X86ShiftOp, UInt amt, HReg src, HReg dst ); -extern X86Instr* X86Instr_Push ( X86RMI* ); -extern X86Instr* X86Instr_Call ( HReg ); -extern X86Instr* X86Instr_Goto ( IRJumpKind, X86CondCode cond, X86RI* dst ); -extern X86Instr* X86Instr_CMov32 ( X86CondCode, X86RM* src, HReg dst ); -extern X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned, - X86AMode* src, HReg dst ); -extern X86Instr* X86Instr_Store ( UChar sz, HReg src, X86AMode* dst ); -extern X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst ); -extern X86Instr* X86Instr_Bsfr32 ( Bool isFwds, HReg src, HReg dst ); -extern X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst ); -extern X86Instr* X86Instr_FpBinary ( X86FpOp op, HReg srcL, HReg srcR, HReg dst ); -extern X86Instr* X86Instr_FpLdSt ( Bool isLoad, UChar sz, HReg reg, X86AMode* ); -extern X86Instr* X86Instr_FpLdStI ( Bool isLoad, UChar sz, HReg reg, X86AMode* ); -extern X86Instr* X86Instr_FpCMov ( X86CondCode, HReg src, HReg dst ); -extern X86Instr* X86Instr_FpLdStCW ( Bool isLoad, X86AMode* ); -extern X86Instr* X86Instr_FpCmp ( HReg srcL, HReg srcR, HReg dst ); +extern X86Instr* X86Instr_Alu32R ( X86AluOp, X86RMI*, HReg ); +extern X86Instr* X86Instr_Alu32M ( X86AluOp, X86RI*, X86AMode* ); +extern X86Instr* X86Instr_Unary32 ( X86UnaryOp op, X86RM* dst ); +extern X86Instr* X86Instr_Sh32 ( X86ShiftOp, UInt, X86RM* ); +extern X86Instr* X86Instr_Test32 ( X86RI* src, X86RM* dst ); +extern X86Instr* X86Instr_MulL ( Bool syned, X86ScalarSz, X86RM* ); +extern X86Instr* X86Instr_Div ( Bool syned, X86ScalarSz, X86RM* ); +extern X86Instr* X86Instr_Sh3232 ( X86ShiftOp, UInt amt, HReg src, HReg dst ); +extern X86Instr* X86Instr_Push ( X86RMI* ); +extern X86Instr* X86Instr_Call ( HReg ); +extern X86Instr* X86Instr_Goto ( IRJumpKind, X86CondCode cond, X86RI* dst ); +extern X86Instr* X86Instr_CMov32 ( X86CondCode, X86RM* src, HReg dst ); +extern X86Instr* X86Instr_LoadEX ( UChar szSmall, Bool syned, + X86AMode* src, HReg dst ); +extern X86Instr* X86Instr_Store ( UChar sz, HReg src, X86AMode* dst ); +extern X86Instr* X86Instr_Set32 ( X86CondCode cond, HReg dst ); +extern X86Instr* X86Instr_Bsfr32 ( Bool isFwds, HReg src, HReg dst ); +extern X86Instr* X86Instr_FpUnary ( X86FpOp op, HReg src, HReg dst ); +extern X86Instr* X86Instr_FpBinary ( X86FpOp op, HReg srcL, HReg srcR, HReg dst ); +extern X86Instr* X86Instr_FpLdSt ( Bool isLoad, UChar sz, HReg reg, X86AMode* ); +extern X86Instr* X86Instr_FpLdStI ( Bool isLoad, UChar sz, HReg reg, X86AMode* ); +extern X86Instr* X86Instr_FpCMov ( X86CondCode, HReg src, HReg dst ); +extern X86Instr* X86Instr_FpLdStCW ( Bool isLoad, X86AMode* ); +extern X86Instr* X86Instr_FpStSW_AX ( void ); +extern X86Instr* X86Instr_FpCmp ( HReg srcL, HReg srcR, HReg dst ); extern void ppX86Instr ( X86Instr* ); diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index 06e6837a62..5092001602 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -573,6 +573,21 @@ 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) { + 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)); + /* The previous pseudo-insn will have left the FPU's C3210 + flags set correctly. So bag them. */ + addInstr(env, X86Instr_FpStSW_AX()); + addInstr(env, mk_MOVsd_RR(hregX86_EAX(), dst)); + addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(0x4700), dst)); + return dst; + } + break; } @@ -1598,11 +1613,12 @@ static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ) if (e->tag == Iex_Binop) { X86FpOp fpop = Xfp_INVALID; switch (e->Iex.Binop.op) { - case Iop_AddF64: fpop = Xfp_ADD; break; - case Iop_SubF64: fpop = Xfp_SUB; break; - case Iop_MulF64: fpop = Xfp_MUL; break; - case Iop_DivF64: fpop = Xfp_DIV; break; - case Iop_AtanF64: fpop = Xfp_ATAN; break; + case Iop_AddF64: fpop = Xfp_ADD; break; + case Iop_SubF64: fpop = Xfp_SUB; break; + case Iop_MulF64: fpop = Xfp_MUL; break; + case Iop_DivF64: fpop = Xfp_DIV; break; + case Iop_AtanF64: fpop = Xfp_ATAN; break; + case Iop_PRemF64: fpop = Xfp_PREM; break; default: break; } if (fpop != Xfp_INVALID) { @@ -1614,7 +1630,6 @@ static HReg iselDblExpr ( ISelEnv* env, IRExpr* e ) } } - if (e->tag == Iex_Binop && e->Iex.Binop.op == Iop_RoundF64) { HReg rf = iselDblExpr(env, e->Iex.Binop.arg2); HReg rrm = iselIntExpr_R(env, e->Iex.Binop.arg1); diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index 1f4923c82d..1b369a1505 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -129,19 +129,24 @@ void ppIROp ( IROp op ) case Iop_64to32: vex_printf("64to32"); return; case Iop_32HLto64: vex_printf("32HLto64"); return; - case Iop_AtanF64: vex_printf("AtanF64"); return; - case Iop_Yl2xF64: vex_printf("Yl2xF64"); return; case Iop_AddF64: vex_printf("AddF64"); return; case Iop_SubF64: vex_printf("SubF64"); return; case Iop_MulF64: vex_printf("MulF64"); return; case Iop_DivF64: vex_printf("DivF64"); return; - case Iop_CmpF64: vex_printf("CmpF64"); return; - case Iop_NegF64: vex_printf("NegF64"); return; + + case Iop_AtanF64: vex_printf("AtanF64"); return; + case Iop_Yl2xF64: vex_printf("Yl2xF64"); 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_AbsF64: vex_printf("AbsF64"); return; - case Iop_SqrtF64: vex_printf("SqrtF64"); return; case Iop_SinF64: vex_printf("SinF64"); return; case Iop_CosF64: vex_printf("CosF64"); return; + case Iop_CmpF64: vex_printf("CmpF64"); return; + case Iop_I32toF64: vex_printf("I32toF64"); return; case Iop_I64toF64: vex_printf("I64toF64"); return; @@ -633,11 +638,13 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) case Iop_32Sto64: UNARY(Ity_I64,Ity_I32); case Iop_32to8: UNARY(Ity_I8,Ity_I32); + case Iop_PRemF64: case Iop_AtanF64: case Iop_Yl2xF64: case Iop_AddF64: case Iop_SubF64: case Iop_MulF64: case Iop_DivF64: BINARY(Ity_F64,Ity_F64,Ity_F64); + case Iop_PRemC3210F64: 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 3c8501332a..60487245e8 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -160,11 +160,13 @@ typedef /* ------ Floating point. We try and be IEEE754 compliant. ------ */ /* Binary operations mandated by IEEE754. */ - Iop_AddF64, Iop_SubF64, Iop_MulF64, Iop_DivF64, Iop_RemF64, + 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_AtanF64, /* FPATAN, arctan(arg1/arg2) */ + Iop_Yl2xF64, /* FYL2X, arg1 * log2(arg2) */ + Iop_PRemF64, /* FPREM, remainder(arg1/arg2) */ + Iop_PRemC3210F64, /* C3210 flags resulting from FPREM, :: I32 */ /* Unary operations mandated by IEEE754. */ Iop_NegF64, Iop_SqrtF64,