From bfec547677ddf2164ffd49a34c3ace2a41c938ad Mon Sep 17 00:00:00 2001 From: David 'Digit' Turner Date: Tue, 10 May 2011 12:59:13 +0200 Subject: fpu: upstream integrate Change-Id: Ifadcfe209b1d0891a6a81a60bcc1f0ab76dedc11 --- fpu/softfloat-macros.h | 216 ++++--- fpu/softfloat-native.c | 38 +- fpu/softfloat-native.h | 69 ++- fpu/softfloat-specialize.h | 662 ++++++++++++++------- fpu/softfloat.c | 1398 +++++++++++++++++++++++++++++++------------- fpu/softfloat.h | 296 ++++++++-- 6 files changed, 1888 insertions(+), 791 deletions(-) (limited to 'fpu') diff --git a/fpu/softfloat-macros.h b/fpu/softfloat-macros.h index 7838228..e82ce23 100644 --- a/fpu/softfloat-macros.h +++ b/fpu/softfloat-macros.h @@ -1,3 +1,8 @@ +/* + * QEMU float support macros + * + * Derived from SoftFloat. + */ /*============================================================================ @@ -31,6 +36,17 @@ these four paragraphs for those parts of this code that are retained. =============================================================================*/ /*---------------------------------------------------------------------------- +| This macro tests for minimum version of the GNU C compiler. +*----------------------------------------------------------------------------*/ +#if defined(__GNUC__) && defined(__GNUC_MINOR__) +# define SOFTFLOAT_GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +# define SOFTFLOAT_GNUC_PREREQ(maj, min) 0 +#endif + + +/*---------------------------------------------------------------------------- | Shifts `a' right by the number of bits given in `count'. If any nonzero | bits are shifted off, they are ``jammed'' into the least significant bit of | the result by setting the least significant bit to 1. The value of `count' @@ -39,9 +55,9 @@ these four paragraphs for those parts of this code that are retained. | The result is stored in the location pointed to by `zPtr'. *----------------------------------------------------------------------------*/ -INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr ) +INLINE void shift32RightJamming( uint32_t a, int16 count, uint32_t *zPtr ) { - bits32 z; + uint32_t z; if ( count == 0 ) { z = a; @@ -65,9 +81,9 @@ INLINE void shift32RightJamming( bits32 a, int16 count, bits32 *zPtr ) | The result is stored in the location pointed to by `zPtr'. *----------------------------------------------------------------------------*/ -INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr ) +INLINE void shift64RightJamming( uint64_t a, int16 count, uint64_t *zPtr ) { - bits64 z; + uint64_t z; if ( count == 0 ) { z = a; @@ -101,9 +117,9 @@ INLINE void shift64RightJamming( bits64 a, int16 count, bits64 *zPtr ) INLINE void shift64ExtraRightJamming( - bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) + uint64_t a0, uint64_t a1, int16 count, uint64_t *z0Ptr, uint64_t *z1Ptr ) { - bits64 z0, z1; + uint64_t z0, z1; int8 negCount = ( - count ) & 63; if ( count == 0 ) { @@ -138,9 +154,9 @@ INLINE void INLINE void shift128Right( - bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) + uint64_t a0, uint64_t a1, int16 count, uint64_t *z0Ptr, uint64_t *z1Ptr ) { - bits64 z0, z1; + uint64_t z0, z1; int8 negCount = ( - count ) & 63; if ( count == 0 ) { @@ -173,9 +189,9 @@ INLINE void INLINE void shift128RightJamming( - bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) + uint64_t a0, uint64_t a1, int16 count, uint64_t *z0Ptr, uint64_t *z1Ptr ) { - bits64 z0, z1; + uint64_t z0, z1; int8 negCount = ( - count ) & 63; if ( count == 0 ) { @@ -224,16 +240,16 @@ INLINE void INLINE void shift128ExtraRightJamming( - bits64 a0, - bits64 a1, - bits64 a2, + uint64_t a0, + uint64_t a1, + uint64_t a2, int16 count, - bits64 *z0Ptr, - bits64 *z1Ptr, - bits64 *z2Ptr + uint64_t *z0Ptr, + uint64_t *z1Ptr, + uint64_t *z2Ptr ) { - bits64 z0, z1, z2; + uint64_t z0, z1, z2; int8 negCount = ( - count ) & 63; if ( count == 0 ) { @@ -282,7 +298,7 @@ INLINE void INLINE void shortShift128Left( - bits64 a0, bits64 a1, int16 count, bits64 *z0Ptr, bits64 *z1Ptr ) + uint64_t a0, uint64_t a1, int16 count, uint64_t *z0Ptr, uint64_t *z1Ptr ) { *z1Ptr = a1<>32; bLow = b; bHigh = b>>32; - z1 = ( (bits64) aLow ) * bLow; - zMiddleA = ( (bits64) aLow ) * bHigh; - zMiddleB = ( (bits64) aHigh ) * bLow; - z0 = ( (bits64) aHigh ) * bHigh; + z1 = ( (uint64_t) aLow ) * bLow; + zMiddleA = ( (uint64_t) aLow ) * bHigh; + zMiddleB = ( (uint64_t) aHigh ) * bLow; + z0 = ( (uint64_t) aHigh ) * bHigh; zMiddleA += zMiddleB; - z0 += ( ( (bits64) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 ); + z0 += ( ( (uint64_t) ( zMiddleA < zMiddleB ) )<<32 ) + ( zMiddleA>>32 ); zMiddleA <<= 32; z1 += zMiddleA; z0 += ( z1 < zMiddleA ); @@ -478,15 +494,15 @@ INLINE void mul64To128( bits64 a, bits64 b, bits64 *z0Ptr, bits64 *z1Ptr ) INLINE void mul128By64To192( - bits64 a0, - bits64 a1, - bits64 b, - bits64 *z0Ptr, - bits64 *z1Ptr, - bits64 *z2Ptr + uint64_t a0, + uint64_t a1, + uint64_t b, + uint64_t *z0Ptr, + uint64_t *z1Ptr, + uint64_t *z2Ptr ) { - bits64 z0, z1, z2, more1; + uint64_t z0, z1, z2, more1; mul64To128( a1, b, &z1, &z2 ); mul64To128( a0, b, &z0, &more1 ); @@ -506,18 +522,18 @@ INLINE void INLINE void mul128To256( - bits64 a0, - bits64 a1, - bits64 b0, - bits64 b1, - bits64 *z0Ptr, - bits64 *z1Ptr, - bits64 *z2Ptr, - bits64 *z3Ptr + uint64_t a0, + uint64_t a1, + uint64_t b0, + uint64_t b1, + uint64_t *z0Ptr, + uint64_t *z1Ptr, + uint64_t *z2Ptr, + uint64_t *z3Ptr ) { - bits64 z0, z1, z2, z3; - bits64 more1, more2; + uint64_t z0, z1, z2, z3; + uint64_t more1, more2; mul64To128( a1, b1, &z2, &z3 ); mul64To128( a1, b0, &z1, &more2 ); @@ -543,18 +559,18 @@ INLINE void | unsigned integer is returned. *----------------------------------------------------------------------------*/ -static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b ) +static uint64_t estimateDiv128To64( uint64_t a0, uint64_t a1, uint64_t b ) { - bits64 b0, b1; - bits64 rem0, rem1, term0, term1; - bits64 z; + uint64_t b0, b1; + uint64_t rem0, rem1, term0, term1; + uint64_t z; if ( b <= a0 ) return LIT64( 0xFFFFFFFFFFFFFFFF ); b0 = b>>32; z = ( b0<<32 <= a0 ) ? LIT64( 0xFFFFFFFF00000000 ) : ( a0 / b0 )<<32; mul64To128( b, z, &term0, &term1 ); sub128( a0, a1, term0, term1, &rem0, &rem1 ); - while ( ( (sbits64) rem0 ) < 0 ) { + while ( ( (int64_t) rem0 ) < 0 ) { z -= LIT64( 0x100000000 ); b1 = b<<32; add128( rem0, rem1, b0, b1, &rem0, &rem1 ); @@ -575,18 +591,18 @@ static bits64 estimateDiv128To64( bits64 a0, bits64 a1, bits64 b ) | value. *----------------------------------------------------------------------------*/ -static bits32 estimateSqrt32( int16 aExp, bits32 a ) +static uint32_t estimateSqrt32( int16 aExp, uint32_t a ) { - static const bits16 sqrtOddAdjustments[] = { + static const uint16_t sqrtOddAdjustments[] = { 0x0004, 0x0022, 0x005D, 0x00B1, 0x011D, 0x019F, 0x0236, 0x02E0, 0x039C, 0x0468, 0x0545, 0x0631, 0x072B, 0x0832, 0x0946, 0x0A67 }; - static const bits16 sqrtEvenAdjustments[] = { + static const uint16_t sqrtEvenAdjustments[] = { 0x0A2D, 0x08AF, 0x075A, 0x0629, 0x051A, 0x0429, 0x0356, 0x029E, 0x0200, 0x0179, 0x0109, 0x00AF, 0x0068, 0x0034, 0x0012, 0x0002 }; int8 index; - bits32 z; + uint32_t z; index = ( a>>27 ) & 15; if ( aExp & 1 ) { @@ -598,9 +614,9 @@ static bits32 estimateSqrt32( int16 aExp, bits32 a ) 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 ); + if ( z <= a ) return (uint32_t) ( ( (int32_t) a )>>1 ); } - return ( (bits32) ( ( ( (bits64) a )<<31 ) / z ) ) + ( z>>1 ); + return ( (uint32_t) ( ( ( (uint64_t) a )<<31 ) / z ) ) + ( z>>1 ); } @@ -609,8 +625,15 @@ static bits32 estimateSqrt32( int16 aExp, bits32 a ) | `a'. If `a' is zero, 32 is returned. *----------------------------------------------------------------------------*/ -static int8 countLeadingZeros32( bits32 a ) +static int8 countLeadingZeros32( uint32_t a ) { +#if SOFTFLOAT_GNUC_PREREQ(3, 4) + if (a) { + return __builtin_clz(a); + } else { + return 32; + } +#else static const int8 countLeadingZerosHigh[] = { 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, @@ -642,7 +665,7 @@ static int8 countLeadingZeros32( bits32 a ) } shiftCount += countLeadingZerosHigh[ a>>24 ]; return shiftCount; - +#endif } /*---------------------------------------------------------------------------- @@ -650,12 +673,19 @@ static int8 countLeadingZeros32( bits32 a ) | `a'. If `a' is zero, 64 is returned. *----------------------------------------------------------------------------*/ -static int8 countLeadingZeros64( bits64 a ) +static int8 countLeadingZeros64( uint64_t a ) { +#if SOFTFLOAT_GNUC_PREREQ(3, 4) + if (a) { + return __builtin_clzll(a); + } else { + return 64; + } +#else int8 shiftCount; shiftCount = 0; - if ( a < ( (bits64) 1 )<<32 ) { + if ( a < ( (uint64_t) 1 )<<32 ) { shiftCount += 32; } else { @@ -663,7 +693,7 @@ static int8 countLeadingZeros64( bits64 a ) } shiftCount += countLeadingZeros32( a ); return shiftCount; - +#endif } /*---------------------------------------------------------------------------- @@ -672,7 +702,7 @@ static int8 countLeadingZeros64( bits64 a ) | Otherwise, returns 0. *----------------------------------------------------------------------------*/ -INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +INLINE flag eq128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 ) { return ( a0 == b0 ) && ( a1 == b1 ); @@ -685,7 +715,7 @@ INLINE flag eq128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) | Otherwise, returns 0. *----------------------------------------------------------------------------*/ -INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +INLINE flag le128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 ) { return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 <= b1 ) ); @@ -698,7 +728,7 @@ INLINE flag le128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) | returns 0. *----------------------------------------------------------------------------*/ -INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +INLINE flag lt128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 ) { return ( a0 < b0 ) || ( ( a0 == b0 ) && ( a1 < b1 ) ); @@ -711,7 +741,7 @@ INLINE flag lt128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) | Otherwise, returns 0. *----------------------------------------------------------------------------*/ -INLINE flag ne128( bits64 a0, bits64 a1, bits64 b0, bits64 b1 ) +INLINE flag ne128( uint64_t a0, uint64_t a1, uint64_t b0, uint64_t b1 ) { return ( a0 != b0 ) || ( a1 != b1 ); diff --git a/fpu/softfloat-native.c b/fpu/softfloat-native.c index 049c830..8848651 100644 --- a/fpu/softfloat-native.c +++ b/fpu/softfloat-native.c @@ -254,7 +254,7 @@ int float32_is_signaling_nan( float32 a1) return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); } -int float32_is_nan( float32 a1 ) +int float32_is_quiet_nan( float32 a1 ) { float32u u; uint64_t a; @@ -263,6 +263,15 @@ int float32_is_nan( float32 a1 ) return ( 0xFF800000 < ( a<<1 ) ); } +int float32_is_any_nan( float32 a1 ) +{ + float32u u; + uint32_t a; + u.f = a1; + a = u.i; + return (a & ~(1 << 31)) > 0x7f800000U; +} + /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ @@ -411,15 +420,25 @@ int float64_is_signaling_nan( float64 a1) } -int float64_is_nan( float64 a1 ) +int float64_is_quiet_nan( float64 a1 ) { float64u u; uint64_t a; u.f = a1; a = u.i; - return ( LIT64( 0xFFF0000000000000 ) < (bits64) ( a<<1 ) ); + return ( LIT64( 0xFFF0000000000000 ) < (uint64_t) ( a<<1 ) ); + +} + +int float64_is_any_nan( float64 a1 ) +{ + float64u u; + uint64_t a; + u.f = a1; + a = u.i; + return (a & ~(1ULL << 63)) > LIT64 (0x7FF0000000000000 ); } #ifdef FLOATX80 @@ -500,15 +519,22 @@ int floatx80_is_signaling_nan( floatx80 a1) aLow = u.i.low & ~ LIT64( 0x4000000000000000 ); return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) - && (bits64) ( aLow<<1 ) + && (uint64_t) ( aLow<<1 ) && ( u.i.low == aLow ); } -int floatx80_is_nan( floatx80 a1 ) +int floatx80_is_quiet_nan( floatx80 a1 ) +{ + floatx80u u; + u.f = a1; + return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (uint64_t) ( u.i.low<<1 ); +} + +int floatx80_is_any_nan( floatx80 a1 ) { floatx80u u; u.f = a1; - return ( ( u.i.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( u.i.low<<1 ); + return ((u.i.high & 0x7FFF) == 0x7FFF) && ( u.i.low<<1 ); } #endif diff --git a/fpu/softfloat-native.h b/fpu/softfloat-native.h index 6da0bcb..6afb74a 100644 --- a/fpu/softfloat-native.h +++ b/fpu/softfloat-native.h @@ -172,6 +172,15 @@ float128 int64_to_float128( int64_t STATUS_PARAM); #endif /*---------------------------------------------------------------------------- +| Software IEC/IEEE single-precision conversion constants. +*----------------------------------------------------------------------------*/ +#define float32_zero (0.0) +#define float32_one (1.0) +#define float32_ln2 (0.6931471) +#define float32_pi (3.1415926) +#define float32_half (0.5) + +/*---------------------------------------------------------------------------- | Software IEC/IEEE single-precision conversion routines. *----------------------------------------------------------------------------*/ int float32_to_int32( float32 STATUS_PARAM); @@ -210,7 +219,7 @@ INLINE float32 float32_div( float32 a, float32 b STATUS_PARAM) } float32 float32_rem( float32, float32 STATUS_PARAM); float32 float32_sqrt( float32 STATUS_PARAM); -INLINE int float32_eq( float32 a, float32 b STATUS_PARAM) +INLINE int float32_eq_quiet( float32 a, float32 b STATUS_PARAM) { return a == b; } @@ -222,7 +231,7 @@ INLINE int float32_lt( float32 a, float32 b STATUS_PARAM) { return a < b; } -INLINE int float32_eq_signaling( float32 a, float32 b STATUS_PARAM) +INLINE int float32_eq( float32 a, float32 b STATUS_PARAM) { return a <= b && a >= b; } @@ -237,12 +246,16 @@ INLINE int float32_lt_quiet( float32 a, float32 b STATUS_PARAM) INLINE int float32_unordered( float32 a, float32 b STATUS_PARAM) { return isunordered(a, b); - +} +INLINE int float32_unordered_quiet( float32 a, float32 b STATUS_PARAM) +{ + return isunordered(a, b); } 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 ); +int float32_is_quiet_nan( float32 ); +int float32_is_any_nan( float32 ); INLINE float32 float32_abs(float32 a) { @@ -271,12 +284,21 @@ INLINE float32 float32_is_zero(float32 a) return fpclassify(a) == FP_ZERO; } -INLINE float32 float32_scalbn(float32 a, int n) +INLINE float32 float32_scalbn(float32 a, int n STATUS_PARAM) { return scalbnf(a, n); } /*---------------------------------------------------------------------------- +| Software IEC/IEEE double-precision conversion constants. +*----------------------------------------------------------------------------*/ +#define float64_zero (0.0) +#define float64_one (1.0) +#define float64_ln2 (0.693147180559945) +#define float64_pi (3.141592653589793) +#define float64_half (0.5) + +/*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ int float64_to_int32( float64 STATUS_PARAM ); @@ -318,7 +340,7 @@ INLINE float64 float64_div( float64 a, float64 b STATUS_PARAM) } float64 float64_rem( float64, float64 STATUS_PARAM ); float64 float64_sqrt( float64 STATUS_PARAM ); -INLINE int float64_eq( float64 a, float64 b STATUS_PARAM) +INLINE int float64_eq_quiet( float64 a, float64 b STATUS_PARAM) { return a == b; } @@ -330,7 +352,7 @@ INLINE int float64_lt( float64 a, float64 b STATUS_PARAM) { return a < b; } -INLINE int float64_eq_signaling( float64 a, float64 b STATUS_PARAM) +INLINE int float64_eq( float64 a, float64 b STATUS_PARAM) { return a <= b && a >= b; } @@ -346,12 +368,16 @@ INLINE int float64_lt_quiet( float64 a, float64 b STATUS_PARAM) INLINE int float64_unordered( float64 a, float64 b STATUS_PARAM) { return isunordered(a, b); - +} +INLINE int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM) +{ + return isunordered(a, b); } int float64_compare( float64, float64 STATUS_PARAM ); int float64_compare_quiet( float64, float64 STATUS_PARAM ); int float64_is_signaling_nan( float64 ); -int float64_is_nan( float64 ); +int float64_is_any_nan( float64 ); +int float64_is_quiet_nan( float64 ); INLINE float64 float64_abs(float64 a) { @@ -380,7 +406,7 @@ INLINE float64 float64_is_zero(float64 a) return fpclassify(a) == FP_ZERO; } -INLINE float64 float64_scalbn(float64 a, int n) +INLINE float64 float64_scalbn(float64 a, int n STATUS_PARAM) { return scalbn(a, n); } @@ -388,6 +414,15 @@ INLINE float64 float64_scalbn(float64 a, int n) #ifdef FLOATX80 /*---------------------------------------------------------------------------- +| Software IEC/IEEE extended double-precision conversion constants. +*----------------------------------------------------------------------------*/ +#define floatx80_zero (0.0L) +#define floatx80_one (1.0L) +#define floatx80_ln2 (0.69314718055994530943L) +#define floatx80_pi (3.14159265358979323851L) +#define floatx80_half (0.5L) + +/*---------------------------------------------------------------------------- | Software IEC/IEEE extended double-precision conversion routines. *----------------------------------------------------------------------------*/ int floatx80_to_int32( floatx80 STATUS_PARAM ); @@ -422,7 +457,7 @@ INLINE floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM) } floatx80 floatx80_rem( floatx80, floatx80 STATUS_PARAM ); floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); -INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM) { return a == b; } @@ -434,7 +469,7 @@ INLINE int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM) { return a < b; } -INLINE int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM) +INLINE int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM) { return a <= b && a >= b; } @@ -450,12 +485,16 @@ INLINE int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM) INLINE int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM) { return isunordered(a, b); - +} +INLINE int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM) +{ + return isunordered(a, b); } 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 ); +int floatx80_is_quiet_nan( floatx80 ); +int floatx80_is_any_nan( floatx80 ); INLINE floatx80 floatx80_abs(floatx80 a) { @@ -484,7 +523,7 @@ INLINE floatx80 floatx80_is_zero(floatx80 a) return fpclassify(a) == FP_ZERO; } -INLINE floatx80 floatx80_scalbn(floatx80 a, int n) +INLINE floatx80 floatx80_scalbn(floatx80 a, int n STATUS_PARAM) { return scalbnl(a, n); } diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h index 8e6aceb..9d68aae 100644 --- a/fpu/softfloat-specialize.h +++ b/fpu/softfloat-specialize.h @@ -1,3 +1,8 @@ +/* + * QEMU float support + * + * Derived from SoftFloat. + */ /*============================================================================ @@ -30,12 +35,6 @@ these four paragraphs for those parts of this code that are retained. =============================================================================*/ -#if defined(TARGET_MIPS) || defined(TARGET_HPPA) -#define SNAN_BIT_IS_ONE 1 -#else -#define SNAN_BIT_IS_ONE 0 -#endif - /*---------------------------------------------------------------------------- | Raises the exceptions specified by `flags'. Floating-point traps can be | defined here if desired. It is currently not possible for such a trap @@ -53,36 +52,111 @@ void float_raise( int8 flags STATUS_PARAM ) *----------------------------------------------------------------------------*/ typedef struct { flag sign; - bits64 high, low; + uint64_t high, low; } commonNaNT; /*---------------------------------------------------------------------------- -| The pattern for a default generated single-precision NaN. +| Returns 1 if the half-precision floating-point value `a' is a quiet +| NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -#if defined(TARGET_SPARC) -#define float32_default_nan make_float32(0x7FFFFFFF) -#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) -#define float32_default_nan make_float32(0x7FC00000) -#elif defined(TARGET_HPPA) -#define float32_default_nan make_float32(0x7FA00000) -#elif SNAN_BIT_IS_ONE -#define float32_default_nan make_float32(0x7FBFFFFF) + +int float16_is_quiet_nan(float16 a_) +{ + uint16_t a = float16_val(a_); +#if SNAN_BIT_IS_ONE + return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF); #else -#define float32_default_nan make_float32(0xFFC00000) + return ((a & ~0x8000) >= 0x7c80); #endif +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the half-precision floating-point value `a' is a signaling +| NaN; otherwise returns 0. +*----------------------------------------------------------------------------*/ + +int float16_is_signaling_nan(float16 a_) +{ + uint16_t a = float16_val(a_); +#if SNAN_BIT_IS_ONE + return ((a & ~0x8000) >= 0x7c80); +#else + return (((a >> 9) & 0x3F) == 0x3E) && (a & 0x1FF); +#endif +} + +/*---------------------------------------------------------------------------- +| Returns a quiet NaN if the half-precision floating point value `a' is a +| signaling NaN; otherwise returns `a'. +*----------------------------------------------------------------------------*/ +float16 float16_maybe_silence_nan(float16 a_) +{ + if (float16_is_signaling_nan(a_)) { +#if SNAN_BIT_IS_ONE +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) + return float16_default_nan; +# else +# error Rules for silencing a signaling NaN are target-specific +# endif +#else + uint16_t a = float16_val(a_); + a |= (1 << 9); + return make_float16(a); +#endif + } + return a_; +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the half-precision floating-point NaN +| `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid +| exception is raised. +*----------------------------------------------------------------------------*/ + +static commonNaNT float16ToCommonNaN( float16 a STATUS_PARAM ) +{ + commonNaNT z; + + if ( float16_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR ); + z.sign = float16_val(a) >> 15; + z.low = 0; + z.high = ((uint64_t) float16_val(a))<<54; + return z; +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the canonical NaN `a' to the half- +| precision floating-point format. +*----------------------------------------------------------------------------*/ + +static float16 commonNaNToFloat16(commonNaNT a STATUS_PARAM) +{ + uint16_t mantissa = a.high>>54; + + if (STATUS(default_nan_mode)) { + return float16_default_nan; + } + + if (mantissa) { + return make_float16(((((uint16_t) a.sign) << 15) + | (0x1F << 10) | mantissa)); + } else { + return float16_default_nan; + } +} /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is a quiet | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float32_is_nan( float32 a_ ) +int float32_is_quiet_nan( float32 a_ ) { uint32_t a = float32_val(a_); #if SNAN_BIT_IS_ONE return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); #else - return ( 0xFF800000 <= (bits32) ( a<<1 ) ); + return ( 0xFF800000 <= (uint32_t) ( a<<1 ) ); #endif } @@ -95,13 +169,36 @@ int float32_is_signaling_nan( float32 a_ ) { uint32_t a = float32_val(a_); #if SNAN_BIT_IS_ONE - return ( 0xFF800000 <= (bits32) ( a<<1 ) ); + return ( 0xFF800000 <= (uint32_t) ( a<<1 ) ); #else return ( ( ( a>>22 ) & 0x1FF ) == 0x1FE ) && ( a & 0x003FFFFF ); #endif } /*---------------------------------------------------------------------------- +| Returns a quiet NaN if the single-precision floating point value `a' is a +| signaling NaN; otherwise returns `a'. +*----------------------------------------------------------------------------*/ + +float32 float32_maybe_silence_nan( float32 a_ ) +{ + if (float32_is_signaling_nan(a_)) { +#if SNAN_BIT_IS_ONE +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) + return float32_default_nan; +# else +# error Rules for silencing a signaling NaN are target-specific +# endif +#else + uint32_t a = float32_val(a_); + a |= (1 << 22); + return make_float32(a); +#endif + } + return a_; +} + +/*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point NaN | `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid | exception is raised. @@ -114,7 +211,7 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM ) if ( float32_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR ); z.sign = float32_val(a)>>31; z.low = 0; - z.high = ( (bits64) float32_val(a) )<<41; + z.high = ( (uint64_t) float32_val(a) )<<41; return z; } @@ -123,17 +220,134 @@ static commonNaNT float32ToCommonNaN( float32 a STATUS_PARAM ) | precision floating-point format. *----------------------------------------------------------------------------*/ -static float32 commonNaNToFloat32( commonNaNT a ) +static float32 commonNaNToFloat32( commonNaNT a STATUS_PARAM) { - bits32 mantissa = a.high>>41; + uint32_t mantissa = a.high>>41; + + if ( STATUS(default_nan_mode) ) { + return float32_default_nan; + } + if ( mantissa ) return make_float32( - ( ( (bits32) a.sign )<<31 ) | 0x7F800000 | ( a.high>>41 ) ); + ( ( (uint32_t) a.sign )<<31 ) | 0x7F800000 | ( a.high>>41 ) ); else return float32_default_nan; } /*---------------------------------------------------------------------------- +| Select which NaN to propagate for a two-input operation. +| IEEE754 doesn't specify all the details of this, so the +| algorithm is target-specific. +| The routine is passed various bits of information about the +| two NaNs and should return 0 to select NaN a and 1 for NaN b. +| Note that signalling NaNs are always squashed to quiet NaNs +| by the caller, by calling floatXX_maybe_silence_nan() before +| returning them. +| +| aIsLargerSignificand is only valid if both a and b are NaNs +| of some kind, and is true if a has the larger significand, +| or if both a and b have the same significand but a is +| positive but b is negative. It is only needed for the x87 +| tie-break rule. +*----------------------------------------------------------------------------*/ + +#if defined(TARGET_ARM) +static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, + flag aIsLargerSignificand) +{ + /* ARM mandated NaN propagation rules: take the first of: + * 1. A if it is signaling + * 2. B if it is signaling + * 3. A (quiet) + * 4. B (quiet) + * A signaling NaN is always quietened before returning it. + */ + if (aIsSNaN) { + return 0; + } else if (bIsSNaN) { + return 1; + } else if (aIsQNaN) { + return 0; + } else { + return 1; + } +} +#elif defined(TARGET_MIPS) +static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, + flag aIsLargerSignificand) +{ + /* According to MIPS specifications, if one of the two operands is + * a sNaN, a new qNaN has to be generated. This is done in + * floatXX_maybe_silence_nan(). For qNaN inputs the specifications + * says: "When possible, this QNaN result is one of the operand QNaN + * values." In practice it seems that most implementations choose + * the first operand if both operands are qNaN. In short this gives + * the following rules: + * 1. A if it is signaling + * 2. B if it is signaling + * 3. A (quiet) + * 4. B (quiet) + * A signaling NaN is always silenced before returning it. + */ + if (aIsSNaN) { + return 0; + } else if (bIsSNaN) { + return 1; + } else if (aIsQNaN) { + return 0; + } else { + return 1; + } +} +#elif defined(TARGET_PPC) +static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, + flag aIsLargerSignificand) +{ + /* PowerPC propagation rules: + * 1. A if it sNaN or qNaN + * 2. B if it sNaN or qNaN + * A signaling NaN is always silenced before returning it. + */ + if (aIsSNaN || aIsQNaN) { + return 0; + } else { + return 1; + } +} +#else +static int pickNaN(flag aIsQNaN, flag aIsSNaN, flag bIsQNaN, flag bIsSNaN, + flag aIsLargerSignificand) +{ + /* This implements x87 NaN propagation rules: + * SNaN + QNaN => return the QNaN + * two SNaNs => return the one with the larger significand, silenced + * two QNaNs => return the one with the larger significand + * SNaN and a non-NaN => return the SNaN, silenced + * QNaN and a non-NaN => return the QNaN + * + * If we get down to comparing significands and they are the same, + * return the NaN with the positive sign bit (if any). + */ + if (aIsSNaN) { + if (bIsSNaN) { + return aIsLargerSignificand ? 0 : 1; + } + return bIsQNaN ? 1 : 0; + } + else if (aIsQNaN) { + if (bIsSNaN || !bIsQNaN) + return 0; + else { + return aIsLargerSignificand ? 0 : 1; + } + } else { + return 1; + } +} +#endif + +/*---------------------------------------------------------------------------- | Takes two single-precision floating-point values `a' and `b', one of which | is a NaN, and returns the appropriate NaN result. If either `a' or `b' is a | signaling NaN, the invalid exception is raised. @@ -141,78 +355,52 @@ static float32 commonNaNToFloat32( commonNaNT a ) static float32 propagateFloat32NaN( float32 a, float32 b STATUS_PARAM) { - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; - bits32 av, bv, res; + flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN; + flag aIsLargerSignificand; + uint32_t av, bv; - if ( STATUS(default_nan_mode) ) - return float32_default_nan; - - aIsNaN = float32_is_nan( a ); + aIsQuietNaN = float32_is_quiet_nan( a ); aIsSignalingNaN = float32_is_signaling_nan( a ); - bIsNaN = float32_is_nan( b ); + bIsQuietNaN = float32_is_quiet_nan( b ); bIsSignalingNaN = float32_is_signaling_nan( b ); av = float32_val(a); bv = float32_val(b); -#if SNAN_BIT_IS_ONE - av &= ~0x00400000; - bv &= ~0x00400000; -#else - av |= 0x00400000; - bv |= 0x00400000; -#endif + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); - if ( aIsSignalingNaN ) { - if ( bIsSignalingNaN ) goto returnLargerSignificand; - res = bIsNaN ? bv : av; - } - else if ( aIsNaN ) { - if ( bIsSignalingNaN || ! bIsNaN ) - res = av; - else { - returnLargerSignificand: - 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; - } + + if ( STATUS(default_nan_mode) ) + return float32_default_nan; + + if ((uint32_t)(av<<1) < (uint32_t)(bv<<1)) { + aIsLargerSignificand = 0; + } else if ((uint32_t)(bv<<1) < (uint32_t)(av<<1)) { + aIsLargerSignificand = 1; + } else { + aIsLargerSignificand = (av < bv) ? 1 : 0; } - else { - res = bv; + + if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN, + aIsLargerSignificand)) { + return float32_maybe_silence_nan(b); + } else { + return float32_maybe_silence_nan(a); } - return make_float32(res); } /*---------------------------------------------------------------------------- -| The pattern for a default generated double-precision NaN. -*----------------------------------------------------------------------------*/ -#if defined(TARGET_SPARC) -#define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF )) -#elif defined(TARGET_POWERPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) -#define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 )) -#elif defined(TARGET_HPPA) -#define float64_default_nan make_float64(LIT64( 0x7FF4000000000000 )) -#elif SNAN_BIT_IS_ONE -#define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF )) -#else -#define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 )) -#endif - -/*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is a quiet | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float64_is_nan( float64 a_ ) +int float64_is_quiet_nan( float64 a_ ) { - bits64 a = float64_val(a_); + uint64_t a = float64_val(a_); #if SNAN_BIT_IS_ONE return ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) && ( a & LIT64( 0x0007FFFFFFFFFFFF ) ); #else - return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); + return ( LIT64( 0xFFF0000000000000 ) <= (uint64_t) ( a<<1 ) ); #endif } @@ -223,9 +411,9 @@ int float64_is_nan( float64 a_ ) int float64_is_signaling_nan( float64 a_ ) { - bits64 a = float64_val(a_); + uint64_t a = float64_val(a_); #if SNAN_BIT_IS_ONE - return ( LIT64( 0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); + return ( LIT64( 0xFFF0000000000000 ) <= (uint64_t) ( a<<1 ) ); #else return ( ( ( a>>51 ) & 0xFFF ) == 0xFFE ) @@ -234,6 +422,29 @@ int float64_is_signaling_nan( float64 a_ ) } /*---------------------------------------------------------------------------- +| Returns a quiet NaN if the double-precision floating point value `a' is a +| signaling NaN; otherwise returns `a'. +*----------------------------------------------------------------------------*/ + +float64 float64_maybe_silence_nan( float64 a_ ) +{ + if (float64_is_signaling_nan(a_)) { +#if SNAN_BIT_IS_ONE +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) + return float64_default_nan; +# else +# error Rules for silencing a signaling NaN are target-specific +# endif +#else + uint64_t a = float64_val(a_); + a |= LIT64( 0x0008000000000000 ); + return make_float64(a); +#endif + } + return a_; +} + +/*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point NaN | `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid | exception is raised. @@ -255,13 +466,17 @@ static commonNaNT float64ToCommonNaN( float64 a STATUS_PARAM) | precision floating-point format. *----------------------------------------------------------------------------*/ -static float64 commonNaNToFloat64( commonNaNT a ) +static float64 commonNaNToFloat64( commonNaNT a STATUS_PARAM) { - bits64 mantissa = a.high>>12; + uint64_t mantissa = a.high>>12; + + if ( STATUS(default_nan_mode) ) { + return float64_default_nan; + } if ( mantissa ) return make_float64( - ( ( (bits64) a.sign )<<63 ) + ( ( (uint64_t) a.sign )<<63 ) | LIT64( 0x7FF0000000000000 ) | ( a.high>>12 )); else @@ -276,105 +491,108 @@ static float64 commonNaNToFloat64( commonNaNT a ) 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; + flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN; + flag aIsLargerSignificand; + uint64_t av, bv; - aIsNaN = float64_is_nan( a ); + aIsQuietNaN = float64_is_quiet_nan( a ); aIsSignalingNaN = float64_is_signaling_nan( a ); - bIsNaN = float64_is_nan( b ); + bIsQuietNaN = float64_is_quiet_nan( b ); bIsSignalingNaN = float64_is_signaling_nan( b ); av = float64_val(a); bv = float64_val(b); -#if SNAN_BIT_IS_ONE - av &= ~LIT64( 0x0008000000000000 ); - bv &= ~LIT64( 0x0008000000000000 ); -#else - av |= LIT64( 0x0008000000000000 ); - bv |= LIT64( 0x0008000000000000 ); -#endif + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); - if ( aIsSignalingNaN ) { - if ( bIsSignalingNaN ) goto returnLargerSignificand; - res = bIsNaN ? bv : av; - } - else if ( aIsNaN ) { - if ( bIsSignalingNaN || ! bIsNaN ) - res = av; - else { - returnLargerSignificand: - 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; - } + + if ( STATUS(default_nan_mode) ) + return float64_default_nan; + + if ((uint64_t)(av<<1) < (uint64_t)(bv<<1)) { + aIsLargerSignificand = 0; + } else if ((uint64_t)(bv<<1) < (uint64_t)(av<<1)) { + aIsLargerSignificand = 1; + } else { + aIsLargerSignificand = (av < bv) ? 1 : 0; } - else { - res = bv; + + if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN, + aIsLargerSignificand)) { + return float64_maybe_silence_nan(b); + } else { + return float64_maybe_silence_nan(a); } - return make_float64(res); } #ifdef FLOATX80 /*---------------------------------------------------------------------------- -| The pattern for a default generated extended double-precision NaN. The -| `high' and `low' values hold the most- and least-significant bits, -| respectively. -*----------------------------------------------------------------------------*/ -#if SNAN_BIT_IS_ONE -#define floatx80_default_nan_high 0x7FFF -#define floatx80_default_nan_low LIT64( 0xBFFFFFFFFFFFFFFF ) -#else -#define floatx80_default_nan_high 0xFFFF -#define floatx80_default_nan_low LIT64( 0xC000000000000000 ) -#endif - -/*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is a -| quiet NaN; otherwise returns 0. +| quiet NaN; otherwise returns 0. This slightly differs from the same +| function for other types as floatx80 has an explicit bit. *----------------------------------------------------------------------------*/ -int floatx80_is_nan( floatx80 a ) +int floatx80_is_quiet_nan( floatx80 a ) { #if SNAN_BIT_IS_ONE - bits64 aLow; + uint64_t aLow; aLow = a.low & ~ LIT64( 0x4000000000000000 ); return ( ( a.high & 0x7FFF ) == 0x7FFF ) - && (bits64) ( aLow<<1 ) + && (uint64_t) ( aLow<<1 ) && ( a.low == aLow ); #else - return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); + return ( ( a.high & 0x7FFF ) == 0x7FFF ) + && (LIT64( 0x8000000000000000 ) <= ((uint64_t) ( a.low<<1 ))); #endif } /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is a -| signaling NaN; otherwise returns 0. +| signaling NaN; otherwise returns 0. This slightly differs from the same +| function for other types as floatx80 has an explicit bit. *----------------------------------------------------------------------------*/ int floatx80_is_signaling_nan( floatx80 a ) { #if SNAN_BIT_IS_ONE - return ( ( a.high & 0x7FFF ) == 0x7FFF ) && (bits64) ( a.low<<1 ); + return ( ( a.high & 0x7FFF ) == 0x7FFF ) + && (LIT64( 0x8000000000000000 ) <= ((uint64_t) ( a.low<<1 ))); #else - bits64 aLow; + uint64_t aLow; aLow = a.low & ~ LIT64( 0x4000000000000000 ); return ( ( a.high & 0x7FFF ) == 0x7FFF ) - && (bits64) ( aLow<<1 ) + && (uint64_t) ( aLow<<1 ) && ( a.low == aLow ); #endif } /*---------------------------------------------------------------------------- +| Returns a quiet NaN if the extended double-precision floating point value +| `a' is a signaling NaN; otherwise returns `a'. +*----------------------------------------------------------------------------*/ + +floatx80 floatx80_maybe_silence_nan( floatx80 a ) +{ + if (floatx80_is_signaling_nan(a)) { +#if SNAN_BIT_IS_ONE +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) + a.low = floatx80_default_nan_low; + a.high = floatx80_default_nan_high; +# else +# error Rules for silencing a signaling NaN are target-specific +# endif +#else + a.low |= LIT64( 0xC000000000000000 ); + return a; +#endif + } + return a; +} + +/*---------------------------------------------------------------------------- | Returns the result of converting the extended double-precision floating- | point NaN `a' to the canonical NaN format. If `a' is a signaling NaN, the | invalid exception is raised. @@ -385,9 +603,15 @@ static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM) commonNaNT z; if ( floatx80_is_signaling_nan( a ) ) float_raise( float_flag_invalid STATUS_VAR); - z.sign = a.high>>15; - z.low = 0; - z.high = a.low; + if ( a.low >> 63 ) { + z.sign = a.high >> 15; + z.low = 0; + z.high = a.low << 1; + } else { + z.sign = floatx80_default_nan_high >> 15; + z.low = 0; + z.high = floatx80_default_nan_low << 1; + } return z; } @@ -396,15 +620,24 @@ static commonNaNT floatx80ToCommonNaN( floatx80 a STATUS_PARAM) | double-precision floating-point format. *----------------------------------------------------------------------------*/ -static floatx80 commonNaNToFloatx80( commonNaNT a ) +static floatx80 commonNaNToFloatx80( commonNaNT a STATUS_PARAM) { floatx80 z; - if (a.high) - z.low = a.high; - else + if ( STATUS(default_nan_mode) ) { z.low = floatx80_default_nan_low; - z.high = ( ( (bits16) a.sign )<<15 ) | 0x7FFF; + z.high = floatx80_default_nan_high; + return z; + } + + if (a.high >> 1) { + z.low = LIT64( 0x8000000000000000 ) | a.high >> 1; + z.high = ( ( (uint16_t) a.sign )<<15 ) | 0x7FFF; + } else { + z.low = floatx80_default_nan_low; + z.high = floatx80_default_nan_high; + } + return z; } @@ -416,7 +649,15 @@ static floatx80 commonNaNToFloatx80( commonNaNT a ) static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) { - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN; + flag aIsLargerSignificand; + + aIsQuietNaN = floatx80_is_quiet_nan( a ); + aIsSignalingNaN = floatx80_is_signaling_nan( a ); + bIsQuietNaN = floatx80_is_quiet_nan( b ); + bIsSignalingNaN = floatx80_is_signaling_nan( b ); + + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ( STATUS(default_nan_mode) ) { a.low = floatx80_default_nan_low; @@ -424,31 +665,19 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) return a; } - aIsNaN = floatx80_is_nan( a ); - aIsSignalingNaN = floatx80_is_signaling_nan( a ); - bIsNaN = floatx80_is_nan( b ); - bIsSignalingNaN = floatx80_is_signaling_nan( b ); -#if SNAN_BIT_IS_ONE - a.low &= ~LIT64( 0xC000000000000000 ); - b.low &= ~LIT64( 0xC000000000000000 ); -#else - a.low |= LIT64( 0xC000000000000000 ); - b.low |= LIT64( 0xC000000000000000 ); -#endif - if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); - if ( aIsSignalingNaN ) { - if ( bIsSignalingNaN ) goto returnLargerSignificand; - return bIsNaN ? b : a; + if (a.low < b.low) { + aIsLargerSignificand = 0; + } else if (b.low < a.low) { + aIsLargerSignificand = 1; + } else { + aIsLargerSignificand = (a.high < b.high) ? 1 : 0; } - else if ( aIsNaN ) { - if ( bIsSignalingNaN || ! bIsNaN ) return a; - returnLargerSignificand: - if ( a.low < b.low ) return b; - if ( b.low < a.low ) return a; - return ( a.high < b.high ) ? a : b; - } - else { - return b; + + if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN, + aIsLargerSignificand)) { + return floatx80_maybe_silence_nan(b); + } else { + return floatx80_maybe_silence_nan(a); } } @@ -457,23 +686,11 @@ static floatx80 propagateFloatx80NaN( floatx80 a, floatx80 b STATUS_PARAM) #ifdef FLOAT128 /*---------------------------------------------------------------------------- -| The pattern for a default generated quadruple-precision NaN. The `high' and -| `low' values hold the most- and least-significant bits, respectively. -*----------------------------------------------------------------------------*/ -#if SNAN_BIT_IS_ONE -#define float128_default_nan_high LIT64( 0x7FFF7FFFFFFFFFFF ) -#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) -#else -#define float128_default_nan_high LIT64( 0xFFFF800000000000 ) -#define float128_default_nan_low LIT64( 0x0000000000000000 ) -#endif - -/*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is a quiet | NaN; otherwise returns 0. *----------------------------------------------------------------------------*/ -int float128_is_nan( float128 a ) +int float128_is_quiet_nan( float128 a ) { #if SNAN_BIT_IS_ONE return @@ -481,7 +698,7 @@ int float128_is_nan( float128 a ) && ( a.low || ( a.high & LIT64( 0x00007FFFFFFFFFFF ) ) ); #else return - ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) + ( LIT64( 0xFFFE000000000000 ) <= (uint64_t) ( a.high<<1 ) ) && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); #endif } @@ -495,7 +712,7 @@ int float128_is_signaling_nan( float128 a ) { #if SNAN_BIT_IS_ONE return - ( LIT64( 0xFFFE000000000000 ) <= (bits64) ( a.high<<1 ) ) + ( LIT64( 0xFFFE000000000000 ) <= (uint64_t) ( a.high<<1 ) ) && ( a.low || ( a.high & LIT64( 0x0000FFFFFFFFFFFF ) ) ); #else return @@ -505,6 +722,29 @@ int float128_is_signaling_nan( float128 a ) } /*---------------------------------------------------------------------------- +| Returns a quiet NaN if the quadruple-precision floating point value `a' is +| a signaling NaN; otherwise returns `a'. +*----------------------------------------------------------------------------*/ + +float128 float128_maybe_silence_nan( float128 a ) +{ + if (float128_is_signaling_nan(a)) { +#if SNAN_BIT_IS_ONE +# if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) + a.low = float128_default_nan_low; + a.high = float128_default_nan_high; +# else +# error Rules for silencing a signaling NaN are target-specific +# endif +#else + a.high |= LIT64( 0x0000800000000000 ); + return a; +#endif + } + return a; +} + +/*---------------------------------------------------------------------------- | Returns the result of converting the quadruple-precision floating-point NaN | `a' to the canonical NaN format. If `a' is a signaling NaN, the invalid | exception is raised. @@ -525,12 +765,18 @@ static commonNaNT float128ToCommonNaN( float128 a STATUS_PARAM) | precision floating-point format. *----------------------------------------------------------------------------*/ -static float128 commonNaNToFloat128( commonNaNT a ) +static float128 commonNaNToFloat128( commonNaNT a STATUS_PARAM) { float128 z; + if ( STATUS(default_nan_mode) ) { + z.low = float128_default_nan_low; + z.high = float128_default_nan_high; + return z; + } + shift128Right( a.high, a.low, 16, &z.high, &z.low ); - z.high |= ( ( (bits64) a.sign )<<63 ) | LIT64( 0x7FFF000000000000 ); + z.high |= ( ( (uint64_t) a.sign )<<63 ) | LIT64( 0x7FFF000000000000 ); return z; } @@ -542,7 +788,15 @@ static float128 commonNaNToFloat128( commonNaNT a ) static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) { - flag aIsNaN, aIsSignalingNaN, bIsNaN, bIsSignalingNaN; + flag aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN; + flag aIsLargerSignificand; + + aIsQuietNaN = float128_is_quiet_nan( a ); + aIsSignalingNaN = float128_is_signaling_nan( a ); + bIsQuietNaN = float128_is_quiet_nan( b ); + bIsSignalingNaN = float128_is_signaling_nan( b ); + + if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); if ( STATUS(default_nan_mode) ) { a.low = float128_default_nan_low; @@ -550,31 +804,19 @@ static float128 propagateFloat128NaN( float128 a, float128 b STATUS_PARAM) return a; } - aIsNaN = float128_is_nan( a ); - aIsSignalingNaN = float128_is_signaling_nan( a ); - bIsNaN = float128_is_nan( b ); - bIsSignalingNaN = float128_is_signaling_nan( b ); -#if SNAN_BIT_IS_ONE - a.high &= ~LIT64( 0x0000800000000000 ); - b.high &= ~LIT64( 0x0000800000000000 ); -#else - a.high |= LIT64( 0x0000800000000000 ); - b.high |= LIT64( 0x0000800000000000 ); -#endif - if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR); - if ( aIsSignalingNaN ) { - if ( bIsSignalingNaN ) goto returnLargerSignificand; - return bIsNaN ? b : a; - } - else if ( aIsNaN ) { - 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; - return ( a.high < b.high ) ? a : b; + if (lt128(a.high<<1, a.low, b.high<<1, b.low)) { + aIsLargerSignificand = 0; + } else if (lt128(b.high<<1, b.low, a.high<<1, a.low)) { + aIsLargerSignificand = 1; + } else { + aIsLargerSignificand = (a.high < b.high) ? 1 : 0; } - else { - return b; + + if (pickNaN(aIsQuietNaN, aIsSignalingNaN, bIsQuietNaN, bIsSignalingNaN, + aIsLargerSignificand)) { + return float128_maybe_silence_nan(b); + } else { + return float128_maybe_silence_nan(a); } } diff --git a/fpu/softfloat.c b/fpu/softfloat.c index 0b82797..baba1dc 100644 --- a/fpu/softfloat.c +++ b/fpu/softfloat.c @@ -1,3 +1,8 @@ +/* + * QEMU float support + * + * Derived from SoftFloat. + */ /*============================================================================ @@ -30,8 +35,6 @@ 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" /*---------------------------------------------------------------------------- @@ -69,6 +72,33 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM) #endif /*---------------------------------------------------------------------------- +| Returns the fraction bits of the half-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE uint32_t extractFloat16Frac(float16 a) +{ + return float16_val(a) & 0x3ff; +} + +/*---------------------------------------------------------------------------- +| Returns the exponent bits of the half-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE int16 extractFloat16Exp(float16 a) +{ + return (float16_val(a) >> 10) & 0x1f; +} + +/*---------------------------------------------------------------------------- +| Returns the sign bit of the single-precision floating-point value `a'. +*----------------------------------------------------------------------------*/ + +INLINE flag extractFloat16Sign(float16 a) +{ + return float16_val(a)>>15; +} + +/*---------------------------------------------------------------------------- | Takes a 64-bit fixed-point value `absZ' with binary point between bits 6 | and 7, and returns the properly rounded 32-bit integer corresponding to the | input. If `zSign' is 1, the input is negated before being converted to an @@ -79,7 +109,7 @@ void set_floatx80_rounding_precision(int val STATUS_PARAM) | positive or negative integer is returned. *----------------------------------------------------------------------------*/ -static int32 roundAndPackInt32( flag zSign, bits64 absZ STATUS_PARAM) +static int32 roundAndPackInt32( flag zSign, uint64_t absZ STATUS_PARAM) { int8 roundingMode; flag roundNearestEven; @@ -110,7 +140,7 @@ static int32 roundAndPackInt32( flag zSign, bits64 absZ STATUS_PARAM) if ( zSign ) z = - z; if ( ( absZ>>32 ) || ( z && ( ( z < 0 ) ^ zSign ) ) ) { float_raise( float_flag_invalid STATUS_VAR); - return zSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + return zSign ? (int32_t) 0x80000000 : 0x7FFFFFFF; } if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact; return z; @@ -129,7 +159,7 @@ static int32 roundAndPackInt32( flag zSign, bits64 absZ STATUS_PARAM) | returned. *----------------------------------------------------------------------------*/ -static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PARAM) +static int64 roundAndPackInt64( flag zSign, uint64_t absZ0, uint64_t absZ1 STATUS_PARAM) { int8 roundingMode; flag roundNearestEven, increment; @@ -137,7 +167,7 @@ static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PA roundingMode = STATUS(float_rounding_mode); roundNearestEven = ( roundingMode == float_round_nearest_even ); - increment = ( (sbits64) absZ1 < 0 ); + increment = ( (int64_t) absZ1 < 0 ); if ( ! roundNearestEven ) { if ( roundingMode == float_round_to_zero ) { increment = 0; @@ -154,7 +184,7 @@ static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PA if ( increment ) { ++absZ0; if ( absZ0 == 0 ) goto overflow; - absZ0 &= ~ ( ( (bits64) ( absZ1<<1 ) == 0 ) & roundNearestEven ); + absZ0 &= ~ ( ( (uint64_t) ( absZ1<<1 ) == 0 ) & roundNearestEven ); } z = absZ0; if ( zSign ) z = - z; @@ -162,7 +192,7 @@ static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PA overflow: float_raise( float_flag_invalid STATUS_VAR); return - zSign ? (sbits64) LIT64( 0x8000000000000000 ) + zSign ? (int64_t) LIT64( 0x8000000000000000 ) : LIT64( 0x7FFFFFFFFFFFFFFF ); } if ( absZ1 ) STATUS(float_exception_flags) |= float_flag_inexact; @@ -174,7 +204,7 @@ static int64 roundAndPackInt64( flag zSign, bits64 absZ0, bits64 absZ1 STATUS_PA | Returns the fraction bits of the single-precision floating-point value `a'. *----------------------------------------------------------------------------*/ -INLINE bits32 extractFloat32Frac( float32 a ) +INLINE uint32_t extractFloat32Frac( float32 a ) { return float32_val(a) & 0x007FFFFF; @@ -204,6 +234,21 @@ INLINE flag extractFloat32Sign( float32 a ) } /*---------------------------------------------------------------------------- +| If `a' is denormal and we are in flush-to-zero mode then set the +| input-denormal exception and return zero. Otherwise just return the value. +*----------------------------------------------------------------------------*/ +static float32 float32_squash_input_denormal(float32 a STATUS_PARAM) +{ + if (STATUS(flush_inputs_to_zero)) { + if (extractFloat32Exp(a) == 0 && extractFloat32Frac(a) != 0) { + float_raise(float_flag_input_denormal STATUS_VAR); + return make_float32(float32_val(a) & 0x80000000); + } + } + return a; +} + +/*---------------------------------------------------------------------------- | Normalizes the subnormal single-precision floating-point value represented | by the denormalized significand `aSig'. The normalized exponent and | significand are stored at the locations pointed to by `zExpPtr' and @@ -211,7 +256,7 @@ INLINE flag extractFloat32Sign( float32 a ) *----------------------------------------------------------------------------*/ static void - normalizeFloat32Subnormal( bits32 aSig, int16 *zExpPtr, bits32 *zSigPtr ) + normalizeFloat32Subnormal( uint32_t aSig, int16 *zExpPtr, uint32_t *zSigPtr ) { int8 shiftCount; @@ -232,11 +277,11 @@ static void | significand. *----------------------------------------------------------------------------*/ -INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig ) +INLINE float32 packFloat32( flag zSign, int16 zExp, uint32_t zSig ) { return make_float32( - ( ( (bits32) zSign )<<31 ) + ( ( (bits32) zExp )<<23 ) + zSig); + ( ( (uint32_t) zSign )<<31 ) + ( ( (uint32_t) zExp )<<23 ) + zSig); } @@ -262,7 +307,7 @@ INLINE float32 packFloat32( flag zSign, int16 zExp, bits32 zSig ) | Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_PARAM) +static float32 roundAndPackFloat32( flag zSign, int16 zExp, uint32_t zSig STATUS_PARAM) { int8 roundingMode; flag roundNearestEven; @@ -287,10 +332,10 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P } } roundBits = zSig & 0x7F; - if ( 0xFD <= (bits16) zExp ) { + if ( 0xFD <= (uint16_t) zExp ) { if ( ( 0xFD < zExp ) || ( ( zExp == 0xFD ) - && ( (sbits32) ( zSig + roundIncrement ) < 0 ) ) + && ( (int32_t) ( zSig + roundIncrement ) < 0 ) ) ) { float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); return packFloat32( zSign, 0xFF, - ( roundIncrement == 0 )); @@ -325,7 +370,7 @@ static float32 roundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_P *----------------------------------------------------------------------------*/ static float32 - normalizeRoundAndPackFloat32( flag zSign, int16 zExp, bits32 zSig STATUS_PARAM) + normalizeRoundAndPackFloat32( flag zSign, int16 zExp, uint32_t zSig STATUS_PARAM) { int8 shiftCount; @@ -338,7 +383,7 @@ static float32 | Returns the fraction bits of the double-precision floating-point value `a'. *----------------------------------------------------------------------------*/ -INLINE bits64 extractFloat64Frac( float64 a ) +INLINE uint64_t extractFloat64Frac( float64 a ) { return float64_val(a) & LIT64( 0x000FFFFFFFFFFFFF ); @@ -368,6 +413,21 @@ INLINE flag extractFloat64Sign( float64 a ) } /*---------------------------------------------------------------------------- +| If `a' is denormal and we are in flush-to-zero mode then set the +| input-denormal exception and return zero. Otherwise just return the value. +*----------------------------------------------------------------------------*/ +static float64 float64_squash_input_denormal(float64 a STATUS_PARAM) +{ + if (STATUS(flush_inputs_to_zero)) { + if (extractFloat64Exp(a) == 0 && extractFloat64Frac(a) != 0) { + float_raise(float_flag_input_denormal STATUS_VAR); + return make_float64(float64_val(a) & (1ULL << 63)); + } + } + return a; +} + +/*---------------------------------------------------------------------------- | Normalizes the subnormal double-precision floating-point value represented | by the denormalized significand `aSig'. The normalized exponent and | significand are stored at the locations pointed to by `zExpPtr' and @@ -375,7 +435,7 @@ INLINE flag extractFloat64Sign( float64 a ) *----------------------------------------------------------------------------*/ static void - normalizeFloat64Subnormal( bits64 aSig, int16 *zExpPtr, bits64 *zSigPtr ) + normalizeFloat64Subnormal( uint64_t aSig, int16 *zExpPtr, uint64_t *zSigPtr ) { int8 shiftCount; @@ -396,11 +456,11 @@ static void | significand. *----------------------------------------------------------------------------*/ -INLINE float64 packFloat64( flag zSign, int16 zExp, bits64 zSig ) +INLINE float64 packFloat64( flag zSign, int16 zExp, uint64_t zSig ) { return make_float64( - ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<52 ) + zSig); + ( ( (uint64_t) zSign )<<63 ) + ( ( (uint64_t) zExp )<<52 ) + zSig); } @@ -426,7 +486,7 @@ INLINE float64 packFloat64( flag zSign, int16 zExp, bits64 zSig ) | Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_PARAM) +static float64 roundAndPackFloat64( flag zSign, int16 zExp, uint64_t zSig STATUS_PARAM) { int8 roundingMode; flag roundNearestEven; @@ -451,10 +511,10 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P } } roundBits = zSig & 0x3FF; - if ( 0x7FD <= (bits16) zExp ) { + if ( 0x7FD <= (uint16_t) zExp ) { if ( ( 0x7FD < zExp ) || ( ( zExp == 0x7FD ) - && ( (sbits64) ( zSig + roundIncrement ) < 0 ) ) + && ( (int64_t) ( zSig + roundIncrement ) < 0 ) ) ) { float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); return packFloat64( zSign, 0x7FF, - ( roundIncrement == 0 )); @@ -489,7 +549,7 @@ static float64 roundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_P *----------------------------------------------------------------------------*/ static float64 - normalizeRoundAndPackFloat64( flag zSign, int16 zExp, bits64 zSig STATUS_PARAM) + normalizeRoundAndPackFloat64( flag zSign, int16 zExp, uint64_t zSig STATUS_PARAM) { int8 shiftCount; @@ -505,7 +565,7 @@ static float64 | value `a'. *----------------------------------------------------------------------------*/ -INLINE bits64 extractFloatx80Frac( floatx80 a ) +INLINE uint64_t extractFloatx80Frac( floatx80 a ) { return a.low; @@ -544,7 +604,7 @@ INLINE flag extractFloatx80Sign( floatx80 a ) *----------------------------------------------------------------------------*/ static void - normalizeFloatx80Subnormal( bits64 aSig, int32 *zExpPtr, bits64 *zSigPtr ) + normalizeFloatx80Subnormal( uint64_t aSig, int32 *zExpPtr, uint64_t *zSigPtr ) { int8 shiftCount; @@ -559,12 +619,12 @@ static void | extended double-precision floating-point value, returning the result. *----------------------------------------------------------------------------*/ -INLINE floatx80 packFloatx80( flag zSign, int32 zExp, bits64 zSig ) +INLINE floatx80 packFloatx80( flag zSign, int32 zExp, uint64_t zSig ) { floatx80 z; z.low = zSig; - z.high = ( ( (bits16) zSign )<<15 ) + zExp; + z.high = ( ( (uint16_t) zSign )<<15 ) + zExp; return z; } @@ -595,7 +655,7 @@ INLINE floatx80 packFloatx80( flag zSign, int32 zExp, bits64 zSig ) static floatx80 roundAndPackFloatx80( - int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 + int8 roundingPrecision, flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1 STATUS_PARAM) { int8 roundingMode; @@ -632,7 +692,7 @@ static floatx80 } } roundBits = zSig0 & roundMask; - if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) { + if ( 0x7FFD <= (uint32_t) ( zExp - 1 ) ) { if ( ( 0x7FFE < zExp ) || ( ( zExp == 0x7FFE ) && ( zSig0 + roundIncrement < zSig0 ) ) ) { @@ -650,7 +710,7 @@ static floatx80 if ( isTiny && roundBits ) float_raise( float_flag_underflow STATUS_VAR); if ( roundBits ) STATUS(float_exception_flags) |= float_flag_inexact; zSig0 += roundIncrement; - if ( (sbits64) zSig0 < 0 ) zExp = 1; + if ( (int64_t) zSig0 < 0 ) zExp = 1; roundIncrement = roundMask + 1; if ( roundNearestEven && ( roundBits<<1 == roundIncrement ) ) { roundMask |= roundIncrement; @@ -673,7 +733,7 @@ static floatx80 if ( zSig0 == 0 ) zExp = 0; return packFloatx80( zSign, zExp, zSig0 ); precision80: - increment = ( (sbits64) zSig1 < 0 ); + increment = ( (int64_t) zSig1 < 0 ); if ( ! roundNearestEven ) { if ( roundingMode == float_round_to_zero ) { increment = 0; @@ -687,7 +747,7 @@ static floatx80 } } } - if ( 0x7FFD <= (bits32) ( zExp - 1 ) ) { + if ( 0x7FFD <= (uint32_t) ( zExp - 1 ) ) { if ( ( 0x7FFE < zExp ) || ( ( zExp == 0x7FFE ) && ( zSig0 == LIT64( 0xFFFFFFFFFFFFFFFF ) ) @@ -716,7 +776,7 @@ static floatx80 if ( isTiny && zSig1 ) float_raise( float_flag_underflow STATUS_VAR); if ( zSig1 ) STATUS(float_exception_flags) |= float_flag_inexact; if ( roundNearestEven ) { - increment = ( (sbits64) zSig1 < 0 ); + increment = ( (int64_t) zSig1 < 0 ); } else { if ( zSign ) { @@ -729,8 +789,8 @@ static floatx80 if ( increment ) { ++zSig0; zSig0 &= - ~ ( ( (bits64) ( zSig1<<1 ) == 0 ) & roundNearestEven ); - if ( (sbits64) zSig0 < 0 ) zExp = 1; + ~ ( ( (uint64_t) ( zSig1<<1 ) == 0 ) & roundNearestEven ); + if ( (int64_t) zSig0 < 0 ) zExp = 1; } return packFloatx80( zSign, zExp, zSig0 ); } @@ -743,7 +803,7 @@ static floatx80 zSig0 = LIT64( 0x8000000000000000 ); } else { - zSig0 &= ~ ( ( (bits64) ( zSig1<<1 ) == 0 ) & roundNearestEven ); + zSig0 &= ~ ( ( (uint64_t) ( zSig1<<1 ) == 0 ) & roundNearestEven ); } } else { @@ -764,7 +824,7 @@ static floatx80 static floatx80 normalizeRoundAndPackFloatx80( - int8 roundingPrecision, flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 + int8 roundingPrecision, flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1 STATUS_PARAM) { int8 shiftCount; @@ -791,7 +851,7 @@ static floatx80 | floating-point value `a'. *----------------------------------------------------------------------------*/ -INLINE bits64 extractFloat128Frac1( float128 a ) +INLINE uint64_t extractFloat128Frac1( float128 a ) { return a.low; @@ -803,7 +863,7 @@ INLINE bits64 extractFloat128Frac1( float128 a ) | floating-point value `a'. *----------------------------------------------------------------------------*/ -INLINE bits64 extractFloat128Frac0( float128 a ) +INLINE uint64_t extractFloat128Frac0( float128 a ) { return a.high & LIT64( 0x0000FFFFFFFFFFFF ); @@ -845,11 +905,11 @@ INLINE flag extractFloat128Sign( float128 a ) static void normalizeFloat128Subnormal( - bits64 aSig0, - bits64 aSig1, + uint64_t aSig0, + uint64_t aSig1, int32 *zExpPtr, - bits64 *zSig0Ptr, - bits64 *zSig1Ptr + uint64_t *zSig0Ptr, + uint64_t *zSig1Ptr ) { int8 shiftCount; @@ -888,12 +948,12 @@ static void *----------------------------------------------------------------------------*/ INLINE float128 - packFloat128( flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 ) + packFloat128( flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1 ) { float128 z; z.low = zSig1; - z.high = ( ( (bits64) zSign )<<63 ) + ( ( (bits64) zExp )<<48 ) + zSig0; + z.high = ( ( (uint64_t) zSign )<<63 ) + ( ( (uint64_t) zExp )<<48 ) + zSig0; return z; } @@ -921,14 +981,14 @@ INLINE float128 static float128 roundAndPackFloat128( - flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1, bits64 zSig2 STATUS_PARAM) + flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1, uint64_t zSig2 STATUS_PARAM) { int8 roundingMode; flag roundNearestEven, increment, isTiny; roundingMode = STATUS(float_rounding_mode); roundNearestEven = ( roundingMode == float_round_nearest_even ); - increment = ( (sbits64) zSig2 < 0 ); + increment = ( (int64_t) zSig2 < 0 ); if ( ! roundNearestEven ) { if ( roundingMode == float_round_to_zero ) { increment = 0; @@ -942,7 +1002,7 @@ static float128 } } } - if ( 0x7FFD <= (bits32) zExp ) { + if ( 0x7FFD <= (uint32_t) zExp ) { if ( ( 0x7FFD < zExp ) || ( ( zExp == 0x7FFD ) && eq128( @@ -986,7 +1046,7 @@ static float128 zExp = 0; if ( isTiny && zSig2 ) float_raise( float_flag_underflow STATUS_VAR); if ( roundNearestEven ) { - increment = ( (sbits64) zSig2 < 0 ); + increment = ( (int64_t) zSig2 < 0 ); } else { if ( zSign ) { @@ -1022,10 +1082,10 @@ static float128 static float128 normalizeRoundAndPackFloat128( - flag zSign, int32 zExp, bits64 zSig0, bits64 zSig1 STATUS_PARAM) + flag zSign, int32 zExp, uint64_t zSig0, uint64_t zSig1 STATUS_PARAM) { int8 shiftCount; - bits64 zSig2; + uint64_t zSig2; if ( zSig0 == 0 ) { zSig0 = zSig1; @@ -1059,7 +1119,7 @@ float32 int32_to_float32( int32 a STATUS_PARAM ) flag zSign; if ( a == 0 ) return float32_zero; - if ( a == (sbits32) 0x80000000 ) return packFloat32( 1, 0x9E, 0 ); + if ( a == (int32_t) 0x80000000 ) return packFloat32( 1, 0x9E, 0 ); zSign = ( a < 0 ); return normalizeRoundAndPackFloat32( zSign, 0x9C, zSign ? - a : a STATUS_VAR ); @@ -1076,7 +1136,7 @@ float64 int32_to_float64( int32 a STATUS_PARAM ) flag zSign; uint32 absA; int8 shiftCount; - bits64 zSig; + uint64_t zSig; if ( a == 0 ) return float64_zero; zSign = ( a < 0 ); @@ -1101,7 +1161,7 @@ floatx80 int32_to_floatx80( int32 a STATUS_PARAM ) flag zSign; uint32 absA; int8 shiftCount; - bits64 zSig; + uint64_t zSig; if ( a == 0 ) return packFloatx80( 0, 0, 0 ); zSign = ( a < 0 ); @@ -1127,7 +1187,7 @@ float128 int32_to_float128( int32 a STATUS_PARAM ) flag zSign; uint32 absA; int8 shiftCount; - bits64 zSig0; + uint64_t zSig0; if ( a == 0 ) return packFloat128( 0, 0, 0, 0 ); zSign = ( a < 0 ); @@ -1204,7 +1264,7 @@ float64 int64_to_float64( int64 a STATUS_PARAM ) flag zSign; if ( a == 0 ) return float64_zero; - if ( a == (sbits64) LIT64( 0x8000000000000000 ) ) { + if ( a == (int64_t) LIT64( 0x8000000000000000 ) ) { return packFloat64( 1, 0x43E, 0 ); } zSign = ( a < 0 ); @@ -1258,7 +1318,7 @@ float128 int64_to_float128( int64 a STATUS_PARAM ) uint64 absA; int8 shiftCount; int32 zExp; - bits64 zSig0, zSig1; + uint64_t zSig0, zSig1; if ( a == 0 ) return packFloat128( 0, 0, 0, 0 ); zSign = ( a < 0 ); @@ -1295,9 +1355,10 @@ int32 float32_to_int32( float32 a STATUS_PARAM ) { flag aSign; int16 aExp, shiftCount; - bits32 aSig; - bits64 aSig64; + uint32_t aSig; + uint64_t aSig64; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); @@ -1325,8 +1386,9 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM ) { flag aSign; int16 aExp, shiftCount; - bits32 aSig; + uint32_t aSig; int32 z; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -1337,7 +1399,7 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM ) float_raise( float_flag_invalid STATUS_VAR); if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) return 0x7FFFFFFF; } - return (sbits32) 0x80000000; + return (int32_t) 0x80000000; } else if ( aExp <= 0x7E ) { if ( aExp | aSig ) STATUS(float_exception_flags) |= float_flag_inexact; @@ -1345,7 +1407,7 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM ) } aSig = ( aSig | 0x00800000 )<<8; z = aSig>>( - shiftCount ); - if ( (bits32) ( aSig<<( shiftCount & 31 ) ) ) { + if ( (uint32_t) ( aSig<<( shiftCount & 31 ) ) ) { STATUS(float_exception_flags) |= float_flag_inexact; } if ( aSign ) z = - z; @@ -1355,6 +1417,55 @@ int32 float32_to_int32_round_to_zero( float32 a STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns the result of converting the single-precision floating-point value +| `a' to the 16-bit two's complement integer format. The conversion is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic, except that the conversion is always rounded toward zero. +| If `a' is a NaN, the largest positive integer is returned. Otherwise, if +| the conversion overflows, the largest integer with the same sign as `a' is +| returned. +*----------------------------------------------------------------------------*/ + +int16 float32_to_int16_round_to_zero( float32 a STATUS_PARAM ) +{ + flag aSign; + int16 aExp, shiftCount; + uint32_t aSig; + int32 z; + + aSig = extractFloat32Frac( a ); + aExp = extractFloat32Exp( a ); + aSign = extractFloat32Sign( a ); + shiftCount = aExp - 0x8E; + if ( 0 <= shiftCount ) { + if ( float32_val(a) != 0xC7000000 ) { + float_raise( float_flag_invalid STATUS_VAR); + if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) { + return 0x7FFF; + } + } + return (int32_t) 0xffff8000; + } + else if ( aExp <= 0x7E ) { + if ( aExp | aSig ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + return 0; + } + shiftCount -= 0x10; + aSig = ( aSig | 0x00800000 )<<8; + z = aSig>>( - shiftCount ); + if ( (uint32_t) ( aSig<<( shiftCount & 31 ) ) ) { + STATUS(float_exception_flags) |= float_flag_inexact; + } + if ( aSign ) { + z = - z; + } + return z; + +} + +/*---------------------------------------------------------------------------- +| Returns the result of converting the single-precision floating-point value | `a' to the 64-bit two's complement integer format. The conversion is | performed according to the IEC/IEEE Standard for Binary Floating-Point | Arithmetic---which means in particular that the conversion is rounded @@ -1367,8 +1478,9 @@ int64 float32_to_int64( float32 a STATUS_PARAM ) { flag aSign; int16 aExp, shiftCount; - bits32 aSig; - bits64 aSig64, aSigExtra; + uint32_t aSig; + uint64_t aSig64, aSigExtra; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -1379,7 +1491,7 @@ int64 float32_to_int64( float32 a STATUS_PARAM ) if ( ! aSign || ( ( aExp == 0xFF ) && aSig ) ) { return LIT64( 0x7FFFFFFFFFFFFFFF ); } - return (sbits64) LIT64( 0x8000000000000000 ); + return (int64_t) LIT64( 0x8000000000000000 ); } if ( aExp ) aSig |= 0x00800000; aSig64 = aSig; @@ -1403,9 +1515,10 @@ int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM ) { flag aSign; int16 aExp, shiftCount; - bits32 aSig; - bits64 aSig64; + uint32_t aSig; + uint64_t aSig64; int64 z; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -1418,7 +1531,7 @@ int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM ) return LIT64( 0x7FFFFFFFFFFFFFFF ); } } - return (sbits64) LIT64( 0x8000000000000000 ); + return (int64_t) LIT64( 0x8000000000000000 ); } else if ( aExp <= 0x7E ) { if ( aExp | aSig ) STATUS(float_exception_flags) |= float_flag_inexact; @@ -1427,7 +1540,7 @@ int64 float32_to_int64_round_to_zero( float32 a STATUS_PARAM ) aSig64 = aSig | 0x00800000; aSig64 <<= 40; z = aSig64>>( - shiftCount ); - if ( (bits64) ( aSig64<<( shiftCount & 63 ) ) ) { + if ( (uint64_t) ( aSig64<<( shiftCount & 63 ) ) ) { STATUS(float_exception_flags) |= float_flag_inexact; } if ( aSign ) z = - z; @@ -1446,13 +1559,14 @@ float64 float32_to_float64( float32 a STATUS_PARAM ) { flag aSign; int16 aExp; - bits32 aSig; + uint32_t aSig; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { - if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a STATUS_VAR )); + if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); return packFloat64( aSign, 0x7FF, 0 ); } if ( aExp == 0 ) { @@ -1460,7 +1574,7 @@ float64 float32_to_float64( float32 a STATUS_PARAM ) normalizeFloat32Subnormal( aSig, &aExp, &aSig ); --aExp; } - return packFloat64( aSign, aExp + 0x380, ( (bits64) aSig )<<29 ); + return packFloat64( aSign, aExp + 0x380, ( (uint64_t) aSig )<<29 ); } @@ -1477,13 +1591,14 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM ) { flag aSign; int16 aExp; - bits32 aSig; + uint32_t aSig; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { - if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a STATUS_VAR ) ); + if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( aExp == 0 ) { @@ -1491,7 +1606,7 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM ) normalizeFloat32Subnormal( aSig, &aExp, &aSig ); } aSig |= 0x00800000; - return packFloatx80( aSign, aExp + 0x3F80, ( (bits64) aSig )<<40 ); + return packFloatx80( aSign, aExp + 0x3F80, ( (uint64_t) aSig )<<40 ); } @@ -1510,13 +1625,14 @@ float128 float32_to_float128( float32 a STATUS_PARAM ) { flag aSign; int16 aExp; - bits32 aSig; + uint32_t aSig; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { - if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a STATUS_VAR ) ); + if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); return packFloat128( aSign, 0x7FFF, 0, 0 ); } if ( aExp == 0 ) { @@ -1524,7 +1640,7 @@ float128 float32_to_float128( float32 a STATUS_PARAM ) normalizeFloat32Subnormal( aSig, &aExp, &aSig ); --aExp; } - return packFloat128( aSign, aExp + 0x3F80, ( (bits64) aSig )<<25, 0 ); + return packFloat128( aSign, aExp + 0x3F80, ( (uint64_t) aSig )<<25, 0 ); } @@ -1541,9 +1657,10 @@ float32 float32_round_to_int( float32 a STATUS_PARAM) { flag aSign; int16 aExp; - bits32 lastBitMask, roundBitsMask; + uint32_t lastBitMask, roundBitsMask; int8 roundingMode; - bits32 z; + uint32_t z; + a = float32_squash_input_denormal(a STATUS_VAR); aExp = extractFloat32Exp( a ); if ( 0x96 <= aExp ) { @@ -1553,7 +1670,7 @@ float32 float32_round_to_int( float32 a STATUS_PARAM) return a; } if ( aExp <= 0x7E ) { - if ( (bits32) ( float32_val(a)<<1 ) == 0 ) return a; + if ( (uint32_t) ( float32_val(a)<<1 ) == 0 ) return a; STATUS(float_exception_flags) |= float_flag_inexact; aSign = extractFloat32Sign( a ); switch ( STATUS(float_rounding_mode) ) { @@ -1600,7 +1717,7 @@ float32 float32_round_to_int( float32 a STATUS_PARAM) static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) { int16 aExp, bExp, zExp; - bits32 aSig, bSig, zSig; + uint32_t aSig, bSig, zSig; int16 expDiff; aSig = extractFloat32Frac( a ); @@ -1654,7 +1771,7 @@ static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) aSig |= 0x20000000; zSig = ( aSig + bSig )<<1; --zExp; - if ( (sbits32) zSig < 0 ) { + if ( (int32_t) zSig < 0 ) { zSig = aSig + bSig; ++zExp; } @@ -1674,7 +1791,7 @@ static float32 addFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) static float32 subFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) { int16 aExp, bExp, zExp; - bits32 aSig, bSig, zSig; + uint32_t aSig, bSig, zSig; int16 expDiff; aSig = extractFloat32Frac( a ); @@ -1747,6 +1864,8 @@ static float32 subFloat32Sigs( float32 a, float32 b, flag zSign STATUS_PARAM) float32 float32_add( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); @@ -1768,6 +1887,8 @@ float32 float32_add( float32 a, float32 b STATUS_PARAM ) float32 float32_sub( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); aSign = extractFloat32Sign( a ); bSign = extractFloat32Sign( b ); @@ -1790,9 +1911,12 @@ float32 float32_mul( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign, zSign; int16 aExp, bExp, zExp; - bits32 aSig, bSig; - bits64 zSig64; - bits32 zSig; + uint32_t aSig, bSig; + uint64_t zSig64; + uint32_t zSig; + + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -1830,9 +1954,9 @@ float32 float32_mul( float32 a, float32 b STATUS_PARAM ) zExp = aExp + bExp - 0x7F; aSig = ( aSig | 0x00800000 )<<7; bSig = ( bSig | 0x00800000 )<<8; - shift64RightJamming( ( (bits64) aSig ) * bSig, 32, &zSig64 ); + shift64RightJamming( ( (uint64_t) aSig ) * bSig, 32, &zSig64 ); zSig = zSig64; - if ( 0 <= (sbits32) ( zSig<<1 ) ) { + if ( 0 <= (int32_t) ( zSig<<1 ) ) { zSig <<= 1; --zExp; } @@ -1850,7 +1974,9 @@ float32 float32_div( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign, zSign; int16 aExp, bExp, zExp; - bits32 aSig, bSig, zSig; + uint32_t aSig, bSig, zSig; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -1894,9 +2020,9 @@ float32 float32_div( float32 a, float32 b STATUS_PARAM ) aSig >>= 1; ++zExp; } - zSig = ( ( (bits64) aSig )<<32 ) / bSig; + zSig = ( ( (uint64_t) aSig )<<32 ) / bSig; if ( ( zSig & 0x3F ) == 0 ) { - zSig |= ( (bits64) bSig * zSig != ( (bits64) aSig )<<32 ); + zSig |= ( (uint64_t) bSig * zSig != ( (uint64_t) aSig )<<32 ); } return roundAndPackFloat32( zSign, zExp, zSig STATUS_VAR ); @@ -1912,11 +2038,13 @@ float32 float32_rem( float32 a, float32 b STATUS_PARAM ) { flag aSign, zSign; int16 aExp, bExp, expDiff; - bits32 aSig, bSig; - bits32 q; - bits64 aSig64, bSig64, q64; - bits32 alternateASig; - sbits32 sigMean; + uint32_t aSig, bSig; + uint32_t q; + uint64_t aSig64, bSig64, q64; + uint32_t alternateASig; + int32_t sigMean; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -1958,7 +2086,7 @@ float32 float32_rem( float32 a, float32 b STATUS_PARAM ) q = ( bSig <= aSig ); if ( q ) aSig -= bSig; if ( 0 < expDiff ) { - q = ( ( (bits64) aSig )<<32 ) / bSig; + q = ( ( (uint64_t) aSig )<<32 ) / bSig; q >>= 32 - expDiff; bSig >>= 2; aSig = ( ( aSig>>1 )<<( expDiff - 1 ) ) - bSig * q; @@ -1970,8 +2098,8 @@ float32 float32_rem( float32 a, float32 b STATUS_PARAM ) } else { if ( bSig <= aSig ) aSig -= bSig; - aSig64 = ( (bits64) aSig )<<40; - bSig64 = ( (bits64) bSig )<<40; + aSig64 = ( (uint64_t) aSig )<<40; + bSig64 = ( (uint64_t) bSig )<<40; expDiff -= 64; while ( 0 < expDiff ) { q64 = estimateDiv128To64( aSig64, 0, bSig64 ); @@ -1990,12 +2118,12 @@ float32 float32_rem( float32 a, float32 b STATUS_PARAM ) alternateASig = aSig; ++q; aSig -= bSig; - } while ( 0 <= (sbits32) aSig ); + } while ( 0 <= (int32_t) aSig ); sigMean = aSig + alternateASig; if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { aSig = alternateASig; } - zSign = ( (sbits32) aSig < 0 ); + zSign = ( (int32_t) aSig < 0 ); if ( zSign ) aSig = - aSig; return normalizeRoundAndPackFloat32( aSign ^ zSign, bExp, aSig STATUS_VAR ); @@ -2011,8 +2139,9 @@ float32 float32_sqrt( float32 a STATUS_PARAM ) { flag aSign; int16 aExp, zExp; - bits32 aSig, zSig; - bits64 rem, term; + uint32_t aSig, zSig; + uint64_t rem, term; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -2041,11 +2170,11 @@ float32 float32_sqrt( float32 a STATUS_PARAM ) goto roundAndPack; } aSig >>= aExp & 1; - term = ( (bits64) zSig ) * zSig; - rem = ( ( (bits64) aSig )<<32 ) - term; - while ( (sbits64) rem < 0 ) { + term = ( (uint64_t) zSig ) * zSig; + rem = ( ( (uint64_t) aSig )<<32 ) - term; + while ( (int64_t) rem < 0 ) { --zSig; - rem += ( ( (bits64) zSig )<<1 ) | 1; + rem += ( ( (uint64_t) zSig )<<1 ) | 1; } zSig |= ( rem != 0 ); } @@ -2075,30 +2204,31 @@ float32 float32_sqrt( float32 a STATUS_PARAM ) static const float64 float32_exp2_coefficients[15] = { - make_float64( 0x3ff0000000000000ll ), /* 1 */ - make_float64( 0x3fe0000000000000ll ), /* 2 */ - make_float64( 0x3fc5555555555555ll ), /* 3 */ - make_float64( 0x3fa5555555555555ll ), /* 4 */ - make_float64( 0x3f81111111111111ll ), /* 5 */ - make_float64( 0x3f56c16c16c16c17ll ), /* 6 */ - make_float64( 0x3f2a01a01a01a01all ), /* 7 */ - make_float64( 0x3efa01a01a01a01all ), /* 8 */ - make_float64( 0x3ec71de3a556c734ll ), /* 9 */ - make_float64( 0x3e927e4fb7789f5cll ), /* 10 */ - make_float64( 0x3e5ae64567f544e4ll ), /* 11 */ - make_float64( 0x3e21eed8eff8d898ll ), /* 12 */ - make_float64( 0x3de6124613a86d09ll ), /* 13 */ - make_float64( 0x3da93974a8c07c9dll ), /* 14 */ - make_float64( 0x3d6ae7f3e733b81fll ), /* 15 */ + const_float64( 0x3ff0000000000000ll ), /* 1 */ + const_float64( 0x3fe0000000000000ll ), /* 2 */ + const_float64( 0x3fc5555555555555ll ), /* 3 */ + const_float64( 0x3fa5555555555555ll ), /* 4 */ + const_float64( 0x3f81111111111111ll ), /* 5 */ + const_float64( 0x3f56c16c16c16c17ll ), /* 6 */ + const_float64( 0x3f2a01a01a01a01all ), /* 7 */ + const_float64( 0x3efa01a01a01a01all ), /* 8 */ + const_float64( 0x3ec71de3a556c734ll ), /* 9 */ + const_float64( 0x3e927e4fb7789f5cll ), /* 10 */ + const_float64( 0x3e5ae64567f544e4ll ), /* 11 */ + const_float64( 0x3e21eed8eff8d898ll ), /* 12 */ + const_float64( 0x3de6124613a86d09ll ), /* 13 */ + const_float64( 0x3da93974a8c07c9dll ), /* 14 */ + const_float64( 0x3d6ae7f3e733b81fll ), /* 15 */ }; float32 float32_exp2( float32 a STATUS_PARAM ) { flag aSign; int16 aExp; - bits32 aSig; + uint32_t aSig; float64 r, x, xn; int i; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); @@ -2143,8 +2273,9 @@ float32 float32_log2( float32 a STATUS_PARAM ) { flag aSign, zSign; int16 aExp; - bits32 aSig, zSig, i; + uint32_t aSig, zSig, i; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); @@ -2168,7 +2299,7 @@ float32 float32_log2( float32 a STATUS_PARAM ) zSig = aExp << 23; for (i = 1 << 22; i > 0; i >>= 1) { - aSig = ( (bits64)aSig * aSig ) >> 23; + aSig = ( (uint64_t)aSig * aSig ) >> 23; if ( aSig & 0x01000000 ) { aSig >>= 1; zSig |= i; @@ -2183,37 +2314,41 @@ float32 float32_log2( float32 a STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The comparison is performed +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float32_eq( float32 a, float32 b STATUS_PARAM ) { + uint32_t av, bv; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) ) { - if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid STATUS_VAR); - } + float_raise( float_flag_invalid STATUS_VAR); return 0; } - return ( float32_val(a) == float32_val(b) ) || - ( (bits32) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 ); - + av = float32_val(a); + bv = float32_val(b); + return ( av == bv ) || ( (uint32_t) ( ( av | bv )<<1 ) == 0 ); } /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is less than -| or equal to the corresponding value `b', and 0 otherwise. The comparison -| is performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| or equal to the corresponding value `b', and 0 otherwise. The invalid +| exception is raised if either operand is a NaN. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float32_le( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; - bits32 av, bv; + uint32_t av, bv; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2225,21 +2360,24 @@ int float32_le( float32 a, float32 b STATUS_PARAM ) bSign = extractFloat32Sign( b ); av = float32_val(a); bv = float32_val(b); - if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + if ( aSign != bSign ) return aSign || ( (uint32_t) ( ( av | bv )<<1 ) == 0 ); return ( av == bv ) || ( aSign ^ ( av < bv ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. The comparison is performed according +| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float32_lt( float32 a, float32 b STATUS_PARAM ) { flag aSign, bSign; - bits32 av, bv; + uint32_t av, bv; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2251,32 +2389,54 @@ int float32_lt( float32 a, float32 b STATUS_PARAM ) bSign = extractFloat32Sign( b ); av = float32_val(a); bv = float32_val(b); - if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 ); + if ( aSign != bSign ) return aSign && ( (uint32_t) ( ( av | bv )<<1 ) != 0 ); return ( av != bv ) && ( aSign ^ ( av < bv ) ); } /*---------------------------------------------------------------------------- -| Returns 1 if the single-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. Otherwise, the comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| Returns 1 if the single-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. The invalid exception is raised if either +| operand is a NaN. The comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float32_eq_signaling( float32 a, float32 b STATUS_PARAM ) +int float32_unordered( float32 a, float32 b STATUS_PARAM ) { - bits32 av, bv; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) ) { float_raise( float_flag_invalid STATUS_VAR); - return 0; + return 1; } - av = float32_val(a); - bv = float32_val(b); - return ( av == bv ) || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + return 0; +} +/*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point value `a' is equal to +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. The comparison is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_eq_quiet( float32 a, float32 b STATUS_PARAM ) +{ + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 0; + } + return ( float32_val(a) == float32_val(b) ) || + ( (uint32_t) ( ( float32_val(a) | float32_val(b) )<<1 ) == 0 ); } /*---------------------------------------------------------------------------- @@ -2289,7 +2449,9 @@ 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; + uint32_t av, bv; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2303,7 +2465,7 @@ int float32_le_quiet( float32 a, float32 b STATUS_PARAM ) bSign = extractFloat32Sign( b ); av = float32_val(a); bv = float32_val(b); - if ( aSign != bSign ) return aSign || ( (bits32) ( ( av | bv )<<1 ) == 0 ); + if ( aSign != bSign ) return aSign || ( (uint32_t) ( ( av | bv )<<1 ) == 0 ); return ( av == bv ) || ( aSign ^ ( av < bv ) ); } @@ -2318,7 +2480,9 @@ 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; + uint32_t av, bv; + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) @@ -2332,12 +2496,35 @@ int float32_lt_quiet( float32 a, float32 b STATUS_PARAM ) bSign = extractFloat32Sign( b ); av = float32_val(a); bv = float32_val(b); - if ( aSign != bSign ) return aSign && ( (bits32) ( ( av | bv )<<1 ) != 0 ); + if ( aSign != bSign ) return aSign && ( (uint32_t) ( ( av | bv )<<1 ) != 0 ); return ( av != bv ) && ( aSign ^ ( av < bv ) ); } /*---------------------------------------------------------------------------- +| Returns 1 if the single-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The +| comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float32_unordered_quiet( float32 a, float32 b STATUS_PARAM ) +{ + a = float32_squash_input_denormal(a STATUS_VAR); + b = float32_squash_input_denormal(b STATUS_VAR); + + if ( ( ( extractFloat32Exp( a ) == 0xFF ) && extractFloat32Frac( a ) ) + || ( ( extractFloat32Exp( b ) == 0xFF ) && extractFloat32Frac( b ) ) + ) { + if ( float32_is_signaling_nan( a ) || float32_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 1; + } + return 0; +} + +/*---------------------------------------------------------------------------- | Returns the result of converting the double-precision floating-point value | `a' to the 32-bit two's complement integer format. The conversion is | performed according to the IEC/IEEE Standard for Binary Floating-Point @@ -2351,7 +2538,8 @@ int32 float64_to_int32( float64 a STATUS_PARAM ) { flag aSign; int16 aExp, shiftCount; - bits64 aSig; + uint64_t aSig; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -2378,8 +2566,9 @@ int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM ) { flag aSign; int16 aExp, shiftCount; - bits64 aSig, savedASig; + uint64_t aSig, savedASig; int32 z; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -2401,7 +2590,7 @@ int32 float64_to_int32_round_to_zero( float64 a STATUS_PARAM ) if ( ( z < 0 ) ^ aSign ) { invalid: float_raise( float_flag_invalid STATUS_VAR); - return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + return aSign ? (int32_t) 0x80000000 : 0x7FFFFFFF; } if ( ( aSig<>= shiftCount; + z = aSig; + if ( aSign ) { + z = - z; + } + if ( ( (int16_t)z < 0 ) ^ aSign ) { + invalid: + float_raise( float_flag_invalid STATUS_VAR); + return aSign ? (int32_t) 0xffff8000 : 0x7FFF; + } + if ( ( aSig<>( - shiftCount ); - if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) { + if ( (uint64_t) ( aSig<<( shiftCount & 63 ) ) ) { STATUS(float_exception_flags) |= float_flag_inexact; } } @@ -2515,14 +2757,15 @@ float32 float64_to_float32( float64 a STATUS_PARAM ) { flag aSign; int16 aExp; - bits64 aSig; - bits32 zSig; + uint64_t aSig; + uint32_t zSig; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { - if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a STATUS_VAR ) ); + if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); return packFloat32( aSign, 0xFF, 0 ); } shift64RightJamming( aSig, 22, &aSig ); @@ -2546,29 +2789,28 @@ float32 float64_to_float32( float64 a STATUS_PARAM ) | than the desired result exponent whenever `zSig' is a complete, normalized | significand. *----------------------------------------------------------------------------*/ -static bits16 packFloat16(flag zSign, int16 zExp, bits16 zSig) +static float16 packFloat16(flag zSign, int16 zExp, uint16_t zSig) { - return (((bits32)zSign) << 15) + (((bits32)zExp) << 10) + zSig; + return make_float16( + (((uint32_t)zSign) << 15) + (((uint32_t)zExp) << 10) + zSig); } /* Half precision floats come in two formats: standard IEEE and "ARM" format. The latter gains extra exponent range by omitting the NaN/Inf encodings. */ - -float32 float16_to_float32( bits16 a, flag ieee STATUS_PARAM ) + +float32 float16_to_float32(float16 a, flag ieee STATUS_PARAM) { flag aSign; int16 aExp; - bits32 aSig; + uint32_t aSig; - aSign = a >> 15; - aExp = (a >> 10) & 0x1f; - aSig = a & 0x3ff; + aSign = extractFloat16Sign(a); + aExp = extractFloat16Exp(a); + aSig = extractFloat16Frac(a); if (aExp == 0x1f && ieee) { if (aSig) { - /* Make sure correct exceptions are raised. */ - float32ToCommonNaN(a STATUS_VAR); - aSig |= 0x200; + return commonNaNToFloat32(float16ToCommonNaN(a STATUS_VAR) STATUS_VAR); } return packFloat32(aSign, 0xff, aSig << 13); } @@ -2586,38 +2828,45 @@ float32 float16_to_float32( bits16 a, flag ieee STATUS_PARAM ) return packFloat32( aSign, aExp + 0x70, aSig << 13); } -bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM) +float16 float32_to_float16(float32 a, flag ieee STATUS_PARAM) { flag aSign; int16 aExp; - bits32 aSig; - bits32 mask; - bits32 increment; + uint32_t aSig; + uint32_t mask; + uint32_t increment; int8 roundingMode; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { if (aSig) { - /* Make sure correct exceptions are raised. */ - float32ToCommonNaN(a STATUS_VAR); - aSig |= 0x00400000; + /* Input is a NaN */ + float16 r = commonNaNToFloat16( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); + if (!ieee) { + return packFloat16(aSign, 0, 0); + } + return r; } - return packFloat16(aSign, 0x1f, aSig >> 13); + /* Infinity */ + if (!ieee) { + float_raise(float_flag_invalid STATUS_VAR); + return packFloat16(aSign, 0x1f, 0x3ff); + } + return packFloat16(aSign, 0x1f, 0); } - if (aExp == 0 && aSign == 0) { + if (aExp == 0 && aSig == 0) { return packFloat16(aSign, 0, 0); } /* Decimal point between bits 22 and 23. */ aSig |= 0x00800000; aExp -= 0x7f; if (aExp < -14) { - mask = 0x007fffff; - if (aExp < -24) { - aExp = -25; - } else { - mask >>= 24 + aExp; + mask = 0x00ffffff; + if (aExp >= -24) { + mask >>= 25 + aExp; } } else { mask = 0x00001fff; @@ -2659,7 +2908,7 @@ bits16 float32_to_float16( float32 a, flag ieee STATUS_PARAM) } } else { if (aExp > 16) { - float_raise( float_flag_overflow | float_flag_inexact STATUS_VAR); + float_raise(float_flag_invalid | float_flag_inexact STATUS_VAR); return packFloat16(aSign, 0x1f, 0x3ff); } } @@ -2686,13 +2935,14 @@ floatx80 float64_to_floatx80( float64 a STATUS_PARAM ) { flag aSign; int16 aExp; - bits64 aSig; + uint64_t aSig; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { - if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a STATUS_VAR ) ); + if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( aExp == 0 ) { @@ -2720,13 +2970,14 @@ float128 float64_to_float128( float64 a STATUS_PARAM ) { flag aSign; int16 aExp; - bits64 aSig, zSig0, zSig1; + uint64_t aSig, zSig0, zSig1; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { - if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a STATUS_VAR ) ); + if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); return packFloat128( aSign, 0x7FFF, 0, 0 ); } if ( aExp == 0 ) { @@ -2752,9 +3003,10 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) { flag aSign; int16 aExp; - bits64 lastBitMask, roundBitsMask; + uint64_t lastBitMask, roundBitsMask; int8 roundingMode; - bits64 z; + uint64_t z; + a = float64_squash_input_denormal(a STATUS_VAR); aExp = extractFloat64Exp( a ); if ( 0x433 <= aExp ) { @@ -2764,7 +3016,7 @@ float64 float64_round_to_int( float64 a STATUS_PARAM ) return a; } if ( aExp < 0x3FF ) { - if ( (bits64) ( float64_val(a)<<1 ) == 0 ) return a; + if ( (uint64_t) ( float64_val(a)<<1 ) == 0 ) return a; STATUS(float_exception_flags) |= float_flag_inexact; aSign = extractFloat64Sign( a ); switch ( STATUS(float_rounding_mode) ) { @@ -2824,7 +3076,7 @@ float64 float64_trunc_to_int( float64 a STATUS_PARAM) static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) { int16 aExp, bExp, zExp; - bits64 aSig, bSig, zSig; + uint64_t aSig, bSig, zSig; int16 expDiff; aSig = extractFloat64Frac( a ); @@ -2878,7 +3130,7 @@ static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) aSig |= LIT64( 0x2000000000000000 ); zSig = ( aSig + bSig )<<1; --zExp; - if ( (sbits64) zSig < 0 ) { + if ( (int64_t) zSig < 0 ) { zSig = aSig + bSig; ++zExp; } @@ -2898,7 +3150,7 @@ static float64 addFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) static float64 subFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) { int16 aExp, bExp, zExp; - bits64 aSig, bSig, zSig; + uint64_t aSig, bSig, zSig; int16 expDiff; aSig = extractFloat64Frac( a ); @@ -2971,6 +3223,8 @@ static float64 subFloat64Sigs( float64 a, float64 b, flag zSign STATUS_PARAM ) float64 float64_add( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); @@ -2992,6 +3246,8 @@ float64 float64_add( float64 a, float64 b STATUS_PARAM ) float64 float64_sub( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); aSign = extractFloat64Sign( a ); bSign = extractFloat64Sign( b ); @@ -3014,7 +3270,10 @@ float64 float64_mul( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign, zSign; int16 aExp, bExp, zExp; - bits64 aSig, bSig, zSig0, zSig1; + uint64_t aSig, bSig, zSig0, zSig1; + + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -3054,7 +3313,7 @@ float64 float64_mul( float64 a, float64 b STATUS_PARAM ) bSig = ( bSig | LIT64( 0x0010000000000000 ) )<<11; mul64To128( aSig, bSig, &zSig0, &zSig1 ); zSig0 |= ( zSig1 != 0 ); - if ( 0 <= (sbits64) ( zSig0<<1 ) ) { + if ( 0 <= (int64_t) ( zSig0<<1 ) ) { zSig0 <<= 1; --zExp; } @@ -3072,9 +3331,11 @@ float64 float64_div( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign, zSign; int16 aExp, bExp, zExp; - bits64 aSig, bSig, zSig; - bits64 rem0, rem1; - bits64 term0, term1; + uint64_t aSig, bSig, zSig; + uint64_t rem0, rem1; + uint64_t term0, term1; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -3122,7 +3383,7 @@ float64 float64_div( float64 a, float64 b STATUS_PARAM ) if ( ( zSig & 0x1FF ) <= 2 ) { mul64To128( bSig, zSig, &term0, &term1 ); sub128( aSig, 0, term0, term1, &rem0, &rem1 ); - while ( (sbits64) rem0 < 0 ) { + while ( (int64_t) rem0 < 0 ) { --zSig; add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); } @@ -3142,10 +3403,12 @@ float64 float64_rem( float64 a, float64 b STATUS_PARAM ) { flag aSign, zSign; int16 aExp, bExp, expDiff; - bits64 aSig, bSig; - bits64 q, alternateASig; - sbits64 sigMean; + uint64_t aSig, bSig; + uint64_t q, alternateASig; + int64_t sigMean; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); @@ -3205,12 +3468,12 @@ float64 float64_rem( float64 a, float64 b STATUS_PARAM ) alternateASig = aSig; ++q; aSig -= bSig; - } while ( 0 <= (sbits64) aSig ); + } while ( 0 <= (int64_t) aSig ); sigMean = aSig + alternateASig; if ( ( sigMean < 0 ) || ( ( sigMean == 0 ) && ( q & 1 ) ) ) { aSig = alternateASig; } - zSign = ( (sbits64) aSig < 0 ); + zSign = ( (int64_t) aSig < 0 ); if ( zSign ) aSig = - aSig; return normalizeRoundAndPackFloat64( aSign ^ zSign, bExp, aSig STATUS_VAR ); @@ -3226,8 +3489,9 @@ float64 float64_sqrt( float64 a STATUS_PARAM ) { flag aSign; int16 aExp, zExp; - bits64 aSig, zSig, doubleZSig; - bits64 rem0, rem1, term0, term1; + uint64_t aSig, zSig, doubleZSig; + uint64_t rem0, rem1, term0, term1; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -3256,7 +3520,7 @@ float64 float64_sqrt( float64 a STATUS_PARAM ) doubleZSig = zSig<<1; mul64To128( zSig, zSig, &term0, &term1 ); sub128( aSig, 0, term0, term1, &rem0, &rem1 ); - while ( (sbits64) rem0 < 0 ) { + while ( (int64_t) rem0 < 0 ) { --zSig; doubleZSig -= 2; add128( rem0, rem1, zSig>>63, doubleZSig | 1, &rem0, &rem1 ); @@ -3276,7 +3540,8 @@ float64 float64_log2( float64 a STATUS_PARAM ) { flag aSign, zSign; int16 aExp; - bits64 aSig, aSig0, aSig1, zSig, i; + uint64_t aSig, aSig0, aSig1, zSig, i; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); @@ -3298,7 +3563,7 @@ float64 float64_log2( float64 a STATUS_PARAM ) aExp -= 0x3FF; aSig |= LIT64( 0x0010000000000000 ); zSign = aExp < 0; - zSig = (bits64)aExp << 52; + zSig = (uint64_t)aExp << 52; for (i = 1LL << 51; i > 0; i >>= 1) { mul64To128( aSig, aSig, &aSig0, &aSig1 ); aSig = ( aSig0 << 12 ) | ( aSig1 >> 52 ); @@ -3315,39 +3580,42 @@ float64 float64_log2( float64 a STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is equal to the -| corresponding value `b', and 0 otherwise. The comparison is performed +| corresponding value `b', and 0 otherwise. The invalid exception is raised +| if either operand is a NaN. Otherwise, the comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float64_eq( float64 a, float64 b STATUS_PARAM ) { - bits64 av, bv; + uint64_t av, bv; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) ) { - if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid STATUS_VAR); - } + float_raise( float_flag_invalid STATUS_VAR); return 0; } av = float64_val(a); bv = float64_val(b); - return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( (uint64_t) ( ( av | bv )<<1 ) == 0 ); } /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is less than or -| equal to the corresponding value `b', and 0 otherwise. The comparison is -| performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| equal to the corresponding value `b', and 0 otherwise. The invalid +| exception is raised if either operand is a NaN. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float64_le( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; - bits64 av, bv; + uint64_t av, bv; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3359,22 +3627,25 @@ int float64_le( float64 a, float64 b STATUS_PARAM ) bSign = extractFloat64Sign( b ); av = float64_val(a); bv = float64_val(b); - if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + if ( aSign != bSign ) return aSign || ( (uint64_t) ( ( av | bv )<<1 ) == 0 ); return ( av == bv ) || ( aSign ^ ( av < bv ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. The comparison is performed according +| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float64_lt( float64 a, float64 b STATUS_PARAM ) { flag aSign, bSign; - bits64 av, bv; + uint64_t av, bv; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) ) { @@ -3385,31 +3656,56 @@ int float64_lt( float64 a, float64 b STATUS_PARAM ) bSign = extractFloat64Sign( b ); av = float64_val(a); bv = float64_val(b); - if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 ); + if ( aSign != bSign ) return aSign && ( (uint64_t) ( ( av | bv )<<1 ) != 0 ); return ( av != bv ) && ( aSign ^ ( av < bv ) ); } /*---------------------------------------------------------------------------- -| Returns 1 if the double-precision floating-point value `a' is equal to the -| corresponding value `b', and 0 otherwise. The invalid exception is raised -| if either operand is a NaN. Otherwise, the comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| Returns 1 if the double-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. The invalid exception is raised if either +| operand is a NaN. The comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float64_eq_signaling( float64 a, float64 b STATUS_PARAM ) +int float64_unordered( float64 a, float64 b STATUS_PARAM ) { - bits64 av, bv; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) ) { float_raise( float_flag_invalid STATUS_VAR); + return 1; + } + return 0; +} + +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point value `a' is equal to the +| corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception.The comparison is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_eq_quiet( float64 a, float64 b STATUS_PARAM ) +{ + uint64_t av, bv; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } return 0; } av = float64_val(a); bv = float64_val(b); - return ( av == bv ) || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + return ( av == bv ) || ( (uint64_t) ( ( av | bv )<<1 ) == 0 ); } @@ -3423,7 +3719,9 @@ 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; + uint64_t av, bv; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3437,7 +3735,7 @@ int float64_le_quiet( float64 a, float64 b STATUS_PARAM ) bSign = extractFloat64Sign( b ); av = float64_val(a); bv = float64_val(b); - if ( aSign != bSign ) return aSign || ( (bits64) ( ( av | bv )<<1 ) == 0 ); + if ( aSign != bSign ) return aSign || ( (uint64_t) ( ( av | bv )<<1 ) == 0 ); return ( av == bv ) || ( aSign ^ ( av < bv ) ); } @@ -3452,7 +3750,9 @@ 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; + uint64_t av, bv; + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) @@ -3466,11 +3766,34 @@ int float64_lt_quiet( float64 a, float64 b STATUS_PARAM ) bSign = extractFloat64Sign( b ); av = float64_val(a); bv = float64_val(b); - if ( aSign != bSign ) return aSign && ( (bits64) ( ( av | bv )<<1 ) != 0 ); + if ( aSign != bSign ) return aSign && ( (uint64_t) ( ( av | bv )<<1 ) != 0 ); return ( av != bv ) && ( aSign ^ ( av < bv ) ); } +/*---------------------------------------------------------------------------- +| Returns 1 if the double-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The +| comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float64_unordered_quiet( float64 a, float64 b STATUS_PARAM ) +{ + a = float64_squash_input_denormal(a STATUS_VAR); + b = float64_squash_input_denormal(b STATUS_VAR); + + if ( ( ( extractFloat64Exp( a ) == 0x7FF ) && extractFloat64Frac( a ) ) + || ( ( extractFloat64Exp( b ) == 0x7FF ) && extractFloat64Frac( b ) ) + ) { + if ( float64_is_signaling_nan( a ) || float64_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 1; + } + return 0; +} + #ifdef FLOATX80 /*---------------------------------------------------------------------------- @@ -3487,12 +3810,12 @@ int32 floatx80_to_int32( floatx80 a STATUS_PARAM ) { flag aSign; int32 aExp, shiftCount; - bits64 aSig; + uint64_t aSig; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); - if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + if ( ( aExp == 0x7FFF ) && (uint64_t) ( aSig<<1 ) ) aSign = 0; shiftCount = 0x4037 - aExp; if ( shiftCount <= 0 ) shiftCount = 1; shift64RightJamming( aSig, shiftCount, &aSig ); @@ -3514,14 +3837,14 @@ int32 floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM ) { flag aSign; int32 aExp, shiftCount; - bits64 aSig, savedASig; + uint64_t aSig, savedASig; int32 z; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); if ( 0x401E < aExp ) { - if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) aSign = 0; + if ( ( aExp == 0x7FFF ) && (uint64_t) ( aSig<<1 ) ) aSign = 0; goto invalid; } else if ( aExp < 0x3FFF ) { @@ -3536,7 +3859,7 @@ int32 floatx80_to_int32_round_to_zero( floatx80 a STATUS_PARAM ) if ( ( z < 0 ) ^ aSign ) { invalid: float_raise( float_flag_invalid STATUS_VAR); - return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + return aSign ? (int32_t) 0x80000000 : 0x7FFFFFFF; } if ( ( aSig<>( - shiftCount ); - if ( (bits64) ( aSig<<( shiftCount & 63 ) ) ) { + if ( (uint64_t) ( aSig<<( shiftCount & 63 ) ) ) { STATUS(float_exception_flags) |= float_flag_inexact; } if ( aSign ) z = - z; @@ -3640,14 +3963,14 @@ float32 floatx80_to_float32( floatx80 a STATUS_PARAM ) { flag aSign; int32 aExp; - bits64 aSig; + uint64_t aSig; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); if ( aExp == 0x7FFF ) { - if ( (bits64) ( aSig<<1 ) ) { - return commonNaNToFloat32( floatx80ToCommonNaN( a STATUS_VAR ) ); + if ( (uint64_t) ( aSig<<1 ) ) { + return commonNaNToFloat32( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); } return packFloat32( aSign, 0xFF, 0 ); } @@ -3668,14 +3991,14 @@ float64 floatx80_to_float64( floatx80 a STATUS_PARAM ) { flag aSign; int32 aExp; - bits64 aSig, zSig; + uint64_t aSig, zSig; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); if ( aExp == 0x7FFF ) { - if ( (bits64) ( aSig<<1 ) ) { - return commonNaNToFloat64( floatx80ToCommonNaN( a STATUS_VAR ) ); + if ( (uint64_t) ( aSig<<1 ) ) { + return commonNaNToFloat64( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); } return packFloat64( aSign, 0x7FF, 0 ); } @@ -3698,13 +4021,13 @@ float128 floatx80_to_float128( floatx80 a STATUS_PARAM ) { flag aSign; int16 aExp; - bits64 aSig, zSig0, zSig1; + uint64_t aSig, zSig0, zSig1; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); - if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) { - return commonNaNToFloat128( floatx80ToCommonNaN( a STATUS_VAR ) ); + if ( ( aExp == 0x7FFF ) && (uint64_t) ( aSig<<1 ) ) { + return commonNaNToFloat128( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); } shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 ); return packFloat128( aSign, aExp, zSig0, zSig1 ); @@ -3724,27 +4047,27 @@ floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM ) { flag aSign; int32 aExp; - bits64 lastBitMask, roundBitsMask; + uint64_t lastBitMask, roundBitsMask; int8 roundingMode; floatx80 z; aExp = extractFloatx80Exp( a ); if ( 0x403E <= aExp ) { - if ( ( aExp == 0x7FFF ) && (bits64) ( extractFloatx80Frac( a )<<1 ) ) { + if ( ( aExp == 0x7FFF ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) { return propagateFloatx80NaN( a, a STATUS_VAR ); } return a; } if ( aExp < 0x3FFF ) { if ( ( aExp == 0 ) - && ( (bits64) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) { + && ( (uint64_t) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) { return a; } STATUS(float_exception_flags) |= float_flag_inexact; aSign = extractFloatx80Sign( a ); switch ( STATUS(float_rounding_mode) ) { case float_round_nearest_even: - if ( ( aExp == 0x3FFE ) && (bits64) ( extractFloatx80Frac( a )<<1 ) + if ( ( aExp == 0x3FFE ) && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) { return packFloatx80( aSign, 0x3FFF, LIT64( 0x8000000000000000 ) ); @@ -3797,7 +4120,7 @@ floatx80 floatx80_round_to_int( floatx80 a STATUS_PARAM ) static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM) { int32 aExp, bExp, zExp; - bits64 aSig, bSig, zSig0, zSig1; + uint64_t aSig, bSig, zSig0, zSig1; int32 expDiff; aSig = extractFloatx80Frac( a ); @@ -3807,7 +4130,7 @@ static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM expDiff = aExp - bExp; if ( 0 < expDiff ) { if ( aExp == 0x7FFF ) { - if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); return a; } if ( bExp == 0 ) --expDiff; @@ -3816,7 +4139,7 @@ static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM } else if ( expDiff < 0 ) { if ( bExp == 0x7FFF ) { - if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( aExp == 0 ) ++expDiff; @@ -3825,7 +4148,7 @@ static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM } else { if ( aExp == 0x7FFF ) { - if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + if ( (uint64_t) ( ( aSig | bSig )<<1 ) ) { return propagateFloatx80NaN( a, b STATUS_VAR ); } return a; @@ -3840,7 +4163,7 @@ static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM goto shiftRight1; } zSig0 = aSig + bSig; - if ( (sbits64) zSig0 < 0 ) goto roundAndPack; + if ( (int64_t) zSig0 < 0 ) goto roundAndPack; shiftRight1: shift64ExtraRightJamming( zSig0, zSig1, 1, &zSig0, &zSig1 ); zSig0 |= LIT64( 0x8000000000000000 ); @@ -3863,7 +4186,7 @@ static floatx80 addFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM ) { int32 aExp, bExp, zExp; - bits64 aSig, bSig, zSig0, zSig1; + uint64_t aSig, bSig, zSig0, zSig1; int32 expDiff; floatx80 z; @@ -3875,7 +4198,7 @@ static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM if ( 0 < expDiff ) goto aExpBigger; if ( expDiff < 0 ) goto bExpBigger; if ( aExp == 0x7FFF ) { - if ( (bits64) ( ( aSig | bSig )<<1 ) ) { + if ( (uint64_t) ( ( aSig | bSig )<<1 ) ) { return propagateFloatx80NaN( a, b STATUS_VAR ); } float_raise( float_flag_invalid STATUS_VAR); @@ -3893,7 +4216,7 @@ static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM return packFloatx80( STATUS(float_rounding_mode) == float_round_down, 0, 0 ); bExpBigger: if ( bExp == 0x7FFF ) { - if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); return packFloatx80( zSign ^ 1, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( aExp == 0 ) ++expDiff; @@ -3905,7 +4228,7 @@ static floatx80 subFloatx80Sigs( floatx80 a, floatx80 b, flag zSign STATUS_PARAM goto normalizeRoundAndPack; aExpBigger: if ( aExp == 0x7FFF ) { - if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); return a; } if ( bExp == 0 ) --expDiff; @@ -3972,7 +4295,7 @@ floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign, zSign; int32 aExp, bExp, zExp; - bits64 aSig, bSig, zSig0, zSig1; + uint64_t aSig, bSig, zSig0, zSig1; floatx80 z; aSig = extractFloatx80Frac( a ); @@ -3983,15 +4306,15 @@ floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM ) bSign = extractFloatx80Sign( b ); zSign = aSign ^ bSign; if ( aExp == 0x7FFF ) { - if ( (bits64) ( aSig<<1 ) - || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + if ( (uint64_t) ( aSig<<1 ) + || ( ( bExp == 0x7FFF ) && (uint64_t) ( bSig<<1 ) ) ) { return propagateFloatx80NaN( a, b STATUS_VAR ); } if ( ( bExp | bSig ) == 0 ) goto invalid; return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( bExp == 0x7FFF ) { - if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); if ( ( aExp | aSig ) == 0 ) { invalid: float_raise( float_flag_invalid STATUS_VAR); @@ -4011,7 +4334,7 @@ floatx80 floatx80_mul( floatx80 a, floatx80 b STATUS_PARAM ) } zExp = aExp + bExp - 0x3FFE; mul64To128( aSig, bSig, &zSig0, &zSig1 ); - if ( 0 < (sbits64) zSig0 ) { + if ( 0 < (int64_t) zSig0 ) { shortShift128Left( zSig0, zSig1, 1, &zSig0, &zSig1 ); --zExp; } @@ -4031,8 +4354,8 @@ floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, bSign, zSign; int32 aExp, bExp, zExp; - bits64 aSig, bSig, zSig0, zSig1; - bits64 rem0, rem1, rem2, term0, term1, term2; + uint64_t aSig, bSig, zSig0, zSig1; + uint64_t rem0, rem1, rem2, term0, term1, term2; floatx80 z; aSig = extractFloatx80Frac( a ); @@ -4043,15 +4366,15 @@ floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM ) bSign = extractFloatx80Sign( b ); zSign = aSign ^ bSign; if ( aExp == 0x7FFF ) { - if ( (bits64) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( (uint64_t) ( aSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); if ( bExp == 0x7FFF ) { - if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); goto invalid; } return packFloatx80( zSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( bExp == 0x7FFF ) { - if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); return packFloatx80( zSign, 0, 0 ); } if ( bExp == 0 ) { @@ -4081,15 +4404,15 @@ floatx80 floatx80_div( floatx80 a, floatx80 b STATUS_PARAM ) zSig0 = estimateDiv128To64( aSig, rem1, bSig ); mul64To128( bSig, zSig0, &term0, &term1 ); sub128( aSig, rem1, term0, term1, &rem0, &rem1 ); - while ( (sbits64) rem0 < 0 ) { + while ( (int64_t) rem0 < 0 ) { --zSig0; add128( rem0, rem1, 0, bSig, &rem0, &rem1 ); } zSig1 = estimateDiv128To64( rem1, 0, bSig ); - if ( (bits64) ( zSig1<<1 ) <= 8 ) { + if ( (uint64_t) ( zSig1<<1 ) <= 8 ) { mul64To128( bSig, zSig1, &term1, &term2 ); sub128( rem1, 0, term1, term2, &rem1, &rem2 ); - while ( (sbits64) rem1 < 0 ) { + while ( (int64_t) rem1 < 0 ) { --zSig1; add128( rem1, rem2, 0, bSig, &rem1, &rem2 ); } @@ -4111,8 +4434,8 @@ floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM ) { flag aSign, zSign; int32 aExp, bExp, expDiff; - bits64 aSig0, aSig1, bSig; - bits64 q, term0, term1, alternateASig0, alternateASig1; + uint64_t aSig0, aSig1, bSig; + uint64_t q, term0, term1, alternateASig0, alternateASig1; floatx80 z; aSig0 = extractFloatx80Frac( a ); @@ -4121,14 +4444,14 @@ floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM ) bSig = extractFloatx80Frac( b ); bExp = extractFloatx80Exp( b ); if ( aExp == 0x7FFF ) { - if ( (bits64) ( aSig0<<1 ) - || ( ( bExp == 0x7FFF ) && (bits64) ( bSig<<1 ) ) ) { + if ( (uint64_t) ( aSig0<<1 ) + || ( ( bExp == 0x7FFF ) && (uint64_t) ( bSig<<1 ) ) ) { return propagateFloatx80NaN( a, b STATUS_VAR ); } goto invalid; } if ( bExp == 0x7FFF ) { - if ( (bits64) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); + if ( (uint64_t) ( bSig<<1 ) ) return propagateFloatx80NaN( a, b STATUS_VAR ); return a; } if ( bExp == 0 ) { @@ -4142,7 +4465,7 @@ floatx80 floatx80_rem( floatx80 a, floatx80 b STATUS_PARAM ) normalizeFloatx80Subnormal( bSig, &bExp, &bSig ); } if ( aExp == 0 ) { - if ( (bits64) ( aSig0<<1 ) == 0 ) return a; + if ( (uint64_t) ( aSig0<<1 ) == 0 ) return a; normalizeFloatx80Subnormal( aSig0, &aExp, &aSig0 ); } bSig |= LIT64( 0x8000000000000000 ); @@ -4207,15 +4530,15 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM ) { flag aSign; int32 aExp, zExp; - bits64 aSig0, aSig1, zSig0, zSig1, doubleZSig0; - bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + uint64_t aSig0, aSig1, zSig0, zSig1, doubleZSig0; + uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3; floatx80 z; aSig0 = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); if ( aExp == 0x7FFF ) { - if ( (bits64) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a STATUS_VAR ); + if ( (uint64_t) ( aSig0<<1 ) ) return propagateFloatx80NaN( a, a STATUS_VAR ); if ( ! aSign ) return a; goto invalid; } @@ -4238,7 +4561,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM ) doubleZSig0 = zSig0<<1; mul64To128( zSig0, zSig0, &term0, &term1 ); sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); - while ( (sbits64) rem0 < 0 ) { + while ( (int64_t) rem0 < 0 ) { --zSig0; doubleZSig0 -= 2; add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 ); @@ -4250,7 +4573,7 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM ) sub128( rem1, 0, term1, term2, &rem1, &rem2 ); mul64To128( zSig1, zSig1, &term2, &term3 ); sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); - while ( (sbits64) rem1 < 0 ) { + while ( (int64_t) rem1 < 0 ) { --zSig1; shortShift128Left( 0, zSig1, 1, &term2, &term3 ); term3 |= 1; @@ -4268,31 +4591,28 @@ floatx80 floatx80_sqrt( floatx80 a STATUS_PARAM ) } /*---------------------------------------------------------------------------- -| Returns 1 if the extended 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. +| Returns 1 if the extended double-precision floating-point value `a' is equal +| to the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) { if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) ) { - if ( floatx80_is_signaling_nan( a ) - || floatx80_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid STATUS_VAR); - } + float_raise( float_flag_invalid STATUS_VAR); return 0; } return ( a.low == b.low ) && ( ( a.high == b.high ) || ( ( a.low == 0 ) - && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + && ( (uint16_t) ( ( a.high | b.high )<<1 ) == 0 ) ) ); } @@ -4300,8 +4620,9 @@ int floatx80_eq( floatx80 a, floatx80 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is | less than or equal to the corresponding value `b', and 0 otherwise. The -| comparison is performed according to the IEC/IEEE Standard for Binary -| Floating-Point Arithmetic. +| invalid exception is raised if either operand is a NaN. The comparison is +| performed according to the IEC/IEEE Standard for Binary Floating-Point +| Arithmetic. *----------------------------------------------------------------------------*/ int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) @@ -4309,9 +4630,9 @@ int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) flag aSign, bSign; if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) ) { float_raise( float_flag_invalid STATUS_VAR); return 0; @@ -4321,7 +4642,7 @@ int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) if ( aSign != bSign ) { return aSign - || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + || ( ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) == 0 ); } return @@ -4332,9 +4653,9 @@ int floatx80_le( floatx80 a, floatx80 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the extended double-precision floating-point value `a' is -| less than the corresponding value `b', and 0 otherwise. The comparison -| is performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| less than the corresponding value `b', and 0 otherwise. The invalid +| exception is raised if either operand is a NaN. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) @@ -4342,9 +4663,9 @@ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) flag aSign, bSign; if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) ) { float_raise( float_flag_invalid STATUS_VAR); return 0; @@ -4354,7 +4675,7 @@ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) if ( aSign != bSign ) { return aSign - && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + && ( ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) != 0 ); } return @@ -4364,28 +4685,50 @@ int floatx80_lt( floatx80 a, floatx80 b STATUS_PARAM ) } /*---------------------------------------------------------------------------- -| Returns 1 if the extended double-precision floating-point value `a' is equal -| to the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. Otherwise, the comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| Returns 1 if the extended double-precision floating-point values `a' and `b' +| cannot be compared, and 0 otherwise. The invalid exception is raised if +| either operand is a NaN. The comparison is performed according to the +| IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ +int floatx80_unordered( floatx80 a, floatx80 b STATUS_PARAM ) +{ + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 1; + } + return 0; +} -int floatx80_eq_signaling( floatx80 a, floatx80 b STATUS_PARAM ) +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point value `a' is +| equal to the corresponding value `b', and 0 otherwise. Quiet NaNs do not +| cause an exception. The comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int floatx80_eq_quiet( floatx80 a, floatx80 b STATUS_PARAM ) { if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) ) { - float_raise( float_flag_invalid STATUS_VAR); + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } return 0; } return ( a.low == b.low ) && ( ( a.high == b.high ) || ( ( a.low == 0 ) - && ( (bits16) ( ( a.high | b.high )<<1 ) == 0 ) ) + && ( (uint16_t) ( ( a.high | b.high )<<1 ) == 0 ) ) ); } @@ -4402,9 +4745,9 @@ int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM ) flag aSign, bSign; if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) ) { if ( floatx80_is_signaling_nan( a ) || floatx80_is_signaling_nan( b ) ) { @@ -4417,7 +4760,7 @@ int floatx80_le_quiet( floatx80 a, floatx80 b STATUS_PARAM ) if ( aSign != bSign ) { return aSign - || ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + || ( ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) == 0 ); } return @@ -4438,9 +4781,9 @@ int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM ) flag aSign, bSign; if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( a )<<1 ) ) + && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) || ( ( extractFloatx80Exp( b ) == 0x7FFF ) - && (bits64) ( extractFloatx80Frac( b )<<1 ) ) + && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) ) { if ( floatx80_is_signaling_nan( a ) || floatx80_is_signaling_nan( b ) ) { @@ -4453,7 +4796,7 @@ int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM ) if ( aSign != bSign ) { return aSign - && ( ( ( (bits16) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + && ( ( ( (uint16_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) != 0 ); } return @@ -4462,6 +4805,28 @@ int floatx80_lt_quiet( floatx80 a, floatx80 b STATUS_PARAM ) } +/*---------------------------------------------------------------------------- +| Returns 1 if the extended double-precision floating-point values `a' and `b' +| cannot be compared, and 0 otherwise. Quiet NaNs do not cause an exception. +| The comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ +int floatx80_unordered_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + if ( ( ( extractFloatx80Exp( a ) == 0x7FFF ) + && (uint64_t) ( extractFloatx80Frac( a )<<1 ) ) + || ( ( extractFloatx80Exp( b ) == 0x7FFF ) + && (uint64_t) ( extractFloatx80Frac( b )<<1 ) ) + ) { + if ( floatx80_is_signaling_nan( a ) + || floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 1; + } + return 0; +} + #endif #ifdef FLOAT128 @@ -4480,7 +4845,7 @@ int32 float128_to_int32( float128 a STATUS_PARAM ) { flag aSign; int32 aExp, shiftCount; - bits64 aSig0, aSig1; + uint64_t aSig0, aSig1; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); @@ -4509,7 +4874,7 @@ int32 float128_to_int32_round_to_zero( float128 a STATUS_PARAM ) { flag aSign; int32 aExp, shiftCount; - bits64 aSig0, aSig1, savedASig; + uint64_t aSig0, aSig1, savedASig; int32 z; aSig1 = extractFloat128Frac1( a ); @@ -4534,7 +4899,7 @@ int32 float128_to_int32_round_to_zero( float128 a STATUS_PARAM ) if ( ( z < 0 ) ^ aSign ) { invalid: float_raise( float_flag_invalid STATUS_VAR); - return aSign ? (sbits32) 0x80000000 : 0x7FFFFFFF; + return aSign ? (int32_t) 0x80000000 : 0x7FFFFFFF; } if ( ( aSig0<>( ( - shiftCount ) & 63 ) ); - if ( (bits64) ( aSig1<>( - shiftCount ); if ( aSig1 - || ( shiftCount && (bits64) ( aSig0<<( shiftCount & 63 ) ) ) ) { + || ( shiftCount && (uint64_t) ( aSig0<<( shiftCount & 63 ) ) ) ) { STATUS(float_exception_flags) |= float_flag_inexact; } } @@ -4658,8 +5023,8 @@ float32 float128_to_float32( float128 a STATUS_PARAM ) { flag aSign; int32 aExp; - bits64 aSig0, aSig1; - bits32 zSig; + uint64_t aSig0, aSig1; + uint32_t zSig; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); @@ -4667,7 +5032,7 @@ float32 float128_to_float32( float128 a STATUS_PARAM ) aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 ) { - return commonNaNToFloat32( float128ToCommonNaN( a STATUS_VAR ) ); + return commonNaNToFloat32( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); } return packFloat32( aSign, 0xFF, 0 ); } @@ -4693,7 +5058,7 @@ float64 float128_to_float64( float128 a STATUS_PARAM ) { flag aSign; int32 aExp; - bits64 aSig0, aSig1; + uint64_t aSig0, aSig1; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); @@ -4701,7 +5066,7 @@ float64 float128_to_float64( float128 a STATUS_PARAM ) aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 ) { - return commonNaNToFloat64( float128ToCommonNaN( a STATUS_VAR ) ); + return commonNaNToFloat64( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); } return packFloat64( aSign, 0x7FF, 0 ); } @@ -4728,7 +5093,7 @@ floatx80 float128_to_floatx80( float128 a STATUS_PARAM ) { flag aSign; int32 aExp; - bits64 aSig0, aSig1; + uint64_t aSig0, aSig1; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); @@ -4736,7 +5101,7 @@ floatx80 float128_to_floatx80( float128 a STATUS_PARAM ) aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { if ( aSig0 | aSig1 ) { - return commonNaNToFloatx80( float128ToCommonNaN( a STATUS_VAR ) ); + return commonNaNToFloatx80( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); } return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } @@ -4765,7 +5130,7 @@ float128 float128_round_to_int( float128 a STATUS_PARAM ) { flag aSign; int32 aExp; - bits64 lastBitMask, roundBitsMask; + uint64_t lastBitMask, roundBitsMask; int8 roundingMode; float128 z; @@ -4790,9 +5155,9 @@ float128 float128_round_to_int( float128 a STATUS_PARAM ) if ( ( z.low & roundBitsMask ) == 0 ) z.low &= ~ lastBitMask; } else { - if ( (sbits64) z.low < 0 ) { + if ( (int64_t) z.low < 0 ) { ++z.high; - if ( (bits64) ( z.low<<1 ) == 0 ) z.high &= ~1; + if ( (uint64_t) ( z.low<<1 ) == 0 ) z.high &= ~1; } } } @@ -4806,7 +5171,7 @@ float128 float128_round_to_int( float128 a STATUS_PARAM ) } else { if ( aExp < 0x3FFF ) { - if ( ( ( (bits64) ( a.high<<1 ) ) | a.low ) == 0 ) return a; + if ( ( ( (uint64_t) ( a.high<<1 ) ) | a.low ) == 0 ) return a; STATUS(float_exception_flags) |= float_flag_inexact; aSign = extractFloat128Sign( a ); switch ( STATUS(float_rounding_mode) ) { @@ -4868,7 +5233,7 @@ float128 float128_round_to_int( float128 a STATUS_PARAM ) static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM) { int32 aExp, bExp, zExp; - bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; + uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; int32 expDiff; aSig1 = extractFloat128Frac1( a ); @@ -4949,7 +5314,7 @@ static float128 addFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM static float128 subFloat128Sigs( float128 a, float128 b, flag zSign STATUS_PARAM) { int32 aExp, bExp, zExp; - bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1; + uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1; int32 expDiff; float128 z; @@ -5074,7 +5439,7 @@ float128 float128_mul( float128 a, float128 b STATUS_PARAM ) { flag aSign, bSign, zSign; int32 aExp, bExp, zExp; - bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3; + uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2, zSig3; float128 z; aSig1 = extractFloat128Frac1( a ); @@ -5138,8 +5503,8 @@ float128 float128_div( float128 a, float128 b STATUS_PARAM ) { flag aSign, bSign, zSign; int32 aExp, bExp, zExp; - bits64 aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; - bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + uint64_t aSig0, aSig1, bSig0, bSig1, zSig0, zSig1, zSig2; + uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3; float128 z; aSig1 = extractFloat128Frac1( a ); @@ -5193,7 +5558,7 @@ float128 float128_div( float128 a, float128 b STATUS_PARAM ) zSig0 = estimateDiv128To64( aSig0, aSig1, bSig0 ); mul128By64To192( bSig0, bSig1, zSig0, &term0, &term1, &term2 ); sub192( aSig0, aSig1, 0, term0, term1, term2, &rem0, &rem1, &rem2 ); - while ( (sbits64) rem0 < 0 ) { + while ( (int64_t) rem0 < 0 ) { --zSig0; add192( rem0, rem1, rem2, 0, bSig0, bSig1, &rem0, &rem1, &rem2 ); } @@ -5201,7 +5566,7 @@ float128 float128_div( float128 a, float128 b STATUS_PARAM ) if ( ( zSig1 & 0x3FFF ) <= 4 ) { mul128By64To192( bSig0, bSig1, zSig1, &term1, &term2, &term3 ); sub192( rem1, rem2, 0, term1, term2, term3, &rem1, &rem2, &rem3 ); - while ( (sbits64) rem1 < 0 ) { + while ( (int64_t) rem1 < 0 ) { --zSig1; add192( rem1, rem2, rem3, 0, bSig0, bSig1, &rem1, &rem2, &rem3 ); } @@ -5222,9 +5587,9 @@ float128 float128_rem( float128 a, float128 b STATUS_PARAM ) { flag aSign, zSign; int32 aExp, bExp, expDiff; - bits64 aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2; - bits64 allZero, alternateASig0, alternateASig1, sigMean1; - sbits64 sigMean0; + uint64_t aSig0, aSig1, bSig0, bSig1, q, term0, term1, term2; + uint64_t allZero, alternateASig0, alternateASig1, sigMean1; + int64_t sigMean0; float128 z; aSig1 = extractFloat128Frac1( a ); @@ -5306,15 +5671,15 @@ float128 float128_rem( float128 a, float128 b STATUS_PARAM ) alternateASig1 = aSig1; ++q; sub128( aSig0, aSig1, bSig0, bSig1, &aSig0, &aSig1 ); - } while ( 0 <= (sbits64) aSig0 ); + } while ( 0 <= (int64_t) aSig0 ); add128( - aSig0, aSig1, alternateASig0, alternateASig1, (bits64 *)&sigMean0, &sigMean1 ); + aSig0, aSig1, alternateASig0, alternateASig1, (uint64_t *)&sigMean0, &sigMean1 ); if ( ( sigMean0 < 0 ) || ( ( ( sigMean0 | sigMean1 ) == 0 ) && ( q & 1 ) ) ) { aSig0 = alternateASig0; aSig1 = alternateASig1; } - zSign = ( (sbits64) aSig0 < 0 ); + zSign = ( (int64_t) aSig0 < 0 ); if ( zSign ) sub128( 0, 0, aSig0, aSig1, &aSig0, &aSig1 ); return normalizeRoundAndPackFloat128( aSign ^ zSign, bExp - 4, aSig0, aSig1 STATUS_VAR ); @@ -5331,8 +5696,8 @@ float128 float128_sqrt( float128 a STATUS_PARAM ) { flag aSign; int32 aExp, zExp; - bits64 aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0; - bits64 rem0, rem1, rem2, rem3, term0, term1, term2, term3; + uint64_t aSig0, aSig1, zSig0, zSig1, zSig2, doubleZSig0; + uint64_t rem0, rem1, rem2, rem3, term0, term1, term2, term3; float128 z; aSig1 = extractFloat128Frac1( a ); @@ -5364,7 +5729,7 @@ float128 float128_sqrt( float128 a STATUS_PARAM ) doubleZSig0 = zSig0<<1; mul64To128( zSig0, zSig0, &term0, &term1 ); sub128( aSig0, aSig1, term0, term1, &rem0, &rem1 ); - while ( (sbits64) rem0 < 0 ) { + while ( (int64_t) rem0 < 0 ) { --zSig0; doubleZSig0 -= 2; add128( rem0, rem1, zSig0>>63, doubleZSig0 | 1, &rem0, &rem1 ); @@ -5376,7 +5741,7 @@ float128 float128_sqrt( float128 a STATUS_PARAM ) sub128( rem1, 0, term1, term2, &rem1, &rem2 ); mul64To128( zSig1, zSig1, &term2, &term3 ); sub192( rem1, rem2, 0, 0, term2, term3, &rem1, &rem2, &rem3 ); - while ( (sbits64) rem1 < 0 ) { + while ( (int64_t) rem1 < 0 ) { --zSig1; shortShift128Left( 0, zSig1, 1, &term2, &term3 ); term3 |= 1; @@ -5392,7 +5757,8 @@ float128 float128_sqrt( float128 a STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The comparison is performed +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. Otherwise, the comparison is performed | according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ @@ -5404,26 +5770,23 @@ int float128_eq( float128 a, float128 b STATUS_PARAM ) || ( ( extractFloat128Exp( b ) == 0x7FFF ) && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) ) { - if ( float128_is_signaling_nan( a ) - || float128_is_signaling_nan( b ) ) { - float_raise( float_flag_invalid STATUS_VAR); - } + float_raise( float_flag_invalid STATUS_VAR); return 0; } return ( a.low == b.low ) && ( ( a.high == b.high ) || ( ( a.low == 0 ) - && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) + && ( (uint64_t) ( ( a.high | b.high )<<1 ) == 0 ) ) ); } /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is less than -| or equal to the corresponding value `b', and 0 otherwise. The comparison -| is performed according to the IEC/IEEE Standard for Binary Floating-Point -| Arithmetic. +| or equal to the corresponding value `b', and 0 otherwise. The invalid +| exception is raised if either operand is a NaN. The comparison is performed +| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float128_le( float128 a, float128 b STATUS_PARAM ) @@ -5443,7 +5806,7 @@ int float128_le( float128 a, float128 b STATUS_PARAM ) if ( aSign != bSign ) { return aSign - || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + || ( ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) == 0 ); } return @@ -5454,8 +5817,9 @@ int float128_le( float128 a, float128 b STATUS_PARAM ) /*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is less than -| the corresponding value `b', and 0 otherwise. The comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| the corresponding value `b', and 0 otherwise. The invalid exception is +| raised if either operand is a NaN. The comparison is performed according +| to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ int float128_lt( float128 a, float128 b STATUS_PARAM ) @@ -5475,7 +5839,7 @@ int float128_lt( float128 a, float128 b STATUS_PARAM ) if ( aSign != bSign ) { return aSign - && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + && ( ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) != 0 ); } return @@ -5485,13 +5849,33 @@ int float128_lt( float128 a, float128 b STATUS_PARAM ) } /*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. The invalid exception is raised if either +| operand is a NaN. The comparison is performed according to the IEC/IEEE +| Standard for Binary Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_unordered( float128 a, float128 b STATUS_PARAM ) +{ + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + float_raise( float_flag_invalid STATUS_VAR); + return 1; + } + return 0; +} + +/*---------------------------------------------------------------------------- | Returns 1 if the quadruple-precision floating-point value `a' is equal to -| the corresponding value `b', and 0 otherwise. The invalid exception is -| raised if either operand is a NaN. Otherwise, the comparison is performed -| according to the IEC/IEEE Standard for Binary Floating-Point Arithmetic. +| the corresponding value `b', and 0 otherwise. Quiet NaNs do not cause an +| exception. The comparison is performed according to the IEC/IEEE Standard +| for Binary Floating-Point Arithmetic. *----------------------------------------------------------------------------*/ -int float128_eq_signaling( float128 a, float128 b STATUS_PARAM ) +int float128_eq_quiet( float128 a, float128 b STATUS_PARAM ) { if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) @@ -5499,14 +5883,17 @@ int float128_eq_signaling( float128 a, float128 b STATUS_PARAM ) || ( ( extractFloat128Exp( b ) == 0x7FFF ) && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) ) { - float_raise( float_flag_invalid STATUS_VAR); + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } return 0; } return ( a.low == b.low ) && ( ( a.high == b.high ) || ( ( a.low == 0 ) - && ( (bits64) ( ( a.high | b.high )<<1 ) == 0 ) ) + && ( (uint64_t) ( ( a.high | b.high )<<1 ) == 0 ) ) ); } @@ -5538,7 +5925,7 @@ int float128_le_quiet( float128 a, float128 b STATUS_PARAM ) if ( aSign != bSign ) { return aSign - || ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + || ( ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) == 0 ); } return @@ -5574,7 +5961,7 @@ int float128_lt_quiet( float128 a, float128 b STATUS_PARAM ) if ( aSign != bSign ) { return aSign - && ( ( ( (bits64) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) + && ( ( ( (uint64_t) ( ( a.high | b.high )<<1 ) ) | a.low | b.low ) != 0 ); } return @@ -5583,6 +5970,29 @@ int float128_lt_quiet( float128 a, float128 b STATUS_PARAM ) } +/*---------------------------------------------------------------------------- +| Returns 1 if the quadruple-precision floating-point values `a' and `b' cannot +| be compared, and 0 otherwise. Quiet NaNs do not cause an exception. The +| comparison is performed according to the IEC/IEEE Standard for Binary +| Floating-Point Arithmetic. +*----------------------------------------------------------------------------*/ + +int float128_unordered_quiet( float128 a, float128 b STATUS_PARAM ) +{ + if ( ( ( extractFloat128Exp( a ) == 0x7FFF ) + && ( extractFloat128Frac0( a ) | extractFloat128Frac1( a ) ) ) + || ( ( extractFloat128Exp( b ) == 0x7FFF ) + && ( extractFloat128Frac0( b ) | extractFloat128Frac1( b ) ) ) + ) { + if ( float128_is_signaling_nan( a ) + || float128_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return 1; + } + return 0; +} + #endif /* misc functions */ @@ -5632,6 +6042,24 @@ unsigned int float32_to_uint32_round_to_zero( float32 a STATUS_PARAM ) return res; } +unsigned int float32_to_uint16_round_to_zero( float32 a STATUS_PARAM ) +{ + int64_t v; + unsigned int res; + + v = float32_to_int64_round_to_zero(a STATUS_VAR); + if (v < 0) { + res = 0; + float_raise( float_flag_invalid STATUS_VAR); + } else if (v > 0xffff) { + res = 0xffff; + float_raise( float_flag_invalid STATUS_VAR); + } else { + res = v; + } + return res; +} + unsigned int float64_to_uint32( float64 a STATUS_PARAM ) { int64_t v; @@ -5668,6 +6096,24 @@ unsigned int float64_to_uint32_round_to_zero( float64 a STATUS_PARAM ) return res; } +unsigned int float64_to_uint16_round_to_zero( float64 a STATUS_PARAM ) +{ + int64_t v; + unsigned int res; + + v = float64_to_int64_round_to_zero(a STATUS_VAR); + if (v < 0) { + res = 0; + float_raise( float_flag_invalid STATUS_VAR); + } else if (v > 0xffff) { + res = 0xffff; + float_raise( float_flag_invalid STATUS_VAR); + } else { + res = v; + } + return res; +} + /* FIXME: This looks broken. */ uint64_t float64_to_uint64 (float64 a STATUS_PARAM) { @@ -5696,7 +6142,9 @@ INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \ int is_quiet STATUS_PARAM ) \ { \ flag aSign, bSign; \ - bits ## s av, bv; \ + uint ## s ## _t av, bv; \ + a = float ## s ## _squash_input_denormal(a STATUS_VAR); \ + b = float ## s ## _squash_input_denormal(b STATUS_VAR); \ \ if (( ( extractFloat ## s ## Exp( a ) == nan_exp ) && \ extractFloat ## s ## Frac( a ) ) || \ @@ -5714,7 +6162,7 @@ INLINE int float ## s ## _compare_internal( float ## s a, float ## s b, \ av = float ## s ## _val(a); \ bv = float ## s ## _val(b); \ if ( aSign != bSign ) { \ - if ( (bits ## s) ( ( av | bv )<<1 ) == 0 ) { \ + if ( (uint ## s ## _t) ( ( av | bv )<<1 ) == 0 ) { \ /* zero case */ \ return float_relation_equal; \ } else { \ @@ -5742,6 +6190,52 @@ int float ## s ## _compare_quiet( float ## s a, float ## s b STATUS_PARAM ) \ COMPARE(32, 0xff) COMPARE(64, 0x7ff) +INLINE int floatx80_compare_internal( floatx80 a, floatx80 b, + int is_quiet STATUS_PARAM ) +{ + flag aSign, bSign; + + if (( ( extractFloatx80Exp( a ) == 0x7fff ) && + ( extractFloatx80Frac( a )<<1 ) ) || + ( ( extractFloatx80Exp( b ) == 0x7fff ) && + ( extractFloatx80Frac( b )<<1 ) )) { + if (!is_quiet || + floatx80_is_signaling_nan( a ) || + floatx80_is_signaling_nan( b ) ) { + float_raise( float_flag_invalid STATUS_VAR); + } + return float_relation_unordered; + } + aSign = extractFloatx80Sign( a ); + bSign = extractFloatx80Sign( b ); + if ( aSign != bSign ) { + + if ( ( ( (uint16_t) ( ( a.high | b.high ) << 1 ) ) == 0) && + ( ( a.low | b.low ) == 0 ) ) { + /* zero case */ + return float_relation_equal; + } else { + return 1 - (2 * aSign); + } + } else { + if (a.low == b.low && a.high == b.high) { + return float_relation_equal; + } else { + return 1 - 2 * (aSign ^ ( lt128( a.high, a.low, b.high, b.low ) )); + } + } +} + +int floatx80_compare( floatx80 a, floatx80 b STATUS_PARAM ) +{ + return floatx80_compare_internal(a, b, 0 STATUS_VAR); +} + +int floatx80_compare_quiet( floatx80 a, floatx80 b STATUS_PARAM ) +{ + return floatx80_compare_internal(a, b, 1 STATUS_VAR); +} + INLINE int float128_compare_internal( float128 a, float128 b, int is_quiet STATUS_PARAM ) { @@ -5786,18 +6280,71 @@ int float128_compare_quiet( float128 a, float128 b STATUS_PARAM ) return float128_compare_internal(a, b, 1 STATUS_VAR); } +/* min() and max() functions. These can't be implemented as + * 'compare and pick one input' because that would mishandle + * NaNs and +0 vs -0. + */ +#define MINMAX(s, nan_exp) \ +INLINE float ## s float ## s ## _minmax(float ## s a, float ## s b, \ + int ismin STATUS_PARAM ) \ +{ \ + flag aSign, bSign; \ + uint ## s ## _t av, bv; \ + a = float ## s ## _squash_input_denormal(a STATUS_VAR); \ + b = float ## s ## _squash_input_denormal(b STATUS_VAR); \ + if (float ## s ## _is_any_nan(a) || \ + float ## s ## _is_any_nan(b)) { \ + return propagateFloat ## s ## NaN(a, b STATUS_VAR); \ + } \ + aSign = extractFloat ## s ## Sign(a); \ + bSign = extractFloat ## s ## Sign(b); \ + av = float ## s ## _val(a); \ + bv = float ## s ## _val(b); \ + if (aSign != bSign) { \ + if (ismin) { \ + return aSign ? a : b; \ + } else { \ + return aSign ? b : a; \ + } \ + } else { \ + if (ismin) { \ + return (aSign ^ (av < bv)) ? a : b; \ + } else { \ + return (aSign ^ (av < bv)) ? b : a; \ + } \ + } \ +} \ + \ +float ## s float ## s ## _min(float ## s a, float ## s b STATUS_PARAM) \ +{ \ + return float ## s ## _minmax(a, b, 1 STATUS_VAR); \ +} \ + \ +float ## s float ## s ## _max(float ## s a, float ## s b STATUS_PARAM) \ +{ \ + return float ## s ## _minmax(a, b, 0 STATUS_VAR); \ +} + +MINMAX(32, 0xff) +MINMAX(64, 0x7ff) + + /* Multiply A by 2 raised to the power N. */ float32 float32_scalbn( float32 a, int n STATUS_PARAM ) { flag aSign; - int16 aExp; - bits32 aSig; + int16_t aExp; + uint32_t aSig; + a = float32_squash_input_denormal(a STATUS_VAR); aSig = extractFloat32Frac( a ); aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { + if ( aSig ) { + return propagateFloat32NaN( a, a STATUS_VAR ); + } return a; } if ( aExp != 0 ) @@ -5805,6 +6352,12 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM ) else if ( aSig == 0 ) return a; + if (n > 0x200) { + n = 0x200; + } else if (n < -0x200) { + n = -0x200; + } + aExp += n - 1; aSig <<= 7; return normalizeRoundAndPackFloat32( aSign, aExp, aSig STATUS_VAR ); @@ -5813,14 +6366,18 @@ float32 float32_scalbn( float32 a, int n STATUS_PARAM ) float64 float64_scalbn( float64 a, int n STATUS_PARAM ) { flag aSign; - int16 aExp; - bits64 aSig; + int16_t aExp; + uint64_t aSig; + a = float64_squash_input_denormal(a STATUS_VAR); aSig = extractFloat64Frac( a ); aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { + if ( aSig ) { + return propagateFloat64NaN( a, a STATUS_VAR ); + } return a; } if ( aExp != 0 ) @@ -5828,6 +6385,12 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM ) else if ( aSig == 0 ) return a; + if (n > 0x1000) { + n = 0x1000; + } else if (n < -0x1000) { + n = -0x1000; + } + aExp += n - 1; aSig <<= 10; return normalizeRoundAndPackFloat64( aSign, aExp, aSig STATUS_VAR ); @@ -5837,19 +6400,29 @@ float64 float64_scalbn( float64 a, int n STATUS_PARAM ) floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM ) { flag aSign; - int16 aExp; - bits64 aSig; + int32_t aExp; + uint64_t aSig; aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); - if ( aExp == 0x7FF ) { + if ( aExp == 0x7FFF ) { + if ( aSig<<1 ) { + return propagateFloatx80NaN( a, a STATUS_VAR ); + } return a; } + if (aExp == 0 && aSig == 0) return a; + if (n > 0x10000) { + n = 0x10000; + } else if (n < -0x10000) { + n = -0x10000; + } + aExp += n; return normalizeRoundAndPackFloatx80( STATUS(floatx80_rounding_precision), aSign, aExp, aSig, 0 STATUS_VAR ); @@ -5860,14 +6433,17 @@ floatx80 floatx80_scalbn( floatx80 a, int n STATUS_PARAM ) float128 float128_scalbn( float128 a, int n STATUS_PARAM ) { flag aSign; - int32 aExp; - bits64 aSig0, aSig1; + int32_t aExp; + uint64_t aSig0, aSig1; aSig1 = extractFloat128Frac1( a ); aSig0 = extractFloat128Frac0( a ); aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { + if ( aSig0 | aSig1 ) { + return propagateFloat128NaN( a, a STATUS_VAR ); + } return a; } if ( aExp != 0 ) @@ -5875,6 +6451,12 @@ float128 float128_scalbn( float128 a, int n STATUS_PARAM ) else if ( aSig0 == 0 && aSig1 == 0 ) return a; + if (n > 0x10000) { + n = 0x10000; + } else if (n < -0x10000) { + n = -0x10000; + } + aExp += n - 1; return normalizeRoundAndPackFloat128( aSign, aExp, aSig0, aSig1 STATUS_VAR ); diff --git a/fpu/softfloat.h b/fpu/softfloat.h index 9528825..5eff085 100644 --- a/fpu/softfloat.h +++ b/fpu/softfloat.h @@ -1,3 +1,9 @@ +/* + * QEMU float support + * + * Derived from SoftFloat. + */ + /*============================================================================ This C header file is part of the SoftFloat IEC/IEEE Floating-point Arithmetic @@ -59,24 +65,15 @@ typedef signed int int32; typedef uint64_t uint64; typedef int64_t int64; -/*---------------------------------------------------------------------------- -| Each of the following `typedef's defines a type that holds integers -| of _exactly_ the number of bits specified. For instance, for most -| implementation of C, `bits16' and `sbits16' should be `typedef'ed to -| `unsigned short int' and `signed short int' (or `short int'), respectively. -*----------------------------------------------------------------------------*/ -typedef uint8_t bits8; -typedef int8_t sbits8; -typedef uint16_t bits16; -typedef int16_t sbits16; -typedef uint32_t bits32; -typedef int32_t sbits32; -typedef uint64_t bits64; -typedef int64_t sbits64; - #define LIT64( a ) a##LL #define INLINE static inline +#if defined(TARGET_MIPS) || defined(TARGET_SH4) || defined(TARGET_UNICORE32) +#define SNAN_BIT_IS_ONE 1 +#else +#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 @@ -120,29 +117,44 @@ enum { //#define USE_SOFTFLOAT_STRUCT_TYPES #ifdef USE_SOFTFLOAT_STRUCT_TYPES typedef struct { + uint16_t v; +} float16; +#define float16_val(x) (((float16)(x)).v) +#define make_float16(x) __extension__ ({ float16 f16_val = {x}; f16_val; }) +#define const_float16(x) { x } +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; }) +#define const_float32(x) { x } typedef struct { uint64_t v; } float64; #define float64_val(x) (((float64)(x)).v) #define make_float64(x) __extension__ ({ float64 f64_val = {x}; f64_val; }) +#define const_float64(x) { x } #else +typedef uint16_t float16; typedef uint32_t float32; typedef uint64_t float64; +#define float16_val(x) (x) #define float32_val(x) (x) #define float64_val(x) (x) +#define make_float16(x) (x) #define make_float32(x) (x) #define make_float64(x) (x) +#define const_float16(x) (x) +#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 { @@ -180,7 +192,8 @@ enum { float_flag_divbyzero = 4, float_flag_overflow = 8, float_flag_underflow = 16, - float_flag_inexact = 32 + float_flag_inexact = 32, + float_flag_input_denormal = 64 }; typedef struct float_status { @@ -190,16 +203,27 @@ typedef struct float_status { #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? */ + flag flush_inputs_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_float_detect_tininess(int val STATUS_PARAM) +{ + STATUS(float_detect_tininess) = val; +} INLINE void set_flush_to_zero(flag val STATUS_PARAM) { STATUS(flush_to_zero) = val; } +INLINE void set_flush_inputs_to_zero(flag val STATUS_PARAM) +{ + STATUS(flush_inputs_to_zero) = val; +} INLINE void set_default_nan_mode(flag val STATUS_PARAM) { STATUS(default_nan_mode) = val; @@ -221,42 +245,62 @@ void float_raise( int8 flags STATUS_PARAM); /*---------------------------------------------------------------------------- | Software IEC/IEEE integer-to-floating-point conversion routines. *----------------------------------------------------------------------------*/ -float32 int32_to_float32( int STATUS_PARAM ); -float64 int32_to_float64( int STATUS_PARAM ); +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( int STATUS_PARAM ); +floatx80 int32_to_floatx80( int32 STATUS_PARAM ); #endif #ifdef FLOAT128 -float128 int32_to_float128( int STATUS_PARAM ); +float128 int32_to_float128( int32 STATUS_PARAM ); #endif -float32 int64_to_float32( int64_t STATUS_PARAM ); -float32 uint64_to_float32( uint64_t STATUS_PARAM ); -float64 int64_to_float64( int64_t STATUS_PARAM ); -float64 uint64_to_float64( uint64_t STATUS_PARAM ); +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_t STATUS_PARAM ); +floatx80 int64_to_floatx80( int64 STATUS_PARAM ); #endif #ifdef FLOAT128 -float128 int64_to_float128( int64_t STATUS_PARAM ); +float128 int64_to_float128( int64 STATUS_PARAM ); #endif /*---------------------------------------------------------------------------- | Software half-precision conversion routines. *----------------------------------------------------------------------------*/ -bits16 float32_to_float16( float32, flag STATUS_PARAM ); -float32 float16_to_float32( bits16, flag STATUS_PARAM ); +float16 float32_to_float16( float32, flag STATUS_PARAM ); +float32 float16_to_float32( float16, flag STATUS_PARAM ); + +/*---------------------------------------------------------------------------- +| Software half-precision operations. +*----------------------------------------------------------------------------*/ +int float16_is_quiet_nan( float16 ); +int float16_is_signaling_nan( float16 ); +float16 float16_maybe_silence_nan( float16 ); + +/*---------------------------------------------------------------------------- +| The pattern for a default generated half-precision NaN. +*----------------------------------------------------------------------------*/ +#if defined(TARGET_ARM) +#define float16_default_nan make_float16(0x7E00) +#elif SNAN_BIT_IS_ONE +#define float16_default_nan make_float16(0x7DFF) +#else +#define float16_default_nan make_float16(0xFE00) +#endif /*---------------------------------------------------------------------------- | Software IEC/IEEE single-precision conversion routines. *----------------------------------------------------------------------------*/ -int float32_to_int32( float32 STATUS_PARAM ); -int float32_to_int32_round_to_zero( float32 STATUS_PARAM ); -unsigned int float32_to_uint32( float32 STATUS_PARAM ); -unsigned int float32_to_uint32_round_to_zero( float32 STATUS_PARAM ); -int64_t float32_to_int64( float32 STATUS_PARAM ); -int64_t float32_to_int64_round_to_zero( float32 STATUS_PARAM ); +int16 float32_to_int16_round_to_zero( float32 STATUS_PARAM ); +unsigned int float32_to_uint16_round_to_zero( float32 STATUS_PARAM ); +int32 float32_to_int32( float32 STATUS_PARAM ); +int32 float32_to_int32_round_to_zero( float32 STATUS_PARAM ); +uint32 float32_to_uint32( float32 STATUS_PARAM ); +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 ); @@ -280,22 +324,33 @@ 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 ); -int float32_eq_signaling( float32, float32 STATUS_PARAM ); +int float32_unordered( float32, float32 STATUS_PARAM ); +int float32_eq_quiet( float32, float32 STATUS_PARAM ); int float32_le_quiet( float32, float32 STATUS_PARAM ); int float32_lt_quiet( float32, float32 STATUS_PARAM ); +int float32_unordered_quiet( float32, float32 STATUS_PARAM ); int float32_compare( float32, float32 STATUS_PARAM ); int float32_compare_quiet( float32, float32 STATUS_PARAM ); -int float32_is_nan( float32 ); +float32 float32_min(float32, float32 STATUS_PARAM); +float32 float32_max(float32, float32 STATUS_PARAM); +int float32_is_quiet_nan( float32 ); int float32_is_signaling_nan( float32 ); +float32 float32_maybe_silence_nan( float32 ); float32 float32_scalbn( float32, int STATUS_PARAM ); INLINE float32 float32_abs(float32 a) { + /* Note that abs does *not* handle NaN specially, nor does + * it flush denormal inputs to zero. + */ return make_float32(float32_val(a) & 0x7fffffff); } INLINE float32 float32_chs(float32 a) { + /* Note that chs does *not* handle NaN specially, nor does + * it flush denormal inputs to zero. + */ return make_float32(float32_val(a) ^ 0x80000000); } @@ -314,21 +369,55 @@ INLINE int float32_is_zero(float32 a) return (float32_val(a) & 0x7fffffff) == 0; } +INLINE int float32_is_any_nan(float32 a) +{ + return ((float32_val(a) & ~(1 << 31)) > 0x7f800000UL); +} + +INLINE int float32_is_zero_or_denormal(float32 a) +{ + return (float32_val(a) & 0x7f800000) == 0; +} + +INLINE float32 float32_set_sign(float32 a, int sign) +{ + return make_float32((float32_val(a) & 0x7fffffff) | (sign << 31)); +} + #define float32_zero make_float32(0) #define float32_one make_float32(0x3f800000) #define float32_ln2 make_float32(0x3f317218) +#define float32_pi make_float32(0x40490fdb) +#define float32_half make_float32(0x3f000000) +#define float32_infinity make_float32(0x7f800000) + + +/*---------------------------------------------------------------------------- +| The pattern for a default generated single-precision NaN. +*----------------------------------------------------------------------------*/ +#if defined(TARGET_SPARC) +#define float32_default_nan make_float32(0x7FFFFFFF) +#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) +#define float32_default_nan make_float32(0x7FC00000) +#elif SNAN_BIT_IS_ONE +#define float32_default_nan make_float32(0x7FBFFFFF) +#else +#define float32_default_nan make_float32(0xFFC00000) +#endif /*---------------------------------------------------------------------------- | Software IEC/IEEE double-precision conversion routines. *----------------------------------------------------------------------------*/ -int float64_to_int32( float64 STATUS_PARAM ); -int float64_to_int32_round_to_zero( float64 STATUS_PARAM ); -unsigned int float64_to_uint32( float64 STATUS_PARAM ); -unsigned int float64_to_uint32_round_to_zero( float64 STATUS_PARAM ); -int64_t float64_to_int64( float64 STATUS_PARAM ); -int64_t float64_to_int64_round_to_zero( float64 STATUS_PARAM ); -uint64_t float64_to_uint64 (float64 a STATUS_PARAM); -uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM); +int16 float64_to_int16_round_to_zero( float64 STATUS_PARAM ); +unsigned int float64_to_uint16_round_to_zero( float64 STATUS_PARAM ); +int32 float64_to_int32( float64 STATUS_PARAM ); +int32 float64_to_int32_round_to_zero( float64 STATUS_PARAM ); +uint32 float64_to_uint32( float64 STATUS_PARAM ); +uint32 float64_to_uint32_round_to_zero( float64 STATUS_PARAM ); +int64 float64_to_int64( float64 STATUS_PARAM ); +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 ); @@ -352,22 +441,33 @@ 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 ); -int float64_eq_signaling( float64, float64 STATUS_PARAM ); +int float64_unordered( float64, float64 STATUS_PARAM ); +int float64_eq_quiet( float64, float64 STATUS_PARAM ); int float64_le_quiet( float64, float64 STATUS_PARAM ); int float64_lt_quiet( float64, float64 STATUS_PARAM ); +int float64_unordered_quiet( float64, float64 STATUS_PARAM ); int float64_compare( float64, float64 STATUS_PARAM ); int float64_compare_quiet( float64, float64 STATUS_PARAM ); -int float64_is_nan( float64 a ); +float64 float64_min(float64, float64 STATUS_PARAM); +float64 float64_max(float64, float64 STATUS_PARAM); +int float64_is_quiet_nan( float64 a ); int float64_is_signaling_nan( float64 ); +float64 float64_maybe_silence_nan( float64 ); float64 float64_scalbn( float64, int STATUS_PARAM ); INLINE float64 float64_abs(float64 a) { + /* Note that abs does *not* handle NaN specially, nor does + * it flush denormal inputs to zero. + */ return make_float64(float64_val(a) & 0x7fffffffffffffffLL); } INLINE float64 float64_chs(float64 a) { + /* Note that chs does *not* handle NaN specially, nor does + * it flush denormal inputs to zero. + */ return make_float64(float64_val(a) ^ 0x8000000000000000LL); } @@ -386,19 +486,46 @@ INLINE int float64_is_zero(float64 a) return (float64_val(a) & 0x7fffffffffffffffLL) == 0; } +INLINE int float64_is_any_nan(float64 a) +{ + return ((float64_val(a) & ~(1ULL << 63)) > 0x7ff0000000000000ULL); +} + +INLINE float64 float64_set_sign(float64 a, int sign) +{ + return make_float64((float64_val(a) & 0x7fffffffffffffffULL) + | ((int64_t)sign << 63)); +} + #define float64_zero make_float64(0) #define float64_one make_float64(0x3ff0000000000000LL) #define float64_ln2 make_float64(0x3fe62e42fefa39efLL) +#define float64_pi make_float64(0x400921fb54442d18LL) +#define float64_half make_float64(0x3fe0000000000000LL) +#define float64_infinity make_float64(0x7ff0000000000000LL) + +/*---------------------------------------------------------------------------- +| The pattern for a default generated double-precision NaN. +*----------------------------------------------------------------------------*/ +#if defined(TARGET_SPARC) +#define float64_default_nan make_float64(LIT64( 0x7FFFFFFFFFFFFFFF )) +#elif defined(TARGET_PPC) || defined(TARGET_ARM) || defined(TARGET_ALPHA) +#define float64_default_nan make_float64(LIT64( 0x7FF8000000000000 )) +#elif SNAN_BIT_IS_ONE +#define float64_default_nan make_float64(LIT64( 0x7FF7FFFFFFFFFFFF )) +#else +#define float64_default_nan make_float64(LIT64( 0xFFF8000000000000 )) +#endif #ifdef FLOATX80 /*---------------------------------------------------------------------------- | Software IEC/IEEE extended double-precision conversion routines. *----------------------------------------------------------------------------*/ -int floatx80_to_int32( floatx80 STATUS_PARAM ); -int floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM ); -int64_t floatx80_to_int64( floatx80 STATUS_PARAM ); -int64_t floatx80_to_int64_round_to_zero( floatx80 STATUS_PARAM ); +int32 floatx80_to_int32( floatx80 STATUS_PARAM ); +int32 floatx80_to_int32_round_to_zero( floatx80 STATUS_PARAM ); +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 @@ -418,11 +545,16 @@ floatx80 floatx80_sqrt( floatx80 STATUS_PARAM ); int floatx80_eq( floatx80, floatx80 STATUS_PARAM ); int floatx80_le( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt( floatx80, floatx80 STATUS_PARAM ); -int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM ); +int floatx80_unordered( floatx80, floatx80 STATUS_PARAM ); +int floatx80_eq_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM ); int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM ); -int floatx80_is_nan( floatx80 ); +int floatx80_unordered_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_compare( floatx80, floatx80 STATUS_PARAM ); +int floatx80_compare_quiet( floatx80, floatx80 STATUS_PARAM ); +int floatx80_is_quiet_nan( floatx80 ); int floatx80_is_signaling_nan( floatx80 ); +floatx80 floatx80_maybe_silence_nan( floatx80 ); floatx80 floatx80_scalbn( floatx80, int STATUS_PARAM ); INLINE floatx80 floatx80_abs(floatx80 a) @@ -439,7 +571,7 @@ INLINE floatx80 floatx80_chs(floatx80 a) INLINE int floatx80_is_infinity(floatx80 a) { - return (a.high & 0x7fff) == 0x7fff && a.low == 0; + return (a.high & 0x7fff) == 0x7fff && a.low == 0x8000000000000000LL; } INLINE int floatx80_is_neg(floatx80 a) @@ -452,6 +584,31 @@ INLINE int floatx80_is_zero(floatx80 a) return (a.high & 0x7fff) == 0 && a.low == 0; } +INLINE int floatx80_is_any_nan(floatx80 a) +{ + return ((a.high & 0x7fff) == 0x7fff) && (a.low<<1); +} + +#define floatx80_zero make_floatx80(0x0000, 0x0000000000000000LL) +#define floatx80_one make_floatx80(0x3fff, 0x8000000000000000LL) +#define floatx80_ln2 make_floatx80(0x3ffe, 0xb17217f7d1cf79acLL) +#define floatx80_pi make_floatx80(0x4000, 0xc90fdaa22168c235LL) +#define floatx80_half make_floatx80(0x3ffe, 0x8000000000000000LL) +#define floatx80_infinity make_floatx80(0x7fff, 0x8000000000000000LL) + +/*---------------------------------------------------------------------------- +| The pattern for a default generated extended double-precision NaN. The +| `high' and `low' values hold the most- and least-significant bits, +| respectively. +*----------------------------------------------------------------------------*/ +#if SNAN_BIT_IS_ONE +#define floatx80_default_nan_high 0x7FFF +#define floatx80_default_nan_low LIT64( 0xBFFFFFFFFFFFFFFF ) +#else +#define floatx80_default_nan_high 0xFFFF +#define floatx80_default_nan_low LIT64( 0xC000000000000000 ) +#endif + #endif #ifdef FLOAT128 @@ -459,10 +616,10 @@ INLINE int floatx80_is_zero(floatx80 a) /*---------------------------------------------------------------------------- | Software IEC/IEEE quadruple-precision conversion routines. *----------------------------------------------------------------------------*/ -int float128_to_int32( float128 STATUS_PARAM ); -int float128_to_int32_round_to_zero( float128 STATUS_PARAM ); -int64_t float128_to_int64( float128 STATUS_PARAM ); -int64_t float128_to_int64_round_to_zero( float128 STATUS_PARAM ); +int32 float128_to_int32( float128 STATUS_PARAM ); +int32 float128_to_int32_round_to_zero( float128 STATUS_PARAM ); +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 @@ -482,13 +639,16 @@ float128 float128_sqrt( float128 STATUS_PARAM ); int float128_eq( float128, float128 STATUS_PARAM ); int float128_le( float128, float128 STATUS_PARAM ); int float128_lt( float128, float128 STATUS_PARAM ); -int float128_eq_signaling( float128, float128 STATUS_PARAM ); +int float128_unordered( float128, float128 STATUS_PARAM ); +int float128_eq_quiet( float128, float128 STATUS_PARAM ); int float128_le_quiet( float128, float128 STATUS_PARAM ); int float128_lt_quiet( float128, float128 STATUS_PARAM ); +int float128_unordered_quiet( float128, float128 STATUS_PARAM ); int float128_compare( float128, float128 STATUS_PARAM ); int float128_compare_quiet( float128, float128 STATUS_PARAM ); -int float128_is_nan( float128 ); +int float128_is_quiet_nan( float128 ); int float128_is_signaling_nan( float128 ); +float128 float128_maybe_silence_nan( float128 ); float128 float128_scalbn( float128, int STATUS_PARAM ); INLINE float128 float128_abs(float128 a) @@ -518,6 +678,24 @@ INLINE int float128_is_zero(float128 a) return (a.high & 0x7fffffffffffffffLL) == 0 && a.low == 0; } +INLINE int float128_is_any_nan(float128 a) +{ + return ((a.high >> 48) & 0x7fff) == 0x7fff && + ((a.low != 0) || ((a.high & 0xffffffffffffLL) != 0)); +} + +/*---------------------------------------------------------------------------- +| The pattern for a default generated quadruple-precision NaN. The `high' and +| `low' values hold the most- and least-significant bits, respectively. +*----------------------------------------------------------------------------*/ +#if SNAN_BIT_IS_ONE +#define float128_default_nan_high LIT64( 0x7FFF7FFFFFFFFFFF ) +#define float128_default_nan_low LIT64( 0xFFFFFFFFFFFFFFFF ) +#else +#define float128_default_nan_high LIT64( 0xFFFF800000000000 ) +#define float128_default_nan_low LIT64( 0x0000000000000000 ) +#endif + #endif #else /* CONFIG_SOFTFLOAT */ -- cgit v1.1