]> git.ipfire.org Git - thirdparty/valgrind.git/commitdiff
Implement a couple of missing x87 insns.
authorJulian Seward <jseward@acm.org>
Mon, 25 Jul 2005 11:58:34 +0000 (11:58 +0000)
committerJulian Seward <jseward@acm.org>
Mon, 25 Jul 2005 11:58:34 +0000 (11:58 +0000)
git-svn-id: svn://svn.valgrind.org/vex/trunk@1299

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

index d6a3e436d13b7f4a9c4cfb2ac6451634db273b94..218c298289610dbc41e72fd743fdd3ee39983169 100644 (file)
@@ -92,7 +92,7 @@ extern ULong amd64g_calculate_condition (
                 ULong cc_dep1, ULong cc_dep2, ULong cc_ndep 
              );
 
-//extern ULong amd64g_calculate_FXAM ( ULong tag, ULong dbl );
+extern ULong amd64g_calculate_FXAM ( ULong tag, ULong dbl );
 
 extern ULong amd64g_calculate_RCR  ( 
                 ULong arg, ULong rot_amt, ULong rflags_in, Long sz 
@@ -173,10 +173,16 @@ extern void amd64g_dirtyhelper_CPUID ( VexGuestAMD64State* st );
 #define AMD64G_CC_MASK_P    (1 << AMD64G_CC_SHIFT_P)
 
 /* FPU flag masks */
-#define AMD64G_FC_MASK_C3   (1 << 14)
-#define AMD64G_FC_MASK_C2   (1 << 10)
-#define AMD64G_FC_MASK_C1   (1 << 9)
-#define AMD64G_FC_MASK_C0   (1 << 8)
+#define AMD64G_FC_SHIFT_C3   14
+#define AMD64G_FC_SHIFT_C2   10
+#define AMD64G_FC_SHIFT_C1   9
+#define AMD64G_FC_SHIFT_C0   8
+
+#define AMD64G_FC_MASK_C3    (1 << AMD64G_FC_SHIFT_C3)
+#define AMD64G_FC_MASK_C2    (1 << AMD64G_FC_SHIFT_C2)
+#define AMD64G_FC_MASK_C1    (1 << AMD64G_FC_SHIFT_C1)
+#define AMD64G_FC_MASK_C0    (1 << AMD64G_FC_SHIFT_C0)
+
 
 /* %RFLAGS thunk descriptors.  A four-word thunk is used to record
    details of the most recent flag-setting operation, so the flags can
index ec6ccf1af407065f1251fa96ac82a0e9796ae2c1..8e22dd97dc24ff38ac50e632e817f9a5d7b57c95 100644 (file)
@@ -1221,6 +1221,85 @@ IRExpr* guest_amd64_spechelper ( HChar* function_name,
 /*--- Supporting functions for x87 FPU activities.            ---*/
 /*---------------------------------------------------------------*/
 
+static inline Bool host_is_little_endian ( void )
+{
+   UInt x = 0x76543210;
+   UChar* p = (UChar*)(&x);
+   return toBool(*p == 0x10);
+}
+
+/* Inspect a value and its tag, as per the x87 'FXAM' instruction. */
+/* CALLED FROM GENERATED CODE: CLEAN HELPER */
+ULong amd64g_calculate_FXAM ( ULong tag, ULong dbl ) 
+{
+   Bool   mantissaIsZero;
+   Int    bexp;
+   UChar  sign;
+   UChar* f64;
+
+   vassert(host_is_little_endian());
+
+   /* vex_printf("calculate_FXAM ( %d, %llx ) .. ", tag, dbl ); */
+
+   f64  = (UChar*)(&dbl);
+   sign = toUChar( (f64[7] >> 7) & 1 );
+
+   /* First off, if the tag indicates the register was empty,
+      return 1,0,sign,1 */
+   if (tag == 0) {
+      /* vex_printf("Empty\n"); */
+      return AMD64G_FC_MASK_C3 | 0 | (sign << AMD64G_FC_SHIFT_C1) 
+                                   | AMD64G_FC_MASK_C0;
+   }
+
+   bexp = (f64[7] << 4) | ((f64[6] >> 4) & 0x0F);
+   bexp &= 0x7FF;
+
+   mantissaIsZero
+      = toBool(
+           (f64[6] & 0x0F) == 0 
+           && (f64[5] | f64[4] | f64[3] | f64[2] | f64[1] | f64[0]) == 0
+        );
+
+   /* If both exponent and mantissa are zero, the value is zero.
+      Return 1,0,sign,0. */
+   if (bexp == 0 && mantissaIsZero) {
+      /* vex_printf("Zero\n"); */
+      return AMD64G_FC_MASK_C3 | 0 
+                               | (sign << AMD64G_FC_SHIFT_C1) | 0;
+   }
+   
+   /* If exponent is zero but mantissa isn't, it's a denormal.
+      Return 1,1,sign,0. */
+   if (bexp == 0 && !mantissaIsZero) {
+      /* vex_printf("Denormal\n"); */
+      return AMD64G_FC_MASK_C3 | AMD64G_FC_MASK_C2 
+                               | (sign << AMD64G_FC_SHIFT_C1) | 0;
+   }
+
+   /* If the exponent is 7FF and the mantissa is zero, this is an infinity.
+      Return 0,1,sign,1. */
+   if (bexp == 0x7FF && mantissaIsZero) {
+      /* vex_printf("Inf\n"); */
+      return 0 | AMD64G_FC_MASK_C2 | (sign << AMD64G_FC_SHIFT_C1) 
+                                   | AMD64G_FC_MASK_C0;
+   }
+
+   /* If the exponent is 7FF and the mantissa isn't zero, this is a NaN.
+      Return 0,0,sign,1. */
+   if (bexp == 0x7FF && !mantissaIsZero) {
+      /* vex_printf("NaN\n"); */
+      return 0 | 0 | (sign << AMD64G_FC_SHIFT_C1) | AMD64G_FC_MASK_C0;
+   }
+
+   /* Uh, ok, we give up.  It must be a normal finite number.
+      Return 0,1,sign,0.
+   */
+   /* vex_printf("normal\n"); */
+   return 0 | AMD64G_FC_MASK_C2 | (sign << AMD64G_FC_SHIFT_C1) | 0;
+}
+
+
 // MAYBE NOT TRUE: /* CALLED FROM GENERATED CODE */
 // MAYBE NOT TRUE: /* DIRTY HELPER (writes guest state) */
 /* Initialise the x87 FPU state as per 'finit'. */
index df58a3d8d2e582d4265d8590e8618f58c941dd1b..69e63b100317033cb2cdfd91fd4b10cd513c64ec 100644 (file)
@@ -2394,8 +2394,7 @@ ULong dis_op2_E_G ( Prefix      pfx,
          dependency. */
       if ((op8 == Iop_Xor8 || (op8 == Iop_Sub8 && addSubCarry))
           && offsetIRegG(size,pfx,rm) == offsetIRegE(size,pfx,rm)) {
-         vassert(0); /* awaiting test case */
-         if (op8 == Iop_Sub8)
+         if (False && op8 == Iop_Sub8)
             vex_printf("vex amd64->IR: sbb %%r,%%r optimisation(1)\n");
         putIRegG(size,pfx,rm, mkU(ty,0));
       }
@@ -4602,25 +4601,25 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                put_ST_UNCHECKED(0, unop(Iop_AbsF64, get_ST(0)));
                break;
 
-//..             case 0xE5: { /* FXAM */
-//..                /* This is an interesting one.  It examines %st(0),
-//..                   regardless of whether the tag says it's empty or not.
-//..                   Here, just pass both the tag (in our format) and the
-//..                   value (as a double, actually a ULong) to a helper
-//..                   function. */
-//..                IRExpr** args
-//..                   = mkIRExprVec_2( unop(Iop_8Uto32, get_ST_TAG(0)),
-//..                                    unop(Iop_ReinterpF64asI64, 
-//..                                         get_ST_UNCHECKED(0)) );
-//..                put_C3210(mkIRExprCCall(
-//..                             Ity_I32
-//..                             0/*regparm*/, 
-//..                             "x86g_calculate_FXAM", &x86g_calculate_FXAM,
-//..                             args
-//..                         ));
-//..                DIP("fxam\n");
-//..                break;
-//..             }
+            case 0xE5: { /* FXAM */
+               /* This is an interesting one.  It examines %st(0),
+                  regardless of whether the tag says it's empty or not.
+                  Here, just pass both the tag (in our format) and the
+                  value (as a double, actually a ULong) to a helper
+                  function. */
+               IRExpr** args
+                  = mkIRExprVec_2( unop(Iop_8Uto64, get_ST_TAG(0)),
+                                   unop(Iop_ReinterpF64asI64, 
+                                        get_ST_UNCHECKED(0)) );
+               put_C3210(mkIRExprCCall(
+                            Ity_I64
+                            0/*regparm*/, 
+                            "amd64g_calculate_FXAM", &amd64g_calculate_FXAM,
+                            args
+                        ));
+               DIP("fxam\n");
+               break;
+            }
 
             case 0xE8: /* FLD1 */
                DIP("fld1\n");
@@ -5599,21 +5598,24 @@ ULong dis_FPU ( /*OUT*/Bool* decode_ok,
                fp_pop();
                break;
 
-//..             case 0xE0: /* FNSTSW %ax */
-//..                DIP("fnstsw %%ax\n");
-//..                /* Invent a plausible-looking FPU status word value and
-//..                   dump it in %AX:
-//..                      ((ftop & 7) << 11) | (c3210 & 0x4700)
-//..                */
-//..                putIReg(2, R_EAX,
-//..                   unop(Iop_32to16,
-//..                        binop(Iop_Or32,
-//..                              binop(Iop_Shl32, 
-//..                                    binop(Iop_And32, get_ftop(), mkU32(7)), 
-//..                                    mkU8(11)),
-//..                              binop(Iop_And32, get_C3210(), mkU32(0x4700))
-//..                )));
-//..                break;
+            case 0xE0: /* FNSTSW %ax */
+               DIP("fnstsw %%ax\n");
+               /* Invent a plausible-looking FPU status word value and
+                  dump it in %AX:
+                     ((ftop & 7) << 11) | (c3210 & 0x4700)
+               */
+               putIRegRAX(
+                  2,
+                  unop(Iop_32to16,
+                       binop(Iop_Or32,
+                             binop(Iop_Shl32, 
+                                   binop(Iop_And32, get_ftop(), mkU32(7)), 
+                                   mkU8(11)),
+                             binop(Iop_And32, 
+                                   unop(Iop_64to32, get_C3210()), 
+                                   mkU32(0x4700))
+               )));
+               break;
 
             case 0xE8 ... 0xEF: /* FUCOMIP %st(0),%st(?) */
                fp_do_ucomi_ST0_STi( (UInt)modrm - 0xE8, True );