]> Savannah Git Hosting - gnulib.git/commitdiff
totalorder*: Fix test failures on PA-RISC and MIPS CPUs.
authorBruno Haible <bruno@clisp.org>
Sat, 14 Oct 2023 18:48:13 +0000 (20:48 +0200)
committerBruno Haible <bruno@clisp.org>
Sat, 14 Oct 2023 18:48:13 +0000 (20:48 +0200)
* lib/totalorderf.c (totalorderf): On hppa and mips, invert bit 22
before comparing two NaNs.
* lib/totalorder.c (totalorder): On hppa and mips, invert bit 51 before
comparing two NaNs.
* lib/totalorderl.c: Include <float.h>.
(totalorderl): On hppa and mips, invert bit 51 or 47 of the xhi, yhi
parts before comparing two NaNs.
* modules/totalorderl (Depends-on): Add 'float'.

ChangeLog
lib/totalorder.c
lib/totalorderf.c
lib/totalorderl.c
modules/totalorderl

index f4db2f61c113051497790bc63f0ca851681c2423..60f9cbd63a3629e4cca7cb20f95876d7593260ef 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2023-10-14  Bruno Haible  <bruno@clisp.org>
+
+       totalorder*: Fix test failures on PA-RISC and MIPS CPUs.
+       * lib/totalorderf.c (totalorderf): On hppa and mips, invert bit 22
+       before comparing two NaNs.
+       * lib/totalorder.c (totalorder): On hppa and mips, invert bit 51 before
+       comparing two NaNs.
+       * lib/totalorderl.c: Include <float.h>.
+       (totalorderl): On hppa and mips, invert bit 51 or 47 of the xhi, yhi
+       parts before comparing two NaNs.
+       * modules/totalorderl (Depends-on): Add 'float'.
+
 2023-10-14  Bruno Haible  <bruno@clisp.org>
 
        totalorder* tests: Test also the signalling NaNs.
index 4c861f971cd0e4f125406273d2359fa9d2409def..edbcd6998b2d4fe6469bae3c90f4681fc2a65be9 100644 (file)
 
 #include <config.h>
 
+/* Specification.  */
 #include <math.h>
 
 int
 totalorder (double const *x, double const *y)
 {
-  /* Although the following is not strictly portable, and won't work
-     on some obsolete platforms (e.g., PA-RISC, MIPS before alignment
-     to IEEE 754-2008), it should be good enough nowadays.  */
+  /* If the sign bits of *X and *Y differ, the one with non-zero sign bit
+     is "smaller" than the one with sign bit == 0.  */
   int xs = signbit (*x);
   int ys = signbit (*y);
   if (!xs != !ys)
     return xs;
+
+  /* If one of *X, *Y is a NaN and the other isn't, the answer is easy
+     as well: the negative NaN is "smaller", the positive NaN is "greater"
+     than the other argument.  */
   int xn = isnand (*x);
   int yn = isnand (*y);
   if (!xn != !yn)
     return !xn == !xs;
+  /* If none of *X, *Y is a NaN, the '<=' operator does the job, including
+     for -Infinity and +Infinity.  */
   if (!xn)
     return *x <= *y;
 
+  /* At this point, *X and *Y are NaNs with the same sign bit.  */
+
   unsigned long long extended_sign = -!!xs;
+#if defined __hppa || defined __mips__
+  /* 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};
   xu.f = *x;
   yu.f = *y;
index d86299ff09edc8cc7cf0d7350ab780345a4b3eed..4cbfa06ffd7275132435b25f44b91b5536f07777 100644 (file)
 
 #include <config.h>
 
+/* Specification.  */
 #include <math.h>
 
 int
 totalorderf (float const *x, float const *y)
 {
-  /* Although the following is not strictly portable, and won't work
-     on some obsolete platforms (e.g., PA-RISC, MIPS before alignment
-     to IEEE 754-2008), it should be good enough nowadays.  */
+  /* If the sign bits of *X and *Y differ, the one with non-zero sign bit
+     is "smaller" than the one with sign bit == 0.  */
   int xs = signbit (*x);
   int ys = signbit (*y);
   if (!xs != !ys)
     return xs;
+
+  /* If one of *X, *Y is a NaN and the other isn't, the answer is easy
+     as well: the negative NaN is "smaller", the positive NaN is "greater"
+     than the other argument.  */
   int xn = isnanf (*x);
   int yn = isnanf (*y);
   if (!xn != !yn)
     return !xn == !xs;
+  /* If none of *X, *Y is a NaN, the '<=' operator does the job, including
+     for -Infinity and +Infinity.  */
   if (!xn)
     return *x <= *y;
 
-  unsigned long extended_sign = -!!xs;
-  union { unsigned long i; float f; } volatile xu = {0}, yu = {0};
+  /* At this point, *X and *Y are NaNs with the same sign bit.  */
+
+  unsigned int extended_sign = -!!xs;
+#if defined __hppa || defined __mips__
+  /* 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};
   xu.f = *x;
   yu.f = *y;
   return (xu.i ^ extended_sign) <= (yu.i ^ extended_sign);
index cc0698febed69d60297e2f9657ec1352bc13e4d6..6982762a0f634191eb7ff2a74509f75bedeca3db 100644 (file)
 
 #include <config.h>
 
+/* Specification.  */
 #include <math.h>
 
+#include <float.h>
+
 #ifndef LDBL_SIGNBIT_WORD
 # define LDBL_SIGNBIT_WORD (-1)
 #endif
 int
 totalorderl (long double const *x, long double const *y)
 {
-  /* Although the following is not strictly portable, and won't work
-     on some obsolete platforms (e.g., PA-RISC, MIPS before alignment
-     to IEEE 754-2008), it should be good enough nowadays.  */
-
   /* If the sign bits of *X and *Y differ, the one with non-zero sign bit
      is "smaller" than the one with sign bit == 0.  */
   int xs = signbit (*x);
@@ -56,6 +55,10 @@ totalorderl (long double const *x, long double const *y)
 
   if (sizeof (long double) <= sizeof (unsigned long long))
     {
+#if defined __hppa || defined __mips__
+      /* Invert the most significant bit of the mantissa field.  Cf. snan.h.  */
+      extended_sign ^= (1ULL << 51);
+#endif
       union { unsigned long long i; long double f; } volatile
         xu = {0}, yu = {0};
       xu.f = *x;
@@ -63,6 +66,14 @@ totalorderl (long double const *x, long double const *y)
       return (xu.i ^ extended_sign) <= (yu.i ^ extended_sign);
     }
 
+  unsigned long long extended_sign_hi = extended_sign;
+#if defined __hppa || defined __mips__
+  /* Invert the most significant bit of the mantissa field.  Cf. snan.h.  */
+  extended_sign_hi ^=
+    (1ULL << (LDBL_MANT_DIG == 106
+              ? 51                          /* double-double representation */
+              : (LDBL_MANT_DIG - 2) - 64)); /* quad precision representation */
+#endif
   union u { unsigned long long i[2]; long double f; } volatile xu, yu;
   /* Although it is tempting to initialize with {0}, Solaris cc (Sun C 5.8)
      on x86_64 miscompiles {0}: it initializes only the lower 80 bits,
@@ -87,8 +98,8 @@ totalorderl (long double const *x, long double const *y)
     bigendian = LDBL_SIGNBIT_WORD < sizeof xu.i[0] / sizeof (unsigned);
 
   unsigned long long
-    xhi = xu.i[!bigendian] ^ extended_sign,
-    yhi = yu.i[!bigendian] ^ extended_sign,
+    xhi = xu.i[!bigendian] ^ extended_sign_hi,
+    yhi = yu.i[!bigendian] ^ extended_sign_hi,
     xlo = xu.i[ bigendian] ^ extended_sign,
     ylo = yu.i[ bigendian] ^ extended_sign;
   return (xhi < yhi) | ((xhi == yhi) & (xlo <= ylo));
index ed6f8011308f5c3df990c694f2c95c8c8b4e287d..76dafb8ecd021b443e0eca6bb16c7c942b58a163 100644 (file)
@@ -10,6 +10,7 @@ m4/signbit.m4
 Depends-on:
 math
 extensions
+float           [test $HAVE_TOTALORDERL = 0 || test $REPLACE_TOTALORDERL = 1]
 stdbool         [test $HAVE_TOTALORDERL = 0 || test $REPLACE_TOTALORDERL = 1]
 isnanl          [test $HAVE_TOTALORDERL = 0 || test $REPLACE_TOTALORDERL = 1]
 signbit         [test $HAVE_TOTALORDERL = 0 || test $REPLACE_TOTALORDERL = 1]