math: Do not use __builtin_isgreater* and __builtin_isless* on clang

clang does not check for unordered numbers with builtins for 128-bit
float types (both _Float128 on x86_64 or long double on aarch64) [1].

For instance, the code:

  #ifdef __x86_64__
  typedef __float128 FLOAT128_TYPE;
  #elif defined (__aarch64__)
  typedef long double FLOAT128_TYPE;
  #endif

  int foo (FLOAT128_TYPE x, FLOAT128_TYPE y)
  {
    return __builtin_isgreater (x, y);
  }

Will issue a __gttf2 call instead of a __unordtf2 followed by the
comparison.

Using the generic implementation fixes multiple issues with math tests,
such as:

Failure: fmax (0, qNaN): Exception "Invalid operation" set
Failure: fmax (0, -qNaN): Exception "Invalid operation" set
Failure: fmax (-0, qNaN): Exception "Invalid operation" set
Failure: fmax (-0, -qNaN): Exception "Invalid operation" set
Failure: fmax (9, qNaN): Exception "Invalid operation" set
Failure: fmax (9, -qNaN): Exception "Invalid operation" set
Failure: fmax (-9, qNaN): Exception "Invalid operation" set
Failure: fmax (-9, -qNaN): Exception "Invalid operation" set

It has a small performance overhead due to the extra isunordered (which
could be omitted for float and double types). Using _Generic (similar to
how __MATH_TG) on a bivariadic function requires a lot of boilerplate
macros.

[1] https://github.com/llvm/llvm-project/issues/172499
Reviewed-by: H.J. Lu <hjl.tools@gmail.com>
This commit is contained in:
Adhemerval Zanella
2025-12-17 14:51:47 -03:00
parent 9021707ca7
commit 42b4589f28

View File

@@ -1433,7 +1433,7 @@ iszero (__T __val)
#endif #endif
#ifdef __USE_ISOC99 #ifdef __USE_ISOC99
# if __GNUC_PREREQ (3, 1) # if __GNUC_PREREQ (3, 1) && !defined __clang__
/* ISO C99 defines some macros to compare number while taking care for /* ISO C99 defines some macros to compare number while taking care for
unordered numbers. Many FPUs provide special instructions to support unordered numbers. Many FPUs provide special instructions to support
these operations. Generic support in GCC for these as builtins went these operations. Generic support in GCC for these as builtins went