From b4e75104b432e86dc8e308e8f58391bee6b33d78 Mon Sep 17 00:00:00 2001 From: Joseph Myers Date: Thu, 10 Nov 2016 21:41:56 +0000 Subject: [PATCH] Refactor some libm type-generic macros. This patch refactors some type-generic libm macros, in both math.h and math_private.h, to be based on a common __MATH_TG macro rather than all replicating similar logic to choose a function to call based on the type of the argument. This should serve to illustrate what I think float128 support for such macros should look like: common macros such as __MATH_TG may need different definitions depending on whether float128 is supported in glibc, so that the individual macros themselves do not need conditionals on float128 support. Tested for x86_64, x86, mips64 and powerpc. * math/math.h (__MATH_TG): New macro. [__USE_ISOC99] (fpclassify): Define using __MATH_TG. [__USE_ISOC99] (signbit): Likewise. [__USE_ISOC99] (isfinite): Likewise. [__USE_ISOC99] (isnan): Likewise. [__USE_ISOC99] (isinf): Likewise. [__GLIBC_USE (IEC_60559_BFP_EXT)] (issignaling): Likewise. [__GLIBC_USE (IEC_60559_BFP_EXT)] (__MATH_EVAL_FMT2): New macro. [__GLIBC_USE (IEC_60559_BFP_EXT)] (iseqsig): Define using __MATH_TG and __MATH_EVAL_FMT2. * sysdeps/generic/math_private.h (fabs_tg): Define using __MATH_TG. * sysdeps/ieee754/ldbl-128ibm/bits/iscanonical.h [!__NO_LONG_DOUBLE_MATH] (__iscanonicalf): New macro. [!__NO_LONG_DOUBLE_MATH] (__iscanonical): Likewise. [!__NO_LONG_DOUBLE_MATH] (iscanonical): Define using __MATH_TG. * sysdeps/ieee754/ldbl-96/bits/iscanonical.h (__iscanonicalf): New macro. (__iscanonical): Likewise. (iscanonical): Define using __MATH_TG. --- ChangeLog | 23 ++++ math/math.h | 125 ++++++------------ sysdeps/generic/math_private.h | 7 +- .../ieee754/ldbl-128ibm/bits/iscanonical.h | 7 +- sysdeps/ieee754/ldbl-96/bits/iscanonical.h | 7 +- 5 files changed, 70 insertions(+), 99 deletions(-) diff --git a/ChangeLog b/ChangeLog index e2a8e0a23a..40ef733564 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,26 @@ +2016-11-10 Joseph Myers + + * math/math.h (__MATH_TG): New macro. + [__USE_ISOC99] (fpclassify): Define using __MATH_TG. + [__USE_ISOC99] (signbit): Likewise. + [__USE_ISOC99] (isfinite): Likewise. + [__USE_ISOC99] (isnan): Likewise. + [__USE_ISOC99] (isinf): Likewise. + [__GLIBC_USE (IEC_60559_BFP_EXT)] (issignaling): Likewise. + [__GLIBC_USE (IEC_60559_BFP_EXT)] (__MATH_EVAL_FMT2): New macro. + [__GLIBC_USE (IEC_60559_BFP_EXT)] (iseqsig): Define using + __MATH_TG and __MATH_EVAL_FMT2. + * sysdeps/generic/math_private.h (fabs_tg): Define using + __MATH_TG. + * sysdeps/ieee754/ldbl-128ibm/bits/iscanonical.h + [!__NO_LONG_DOUBLE_MATH] (__iscanonicalf): New macro. + [!__NO_LONG_DOUBLE_MATH] (__iscanonical): Likewise. + [!__NO_LONG_DOUBLE_MATH] (iscanonical): Define using __MATH_TG. + * sysdeps/ieee754/ldbl-96/bits/iscanonical.h (__iscanonicalf): New + macro. + (__iscanonical): Likewise. + (iscanonical): Define using __MATH_TG. + 2016-11-10 Adhemerval Zanella * sysdeps/unix/sysv/linux/sh/kernel-features.h: Add include diff --git a/math/math.h b/math/math.h index 70d9b864e8..75ccfc3bed 100644 --- a/math/math.h +++ b/math/math.h @@ -199,6 +199,27 @@ extern int signgam; #endif +/* 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 +# define __MATH_TG(TG_ARG, FUNC, ARGS) \ + (sizeof (TG_ARG) == sizeof (float) ? FUNC ## f ARGS : FUNC ARGS) +#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 + /* ISO C99 defines some generic macros which work on any data type. */ #ifdef __USE_ISOC99 @@ -231,49 +252,22 @@ enum && !defined __OPTIMIZE_SIZE__ # define fpclassify(x) __builtin_fpclassify (FP_NAN, FP_INFINITE, \ FP_NORMAL, FP_SUBNORMAL, FP_ZERO, x) -# elif defined __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)) +# define fpclassify(x) __MATH_TG ((x), __fpclassify, (x)) # endif /* Return nonzero value if sign of X is negative. */ # if __GNUC_PREREQ (4,0) -# define signbit(x) \ - (sizeof (x) == sizeof (float) \ - ? __builtin_signbitf (x) \ - : sizeof (x) == sizeof (double) \ - ? __builtin_signbit (x) : __builtin_signbitl (x)) +# define signbit(x) __MATH_TG ((x), __builtin_signbit, (x)) # else -# 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)) -# endif +# define signbit(x) __MATH_TG ((x), __signbit, (x)) # endif /* Return nonzero value if X is not +-Inf or NaN. */ # if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__ # define isfinite(x) __builtin_isfinite (x) -# elif defined __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)) +# define isfinite(x) __MATH_TG ((x), __finite, (x)) # endif /* Return nonzero value if X is neither zero, subnormal, Inf, nor NaN. */ @@ -287,29 +281,15 @@ enum we already have this functions `__isnan' and it is faster. */ # if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__ # define isnan(x) __builtin_isnan (x) -# elif defined __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)) +# define isnan(x) __MATH_TG ((x), __isnan, (x)) # endif /* Return nonzero value if X is positive or negative infinity. */ # if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__ # define isinf(x) __builtin_isinf_sign (x) -# elif defined __NO_LONG_DOUBLE_MATH -# define isinf(x) \ - (sizeof (x) == sizeof (float) ? __isinff (x) : __isinf (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. */ @@ -329,16 +309,7 @@ enum # include /* Return nonzero value if X is a signaling NaN. */ -# ifdef __NO_LONG_DOUBLE_MATH -# define issignaling(x) \ - (sizeof (x) == sizeof (float) ? __issignalingf (x) : __issignaling (x)) -# else -# define issignaling(x) \ - (sizeof (x) == sizeof (float) \ - ? __issignalingf (x) \ - : sizeof (x) == sizeof (double) \ - ? __issignaling (x) : __issignalingl (x)) -# endif +# define issignaling(x) __MATH_TG ((x), __issignaling, (x)) /* Return nonzero value if X is subnormal. */ # define issubnormal(x) (fpclassify (x) == FP_SUBNORMAL) @@ -555,36 +526,20 @@ extern int matherr (struct exception *__exc); #endif #if __GLIBC_USE (IEC_60559_BFP_EXT) -/* Return X == Y but raising "invalid" and setting errno if X or Y is - a NaN. */ -# ifdef __NO_LONG_DOUBLE_MATH -# if (__FLT_EVAL_METHOD__ == 1 \ - || __FLT_EVAL_METHOD__ == 2 \ - || __FLT_EVAL_METHOD__ > 32) -# define iseqsig(x, y) __iseqsig ((x), (y)) -# else -# define iseqsig(x, y) \ - (sizeof ((x) + (y)) == sizeof (float) \ - ? __iseqsigf ((x), (y)) \ - : __iseqsig ((x), (y))) -# endif +/* An expression whose type has the widest of the evaluation formats + of X and Y (which are of floating-point types). */ +# if __FLT_EVAL_METHOD__ == 2 || __FLT_EVAL_METHOD__ > 64 +# define __MATH_EVAL_FMT2(x, y) ((x) + (y) + 0.0L) +# elif __FLT_EVAL_METHOD__ == 1 || __FLT_EVAL_METHOD__ > 32 +# define __MATH_EVAL_FMT2(x, y) ((x) + (y) + 0.0) # else -# if __FLT_EVAL_METHOD__ == 2 || __FLT_EVAL_METHOD__ > 64 -# define iseqsig(x, y) __iseqsigl ((x), (y)) -# elif __FLT_EVAL_METHOD__ == 1 || __FLT_EVAL_METHOD__ > 32 -# define iseqsig(x, y) \ - (sizeof ((x) + (y)) <= sizeof (double) \ - ? __iseqsig ((x), (y)) \ - : __iseqsigl ((x), (y))) -# else -# define iseqsig(x, y) \ - (sizeof ((x) + (y)) == sizeof (float) \ - ? __iseqsigf ((x), (y)) \ - : sizeof ((x) + (y)) == sizeof (double) \ - ? __iseqsig ((x), (y)) \ - : __iseqsigl ((x), (y))) -# endif +# define __MATH_EVAL_FMT2(x, y) ((x) + (y)) # endif + +/* Return X == Y but raising "invalid" and setting errno if X or Y is + a NaN. */ +# define iseqsig(x, y) \ + __MATH_TG (__MATH_EVAL_FMT2 (x, y), __iseqsig, ((x), (y))) #endif __END_DECLS diff --git a/sysdeps/generic/math_private.h b/sysdeps/generic/math_private.h index 28e5df0a24..c0d4e3dbcd 100644 --- a/sysdeps/generic/math_private.h +++ b/sysdeps/generic/math_private.h @@ -427,12 +427,7 @@ extern long double __lgamma_productl (long double t, long double x, }) #endif -#define fabs_tg(x) __builtin_choose_expr \ - (__builtin_types_compatible_p (__typeof (x), float), \ - __builtin_fabsf (x), \ - __builtin_choose_expr \ - (__builtin_types_compatible_p (__typeof (x), double), \ - __builtin_fabs (x), __builtin_fabsl (x))) +#define fabs_tg(x) __MATH_TG ((x), (__typeof (x)) __builtin_fabs, (x)) #define min_of_type(type) __builtin_choose_expr \ (__builtin_types_compatible_p (type, float), \ FLT_MIN, \ diff --git a/sysdeps/ieee754/ldbl-128ibm/bits/iscanonical.h b/sysdeps/ieee754/ldbl-128ibm/bits/iscanonical.h index c7b7c63f95..d613cde4d3 100644 --- a/sysdeps/ieee754/ldbl-128ibm/bits/iscanonical.h +++ b/sysdeps/ieee754/ldbl-128ibm/bits/iscanonical.h @@ -25,6 +25,8 @@ #else extern int __iscanonicall (long double __x) __THROW __attribute__ ((__const__)); +# define __iscanonicalf(x) ((void) (__typeof (x)) (x), 1) +# define __iscanonical(x) ((void) (__typeof (x)) (x), 1) /* Return nonzero value if X is canonical. In IEEE interchange binary formats, all values are canonical, but the argument must still be @@ -32,8 +34,5 @@ extern int __iscanonicall (long double __x) conversion, before being discarded; in IBM long double, there are encodings that are not consistently handled as corresponding to any particular value of the type, and we return 0 for those. */ -# define iscanonical(x) \ - (sizeof (x) == sizeof (long double) \ - ? __iscanonicall (x) \ - : ((void) (__typeof (x)) (x), 1)) +# define iscanonical(x) __MATH_TG ((x), __iscanonical, (x)) #endif diff --git a/sysdeps/ieee754/ldbl-96/bits/iscanonical.h b/sysdeps/ieee754/ldbl-96/bits/iscanonical.h index af0c72cc7f..8638db8903 100644 --- a/sysdeps/ieee754/ldbl-96/bits/iscanonical.h +++ b/sysdeps/ieee754/ldbl-96/bits/iscanonical.h @@ -22,6 +22,8 @@ extern int __iscanonicall (long double __x) __THROW __attribute__ ((__const__)); +#define __iscanonicalf(x) ((void) (__typeof (x)) (x), 1) +#define __iscanonical(x) ((void) (__typeof (x)) (x), 1) /* Return nonzero value if X is canonical. In IEEE interchange binary formats, all values are canonical, but the argument must still be @@ -29,7 +31,4 @@ extern int __iscanonicall (long double __x) conversion, before being discarded; in extended precision, there are encodings that are not consistently handled as corresponding to any particular value of the type, and we return 0 for those. */ -#define iscanonical(x) \ - (sizeof (x) == sizeof (long double) \ - ? __iscanonicall (x) \ - : ((void) (__typeof (x)) (x), 1)) +#define iscanonical(x) __MATH_TG ((x), __iscanonical, (x)) -- 2.43.5