From 618a165ae745c892a5c19541b4793dfd91b7c131 Mon Sep 17 00:00:00 2001 From: OPNA2608 Date: Sun, 6 Jul 2025 18:55:01 +0200 Subject: [PATCH] gnugrep: Fix gnulib test failure on ppc64 --- pkgs/tools/text/gnugrep/default.nix | 7 + ...loat-h-tests-port-to-C23-PowerPC-GCC.patch | 230 ++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 pkgs/tools/text/gnugrep/gnulib-float-h-tests-port-to-C23-PowerPC-GCC.patch diff --git a/pkgs/tools/text/gnugrep/default.nix b/pkgs/tools/text/gnugrep/default.nix index d4bb7bd9d23e..ea0deac1bb2d 100644 --- a/pkgs/tools/text/gnugrep/default.nix +++ b/pkgs/tools/text/gnugrep/default.nix @@ -28,6 +28,13 @@ stdenv.mkDerivation { hash = "sha256-JkmyfA6Q5jLq3NdXvgbG6aT0jZQd5R58D4P/dkCKB7k="; }; + patches = [ + # Fixes test-float-h failure on ppc64 with C23 + # https://lists.gnu.org/archive/html/bug-gnulib/2025-07/msg00021.html + # Multiple upstream commits squashed with adjustments, see header + ./gnulib-float-h-tests-port-to-C23-PowerPC-GCC.patch + ]; + # Some gnulib tests fail # - on Musl: https://github.com/NixOS/nixpkgs/pull/228714 # - on x86_64-darwin: https://github.com/NixOS/nixpkgs/pull/228714#issuecomment-1576826330 diff --git a/pkgs/tools/text/gnugrep/gnulib-float-h-tests-port-to-C23-PowerPC-GCC.patch b/pkgs/tools/text/gnugrep/gnulib-float-h-tests-port-to-C23-PowerPC-GCC.patch new file mode 100644 index 000000000000..26e0765e7bcf --- /dev/null +++ b/pkgs/tools/text/gnugrep/gnulib-float-h-tests-port-to-C23-PowerPC-GCC.patch @@ -0,0 +1,230 @@ +Applies the following incremental gnulib commits: + +- 55a366a06fbd98bf13adc531579e3513cee97a32 +- 65ed9d3b24ad09fd61d326c83e7f1b05f6e9d65f +- ce8e9de0bf34bc63dffc67ab384334c509175f64 +- 6164b4cb0887b5331a4e64449107decd37d32735 + +With adjustments specific to the structure & differences in gnugrep: + +- gnulib code is completely contained in gnulib-tests (flat, no separate lib directory) +- A Makefile.in is used for the test flags instead of the fancy automake modules + in the upstream gnulib project, so we add -lm to the float test there. + Surrounding texts in this file are slightly different in every project. +--- +diff '--color=auto' -ruN a/gnulib-tests/float.c b/gnulib-tests/float.c +--- a/gnulib-tests/float.c 2025-01-02 03:33:12.000000000 +0100 ++++ b/gnulib-tests/float.c 2025-07-09 06:45:05.176372632 +0200 +@@ -23,7 +23,7 @@ + #if GNULIB_defined_long_double_union + # if (defined _ARCH_PPC || defined _POWER) && (defined _AIX || defined __linux__) && (LDBL_MANT_DIG == 106) && defined __GNUC__ + const union gl_long_double_union gl_LDBL_MAX = +- { { DBL_MAX, DBL_MAX / (double)134217728UL / (double)134217728UL } }; ++ { { DBL_MAX, DBL_MAX / 0x1p53 } }; + # elif defined __i386__ + const union gl_long_double_union gl_LDBL_MAX = + { { 0xFFFFFFFF, 0xFFFFFFFF, 32766 } }; +diff '--color=auto' -ruN a/gnulib-tests/float.in.h b/gnulib-tests/float.in.h +--- a/gnulib-tests/float.in.h 2025-01-02 03:33:12.000000000 +0100 ++++ b/gnulib-tests/float.in.h 2025-07-09 06:44:02.203541534 +0200 +@@ -113,44 +113,38 @@ + # define LDBL_MAX_10_EXP 4932 + #endif + +-/* On AIX 7.1 with gcc 4.2, the values of LDBL_MIN_EXP, LDBL_MIN, LDBL_MAX are +- wrong. +- On Linux/PowerPC with gcc 4.4, the value of LDBL_MAX is wrong. */ +-#if (defined _ARCH_PPC || defined _POWER) && defined _AIX && (LDBL_MANT_DIG == 106) && defined __GNUC__ ++/* On PowerPC with gcc 15 when using __ibm128 long double, the value of ++ LDBL_MIN_EXP, LDBL_MIN, LDBL_MAX, and LDBL_NORM_MAX are wrong. */ ++#if ((defined _ARCH_PPC || defined _POWER) && LDBL_MANT_DIG == 106 \ ++ && defined __GNUC__) + # undef LDBL_MIN_EXP + # define LDBL_MIN_EXP DBL_MIN_EXP + # undef LDBL_MIN_10_EXP + # define LDBL_MIN_10_EXP DBL_MIN_10_EXP + # undef LDBL_MIN + # define LDBL_MIN 2.22507385850720138309023271733240406422e-308L /* DBL_MIN = 2^-1022 */ +-#endif +-#if (defined _ARCH_PPC || defined _POWER) && (defined _AIX || defined __linux__) && (LDBL_MANT_DIG == 106) && defined __GNUC__ + # undef LDBL_MAX +-/* LDBL_MAX is represented as { 0x7FEFFFFF, 0xFFFFFFFF, 0x7C8FFFFF, 0xFFFFFFFF }. +- It is not easy to define: +- #define LDBL_MAX 1.79769313486231580793728971405302307166e308L +- is too small, whereas +- #define LDBL_MAX 1.79769313486231580793728971405302307167e308L +- is too large. Apparently a bug in GCC decimal-to-binary conversion. +- Also, I can't get values larger than +- #define LDBL63 ((long double) (1ULL << 63)) +- #define LDBL882 (LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63) +- #define LDBL945 (LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63) +- #define LDBL1008 (LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63 * LDBL63) +- #define LDBL_MAX (LDBL1008 * 65535.0L + LDBL945 * (long double) 9223372036821221375ULL + LDBL882 * (long double) 4611686018427387904ULL) +- which is represented as { 0x7FEFFFFF, 0xFFFFFFFF, 0x7C8FFFFF, 0xF8000000 }. +- So, define it like this through a reference to an external variable ++/* LDBL_MAX is 2**1024 - 2**918, represented as: { 0x7FEFFFFF, 0xFFFFFFFF, ++ 0x7C9FFFFF, 0xFFFFFFFF }. ++ ++ Do not write it as a constant expression, as GCC would likely treat ++ that as infinity due to the vagaries of this platform's funky arithmetic. ++ Instead, define it through a reference to an external variable. ++ Like the following, but using a union to avoid type mismatches: + +- const double LDBL_MAX[2] = { DBL_MAX, DBL_MAX / (double)134217728UL / (double)134217728UL }; ++ const double LDBL_MAX[2] = { DBL_MAX, DBL_MAX / 0x1p53 }; + extern const long double LDBL_MAX; + +- or through a pointer cast ++ The following alternative would not work as well when GCC is optimizing: ++ ++ #define LDBL_MAX (*(long double const *) (double[]) ++ { DBL_MAX, DBL_MAX / 0x1p53 }) + +- #define LDBL_MAX \ +- (*(const long double *) (double[]) { DBL_MAX, DBL_MAX / (double)134217728UL / (double)134217728UL }) ++ The following alternative would require GCC 6 or later: + +- Unfortunately, this is not a constant expression, and the latter expression +- does not work well when GCC is optimizing.. */ ++ #define LDBL_MAX __builtin_pack_longdouble (DBL_MAX, DBL_MAX / 0x1p53) ++ ++ Unfortunately none of the alternatives are constant expressions. */ + # if !GNULIB_defined_long_double_union + union gl_long_double_union + { +@@ -161,6 +155,8 @@ + # endif + extern const union gl_long_double_union gl_LDBL_MAX; + # define LDBL_MAX (gl_LDBL_MAX.ld) ++# undef LDBL_NORM_MAX ++# define LDBL_NORM_MAX LDBL_MAX + #endif + + /* On IRIX 6.5, with cc, the value of LDBL_MANT_DIG is wrong. +@@ -181,6 +177,21 @@ + # endif + #endif + ++/* On PowerPC platforms, 'long double' has a double-double representation. ++ Up to ISO C 17, this was outside the scope of ISO C because it can represent ++ numbers with mantissas of the form 1.<52 bits><52 bits>, such as ++ 1.0L + 4.94065645841246544176568792868221e-324L = 1 + 2^-1074; see ++ ISO C 17 § 5.2.4.2.2.(3). ++ In ISO C 23, wording has been included that makes this 'long double' ++ representation compliant; see ISO C 23 § 5.2.5.3.3.(8)-(9). In this setting, ++ numbers with mantissas of the form 1.<52 bits><52 bits> are ++ called "unnormalized". And since LDBL_EPSILON must be normalized (per ++ ISO C 23 § 5.2.5.3.3.(33)), it must be 2^-105. */ ++#if defined __powerpc__ && LDBL_MANT_DIG == 106 ++# undef LDBL_EPSILON ++# define LDBL_EPSILON 2.46519032881566189191165176650870696773e-32L /* 2^-105 */ ++#endif ++ + /* ============================ ISO C11 support ============================ */ + + /* 'float' properties */ +@@ -309,7 +320,11 @@ + # endif + #endif + #ifndef LDBL_NORM_MAX +-# define LDBL_NORM_MAX LDBL_MAX ++# ifdef __LDBL_NORM_MAX__ ++# define LDBL_NORM_MAX __LDBL_NORM_MAX__ ++# else ++# define LDBL_NORM_MAX LDBL_MAX ++# endif + #endif + #ifndef LDBL_SNAN + /* For sh, beware of . */ +diff '--color=auto' -ruN a/gnulib-tests/Makefile.in b/gnulib-tests/Makefile.in +--- a/gnulib-tests/Makefile.in 2025-04-10 17:51:23.000000000 +0200 ++++ b/gnulib-tests/Makefile.in 2025-07-09 06:35:48.276939180 +0200 +@@ -1056,7 +1056,7 @@ + ../lib/libgreputils.a libtests.a $(am__DEPENDENCIES_1) + test_float_h_SOURCES = test-float-h.c + test_float_h_OBJECTS = test-float-h.$(OBJEXT) +-test_float_h_LDADD = $(LDADD) ++test_float_h_LDADD = $(LDADD) -lm + test_float_h_DEPENDENCIES = libtests.a ../lib/libgreputils.a \ + libtests.a ../lib/libgreputils.a libtests.a \ + $(am__DEPENDENCIES_1) +diff '--color=auto' -ruN a/gnulib-tests/test-float-h.c b/gnulib-tests/test-float-h.c +--- a/gnulib-tests/test-float-h.c 2025-01-02 03:33:12.000000000 +0100 ++++ b/gnulib-tests/test-float-h.c 2025-07-09 06:54:02.794407115 +0200 +@@ -101,6 +101,8 @@ + + /* ------------------------------------------------------------------------- */ + ++#include ++ + #include "fpucw.h" + #include "isnanf-nolibm.h" + #include "isnand-nolibm.h" +@@ -396,6 +398,44 @@ + + /* -------------------- Check macros for 'long double' -------------------- */ + ++static int ++test_isfinitel (long double volatile x) ++{ ++ if (x != x) ++ return 0; ++ long double volatile zero = x * 0; ++ return zero == 0; ++} ++ ++/* Return X after normalization. This makes a difference on platforms ++ where long double can represent unnormalized values. For example, ++ suppose x = 1 + 2**-106 on PowerPC with IBM long double where ++ FLT_RADIX = 2, LDBL_MANT_DIG = 106, and LDBL_EPSILON = 2**-105. ++ Then 1 < x < 1 + LDBL_EPSILON, and normalize_long_double (x) returns 1. */ ++static long double ++normalize_long_double (long double volatile x) ++{ ++ if (FLT_RADIX == 2 && test_isfinitel (x)) ++ { ++ int xexp; ++ long double volatile ++ frac = frexpl (x, &xexp), ++ significand = frac * pow2l (LDBL_MANT_DIG), ++ normalized_significand = truncl (significand), ++ normalized_x = normalized_significand * pow2l (xexp - LDBL_MANT_DIG); ++ ++ /* The test_isfinitel defends against PowerPC with IBM long double, ++ which fritzes out near LDBL_MAX. */ ++ if (test_isfinitel (normalized_x)) ++ x = normalized_x; ++ } ++ else ++ { ++ /* Hope that X is already normalized. */ ++ } ++ return x; ++} ++ + static void + test_long_double (void) + { +@@ -455,7 +495,7 @@ + for (n = 0; n <= 2 * LDBL_MANT_DIG; n++) + { + volatile long double half_n = pow2l (- n); /* 2^-n */ +- volatile long double x = me - half_n; ++ volatile long double x = normalize_long_double (me - half_n); + if (x < me) + ASSERT (x <= 1.0L); + } +@@ -483,8 +523,12 @@ + ASSERT (!LDBL_IS_IEC_60559); + #endif + ++ printf("LDBL_NORM_MAX: %LF\n", LDBL_NORM_MAX); ++ printf("LDBL_MAX: %LF\n", LDBL_MAX); ++ printf("normalize_long_double(LDBL_MAX): %LF\n", normalize_long_double(LDBL_MAX)); ++ + /* Check the value of LDBL_NORM_MAX. */ +- ASSERT (LDBL_NORM_MAX == LDBL_MAX); ++ ASSERT (LDBL_NORM_MAX == normalize_long_double (LDBL_MAX)); + + /* Check the value of LDBL_SNAN. */ + ASSERT (isnanl (LDBL_SNAN));