]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Implement IEEE754-compliant fprem1.
authorJulian Seward <jseward@acm.org>
Fri, 15 Oct 2004 22:57:13 +0000 (22:57 +0000)
committerJulian Seward <jseward@acm.org>
Fri, 15 Oct 2004 22:57:13 +0000 (22:57 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@354

VEX/priv/guest-x86/toIR.c
VEX/priv/host-x86/hdefs.c
VEX/priv/host-x86/hdefs.h
VEX/priv/host-x86/isel.c
VEX/priv/ir/irdefs.c
VEX/pub/libvex_ir.h

index d1757d58b5417f67f2827597fddcae7414ca15c3..82c6175e355b9c4ab1d41a7290ee364d0d037e5f 100644 (file)
@@ -3529,6 +3529,20 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, UInt delta )
                fp_pop();
                break;
 
+            case 0xF5: { /* FPREM1 -- IEEE compliant */
+               IRTemp a1 = newTemp(Ity_F64);
+               IRTemp a2 = newTemp(Ity_F64);
+               DIP("fprem1\n");
+               /* Do FPREM1 twice, once to get the remainder, and once
+                  to get the C3210 flag values. */
+               assign( a1, get_ST(0) );
+               assign( a2, get_ST(1) );
+               put_ST_UNCHECKED(0, binop(Iop_PRem1F64,
+                                         mkexpr(a1), mkexpr(a2)));
+               put_C3210( binop(Iop_PRem1C3210F64, mkexpr(a1), mkexpr(a2)) );
+               break;
+            }
+
             case 0xF8: { /* FPREM -- not IEEE compliant */
                IRTemp a1 = newTemp(Ity_F64);
                IRTemp a2 = newTemp(Ity_F64);
index 7be97274ff74e910340076fd8a2ef2725398543a..c79e490c2beeac500b0db2aeada786fb38c54a79 100644 (file)
@@ -427,6 +427,8 @@ Char* showX86FpOp ( X86FpOp op ) {
       case Xfp_TAN:    return "tan";
       case Xfp_2XM1:   return "2xm1";
       case Xfp_ATAN:   return "atan";
+      case Xfp_PREM:   return "prem";
+      case Xfp_PREM1:  return "prem1";
       default: vpanic("showX86FpOp");
    }
 }
@@ -1878,17 +1880,23 @@ Int emit_X86Instr ( UChar* buf, Int nbuf, X86Instr* i )
          goto done;
       }
       if (i->Xin.FpBinary.op == Xfp_PREM
+          || i->Xin.FpBinary.op == Xfp_PREM1
           || i->Xin.FpBinary.op == Xfp_SCALE) {
          /* Have to do this specially. */
          /* ffree %st7 ; fld %st(srcR) ; 
-            ffree %st7 ; fld %st(srcL+1) ; fprem/fscale ; fstp(2+dst) ; 
+            ffree %st7 ; fld %st(srcL+1) ; fprem/fprem1/fscale ; fstp(2+dst) ; 
             fincstp ; ffree %st7 */
          p = do_ffree_st7(p);
          p = do_fld_st(p, 0+hregNumber(i->Xin.FpBinary.srcR));
          p = do_ffree_st7(p);
          p = do_fld_st(p, 1+hregNumber(i->Xin.FpBinary.srcL));
-         *p++ = 0xD9; 
-         *p++ = i->Xin.FpBinary.op==Xfp_PREM ? 0xF8 : 0xFD;
+         *p++ = 0xD9;
+         switch (i->Xin.FpBinary.op) {
+            case Xfp_PREM: *p++ = 0xF8; break;
+            case Xfp_PREM1: *p++ = 0xF5; break;
+            case Xfp_SCALE: *p++ =  0xFD; break;
+            default: vpanic("emitX86Instr(FpBinary,PREM/PREM1/SCALE)");
+         }
          p = do_fstp_st(p, 2+hregNumber(i->Xin.FpBinary.dst));
          *p++ = 0xD9; *p++ = 0xF7;
          p = do_ffree_st7(p);
index 9c474103019d311c0d25e7f4612a091ca74034c6..12a6fb8a0a8e39b00fc5241a6c9d5b50951a0730 100644 (file)
@@ -248,7 +248,7 @@ typedef
       Xfp_INVALID,
       /* Binary */
       Xfp_ADD, Xfp_SUB, Xfp_MUL, Xfp_DIV, 
-      Xfp_SCALE, Xfp_ATAN, Xfp_YL2X, Xfp_YL2XP1, Xfp_PREM,
+      Xfp_SCALE, Xfp_ATAN, Xfp_YL2X, Xfp_YL2XP1, Xfp_PREM, Xfp_PREM1,
       /* Unary */
       Xfp_SQRT, Xfp_ABS, Xfp_NEG, Xfp_MOV, Xfp_SIN, Xfp_COS, Xfp_TAN,
       Xfp_ROUND, Xfp_2XM1
index b302f9b2a824ab4c5e138d95dc6626d3c9d1a721..4421ed4b11a3dcb1b917e6245e1bf02b6d514551 100644 (file)
@@ -664,13 +664,18 @@ static HReg iselIntExpr_R_wrk ( ISelEnv* env, IRExpr* e )
          return dst;
       }
 
-      /* C3210 flags following FPU partial remainder (fprem). */
-      if (e->Iex.Binop.op == Iop_PRemC3210F64) {
+      /* C3210 flags following FPU partial remainder (fprem), both
+         IEEE compliant (PREM1) and non-IEEE compliant (PREM). */
+      if (e->Iex.Binop.op == Iop_PRemC3210F64
+          || e->Iex.Binop.op == Iop_PRem1C3210F64) {
          HReg junk = newVRegF(env);
          HReg dst  = newVRegI(env);
          HReg srcL = iselDblExpr(env, e->Iex.Binop.arg1);
          HReg srcR = iselDblExpr(env, e->Iex.Binop.arg2);
-         addInstr(env, X86Instr_FpBinary(Xfp_PREM,srcL,srcR,junk));
+         addInstr(env, X86Instr_FpBinary(
+                           e->Iex.Binop.op==Iop_PRemC3210F64 ? Xfp_PREM : Xfp_PREM1,
+                           srcL,srcR,junk
+                 ));
          /* The previous pseudo-insn will have left the FPU's C3210
             flags set correctly.  So bag them. */
          addInstr(env, X86Instr_FpStSW_AX());
@@ -1786,6 +1791,7 @@ static HReg iselDblExpr ( ISelEnv* env, IRExpr* e )
          case Iop_Yl2xF64:   fpop = Xfp_YL2X; break;
          case Iop_Yl2xp1F64: fpop = Xfp_YL2XP1; break;
          case Iop_PRemF64:   fpop = Xfp_PREM; break;
+         case Iop_PRem1F64:  fpop = Xfp_PREM1; break;
          default: break;
       }
       if (fpop != Xfp_INVALID) {
index 2c3377e96962da20cc798b7f44298a332e7193c5..162ec50f2a11cc51be97e8123a35956b492e5028 100644 (file)
@@ -145,14 +145,16 @@ void ppIROp ( IROp op )
       case Iop_MulF64:    vex_printf("MulF64"); return;
       case Iop_DivF64:    vex_printf("DivF64"); return;
 
-      case Iop_ScaleF64:     vex_printf("ScaleF64"); return;
-      case Iop_AtanF64:      vex_printf("AtanF64"); return;
-      case Iop_Yl2xF64:      vex_printf("Yl2xF64"); return;
-      case Iop_Yl2xp1F64:    vex_printf("Yl2xp1F64"); return;
-      case Iop_PRemF64:      vex_printf("PRemF64"); return;
-      case Iop_PRemC3210F64: vex_printf("PRemC3210F64"); return;
-      case Iop_NegF64:       vex_printf("NegF64"); return;
-      case Iop_SqrtF64:      vex_printf("SqrtF64"); return;
+      case Iop_ScaleF64:      vex_printf("ScaleF64"); return;
+      case Iop_AtanF64:       vex_printf("AtanF64"); return;
+      case Iop_Yl2xF64:       vex_printf("Yl2xF64"); return;
+      case Iop_Yl2xp1F64:     vex_printf("Yl2xp1F64"); return;
+      case Iop_PRemF64:       vex_printf("PRemF64"); return;
+      case Iop_PRemC3210F64:  vex_printf("PRemC3210F64"); return;
+      case Iop_PRem1F64:      vex_printf("PRem1F64"); return;
+      case Iop_PRem1C3210F64: vex_printf("PRem1C3210F64"); return;
+      case Iop_NegF64:        vex_printf("NegF64"); return;
+      case Iop_SqrtF64:       vex_printf("SqrtF64"); return;
 
       case Iop_AbsF64:    vex_printf("AbsF64"); return;
       case Iop_SinF64:    vex_printf("SinF64"); return;
@@ -903,11 +905,11 @@ void typeOfPrimop ( IROp op, IRType* t_dst, IRType* t_arg1, IRType* t_arg2 )
 
       case Iop_32to8: UNARY(Ity_I8,Ity_I32);
 
-      case Iop_ScaleF64: case Iop_PRemF64:
+      case Iop_ScaleF64: case Iop_PRemF64: case Iop_PRem1F64:
       case Iop_AtanF64: case Iop_Yl2xF64:  case Iop_Yl2xp1F64: 
       case Iop_AddF64: case Iop_SubF64: case Iop_MulF64: case Iop_DivF64:
          BINARY(Ity_F64,Ity_F64,Ity_F64);
-      case Iop_PRemC3210F64:
+      case Iop_PRemC3210F64: case Iop_PRem1C3210F64:
       case Iop_CmpF64:
          BINARY(Ity_I32,Ity_F64,Ity_F64);
       case Iop_NegF64: case Iop_AbsF64: case Iop_SqrtF64:
index e617237b4c50537a2cf569fd3fa773eec86e02b3..bc2e8804200ef8d8f4772353af7aa0fcce90585b 100644 (file)
@@ -173,12 +173,17 @@ typedef
       Iop_AddF64, Iop_SubF64, Iop_MulF64, Iop_DivF64, /* Iop_RemF64, */
 
       /* Binary ops supported by IA32 but not mandated by 754. */
-      Iop_AtanF64,      /* FPATAN,  arctan(arg1/arg2)       */
-      Iop_Yl2xF64,      /* FYL2X,   arg1 * log2(arg2)       */
-      Iop_Yl2xp1F64,    /* FYL2XP1, arg1 * log2(arg2+1.0)   */
-      Iop_PRemF64,      /* FPREM,   remainder(arg1/arg2)    */
-      Iop_PRemC3210F64, /* C3210 flags resulting from FPREM, :: I32 */
-      Iop_ScaleF64,     /* FSCALE,  arg1 * (2^RoundTowardsZero(arg2)) */
+      Iop_AtanF64,       /* FPATAN,  arctan(arg1/arg2)       */
+      Iop_Yl2xF64,       /* FYL2X,   arg1 * log2(arg2)       */
+      Iop_Yl2xp1F64,     /* FYL2XP1, arg1 * log2(arg2+1.0)   */
+      Iop_PRemF64,       /* FPREM,   non-IEEE remainder(arg1/arg2)    */
+      Iop_PRemC3210F64,  /* C3210 flags resulting from FPREM, :: I32 */
+      Iop_PRem1F64,      /* FPREM1,  IEEE remainder(arg1/arg2)    */
+      Iop_PRem1C3210F64, /* C3210 flags resulting from FPREM1, :: I32 */
+      Iop_ScaleF64,      /* FSCALE,  arg1 * (2^RoundTowardsZero(arg2)) */
+      /* Note that on x86 guest, PRem1{C3210} has the same behaviour
+         as the IEEE mandated RemF64, except it is limited in the
+         range of its operand.  Hence the partialness. */
 
       /* Unary operations mandated by IEEE754. */
       Iop_NegF64, Iop_SqrtF64,