kernels/linux-2.4.0/arch/arm/nwfpe/softfloat.c
/*
-------------------------------------------------------------------------------
Takes an abstract floating-point value having sign `zSign', exponent `zExp',
and extended significand formed by the concatenation of `zSig0' and `zSig1',
and returns the proper extended double-precision floating-point value
corresponding to the abstract input.  Ordinarily, the abstract value is
rounded and packed into the extended double-precision format, with the
inexact exception raised if the abstract input cannot be represented
exactly.  If the abstract value is too large, however, the overflow and
inexact exceptions are raised and an infinity or maximal finite value is
returned.  If the abstract value is too small, the input value is rounded to
a subnormal number, and the underflow and inexact exceptions are raised if
the abstract input cannot be represented exactly as a subnormal extended
double-precision floating-point number.
    If `roundingPrecision' is 32 or 64, the result is rounded to the same
number of bits as single or double precision, respectively.  Otherwise, the
result is rounded to the full precision of the extended double-precision
format.
    The input significand must be normalized or smaller.  If the input
significand is not normalized, `zExp' must be 0; in that case, the result
returned is a subnormal number, and it must not require rounding.  The
handling of underflow and overflow follows the IEC/IEEE Standard for Binary
Floating-point Arithmetic.
-------------------------------------------------------------------------------
*/
Takes an abstract floating-point value having sign `zSign', exponent `zExp',
and extended significand formed by the concatenation of `zSig0' and `zSig1',
and returns the proper extended double-precision floating-point value
corresponding to the abstract input.  Ordinarily, the abstract value is
rounded and packed into the extended double-precision format, with the
inexact exception raised if the abstract input cannot be represented
exactly.  If the abstract value is too large, however, the overflow and
inexact exceptions are raised and an infinity or maximal finite value is
returned.  If the abstract value is too small, the input value is rounded to
a subnormal number, and the underflow and inexact exceptions are raised if
the abstract input cannot be represented exactly as a subnormal extended
double-precision floating-point number.
If `roundingPrecision' is 32 or 64, the result is rounded to the same
number of bits as single or double precision, respectively.  Otherwise, the
result is rounded to the full precision of the extended double-precision
format.
The input significand must be normalized or smaller.  If the input
significand is not normalized, `zExp' must be 0; in that case, the result
returned is a subnormal number, and it must not require rounding.  The
handling of underflow and overflow follows the IEC/IEEE Standard for Binary
Floating-point Arithmetic.
Takes an abstract floating - point value having sign ` zSign ' exponent ` zExp ' and extended significand formed by the concatenation of ` zSig0 ' and ` zSig1 ' and returns the proper extended double - precision floating - point value corresponding to the abstract input . Ordinarily the abstract value is rounded and packed into the extended double - precision format with the inexact exception raised if the abstract input cannot be represented exactly . If the abstract value is too large however the overflow and inexact exceptions are raised and an infinity or maximal finite value is returned . If the abstract value is too small the input value is rounded to a subnormal number and the underflow and inexact exceptions are raised if the abstract input cannot be represented exactly as a subnormal extended double - precision floating - point number . If ` roundingPrecision ' is 32 or 64 the result is rounded to the same number of bits as single or double precision respectively . Otherwise the result is rounded to the full precision of the extended double - precision format . The input significand must be normalized or smaller . If the input significand is not normalized ` zExp ' must be 0 ; in that case the result returned is a subnormal number and it must not require rounding . The handling of underflow and overflow follows the IEC / IEEE Standard for Binary Floating - point Arithmetic .
static floatx80
 roundAndPackFloatx80(
     int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1
 )
{
    int8 roundingMode;
    flag roundNearestEven, increment, isTiny;
    int64 roundIncrement, roundMask, roundBits;
    roundingMode = float_rounding_mode;
    roundNearestEven = ( roundingMode == float_round_nearest_even );
    if ( roundingPrecision == 80 ) goto precision80;
    if ( roundingPrecision == 64 ) {
        roundIncrement = LIT64( 0x0000000000000400 );
        roundMask = LIT64( 0x00000000000007FF );
    }
    else if ( roundingPrecision == 32 ) {
        roundIncrement = LIT64( 0x0000008000000000 );
        roundMask = LIT64( 0x000000FFFFFFFFFF );
    }
    else {
        goto precision80;
    }
    zSig0 |= ( zSig1 != 0 );
    if ( ! roundNearestEven ) {
        if ( roundingMode == float_round_to_zero ) {
            roundIncrement = 0;
        }
        else {
            roundIncrement = roundMask;
            if ( zSign ) {
                if ( roundingMode == float_round_up ) roundIncrement = 0;
            }
            else {
                if ( roundingMode == float_round_down ) roundIncrement = 0;
            }
        }
    }
    roundBits = zSig0 & roundMask;
    if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) {
        if (    ( 0x7FFE < zExp )
             || ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) )
           ) {
            goto overflow;
        }
        if ( zExp <= 0 ) {
            isTiny =
                   ( float_detect_tininess == float_tininess_before_rounding )
                || ( zExp < 0 )
                || ( zSig0 <= zSig0 + roundIncrement );
            shift64RightJamming( zSig0, 1 - zExp, &zSig0 );
            zExp = 0;
            roundBits = zSig0 & roundMask;
            if ( isTiny && roundBits ) float_raise( float_flag_underflow );
            if ( roundBits ) float_exception_flags |= float_flag_inexact;
            zSig0 += roundIncrement;
            if ( (sbits64) zSig0 < 0 ) zExp = 1;
            roundIncrement = roundMask + 1;
            if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) {
                roundMask |= roundIncrement;
            }
            zSig0 &= ~ roundMask;
            return packFloatx80( zSign, zExp, zSig0 );
        }
    }
    if ( roundBits ) float_exception_flags |= float_flag_inexact;
    zSig0 += roundIncrement;
    if ( zSig0 < roundIncrement ) {
        ++zExp;
        zSig0 = LIT64( 0x8000000000000000 );
    }
    roundIncrement = roundMask + 1;
    if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) {
        roundMask |= roundIncrement;
    }
    zSig0 &= ~ roundMask;
    if ( zSig0 == 0 ) zExp = 0;
    return packFloatx80( zSign, zExp, zSig0 );
 precision80:
    increment = ( (sbits64) zSig1 < 0 );
    if ( ! roundNearestEven ) {
        if ( roundingMode == float_round_to_zero ) {
            increment = 0;
        }
        else {
            if ( zSign ) {
                increment = ( roundingMode == float_round_down ) && zSig1;
            }
            else {
                increment = ( roundingMode == float_round_up ) && zSig1;
            }
        }
    }
    if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) {
        if (    ( 0x7FFE < zExp )
             || (    ( zExp == 0x7FFE )
                  && ( zSig0 == LIT64( 0xFFFFFFFFFFFFFFFF ) )
                  && increment
                )
           ) {
            roundMask = 0;
 overflow:
            float_raise( float_flag_overflow | float_flag_inexact );
            if (    ( roundingMode == float_round_to_zero )
                 || ( zSign && ( roundingMode == float_round_up ) )
                 || ( ! zSign && ( roundingMode == float_round_down ) )
               ) {
                return packFloatx80( zSign, 0x7FFE, ~ roundMask );
            }
            return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) );
        }
        if ( zExp <= 0 ) {
            isTiny =
                   ( float_detect_tininess == float_tininess_before_rounding )
                || ( zExp < 0 )
                || ! increment
                || ( zSig0 < LIT64( 0xFFFFFFFFFFFFFFFF ) );
            shift64ExtraRightJamming( zSig0, zSig1, 1 - zExp, &zSig0, &zSig1 );
            zExp = 0;
            if ( isTiny && zSig1 ) float_raise( float_flag_underflow );
            if ( zSig1 ) float_exception_flags |= float_flag_inexact;
            if ( roundNearestEven ) {
                increment = ( (sbits64) zSig1 < 0 );
            }
            else {
                if ( zSign ) {
                    increment = ( roundingMode == float_round_down ) && zSig1;
                }
                else {
                    increment = ( roundingMode == float_round_up ) && zSig1;
                }
            }
            if ( increment ) {
                ++zSig0;
                zSig0 &= ~ ( ( zSig1 + zSig1 == 0 ) & roundNearestEven );
                if ( (sbits64) zSig0 < 0 ) zExp = 1;
            }
            return packFloatx80( zSign, zExp, zSig0 );
        }
    }
    if ( zSig1 ) float_exception_flags |= float_flag_inexact;
    if ( increment ) {
        ++zSig0;
        if ( zSig0 == 0 ) {
            ++zExp;
            zSig0 = LIT64( 0x8000000000000000 );
        }
        else {
            zSig0 &= ~ ( ( zSig1 + zSig1 == 0 ) & roundNearestEven );
        }
    }
    else {
        if ( zSig0 == 0 ) zExp = 0;
    }
    return packFloatx80( zSign, zExp, zSig0 );
}
static floatx80 roundAndPackFloatx80 ( int8 roundingPrecision , flag zSign , int32 zExp , bits64 zSig0 , bits64 zSig1 ) { int8 roundingMode ; flag roundNearestEven , increment , isTiny ; int64 roundIncrement , roundMask , roundBits ; roundingMode = float_rounding_mode ; roundNearestEven = ( roundingMode == float_round_nearest_even ) ; if ( roundingPrecision == 80 ) goto precision80 ; if ( roundingPrecision == 64 ) { roundIncrement = LIT64 ( 0x0000000000000400 ) ; roundMask = LIT64 ( 0x00000000000007FF ) ; } else if ( roundingPrecision == 32 ) { roundIncrement = LIT64 ( 0x0000008000000000 ) ; roundMask = LIT64 ( 0x000000FFFFFFFFFF ) ; } else { goto precision80 ; } zSig0 |= ( zSig1 != 0 ) ; if ( ! roundNearestEven ) { if ( roundingMode == float_round_to_zero ) { roundIncrement = 0 ; } else { roundIncrement = roundMask ; if ( zSign ) { if ( roundingMode == float_round_up ) roundIncrement = 0 ; } else { if ( roundingMode == float_round_down ) roundIncrement = 0 ; } } } roundBits = zSig0 & roundMask ; if ( 0x7FFD <= ( bits32 ) ( zExp - 1 ) ) { if ( ( 0x7FFE < zExp ) || ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) ) ) { goto overflow ; } if ( zExp <= 0 ) { isTiny = ( float_detect_tininess == float_tininess_before_rounding ) || ( zExp < 0 ) || ( zSig0 <= zSig0 + roundIncrement ) ; shift64RightJamming ( zSig0 , 1 - zExp , & zSig0 ) ; zExp = 0 ; roundBits = zSig0 & roundMask ; if ( isTiny && roundBits ) float_raise ( float_flag_underflow ) ; if ( roundBits ) float_exception_flags |= float_flag_inexact ; zSig0 += roundIncrement ; if ( ( sbits64 ) zSig0 < 0 ) zExp = 1 ; roundIncrement = roundMask + 1 ; if ( roundNearestEven && ( roundBits << 1 == roundIncrement ) ) { roundMask |= roundIncrement ; } zSig0 &= ~ roundMask ; return packFloatx80 ( zSign , zExp , zSig0 ) ; } } if ( roundBits ) float_exception_flags |= float_flag_inexact ; zSig0 += roundIncrement ; if ( zSig0 < roundIncrement ) { ++ zExp ; zSig0 = LIT64 ( 0x8000000000000000 ) ; } roundIncrement = roundMask + 1 ; if ( roundNearestEven && ( roundBits << 1 == roundIncrement ) ) { roundMask |= roundIncrement ; } zSig0 &= ~ roundMask ; if ( zSig0 == 0 ) zExp = 0 ; return packFloatx80 ( zSign , zExp , zSig0 ) ; precision80 : increment = ( ( sbits64 ) zSig1 < 0 ) ; if ( ! roundNearestEven ) { if ( roundingMode == float_round_to_zero ) { increment = 0 ; } else { if ( zSign ) { increment = ( roundingMode == float_round_down ) && zSig1 ; } else { increment = ( roundingMode == float_round_up ) && zSig1 ; } } } if ( 0x7FFD <= ( bits32 ) ( zExp - 1 ) ) { if ( ( 0x7FFE < zExp ) || ( ( zExp == 0x7FFE ) && ( zSig0 == LIT64 ( 0xFFFFFFFFFFFFFFFF ) ) && increment ) ) { roundMask = 0 ; overflow : float_raise ( float_flag_overflow | float_flag_inexact ) ; if ( ( roundingMode == float_round_to_zero ) || ( zSign && ( roundingMode == float_round_up ) ) || ( ! zSign && ( roundingMode == float_round_down ) ) ) { return packFloatx80 ( zSign , 0x7FFE , ~ roundMask ) ; } return packFloatx80 ( zSign , 0x7FFF , LIT64 ( 0x8000000000000000 ) ) ; } if ( zExp <= 0 ) { isTiny = ( float_detect_tininess == float_tininess_before_rounding ) || ( zExp < 0 ) || ! increment || ( zSig0 < LIT64 ( 0xFFFFFFFFFFFFFFFF ) ) ; shift64ExtraRightJamming ( zSig0 , zSig1 , 1 - zExp , & zSig0 , & zSig1 ) ; zExp = 0 ; if ( isTiny && zSig1 ) float_raise ( float_flag_underflow ) ; if ( zSig1 ) float_exception_flags |= float_flag_inexact ; if ( roundNearestEven ) { increment = ( ( sbits64 ) zSig1 < 0 ) ; } else { if ( zSign ) { increment = ( roundingMode == float_round_down ) && zSig1 ; } else { increment = ( roundingMode == float_round_up ) && zSig1 ; } } if ( increment ) { ++ zSig0 ; zSig0 &= ~ ( ( zSig1 + zSig1 == 0 ) & roundNearestEven ) ; if ( ( sbits64 ) zSig0 < 0 ) zExp = 1 ; } return packFloatx80 ( zSign , zExp , zSig0 ) ; } } if ( zSig1 ) float_exception_flags |= float_flag_inexact ; if ( increment ) { ++ zSig0 ; if ( zSig0 == 0 ) { ++ zExp ; zSig0 = LIT64 ( 0x8000000000000000 ) ; } else { zSig0 &= ~ ( ( zSig1 + zSig1 == 0 ) & roundNearestEven ) ; } } else { if ( zSig0 == 0 ) zExp = 0 ; } return packFloatx80 ( zSign , zExp , zSig0 ) ; }
Takes an abstract floating-point value having sign `zSign', exponent `zExp',
and extended significand formed by the concatenation of `zSig0' and `zSig1',
and returns the proper extended double-precision floating-point value
corresponding to the abstract input.
Takes an abstract floating - point value having sign ` zSign ' exponent ` zExp ' and extended significand formed by the concatenation of ` zSig0 ' and ` zSig1 ' and returns the proper extended double - precision floating - point value corresponding to the abstract input .