From e6afc87f804abee7d0479be5e8e31c56d885fafb Mon Sep 17 00:00:00 2001 From: Peter Maydell Date: Thu, 19 May 2011 14:46:17 +0100 Subject: softfloat: Add new flag for when denormal result is flushed to zero Add a new float_flag_output_denormal which is set when the result of a floating point operation would be denormal but is flushed to zero because we are in flush_to_zero mode. This is necessary because some architectures signal this condition as an underflow and others signal it as an inexact result. Signed-off-by: Peter Maydell Signed-off-by: Aurelien Jarno --- fpu/softfloat.c | 41 ++++++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-) (limited to 'fpu/softfloat.c') diff --git a/fpu/softfloat.c b/fpu/softfloat.c index baba1dc44b..e3cd8a7296 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -341,7 +341,10 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, uint32_t zSig STATUS return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 )); } if ( zExp < 0 ) { - if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 ); + if (STATUS(flush_to_zero)) { + float_raise(float_flag_output_denormal STATUS_VAR); + return packFloat32(zSign, 0, 0); + } isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < -1 ) @@ -520,7 +523,10 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, uint64_t zSig STATUS return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 )); } if ( zExp < 0 ) { - if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 ); + if (STATUS(flush_to_zero)) { + float_raise(float_flag_output_denormal STATUS_VAR); + return packFloat64(zSign, 0, 0); + } isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < -1 ) @@ -699,7 +705,10 @@ static floatx80 goto overflow; } if ( zExp <= 0 ) { - if ( STATUS(flush_to_zero) ) return packFloatx80( zSign, 0, 0 ); + if (STATUS(flush_to_zero)) { + float_raise(float_flag_output_denormal STATUS_VAR); + return packFloatx80(zSign, 0, 0); + } isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < 0 ) @@ -1030,7 +1039,10 @@ static float128 return packFloat128( zSign, 0x7FFF, 0, 0 ); } if ( zExp < 0 ) { - if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 ); + if (STATUS(flush_to_zero)) { + float_raise(float_flag_output_denormal STATUS_VAR); + return packFloat128(zSign, 0, 0, 0); + } isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < -1 ) @@ -1761,7 +1773,12 @@ static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) return a; } if ( aExp == 0 ) { - if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 ); + if (STATUS(flush_to_zero)) { + if (aSig | bSig) { + float_raise(float_flag_output_denormal STATUS_VAR); + } + return packFloat32(zSign, 0, 0); + } return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); } zSig = 0x40000000 + aSig + bSig; @@ -3120,7 +3137,12 @@ static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) return a; } if ( aExp == 0 ) { - if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 ); + if (STATUS(flush_to_zero)) { + if (aSig | bSig) { + float_raise(float_flag_output_denormal STATUS_VAR); + } + return packFloat64(zSign, 0, 0); + } return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); } zSig = LIT64( 0x4000000000000000 ) + aSig + bSig; @@ -5282,7 +5304,12 @@ static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM } add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); if ( aExp == 0 ) { - if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 ); + if (STATUS(flush_to_zero)) { + if (zSig0 | zSig1) { + float_raise(float_flag_output_denormal STATUS_VAR); + } + return packFloat128(zSign, 0, 0, 0); + } return packFloat128( zSign, 0, zSig0, zSig1 ); } zSig2 = 0; -- cgit 1.4.1 From be22a9abc0dd02aa99726b656482b64e2aa4af80 Mon Sep 17 00:00:00 2001 From: Aurelien Jarno Date: Sun, 15 May 2011 14:09:18 +0200 Subject: softfloat: always enable floatx80 and float128 support Now that softfloat-native is gone, there is no real point on not always enabling floatx80 and float128 support. Reviewed-by: Peter Maydell Signed-off-by: Aurelien Jarno --- cpu-all.h | 2 -- fpu/softfloat-specialize.h | 7 ------ fpu/softfloat.c | 62 ---------------------------------------------- fpu/softfloat.h | 47 ----------------------------------- 4 files changed, 118 deletions(-) (limited to 'fpu/softfloat.c') diff --git a/cpu-all.h b/cpu-all.h index fc252ba6e5..880f570d56 100644 --- a/cpu-all.h +++ b/cpu-all.h @@ -137,7 +137,6 @@ typedef union { uint64_t ll; } CPU_DoubleU; -#if defined(FLOATX80) typedef union { floatx80 d; struct { @@ -145,7 +144,6 @@ typedef union { uint16_t upper; } l; } CPU_LDoubleU; -#endif typedef union { float128 q; diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index 9d68aae9d5..c7d35a161d 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -523,8 +523,6 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) } } -#ifdef FLOATX80 - /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is a | quiet NaN; otherwise returns 0. This slightly differs from the same @@ -681,10 +679,6 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) } } -#endif - -#ifdef FLOAT128 - /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is a quiet | NaN; otherwise returns 0. @@ -820,4 +814,3 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) } } -#endif diff --git a/fpu/softfloat.c b/fpu/softfloat.c index e3cd8a7296..7951a0e869 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -64,12 +64,10 @@ void set_float_exception_flags(int val STATUS_PARAM) STATUS(float_exception_flags) = val; } -#ifdef FLOATX80 void set_floatx80_rounding_precision(int val STATUS_PARAM) { STATUS(floatx80_rounding_precision) = val; } -#endif /*---------------------------------------------------------------------------- | Returns the fraction bits of the half-precision floating-point value `a'. @@ -564,8 +562,6 @@ static float64 } -#ifdef FLOATX80 - /*---------------------------------------------------------------------------- | Returns the fraction bits of the extended double-precision floating-point | value `a'. @@ -851,10 +847,6 @@ static floatx80 } -#endif - -#ifdef FLOAT128 - /*---------------------------------------------------------------------------- | Returns the least-significant 64 fraction bits of the quadruple-precision | floating-point value `a'. @@ -1118,8 +1110,6 @@ static float128 } -#endif - /*---------------------------------------------------------------------------- | Returns the result of converting the 32-bit two's complement integer `a' | to the single-precision floating-point format. The conversion is performed @@ -1159,8 +1149,6 @@ float64 int32_to_float64( int32 a STATUS_PARAM ) } -#ifdef FLOATX80 - /*---------------------------------------------------------------------------- | Returns the result of converting the 32-bit two's complement integer `a' | to the extended double-precision floating-point format. The conversion @@ -1184,10 +1172,6 @@ floatx80 int32_to_floatx80( int32 a STATUS_PARAM ) } -#endif - -#ifdef FLOAT128 - /*---------------------------------------------------------------------------- | Returns the result of converting the 32-bit two's complement integer `a' to | the quadruple-precision floating-point format. The conversion is performed @@ -1210,8 +1194,6 @@ float128 int32_to_float128( int32 a STATUS_PARAM ) } -#endif - /*---------------------------------------------------------------------------- | Returns the result of converting the 64-bit two's complement integer `a' | to the single-precision floating-point format. The conversion is performed @@ -1291,8 +1273,6 @@ float64 uint64_to_float64( uint64 a STATUS_PARAM ) } -#ifdef FLOATX80 - /*---------------------------------------------------------------------------- | Returns the result of converting the 64-bit two's complement integer `a' | to the extended double-precision floating-point format. The conversion @@ -1314,10 +1294,6 @@ floatx80 int64_to_floatx80( int64 a STATUS_PARAM ) } -#endif - -#ifdef FLOAT128 - /*---------------------------------------------------------------------------- | Returns the result of converting the 64-bit two's complement integer `a' to | the quadruple-precision floating-point format. The conversion is performed @@ -1351,8 +1327,6 @@ float128 int64_to_float128( int64 a STATUS_PARAM ) } -#endif - /*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point value | `a' to the 32-bit two's complement integer format. The conversion is @@ -1590,8 +1564,6 @@ float64 float32_to_float64( float32 a STATUS_PARAM ) } -#ifdef FLOATX80 - /*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point value | `a' to the extended double-precision floating-point format. The conversion @@ -1622,10 +1594,6 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM ) } -#endif - -#ifdef FLOAT128 - /*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point value | `a' to the double-precision floating-point format. The conversion is @@ -1656,8 +1624,6 @@ float128 float32_to_float128( float32 a STATUS_PARAM ) } -#endif - /*---------------------------------------------------------------------------- | Rounds the single-precision floating-point value `a' to an integer, and | returns the result as a single-precision floating-point value. The @@ -2939,8 +2905,6 @@ float16 float32_to_float16(float32 a, flag ieee STATUS_PARAM) return packFloat16(aSign, aExp + 14, aSig >> 13); } -#ifdef FLOATX80 - /*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point value | `a' to the extended double-precision floating-point format. The conversion @@ -2972,10 +2936,6 @@ floatx80 float64_to_floatx80( float64 a STATUS_PARAM ) } -#endif - -#ifdef FLOAT128 - /*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point value | `a' to the quadruple-precision floating-point format. The conversion is @@ -3007,8 +2967,6 @@ float128 float64_to_float128( float64 a STATUS_PARAM ) } -#endif - /*---------------------------------------------------------------------------- | Rounds the double-precision floating-point value `a' to an integer, and | returns the result as a double-precision floating-point value. The @@ -3816,8 +3774,6 @@ int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM ) return 0; } -#ifdef FLOATX80 - /*---------------------------------------------------------------------------- | Returns the result of converting the extended double-precision floating- | point value `a' to the 32-bit two's complement integer format. The @@ -4030,8 +3986,6 @@ float64 floatx80_to_float64( floatx80 a STATUS_PARAM ) } -#ifdef FLOAT128 - /*---------------------------------------------------------------------------- | Returns the result of converting the extended double-precision floating- | point value `a' to the quadruple-precision floating-point format. The @@ -4056,8 +4010,6 @@ float128 floatx80_to_float128( floatx80 a STATUS_PARAM ) } -#endif - /*---------------------------------------------------------------------------- | Rounds the extended double-precision floating-point value `a' to an integer, | and returns the result as an extended quadruple-precision floating-point @@ -4849,10 +4801,6 @@ int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM ) return 0; } -#endif - -#ifdef FLOAT128 - /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point | value `a' to the 32-bit two's complement integer format. The conversion @@ -5102,8 +5050,6 @@ float64 float128_to_float64( float128 a STATUS_PARAM ) } -#ifdef FLOATX80 - /*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point | value `a' to the extended double-precision floating-point format. The @@ -5139,8 +5085,6 @@ floatx80 float128_to_floatx80( float128 a STATUS_PARAM ) } -#endif - /*---------------------------------------------------------------------------- | Rounds the quadruple-precision floating-point value `a' to an integer, and | returns the result as a quadruple-precision floating-point value. The @@ -6020,8 +5964,6 @@ int float128_unordered_quiet( float128 a, float128 b STATUS_PARAM ) return 0; } -#endif - /* misc functions */ float32 uint32_to_float32( unsigned int a STATUS_PARAM ) { @@ -6423,7 +6365,6 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM ) return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR ); } -#ifdef FLOATX80 floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM ) { flag aSign; @@ -6454,9 +6395,7 @@ floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM ) return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision), aSign, aExp, aSig, 0 STATUS_VAR ); } -#endif -#ifdef FLOAT128 float128 float128_scalbn( float128 a, int n STATUS_PARAM ) { flag aSign; @@ -6489,4 +6428,3 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM ) STATUS_VAR ); } -#endif diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 999b95cefb..8931446fd1 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -74,17 +74,6 @@ typedef int64_t int64; #define SNAN_BIT_IS_ONE 0 #endif -/*---------------------------------------------------------------------------- -| The macro `FLOATX80' must be defined to enable the extended double-precision -| floating-point format `floatx80'. If this macro is not defined, the -| `floatx80' type will not be defined, and none of the functions that either -| input or output the `floatx80' type will be defined. The same applies to -| the `FLOAT128' macro and the quadruple-precision format `float128'. -*----------------------------------------------------------------------------*/ -/* bit exact soft float support */ -#define FLOATX80 -#define FLOAT128 - #define STATUS_PARAM , float_status *status #define STATUS(field) status->field #define STATUS_VAR , status @@ -141,14 +130,11 @@ typedef uint64_t float64; #define const_float32(x) (x) #define const_float64(x) (x) #endif -#ifdef FLOATX80 typedef struct { uint64_t low; uint16_t high; } floatx80; #define make_floatx80(exp, mant) ((floatx80) { mant, exp }) -#endif -#ifdef FLOAT128 typedef struct { #ifdef HOST_WORDS_BIGENDIAN uint64_t high, low; @@ -156,7 +142,6 @@ typedef struct { uint64_t low, high; #endif } float128; -#endif /*---------------------------------------------------------------------------- | Software IEC/IEEE floating-point underflow tininess-detection mode. @@ -193,9 +178,7 @@ typedef struct float_status { signed char float_detect_tininess; signed char float_rounding_mode; signed char float_exception_flags; -#ifdef FLOATX80 signed char floatx80_rounding_precision; -#endif /* should denormalised results go to zero and set the inexact flag? */ flag flush_to_zero; /* should denormalised inputs go to zero and set the input_denormal flag? */ @@ -225,9 +208,7 @@ INLINE int get_float_exception_flags(float_status *status) { return STATUS(float_exception_flags); } -#ifdef FLOATX80 void set_floatx80_rounding_precision(int val STATUS_PARAM); -#endif /*---------------------------------------------------------------------------- | Routine to raise any or all of the software IEC/IEEE floating-point @@ -242,22 +223,14 @@ float32 int32_to_float32( int32 STATUS_PARAM ); float64 int32_to_float64( int32 STATUS_PARAM ); float32 uint32_to_float32( unsigned int STATUS_PARAM ); float64 uint32_to_float64( unsigned int STATUS_PARAM ); -#ifdef FLOATX80 floatx80 int32_to_floatx80( int32 STATUS_PARAM ); -#endif -#ifdef FLOAT128 float128 int32_to_float128( int32 STATUS_PARAM ); -#endif float32 int64_to_float32( int64 STATUS_PARAM ); float32 uint64_to_float32( uint64 STATUS_PARAM ); float64 int64_to_float64( int64 STATUS_PARAM ); float64 uint64_to_float64( uint64 STATUS_PARAM ); -#ifdef FLOATX80 floatx80 int64_to_floatx80( int64 STATUS_PARAM ); -#endif -#ifdef FLOAT128 float128 int64_to_float128( int64 STATUS_PARAM ); -#endif /*---------------------------------------------------------------------------- | Software half-precision conversion routines. @@ -295,12 +268,8 @@ uint32 float32_to_uint32_round_to_zero( float32 STATUS_PARAM ); int64 float32_to_int64( float32 STATUS_PARAM ); int64 float32_to_int64_round_to_zero( float32 STATUS_PARAM ); float64 float32_to_float64( float32 STATUS_PARAM ); -#ifdef FLOATX80 floatx80 float32_to_floatx80( float32 STATUS_PARAM ); -#endif -#ifdef FLOAT128 float128 float32_to_float128( float32 STATUS_PARAM ); -#endif /*---------------------------------------------------------------------------- | Software IEC/IEEE single-precision operations. @@ -412,12 +381,8 @@ int64 float64_to_int64_round_to_zero( float64 STATUS_PARAM ); uint64 float64_to_uint64 (float64 a STATUS_PARAM); uint64 float64_to_uint64_round_to_zero (float64 a STATUS_PARAM); float32 float64_to_float32( float64 STATUS_PARAM ); -#ifdef FLOATX80 floatx80 float64_to_floatx80( float64 STATUS_PARAM ); -#endif -#ifdef FLOAT128 float128 float64_to_float128( float64 STATUS_PARAM ); -#endif /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision operations. @@ -510,8 +475,6 @@ INLINE float64 float64_set_sign(float64 a, int sign) #define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 )) #endif -#ifdef FLOATX80 - /*---------------------------------------------------------------------------- | Software IEC/IEEE extended double-precision conversion routines. *----------------------------------------------------------------------------*/ @@ -521,9 +484,7 @@ int64 floatx80_to_int64( floatx80 STATUS_PARAM ); int64 floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM ); float32 floatx80_to_float32( floatx80 STATUS_PARAM ); float64 floatx80_to_float64( floatx80 STATUS_PARAM ); -#ifdef FLOAT128 float128 floatx80_to_float128( floatx80 STATUS_PARAM ); -#endif /*---------------------------------------------------------------------------- | Software IEC/IEEE extended double-precision operations. @@ -602,10 +563,6 @@ INLINE int floatx80_is_any_nan(floatx80 a) #define floatx80_default_nan_low LIT64( 0xC000000000000000 ) #endif -#endif - -#ifdef FLOAT128 - /*---------------------------------------------------------------------------- | Software IEC/IEEE quadruple-precision conversion routines. *----------------------------------------------------------------------------*/ @@ -615,9 +572,7 @@ int64 float128_to_int64( float128 STATUS_PARAM ); int64 float128_to_int64_round_to_zero( float128 STATUS_PARAM ); float32 float128_to_float32( float128 STATUS_PARAM ); float64 float128_to_float64( float128 STATUS_PARAM ); -#ifdef FLOATX80 floatx80 float128_to_floatx80( float128 STATUS_PARAM ); -#endif /*---------------------------------------------------------------------------- | Software IEC/IEEE quadruple-precision operations. @@ -689,6 +644,4 @@ INLINE int float128_is_any_nan(float128 a) #define float128_default_nan_low LIT64( 0x0000000000000000 ) #endif -#endif - #endif /* !SOFTFLOAT_H */ -- cgit 1.4.1