diff options
-rw-r--r-- | ChangeLog | 16 | ||||
-rw-r--r-- | NEWS | 20 | ||||
-rw-r--r-- | config.h.in | 3 | ||||
-rw-r--r-- | sysdeps/powerpc/powerpc32/fpu/configure | 27 | ||||
-rw-r--r-- | sysdeps/powerpc/powerpc32/fpu/configure.ac | 16 | ||||
-rw-r--r-- | sysdeps/powerpc/powerpc32/fpu/s_llrint.c | 31 | ||||
-rw-r--r-- | sysdeps/powerpc/powerpc32/fpu/s_llrintf.c | 22 |
7 files changed, 123 insertions, 12 deletions
diff --git a/ChangeLog b/ChangeLog index 00e1cc5827..fe606d6134 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +2015-10-13 Joseph Myers <joseph@codesourcery.com> + + [BZ #16422] + * sysdeps/powerpc/powerpc32/fpu/configure.ac (libc_cv_ppc_fctidz): + New configure test. + * sysdeps/powerpc/powerpc32/fpu/configure: Regenerated. + * config.h.in [_LIBC] (HAVE_PPC_FCTIDZ): New macro. + * sysdeps/powerpc/powerpc32/fpu/s_llrint.c: Include <limits.h>, + <math_private.h> and <stdint.h>. + (__llrint): Avoid conversions to long long int where those might + raise spurious exceptions. + * sysdeps/powerpc/powerpc32/fpu/s_llrintf.c: Include + <math_private.h> and <stdint.h>. + (__llrintf): Avoid conversions to long long int where those might + raise spurious exceptions. + 2015-10-12 Andreas Schwab <schwab@suse.de> [BZ #18969] diff --git a/NEWS b/NEWS index 512b338492..478ed2dadb 100644 --- a/NEWS +++ b/NEWS @@ -10,16 +10,16 @@ Version 2.23 * The following bugs are resolved with this release: 887, 2542, 2543, 2558, 2898, 4404, 6803, 10432, 14341, 14912, 15367, - 15384, 15470, 15786, 15918, 16141, 16296, 16347, 16399, 16415, 16517, - 16519, 16520, 16521, 16620, 16734, 16973, 16985, 17118, 17243, 17244, - 17250, 17441, 17787, 17886, 17887, 17905, 18084, 18086, 18240, 18265, - 18370, 18421, 18480, 18525, 18595, 18589, 18610, 18618, 18647, 18661, - 18674, 18675, 18681, 18724, 18757, 18778, 18781, 18787, 18789, 18790, - 18795, 18796, 18803, 18820, 18823, 18824, 18825, 18857, 18863, 18870, - 18872, 18873, 18875, 18887, 18921, 18951, 18952, 18956, 18961, 18966, - 18967, 18969, 18970, 18977, 18980, 18981, 18985, 19003, 19012, 19016, - 19018, 19032, 19046, 19049, 19050, 19059, 19071, 19076, 19077, 19078, - 19079, 19085, 19086, 19088, 19094, 19095. + 15384, 15470, 15786, 15918, 16141, 16296, 16347, 16399, 16415, 16422, + 16517, 16519, 16520, 16521, 16620, 16734, 16973, 16985, 17118, 17243, + 17244, 17250, 17441, 17787, 17886, 17887, 17905, 18084, 18086, 18240, + 18265, 18370, 18421, 18480, 18525, 18595, 18589, 18610, 18618, 18647, + 18661, 18674, 18675, 18681, 18724, 18757, 18778, 18781, 18787, 18789, + 18790, 18795, 18796, 18803, 18820, 18823, 18824, 18825, 18857, 18863, + 18870, 18872, 18873, 18875, 18887, 18921, 18951, 18952, 18956, 18961, + 18966, 18967, 18969, 18970, 18977, 18980, 18981, 18985, 19003, 19012, + 19016, 19018, 19032, 19046, 19049, 19050, 19059, 19071, 19076, 19077, + 19078, 19079, 19085, 19086, 19088, 19094, 19095. * The obsolete header <regexp.h> has been removed. Programs that require this header must be updated to use <regex.h> instead. diff --git a/config.h.in b/config.h.in index 7c851c97fe..5fd4897428 100644 --- a/config.h.in +++ b/config.h.in @@ -251,4 +251,7 @@ /* PowerPC32 uses fcfid for integer to floating point conversions. */ #define HAVE_PPC_FCFID 0 +/* PowerPC32 uses fctidz for floating point to long long conversions. */ +#define HAVE_PPC_FCTIDZ 0 + #endif diff --git a/sysdeps/powerpc/powerpc32/fpu/configure b/sysdeps/powerpc/powerpc32/fpu/configure index 69a151b2c0..98c6f30ca3 100644 --- a/sysdeps/powerpc/powerpc32/fpu/configure +++ b/sysdeps/powerpc/powerpc32/fpu/configure @@ -27,3 +27,30 @@ if test $libc_cv_ppc_fcfid = yes; then $as_echo "#define HAVE_PPC_FCFID 1" >>confdefs.h fi + +# Test whether floating point to long long conversions use fctidz. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fctidz use" >&5 +$as_echo_n "checking for fctidz use... " >&6; } +if ${libc_cv_ppc_fctidz+:} false; then : + $as_echo_n "(cached) " >&6 +else + echo 'long long int foo (double x) { return (long long int) x; }' > conftest.c +libc_cv_ppc_fctidz=no +if { ac_try='${CC-cc} -S $CFLAGS conftest.c -o conftest.s 1>&5' + { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5 + (eval $ac_try) 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + if grep '[ ]fctidz' conftest.s > /dev/null 2>&1; then + libc_cv_ppc_fctidz=yes + fi +fi +rm -rf conftest* +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ppc_fctidz" >&5 +$as_echo "$libc_cv_ppc_fctidz" >&6; } +if test $libc_cv_ppc_fctidz = yes; then + $as_echo "#define HAVE_PPC_FCTIDZ 1" >>confdefs.h + +fi diff --git a/sysdeps/powerpc/powerpc32/fpu/configure.ac b/sysdeps/powerpc/powerpc32/fpu/configure.ac index e596e793ae..1899705aab 100644 --- a/sysdeps/powerpc/powerpc32/fpu/configure.ac +++ b/sysdeps/powerpc/powerpc32/fpu/configure.ac @@ -16,3 +16,19 @@ rm -rf conftest*]) if test $libc_cv_ppc_fcfid = yes; then AC_DEFINE([HAVE_PPC_FCFID]) fi + +# Test whether floating point to long long conversions use fctidz. +AC_CACHE_CHECK([for fctidz use], [libc_cv_ppc_fctidz], [dnl +echo 'long long int foo (double x) { return (long long int) x; }' > conftest.c +libc_cv_ppc_fctidz=no +if AC_TRY_COMMAND(${CC-cc} -S $CFLAGS conftest.c -o conftest.s 1>&AS_MESSAGE_LOG_FD); then +changequote(,)dnl + if grep '[ ]fctidz' conftest.s > /dev/null 2>&1; then + libc_cv_ppc_fctidz=yes + fi +changequote([,])dnl +fi +rm -rf conftest*]) +if test $libc_cv_ppc_fctidz = yes; then + AC_DEFINE([HAVE_PPC_FCTIDZ]) +fi diff --git a/sysdeps/powerpc/powerpc32/fpu/s_llrint.c b/sysdeps/powerpc/powerpc32/fpu/s_llrint.c index 48af9eb726..bb12272461 100644 --- a/sysdeps/powerpc/powerpc32/fpu/s_llrint.c +++ b/sysdeps/powerpc/powerpc32/fpu/s_llrint.c @@ -16,13 +16,42 @@ License along with the GNU C Library; if not, see <http://www.gnu.org/licenses/>. */ +#include <limits.h> #include <math.h> #include <math_ldbl_opt.h> +#include <math_private.h> +#include <stdint.h> long long int __llrint (double x) { - return (long long int) __rint (x); + double rx = __rint (x); + if (HAVE_PPC_FCTIDZ || rx != x) + return (long long int) rx; + else + { + /* Avoid incorrect exceptions from libgcc conversions (as of GCC + 5): <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59412>. */ + if (fabs (rx) < 0x1p31) + return (long long int) (long int) rx; + uint64_t i0; + EXTRACT_WORDS64 (i0, rx); + int exponent = ((i0 >> 52) & 0x7ff) - 0x3ff; + if (exponent < 63) + { + unsigned long long int mant + = (i0 & ((1ULL << 52) - 1)) | (1ULL << 52); + if (exponent < 52) + mant >>= 52 - exponent; + else + mant <<= exponent - 52; + return (long long int) ((i0 & (1ULL << 63)) != 0 ? -mant : mant); + } + else if (rx == (double) LLONG_MIN) + return LLONG_MIN; + else + return (long long int) (long int) rx << 32; + } } weak_alias (__llrint, llrint) #ifdef NO_LONG_DOUBLE diff --git a/sysdeps/powerpc/powerpc32/fpu/s_llrintf.c b/sysdeps/powerpc/powerpc32/fpu/s_llrintf.c index 205df4e03a..bcee02020a 100644 --- a/sysdeps/powerpc/powerpc32/fpu/s_llrintf.c +++ b/sysdeps/powerpc/powerpc32/fpu/s_llrintf.c @@ -17,10 +17,30 @@ <http://www.gnu.org/licenses/>. */ #include <math.h> +#include <math_private.h> +#include <stdint.h> long long int __llrintf (float x) { - return (long long int) __rintf (x); + float rx = __rintf (x); + if (HAVE_PPC_FCTIDZ || rx != x) + return (long long int) rx; + else + { + float arx = fabsf (rx); + /* Avoid incorrect exceptions from libgcc conversions (as of GCC + 5): <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59412>. */ + if (arx < 0x1p31f) + return (long long int) (long int) rx; + else if (!(arx < 0x1p55f)) + return (long long int) (long int) (rx * 0x1p-32f) << 32; + uint32_t i0; + GET_FLOAT_WORD (i0, rx); + int exponent = ((i0 >> 23) & 0xff) - 0x7f; + unsigned long long int mant = (i0 & 0x7fffff) | 0x800000; + mant <<= exponent - 23; + return (long long int) ((i0 & 0x80000000) != 0 ? -mant : mant); + } } weak_alias (__llrintf, llrintf) |