diff options
Diffstat (limited to 'fpu')
-rw-r--r-- | fpu/softfloat-macros.h | 5 | ||||
-rw-r--r-- | fpu/softfloat-native.c | 84 | ||||
-rw-r--r-- | fpu/softfloat-native.h | 85 | ||||
-rw-r--r-- | fpu/softfloat-specialize.h | 36 | ||||
-rw-r--r-- | fpu/softfloat.c | 153 | ||||
-rw-r--r-- | fpu/softfloat.h | 78 |
6 files changed, 377 insertions, 64 deletions
diff --git a/fpu/softfloat-macros.h b/fpu/softfloat-macros.h index 2c8f18b..7838228 100644 --- a/fpu/softfloat-macros.h +++ b/fpu/softfloat-macros.h @@ -590,12 +590,12 @@ static bits32 estimateSqrt32( int16 aExp, bits32 a ) index = ( a>>27 ) & 15; if ( aExp & 1 ) { - z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ index ]; + z = 0x4000 + ( a>>17 ) - sqrtOddAdjustments[ (int)index ]; z = ( ( a / z )<<14 ) + ( z<<15 ); a >>= 1; } else { - z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ index ]; + z = 0x8000 + ( a>>17 ) - sqrtEvenAdjustments[ (int)index ]; z = a / z + z; z = ( 0x20000 <= z ) ? 0xFFFF8000 : ( z<<15 ); if ( z <= a ) return (bits32) ( ( (sbits32) a )>>1 ); @@ -717,4 +717,3 @@ INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) return ( a0 != b0 ) || ( a1 != b1 ); } - diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index e58551f..2af07a3 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -2,11 +2,15 @@ context is supported */ #include "softfloat.h" #include <math.h> +#if defined(HOST_SOLARIS) +#include <fenv.h> +#endif void set_float_rounding_mode(int val STATUS_PARAM) { STATUS(float_rounding_mode) = val; -#if defined(_BSD) && !defined(__APPLE__) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10) +#if defined(HOST_BSD) && !defined(__APPLE__) || \ + (defined(HOST_SOLARIS) && HOST_SOLARIS < 10) fpsetround(val); #elif defined(__arm__) /* nothing to do */ @@ -22,7 +26,7 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM) } #endif -#if defined(_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10) +#if defined(HOST_BSD) || (defined(HOST_SOLARIS) && HOST_SOLARIS < 10) #define lrint(d) ((int32_t)rint(d)) #define llrint(d) ((int64_t)rint(d)) #define lrintf(f) ((int32_t)rint(f)) @@ -51,10 +55,10 @@ ldexpl(long double x, int n) { #endif #endif -#if defined(__powerpc__) +#if defined(_ARCH_PPC) /* correct (but slow) PowerPC rint() (glibc version is incorrect) */ -double qemu_rint(double x) +static double qemu_rint(double x) { double y = 4503599627370496.0; if (fabs(x) >= y) @@ -220,25 +224,25 @@ float32 float32_sqrt( float32 a STATUS_PARAM) int float32_compare( float32 a, float32 b STATUS_PARAM ) { if (a < b) { - return -1; + return float_relation_less; } else if (a == b) { - return 0; + return float_relation_equal; } else if (a > b) { - return 1; + return float_relation_greater; } else { - return 2; + return float_relation_unordered; } } int float32_compare_quiet( float32 a, float32 b STATUS_PARAM ) { if (isless(a, b)) { - return -1; + return float_relation_less; } else if (a == b) { - return 0; + return float_relation_equal; } else if (isgreater(a, b)) { - return 1; + return float_relation_greater; } else { - return 2; + return float_relation_unordered; } } int float32_is_signaling_nan( float32 a1) @@ -250,6 +254,15 @@ int float32_is_signaling_nan( float32 a1) return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); } +int float32_is_nan( float32 a1 ) +{ + float32u u; + uint64_t a; + u.f = a1; + a = u.i; + return ( 0xFF800000 < ( a<<1 ) ); +} + /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ @@ -382,25 +395,25 @@ float64 float64_sqrt( float64 a STATUS_PARAM) int float64_compare( float64 a, float64 b STATUS_PARAM ) { if (a < b) { - return -1; + return float_relation_less; } else if (a == b) { - return 0; + return float_relation_equal; } else if (a > b) { - return 1; + return float_relation_greater; } else { - return 2; + return float_relation_unordered; } } int float64_compare_quiet( float64 a, float64 b STATUS_PARAM ) { if (isless(a, b)) { - return -1; + return float_relation_less; } else if (a == b) { - return 0; + return float_relation_equal; } else if (isgreater(a, b)) { - return 1; + return float_relation_greater; } else { - return 2; + return float_relation_unordered; } } int float64_is_signaling_nan( float64 a1) @@ -422,7 +435,7 @@ int float64_is_nan( float64 a1 ) u.f = a1; a = u.i; - return ( LIT64( 0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); + return ( LIT64( 0xFFF0000000000000 ) < (bits64) ( a<<1 ) ); } @@ -474,30 +487,43 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM) int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM ) { if (a < b) { - return -1; + return float_relation_less; } else if (a == b) { - return 0; + return float_relation_equal; } else if (a > b) { - return 1; + return float_relation_greater; } else { - return 2; + return float_relation_unordered; } } int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { if (isless(a, b)) { - return -1; + return float_relation_less; } else if (a == b) { - return 0; + return float_relation_equal; } else if (isgreater(a, b)) { - return 1; + return float_relation_greater; } else { - return 2; + return float_relation_unordered; } } int floatx80_is_signaling_nan( floatx80 a1) { floatx80u u; + uint64_t aLow; + u.f = a1; + + aLow = u.i.low & ~ LIT64( 0x4000000000000000 ); + return + ( ( u.i.high & 0x7FFF ) == 0x7FFF ) + && (bits64) ( aLow<<1 ) + && ( u.i.low == aLow ); +} + +int floatx80_is_nan( floatx80 a1 ) +{ + floatx80u u; u.f = a1; return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( u.i.low<<1 ); } diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 379d49d..a28c769 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -1,15 +1,14 @@ /* Native implementation of soft float functions */ #include <math.h> -#if (defined(_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS) +#if (defined(HOST_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS) #include <ieeefp.h> #define fabsf(f) ((float)fabs(f)) #else #include <fenv.h> #endif -#ifdef __OpenBSD__ -/* Get OpenBSD version number */ +#if defined(__OpenBSD__) || defined(__NetBSD__) #include <sys/param.h> #endif @@ -21,7 +20,7 @@ * are defined in <iso/math_c99.h> with a compiler directive */ #if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ((HOST_SOLARIS >= 10) \ - && (__GNUC__ <= 4))) \ + && (__GNUC__ < 4))) \ || (defined(__OpenBSD__) && (OpenBSD < 200811)) /* * C99 7.12.3 classification macros @@ -35,6 +34,25 @@ #define unordered(x, y) (isnan(x) || isnan(y)) #endif +#ifdef __NetBSD__ +#ifndef isgreater +#define isgreater(x, y) __builtin_isgreater(x, y) +#endif +#ifndef isgreaterequal +#define isgreaterequal(x, y) __builtin_isgreaterequal(x, y) +#endif +#ifndef isless +#define isless(x, y) __builtin_isless(x, y) +#endif +#ifndef islessequal +#define islessequal(x, y) __builtin_islessequal(x, y) +#endif +#ifndef isunordered +#define isunordered(x, y) __builtin_isunordered(x, y) +#endif +#endif + + #define isnormal(x) (fpclass(x) >= FP_NZERO) #define isgreater(x, y) ((!unordered(x, y)) && ((x) > (y))) #define isgreaterequal(x, y) ((!unordered(x, y)) && ((x) >= (y))) @@ -93,7 +111,7 @@ typedef union { /*---------------------------------------------------------------------------- | Software IEC/IEEE floating-point rounding mode. *----------------------------------------------------------------------------*/ -#if (defined(_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS) +#if (defined(HOST_BSD) && !defined(__APPLE__)) || defined(HOST_SOLARIS) #if defined(__OpenBSD__) #define FE_RM FP_RM #define FE_RP FP_RP @@ -122,9 +140,9 @@ enum { #endif typedef struct float_status { - signed char float_rounding_mode; + int float_rounding_mode; #ifdef FLOATX80 - signed char floatx80_rounding_precision; + int floatx80_rounding_precision; #endif } float_status; @@ -228,6 +246,7 @@ INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM) int float32_compare( float32, float32 STATUS_PARAM ); int float32_compare_quiet( float32, float32 STATUS_PARAM ); int float32_is_signaling_nan( float32 ); +int float32_is_nan( float32 ); INLINE float32 float32_abs(float32 a) { @@ -239,6 +258,23 @@ INLINE float32 float32_chs(float32 a) return -a; } +INLINE float32 float32_is_infinity(float32 a) +{ + return fpclassify(a) == FP_INFINITE; +} + +INLINE float32 float32_is_neg(float32 a) +{ + float32u u; + u.f = a; + return u.i >> 31; +} + +INLINE float32 float32_is_zero(float32 a) +{ + return fpclassify(a) == FP_ZERO; +} + INLINE float32 float32_scalbn(float32 a, int n) { return scalbnf(a, n); @@ -331,6 +367,23 @@ INLINE float64 float64_chs(float64 a) return -a; } +INLINE float64 float64_is_infinity(float64 a) +{ + return fpclassify(a) == FP_INFINITE; +} + +INLINE float64 float64_is_neg(float64 a) +{ + float64u u; + u.f = a; + return u.i >> 63; +} + +INLINE float64 float64_is_zero(float64 a) +{ + return fpclassify(a) == FP_ZERO; +} + INLINE float64 float64_scalbn(float64 a, int n) { return scalbn(a, n); @@ -406,6 +459,7 @@ INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM) int floatx80_compare( floatx80, floatx80 STATUS_PARAM ); int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_is_signaling_nan( floatx80 ); +int floatx80_is_nan( floatx80 ); INLINE floatx80 floatx80_abs(floatx80 a) { @@ -417,6 +471,23 @@ INLINE floatx80 floatx80_chs(floatx80 a) return -a; } +INLINE floatx80 floatx80_is_infinity(floatx80 a) +{ + return fpclassify(a) == FP_INFINITE; +} + +INLINE floatx80 floatx80_is_neg(floatx80 a) +{ + floatx80u u; + u.f = a; + return u.i.high >> 15; +} + +INLINE floatx80 floatx80_is_zero(floatx80 a) +{ + return fpclassify(a) == FP_ZERO; +} + INLINE floatx80 floatx80_scalbn(floatx80 a, int n) { return scalbnl(a, n); diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index 93fe06e..f607e19 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -37,12 +37,6 @@ these four paragraphs for those parts of this code that are retained. #endif /*---------------------------------------------------------------------------- -| Underflow tininess-detection mode, statically initialized to default value. -| (The declaration in `softfloat.h' must match the `int8' type here.) -*----------------------------------------------------------------------------*/ -int8 float_detect_tininess = float_tininess_after_rounding; - -/*---------------------------------------------------------------------------- | Raises the exceptions specified by `flags'. Floating-point traps can be | defined here if desired. It is currently not possible for such a trap | to substitute a result value. If traps are not implemented, this routine @@ -67,7 +61,7 @@ typedef struct { *----------------------------------------------------------------------------*/ #if defined(TARGET_SPARC) #define float32_default_nan make_float32(0x7FFFFFFF) -#elif defined(TARGET_POWERPC) +#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) #define float32_default_nan make_float32(0x7FC00000) #elif defined(TARGET_HPPA) #define float32_default_nan make_float32(0x7FA00000) @@ -150,6 +144,9 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; bits32 av, bv, res; + if ( STATUS(default_nan_mode) ) + return float32_default_nan; + aIsNaN = float32_is_nan( a ); aIsSignalingNaN = float32_is_signaling_nan( a ); bIsNaN = float32_is_nan( b ); @@ -169,7 +166,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) res = bIsNaN ? bv : av; } else if ( aIsNaN ) { - if ( bIsSignalingNaN | ! bIsNaN ) + if ( bIsSignalingNaN || ! bIsNaN ) res = av; else { returnLargerSignificand: @@ -192,7 +189,7 @@ static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) *----------------------------------------------------------------------------*/ #if defined(TARGET_SPARC) #define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF )) -#elif defined(TARGET_POWERPC) +#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) #define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 )) #elif defined(TARGET_HPPA) #define float64_default_nan make_float64(LIT64( 0x7FF4000000000000 )) @@ -282,6 +279,9 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; bits64 av, bv, res; + if ( STATUS(default_nan_mode) ) + return float64_default_nan; + aIsNaN = float64_is_nan( a ); aIsSignalingNaN = float64_is_signaling_nan( a ); bIsNaN = float64_is_nan( b ); @@ -301,7 +301,7 @@ static float64 propagateFloat64NaN( float64 a, float64 b STATUS_PARAM) res = bIsNaN ? bv : av; } else if ( aIsNaN ) { - if ( bIsSignalingNaN | ! bIsNaN ) + if ( bIsSignalingNaN || ! bIsNaN ) res = av; else { returnLargerSignificand: @@ -418,6 +418,12 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) { flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + if ( STATUS(default_nan_mode) ) { + a.low = floatx80_default_nan_low; + a.high = floatx80_default_nan_high; + return a; + } + aIsNaN = floatx80_is_nan( a ); aIsSignalingNaN = floatx80_is_signaling_nan( a ); bIsNaN = floatx80_is_nan( b ); @@ -435,7 +441,7 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) return bIsNaN ? b : a; } else if ( aIsNaN ) { - if ( bIsSignalingNaN | ! bIsNaN ) return a; + if ( bIsSignalingNaN || ! bIsNaN ) return a; returnLargerSignificand: if ( a.low < b.low ) return b; if ( b.low < a.low ) return a; @@ -538,6 +544,12 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) { flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + if ( STATUS(default_nan_mode) ) { + a.low = float128_default_nan_low; + a.high = float128_default_nan_high; + return a; + } + aIsNaN = float128_is_nan( a ); aIsSignalingNaN = float128_is_signaling_nan( a ); bIsNaN = float128_is_nan( b ); @@ -555,7 +567,7 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) return bIsNaN ? b : a; } else if ( aIsNaN ) { - if ( bIsSignalingNaN | ! bIsNaN ) return a; + if ( bIsSignalingNaN || ! bIsNaN ) return a; returnLargerSignificand: if ( lt128( a.high<<1, a.low, b.high<<1, b.low ) ) return b; if ( lt128( b.high<<1, b.low, a.high<<1, a.low ) ) return a; diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 3ec1e0d..4d58744 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -30,6 +30,8 @@ these four paragraphs for those parts of this code that are retained. =============================================================================*/ +/* FIXME: Flush-To-Zero only effects results. Denormal inputs should also + be flushed to zero. */ #include "softfloat.h" /*---------------------------------------------------------------------------- @@ -294,6 +296,7 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 )); } if ( zExp < 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 ); isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < -1 ) @@ -457,6 +460,7 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 )); } if ( zExp < 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 ); isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < -1 ) @@ -635,6 +639,7 @@ static floatx80 goto overflow; } if ( zExp <= 0 ) { + if ( STATUS(flush_to_zero) ) return packFloatx80( zSign, 0, 0 ); isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < 0 ) @@ -965,6 +970,7 @@ static float128 return packFloat128( zSign, 0x7FFF, 0, 0 ); } if ( zExp < 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 ); isTiny = ( STATUS(float_detect_tininess) == float_tininess_before_rounding ) || ( zExp < -1 ) @@ -1637,7 +1643,10 @@ static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) if ( aSig | bSig ) return propagateFloat32NaN( a, b STATUS_VAR ); return a; } - if ( aExp == 0 ) return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); + if ( aExp == 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat32( zSign, 0, 0 ); + return packFloat32( zSign, 0, ( aSig + bSig )>>6 ); + } zSig = 0x40000000 + aSig + bSig; zExp = aExp; goto roundAndPack; @@ -2048,6 +2057,53 @@ float32 float32_sqrt( float32 a STATUS_PARAM ) } /*---------------------------------------------------------------------------- +| Returns the binary log of the single-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ +float32 float32_log2( float32 a STATUS_PARAM ) +{ + flag aSign, zSign; + int16 aExp; + bits32 aSig, zSig, i; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat32( 1, 0xFF, 0 ); + normalizeFloat32Subnormal( aSig, &aExp, &aSig ); + } + if ( aSign ) { + float_raise( float_flag_invalid STATUS_VAR); + return float32_default_nan; + } + if ( aExp == 0xFF ) { + if ( aSig ) return propagateFloat32NaN( a, float32_zero STATUS_VAR ); + return a; + } + + aExp -= 0x7F; + aSig |= 0x00800000; + zSign = aExp < 0; + zSig = aExp << 23; + + for (i = 1 << 22; i > 0; i >>= 1) { + aSig = ( (bits64)aSig * aSig ) >> 23; + if ( aSig & 0x01000000 ) { + aSig >>= 1; + zSig |= i; + } + } + + if ( zSign ) + zSig = -zSig; + + return normalizeRoundAndPackFloat32( zSign, 0x85, zSig STATUS_VAR ); +} + +/*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is equal to | the corresponding value `b', and 0 otherwise. The comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. @@ -2595,7 +2651,10 @@ static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) if ( aSig | bSig ) return propagateFloat64NaN( a, b STATUS_VAR ); return a; } - if ( aExp == 0 ) return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); + if ( aExp == 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat64( zSign, 0, 0 ); + return packFloat64( zSign, 0, ( aSig + bSig )>>9 ); + } zSig = LIT64( 0x4000000000000000 ) + aSig + bSig; zExp = aExp; goto roundAndPack; @@ -2994,6 +3053,52 @@ float64 float64_sqrt( float64 a STATUS_PARAM ) } /*---------------------------------------------------------------------------- +| Returns the binary log of the double-precision floating-point value `a'. +| The operation is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ +float64 float64_log2( float64 a STATUS_PARAM ) +{ + flag aSign, zSign; + int16 aExp; + bits64 aSig, aSig0, aSig1, zSig, i; + + aSig = extractFloat64Frac( a ); + aExp = extractFloat64Exp( a ); + aSign = extractFloat64Sign( a ); + + if ( aExp == 0 ) { + if ( aSig == 0 ) return packFloat64( 1, 0x7FF, 0 ); + normalizeFloat64Subnormal( aSig, &aExp, &aSig ); + } + if ( aSign ) { + float_raise( float_flag_invalid STATUS_VAR); + return float64_default_nan; + } + if ( aExp == 0x7FF ) { + if ( aSig ) return propagateFloat64NaN( a, float64_zero STATUS_VAR ); + return a; + } + + aExp -= 0x3FF; + aSig |= LIT64( 0x0010000000000000 ); + zSign = aExp < 0; + zSig = (bits64)aExp << 52; + for (i = 1LL << 51; i > 0; i >>= 1) { + mul64To128( aSig, aSig, &aSig0, &aSig1 ); + aSig = ( aSig0 << 12 ) | ( aSig1 >> 52 ); + if ( aSig & LIT64( 0x0020000000000000 ) ) { + aSig >>= 1; + zSig |= i; + } + } + + if ( zSign ) + zSig = -zSig; + return normalizeRoundAndPackFloat64( zSign, 0x408, zSig STATUS_VAR ); +} + +/*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is equal to the | corresponding value `b', and 0 otherwise. The comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. @@ -4597,7 +4702,10 @@ static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM return a; } add128( aSig0, aSig1, bSig0, bSig1, &zSig0, &zSig1 ); - if ( aExp == 0 ) return packFloat128( zSign, 0, zSig0, zSig1 ); + if ( aExp == 0 ) { + if ( STATUS(flush_to_zero) ) return packFloat128( zSign, 0, 0, 0 ); + return packFloat128( zSign, 0, zSig0, zSig1 ); + } zSig2 = 0; zSig0 |= LIT64( 0x0002000000000000 ); zExp = aExp; @@ -4987,7 +5095,7 @@ float128 float128_rem( float128 a, float128 b STATUS_PARAM ) sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); } while ( 0 <= (sbits64) aSig0 ); add128( - aSig0, aSig1, alternateASig0, alternateASig1, &sigMean0, &sigMean1 ); + aSig0, aSig1, alternateASig0, alternateASig1, (bits64 *)&sigMean0, &sigMean1 ); if ( ( sigMean0 < 0 ) || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) { aSig0 = alternateASig0; @@ -5479,8 +5587,14 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM ) if ( aExp == 0xFF ) { return a; } - aExp += n; - return roundAndPackFloat32( aSign, aExp, aSig STATUS_VAR ); + if ( aExp != 0 ) + aSig |= 0x00800000; + else if ( aSig == 0 ) + return a; + + aExp += n - 1; + aSig <<= 7; + return normalizeRoundAndPackFloat32( aSign, aExp, aSig STATUS_VAR ); } float64 float64_scalbn( float64 a, int n STATUS_PARAM ) @@ -5496,8 +5610,14 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM ) if ( aExp == 0x7FF ) { return a; } - aExp += n; - return roundAndPackFloat64( aSign, aExp, aSig STATUS_VAR ); + if ( aExp != 0 ) + aSig |= LIT64( 0x0010000000000000 ); + else if ( aSig == 0 ) + return a; + + aExp += n - 1; + aSig <<= 10; + return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR ); } #ifdef FLOATX80 @@ -5514,9 +5634,12 @@ floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM ) if ( aExp == 0x7FF ) { return a; } + if (aExp == 0 && aSig == 0) + return a; + aExp += n; - return roundAndPackFloatx80( STATUS(floatx80_rounding_precision), - aSign, aExp, aSig, 0 STATUS_VAR ); + return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision), + aSign, aExp, aSig, 0 STATUS_VAR ); } #endif @@ -5534,8 +5657,14 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM ) if ( aExp == 0x7FFF ) { return a; } - aExp += n; - return roundAndPackFloat128( aSign, aExp, aSig0, aSig1, 0 STATUS_VAR ); + if ( aExp != 0 ) + aSig0 |= LIT64( 0x0001000000000000 ); + else if ( aSig0 == 0 && aSig1 == 0 ) + return a; + + aExp += n - 1; + return normalizeRoundAndPackFloat128( aSign, aExp, aSig0, aSig1 + STATUS_VAR ); } #endif diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 5f95d06..850a01f 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -50,8 +50,10 @@ these four paragraphs for those parts of this code that are retained. typedef uint8_t flag; typedef uint8_t uint8; typedef int8_t int8; +#ifndef _AIX typedef int uint16; typedef int int16; +#endif typedef unsigned int uint32; typedef signed int int32; typedef uint64_t uint64; @@ -88,7 +90,7 @@ typedef int64_t sbits64; #define FLOAT128 #else /* native float support */ -#if (defined(__i386__) || defined(__x86_64__)) && !defined(_BSD) +#if (defined(__i386__) || defined(__x86_64__)) && !defined(HOST_BSD) #define FLOATX80 #endif #endif /* !CONFIG_SOFTFLOAT */ @@ -188,10 +190,20 @@ typedef struct float_status { #ifdef FLOATX80 signed char floatx80_rounding_precision; #endif + flag flush_to_zero; + flag default_nan_mode; } float_status; void set_float_rounding_mode(int val STATUS_PARAM); void set_float_exception_flags(int val STATUS_PARAM); +INLINE void set_flush_to_zero(flag val STATUS_PARAM) +{ + STATUS(flush_to_zero) = val; +} +INLINE void set_default_nan_mode(flag val STATUS_PARAM) +{ + STATUS(default_nan_mode) = val; +} INLINE int get_float_exception_flags(float_status *status) { return STATUS(float_exception_flags); @@ -257,6 +269,7 @@ float32 float32_mul( float32, float32 STATUS_PARAM ); float32 float32_div( float32, float32 STATUS_PARAM ); float32 float32_rem( float32, float32 STATUS_PARAM ); float32 float32_sqrt( float32 STATUS_PARAM ); +float32 float32_log2( float32 STATUS_PARAM ); int float32_eq( float32, float32 STATUS_PARAM ); int float32_le( float32, float32 STATUS_PARAM ); int float32_lt( float32, float32 STATUS_PARAM ); @@ -279,7 +292,23 @@ INLINE float32 float32_chs(float32 a) return make_float32(float32_val(a) ^ 0x80000000); } +INLINE int float32_is_infinity(float32 a) +{ + return (float32_val(a) & 0x7fffffff) == 0x7f800000; +} + +INLINE int float32_is_neg(float32 a) +{ + return float32_val(a) >> 31; +} + +INLINE int float32_is_zero(float32 a) +{ + return (float32_val(a) & 0x7fffffff) == 0; +} + #define float32_zero make_float32(0) +#define float32_one make_float32(0x3f800000) /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. @@ -311,6 +340,7 @@ float64 float64_mul( float64, float64 STATUS_PARAM ); float64 float64_div( float64, float64 STATUS_PARAM ); float64 float64_rem( float64, float64 STATUS_PARAM ); float64 float64_sqrt( float64 STATUS_PARAM ); +float64 float64_log2( float64 STATUS_PARAM ); int float64_eq( float64, float64 STATUS_PARAM ); int float64_le( float64, float64 STATUS_PARAM ); int float64_lt( float64, float64 STATUS_PARAM ); @@ -333,7 +363,23 @@ INLINE float64 float64_chs(float64 a) return make_float64(float64_val(a) ^ 0x8000000000000000LL); } +INLINE int float64_is_infinity(float64 a) +{ + return (float64_val(a) & 0x7fffffffffffffffLL ) == 0x7ff0000000000000LL; +} + +INLINE int float64_is_neg(float64 a) +{ + return float64_val(a) >> 63; +} + +INLINE int float64_is_zero(float64 a) +{ + return (float64_val(a) & 0x7fffffffffffffffLL) == 0; +} + #define float64_zero make_float64(0) +#define float64_one make_float64(0x3ff0000000000000LL) #ifdef FLOATX80 @@ -382,6 +428,21 @@ INLINE floatx80 floatx80_chs(floatx80 a) return a; } +INLINE int floatx80_is_infinity(floatx80 a) +{ + return (a.high & 0x7fff) == 0x7fff && a.low == 0; +} + +INLINE int floatx80_is_neg(floatx80 a) +{ + return a.high >> 15; +} + +INLINE int floatx80_is_zero(floatx80 a) +{ + return (a.high & 0x7fff) == 0 && a.low == 0; +} + #endif #ifdef FLOAT128 @@ -433,6 +494,21 @@ INLINE float128 float128_chs(float128 a) return a; } +INLINE int float128_is_infinity(float128 a) +{ + return (a.high & 0x7fffffffffffffffLL) == 0x7fff000000000000LL && a.low == 0; +} + +INLINE int float128_is_neg(float128 a) +{ + return a.high >> 63; +} + +INLINE int float128_is_zero(float128 a) +{ + return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0; +} + #endif #else /* CONFIG_SOFTFLOAT */ |