floatx80 x87 pseudo-denormal fixes
-----BEGIN PGP SIGNATURE----- iQFRBAABCgA7FiEEekgeeIaLTbaoWgXAZN846K9+IV8FAl6+2xMdHHJpY2hhcmQu aGVuZGVyc29uQGxpbmFyby5vcmcACgkQZN846K9+IV9vuQf/cxuZV8JkewohGv/7 7RmtiSvsvJcSx/iT2uGr/MhTy5pRkBGEtVwU7z3YDLpX6ZKl1mUXC9FXjutXpohE gbtJiYSFUP10m2/+WtkfFeKl4gPMsl/BQ1aVDz2Cdt1X1MsfYT/tWb7W/Bs8p4z2 cTBr791tzyg9coGjJOXMUebxiciSoFrVEgNCN+SHXF8x3EhOOEuS79dP1bFCgLBk 0lMoLupKqWVZv/tsQJVNl8a8gwauKhd7fPpwmQCtszgCRBo/l2NUX5kj/gzGdji9 BEM+bxlZocKMmXuEiFB5IPtf3Wi8TocHeaJ6rLuK1RhL7yQdt5zE3lOU/E5K8pvs VGMjsA== =eBK6 -----END PGP SIGNATURE----- Merge remote-tracking branch 'remotes/rth/tags/pull-fpu-20200515' into staging floatx80 x87 pseudo-denormal fixes # gpg: Signature made Fri 15 May 2020 19:10:27 BST # gpg: using RSA key 7A481E78868B4DB6A85A05C064DF38E8AF7E215F # gpg: issuer "richard.henderson@linaro.org" # gpg: Good signature from "Richard Henderson <richard.henderson@linaro.org>" [full] # Primary key fingerprint: 7A48 1E78 868B 4DB6 A85A 05C0 64DF 38E8 AF7E 215F * remotes/rth/tags/pull-fpu-20200515: softfloat: fix floatx80 pseudo-denormal round to integer softfloat: fix floatx80 pseudo-denormal comparisons softfloat: fix floatx80 pseudo-denormal addition / subtraction softfloat: silence sNaN for conversions to/from floatx80 Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
commit
debe78ce14
@ -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 );
|
||||
@ -5731,7 +5741,7 @@ floatx80 floatx80_round_to_int(floatx80 a, float_status *status)
|
||||
}
|
||||
if ( aExp < 0x3FFF ) {
|
||||
if ( ( aExp == 0 )
|
||||
&& ( (uint64_t) ( extractFloatx80Frac( a )<<1 ) == 0 ) ) {
|
||||
&& ( (uint64_t) ( extractFloatx80Frac( a ) ) == 0 ) ) {
|
||||
return a;
|
||||
}
|
||||
status->float_exception_flags |= float_flag_inexact;
|
||||
@ -5856,6 +5866,12 @@ static floatx80 addFloatx80Sigs(floatx80 a, floatx80 b, flag zSign,
|
||||
zSig1 = 0;
|
||||
zSig0 = aSig + bSig;
|
||||
if ( aExp == 0 ) {
|
||||
if ((aSig | bSig) & UINT64_C(0x8000000000000000) && zSig0 < aSig) {
|
||||
/* At least one of the values is a pseudo-denormal,
|
||||
* and there is a carry out of the result. */
|
||||
zExp = 1;
|
||||
goto shiftRight1;
|
||||
}
|
||||
if (zSig0 == 0) {
|
||||
return packFloatx80(zSign, 0, 0);
|
||||
}
|
||||
@ -6959,7 +6975,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);
|
||||
@ -7948,6 +7966,13 @@ static inline int floatx80_compare_internal(floatx80 a, floatx80 b,
|
||||
return 1 - (2 * aSign);
|
||||
}
|
||||
} else {
|
||||
/* Normalize pseudo-denormals before comparison. */
|
||||
if ((a.high & 0x7fff) == 0 && a.low & UINT64_C(0x8000000000000000)) {
|
||||
++a.high;
|
||||
}
|
||||
if ((b.high & 0x7fff) == 0 && b.low & UINT64_C(0x8000000000000000)) {
|
||||
++b.high;
|
||||
}
|
||||
if (a.low == b.low && a.high == b.high) {
|
||||
return float_relation_equal;
|
||||
} else {
|
||||
|
38
tests/tcg/i386/test-i386-pseudo-denormal.c
Normal file
38
tests/tcg/i386/test-i386-pseudo-denormal.c
Normal file
@ -0,0 +1,38 @@
|
||||
/* Test pseudo-denormal operations. */
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
union u {
|
||||
struct { uint64_t sig; uint16_t sign_exp; } s;
|
||||
long double ld;
|
||||
};
|
||||
|
||||
volatile union u ld_pseudo_m16382 = { .s = { UINT64_C(1) << 63, 0 } };
|
||||
|
||||
volatile long double ld_res;
|
||||
|
||||
int main(void)
|
||||
{
|
||||
short cw;
|
||||
int ret = 0;
|
||||
ld_res = ld_pseudo_m16382.ld + ld_pseudo_m16382.ld;
|
||||
if (ld_res != 0x1p-16381L) {
|
||||
printf("FAIL: pseudo-denormal add\n");
|
||||
ret = 1;
|
||||
}
|
||||
if (ld_pseudo_m16382.ld != 0x1p-16382L) {
|
||||
printf("FAIL: pseudo-denormal compare\n");
|
||||
ret = 1;
|
||||
}
|
||||
/* Set round-upward. */
|
||||
__asm__ volatile ("fnstcw %0" : "=m" (cw));
|
||||
cw = (cw & ~0xc00) | 0x800;
|
||||
__asm__ volatile ("fldcw %0" : : "m" (cw));
|
||||
__asm__ ("frndint" : "=t" (ld_res) : "0" (ld_pseudo_m16382.ld));
|
||||
if (ld_res != 1.0L) {
|
||||
printf("FAIL: pseudo-denormal round-to-integer\n");
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
63
tests/tcg/i386/test-i386-snan-convert.c
Normal file
63
tests/tcg/i386/test-i386-snan-convert.c
Normal 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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user