From: Julian Seward Date: Mon, 25 Jul 2005 11:58:34 +0000 (+0000) Subject: Implement a couple of missing x87 insns. X-Git-Tag: svn/VALGRIND_3_0_1^2~35 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bff858fd9d21b108cd845601acf539bafda17335;p=thirdparty%2Fvalgrind.git Implement a couple of missing x87 insns. git-svn-id: svn://svn.valgrind.org/vex/trunk@1299 --- diff --git a/VEX/priv/guest-amd64/gdefs.h b/VEX/priv/guest-amd64/gdefs.h index d6a3e436d1..218c298289 100644 --- a/VEX/priv/guest-amd64/gdefs.h +++ b/VEX/priv/guest-amd64/gdefs.h @@ -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 diff --git a/VEX/priv/guest-amd64/ghelpers.c b/VEX/priv/guest-amd64/ghelpers.c index ec6ccf1af4..8e22dd97dc 100644 --- a/VEX/priv/guest-amd64/ghelpers.c +++ b/VEX/priv/guest-amd64/ghelpers.c @@ -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'. */ diff --git a/VEX/priv/guest-amd64/toIR.c b/VEX/priv/guest-amd64/toIR.c index df58a3d8d2..69e63b1003 100644 --- a/VEX/priv/guest-amd64/toIR.c +++ b/VEX/priv/guest-amd64/toIR.c @@ -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 );