qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v3 0/6] target-arm: Fix floating point conversions
@ 2011-02-10 11:28 Peter Maydell
  2011-02-10 11:28 ` [Qemu-devel] [PATCH v3 1/6] softfloat: Add float16 type and float16 NaN handling functions Peter Maydell
                   ` (6 more replies)
  0 siblings, 7 replies; 8+ messages in thread
From: Peter Maydell @ 2011-02-10 11:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Christophe Lyon, patches

This patchset fixes two issues:
 * default_nan_mode not being honoured for float-to-float conversions
 * half precision conversions being broken in a number of ways as
   well as not handling default_nan_mode.

With this patchset qemu passes random-instruction-selection tests
for VCVT.F32.F16, VCVT.F16.F32, VCVTB and VCVTT, in both IEEE and
non-IEEE modes, with and without default-NaN behaviour.

Christophe: this patchset includes your softfloat v3 patch, although
I have split it up a little to keep the float16 bits separate.

Changes since v2:
 * added STRUCT_TYPES version of float16 and fixed various
   places which needed a make_float16()/float16_val() in order
   to compile with STRUCT_TYPES enabled
 * s/bits16/float16/ in patch 3 as suggested by Aurelien
 * fixed the types in the f16-related ARM helper wrappers in patch 6

Patch 2 is unchanged and so I've added Aurelien's reviewed-by
signoff; the others all changed, although mostly in minor ways.

(Compiling with STRUCT_TYPES enabled also needs some fixes to
existing float32/float64 code; I'll send a separate patchset
for that.)


Christophe Lyon (1):
  softfloat: Honour default_nan_mode for float-to-float conversions

Peter Maydell (5):
  softfloat: Add float16 type and float16 NaN handling functions
  softfloat: Fix single-to-half precision float conversions
  softfloat: Correctly handle NaNs in float16_to_float32()
  target-arm: Silence NaNs resulting from half-precision conversions
  target-arm: Use standard FPSCR for Neon half-precision operations

 fpu/softfloat-specialize.h |  130 ++++++++++++++++++++++++++++++++++++++++++--
 fpu/softfloat.c            |  100 ++++++++++++++++++++++------------
 fpu/softfloat.h            |   19 ++++++-
 target-arm/helper.c        |   38 +++++++++++--
 target-arm/helpers.h       |    2 +
 target-arm/translate.c     |   16 +++---
 6 files changed, 251 insertions(+), 54 deletions(-)

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH v3 1/6] softfloat: Add float16 type and float16 NaN handling functions
  2011-02-10 11:28 [Qemu-devel] [PATCH v3 0/6] target-arm: Fix floating point conversions Peter Maydell
@ 2011-02-10 11:28 ` Peter Maydell
  2011-02-10 11:28 ` [Qemu-devel] [PATCH v3 2/6] softfloat: Honour default_nan_mode for float-to-float conversions Peter Maydell
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Peter Maydell @ 2011-02-10 11:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Christophe Lyon, patches

Add a float16 type to softfloat, rather than using bits16 directly.
Also add the missing functions float16_is_quiet_nan(),
float16_is_signaling_nan() and float16_maybe_silence_nan(),
which are needed for the float16 conversion routines.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 fpu/softfloat-specialize.h |   63 ++++++++++++++++++++++++++++++++++++++++++++
 fpu/softfloat.c            |   44 +++++++++++++++++++++++++-----
 fpu/softfloat.h            |   19 ++++++++++++-
 target-arm/helper.c        |    4 +-
 4 files changed, 118 insertions(+), 12 deletions(-)

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index eb644b2..495f6f3 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -57,6 +57,69 @@ typedef struct {
 } commonNaNT;
 
 /*----------------------------------------------------------------------------
+| 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
+
+/*----------------------------------------------------------------------------
+| Returns 1 if the half-precision floating-point value `a' is a quiet
+| NaN; otherwise returns 0.
+*----------------------------------------------------------------------------*/
+
+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
+    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)
+        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_;
+}
+
+/*----------------------------------------------------------------------------
 | The pattern for a default generated single-precision NaN.
 *----------------------------------------------------------------------------*/
 #if defined(TARGET_SPARC)
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 17842f4..635c74c 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -67,6 +67,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
@@ -2713,23 +2740,24 @@ 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, bits16 zSig)
 {
-    return (((bits32)zSign) << 15) + (((bits32)zExp) << 10) + zSig;
+    return make_float16(
+        (((bits32)zSign) << 15) + (((bits32)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;
 
-    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) {
@@ -2753,7 +2781,7 @@ 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;
diff --git a/fpu/softfloat.h b/fpu/softfloat.h
index 4a5345c..2296adb 100644
--- a/fpu/softfloat.h
+++ b/fpu/softfloat.h
@@ -120,6 +120,11 @@ 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; })
+typedef struct {
     uint32_t v;
 } float32;
 /* The cast ensures an error if the wrong type is passed.  */
@@ -131,10 +136,13 @@ typedef struct {
 #define float64_val(x) (((float64)(x)).v)
 #define make_float64(x) __extension__ ({ float64 f64_val = {x}; f64_val; })
 #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)
 #endif
@@ -253,8 +261,15 @@ float128 int64_to_float128( int64_t STATUS_PARAM );
 /*----------------------------------------------------------------------------
 | 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 );
 
 /*----------------------------------------------------------------------------
 | Software IEC/IEEE single-precision conversion routines.
diff --git a/target-arm/helper.c b/target-arm/helper.c
index d46defc..d29c42b 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2627,14 +2627,14 @@ float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, CPUState *env)
 {
     float_status *s = &env->vfp.fp_status;
     int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
-    return float16_to_float32(a, ieee, s);
+    return float16_to_float32(make_float16(a), ieee, s);
 }
 
 uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUState *env)
 {
     float_status *s = &env->vfp.fp_status;
     int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
-    return float32_to_float16(a, ieee, s);
+    return float16_val(float32_to_float16(a, ieee, s));
 }
 
 float32 HELPER(recps_f32)(float32 a, float32 b, CPUState *env)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH v3 2/6] softfloat: Honour default_nan_mode for float-to-float conversions
  2011-02-10 11:28 [Qemu-devel] [PATCH v3 0/6] target-arm: Fix floating point conversions Peter Maydell
  2011-02-10 11:28 ` [Qemu-devel] [PATCH v3 1/6] softfloat: Add float16 type and float16 NaN handling functions Peter Maydell
@ 2011-02-10 11:28 ` Peter Maydell
  2011-02-10 11:28 ` [Qemu-devel] [PATCH v3 3/6] softfloat: Fix single-to-half precision float conversions Peter Maydell
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Peter Maydell @ 2011-02-10 11:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Christophe Lyon, patches

From: Christophe Lyon <christophe.lyon@st.com>

Honour the default_nan_mode flag when doing conversions between
different floating point formats, as well as when returning a NaN from
a two-operand floating point function. This corrects the behaviour
of float<->double conversions on both ARM and SH4.

Signed-off-by: Christophe Lyon <christophe.lyon@st.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Aurelien Jarno <aurelien@aurel32.net>
---
 fpu/softfloat-specialize.h |   29 +++++++++++++++++++++++++----
 fpu/softfloat.c            |   24 ++++++++++++------------
 2 files changed, 37 insertions(+), 16 deletions(-)

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 495f6f3..1b7521f 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -207,9 +207,14 @@ 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;
+
+    if ( STATUS(default_nan_mode) ) {
+        return float32_default_nan;
+    }
+
     if ( mantissa )
         return make_float32(
             ( ( (bits32) a.sign )<<31 ) | 0x7F800000 | ( a.high>>41 ) );
@@ -461,10 +466,14 @@ 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;
 
+    if ( STATUS(default_nan_mode) ) {
+        return float64_default_nan;
+    }
+
     if ( mantissa )
         return make_float64(
               ( ( (bits64) a.sign )<<63 )
@@ -618,10 +627,16 @@ 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 ( STATUS(default_nan_mode) ) {
+        z.low = floatx80_default_nan_low;
+        z.high = floatx80_default_nan_high;
+        return z;
+    }
+
     if (a.high)
         z.low = a.high;
     else
@@ -766,10 +781,16 @@ 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 );
     return z;
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 635c74c..ffc8a99 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -1561,7 +1561,7 @@ float64 float32_to_float64( float32 a STATUS_PARAM )
     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 ) {
@@ -1593,7 +1593,7 @@ floatx80 float32_to_floatx80( float32 a STATUS_PARAM )
     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 ) {
@@ -1627,7 +1627,7 @@ float128 float32_to_float128( float32 a STATUS_PARAM )
     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 ) {
@@ -2716,7 +2716,7 @@ float32 float64_to_float32( float64 a STATUS_PARAM )
     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 );
@@ -2889,7 +2889,7 @@ floatx80 float64_to_floatx80( float64 a STATUS_PARAM )
     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 ) {
@@ -2924,7 +2924,7 @@ float128 float64_to_float128( float64 a STATUS_PARAM )
     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 ) {
@@ -3871,7 +3871,7 @@ float32 floatx80_to_float32( floatx80 a STATUS_PARAM )
     aSign = extractFloatx80Sign( a );
     if ( aExp == 0x7FFF ) {
         if ( (bits64) ( aSig<<1 ) ) {
-            return commonNaNToFloat32( floatx80ToCommonNaN( a STATUS_VAR ) );
+            return commonNaNToFloat32( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
         }
         return packFloat32( aSign, 0xFF, 0 );
     }
@@ -3899,7 +3899,7 @@ float64 floatx80_to_float64( floatx80 a STATUS_PARAM )
     aSign = extractFloatx80Sign( a );
     if ( aExp == 0x7FFF ) {
         if ( (bits64) ( aSig<<1 ) ) {
-            return commonNaNToFloat64( floatx80ToCommonNaN( a STATUS_VAR ) );
+            return commonNaNToFloat64( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
         }
         return packFloat64( aSign, 0x7FF, 0 );
     }
@@ -3928,7 +3928,7 @@ float128 floatx80_to_float128( floatx80 a STATUS_PARAM )
     aExp = extractFloatx80Exp( a );
     aSign = extractFloatx80Sign( a );
     if ( ( aExp == 0x7FFF ) && (bits64) ( aSig<<1 ) ) {
-        return commonNaNToFloat128( floatx80ToCommonNaN( a STATUS_VAR ) );
+        return commonNaNToFloat128( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR );
     }
     shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 );
     return packFloat128( aSign, aExp, zSig0, zSig1 );
@@ -4891,7 +4891,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 );
     }
@@ -4925,7 +4925,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 );
     }
@@ -4960,7 +4960,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 ) );
     }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH v3 3/6] softfloat: Fix single-to-half precision float conversions
  2011-02-10 11:28 [Qemu-devel] [PATCH v3 0/6] target-arm: Fix floating point conversions Peter Maydell
  2011-02-10 11:28 ` [Qemu-devel] [PATCH v3 1/6] softfloat: Add float16 type and float16 NaN handling functions Peter Maydell
  2011-02-10 11:28 ` [Qemu-devel] [PATCH v3 2/6] softfloat: Honour default_nan_mode for float-to-float conversions Peter Maydell
@ 2011-02-10 11:28 ` Peter Maydell
  2011-02-10 11:28 ` [Qemu-devel] [PATCH v3 4/6] softfloat: Correctly handle NaNs in float16_to_float32() Peter Maydell
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Peter Maydell @ 2011-02-10 11:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Christophe Lyon, patches

Fix various bugs in the single-to-half-precision conversion code:
 * input NaNs not correctly converted in IEEE mode
   (fixed by defining and using a commonNaNToFloat16())
 * wrong values returned when converting NaN/Inf into non-IEEE
   half precision value
 * wrong values returned for conversion of values which are
   on the boundary between denormal and zero for the half
   precision format
 * zeroes not correctly identified
 * excessively large results in non-IEEE mode should
   generate InvalidOp, not Overflow

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 fpu/softfloat-specialize.h |   21 +++++++++++++++++++++
 fpu/softfloat.c            |   28 +++++++++++++++++-----------
 2 files changed, 38 insertions(+), 11 deletions(-)

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 1b7521f..1c0b12b 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -120,6 +120,27 @@ float16 float16_maybe_silence_nan(float16 a_)
 }
 
 /*----------------------------------------------------------------------------
+| 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;
+    }
+}
+
+/*----------------------------------------------------------------------------
 | The pattern for a default generated single-precision NaN.
 *----------------------------------------------------------------------------*/
 #if defined(TARGET_SPARC)
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index ffc8a99..80d8cc4 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -2796,24 +2796,30 @@ float16 float32_to_float16(float32 a, flag ieee STATUS_PARAM)
     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;
@@ -2855,7 +2861,7 @@ float16 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);
         }
     }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH v3 4/6] softfloat: Correctly handle NaNs in float16_to_float32()
  2011-02-10 11:28 [Qemu-devel] [PATCH v3 0/6] target-arm: Fix floating point conversions Peter Maydell
                   ` (2 preceding siblings ...)
  2011-02-10 11:28 ` [Qemu-devel] [PATCH v3 3/6] softfloat: Fix single-to-half precision float conversions Peter Maydell
@ 2011-02-10 11:28 ` Peter Maydell
  2011-02-10 11:29 ` [Qemu-devel] [PATCH v3 5/6] target-arm: Silence NaNs resulting from half-precision conversions Peter Maydell
                   ` (2 subsequent siblings)
  6 siblings, 0 replies; 8+ messages in thread
From: Peter Maydell @ 2011-02-10 11:28 UTC (permalink / raw)
  To: qemu-devel; +Cc: Christophe Lyon, patches

Correctly handle NaNs in float16_to_float32(), by defining and
using a float16ToCommonNaN() function, as we do with the other formats.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 fpu/softfloat-specialize.h |   17 +++++++++++++++++
 fpu/softfloat.c            |    4 +---
 2 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/fpu/softfloat-specialize.h b/fpu/softfloat-specialize.h
index 1c0b12b..2d025bf 100644
--- a/fpu/softfloat-specialize.h
+++ b/fpu/softfloat-specialize.h
@@ -120,6 +120,23 @@ float16 float16_maybe_silence_nan(float16 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 = ((bits64) float16_val(a))<<54;
+    return z;
+}
+
+/*----------------------------------------------------------------------------
 | Returns the result of converting the canonical NaN `a' to the half-
 | precision floating-point format.
 *----------------------------------------------------------------------------*/
diff --git a/fpu/softfloat.c b/fpu/softfloat.c
index 80d8cc4..3abd170 100644
--- a/fpu/softfloat.c
+++ b/fpu/softfloat.c
@@ -2761,9 +2761,7 @@ float32 float16_to_float32(float16 a, flag ieee STATUS_PARAM)
 
     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);
     }
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH v3 5/6] target-arm: Silence NaNs resulting from half-precision conversions
  2011-02-10 11:28 [Qemu-devel] [PATCH v3 0/6] target-arm: Fix floating point conversions Peter Maydell
                   ` (3 preceding siblings ...)
  2011-02-10 11:28 ` [Qemu-devel] [PATCH v3 4/6] softfloat: Correctly handle NaNs in float16_to_float32() Peter Maydell
@ 2011-02-10 11:29 ` Peter Maydell
  2011-02-10 11:29 ` [Qemu-devel] [PATCH v3 6/6] target-arm: Use standard FPSCR for Neon half-precision operations Peter Maydell
  2011-02-10 18:47 ` [Qemu-devel] [PATCH v3 0/6] target-arm: Fix floating point conversions Aurelien Jarno
  6 siblings, 0 replies; 8+ messages in thread
From: Peter Maydell @ 2011-02-10 11:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Christophe Lyon, patches

Silence the NaNs that may result from half-precision conversion,
as we do for the other conversions.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/helper.c |   12 ++++++++++--
 1 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/target-arm/helper.c b/target-arm/helper.c
index d29c42b..e427747 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2627,14 +2627,22 @@ float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, CPUState *env)
 {
     float_status *s = &env->vfp.fp_status;
     int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
-    return float16_to_float32(make_float16(a), ieee, s);
+    float32 r = float16_to_float32(make_float16(a), ieee, s);
+    if (ieee) {
+        return float32_maybe_silence_nan(r);
+    }
+    return r;
 }
 
 uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUState *env)
 {
     float_status *s = &env->vfp.fp_status;
     int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
-    return float16_val(float32_to_float16(a, ieee, s));
+    float16 r = float32_to_float16(a, ieee, s);
+    if (ieee) {
+        r = float16_maybe_silence_nan(r);
+    }
+    return float16_val(r);
 }
 
 float32 HELPER(recps_f32)(float32 a, float32 b, CPUState *env)
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [Qemu-devel] [PATCH v3 6/6] target-arm: Use standard FPSCR for Neon half-precision operations
  2011-02-10 11:28 [Qemu-devel] [PATCH v3 0/6] target-arm: Fix floating point conversions Peter Maydell
                   ` (4 preceding siblings ...)
  2011-02-10 11:29 ` [Qemu-devel] [PATCH v3 5/6] target-arm: Silence NaNs resulting from half-precision conversions Peter Maydell
@ 2011-02-10 11:29 ` Peter Maydell
  2011-02-10 18:47 ` [Qemu-devel] [PATCH v3 0/6] target-arm: Fix floating point conversions Aurelien Jarno
  6 siblings, 0 replies; 8+ messages in thread
From: Peter Maydell @ 2011-02-10 11:29 UTC (permalink / raw)
  To: qemu-devel; +Cc: Christophe Lyon, patches

The Neon half-precision conversion operations (VCVT.F16.F32 and
VCVT.F32.F16) use ARM standard floating-point arithmetic, unlike
the VFP versions (VCVTB and VCVTT).

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/helper.c    |   26 ++++++++++++++++++++++----
 target-arm/helpers.h   |    2 ++
 target-arm/translate.c |   16 ++++++++--------
 3 files changed, 32 insertions(+), 12 deletions(-)

diff --git a/target-arm/helper.c b/target-arm/helper.c
index e427747..7f63a28 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -2623,9 +2623,8 @@ VFP_CONV_FIX(ul, s, float32, uint32, u)
 #undef VFP_CONV_FIX
 
 /* Half precision conversions.  */
-float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, CPUState *env)
+static float32 do_fcvt_f16_to_f32(uint32_t a, CPUState *env, float_status *s)
 {
-    float_status *s = &env->vfp.fp_status;
     int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
     float32 r = float16_to_float32(make_float16(a), ieee, s);
     if (ieee) {
@@ -2634,9 +2633,8 @@ float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, CPUState *env)
     return r;
 }
 
-uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUState *env)
+static uint32_t do_fcvt_f32_to_f16(float32 a, CPUState *env, float_status *s)
 {
-    float_status *s = &env->vfp.fp_status;
     int ieee = (env->vfp.xregs[ARM_VFP_FPSCR] & (1 << 26)) == 0;
     float16 r = float32_to_float16(a, ieee, s);
     if (ieee) {
@@ -2645,6 +2643,26 @@ uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUState *env)
     return float16_val(r);
 }
 
+float32 HELPER(neon_fcvt_f16_to_f32)(uint32_t a, CPUState *env)
+{
+    return do_fcvt_f16_to_f32(a, env, &env->vfp.standard_fp_status);
+}
+
+uint32_t HELPER(neon_fcvt_f32_to_f16)(float32 a, CPUState *env)
+{
+    return do_fcvt_f32_to_f16(a, env, &env->vfp.standard_fp_status);
+}
+
+float32 HELPER(vfp_fcvt_f16_to_f32)(uint32_t a, CPUState *env)
+{
+    return do_fcvt_f16_to_f32(a, env, &env->vfp.fp_status);
+}
+
+uint32_t HELPER(vfp_fcvt_f32_to_f16)(float32 a, CPUState *env)
+{
+    return do_fcvt_f32_to_f16(a, env, &env->vfp.fp_status);
+}
+
 float32 HELPER(recps_f32)(float32 a, float32 b, CPUState *env)
 {
     float_status *s = &env->vfp.fp_status;
diff --git a/target-arm/helpers.h b/target-arm/helpers.h
index 8a2564e..40264b4 100644
--- a/target-arm/helpers.h
+++ b/target-arm/helpers.h
@@ -129,6 +129,8 @@ DEF_HELPER_3(vfp_ultod, f64, f64, i32, env)
 
 DEF_HELPER_2(vfp_fcvt_f16_to_f32, f32, i32, env)
 DEF_HELPER_2(vfp_fcvt_f32_to_f16, i32, f32, env)
+DEF_HELPER_2(neon_fcvt_f16_to_f32, f32, i32, env)
+DEF_HELPER_2(neon_fcvt_f32_to_f16, i32, f32, env)
 
 DEF_HELPER_3(recps_f32, f32, f32, f32, env)
 DEF_HELPER_3(rsqrts_f32, f32, f32, f32, env)
diff --git a/target-arm/translate.c b/target-arm/translate.c
index e4649e6..a867f55 100644
--- a/target-arm/translate.c
+++ b/target-arm/translate.c
@@ -5495,17 +5495,17 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     tmp = new_tmp();
                     tmp2 = new_tmp();
                     tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 0));
-                    gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
+                    gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
                     tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 1));
-                    gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
+                    gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
                     tcg_gen_shli_i32(tmp2, tmp2, 16);
                     tcg_gen_or_i32(tmp2, tmp2, tmp);
                     tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 2));
-                    gen_helper_vfp_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
+                    gen_helper_neon_fcvt_f32_to_f16(tmp, cpu_F0s, cpu_env);
                     tcg_gen_ld_f32(cpu_F0s, cpu_env, neon_reg_offset(rm, 3));
                     neon_store_reg(rd, 0, tmp2);
                     tmp2 = new_tmp();
-                    gen_helper_vfp_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
+                    gen_helper_neon_fcvt_f32_to_f16(tmp2, cpu_F0s, cpu_env);
                     tcg_gen_shli_i32(tmp2, tmp2, 16);
                     tcg_gen_or_i32(tmp2, tmp2, tmp);
                     neon_store_reg(rd, 1, tmp2);
@@ -5518,17 +5518,17 @@ static int disas_neon_data_insn(CPUState * env, DisasContext *s, uint32_t insn)
                     tmp = neon_load_reg(rm, 0);
                     tmp2 = neon_load_reg(rm, 1);
                     tcg_gen_ext16u_i32(tmp3, tmp);
-                    gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
                     tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 0));
                     tcg_gen_shri_i32(tmp3, tmp, 16);
-                    gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
                     tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 1));
                     dead_tmp(tmp);
                     tcg_gen_ext16u_i32(tmp3, tmp2);
-                    gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
                     tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 2));
                     tcg_gen_shri_i32(tmp3, tmp2, 16);
-                    gen_helper_vfp_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
+                    gen_helper_neon_fcvt_f16_to_f32(cpu_F0s, tmp3, cpu_env);
                     tcg_gen_st_f32(cpu_F0s, cpu_env, neon_reg_offset(rd, 3));
                     dead_tmp(tmp2);
                     dead_tmp(tmp3);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [Qemu-devel] [PATCH v3 0/6] target-arm: Fix floating point conversions
  2011-02-10 11:28 [Qemu-devel] [PATCH v3 0/6] target-arm: Fix floating point conversions Peter Maydell
                   ` (5 preceding siblings ...)
  2011-02-10 11:29 ` [Qemu-devel] [PATCH v3 6/6] target-arm: Use standard FPSCR for Neon half-precision operations Peter Maydell
@ 2011-02-10 18:47 ` Aurelien Jarno
  6 siblings, 0 replies; 8+ messages in thread
From: Aurelien Jarno @ 2011-02-10 18:47 UTC (permalink / raw)
  To: Peter Maydell; +Cc: Christophe Lyon, qemu-devel, patches

On Thu, Feb 10, 2011 at 11:28:55AM +0000, Peter Maydell wrote:
> This patchset fixes two issues:
>  * default_nan_mode not being honoured for float-to-float conversions
>  * half precision conversions being broken in a number of ways as
>    well as not handling default_nan_mode.
> 
> With this patchset qemu passes random-instruction-selection tests
> for VCVT.F32.F16, VCVT.F16.F32, VCVTB and VCVTT, in both IEEE and
> non-IEEE modes, with and without default-NaN behaviour.
> 
> Christophe: this patchset includes your softfloat v3 patch, although
> I have split it up a little to keep the float16 bits separate.
> 
> Changes since v2:
>  * added STRUCT_TYPES version of float16 and fixed various
>    places which needed a make_float16()/float16_val() in order
>    to compile with STRUCT_TYPES enabled
>  * s/bits16/float16/ in patch 3 as suggested by Aurelien
>  * fixed the types in the f16-related ARM helper wrappers in patch 6
> 
> Patch 2 is unchanged and so I've added Aurelien's reviewed-by
> signoff; the others all changed, although mostly in minor ways.
> 
> (Compiling with STRUCT_TYPES enabled also needs some fixes to
> existing float32/float64 code; I'll send a separate patchset
> for that.)
> 
> 
> Christophe Lyon (1):
>   softfloat: Honour default_nan_mode for float-to-float conversions
> 
> Peter Maydell (5):
>   softfloat: Add float16 type and float16 NaN handling functions
>   softfloat: Fix single-to-half precision float conversions
>   softfloat: Correctly handle NaNs in float16_to_float32()
>   target-arm: Silence NaNs resulting from half-precision conversions
>   target-arm: Use standard FPSCR for Neon half-precision operations
> 
>  fpu/softfloat-specialize.h |  130 ++++++++++++++++++++++++++++++++++++++++++--
>  fpu/softfloat.c            |  100 ++++++++++++++++++++++------------
>  fpu/softfloat.h            |   19 ++++++-
>  target-arm/helper.c        |   38 +++++++++++--
>  target-arm/helpers.h       |    2 +
>  target-arm/translate.c     |   16 +++---
>  6 files changed, 251 insertions(+), 54 deletions(-)
> 

Thanks, all applied.

-- 
Aurelien Jarno                          GPG: 1024D/F1BCDB73
aurelien@aurel32.net                 http://www.aurel32.net

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2011-02-10 18:47 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-02-10 11:28 [Qemu-devel] [PATCH v3 0/6] target-arm: Fix floating point conversions Peter Maydell
2011-02-10 11:28 ` [Qemu-devel] [PATCH v3 1/6] softfloat: Add float16 type and float16 NaN handling functions Peter Maydell
2011-02-10 11:28 ` [Qemu-devel] [PATCH v3 2/6] softfloat: Honour default_nan_mode for float-to-float conversions Peter Maydell
2011-02-10 11:28 ` [Qemu-devel] [PATCH v3 3/6] softfloat: Fix single-to-half precision float conversions Peter Maydell
2011-02-10 11:28 ` [Qemu-devel] [PATCH v3 4/6] softfloat: Correctly handle NaNs in float16_to_float32() Peter Maydell
2011-02-10 11:29 ` [Qemu-devel] [PATCH v3 5/6] target-arm: Silence NaNs resulting from half-precision conversions Peter Maydell
2011-02-10 11:29 ` [Qemu-devel] [PATCH v3 6/6] target-arm: Use standard FPSCR for Neon half-precision operations Peter Maydell
2011-02-10 18:47 ` [Qemu-devel] [PATCH v3 0/6] target-arm: Fix floating point conversions Aurelien Jarno

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).