On platforms where 'long double' is the same as 'double' (namely, MSVC), it
is a waste of code to compile both 'totalorder' and 'totalorderl' with the
complicated algorithm, since they will both do the same thing. Instead,
better just redirect from 'totalorderl' to 'totalorder' (like we already
do for many 'long double' functions).

Once we do this, the code branch

  if (sizeof (long double) <= sizeof (unsigned long long))

is no longer needed, since no platform exists (nor will likely ever exist)
where 'long double' needs at most 64 bits but is *not* the same as 'double'.


2024-04-18  Bruno Haible  <br...@clisp.org>

        totalorderl: Simplify on MSVC.
        * lib/totalorderl.c (totalorderl): If 'long double' is the same as
        'double', just invoke totalorder. Otherwise, drop the optimized code
        for small 'long double' since it does not occur on any platform.
        * m4/totalorder.m4 (gl_FUNC_TOTALORDERL): Require
        gl_LONG_DOUBLE_VS_DOUBLE. If 'long double' is the same as 'double', use
        TOTALORDER_LIBM.
        * modules/totalorderl (Depends-on): Add totalorder.

diff --git a/lib/totalorderl.c b/lib/totalorderl.c
index 1532a84c10..4ccb7e7e23 100644
--- a/lib/totalorderl.c
+++ b/lib/totalorderl.c
@@ -21,11 +21,21 @@
 /* Specification.  */
 #include <math.h>
 
-#include <float.h>
+#if HAVE_SAME_LONG_DOUBLE_AS_DOUBLE
 
-#ifndef LDBL_SIGNBIT_WORD
-# define LDBL_SIGNBIT_WORD (-1)
-#endif
+int
+totalorderl (long double const *x, long double const *y)
+{
+  return totalorder ((double const *) x, (double const *) y);
+}
+
+#else
+
+# include <float.h>
+
+# ifndef LDBL_SIGNBIT_WORD
+#  define LDBL_SIGNBIT_WORD (-1)
+# endif
 
 int
 totalorderl (long double const *x, long double const *y)
@@ -52,28 +62,14 @@ totalorderl (long double const *x, long double const *y)
   /* At this point, *X and *Y are NaNs with the same sign bit.  */
 
   unsigned long long extended_sign = -!!xs;
-
-  if (sizeof (long double) <= sizeof (unsigned long long))
-    {
-#if defined __hppa || defined __mips__ || defined __sh__
-      /* 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;
-      yu.f = *y;
-      return (xu.i ^ extended_sign) <= (yu.i ^ extended_sign);
-    }
-
   unsigned long long extended_sign_hi = extended_sign;
-#if defined __hppa || defined __mips__ || defined __sh__
+# if defined __hppa || defined __mips__ || defined __sh__
   /* 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
+# 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,
@@ -104,3 +100,5 @@ totalorderl (long double const *x, long double const *y)
     ylo = yu.i[ bigendian] ^ extended_sign;
   return (xhi < yhi) | ((xhi == yhi) & (xlo <= ylo));
 }
+
+#endif
diff --git a/m4/totalorder.m4 b/m4/totalorder.m4
index 92166de484..51012b8503 100644
--- a/m4/totalorder.m4
+++ b/m4/totalorder.m4
@@ -1,5 +1,5 @@
 # totalorder.m4
-# serial 1
+# serial 2
 dnl Copyright 2023-2024 Free Software Foundation, Inc.
 dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
@@ -85,6 +85,7 @@ AC_DEFUN([gl_FUNC_TOTALORDERL]
 [
   AC_REQUIRE([gl_MATH_H_DEFAULTS])
   AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+  AC_REQUIRE([gl_LONG_DOUBLE_VS_DOUBLE])
 
   dnl glibc versions < 2.31 had an incompatible declaration of this function,
   dnl see 
<https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=42760d764649ad82f5fe45a26cbdf2c2500409f7>
@@ -115,7 +116,13 @@ AC_DEFUN([gl_FUNC_TOTALORDERL]
     fi
   fi
   if test $HAVE_TOTALORDERL = 0 || test $REPLACE_TOTALORDERL = 1; then
-    TOTALORDERL_LIBM='$(ISNANL_LIBM)'
+    dnl Find libraries needed to link lib/totalorderl.c.
+    if test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1; then
+      AC_REQUIRE([gl_FUNC_TOTALORDER])
+      TOTALORDERL_LIBM="$TOTALORDER_LIBM"
+    else
+      TOTALORDERL_LIBM='$(ISNANL_LIBM)'
+    fi
     dnl Prerequisite of lib/totalorderl.c.
     gl_LONG_DOUBLE_SIGN_LOCATION
   fi
diff --git a/modules/totalorderl b/modules/totalorderl
index 76dafb8ecd..d153f4c8cc 100644
--- a/modules/totalorderl
+++ b/modules/totalorderl
@@ -10,10 +10,11 @@ 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]
+totalorder      [{ test $HAVE_TOTALORDERL = 0 || test $REPLACE_TOTALORDERL = 
1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 1]
+float           [{ test $HAVE_TOTALORDERL = 0 || test $REPLACE_TOTALORDERL = 
1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
+stdbool         [{ test $HAVE_TOTALORDERL = 0 || test $REPLACE_TOTALORDERL = 
1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
+isnanl          [{ test $HAVE_TOTALORDERL = 0 || test $REPLACE_TOTALORDERL = 
1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
+signbit         [{ test $HAVE_TOTALORDERL = 0 || test $REPLACE_TOTALORDERL = 
1; } && test $HAVE_SAME_LONG_DOUBLE_AS_DOUBLE = 0]
 
 configure.ac:
 gl_FUNC_TOTALORDERL




Reply via email to