VirtualBox

Changeset 94397 in vbox for trunk/src/VBox/VMM


Ignore:
Timestamp:
Mar 30, 2022 1:53:25 PM (3 years ago)
Author:
vboxsync
Message:

VMM/IEM: Implemented C version of fbstp; fixes to fst, fist and fistt (crazy stuff). bugref:9898

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/VMM/VMMAll/IEMAllAImplC.cpp

    r94387 r94397  
    33333333     * Normal or subnormal number.
    33343334     */
    3335     /* Do rounding. */
    3336     uint64_t uMantissaOut = uMantissaIn + uRoundingAdd;
    3337     if (uMantissaOut < uMantissaIn)
    3338     {
    3339         uMantissaOut >>= 1;
    3340         iExponentOut++;
    3341         Assert(iExponentOut < RTFLOAT32U_EXP_MAX);  /* checked above */
    3342         fFsw |= X86_FSW_C1;
    3343     }
    3344     /** @todo not sure if this is applied correctly, with the above carry check. */
    3345     else if (   (fFcw & X86_FCW_RC_MASK) == X86_FCW_RC_NEAREST
    3346              && !(fRoundedOff & RT_BIT_64(RTFLOAT80U_FRACTION_BITS - RTFLOAT32U_FRACTION_BITS - 1)))
    3347         uMantissaOut &= ~(uint64_t)1;
    3348 
    3349     /* Truncat the mantissa and set the return value. */
     3335    /* Do rounding - just truncate in near mode when midway on an even outcome. */
     3336    uint64_t uMantissaOut = uMantissaIn;
     3337    if (   (fFcw & X86_FCW_RC_MASK) != X86_FCW_RC_NEAREST
     3338        || (uMantissaIn & RT_BIT_64(RTFLOAT80U_FRACTION_BITS - RTFLOAT32U_FRACTION_BITS))
     3339        || fRoundedOff != uRoundingAdd)
     3340    {
     3341        uMantissaOut = uMantissaIn + uRoundingAdd;
     3342        if (uMantissaOut >= uMantissaIn)
     3343        { /* likely */ }
     3344        else
     3345        {
     3346            uMantissaOut >>= 1; /* (We don't need to add bit 63 here (the integer bit), as it will be chopped off below.) */
     3347            iExponentOut++;
     3348            Assert(iExponentOut < RTFLOAT32U_EXP_MAX);  /* checked above */
     3349            fFsw |= X86_FSW_C1;
     3350        }
     3351    }
     3352    else
     3353        uMantissaOut = uMantissaIn;
     3354
     3355    /* Truncate the mantissa and set the return value. */
    33503356    uMantissaOut >>= RTFLOAT80U_FRACTION_BITS - RTFLOAT32U_FRACTION_BITS;
    33513357
     
    35073513        if (iExponentOut <= 0)
    35083514        {
    3509             uMantissaIn = iExponentOut <= -63
    3510                         ? uMantissaIn != 0
    3511                         : (uMantissaIn >> (-iExponentOut + 1)) | ((uMantissaIn & (RT_BIT_64(-iExponentOut + 1) - 1)) != 0);
    3512             fRoundedOff = uMantissaIn & fRoundingOffMask;
     3515            uMantissaIn  = iExponentOut <= -63
     3516                         ? uMantissaIn != 0
     3517                         : (uMantissaIn >> (-iExponentOut + 1)) | ((uMantissaIn & (RT_BIT_64(-iExponentOut + 1) - 1)) != 0);
     3518            fRoundedOff  = uMantissaIn & fRoundingOffMask;
    35133519            if (fRoundedOff && fIsTiny)
    3514                 fFsw |= X86_FSW_UE;
    3515             iExponentOut   = 0;
     3520                fFsw    |= X86_FSW_UE;
     3521            iExponentOut = 0;
    35163522        }
    35173523    }
     
    35513557     * Normal or subnormal number.
    35523558     */
    3553     /* Do rounding. */
    3554     uint64_t uMantissaOut = uMantissaIn + uRoundingAdd;
    3555     if (uMantissaOut < uMantissaIn)
    3556     {
    3557         uMantissaOut >>= 1;
    3558         iExponentOut++;
    3559         Assert(iExponentOut < RTFLOAT64U_EXP_MAX);  /* checked above */
    3560         fFsw |= X86_FSW_C1;
    3561     }
    3562     /** @todo not sure if this is applied correctly, with the above carry check. */
    3563     else if (   (fFcw & X86_FCW_RC_MASK) == X86_FCW_RC_NEAREST
    3564              && !(fRoundedOff & RT_BIT_32(RTFLOAT80U_FRACTION_BITS - RTFLOAT64U_FRACTION_BITS - 1)))
    3565         uMantissaOut &= ~(uint64_t)1;
    3566 
    3567     /* Truncat the mantissa and set the return value. */
     3559    /* Do rounding - just truncate in near mode when midway on an even outcome. */
     3560    uint64_t uMantissaOut = uMantissaIn;
     3561    if (   (fFcw & X86_FCW_RC_MASK) != X86_FCW_RC_NEAREST
     3562        || (uMantissaIn & RT_BIT_32(RTFLOAT80U_FRACTION_BITS - RTFLOAT64U_FRACTION_BITS))
     3563        || fRoundedOff != uRoundingAdd)
     3564    {
     3565        uMantissaOut = uMantissaIn + uRoundingAdd;
     3566        if (uMantissaOut >= uMantissaIn)
     3567        { /* likely */ }
     3568        else
     3569        {
     3570            uMantissaOut >>= 1; /* (We don't need to add bit 63 here (the integer bit), as it will be chopped off below.) */
     3571            iExponentOut++;
     3572            Assert(iExponentOut < RTFLOAT64U_EXP_MAX);  /* checked above */
     3573            fFsw |= X86_FSW_C1;
     3574        }
     3575    }
     3576    else
     3577        uMantissaOut = uMantissaIn;
     3578
     3579    /* Truncate the mantissa and set the return value. */
    35683580    uMantissaOut >>= RTFLOAT80U_FRACTION_BITS - RTFLOAT64U_FRACTION_BITS;
    35693581
     
    37043716 * where we'll drop off all but bit 63.
    37053717 */
    3706 #define EMIT_FIST(a_cBits, a_iType, a_iTypeMin, a_iTypeMax, a_iTypeIndefinite) \
     3718#define EMIT_FIST(a_cBits, a_iType, a_iTypeMin, a_iTypeIndefinite) \
    37073719IEM_DECL_IMPL_DEF(void, iemAImpl_fist_r80_to_i ## a_cBits,(PCX86FXSTATE pFpuState, uint16_t *pu16FSW, \
    37083720                                                           a_iType *piDst, PCRTFLOAT80U pr80Val)) \
     
    37543766            else \
    37553767            { \
    3756                 AssertMsg(iExponent == a_cBits - 2, \
     3768                /* overflowed after rounding. */ \
     3769                AssertMsg(iExponent == a_cBits - 2 && uMantissa == RT_BIT_64(a_cBits - 1), \
    37573770                          ("e=%d m=%#RX64 (org %#RX64) s=%d; shift=%d ro=%#RX64 rm=%#RX64 ra=%#RX64\n", iExponent, uMantissa, \
    37583771                          pr80Val->s.uMantissa, fSignIn, cShiftOff, fRoundedOff, fRoundingOffMask, uRoundingAdd)); \
    37593772                \
    37603773                /* Special case for the integer minimum value. */ \
    3761                 if (fSignIn && uMantissa == RT_BIT_64(a_cBits - 1)) \
     3774                if (fSignIn) \
    37623775                { \
    37633776                    *piDst = a_iTypeMin; \
     
    37683781                else \
    37693782                { \
    3770                     /* overflowed after rounding. */ \
    37713783                    fFsw |= X86_FSW_IE; \
    37723784                    if (fFcw & X86_FCW_IM) \
    3773                     { \
    3774                         if (   (fSignIn && (fFcw & X86_FCW_RC_MASK) != X86_FCW_RC_DOWN) \
    3775                             || (!fSignIn && uMantissa == RT_BIT_64(a_cBits - 1)) ) \
    3776                             *piDst = a_iTypeMin; \
    3777                         else if (!fSignIn && (fFcw & X86_FCW_RC_MASK) != X86_FCW_RC_UP) \
    3778                             *piDst = a_iTypeMax; \
    3779                         else \
    3780                         { \
    3781                             *piDst = 0; \
    3782                             fFsw |= X86_FSW_C1; \
    3783                         } \
    3784                     } \
     3785                        *piDst = a_iTypeMin; \
    37853786                    else \
    37863787                        fFsw |= X86_FSW_ES | X86_FSW_B | (7 << X86_FSW_TOP_SHIFT); \
     
    38193820            if (!(fFcw & X86_FCW_PM)) \
    38203821                fFsw |= X86_FSW_ES | X86_FSW_B; \
     3822        } \
     3823        /* \
     3824         * Special MIN case. \
     3825         */ \
     3826        else if (   fSignIn && iExponent == a_cBits - 1 \
     3827                 && ( a_cBits < 64 && (fFcw & X86_FCW_RC_MASK) != X86_FCW_RC_DOWN \
     3828                     ? uMantissa < (RT_BIT_64(63) | RT_BIT_64(65 - a_cBits)) \
     3829                     : uMantissa == RT_BIT_64(63))) \
     3830        { \
     3831            *piDst = a_iTypeMin;  \
     3832            if (uMantissa & (RT_BIT_64(64 - a_cBits + 1) - 1)) \
     3833            { \
     3834                fFsw |= X86_FSW_PE; \
     3835                if (!(fFcw & X86_FCW_PM)) \
     3836                    fFsw |= X86_FSW_ES | X86_FSW_B; \
     3837            } \
    38213838        } \
    38223839        /* \
     
    38683885    *pu16FSW = fFsw; \
    38693886}
    3870 EMIT_FIST(64, int64_t, INT64_MIN, INT64_MAX, X86_FPU_INT64_INDEFINITE)
    3871 EMIT_FIST(32, int32_t, INT32_MIN, INT32_MAX, X86_FPU_INT32_INDEFINITE)
    3872 EMIT_FIST(16, int16_t, INT16_MIN, INT16_MAX, X86_FPU_INT16_INDEFINITE)
    3873 
    3874 
    3875 #define EMIT_FISTT(a_cBits, a_iType, a_iTypeMin, a_iTypeMax, a_iTypeIndefinite) \
     3887EMIT_FIST(64, int64_t, INT64_MIN, X86_FPU_INT64_INDEFINITE)
     3888EMIT_FIST(32, int32_t, INT32_MIN, X86_FPU_INT32_INDEFINITE)
     3889EMIT_FIST(16, int16_t, INT16_MIN, X86_FPU_INT16_INDEFINITE)
     3890
     3891
     3892/*
     3893 * The FISTT instruction was added with SSE3 and are a lot simpler than FIST.
     3894 *
     3895 * The 16-bit version is a bit peculiar, though, as it seems to be raising IE
     3896 * as if it was the 32-bit version (i.e. starting with exp 31 instead of 15),
     3897 * thus the @a a_cBitsIn.
     3898 */
     3899#define EMIT_FISTT(a_cBits, a_cBitsIn, a_iType, a_iTypeMin, a_iTypeMax, a_iTypeIndefinite) \
    38763900IEM_DECL_IMPL_DEF(void, iemAImpl_fistt_r80_to_i ## a_cBits,(PCX86FXSTATE pFpuState, uint16_t *pu16FSW, \
    38773901                                                            a_iType *piDst, PCRTFLOAT80U pr80Val)) \
     
    38893913        int32_t        iExponent = (int32_t)pr80Val->s.uExponent - RTFLOAT80U_EXP_BIAS; \
    38903914        \
    3891         if ((uint32_t)iExponent <= a_cBits - 2) \
     3915        if ((uint32_t)iExponent <= a_cBitsIn - 2) \
    38923916        { \
    38933917            unsigned const cShiftOff        = 63 - iExponent; \
     
    38953919            uint64_t const fRoundedOff      = uMantissa & fRoundingOffMask; \
    38963920            uMantissa >>= cShiftOff; \
    3897             Assert(!(uMantissa & RT_BIT_64(a_cBits - 1))); \
     3921            /*Assert(!(uMantissa & RT_BIT_64(a_cBits - 1)));*/ \
    38983922            if (!fSignIn) \
    38993923                *piDst = (a_iType)uMantissa; \
     
    39173941            if (!(fFcw & X86_FCW_PM)) \
    39183942                fFsw |= X86_FSW_ES | X86_FSW_B; \
     3943        } \
     3944        /* \
     3945         * Special MIN case. \
     3946         */ \
     3947        else if (   fSignIn && iExponent == a_cBits - 1 \
     3948                 && (a_cBits < 64 \
     3949                     ? uMantissa < (RT_BIT_64(63) | RT_BIT_64(65 - a_cBits)) \
     3950                     : uMantissa == RT_BIT_64(63)) ) \
     3951        { \
     3952            *piDst = a_iTypeMin;  \
     3953            if (uMantissa & (RT_BIT_64(64 - a_cBits + 1) - 1)) \
     3954            { \
     3955                fFsw |= X86_FSW_PE; \
     3956                if (!(fFcw & X86_FCW_PM)) \
     3957                    fFsw |= X86_FSW_ES | X86_FSW_B; \
     3958            } \
     3959        } \
     3960        /* \
     3961         * Figure this weirdness. \
     3962         */ \
     3963        else if (a_cBits == 16 && fSignIn && iExponent == 31 && uMantissa < UINT64_C(0x8000100000000000) ) \
     3964        { \
     3965            *piDst = 0;  \
     3966            if (uMantissa & (RT_BIT_64(64 - a_cBits + 1) - 1)) \
     3967            { \
     3968                fFsw |= X86_FSW_PE; \
     3969                if (!(fFcw & X86_FCW_PM)) \
     3970                    fFsw |= X86_FSW_ES | X86_FSW_B; \
     3971            } \
    39193972        } \
    39203973        /* \
     
    39594012    *pu16FSW = fFsw; \
    39604013}
    3961 EMIT_FISTT(64, int64_t, INT64_MIN, INT64_MAX, X86_FPU_INT64_INDEFINITE)
    3962 EMIT_FISTT(32, int32_t, INT32_MIN, INT32_MAX, X86_FPU_INT32_INDEFINITE)
    3963 EMIT_FISTT(16, int16_t, INT16_MIN, INT16_MAX, 0 /* X86_FPU_INT16_INDEFINITE - weird weird weird! */)
     4014EMIT_FISTT(64, 64, int64_t, INT64_MIN, INT64_MAX, X86_FPU_INT64_INDEFINITE)
     4015EMIT_FISTT(32, 32, int32_t, INT32_MIN, INT32_MAX, X86_FPU_INT32_INDEFINITE)
     4016EMIT_FISTT(16, 32, int16_t, INT16_MIN, INT16_MAX, 0 /* X86_FPU_INT16_INDEFINITE - weird weird weird! */)
    39644017
    39654018
     
    39674020                                                 PRTPBCD80U pd80Dst, PCRTFLOAT80U pr80Src))
    39684021{
    3969     RT_NOREF(pFpuState, pu16FSW, pd80Dst, pr80Src);
    3970     AssertReleaseFailed();
     4022    /*static RTPBCD80U const s_ad80MaxMin[2] = { RTPBCD80U_INIT_MAX(),   RTPBCD80U_INIT_MIN() };*/
     4023    static RTPBCD80U const s_ad80Zeros[2]  = { RTPBCD80U_INIT_ZERO(0), RTPBCD80U_INIT_ZERO(1) };
     4024    static RTPBCD80U const s_ad80One[2]    = { RTPBCD80U_INIT_C(0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,1),
     4025                                               RTPBCD80U_INIT_C(1, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,0, 0,1) };
     4026    static RTPBCD80U const s_d80Indefinite = RTPBCD80U_INIT_INDEFINITE();
     4027
     4028    uint16_t const fFcw    = pFpuState->FCW;
     4029    uint16_t       fFsw    = (pFpuState->FSW & (X86_FSW_C0 | X86_FSW_C2 | X86_FSW_C3));
     4030    bool const     fSignIn = pr80Src->s.fSign;
     4031
     4032    /*
     4033     * Deal with normal numbers first.
     4034     */
     4035    if (RTFLOAT80U_IS_NORMAL(pr80Src))
     4036    {
     4037        uint64_t       uMantissa = pr80Src->s.uMantissa;
     4038        int32_t        iExponent = (int32_t)pr80Src->s.uExponent - RTFLOAT80U_EXP_BIAS;
     4039        if (   (uint32_t)iExponent <= 58
     4040            || ((uint32_t)iExponent == 59 && uMantissa <= UINT64_C(0xde0b6b3a763fffff)) )
     4041        {
     4042            unsigned const cShiftOff        = 63 - iExponent;
     4043            uint64_t const fRoundingOffMask = RT_BIT_64(cShiftOff) - 1;
     4044            uint64_t const uRoundingAdd     = (fFcw & X86_FCW_RC_MASK) == X86_FCW_RC_NEAREST
     4045                                            ? RT_BIT_64(cShiftOff - 1)
     4046                                            : (fFcw & X86_FCW_RC_MASK) == (fSignIn ? X86_FCW_RC_DOWN : X86_FCW_RC_UP)
     4047                                            ? fRoundingOffMask
     4048                                            : 0;
     4049            uint64_t       fRoundedOff      = uMantissa & fRoundingOffMask;
     4050
     4051            uMantissa >>= cShiftOff;
     4052            uint64_t const uRounding = (fRoundedOff + uRoundingAdd) >> cShiftOff;
     4053            uMantissa += uRounding;
     4054            if (uMantissa <= (uint64_t)RTPBCD80U_MAX)
     4055            {
     4056                if (fRoundedOff)
     4057                {
     4058                    if ((uMantissa & 1) && (fFcw & X86_FCW_RC_MASK) == X86_FCW_RC_NEAREST && fRoundedOff == uRoundingAdd)
     4059                        uMantissa &= ~(uint64_t)1; /* round to even number if equal distance between up/down. */
     4060                    else if (uRounding)
     4061                        fFsw |= X86_FSW_C1;
     4062                    fFsw |= X86_FSW_PE;
     4063                    if (!(fFcw & X86_FCW_PM))
     4064                        fFsw |= X86_FSW_ES | X86_FSW_B;
     4065                }
     4066
     4067                pd80Dst->s.fSign = fSignIn;
     4068                pd80Dst->s.uPad  = 0;
     4069                for (size_t iPair = 0; iPair < RT_ELEMENTS(pd80Dst->s.abPairs); iPair++)
     4070                {
     4071                    unsigned const uDigits = uMantissa % 100;
     4072                    uMantissa /= 100;
     4073                    uint8_t const bLo = uDigits % 10;
     4074                    uint8_t const bHi = uDigits / 10;
     4075                    pd80Dst->s.abPairs[iPair] = RTPBCD80U_MAKE_PAIR(bHi, bLo);
     4076                }
     4077            }
     4078            else
     4079            {
     4080                /* overflowed after rounding. */
     4081                fFsw |= X86_FSW_IE;
     4082                if (fFcw & X86_FCW_IM)
     4083                    *pd80Dst = s_d80Indefinite;
     4084                else
     4085                    fFsw |= X86_FSW_ES | X86_FSW_B | (7 << X86_FSW_TOP_SHIFT);
     4086            }
     4087        }
     4088        /*
     4089         * Tiny sub-zero numbers.
     4090         */
     4091        else if (iExponent < 0)
     4092        {
     4093            if (!fSignIn)
     4094            {
     4095                if (   (fFcw & X86_FCW_RC_MASK) == X86_FCW_RC_UP
     4096                    || (iExponent == -1 && (fFcw & X86_FCW_RC_MASK) == X86_FCW_RC_NEAREST))
     4097                {
     4098                    *pd80Dst = s_ad80One[fSignIn];
     4099                    fFsw |= X86_FSW_C1;
     4100                }
     4101                else
     4102                    *pd80Dst = s_ad80Zeros[fSignIn];
     4103            }
     4104            else
     4105            {
     4106                if (   (fFcw & X86_FCW_RC_MASK) == X86_FCW_RC_UP
     4107                    || (fFcw & X86_FCW_RC_MASK) == X86_FCW_RC_ZERO
     4108                    || (iExponent < -1 && (fFcw & X86_FCW_RC_MASK) == X86_FCW_RC_NEAREST))
     4109                    *pd80Dst = s_ad80Zeros[fSignIn];
     4110                else
     4111                {
     4112                    *pd80Dst = s_ad80One[fSignIn];
     4113                    fFsw |= X86_FSW_C1;
     4114                }
     4115            }
     4116            fFsw |= X86_FSW_PE;
     4117            if (!(fFcw & X86_FCW_PM))
     4118                fFsw |= X86_FSW_ES | X86_FSW_B;
     4119        }
     4120        /*
     4121         * Too large/small number outside the target integer range.
     4122         */
     4123        else
     4124        {
     4125            fFsw |= X86_FSW_IE;
     4126            if (fFcw & X86_FCW_IM)
     4127                *pd80Dst = s_d80Indefinite;
     4128            else
     4129                fFsw |= X86_FSW_ES | X86_FSW_B | (7 << X86_FSW_TOP_SHIFT);
     4130        }
     4131    }
     4132    /*
     4133     * Map both +0 and -0 to integer zero (signless/+).
     4134     */
     4135    else if (RTFLOAT80U_IS_ZERO(pr80Src))
     4136        *pd80Dst = s_ad80Zeros[fSignIn];
     4137    /*
     4138     * Denormals are just really tiny sub-zero numbers that are either rounded
     4139     * to zero, 1 or -1 depending on sign and rounding control.
     4140     */
     4141    else if (RTFLOAT80U_IS_PSEUDO_DENORMAL(pr80Src) || RTFLOAT80U_IS_DENORMAL(pr80Src))
     4142    {
     4143        if ((fFcw & X86_FCW_RC_MASK) != (fSignIn ? X86_FCW_RC_DOWN : X86_FCW_RC_UP))
     4144            *pd80Dst = s_ad80Zeros[fSignIn];
     4145        else
     4146        {
     4147            *pd80Dst = s_ad80One[fSignIn];
     4148            fFsw |= X86_FSW_C1;
     4149        }
     4150        fFsw |= X86_FSW_PE;
     4151        if (!(fFcw & X86_FCW_PM))
     4152            fFsw |= X86_FSW_ES | X86_FSW_B;
     4153    }
     4154    /*
     4155     * All other special values are considered invalid arguments and result
     4156     * in an IE exception and indefinite value if masked.
     4157     */
     4158    else
     4159    {
     4160        fFsw |= X86_FSW_IE;
     4161        if (fFcw & X86_FCW_IM)
     4162            *pd80Dst = s_d80Indefinite;
     4163        else
     4164            fFsw |= X86_FSW_ES | X86_FSW_B | (7 << X86_FSW_TOP_SHIFT);
     4165    }
     4166    *pu16FSW = fFsw;
    39714167}
    39724168
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette