]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
x86 front end: implement FXTRACT. I knew there was a reason I'd been
authorJulian Seward <jseward@acm.org>
Mon, 3 Oct 2005 01:02:40 +0000 (01:02 +0000)
committerJulian Seward <jseward@acm.org>
Mon, 3 Oct 2005 01:02:40 +0000 (01:02 +0000)
avoiding this ...

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

VEX/priv/guest-x86/gdefs.h
VEX/priv/guest-x86/ghelpers.c
VEX/priv/guest-x86/toIR.c

index 310423929af7adcf751a7d893a1d8cb8cdf3af5e..39c6e49857c69482731fa9eaa084b0992f92c1bb 100644 (file)
@@ -119,6 +119,9 @@ extern ULong x86g_check_ldmxcsr ( UInt mxcsr );
 
 extern UInt  x86g_create_mxcsr ( UInt sseround );
 
+extern ULong x86g_calculate_FXTRACT ( ULong arg, UInt getExp );
+
+
 /* Translate a guest virtual_addr into a guest linear address by
    consulting the supplied LDT/GDT structures.  Their representation
    must be as specified in pub/libvex_guest_x86.h.  To indicate a
index fa2323bd307d5f59d95ee525b04c185a03373265..464cedb45089de31a0650fc700e8fa173fba2277 100644 (file)
@@ -1243,6 +1243,90 @@ void x86g_dirtyhelper_storeF80le ( UInt addrU, ULong f64 )
 }
 
 
+/* CALLED FROM GENERATED CODE: CLEAN HELPER */
+/* Extract the signed significand or exponent component as per
+   fxtract.  Arg and result are doubles travelling under the guise of
+   ULongs.  Returns significand when getExp is zero and exponent
+   otherwise. */
+ULong x86g_calculate_FXTRACT ( ULong arg, UInt getExp )
+{
+   ULong  uSig;
+   Long   sSig;
+   Double dSig, dExp;
+   Int    sExp, i;
+   UInt   sign;
+
+   /*
+    S  7FF    0------0   infinity
+    S  7FF    0X-----X   snan
+    S  7FF    1X-----X   qnan
+   */
+   const ULong posInf  = 0x7FF0000000000000ULL;
+   const ULong negInf  = 0xFFF0000000000000ULL;
+   const ULong nanMask = 0x7FF0000000000000ULL;
+   const ULong qNan    = 0x7FF8000000000000ULL;
+   const ULong posZero = 0x0000000000000000ULL;
+   const ULong negZero = 0x8000000000000000ULL;
+   const ULong bit51   = 1ULL << 51;
+   const ULong bit52   = 1ULL << 52;
+
+   /* Mimic PIII behaviour for special cases. */
+   if (arg == posInf)
+      return getExp ? posInf : posInf;
+   if (arg == negInf)
+      return getExp ? posInf : negInf;
+   if ((arg & nanMask) == nanMask)
+      return qNan;
+   if (arg == posZero)
+      return getExp ? negInf : posZero;
+   if (arg == negZero)
+      return getExp ? negInf : negZero;
+
+   /* Split into sign, exponent and significand. */
+   sign = ((UInt)(arg >> 63)) & 1;
+
+   /* Mask off exponent & sign. uSig is in range 0 .. 2^52-1. */
+   uSig = arg & (bit52 - 1);
+
+   /* Get the exponent. */
+   sExp = ((Int)(arg >> 52)) & 0x7FF;
+
+   /* Deal with denormals: if the exponent is zero, then the
+      significand cannot possibly be zero (negZero/posZero are handled
+      above).  Shift the significand left until bit 51 of it becomes
+      1, and decrease the exponent accordingly.
+   */
+   if (sExp == 0) {
+      for (i = 0; i < 52; i++) {
+         if (uSig & bit51)
+            break;
+         uSig <<= 1;
+         sExp--;
+      }
+      uSig <<= 1;
+   } else {
+      /* Add the implied leading-1 in the significand. */
+      uSig |= bit52;
+   }
+
+   /* Roll in the sign. */
+   sSig = uSig;
+   if (sign) sSig =- sSig;
+
+   /* Convert sig into a double.  This should be an exact conversion.
+      Then divide by 2^52, which should give a value in the range 1.0
+      to 2.0-epsilon, at least for normalised args. */
+   dSig = (Double)sSig;
+   dSig /= 67108864.0; /* 2^26 */
+   dSig /= 67108864.0; /* 2^26 */
+
+   /* Convert exp into a double.  Also an exact conversion. */
+   dExp = (Double)(sExp - 1023);
+
+   return *(ULong*)(getExp ? &dExp : &dSig);
+}
+
+
 /*----------------------------------------------*/
 /*--- The exported fns ..                    ---*/
 /*----------------------------------------------*/
index ebc81c4d93b8d330fb626df7e091cbf4f38f7e8d..e6ec7851fd89509a6cf29be9221adf0c4f228d6a 100644 (file)
@@ -3863,6 +3863,38 @@ UInt dis_FPU ( Bool* decode_ok, UChar sorb, Int delta )
                fp_pop();
                break;
 
+            case 0xF4: {
+               IRTemp argF = newTemp(Ity_F64);
+               IRTemp sigF = newTemp(Ity_F64);
+               IRTemp expF = newTemp(Ity_F64);
+               IRTemp argI = newTemp(Ity_I64);
+               IRTemp sigI = newTemp(Ity_I64);
+               IRTemp expI = newTemp(Ity_I64);
+               DIP("fxtract\n");
+               assign( argF, get_ST(0) );
+               assign( argI, unop(Iop_ReinterpF64asI64, mkexpr(argF)));
+               assign( sigI, 
+                       mkIRExprCCall(Ity_I64, 0/*regparms*/, 
+                                     "x86g_calculate_FXTRACT", 
+                                     &x86g_calculate_FXTRACT, 
+                                     mkIRExprVec_2( mkexpr(argI), 
+                                                    mkU32(0)/*sig*/ )) );
+               assign( expI, 
+                       mkIRExprCCall(Ity_I64, 0/*regparms*/, 
+                                     "x86g_calculate_FXTRACT", 
+                                     &x86g_calculate_FXTRACT, 
+                                     mkIRExprVec_2( mkexpr(argI), 
+                                                    mkU32(1)/*exp*/ )) );
+               assign( sigF, unop(Iop_ReinterpI64asF64, mkexpr(sigI)) );
+               assign( expF, unop(Iop_ReinterpI64asF64, mkexpr(expI)) );
+               /* exponent */
+               put_ST_UNCHECKED(0, mkexpr(expF) );
+               fp_push();
+               /* significand */
+               put_ST(0, mkexpr(sigF) );
+               break;
+            }
+
             case 0xF5: { /* FPREM1 -- IEEE compliant */
                IRTemp a1 = newTemp(Ity_F64);
                IRTemp a2 = newTemp(Ity_F64);