This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Refactor some libm type-generic macros [committed]


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.  Committed.

2016-11-10  Joseph Myers  <joseph@codesourcery.com>

	* 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.

diff --git a/math/math.h b/math/math.h
index 70d9b86..75ccfc3 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 <bits/iscanonical.h>
 
 /* 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 28e5df0..c0d4e3d 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 c7b7c63..d613cde 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 af0c72c..8638db8 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))

-- 
Joseph S. Myers
joseph@codesourcery.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]