Skip to contentSkip to conversation

Fix softfloat NaN handling

RFC PATCH In review Thiemo Seufer 2 participants 3 messages May 9, 2007

lore
Share & tools
lore
#0 lore raw

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
Index: qemu-cvs/fpu/softfloat-specialize.h
===================================================================
@@ -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;
#1 lore raw
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?

#2 lore raw
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