case 0xE8: /* FLD1 */
DIP("fld1\n");
fp_push();
- put_ST(0, IRExpr_Const(IRConst_F64(1.0)));
+ /* put_ST(0, IRExpr_Const(IRConst_F64(1.0))); */
+ put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff0000000000000ULL)));
break;
case 0xE9: /* FLDL2T */
DIP("fldl2t\n");
fp_push();
- put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781)));
+ /* put_ST(0, IRExpr_Const(IRConst_F64(3.32192809488736234781))); */
+ put_ST(0, IRExpr_Const(IRConst_F64i(0x400a934f0979a371ULL)));
break;
case 0xEA: /* FLDL2E */
DIP("fldl2e\n");
fp_push();
- put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739)));
+ /* put_ST(0, IRExpr_Const(IRConst_F64(1.44269504088896340739))); */
+ put_ST(0, IRExpr_Const(IRConst_F64i(0x3ff71547652b82feULL)));
break;
case 0xEB: /* FLDPI */
DIP("fldpi\n");
fp_push();
- put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851)));
+ /* put_ST(0, IRExpr_Const(IRConst_F64(3.14159265358979323851))); */
+ put_ST(0, IRExpr_Const(IRConst_F64i(0x400921fb54442d18ULL)));
break;
case 0xEC: /* FLDLG2 */
DIP("fldlg2\n");
fp_push();
- put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143)));
+ /* put_ST(0, IRExpr_Const(IRConst_F64(0.301029995663981143))); */
+ put_ST(0, IRExpr_Const(IRConst_F64i(0x3fd34413509f79ffULL)));
break;
case 0xED: /* FLDLN2 */
DIP("fldln2\n");
fp_push();
- put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942)));
+ /* put_ST(0, IRExpr_Const(IRConst_F64(0.69314718055994530942))); */
+ put_ST(0, IRExpr_Const(IRConst_F64i(0x3fe62e42fefa39efULL)));
break;
case 0xEE: /* FLDZ */
DIP("fldz\n");
fp_push();
- put_ST(0, IRExpr_Const(IRConst_F64(0.0)));
+ /* put_ST(0, IRExpr_Const(IRConst_F64(0.0))); */
+ put_ST(0, IRExpr_Const(IRConst_F64i(0x0000000000000000ULL)));
break;
case 0xF0: /* F2XM1 */
#include "host-x86/hdefs.h"
+/*---------------------------------------------------------*/
+/*--- x87 control word stuff ---*/
+/*---------------------------------------------------------*/
+
+/* Vex-generated code expects to run with the FPU set as follows: all
+ exceptions masked, round-to-nearest, precision = 53 bits. This
+ corresponds to a FPU control word value of 0x027F.
+
+ Similarly the SSE control word (%mxcsr) should be 0x1F80.
+
+ %fpucw and %mxcsr should have these values on entry to
+ Vex-generated code, and should those values should be
+ unchanged at exit.
+*/
+
+#define DEFAULT_FPUCW 0x027F
+
+/* debugging only, do not use */
+/* define DEFAULT_FPUCW 0x037F */
+
+
/*---------------------------------------------------------*/
/*--- misc helpers ---*/
/*---------------------------------------------------------*/
/* Mess with the FPU's rounding mode: set to the default rounding mode
- (0x037F). */
+ (DEFAULT_FPUCW). */
static
void set_FPU_rounding_default ( ISelEnv* env )
{
- /* pushl $0x037F
+ /* pushl $DEFAULT_FPUCW
fldcw 0(%esp)
addl $4, %esp
*/
X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
- addInstr(env, X86Instr_Push(X86RMI_Imm(0x037F)));
+ addInstr(env, X86Instr_Push(X86RMI_Imm(DEFAULT_FPUCW)));
addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
add_to_esp(env, 4);
}
/* movl %rrm, %rrm2
andl $3, %rrm2 -- shouldn't be needed; paranoia
shll $10, %rrm2
- orl $0x037F, %rrm2
+ orl $DEFAULT_FPUCW, %rrm2
pushl %rrm2
fldcw 0(%esp)
addl $4, %esp
addInstr(env, mk_iMOVsd_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_Alu32R(Xalu_OR, X86RMI_Imm(DEFAULT_FPUCW), rrm2));
addInstr(env, X86Instr_Push(X86RMI_Reg(rrm2)));
addInstr(env, X86Instr_FpLdStCW(True/*load*/, zero_esp));
add_to_esp(env, 4);
}
+/* Round an x87 FPU value to 53-bit-mantissa precision, to be used
+ after most non-simple FPU operations (simple = +, -, *, / and
+ sqrt).
+
+ This could be done a lot more efficiently if needed, by loading
+ zero and adding it to the value to be rounded (fldz ; faddp?).
+*/
+static void roundToF64 ( ISelEnv* env, HReg reg )
+{
+ X86AMode* zero_esp = X86AMode_IR(0, hregX86_ESP());
+ sub_from_esp(env, 8);
+ addInstr(env, X86Instr_FpLdSt(False/*store*/, 8, reg, zero_esp));
+ addInstr(env, X86Instr_FpLdSt(True/*load*/, 8, reg, zero_esp));
+ add_to_esp(env, 8);
+}
+
+
/*---------------------------------------------------------*/
/*--- ISEL: Integer expressions (32/16/8 bit) ---*/
/*---------------------------------------------------------*/
HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1);
HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2);
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;
}
}
HReg res = newVRegF(env);
HReg src = iselDblExpr(env, e->Iex.Unop.arg);
addInstr(env, X86Instr_FpUnary(fpop,src,res));
+ if (fpop != Xfp_SQRT
+ && fpop != Xfp_NEG && fpop != Xfp_ABS)
+ roundToF64(env, res);
return res;
}
}
add_to_esp(env, 8);
return dst;
}
- case Iop_F32toF64:
+ case Iop_F32toF64: {
/* this is a no-op */
- return iselFltExpr(env, e->Iex.Unop.arg);
+ HReg res = iselFltExpr(env, e->Iex.Unop.arg);
+ return res;
+ }
default:
break;
}