rounding mode.
git-svn-id: svn://svn.valgrind.org/vex/trunk@250
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)));
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;
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");
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));
/* 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;
}
}
+
+ 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) {
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;
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);
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
*/
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;