From ca120f6d7dc71c4637fb2168296aff001998e54b Mon Sep 17 00:00:00 2001 From: Julian Seward Date: Fri, 3 Feb 2006 22:54:17 +0000 Subject: [PATCH] Followup to r1562: fixes for x86 git-svn-id: svn://svn.valgrind.org/vex/trunk@1564 --- VEX/priv/guest-x86/toIR.c | 111 ++++++++++++++++++++++++++++---------- VEX/priv/host-x86/isel.c | 60 ++++++++++++++++----- VEX/pub/libvex_ir.h | 11 +++- 3 files changed, 141 insertions(+), 41 deletions(-) diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index 2a0c20918a..d9aa5cb2a8 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -630,6 +630,11 @@ static IRExpr* binop ( IROp op, IRExpr* a1, IRExpr* a2 ) return IRExpr_Binop(op, a1, a2); } +static IRExpr* triop ( IROp op, IRExpr* a1, IRExpr* a2, IRExpr* a3 ) +{ + return IRExpr_Triop(op, a1, a2, a3); +} + static IRExpr* mkexpr ( IRTemp tmp ) { return IRExpr_Tmp(tmp); @@ -3181,6 +3186,11 @@ static IRExpr* /* :: Ity_I32 */ get_roundingmode ( void ) return binop( Iop_And32, get_fpround(), mkU32(3) ); } +static IRExpr* /* :: Ity_I32 */ get_FAKE_roundingmode ( void ) +{ + return mkU32(Irrm_NEAREST); +} + /* --------- Get/set FP register tag bytes. --------- */ @@ -3317,13 +3327,15 @@ void fp_do_op_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf, DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf); if (dbl) { put_ST_UNCHECKED(0, - binop( op, + triop( op, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ get_ST(0), loadLE(Ity_F64,mkexpr(addr)) )); } else { put_ST_UNCHECKED(0, - binop( op, + triop( op, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ get_ST(0), unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))) )); @@ -3341,13 +3353,15 @@ void fp_do_oprev_mem_ST_0 ( IRTemp addr, HChar* op_txt, HChar* dis_buf, DIP("f%s%c %s\n", op_txt, dbl?'l':'s', dis_buf); if (dbl) { put_ST_UNCHECKED(0, - binop( op, + triop( op, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ loadLE(Ity_F64,mkexpr(addr)), get_ST(0) )); } else { put_ST_UNCHECKED(0, - binop( op, + triop( op, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ unop(Iop_F32toF64, loadLE(Ity_F32,mkexpr(addr))), get_ST(0) )); @@ -3366,7 +3380,10 @@ void fp_do_op_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst, (Int)st_src, (Int)st_dst ); put_ST_UNCHECKED( st_dst, - binop(op, get_ST(st_dst), get_ST(st_src) ) + triop( op, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ + get_ST(st_dst), + get_ST(st_src) ) ); if (pop_after) fp_pop(); @@ -3383,7 +3400,10 @@ void fp_do_oprev_ST_ST ( HChar* op_txt, IROp op, UInt st_src, UInt st_dst, (Int)st_src, (Int)st_dst ); put_ST_UNCHECKED( st_dst, - binop(op, get_ST(st_src), get_ST(st_dst) ) + triop( op, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ + get_ST(st_src), + get_ST(st_dst) ) ); if (pop_after) fp_pop(); @@ -3876,19 +3896,28 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta ) case 0xF0: /* F2XM1 */ DIP("f2xm1\n"); - put_ST_UNCHECKED(0, unop(Iop_2xm1F64, get_ST(0))); + put_ST_UNCHECKED(0, + binop(Iop_2xm1F64, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ + get_ST(0))); break; case 0xF1: /* FYL2X */ DIP("fyl2x\n"); - put_ST_UNCHECKED(1, binop(Iop_Yl2xF64, - get_ST(1), get_ST(0))); + put_ST_UNCHECKED(1, + triop(Iop_Yl2xF64, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ + get_ST(1), + get_ST(0))); fp_pop(); break; case 0xF2: /* FPTAN */ DIP("ftan\n"); - put_ST_UNCHECKED(0, unop(Iop_TanF64, get_ST(0))); + put_ST_UNCHECKED(0, + binop(Iop_TanF64, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ + get_ST(0))); fp_push(); put_ST(0, IRExpr_Const(IRConst_F64(1.0))); clear_C2(); /* HACK */ @@ -3896,12 +3925,15 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta ) case 0xF3: /* FPATAN */ DIP("fpatan\n"); - put_ST_UNCHECKED(1, binop(Iop_AtanF64, - get_ST(1), get_ST(0))); + put_ST_UNCHECKED(1, + triop(Iop_AtanF64, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ + get_ST(1), + get_ST(0))); fp_pop(); break; - case 0xF4: { + case 0xF4: { /* FXTRACT */ IRTemp argF = newTemp(Ity_F64); IRTemp sigF = newTemp(Ity_F64); IRTemp expF = newTemp(Ity_F64); @@ -3968,23 +4000,35 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta ) case 0xF9: /* FYL2XP1 */ DIP("fyl2xp1\n"); - put_ST_UNCHECKED(1, binop(Iop_Yl2xp1F64, - get_ST(1), get_ST(0))); + put_ST_UNCHECKED(1, + triop(Iop_Yl2xp1F64, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ + get_ST(1), + get_ST(0))); fp_pop(); break; case 0xFA: /* FSQRT */ DIP("fsqrt\n"); - put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0))); + put_ST_UNCHECKED(0, + binop(Iop_SqrtF64, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ + get_ST(0))); break; case 0xFB: { /* FSINCOS */ IRTemp a1 = newTemp(Ity_F64); assign( a1, get_ST(0) ); DIP("fsincos\n"); - put_ST_UNCHECKED(0, unop(Iop_SinF64, mkexpr(a1))); + put_ST_UNCHECKED(0, + binop(Iop_SinF64, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ + mkexpr(a1))); fp_push(); - put_ST(0, unop(Iop_CosF64, mkexpr(a1))); + put_ST(0, + binop(Iop_CosF64, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ + mkexpr(a1))); clear_C2(); /* HACK */ break; } @@ -3997,19 +4041,28 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta ) case 0xFD: /* FSCALE */ DIP("fscale\n"); - put_ST_UNCHECKED(0, binop(Iop_ScaleF64, - get_ST(0), get_ST(1))); + put_ST_UNCHECKED(0, + triop(Iop_ScaleF64, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ + get_ST(0), + get_ST(1))); break; case 0xFE: /* FSIN */ DIP("fsin\n"); - put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0))); + put_ST_UNCHECKED(0, + binop(Iop_SinF64, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ + get_ST(0))); clear_C2(); /* HACK */ break; case 0xFF: /* FCOS */ DIP("fcos\n"); - put_ST_UNCHECKED(0, unop(Iop_CosF64, get_ST(0))); + put_ST_UNCHECKED(0, + binop(Iop_CosF64, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ + get_ST(0))); clear_C2(); /* HACK */ break; @@ -4095,7 +4148,8 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta ) do_fop_m32: put_ST_UNCHECKED(0, - binop(fop, + triop(fop, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ get_ST(0), unop(Iop_I32toF64, loadLE(Ity_I32, mkexpr(addr))))); @@ -4103,7 +4157,8 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta ) do_foprev_m32: put_ST_UNCHECKED(0, - binop(fop, + triop(fop, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ unop(Iop_I32toF64, loadLE(Ity_I32, mkexpr(addr))), get_ST(0))); @@ -4741,7 +4796,7 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta ) get_ST(0), unop(Iop_I32toF64, unop(Iop_16Sto32, - loadLE(Ity_I16,mkexpr(addr))))), + loadLE(Ity_I16,mkexpr(addr))))), mkU8(8)), mkU32(0x4500) )); @@ -4770,7 +4825,8 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta ) do_fop_m16: put_ST_UNCHECKED(0, - binop(fop, + triop(fop, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ get_ST(0), unop(Iop_I32toF64, unop(Iop_16Sto32, @@ -4779,7 +4835,8 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta ) do_foprev_m16: put_ST_UNCHECKED(0, - binop(fop, + triop(fop, + get_FAKE_roundingmode(), /* XXXROUNDINGFIXME */ unop(Iop_I32toF64, unop(Iop_16Sto32, loadLE(Ity_I16, mkexpr(addr)))), diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index 6240ae8fa0..b30a215b35 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -661,14 +661,14 @@ void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode ) static HReg do_sse_Not128 ( 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. If dst contains a NaN then all hell might + break loose after the comparison. So, first zero it. */ addInstr(env, X86Instr_SseReRg(Xsse_XOR, dst, dst)); /* And now make it all 1s ... */ addInstr(env, X86Instr_Sse32Fx4(Xsse_CMPEQF, dst, dst)); /* Finally, xor 'src' into it. */ addInstr(env, X86Instr_SseReRg(Xsse_XOR, src, dst)); + /* Doesn't that just totally suck? */ return dst; } @@ -2604,17 +2604,36 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) return res; } - if (e->tag == Iex_Binop) { + if (e->tag == Iex_Triop) { X86FpOp fpop = Xfp_INVALID; - switch (e->Iex.Binop.op) { + switch (e->Iex.Triop.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_ScaleF64: fpop = Xfp_SCALE; break; - case Iop_AtanF64: fpop = Xfp_ATAN; break; case Iop_Yl2xF64: fpop = Xfp_YL2X; break; case Iop_Yl2xp1F64: fpop = Xfp_YL2XP1; break; + case Iop_AtanF64: fpop = Xfp_ATAN; break; + default: break; + } + if (fpop != Xfp_INVALID) { + HReg res = newVRegF(env); + HReg srcL = iselDblExpr(env, e->Iex.Triop.arg2); + HReg srcR = iselDblExpr(env, e->Iex.Triop.arg3); + /* XXXROUNDINGFIXME */ + /* set roundingmode here */ + addInstr(env, X86Instr_FpBinary(fpop,srcL,srcR,res)); + if (fpop != Xfp_ADD && fpop != Xfp_SUB + && fpop != Xfp_MUL && fpop != Xfp_DIV) + roundToF64(env, res); + return res; + } + } + + if (e->tag == Iex_Binop) { + X86FpOp fpop = Xfp_INVALID; + switch (e->Iex.Binop.op) { case Iop_PRemF64: fpop = Xfp_PREM; break; case Iop_PRem1F64: fpop = Xfp_PREM1; break; default: break; @@ -2671,21 +2690,21 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) return dst; } - if (e->tag == Iex_Unop) { + if (e->tag == Iex_Binop) { X86FpOp fpop = Xfp_INVALID; - switch (e->Iex.Unop.op) { - case Iop_NegF64: fpop = Xfp_NEG; break; - case Iop_AbsF64: fpop = Xfp_ABS; break; - case Iop_SqrtF64: fpop = Xfp_SQRT; break; + switch (e->Iex.Binop.op) { case Iop_SinF64: fpop = Xfp_SIN; break; case Iop_CosF64: fpop = Xfp_COS; break; case Iop_TanF64: fpop = Xfp_TAN; break; case Iop_2xm1F64: fpop = Xfp_2XM1; break; + case Iop_SqrtF64: fpop = Xfp_SQRT; break; default: break; } if (fpop != Xfp_INVALID) { HReg res = newVRegF(env); - HReg src = iselDblExpr(env, e->Iex.Unop.arg); + HReg src = iselDblExpr(env, e->Iex.Binop.arg2); + /* XXXROUNDINGFIXME */ + /* set roundingmode here */ addInstr(env, X86Instr_FpUnary(fpop,src,res)); if (fpop != Xfp_SQRT && fpop != Xfp_NEG && fpop != Xfp_ABS) @@ -2694,6 +2713,23 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e ) } } + if (e->tag == Iex_Unop) { + X86FpOp fpop = Xfp_INVALID; + switch (e->Iex.Unop.op) { + case Iop_NegF64: fpop = Xfp_NEG; break; + case Iop_AbsF64: fpop = Xfp_ABS; break; + default: break; + } + if (fpop != Xfp_INVALID) { + HReg res = newVRegF(env); + HReg src = iselDblExpr(env, e->Iex.Unop.arg); + addInstr(env, X86Instr_FpUnary(fpop,src,res)); + if (fpop != Xfp_NEG && fpop != Xfp_ABS) + roundToF64(env, res); + return res; + } + } + if (e->tag == Iex_Unop) { switch (e->Iex.Unop.op) { case Iop_I32toF64: { diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index aa879a5715..27f92c599b 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -658,9 +658,16 @@ extern void ppIROp ( IROp ); /* Encoding of IEEE754-specified rounding modes. This is the same as - the encoding used by Intel IA32 to indicate x87 rounding mode. */ + the encoding used by Intel IA32 to indicate x87 rounding mode. + Note, various front and back ends rely on the actual numerical + values of these, so do not change them. */ typedef - enum { Irrm_NEAREST=0, Irrm_NegINF=1, Irrm_PosINF=2, Irrm_ZERO=3 } + enum { + Irrm_NEAREST = 0, + Irrm_NegINF = 1, + Irrm_PosINF = 2, + Irrm_ZERO = 3 + } IRRoundingMode; /* Floating point comparison result values, as created by Iop_CmpF64. -- 2.47.2