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
#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
/*--- 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'. */
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));
}
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");
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 );