From: Bruno Haible Date: Tue, 9 Apr 2024 11:08:32 +0000 (+0200) Subject: totalorder, totalorderf: Fix handling of SNaN on i386 and x86_64 CPUs. X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=2cb393d0ac962efe0407c31d466b16f7b0c0c669;p=gnulib.git totalorder, totalorderf: Fix handling of SNaN on i386 and x86_64 CPUs. * lib/totalorder.c: Include . (totalorder): Use memcpy to copy the 'double' values into the union. Drop 'volatile'. * lib/totalorderf.c: Include . (totalorderf): Use memcpy to copy the 'float' values into the union. Drop 'volatile'. --- diff --git a/ChangeLog b/ChangeLog index 3325c626e9..c3eae2e396 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2024-04-09 Bruno Haible + + totalorder, totalorderf: Fix handling of SNaN on i386 and x86_64 CPUs. + * lib/totalorder.c: Include . + (totalorder): Use memcpy to copy the 'double' values into the union. + Drop 'volatile'. + * lib/totalorderf.c: Include . + (totalorderf): Use memcpy to copy the 'float' values into the union. + Drop 'volatile'. + 2024-04-09 Bruno Haible totalorder tests: Fix signature test. diff --git a/lib/totalorder.c b/lib/totalorder.c index 1fb8f0d24d..635e3cb276 100644 --- a/lib/totalorder.c +++ b/lib/totalorder.c @@ -21,6 +21,8 @@ /* Specification. */ #include +#include + int totalorder (double const *x, double const *y) { @@ -50,8 +52,18 @@ totalorder (double const *x, double const *y) /* Invert the most significant bit of the mantissa field. Cf. snan.h. */ extended_sign ^= (1ULL << 51); #endif - union { unsigned long long i; double f; } volatile xu = {0}, yu = {0}; + union { unsigned long long i; double f; } xu = {0}, yu = {0}; +#if 0 xu.f = *x; yu.f = *y; +#else + /* On 32-bit x86 processors, as well as on x86_64 processors with + CC="gcc -mfpmath=387", the evaluation of *x and *y above is done through + an 'fldl' instruction, which converts a signalling NaN to a quiet NaN. See + + for details. Use memcpy to avoid this. */ + memcpy (&xu.f, x, sizeof (double)); + memcpy (&yu.f, y, sizeof (double)); +#endif return (xu.i ^ extended_sign) <= (yu.i ^ extended_sign); } diff --git a/lib/totalorderf.c b/lib/totalorderf.c index d235bc98bc..75024b6839 100644 --- a/lib/totalorderf.c +++ b/lib/totalorderf.c @@ -21,6 +21,8 @@ /* Specification. */ #include +#include + int totalorderf (float const *x, float const *y) { @@ -50,8 +52,18 @@ totalorderf (float const *x, float const *y) /* Invert the most significant bit of the mantissa field. Cf. snan.h. */ extended_sign ^= (1U << 22); #endif - union { unsigned int i; float f; } volatile xu = {0}, yu = {0}; + union { unsigned int i; float f; } xu = {0}, yu = {0}; +#if 0 xu.f = *x; yu.f = *y; +#else + /* On 32-bit x86 processors, as well as on x86_64 processors with + CC="gcc -mfpmath=387", the evaluation of *x and *y above is done through + an 'flds' instruction, which converts a signalling NaN to a quiet NaN. See + + for details. Use memcpy to avoid this. */ + memcpy (&xu.f, x, sizeof (float)); + memcpy (&yu.f, y, sizeof (float)); +#endif return (xu.i ^ extended_sign) <= (yu.i ^ extended_sign); }