]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
x86 floating point accuracy improvements. The aim is to make x86 FP
authorJulian Seward <jseward@acm.org>
Mon, 10 Jan 2005 16:49:19 +0000 (16:49 +0000)
committerJulian Seward <jseward@acm.org>
Mon, 10 Jan 2005 16:49:19 +0000 (16:49 +0000)
behave more consistently like an 64-bit implementation.  Mostly this
means running the host with the FPU set to 64-bit precision, not
80-bit.

Requires corresponding changes on the Valgrind side of the fence.

git-svn-id: svn://svn.valgrind.org/vex/trunk@705

VEX/priv/guest-x86/toIR.c
VEX/priv/host-x86/isel.c

index 98cf4039f8fe823cd2ac70cb1f2e1a35dedd0672..e86a2f751340a4bb30ec7305723791bf835b5a46 100644 (file)
@@ -3905,43 +3905,50 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
             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 */
index 71a3fc702146c367f2d0ad687d2d5099d643de7f..8f822fb66ec5582aa89c168e6fca7f1f1c4a0fdd 100644 (file)
 #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                                      ---*/
 /*---------------------------------------------------------*/
@@ -572,16 +593,16 @@ X86AMode* genGuestArrayOffset ( ISelEnv* env, IRArray* descr,
 
 
 /* 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);
 }
@@ -602,7 +623,7 @@ void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode )
    /* 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
@@ -610,7 +631,7 @@ void set_FPU_rounding_mode ( ISelEnv* env, IRExpr* mode )
    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);
@@ -636,6 +657,23 @@ static HReg do_sse_Not128 ( ISelEnv* env, HReg src )
 }
 
 
+/* 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)           ---*/
 /*---------------------------------------------------------*/
@@ -2245,6 +2283,9 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
          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;
       }
    }
@@ -2305,6 +2346,9 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
          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;
       }
    }
@@ -2338,9 +2382,11 @@ static HReg iselDblExpr_wrk ( ISelEnv* env, IRExpr* e )
            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;
       }