diff mbox

[4/5] softfloat: add float{32, 64, x80, 128}_unordered() functions

Message ID 1302462807-8795-4-git-send-email-aurelien@aurel32.net
State New
Headers show

Commit Message

Aurelien Jarno April 10, 2011, 7:13 p.m. UTC
Add float{32,64,x80,128}_unordered() functions to softfloat, matching
the softfloat-native ones. This allow target-i386/ops_sse.h to be
compiled with softfloat.

Cc: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
---
 fpu/softfloat.c |   88 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 fpu/softfloat.h |    4 ++
 2 files changed, 92 insertions(+), 0 deletions(-)

Comments

Peter Maydell April 10, 2011, 7:59 p.m. UTC | #1
On 10 April 2011 20:13, Aurelien Jarno <aurelien@aurel32.net> wrote:
> Add float{32,64,x80,128}_unordered() functions to softfloat, matching
> the softfloat-native ones. This allow target-i386/ops_sse.h to be
> compiled with softfloat.

I guess you could have made the x86 target use float*_compare()
instead, but I agree that it makes sense to have the unordered()
comparison to match the other specific-comparison ops.

>  /*----------------------------------------------------------------------------
> +| Returns 1 if the single-precision floating-point values `a' and `b' cannot
> +| be compared, and 0 otherwise. The comparison is performed according to the
> +| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
> +*----------------------------------------------------------------------------*/
> +
> +int float32_unordered( 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;
> +}

So the NaN signalling semantics here are that we raise Invalid
for an SNaN but not for a QNaN. That's correct for the x86 op
we're implementing, but the float*_lt, _le and _compare functions
use the _quiet suffix for these semantics (with plain float*_lt
etc being "raise Invalid for both QNaN and SNaN"). So I think
these functions should be float*_unordered_quiet().

Annoyingly for eq the two versions use a different convention,
so we have float*_eq [raise Invalid only if SNaN] and
float*_eq_signaling [for any NaN] -- ideally that inconsistency
should be fixed...

> +int float64_unordered( 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 0;
> +    }
> +    return 1;
> +}

You've got the sense the wrong way round on this one, I think.

I note that target-mips has a private float32_is_unordered()
and float64_is_unordered() which could probably be cleaned
up to use these instead. You'd need to implement both the
float*_unordered() and float*_unordered_quiet() versions.

-- PMM
Aurelien Jarno April 10, 2011, 9 p.m. UTC | #2
On Sun, Apr 10, 2011 at 08:59:04PM +0100, Peter Maydell wrote:
> On 10 April 2011 20:13, Aurelien Jarno <aurelien@aurel32.net> wrote:
> > Add float{32,64,x80,128}_unordered() functions to softfloat, matching
> > the softfloat-native ones. This allow target-i386/ops_sse.h to be
> > compiled with softfloat.
> 
> I guess you could have made the x86 target use float*_compare()
> instead, but I agree that it makes sense to have the unordered()
> comparison to match the other specific-comparison ops.

Given it's used in the same macro which also handle float*_le, _ge and
so on, it was easier that way. Also float*_compare() is probably a bit
slower as it does a bit more stuff.

> >  /*----------------------------------------------------------------------------
> > +| Returns 1 if the single-precision floating-point values `a' and `b' cannot
> > +| be compared, and 0 otherwise. The comparison is performed according to the
> > +| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
> > +*----------------------------------------------------------------------------*/
> > +
> > +int float32_unordered( 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;
> > +}
> 
> So the NaN signalling semantics here are that we raise Invalid
> for an SNaN but not for a QNaN. That's correct for the x86 op
> we're implementing, but the float*_lt, _le and _compare functions
> use the _quiet suffix for these semantics (with plain float*_lt
> etc being "raise Invalid for both QNaN and SNaN"). So I think
> these functions should be float*_unordered_quiet().

Ok, will change that.

> Annoyingly for eq the two versions use a different convention,
> so we have float*_eq [raise Invalid only if SNaN] and
> float*_eq_signaling [for any NaN] -- ideally that inconsistency
> should be fixed...

I'll try to send a patch for that in my next version of the series.

> > +int float64_unordered( 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 0;
> > +    }
> > +    return 1;
> > +}
> 
> You've got the sense the wrong way round on this one, I think.

Yup, good catch.

> I note that target-mips has a private float32_is_unordered()
> and float64_is_unordered() which could probably be cleaned
> up to use these instead. You'd need to implement both the
> float*_unordered() and float*_unordered_quiet() versions.
> 

I missed that when running grep. I'll also add that in my next version
of the series (so that will be x86 + mips at the end).

Thanks for the review!
diff mbox

Patch

diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 03fb948..9f94b0e 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -2481,6 +2481,29 @@  int float32_lt_quiet( float32 a, float32 b STATUS_PARAM )
 }
 
 /*----------------------------------------------------------------------------
+| Returns 1 if the single-precision floating-point values `a' and `b' cannot
+| be compared, and 0 otherwise. The comparison is performed according to the
+| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float32_unordered( 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
@@ -3704,6 +3727,28 @@  int float64_lt_quiet( float64 a, float64 b STATUS_PARAM )
 
 }
 
+/*----------------------------------------------------------------------------
+| Returns 1 if the double-precision floating-point values `a' and `b' cannot
+| be compared, and 0 otherwise. The comparison is performed according to the
+| IEC/IEEE Standard for Binary Floating-Point Arithmetic.
+*----------------------------------------------------------------------------*/
+
+int float64_unordered( 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 0;
+    }
+    return 1;
+}
+
 #ifdef FLOATX80
 
 /*----------------------------------------------------------------------------
@@ -4695,6 +4740,27 @@  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. 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 ) )
+       ) {
+        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
@@ -5816,6 +5882,28 @@  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. 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 ) ) )
+       ) {
+        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 */
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 90f4250..db97be9 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -322,6 +322,7 @@  int float32_lt( float32, float32 STATUS_PARAM );
 int float32_eq_signaling( float32, float32 STATUS_PARAM );
 int float32_le_quiet( float32, float32 STATUS_PARAM );
 int float32_lt_quiet( float32, float32 STATUS_PARAM );
+int float32_unordered( float32, float32 STATUS_PARAM );
 int float32_compare( float32, float32 STATUS_PARAM );
 int float32_compare_quiet( float32, float32 STATUS_PARAM );
 float32 float32_min(float32, float32 STATUS_PARAM);
@@ -436,6 +437,7 @@  int float64_lt( float64, float64 STATUS_PARAM );
 int float64_eq_signaling( float64, float64 STATUS_PARAM );
 int float64_le_quiet( float64, float64 STATUS_PARAM );
 int float64_lt_quiet( float64, float64 STATUS_PARAM );
+int float64_unordered( float64, float64 STATUS_PARAM );
 int float64_compare( float64, float64 STATUS_PARAM );
 int float64_compare_quiet( float64, float64 STATUS_PARAM );
 float64 float64_min(float64, float64 STATUS_PARAM);
@@ -537,6 +539,7 @@  int floatx80_lt( floatx80, floatx80 STATUS_PARAM );
 int floatx80_eq_signaling( floatx80, floatx80 STATUS_PARAM );
 int floatx80_le_quiet( floatx80, floatx80 STATUS_PARAM );
 int floatx80_lt_quiet( floatx80, floatx80 STATUS_PARAM );
+int floatx80_unordered( floatx80, floatx80 STATUS_PARAM );
 int floatx80_is_quiet_nan( floatx80 );
 int floatx80_is_signaling_nan( floatx80 );
 floatx80 floatx80_maybe_silence_nan( floatx80 );
@@ -620,6 +623,7 @@  int float128_lt( float128, float128 STATUS_PARAM );
 int float128_eq_signaling( float128, float128 STATUS_PARAM );
 int float128_le_quiet( float128, float128 STATUS_PARAM );
 int float128_lt_quiet( float128, float128 STATUS_PARAM );
+int float128_unordered( float128, float128 STATUS_PARAM );
 int float128_compare( float128, float128 STATUS_PARAM );
 int float128_compare_quiet( float128, float128 STATUS_PARAM );
 int float128_is_quiet_nan( float128 );