* [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).