about summary refs log tree commit diff
diff options
context:
space:
mode:
authorWilco Dijkstra <wdijkstr@arm.com>2015-09-18 16:30:43 +0100
committerWilco Dijkstra <wdijkstr@arm.com>2015-09-18 16:34:45 +0100
commit8df4e219e43a4a257d0759b54fef8c488e2f282e (patch)
treefd17e1976bc8fb5443476300f9bcf9645de920a9
parentcb2f668d4692df8d31b2ccf9b18b86bebe2d9174 (diff)
downloadglibc-8df4e219e43a4a257d0759b54fef8c488e2f282e.tar.gz
glibc-8df4e219e43a4a257d0759b54fef8c488e2f282e.tar.xz
glibc-8df4e219e43a4a257d0759b54fef8c488e2f282e.zip
Add inlining of the C99 math functions isinf/isnan/signbit/isfinite/isnormal/fpclassify using GCC
built-ins when available. Since going through the PLT is expensive for these small functions,
inlining results in major speedups (about 7x on Cortex-A57 for isinf). The GCC built-ins are not
correct if signalling NaN support is required, and thus are turned off in that case (see GCC bug
66462). The test-snan.c tests sNaNs and so must be explicitly built with -fsignaling-nans.

2015-09-18  Wilco Dijkstra  <wdijkstr@arm.com>

        [BZ #15367]
        [BZ #17441]

        * math/Makefile: Build test-snan.c with -fsignaling-nans.
        * math/math.h (fpclassify): Use __builtin_fpclassify when
        available.  (signbit): Use __builtin_signbit(f/l).
        (isfinite): Use__builtin_isfinite.  (isnormal): Use
        __builtin_isnormal.  (isnan): Use __builtin_isnan.
        (isinf): Use __builtin_isinf_sign.
-rw-r--r--ChangeLog12
-rw-r--r--NEWS15
-rw-r--r--math/Makefile3
-rw-r--r--math/math.h42
4 files changed, 56 insertions, 16 deletions
diff --git a/ChangeLog b/ChangeLog
index 93652a9e90..c6216c982b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,17 @@
 2015-09-18  Wilco Dijkstra  <wdijkstr@arm.com>
 
+	[BZ #15367]
+	[BZ #17441]
+
+	* math/Makefile: Build test-snan.c with -fsignaling-nans.
+	* math/math.h (fpclassify): Use __builtin_fpclassify when
+	available.  (signbit): Use __builtin_signbit(f/l).
+	(isfinite): Use__builtin_isfinite.  (isnormal): Use
+	__builtin_isnormal.  (isnan): Use __builtin_isnan.
+	(isinf): Use __builtin_isinf_sign.
+
+2015-09-18  Wilco Dijkstra  <wdijkstr@arm.com>
+
 	* benchtests/Makefile: Add bench-math-inlines, link with libm.
 	* benchtests/bench-math-inlines.c: New benchmark.
 	* benchtests/bench-util.h: New file.
diff --git a/NEWS b/NEWS
index 6a69bdb483..8f487fac8d 100644
--- a/NEWS
+++ b/NEWS
@@ -9,13 +9,14 @@ Version 2.23
 
 * The following bugs are resolved with this release:
 
-  2542, 2543, 2558, 2898, 4404, 6803, 14341, 14912, 15384, 15786, 15918,
-  16141, 16296, 16415, 16517, 16519, 16520, 16521, 16734, 16973, 16985,
-  17118, 17243, 17244, 17787, 17886, 17887, 17905, 18084, 18086, 18240,
-  18265, 18370, 18421, 18480, 18525, 18595, 18610, 18618, 18647, 18661,
-  18674, 18675, 18681, 18757, 18778, 18781, 18787, 18789, 18790, 18795,
-  18796, 18820, 18823, 18824, 18857, 18863, 18870, 18872, 18873, 18875,
-  18887, 18921, 18951, 18952, 18961, 18966, 18967, 18970, 18977.
+  2542, 2543, 2558, 2898, 4404, 6803, 14341, 14912, 15367, 15384, 15786,
+  15918, 16141, 16296, 16415, 16517, 16519, 16520, 16521, 16734, 16973,
+  16985, 17118, 17243, 17244, 17441, 17787, 17886, 17887, 17905, 18084,
+  18086, 18240, 18265, 18370, 18421, 18480, 18525, 18595, 18610, 18618,
+  18647, 18661, 18674, 18675, 18681, 18757, 18778, 18781, 18787, 18789,
+  18790, 18795, 18796, 18820, 18823, 18824, 18857, 18863, 18870, 18872,
+  18873, 18875, 18887, 18921, 18951, 18952, 18961, 18966, 18967, 18970,
+  18977.
 
 * The obsolete header <regexp.h> has been removed.  Programs that require
   this header must be updated to use <regex.h> instead.
diff --git a/math/Makefile b/math/Makefile
index 48e7e4ce52..2e5291a378 100644
--- a/math/Makefile
+++ b/math/Makefile
@@ -176,6 +176,8 @@ CFLAGS-test-tgmath.c = -fno-builtin
 CFLAGS-test-tgmath2.c = -fno-builtin
 CFLAGS-test-tgmath-ret.c = -fno-builtin
 CFLAGS-test-powl.c = -fno-builtin
+
+CFLAGS-test-snan.c = -fsignaling-nans
 CPPFLAGS-test-ifloat.c = -U__LIBC_INTERNAL_MATH_INLINES \
 			 $(libm-test-fast-math-cflags)
 CPPFLAGS-test-idouble.c = -U__LIBC_INTERNAL_MATH_INLINES \
@@ -183,7 +185,6 @@ CPPFLAGS-test-idouble.c = -U__LIBC_INTERNAL_MATH_INLINES \
 CPPFLAGS-test-ildoubl.c = -U__LIBC_INTERNAL_MATH_INLINES \
 			  $(libm-test-fast-math-cflags)
 
-
 # The -lieee module sets the _LIB_VERSION_ switch to IEEE mode
 # for error handling in the -lm functions.
 install-lib += libieee.a
diff --git a/math/math.h b/math/math.h
index 63511a68ec..fa476e0b34 100644
--- a/math/math.h
+++ b/math/math.h
@@ -225,8 +225,16 @@ enum
       FP_NORMAL
   };
 
+/* GCC bug 66462 means we cannot use the math builtins with -fsignaling-nan,
+   so disable builtins if this is enabled.  When fixed in a newer GCC,
+   the __SUPPORT_SNAN__ check may be skipped for those versions.  */
+
 /* Return number of classification appropriate for X.  */
-# ifdef __NO_LONG_DOUBLE_MATH
+# if __GNUC_PREREQ (4,4) && !defined __SUPPORT_SNAN__			      \
+     && !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
@@ -238,19 +246,29 @@ enum
 # endif
 
 /* Return nonzero value if sign of X is negative.  */
-# ifdef __NO_LONG_DOUBLE_MATH
+# if __GNUC_PREREQ (4,0)
 #  define signbit(x) \
-     (sizeof (x) == sizeof (float) ? __signbitf (x) : __signbit (x))
+     (sizeof (x) == sizeof (float)                                            \
+      ? __builtin_signbitf (x)                                                        \
+      : sizeof (x) == sizeof (double)                                         \
+      ? __builtin_signbit (x) : __builtin_signbitl (x))
 # else
-#  define signbit(x) \
+#  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
 # endif
 
 /* Return nonzero value if X is not +-Inf or NaN.  */
-# ifdef __NO_LONG_DOUBLE_MATH
+# 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
@@ -262,11 +280,17 @@ enum
 # 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
+# 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
@@ -278,7 +302,9 @@ enum
 # endif
 
 /* Return nonzero value if X is positive or negative infinity.  */
-# ifdef __NO_LONG_DOUBLE_MATH
+# 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