Fix sNaN handling in floating-point format conversion operations, that are classified by the IEEE 754-2008 standard as general-computational operations [1]:
"5.4 formatOf general-computational operations "5.4.2 Conversion operations for floating-point formats and decimal character sequences "Implementations shall provide the following formatOf conversion operations from all supported floating-point formats to all supported floating-point formats, as well as conversions to and from decimal character sequences. These operations shall not propagate non-canonical results. Some format conversion operations produce results in a different radix than the operands." according to the quietening requirement [2] set by the same standard: "7.2 Invalid operation "For operations producing results in floating-point format, the default result of an operation that signals the invalid operation exception shall be a quiet NaN that should provide some diagnostic information (see 6.2). "These operations are: a) any general-computational or signaling-computational operation on a signaling NaN (see 6.2), except for some conversions (see 5.12)" and the reference above is [3]: "5.12 Details of conversion between floating-point data and external character sequences" so does not apply to conversions a pair of floating-point formats. Therefore quieten any sNaN encountered in floating-point format conversions, in the usual manner. References: [1] "IEEE Standard for Floating-Point Arithmetic", IEEE Computer Society, IEEE Std 754-2008, 29 August 2008, pp. 21-22 [2] same, p. 37 [3] same, p. 30 Signed-off-by: Maciej W. Rozycki <ma...@codesourcery.com> --- This is in particular how MIPS hardware operates, other processors supposedly do the same if they claim compliance to IEEE 754. Please apply. qemu-softfloat-convert-snan.diff Index: qemu-git-trunk/fpu/softfloat.c =================================================================== --- qemu-git-trunk.orig/fpu/softfloat.c 2014-10-24 22:03:48.000000000 +0100 +++ qemu-git-trunk/fpu/softfloat.c 2014-11-03 01:45:15.488923310 +0000 @@ -1711,7 +1711,11 @@ float64 float32_to_float64( float32 a ST aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { - if ( aSig ) return commonNaNToFloat64( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); + if (aSig) { + return float64_maybe_silence_nan( + commonNaNToFloat64(float32ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); + } return packFloat64( aSign, 0x7FF, 0 ); } if ( aExp == 0 ) { @@ -1741,7 +1745,11 @@ floatx80 float32_to_floatx80( float32 a aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { - if ( aSig ) return commonNaNToFloatx80( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); + if (aSig) { + return floatx80_maybe_silence_nan( + commonNaNToFloatx80(float32ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); + } return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( aExp == 0 ) { @@ -1771,7 +1779,11 @@ float128 float32_to_float128( float32 a aExp = extractFloat32Exp( a ); aSign = extractFloat32Sign( a ); if ( aExp == 0xFF ) { - if ( aSig ) return commonNaNToFloat128( float32ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); + if (aSig) { + return float128_maybe_silence_nan( + commonNaNToFloat128(float32ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); + } return packFloat128( aSign, 0x7FFF, 0, 0 ); } if ( aExp == 0 ) { @@ -3151,7 +3163,11 @@ float32 float64_to_float32( float64 a ST aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { - if ( aSig ) return commonNaNToFloat32( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); + if (aSig) { + return float32_maybe_silence_nan( + commonNaNToFloat32(float64ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); + } return packFloat32( aSign, 0xFF, 0 ); } shift64RightJamming( aSig, 22, &aSig ); @@ -3318,7 +3334,9 @@ float32 float16_to_float32(float16 a, fl if (aExp == 0x1f && ieee) { if (aSig) { - return commonNaNToFloat32(float16ToCommonNaN(a STATUS_VAR) STATUS_VAR); + return float32_maybe_silence_nan( + commonNaNToFloat32(float16ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); } return packFloat32(aSign, 0xff, 0); } @@ -3351,8 +3369,9 @@ float16 float32_to_float16(float32 a, fl float_raise(float_flag_invalid STATUS_VAR); return packFloat16(aSign, 0, 0); } - return commonNaNToFloat16( - float32ToCommonNaN(a STATUS_VAR) STATUS_VAR); + return float16_maybe_silence_nan( + commonNaNToFloat16(float32ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); } /* Infinity */ if (!ieee) { @@ -3389,8 +3408,9 @@ float64 float16_to_float64(float16 a, fl if (aExp == 0x1f && ieee) { if (aSig) { - return commonNaNToFloat64( - float16ToCommonNaN(a STATUS_VAR) STATUS_VAR); + return float64_maybe_silence_nan( + commonNaNToFloat64(float16ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); } return packFloat64(aSign, 0x7ff, 0); } @@ -3424,8 +3444,9 @@ float16 float64_to_float16(float64 a, fl float_raise(float_flag_invalid STATUS_VAR); return packFloat16(aSign, 0, 0); } - return commonNaNToFloat16( - float64ToCommonNaN(a STATUS_VAR) STATUS_VAR); + return float16_maybe_silence_nan( + commonNaNToFloat16(float64ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); } /* Infinity */ if (!ieee) { @@ -3470,7 +3491,11 @@ floatx80 float64_to_floatx80( float64 a aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { - if ( aSig ) return commonNaNToFloatx80( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); + if (aSig) { + return floatx80_maybe_silence_nan( + commonNaNToFloatx80(float64ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); + } return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); } if ( aExp == 0 ) { @@ -3501,7 +3526,11 @@ float128 float64_to_float128( float64 a aExp = extractFloat64Exp( a ); aSign = extractFloat64Sign( a ); if ( aExp == 0x7FF ) { - if ( aSig ) return commonNaNToFloat128( float64ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); + if (aSig) { + return float128_maybe_silence_nan( + commonNaNToFloat128(float64ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); + } return packFloat128( aSign, 0x7FFF, 0, 0 ); } if ( aExp == 0 ) { @@ -4759,8 +4788,10 @@ float32 floatx80_to_float32( floatx80 a aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); if ( aExp == 0x7FFF ) { - if ( (uint64_t) ( aSig<<1 ) ) { - return commonNaNToFloat32( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); + if ((uint64_t)(aSig << 1)) { + return float32_maybe_silence_nan( + commonNaNToFloat32(floatx80ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); } return packFloat32( aSign, 0xFF, 0 ); } @@ -4787,8 +4818,10 @@ float64 floatx80_to_float64( floatx80 a aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); if ( aExp == 0x7FFF ) { - if ( (uint64_t) ( aSig<<1 ) ) { - return commonNaNToFloat64( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); + if ((uint64_t)(aSig << 1)) { + return float64_maybe_silence_nan( + commonNaNToFloat64(floatx80ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); } return packFloat64( aSign, 0x7FF, 0 ); } @@ -4814,8 +4847,9 @@ float128 floatx80_to_float128( floatx80 aSig = extractFloatx80Frac( a ); aExp = extractFloatx80Exp( a ); aSign = extractFloatx80Sign( a ); - if ( ( aExp == 0x7FFF ) && (uint64_t) ( aSig<<1 ) ) { - return commonNaNToFloat128( floatx80ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); + if (aExp == 0x7FFF && (uint64_t)(aSig << 1)) { + return float128_maybe_silence_nan( + commonNaNToFloat128(floatx80ToCommonNaN(a STATUS_VAR) STATUS_VAR)); } shift128Right( aSig<<1, 0, 16, &zSig0, &zSig1 ); return packFloat128( aSign, aExp, zSig0, zSig1 ); @@ -5832,8 +5866,10 @@ float32 float128_to_float32( float128 a aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 ) { - return commonNaNToFloat32( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); + if (aSig0 | aSig1) { + return float32_maybe_silence_nan( + commonNaNToFloat32(float128ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); } return packFloat32( aSign, 0xFF, 0 ); } @@ -5866,8 +5902,10 @@ float64 float128_to_float64( float128 a aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 ) { - return commonNaNToFloat64( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); + if (aSig0 | aSig1) { + return float64_maybe_silence_nan( + commonNaNToFloat64(float128ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); } return packFloat64( aSign, 0x7FF, 0 ); } @@ -5899,8 +5937,10 @@ floatx80 float128_to_floatx80( float128 aExp = extractFloat128Exp( a ); aSign = extractFloat128Sign( a ); if ( aExp == 0x7FFF ) { - if ( aSig0 | aSig1 ) { - return commonNaNToFloatx80( float128ToCommonNaN( a STATUS_VAR ) STATUS_VAR ); + if (aSig0 | aSig1) { + return floatx80_maybe_silence_nan( + commonNaNToFloatx80(float128ToCommonNaN(a STATUS_VAR) + STATUS_VAR)); } return packFloatx80( aSign, 0x7FFF, LIT64( 0x8000000000000000 ) ); }