diff options
author | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-11-18 14:33:24 +0000 |
---|---|---|
committer | pbrook <pbrook@c046a42c-6fe2-441c-8c8c-71466251a162> | 2007-11-18 14:33:24 +0000 |
commit | f090c9d4ad5812fb92843d6470a1111c15190c4c (patch) | |
tree | d87c6a10eeefb28eb66dc88ebee02a92eabe2812 /fpu | |
parent | b881c2c6e774d40b33980f00f830431deed9e896 (diff) | |
download | qemu-f090c9d4ad5812fb92843d6470a1111c15190c4c.tar.gz qemu-f090c9d4ad5812fb92843d6470a1111c15190c4c.tar.bz2 qemu-f090c9d4ad5812fb92843d6470a1111c15190c4c.zip |
Add strict checking mode for softfp code.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3688 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'fpu')
-rw-r--r-- | fpu/softfloat-specialize.h | 95 | ||||
-rw-r--r-- | fpu/softfloat.c | 175 | ||||
-rw-r--r-- | fpu/softfloat.h | 35 |
3 files changed, 200 insertions, 105 deletions
diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index 8f9dd5c454..18c6dd52d0 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -66,9 +66,9 @@ typedef struct { | The pattern for a default generated single-precision NaN. *----------------------------------------------------------------------------*/ #if SNAN_BIT_IS_ONE -#define float32_default_nan 0x7FBFFFFF +#define float32_default_nan make_float32(0x7FBFFFFF) #else -#define float32_default_nan 0xFFC00000 +#define float32_default_nan make_float32(0xFFC00000) #endif /*---------------------------------------------------------------------------- @@ -76,8 +76,9 @@ typedef struct { | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float32_is_nan( float32 a ) +int float32_is_nan( float32 a_ ) { + uint32_t a = float32_val(a_); #if SNAN_BIT_IS_ONE return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); #else @@ -90,8 +91,9 @@ int float32_is_nan( float32 a ) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float32_is_signaling_nan( float32 a ) +int float32_is_signaling_nan( float32 a_ ) { + uint32_t a = float32_val(a_); #if SNAN_BIT_IS_ONE return ( 0xFF800000 <= (bits32) ( a<<1 ) ); #else @@ -110,9 +112,9 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM ) commonNaNT z; if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR ); - z.sign = a>>31; + z.sign = float32_val(a)>>31; z.low = 0; - z.high = ( (bits64) a )<<41; + z.high = ( (bits64) float32_val(a) )<<41; return z; } @@ -123,7 +125,8 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM ) static float32 commonNaNToFloat32( commonNaNT a ) { - return ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ); + return make_float32( + ( ( (bits32) a.sign )<<31 ) | 0x7FC00000 | ( a.high>>41 ) ); } /*---------------------------------------------------------------------------- @@ -135,42 +138,52 @@ static float32 commonNaNToFloat32( commonNaNT a ) static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) { flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + bits32 av, bv, res; aIsNaN = float32_is_nan( a ); aIsSignalingNaN = float32_is_signaling_nan( a ); bIsNaN = float32_is_nan( b ); bIsSignalingNaN = float32_is_signaling_nan( b ); + av = float32_val(a); + bv = float32_val(b); #if SNAN_BIT_IS_ONE - a &= ~0x00400000; - b &= ~0x00400000; + av &= ~0x00400000; + bv &= ~0x00400000; #else - a |= 0x00400000; - b |= 0x00400000; + av |= 0x00400000; + bv |= 0x00400000; #endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ( aIsSignalingNaN ) { if ( bIsSignalingNaN ) goto returnLargerSignificand; - return bIsNaN ? b : a; + res = bIsNaN ? bv : av; } else if ( aIsNaN ) { - if ( bIsSignalingNaN | ! bIsNaN ) return a; + if ( bIsSignalingNaN | ! bIsNaN ) + res = av; + else { returnLargerSignificand: - if ( (bits32) ( a<<1 ) < (bits32) ( b<<1 ) ) return b; - if ( (bits32) ( b<<1 ) < (bits32) ( a<<1 ) ) return a; - return ( a < b ) ? a : b; + if ( (bits32) ( av<<1 ) < (bits32) ( bv<<1 ) ) + res = bv; + else if ( (bits32) ( bv<<1 ) < (bits32) ( av<<1 ) ) + res = av; + else + res = ( av < bv ) ? av : bv; + } } else { - return b; + res = bv; } + return make_float32(res); } /*---------------------------------------------------------------------------- | The pattern for a default generated double-precision NaN. *----------------------------------------------------------------------------*/ #if SNAN_BIT_IS_ONE -#define float64_default_nan LIT64( 0x7FF7FFFFFFFFFFFF ) +#define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF )) #else -#define float64_default_nan LIT64( 0xFFF8000000000000 ) +#define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 )) #endif /*---------------------------------------------------------------------------- @@ -178,8 +191,9 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float64_is_nan( float64 a ) +int float64_is_nan( float64 a_ ) { + bits64 a = float64_val(a_); #if SNAN_BIT_IS_ONE return ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) @@ -194,8 +208,9 @@ int float64_is_nan( float64 a ) | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float64_is_signaling_nan( float64 a ) +int float64_is_signaling_nan( float64 a_ ) { + bits64 a = float64_val(a_); #if SNAN_BIT_IS_ONE return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); #else @@ -216,9 +231,9 @@ static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM) commonNaNT z; if ( float64_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); - z.sign = a>>63; + z.sign = float64_val(a)>>63; z.low = 0; - z.high = a<<12; + z.high = float64_val(a)<<12; return z; } @@ -229,10 +244,10 @@ static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM) static float64 commonNaNToFloat64( commonNaNT a ) { - return + return make_float64( ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FF8000000000000 ) - | ( a.high>>12 ); + | ( a.high>>12 )); } /*---------------------------------------------------------------------------- @@ -244,33 +259,43 @@ static float64 commonNaNToFloat64( commonNaNT a ) static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) { flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + bits64 av, bv, res; aIsNaN = float64_is_nan( a ); aIsSignalingNaN = float64_is_signaling_nan( a ); bIsNaN = float64_is_nan( b ); bIsSignalingNaN = float64_is_signaling_nan( b ); + av = float64_val(a); + bv = float64_val(b); #if SNAN_BIT_IS_ONE - a &= ~LIT64( 0x0008000000000000 ); - b &= ~LIT64( 0x0008000000000000 ); + av &= ~LIT64( 0x0008000000000000 ); + bv &= ~LIT64( 0x0008000000000000 ); #else - a |= LIT64( 0x0008000000000000 ); - b |= LIT64( 0x0008000000000000 ); + av |= LIT64( 0x0008000000000000 ); + bv |= LIT64( 0x0008000000000000 ); #endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ( aIsSignalingNaN ) { if ( bIsSignalingNaN ) goto returnLargerSignificand; - return bIsNaN ? b : a; + res = bIsNaN ? bv : av; } else if ( aIsNaN ) { - if ( bIsSignalingNaN | ! bIsNaN ) return a; + if ( bIsSignalingNaN | ! bIsNaN ) + res = av; + else { returnLargerSignificand: - if ( (bits64) ( a<<1 ) < (bits64) ( b<<1 ) ) return b; - if ( (bits64) ( b<<1 ) < (bits64) ( a<<1 ) ) return a; - return ( a < b ) ? a : b; + if ( (bits64) ( av<<1 ) < (bits64) ( bv<<1 ) ) + res = bv; + else if ( (bits64) ( bv<<1 ) < (bits64) ( av<<1 ) ) + res = av; + else + res = ( av < bv ) ? av : bv; + } } else { - return b; + res = bv; } + return make_float64(res); } #ifdef FLOATX80 diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 8ebb692648..f6cbd29ce6 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -175,7 +175,7 @@ static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PA INLINE bits32 extractFloat32Frac( float32 a ) { - return a & 0x007FFFFF; + return float32_val(a) & 0x007FFFFF; } @@ -186,7 +186,7 @@ INLINE bits32 extractFloat32Frac( float32 a ) INLINE int16 extractFloat32Exp( float32 a ) { - return ( a>>23 ) & 0xFF; + return ( float32_val(a)>>23 ) & 0xFF; } @@ -197,7 +197,7 @@ INLINE int16 extractFloat32Exp( float32 a ) INLINE flag extractFloat32Sign( float32 a ) { - return a>>31; + return float32_val(a)>>31; } @@ -233,7 +233,8 @@ static void INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig ) { - return ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig; + return make_float32( + ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig); } @@ -290,7 +291,7 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P && ( (sbits32) ( zSig + roundIncrement ) < 0 ) ) ) { float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); - return packFloat32( zSign, 0xFF, 0 ) - ( roundIncrement == 0 ); + return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 )); } if ( zExp < 0 ) { isTiny = @@ -337,7 +338,7 @@ static float32 INLINE bits64 extractFloat64Frac( float64 a ) { - return a & LIT64( 0x000FFFFFFFFFFFFF ); + return float64_val(a) & LIT64( 0x000FFFFFFFFFFFFF ); } @@ -348,7 +349,7 @@ INLINE bits64 extractFloat64Frac( float64 a ) INLINE int16 extractFloat64Exp( float64 a ) { - return ( a>>52 ) & 0x7FF; + return ( float64_val(a)>>52 ) & 0x7FF; } @@ -359,7 +360,7 @@ INLINE int16 extractFloat64Exp( float64 a ) INLINE flag extractFloat64Sign( float64 a ) { - return a>>63; + return float64_val(a)>>63; } @@ -395,7 +396,8 @@ static void INLINE float64 packFloat64( flag zSign, int16 zExp, bits64 zSig ) { - return ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<52 ) + zSig; + return make_float64( + ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<52 ) + zSig); } @@ -452,7 +454,7 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P && ( (sbits64) ( zSig + roundIncrement ) < 0 ) ) ) { float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); - return packFloat64( zSign, 0x7FF, 0 ) - ( roundIncrement == 0 ); + return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 )); } if ( zExp < 0 ) { isTiny = @@ -1050,7 +1052,7 @@ float32 int32_to_float32( int32 a STATUS_PARAM ) { flag zSign; - if ( a == 0 ) return 0; + if ( a == 0 ) return float32_zero; if ( a == (sbits32) 0x80000000 ) return packFloat32( 1, 0x9E, 0 ); zSign = ( a < 0 ); return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a STATUS_VAR ); @@ -1070,7 +1072,7 @@ float64 int32_to_float64( int32 a STATUS_PARAM ) int8 shiftCount; bits64 zSig; - if ( a == 0 ) return 0; + if ( a == 0 ) return float64_zero; zSign = ( a < 0 ); absA = zSign ? - a : a; shiftCount = countLeadingZeros32( absA ) + 21; @@ -1144,7 +1146,7 @@ float32 int64_to_float32( int64 a STATUS_PARAM ) uint64 absA; int8 shiftCount; - if ( a == 0 ) return 0; + if ( a == 0 ) return float32_zero; zSign = ( a < 0 ); absA = zSign ? - a : a; shiftCount = countLeadingZeros64( absA ) - 40; @@ -1168,7 +1170,7 @@ float32 uint64_to_float32( uint64 a STATUS_PARAM ) { int8 shiftCount; - if ( a == 0 ) return 0; + if ( a == 0 ) return float32_zero; shiftCount = countLeadingZeros64( a ) - 40; if ( 0 <= shiftCount ) { return packFloat32( 1 > 0, 0x95 - shiftCount, a<<shiftCount ); @@ -1195,7 +1197,7 @@ float64 int64_to_float64( int64 a STATUS_PARAM ) { flag zSign; - if ( a == 0 ) return 0; + if ( a == 0 ) return float64_zero; if ( a == (sbits64) LIT64( 0x8000000000000000 ) ) { return packFloat64( 1, 0x43E, 0 ); } @@ -1206,7 +1208,7 @@ float64 int64_to_float64( int64 a STATUS_PARAM ) float64 uint64_to_float64( uint64 a STATUS_PARAM ) { - if ( a == 0 ) return 0; + if ( a == 0 ) return float64_zero; return normalizeRoundAndPackFloat64( 0, 0x43C, a STATUS_VAR ); } @@ -1325,7 +1327,7 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM ) aSign = extractFloat32Sign( a ); shiftCount = aExp - 0x9E; if ( 0 <= shiftCount ) { - if ( a != 0xCF000000 ) { + if ( float32_val(a) != 0xCF000000 ) { float_raise( float_flag_invalid STATUS_VAR); if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF; } @@ -1404,7 +1406,7 @@ int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM ) aSign = extractFloat32Sign( a ); shiftCount = aExp - 0xBE; if ( 0 <= shiftCount ) { - if ( a != 0xDF000000 ) { + if ( float32_val(a) != 0xDF000000 ) { float_raise( float_flag_invalid STATUS_VAR); if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) { return LIT64( 0x7FFFFFFFFFFFFFFF ); @@ -1535,7 +1537,7 @@ float32 float32_round_to_int( float32 a STATUS_PARAM) int16 aExp; bits32 lastBitMask, roundBitsMask; int8 roundingMode; - float32 z; + bits32 z; aExp = extractFloat32Exp( a ); if ( 0x96 <= aExp ) { @@ -1545,7 +1547,7 @@ float32 float32_round_to_int( float32 a STATUS_PARAM) return a; } if ( aExp <= 0x7E ) { - if ( (bits32) ( a<<1 ) == 0 ) return a; + if ( (bits32) ( float32_val(a)<<1 ) == 0 ) return a; STATUS(float_exception_flags) |= float_flag_inexact; aSign = extractFloat32Sign( a ); switch ( STATUS(float_rounding_mode) ) { @@ -1555,29 +1557,29 @@ float32 float32_round_to_int( float32 a STATUS_PARAM) } break; case float_round_down: - return aSign ? 0xBF800000 : 0; + return make_float32(aSign ? 0xBF800000 : 0); case float_round_up: - return aSign ? 0x80000000 : 0x3F800000; + return make_float32(aSign ? 0x80000000 : 0x3F800000); } return packFloat32( aSign, 0, 0 ); } lastBitMask = 1; lastBitMask <<= 0x96 - aExp; roundBitsMask = lastBitMask - 1; - z = a; + z = float32_val(a); roundingMode = STATUS(float_rounding_mode); if ( roundingMode == float_round_nearest_even ) { z += lastBitMask>>1; if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; } else if ( roundingMode != float_round_to_zero ) { - if ( extractFloat32Sign( z ) ^ ( roundingMode == float_round_up ) ) { + if ( extractFloat32Sign( make_float32(z) ) ^ ( roundingMode == float_round_up ) ) { z += roundBitsMask; } } z &= ~ roundBitsMask; - if ( z != a ) STATUS(float_exception_flags) |= float_flag_inexact; - return z; + if ( z != float32_val(a) ) STATUS(float_exception_flags) |= float_flag_inexact; + return make_float32(z); } @@ -2008,7 +2010,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM ) aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { - if ( aSig ) return propagateFloat32NaN( a, 0 STATUS_VAR ); + if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR ); if ( ! aSign ) return a; float_raise( float_flag_invalid STATUS_VAR); return float32_default_nan; @@ -2019,7 +2021,7 @@ float32 float32_sqrt( float32 a STATUS_PARAM ) return float32_default_nan; } if ( aExp == 0 ) { - if ( aSig == 0 ) return 0; + if ( aSig == 0 ) return float32_zero; normalizeFloat32Subnormal( aSig, &aExp, &aSig ); } zExp = ( ( aExp - 0x7F )>>1 ) + 0x7E; @@ -2062,7 +2064,8 @@ int float32_eq( float32 a, float32 b STATUS_PARAM ) } return 0; } - return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + return ( float32_val(a) == float32_val(b) ) || + ( (bits32) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 ); } @@ -2076,6 +2079,7 @@ int float32_eq( float32 a, float32 b STATUS_PARAM ) int float32_le( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2085,8 +2089,10 @@ int float32_le( float32 a, float32 b STATUS_PARAM ) } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); } @@ -2099,6 +2105,7 @@ int float32_le( float32 a, float32 b STATUS_PARAM ) int float32_lt( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2108,8 +2115,10 @@ int float32_lt( float32 a, float32 b STATUS_PARAM ) } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); } @@ -2122,6 +2131,7 @@ int float32_lt( float32 a, float32 b STATUS_PARAM ) int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) { + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2129,7 +2139,9 @@ int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) float_raise( float_flag_invalid STATUS_VAR); return 0; } - return ( a == b ) || ( (bits32) ( ( a | b )<<1 ) == 0 ); + av = float32_val(a); + bv = float32_val(b); + return ( av == bv ) || ( (bits32) ( ( av | bv )<<1 ) == 0 ); } @@ -2143,6 +2155,7 @@ int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) int float32_le_quiet( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2154,8 +2167,10 @@ int float32_le_quiet( float32 a, float32 b STATUS_PARAM ) } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits32) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); } @@ -2169,6 +2184,7 @@ int float32_le_quiet( float32 a, float32 b STATUS_PARAM ) int float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + bits32 av, bv; if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2180,8 +2196,10 @@ int float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) } aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits32) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); + av = float32_val(a); + bv = float32_val(b); + if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); } @@ -2324,7 +2342,7 @@ int64 float64_to_int64_round_to_zero( float64 a STATUS_PARAM ) shiftCount = aExp - 0x433; if ( 0 <= shiftCount ) { if ( 0x43E <= aExp ) { - if ( a != LIT64( 0xC3E0000000000000 ) ) { + if ( float64_val(a) != LIT64( 0xC3E0000000000000 ) ) { float_raise( float_flag_invalid STATUS_VAR); if ( ! aSign || ( ( aExp == 0x7FF ) @@ -2464,7 +2482,7 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) int16 aExp; bits64 lastBitMask, roundBitsMask; int8 roundingMode; - float64 z; + bits64 z; aExp = extractFloat64Exp( a ); if ( 0x433 <= aExp ) { @@ -2474,7 +2492,7 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) return a; } if ( aExp < 0x3FF ) { - if ( (bits64) ( a<<1 ) == 0 ) return a; + if ( (bits64) ( float64_val(a)<<1 ) == 0 ) return a; STATUS(float_exception_flags) |= float_flag_inexact; aSign = extractFloat64Sign( a ); switch ( STATUS(float_rounding_mode) ) { @@ -2484,30 +2502,31 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) } break; case float_round_down: - return aSign ? LIT64( 0xBFF0000000000000 ) : 0; + return make_float64(aSign ? LIT64( 0xBFF0000000000000 ) : 0); case float_round_up: - return - aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 ); + return make_float64( + aSign ? LIT64( 0x8000000000000000 ) : LIT64( 0x3FF0000000000000 )); } return packFloat64( aSign, 0, 0 ); } lastBitMask = 1; lastBitMask <<= 0x433 - aExp; roundBitsMask = lastBitMask - 1; - z = a; + z = float64_val(a); roundingMode = STATUS(float_rounding_mode); if ( roundingMode == float_round_nearest_even ) { z += lastBitMask>>1; if ( ( z & roundBitsMask ) == 0 ) z &= ~ lastBitMask; } else if ( roundingMode != float_round_to_zero ) { - if ( extractFloat64Sign( z ) ^ ( roundingMode == float_round_up ) ) { + if ( extractFloat64Sign( make_float64(z) ) ^ ( roundingMode == float_round_up ) ) { z += roundBitsMask; } } z &= ~ roundBitsMask; - if ( z != a ) STATUS(float_exception_flags) |= float_flag_inexact; - return z; + if ( z != float64_val(a) ) + STATUS(float_exception_flags) |= float_flag_inexact; + return make_float64(z); } @@ -2951,7 +2970,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM ) return float64_default_nan; } if ( aExp == 0 ) { - if ( aSig == 0 ) return 0; + if ( aSig == 0 ) return float64_zero; normalizeFloat64Subnormal( aSig, &aExp, &aSig ); } zExp = ( ( aExp - 0x3FF )>>1 ) + 0x3FE; @@ -2982,6 +3001,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM ) int float64_eq( float64 a, float64 b STATUS_PARAM ) { + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -2991,7 +3011,9 @@ int float64_eq( float64 a, float64 b STATUS_PARAM ) } return 0; } - return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + av = float64_val(a); + bv = float64_val(a); + return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 ); } @@ -3005,6 +3027,7 @@ int float64_eq( float64 a, float64 b STATUS_PARAM ) int float64_le( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3014,8 +3037,10 @@ int float64_le( float64 a, float64 b STATUS_PARAM ) } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); + av = float64_val(a); + bv = float64_val(a); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); } @@ -3028,6 +3053,7 @@ int float64_le( float64 a, float64 b STATUS_PARAM ) int float64_lt( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3037,8 +3063,10 @@ int float64_lt( float64 a, float64 b STATUS_PARAM ) } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); + av = float64_val(a); + bv = float64_val(a); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); } @@ -3051,6 +3079,7 @@ int float64_lt( float64 a, float64 b STATUS_PARAM ) int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) { + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3058,7 +3087,9 @@ int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) float_raise( float_flag_invalid STATUS_VAR); return 0; } - return ( a == b ) || ( (bits64) ( ( a | b )<<1 ) == 0 ); + av = float64_val(a); + bv = float64_val(a); + return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 ); } @@ -3072,6 +3103,7 @@ int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) int float64_le_quiet( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3083,8 +3115,10 @@ int float64_le_quiet( float64 a, float64 b STATUS_PARAM ) } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign || ( (bits64) ( ( a | b )<<1 ) == 0 ); - return ( a == b ) || ( aSign ^ ( a < b ) ); + av = float64_val(a); + bv = float64_val(a); + if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( aSign ^ ( av < bv ) ); } @@ -3098,6 +3132,7 @@ int float64_le_quiet( float64 a, float64 b STATUS_PARAM ) int float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + bits64 av, bv; if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3109,8 +3144,10 @@ int float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) } aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); - if ( aSign != bSign ) return aSign && ( (bits64) ( ( a | b )<<1 ) != 0 ); - return ( a != b ) && ( aSign ^ ( a < b ) ); + av = float64_val(a); + bv = float64_val(a); + if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 ); + return ( av != bv ) && ( aSign ^ ( av < bv ) ); } @@ -5310,12 +5347,14 @@ unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM ) return res; } +/* FIXME: This looks broken. */ uint64_t float64_to_uint64 (float64 a STATUS_PARAM) { int64_t v; - v = int64_to_float64(INT64_MIN STATUS_VAR); - v = float64_to_int64((a + v) STATUS_VAR); + v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR)); + v += float64_val(a); + v = float64_to_int64(make_float64(v) STATUS_VAR); return v - INT64_MIN; } @@ -5324,8 +5363,9 @@ uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM) { int64_t v; - v = int64_to_float64(INT64_MIN STATUS_VAR); - v = float64_to_int64_round_to_zero((a + v) STATUS_VAR); + v = float64_val(int64_to_float64(INT64_MIN STATUS_VAR)); + v += float64_val(a); + v = float64_to_int64_round_to_zero(make_float64(v) STATUS_VAR); return v - INT64_MIN; } @@ -5335,6 +5375,7 @@ INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \ int is_quiet STATUS_PARAM ) \ { \ flag aSign, bSign; \ + bits ## s av, bv; \ \ if (( ( extractFloat ## s ## Exp( a ) == nan_exp ) && \ extractFloat ## s ## Frac( a ) ) || \ @@ -5349,18 +5390,20 @@ INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \ } \ aSign = extractFloat ## s ## Sign( a ); \ bSign = extractFloat ## s ## Sign( b ); \ + av = float ## s ## _val(a); \ + bv = float ## s ## _val(a); \ if ( aSign != bSign ) { \ - if ( (bits ## s) ( ( a | b )<<1 ) == 0 ) { \ + if ( (bits ## s) ( ( av | bv )<<1 ) == 0 ) { \ /* zero case */ \ return float_relation_equal; \ } else { \ return 1 - (2 * aSign); \ } \ } else { \ - if (a == b) { \ + if (av == bv) { \ return float_relation_equal; \ } else { \ - return 1 - 2 * (aSign ^ ( a < b )); \ + return 1 - 2 * (aSign ^ ( av < bv )); \ } \ } \ } \ diff --git a/fpu/softfloat.h b/fpu/softfloat.h index f0261fb6a7..84cffdd5d5 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -111,8 +111,31 @@ enum { /*---------------------------------------------------------------------------- | Software IEC/IEEE floating-point types. *----------------------------------------------------------------------------*/ +/* Use structures for soft-float types. This prevents accidentally mixing + them with native int/float types. A sufficiently clever compiler and + sane ABI should be able to see though these structs. However + x86/gcc 3.x seems to struggle a bit, so leave them disabled by default. */ +//#define USE_SOFTFLOAT_STRUCT_TYPES +#ifdef USE_SOFTFLOAT_STRUCT_TYPES +typedef struct { + uint32_t v; +} float32; +/* The cast ensures an error if the wrong type is passed. */ +#define float32_val(x) (((float32)(x)).v) +#define make_float32(x) __extension__ ({ float32 f32_val = {x}; f32_val; }) +typedef struct { + uint64_t v; +} float64; +#define float64_val(x) (((float64)(x)).v) +#define make_float64(x) __extension__ ({ float64 f64_val = {x}; f64_val; }) +#else typedef uint32_t float32; typedef uint64_t float64; +#define float32_val(x) (x) +#define float64_val(x) (x) +#define make_float32(x) (x) +#define make_float64(x) (x) +#endif #ifdef FLOATX80 typedef struct { uint64_t low; @@ -248,14 +271,16 @@ float32 float32_scalbn( float32, int STATUS_PARAM ); INLINE float32 float32_abs(float32 a) { - return a & 0x7fffffff; + return make_float32(float32_val(a) & 0x7fffffff); } INLINE float32 float32_chs(float32 a) { - return a ^ 0x80000000; + return make_float32(float32_val(a) ^ 0x80000000); } +#define float32_zero make_float32(0) + /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ @@ -300,14 +325,16 @@ float64 float64_scalbn( float64, int STATUS_PARAM ); INLINE float64 float64_abs(float64 a) { - return a & 0x7fffffffffffffffLL; + return make_float64(float64_val(a) & 0x7fffffffffffffffLL); } INLINE float64 float64_chs(float64 a) { - return a ^ 0x8000000000000000LL; + return make_float64(float64_val(a) ^ 0x8000000000000000LL); } +#define float64_zero make_float64(0) + #ifdef FLOATX80 /*---------------------------------------------------------------------------- |