From: Julian Seward Date: Fri, 10 Sep 2004 18:37:18 +0000 (+0000) Subject: Implement x86 FRNDINT, taking into account of course the current X-Git-Tag: svn/VALGRIND_3_0_1^2~1084 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=02e8964313b9e1ddc395de076832068f6dd38db4;p=thirdparty%2Fvalgrind.git Implement x86 FRNDINT, taking into account of course the current rounding mode. git-svn-id: svn://svn.valgrind.org/vex/trunk@250 --- diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index d31593ddb5..bc5447edf2 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -3564,6 +3564,12 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta ) put_ST_UNCHECKED(0, unop(Iop_SqrtF64, get_ST(0))); break; + case 0xFC: /* FRNDINT */ + DIP("frndint\n"); + put_ST_UNCHECKED(0, + binop(Iop_RoundF64, get_roundingmode(), get_ST(0)) ); + break; + case 0xFE: /* FSIN */ DIP("fsin\n"); put_ST_UNCHECKED(0, unop(Iop_SinF64, get_ST(0))); @@ -8366,9 +8372,9 @@ static UInt disInstr ( UInt delta, Bool* isEnd ) case 0xA3: /* BT Gv,Ev */ delta = dis_bt_G_E ( sorb, sz, delta, BtOpNone ); break; -//-- case 0xB3: /* BTR Gv,Ev */ -//-- eip = dis_bt_G_E ( cb, sorb, sz, eip, BtOpReset ); -//-- break; + case 0xB3: /* BTR Gv,Ev */ + delta = dis_bt_G_E ( sorb, sz, delta, BtOpReset ); + break; case 0xAB: /* BTS Gv,Ev */ delta = dis_bt_G_E ( sorb, sz, delta, BtOpSet ); break; diff --git a/VEX/priv/host-x86/hdefs.c b/VEX/priv/host-x86/hdefs.c index 09f72fb61a..37707b2cd6 100644 --- a/VEX/priv/host-x86/hdefs.c +++ b/VEX/priv/host-x86/hdefs.c @@ -1260,6 +1260,7 @@ static UChar* do_fop1_st ( UChar* p, X86FpOp op ) switch (op) { case Xfp_NEGATE: *p++ = 0xD9; *p++ = 0xE0; break; case Xfp_SQRT: *p++ = 0xD9; *p++ = 0xFA; break; + case Xfp_ROUND: *p++ = 0xD9; *p++ = 0xFC; break; case Xfp_SIN: *p++ = 0xD9; *p++ = 0xFE; break; case Xfp_COS: *p++ = 0xD9; *p++ = 0xFF; break; default: vpanic("do_fop1_st: unknown op"); @@ -1819,7 +1820,7 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i ) case Xin_FpBinary: if (i->Xin.FpBinary.op == Xfp_ATANYX) { /* Have to do this specially. */ - /* ffree %st7 ; fld %st(srcL) ; fld %st(srcR+1) ; fpatan ; fstp(1+dst) */ + /* ffree %st7 ; fld %st(srcL) ; 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_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcR)); diff --git a/VEX/priv/host-x86/hdefs.h b/VEX/priv/host-x86/hdefs.h index 4dd23256f2..f40771576d 100644 --- a/VEX/priv/host-x86/hdefs.h +++ b/VEX/priv/host-x86/hdefs.h @@ -249,7 +249,8 @@ typedef /* Binary */ Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV, Xfp_ATANYX, /* Unary */ - Xfp_SQRT, Xfp_NEGATE, Xfp_MOV, Xfp_SIN, Xfp_COS + Xfp_SQRT, Xfp_NEGATE, Xfp_MOV, Xfp_SIN, Xfp_COS, + Xfp_ROUND } X86FpOp; diff --git a/VEX/priv/host-x86/isel.c b/VEX/priv/host-x86/isel.c index e9298c4e20..713cc9ba39 100644 --- a/VEX/priv/host-x86/isel.c +++ b/VEX/priv/host-x86/isel.c @@ -1614,6 +1614,58 @@ 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); + HReg rrm2 = newVRegI(env); + HReg dst = newVRegF(env); + + /* Used several times ... */ + /* Careful ... this sharing is only safe because + zero_esp does not hold any registers which the + register allocator could attempt to swizzle later. */ + X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP()); + + /* rf now holds the value to be rounded, and rrm holds the + rounding mode value, encoded as per the IRRoundingMode enum. + The first thing to do is set the FPU's rounding mode + accordingly. */ + + /* subl $4, %esp */ + addInstr(env, + X86Instr_Alu32R(Xalu_SUB, X86RMI_Imm(4), hregX86_ESP())); + /* movl %rrm, %rrm2 + andl $3, %rrm2 -- shouldn't be needed; paranoia + shll $10, %rrm2 + orl $0x037F, %rrm2 + movl %rrm2, 0(%esp) + fldcw 0(%esp) + */ + addInstr(env, mk_MOVsd_RR(rrm, rrm2)); + addInstr(env, X86Instr_Alu32R(Xalu_AND, X86RMI_Imm(3), rrm2)); + addInstr(env, X86Instr_Sh32(Xsh_SHL, 10, X86RM_Reg(rrm2))); + addInstr(env, X86Instr_Alu32R(Xalu_OR, X86RMI_Imm(0x037F), rrm2)); + addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Reg(rrm2), zero_esp)); + addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp)); + + /* grndint %rf, %dst */ + addInstr(env, X86Instr_FpUnary(Xfp_ROUND, rf, dst)); + + /* Restore default FPU control. + movl $0x037F, 0(%esp) + fldcw 0(%esp) + */ + addInstr(env, X86Instr_Alu32M(Xalu_MOV, X86RI_Imm(0x037F), zero_esp)); + addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp)); + + /* addl $4, %esp */ + addInstr(env, + X86Instr_Alu32R(Xalu_ADD, X86RMI_Imm(4), hregX86_ESP())); + return dst; + } + + if (e->tag == Iex_Unop) { X86FpOp fpop = Xfp_INVALID; switch (e->Iex.Unop.op) { diff --git a/VEX/priv/ir/irdefs.c b/VEX/priv/ir/irdefs.c index 4570f1b4c4..cdb019238a 100644 --- a/VEX/priv/ir/irdefs.c +++ b/VEX/priv/ir/irdefs.c @@ -146,6 +146,7 @@ void ppIROp ( IROp op ) case Iop_F64toI64: vex_printf("F64toI64"); return; case Iop_F64toI32: vex_printf("F64toI32"); return; case Iop_F64toI16: vex_printf("F64toI16"); return; + case Iop_RoundF64: vex_printf("RoundF64"); return; case Iop_F32toF64: vex_printf("F32toF64"); return; case Iop_F64toF32: vex_printf("F64toF32"); return; @@ -645,6 +646,7 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 ) case Iop_F64toI64: BINARY(Ity_I64, Ity_I32,Ity_F64); case Iop_F64toI32: BINARY(Ity_I32, Ity_I32,Ity_F64); case Iop_F64toI16: BINARY(Ity_I16, Ity_I32,Ity_F64); + case Iop_RoundF64: BINARY(Ity_F64, Ity_I32,Ity_F64); case Iop_F32toF64: UNARY(Ity_F64,Ity_F32); case Iop_F64toF32: UNARY(Ity_F32,Ity_F64); diff --git a/VEX/pub/libvex_ir.h b/VEX/pub/libvex_ir.h index 2d9a9a618a..ce39516605 100644 --- a/VEX/pub/libvex_ir.h +++ b/VEX/pub/libvex_ir.h @@ -202,6 +202,9 @@ typedef of the argument. */ Iop_F64toI64, Iop_F64toI32, Iop_F64toI16, + /* F64 -> F64, also takes an I32 first argument encoding the + rounding mode. */ + Iop_RoundF64, /* double <-> float. What does this mean -- does it round? */ Iop_F32toF64, Iop_F64toF32 @@ -241,8 +244,8 @@ obscure IR optimisation bugs. */ typedef - enum { Iex_Binder, /* Used only in pattern matching. - Not an expression. */ + enum { Iex_Binder, /* Used only in pattern matching. + Not an expression. */ Iex_Get, Iex_GetI, Iex_Tmp, Iex_Binop, Iex_Unop, Iex_LDle, Iex_Const, Iex_CCall, Iex_Mux0X } IRExprTag;