Fix softfloat NaN handling
RFC PATCH 1/1 Fix softfloat NaN handling
Hello All,
The relevant IEEE standards don't define if a set or a clear bit is used to distinguish between QNaN and SNaN. MIPS, and apparently PA RISC, made a different choice than the rest of the industry.
The appended patch accounts for this, it fixes a number of failures on MIPS, none of those appears to be covered by e.g. classic paranoia.
It also changes some things for the other architectures, that's why I ask for comments:
- float32_is_nan tests now for <=, since the set MSB of the mantissa is enough to make it a proper QNaN.
- float64_is_nan has the same change, plus a changed bitmask which is consistent to the QNaN definition.
Thiemo
fpu/softfloat-specialize.h +38 -10
@@ -61,7 +61,11 @@/*---------------------------------------------------------------------------- | The pattern for a default generated single-precision NaN. *----------------------------------------------------------------------------*/ +#if defined(TARGET_MIPS ) || defined(TARGET_HPPA ) +#define float32_default_nan 0xFF800000 +#else #define float32_default_nan 0xFFC00000 +#endif /*---------------------------------------------------------------------------- | Returns 1 if the single-precision floating-point value `a' is a NaN;
@@ -70,9 +74,11 @@int float32_is_nan (float32 a ) { - -return (0xFF000000 < (bits32) ( a<<1 ) ); - +#if defined(TARGET_MIPS ) || defined(TARGET_HPPA ) +return ( ( ( a>>22 ) &0x1FF ) ==0x1FE ) && ( a &0x003FFFFF ); +#else +return (0xFF800000 <= (bits32) ( a<<1 ) ); +#endif }/*----------------------------------------------------------------------------
@@ -82,9 +88,11 @@int float32_is_signaling_nan (float32 a ) { - +#if defined(TARGET_MIPS ) || defined(TARGET_HPPA ) +return (0xFF800000 <= (bits32) ( a<<1 ) ); +#else return ( ( ( a>>22 ) &0x1FF ) ==0x1FE ) && ( a &0x003FFFFF ); - +#endif }/*----------------------------------------------------------------------------
@@ -131,8 +139,13 @@ aIsSignalingNaN =float32_is_signaling_nan ( a ); bIsNaN =float32_is_nan ( b ); bIsSignalingNaN =float32_is_signaling_nan ( b ); +#if defined(TARGET_MIPS ) || defined(TARGET_HPPA ) + a &= ~0x00400000 ; + b &= ~0x00400000 ; +#else a |=0x00400000 ; b |=0x00400000 ; +#endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);if ( aIsSignalingNaN ) {if ( bIsSignalingNaN ) goto returnLargerSignificand;
@@ -154,7 +167,11 @@/*---------------------------------------------------------------------------- | The pattern for a default generated double-precision NaN. *----------------------------------------------------------------------------*/ +#if defined(TARGET_MIPS ) || defined(TARGET_HPPA ) +#define float64_default_nan LIT64( 0xFFF0000000000000 ) +#else #define float64_default_nan LIT64( 0xFFF8000000000000 ) +#endif /*---------------------------------------------------------------------------- | Returns 1 if the double-precision floating-point value `a' is a NaN;
@@ -163,9 +180,13 @@int float64_is_nan (float64 a ) { - -return (LIT64 (0xFFE0000000000000 ) < (bits64) ( a<<1 ) ); - +#if defined(TARGET_MIPS ) || defined(TARGET_HPPA ) +return + ( ( ( a>>51 ) &0xFFF ) ==0xFFE ) + && ( a &LIT64 (0x0007FFFFFFFFFFFF ) ); +#else +return (LIT64 (0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); +#endif }/*----------------------------------------------------------------------------
@@ -175,11 +196,13 @@int float64_is_signaling_nan (float64 a ) { - +#if defined(TARGET_MIPS ) || defined(TARGET_HPPA ) +return (LIT64 (0xFFF0000000000000 ) <= (bits64) ( a<<1 ) ); +#else return ( ( ( a>>51 ) &0xFFF ) ==0xFFE ) && ( a &LIT64 (0x0007FFFFFFFFFFFF ) ); - +#endif }/*----------------------------------------------------------------------------
@@ -229,8 +252,13 @@ aIsSignalingNaN =float64_is_signaling_nan ( a ); bIsNaN =float64_is_nan ( b ); bIsSignalingNaN =float64_is_signaling_nan ( b ); +#if defined(TARGET_MIPS ) || defined(TARGET_HPPA ) + a &= ~LIT64 (0x0008000000000000 ); + b &= ~LIT64 (0x0008000000000000 ); +#else a |=LIT64 (0x0008000000000000 ); b |=LIT64 (0x0008000000000000 ); +#endif if ( aIsSignalingNaN | bIsSignalingNaN ) float_raise( float_flag_invalid STATUS_VAR);if ( aIsSignalingNaN ) {if ( bIsSignalingNaN ) goto returnLargerSignificand;
Quoted 5 lines · Thiemo Seufer
Hello All,
The relevant IEEE standards don't define if a set or a clear bit is used to distinguish between QNaN and SNaN. MIPS, and apparently PA RISC, made a different choice than the rest of the industry.
On Sparc, the rule is as follows:
SNaN: sign undefined, exponent 255, mantissa 0xxx...and at least one bit must be nonzero
QNaN: sign undefined, exponent 255, mantissa 1xxx...
Is this the same as MIPS?
Quoted 7 lines · Blue Swirl
Quoted 5 lines · Thiemo Seufer
Hello All,
The relevant IEEE standards don't define if a set or a clear bit is used to distinguish between QNaN and SNaN. MIPS, and apparently PA RISC, made a different choice than the rest of the industry.
Quoted 7 lines
On Sparc, the rule is as follows:
SNaN: sign undefined, exponent 255, mantissa 0xxx...and at least one bit must be nonzero
QNaN: sign undefined, exponent 255, mantissa 1xxx...Is this the same as MIPS?
For MIPS, and allegedly HPPA, the meaning of the highest bit in the mantissa is inverted. IOW, 0xxx... is a QNaN, 1xxx... is a SNaN. The rest is the same, and AFAIK mandated by the standard.
Thiemo