From: Julian Seward Date: Mon, 3 Oct 2005 01:02:40 +0000 (+0000) Subject: x86 front end: implement FXTRACT. I knew there was a reason I'd been X-Git-Tag: svn/VALGRIND_3_1_1^2~86 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a7e18e6ac845afcf63d586444f6a0120ecbed831;p=thirdparty%2Fvalgrind.git x86 front end: implement FXTRACT. I knew there was a reason I'd been avoiding this ... git-svn-id: svn://svn.valgrind.org/vex/trunk@1405 --- diff --git a/VEX/priv/guest-x86/gdefs.h b/VEX/priv/guest-x86/gdefs.h index 310423929a..39c6e49857 100644 --- a/VEX/priv/guest-x86/gdefs.h +++ b/VEX/priv/guest-x86/gdefs.h @@ -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 diff --git a/VEX/priv/guest-x86/ghelpers.c b/VEX/priv/guest-x86/ghelpers.c index fa2323bd30..464cedb450 100644 --- a/VEX/priv/guest-x86/ghelpers.c +++ b/VEX/priv/guest-x86/ghelpers.c @@ -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 .. ---*/ /*----------------------------------------------*/ diff --git a/VEX/priv/guest-x86/toIR.c b/VEX/priv/guest-x86/toIR.c index ebc81c4d93..e6ec7851fd 100644 --- a/VEX/priv/guest-x86/toIR.c +++ b/VEX/priv/guest-x86/toIR.c @@ -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);