From: Bruno Haible Date: Fri, 19 Apr 2024 11:57:14 +0000 (+0200) Subject: signed-nan: Don't assume that '-' works as expected on NaN values. X-Git-Url: https://gitweb.git.savannah.gnu.org/gitweb/?a=commitdiff_plain;h=d5613cfaea71bdb5899c5b318eafd13ef37d7870;p=gnulib.git signed-nan: Don't assume that '-' works as expected on NaN values. * lib/signed-nan.h (minus_NaNf): New function. (positive_NaNf, negative_NaNf): Use it. (minus_NaNd): New function. (positive_NaNd, negative_NaNd): Use it. (minus_NaNl): New function. (positive_NaNl, negative_NaNl): Use it. --- diff --git a/ChangeLog b/ChangeLog index 86f04d2fe6..831a14211d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2024-04-19 Bruno Haible + + signed-nan: Don't assume that '-' works as expected on NaN values. + * lib/signed-nan.h (minus_NaNf): New function. + (positive_NaNf, negative_NaNf): Use it. + (minus_NaNd): New function. + (positive_NaNd, negative_NaNd): Use it. + (minus_NaNl): New function. + (positive_NaNl, negative_NaNl): Use it. + 2024-04-18 Bruno Haible totalorder*: Support newer MIPS CPUs. diff --git a/lib/signed-nan.h b/lib/signed-nan.h index 18a550a751..92b42510a9 100644 --- a/lib/signed-nan.h +++ b/lib/signed-nan.h @@ -22,6 +22,23 @@ #include "nan.h" +/* Returns - x, implemented by inverting the sign bit, + so that it works also on 'float' NaN values. */ +_GL_UNUSED static float +minus_NaNf (float x) +{ +#if defined __mips__ + /* The mips instruction neg.s may have no effect on NaNs. + Therefore, invert the sign bit using integer operations. */ + union { unsigned int i; float value; } u; + u.value = x; + u.i ^= 1U << 31; + return u.value; +#else + return - x; +#endif +} + /* Returns a quiet 'float' NaN with sign bit == 0. */ _GL_UNUSED static float positive_NaNf () @@ -29,7 +46,7 @@ positive_NaNf () /* 'volatile' works around a GCC bug: */ float volatile nan = NaNf (); - return (signbit (nan) ? - nan : nan); + return (signbit (nan) ? minus_NaNf (nan) : nan); } /* Returns a quiet 'float' NaN with sign bit == 1. */ @@ -39,10 +56,27 @@ negative_NaNf () /* 'volatile' works around a GCC bug: */ float volatile nan = NaNf (); - return (signbit (nan) ? nan : - nan); + return (signbit (nan) ? nan : minus_NaNf (nan)); } +/* Returns - x, implemented by inverting the sign bit, + so that it works also on 'double' NaN values. */ +_GL_UNUSED static double +minus_NaNd (double x) +{ +#if defined __mips__ + /* The mips instruction neg.d may have no effect on NaNs. + Therefore, invert the sign bit using integer operations. */ + union { unsigned long long i; double value; } u; + u.value = x; + u.i ^= 1ULL << 63; + return u.value; +#else + return - x; +#endif +} + /* Returns a quiet 'double' NaN with sign bit == 0. */ _GL_UNUSED static double positive_NaNd () @@ -50,7 +84,7 @@ positive_NaNd () /* 'volatile' works around a GCC bug: */ double volatile nan = NaNd (); - return (signbit (nan) ? - nan : nan); + return (signbit (nan) ? minus_NaNd (nan) : nan); } /* Returns a quiet 'double' NaN with sign bit == 1. */ @@ -60,10 +94,18 @@ negative_NaNd () /* 'volatile' works around a GCC bug: */ double volatile nan = NaNd (); - return (signbit (nan) ? nan : - nan); + return (signbit (nan) ? nan : minus_NaNd (nan)); } +/* Returns - x, implemented by inverting the sign bit, + so that it works also on 'long double' NaN values. */ +_GL_UNUSED static long double +minus_NaNl (long double x) +{ + return - x; +} + /* Returns a quiet 'long double' NaN with sign bit == 0. */ _GL_UNUSED static long double positive_NaNl () @@ -71,7 +113,7 @@ positive_NaNl () /* 'volatile' works around a GCC bug: */ long double volatile nan = NaNl (); - return (signbit (nan) ? - nan : nan); + return (signbit (nan) ? minus_NaNl (nan) : nan); } /* Returns a quiet 'long double' NaN with sign bit == 1. */ @@ -81,7 +123,7 @@ negative_NaNl () /* 'volatile' works around a GCC bug: */ long double volatile nan = NaNl (); - return (signbit (nan) ? nan : - nan); + return (signbit (nan) ? nan : minus_NaNl (nan)); }