--- centos7/math.h 2020-12-31 23:15:40.678843646 +0100 +++ builtin/math.h 2022-03-16 21:35:13.086169875 +0100 @@ -206,68 +206,142 @@ FP_NORMAL }; + +/* Depending on the type of TG_ARG, call an appropriately suffixed + version of FUNC with arguments (including parentheses) ARGS. + Suffixed functions may not exist for long double if it has the same + format as double, or for other types with the same format as float, + double or long double. The behavior is undefined if the argument + does not have a real floating type. The definition may use a + conditional expression, so all suffixed versions of FUNC must + return the same type (FUNC may include a cast if necessary rather + than being a single identifier). */ +#ifdef __NO_LONG_DOUBLE_MATH +# if __HAVE_DISTINCT_FLOAT128 +# error "Distinct _Float128 without distinct long double not supported." +# endif +# define __MATH_TG(TG_ARG, FUNC, ARGS) \ + (sizeof (TG_ARG) == sizeof (float) ? FUNC ## f ARGS : FUNC ARGS) +#elif __HAVE_DISTINCT_FLOAT128 +# if __HAVE_GENERIC_SELECTION +# if __HAVE_FLOATN_NOT_TYPEDEF && __HAVE_FLOAT32 +# define __MATH_TG_F32(FUNC, ARGS) _Float32: FUNC ## f ARGS, +# else +# define __MATH_TG_F32(FUNC, ARGS) +# endif +# if __HAVE_FLOATN_NOT_TYPEDEF && __HAVE_FLOAT64X +# if __HAVE_FLOAT64X_LONG_DOUBLE +# define __MATH_TG_F64X(FUNC, ARGS) _Float64x: FUNC ## l ARGS, +# else +# define __MATH_TG_F64X(FUNC, ARGS) _Float64x: FUNC ## f128 ARGS, +# endif +# else +# define __MATH_TG_F64X(FUNC, ARGS) +# endif +# define __MATH_TG(TG_ARG, FUNC, ARGS) \ + _Generic ((TG_ARG), \ + float: FUNC ## f ARGS, \ + __MATH_TG_F32 (FUNC, ARGS) \ + default: FUNC ARGS, \ + long double: FUNC ## l ARGS, \ + __MATH_TG_F64X (FUNC, ARGS) \ + _Float128: FUNC ## f128 ARGS) +# else +# if __HAVE_FLOATN_NOT_TYPEDEF +# error "Non-typedef _FloatN but no _Generic." +# endif +# define __MATH_TG(TG_ARG, FUNC, ARGS) \ + __builtin_choose_expr \ + (__builtin_types_compatible_p (__typeof (TG_ARG), float), \ + FUNC ## f ARGS, \ + __builtin_choose_expr \ + (__builtin_types_compatible_p (__typeof (TG_ARG), double), \ + FUNC ARGS, \ + __builtin_choose_expr \ + (__builtin_types_compatible_p (__typeof (TG_ARG), long double), \ + FUNC ## l ARGS, \ + FUNC ## f128 ARGS))) +# endif +#else +# define __MATH_TG(TG_ARG, FUNC, ARGS) \ + (sizeof (TG_ARG) == sizeof (float) \ + ? FUNC ## f ARGS \ + : sizeof (TG_ARG) == sizeof (double) \ + ? FUNC ARGS \ + : FUNC ## l ARGS) +#endif + /* Return number of classification appropriate for X. */ -# ifdef __NO_LONG_DOUBLE_MATH -# define fpclassify(x) \ - (sizeof (x) == sizeof (float) ? __fpclassifyf (x) : __fpclassify (x)) -# else -# define fpclassify(x) \ - (sizeof (x) == sizeof (float) \ - ? __fpclassifyf (x) \ - : sizeof (x) == sizeof (double) \ - ? __fpclassify (x) : __fpclassifyl (x)) +# if ((__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) \ + ) \ + && (!defined __OPTIMIZE_SIZE__ || defined __cplusplus) + /* The check for __cplusplus allows the use of the builtin, even + when optimization for size is on. This is provided for + libstdc++, only to let its configure test work when it is built + with -Os. No further use of this definition of fpclassify is + expected in C++ mode, since libstdc++ provides its own version + of fpclassify in cmath (which undefines fpclassify). */ +# define fpclassify(x) __builtin_fpclassify (FP_NAN, FP_INFINITE, \ + FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x) +# else +# define fpclassify(x) __MATH_TG ((x), __fpclassify, (x)) # endif /* Return nonzero value if sign of X is negative. */ -# ifdef __NO_LONG_DOUBLE_MATH -# define signbit(x) \ - (sizeof (x) == sizeof (float) ? __signbitf (x) : __signbit (x)) -# else -# define signbit(x) \ - (sizeof (x) == sizeof (float) \ - ? __signbitf (x) \ - : sizeof (x) == sizeof (double) \ - ? __signbit (x) : __signbitl (x)) +# if __GNUC_PREREQ (6,0) +# define signbit(x) __builtin_signbit (x) +# elif defined __cplusplus + /* In C++ mode, __MATH_TG cannot be used, because it relies on + __builtin_types_compatible_p, which is a C-only builtin. + The check for __cplusplus allows the use of the builtin instead of + __MATH_TG. This is provided for libstdc++, only to let its configure + test work. No further use of this definition of signbit is expected + in C++ mode, since libstdc++ provides its own version of signbit + in cmath (which undefines signbit). */ +# define signbit(x) __builtin_signbitl (x) +# elif __GNUC_PREREQ (4,0) +# define signbit(x) __MATH_TG ((x), __builtin_signbit, (x)) +# else +# define signbit(x) __MATH_TG ((x), __signbit, (x)) # endif /* Return nonzero value if X is not +-Inf or NaN. */ -# ifdef __NO_LONG_DOUBLE_MATH -# define isfinite(x) \ - (sizeof (x) == sizeof (float) ? __finitef (x) : __finite (x)) -# else -# define isfinite(x) \ - (sizeof (x) == sizeof (float) \ - ? __finitef (x) \ - : sizeof (x) == sizeof (double) \ - ? __finite (x) : __finitel (x)) +# if (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) +# define isfinite(x) __builtin_isfinite (x) +# else +# define isfinite(x) __MATH_TG ((x), __finite, (x)) # endif /* Return nonzero value if X is neither zero, subnormal, Inf, nor NaN. */ -# define isnormal(x) (fpclassify (x) == FP_NORMAL) +# if (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) +# define isnormal(x) __builtin_isnormal (x) +# else +# define isnormal(x) (fpclassify (x) == FP_NORMAL) +# endif /* Return nonzero value if X is a NaN. We could use `fpclassify' but we already have this functions `__isnan' and it is faster. */ -# ifdef __NO_LONG_DOUBLE_MATH -# define isnan(x) \ - (sizeof (x) == sizeof (float) ? __isnanf (x) : __isnan (x)) -# else -# define isnan(x) \ - (sizeof (x) == sizeof (float) \ - ? __isnanf (x) \ - : sizeof (x) == sizeof (double) \ - ? __isnan (x) : __isnanl (x)) +# if (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) +# define isnan(x) __builtin_isnan (x) +# else +# define isnan(x) __MATH_TG ((x), __isnan, (x)) # endif /* Return nonzero value if X is positive or negative infinity. */ -# ifdef __NO_LONG_DOUBLE_MATH +# if __HAVE_DISTINCT_FLOAT128 && !__GNUC_PREREQ (7,0) \ + && !defined __SUPPORT_SNAN__ && !defined __cplusplus + /* Since __builtin_isinf_sign is broken for float128 before GCC 7.0, + use the helper function, __isinff128, with older compilers. This is + only provided for C mode, because in C++ mode, GCC has no support + for __builtin_types_compatible_p (and when in C++ mode, this macro is + not used anyway, because libstdc++ headers undefine it). */ # define isinf(x) \ - (sizeof (x) == sizeof (float) ? __isinff (x) : __isinf (x)) + (__builtin_types_compatible_p (__typeof (x), _Float128) \ + ? __isinff128 (x) : __builtin_isinf_sign (x)) +# elif (__GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__) +# define isinf(x) __builtin_isinf_sign (x) # else -# define isinf(x) \ - (sizeof (x) == sizeof (float) \ - ? __isinff (x) \ - : sizeof (x) == sizeof (double) \ - ? __isinf (x) : __isinfl (x)) +# define isinf(x) __MATH_TG ((x), __isinf, (x)) # endif /* Bitmasks for the math_errhandling macro. */