softfloat: silence sNaN for conversions to/from floatx80

Conversions between IEEE floating-point formats should convert
signaling NaNs to quiet NaNs.  Most of those in QEMU's softfloat code
do so, but those for floatx80 fail to.  Fix those conversions to
silence signaling NaNs as well.

Signed-off-by: Joseph Myers <joseph@codesourcery.com>
Message-Id: <alpine.DEB.2.21.2005042336170.22972@digraph.polyomino.org.uk>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Joseph Myers 2020-05-04 23:37:54 +00:00 committed by Richard Henderson
parent 66706192de
commit 7537c2b4a3
2 changed files with 81 additions and 6 deletions

View file

@ -4498,7 +4498,9 @@ floatx80 float32_to_floatx80(float32 a, float_status *status)
aSign = extractFloat32Sign( a );
if ( aExp == 0xFF ) {
if (aSig) {
return commonNaNToFloatx80(float32ToCommonNaN(a, status), status);
floatx80 res = commonNaNToFloatx80(float32ToCommonNaN(a, status),
status);
return floatx80_silence_nan(res, status);
}
return packFloatx80(aSign,
floatx80_infinity_high,
@ -5016,7 +5018,9 @@ floatx80 float64_to_floatx80(float64 a, float_status *status)
aSign = extractFloat64Sign( a );
if ( aExp == 0x7FF ) {
if (aSig) {
return commonNaNToFloatx80(float64ToCommonNaN(a, status), status);
floatx80 res = commonNaNToFloatx80(float64ToCommonNaN(a, status),
status);
return floatx80_silence_nan(res, status);
}
return packFloatx80(aSign,
floatx80_infinity_high,
@ -5618,7 +5622,9 @@ float32 floatx80_to_float32(floatx80 a, float_status *status)
aSign = extractFloatx80Sign( a );
if ( aExp == 0x7FFF ) {
if ( (uint64_t) ( aSig<<1 ) ) {
return commonNaNToFloat32(floatx80ToCommonNaN(a, status), status);
float32 res = commonNaNToFloat32(floatx80ToCommonNaN(a, status),
status);
return float32_silence_nan(res, status);
}
return packFloat32( aSign, 0xFF, 0 );
}
@ -5650,7 +5656,9 @@ float64 floatx80_to_float64(floatx80 a, float_status *status)
aSign = extractFloatx80Sign( a );
if ( aExp == 0x7FFF ) {
if ( (uint64_t) ( aSig<<1 ) ) {
return commonNaNToFloat64(floatx80ToCommonNaN(a, status), status);
float64 res = commonNaNToFloat64(floatx80ToCommonNaN(a, status),
status);
return float64_silence_nan(res, status);
}
return packFloat64( aSign, 0x7FF, 0 );
}
@ -5681,7 +5689,9 @@ float128 floatx80_to_float128(floatx80 a, float_status *status)
aExp = extractFloatx80Exp( a );
aSign = extractFloatx80Sign( a );
if ( ( aExp == 0x7FFF ) && (uint64_t) ( aSig<<1 ) ) {
return commonNaNToFloat128(floatx80ToCommonNaN(a, status), status);
float128 res = commonNaNToFloat128(floatx80ToCommonNaN(a, status),
status);
return float128_silence_nan(res, status);
}
shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 );
return packFloat128( aSign, aExp, zSig0, zSig1 );
@ -6959,7 +6969,9 @@ floatx80 float128_to_floatx80(float128 a, float_status *status)
aSign = extractFloat128Sign( a );
if ( aExp == 0x7FFF ) {
if ( aSig0 | aSig1 ) {
return commonNaNToFloatx80(float128ToCommonNaN(a, status), status);
floatx80 res = commonNaNToFloatx80(float128ToCommonNaN(a, status),
status);
return floatx80_silence_nan(res, status);
}
return packFloatx80(aSign, floatx80_infinity_high,
floatx80_infinity_low);

View file

@ -0,0 +1,63 @@
/* Test conversions of signaling NaNs to and from long double. */
#include <stdint.h>
#include <stdio.h>
volatile float f_res;
volatile double d_res;
volatile long double ld_res;
volatile float f_snan = __builtin_nansf("");
volatile double d_snan = __builtin_nans("");
volatile long double ld_snan = __builtin_nansl("");
int issignaling_f(float x)
{
union { float f; uint32_t u; } u = { .f = x };
return (u.u & 0x7fffffff) > 0x7f800000 && (u.u & 0x400000) == 0;
}
int issignaling_d(double x)
{
union { double d; uint64_t u; } u = { .d = x };
return (((u.u & UINT64_C(0x7fffffffffffffff)) >
UINT64_C(0x7ff0000000000000)) &&
(u.u & UINT64_C(0x8000000000000)) == 0);
}
int issignaling_ld(long double x)
{
union {
long double ld;
struct { uint64_t sig; uint16_t sign_exp; } s;
} u = { .ld = x };
return ((u.s.sign_exp & 0x7fff) == 0x7fff &&
(u.s.sig >> 63) != 0 &&
(u.s.sig & UINT64_C(0x4000000000000000)) == 0);
}
int main(void)
{
int ret = 0;
ld_res = f_snan;
if (issignaling_ld(ld_res)) {
printf("FAIL: float -> long double\n");
ret = 1;
}
ld_res = d_snan;
if (issignaling_ld(ld_res)) {
printf("FAIL: double -> long double\n");
ret = 1;
}
f_res = ld_snan;
if (issignaling_d(f_res)) {
printf("FAIL: long double -> float\n");
ret = 1;
}
d_res = ld_snan;
if (issignaling_d(d_res)) {
printf("FAIL: long double -> double\n");
ret = 1;
}
return ret;
}