From 8df4e219e43a4a257d0759b54fef8c488e2f282e Mon Sep 17 00:00:00 2001 From: Wilco Dijkstra Date: Fri, 18 Sep 2015 16:30:43 +0100 Subject: [PATCH] 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 [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. --- ChangeLog | 12 ++++++++++++ NEWS | 15 ++++++++------- math/Makefile | 3 ++- math/math.h | 42 ++++++++++++++++++++++++++++++++++-------- 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/ChangeLog b/ChangeLog index 93652a9e90..c6216c982b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2015-09-18 Wilco Dijkstra + + [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 * benchtests/Makefile: Add bench-math-inlines, link with libm. 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 has been removed. Programs that require this header must be updated to use 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