diff options
author | Joseph Myers <joseph@codesourcery.com> | 2015-10-13 00:52:54 +0000 |
---|---|---|
committer | Joseph Myers <joseph@codesourcery.com> | 2015-10-13 00:52:54 +0000 |
commit | e8dab9477f33ab7a67405f4e147cbaa1a4bb443b (patch) | |
tree | f9a6edfe0acaaa15b4c8a42daad0ef31510e5994 | |
parent | 5b1766a0cde255eff9868a9eeb49f66a89842cb8 (diff) | |
download | glibc-e8dab9477f33ab7a67405f4e147cbaa1a4bb443b.tar.gz glibc-e8dab9477f33ab7a67405f4e147cbaa1a4bb443b.tar.xz glibc-e8dab9477f33ab7a67405f4e147cbaa1a4bb443b.zip |
Fix powerpc32 llrint, llrintf bad exceptions (bug 16422).
The versions of llrint and llrintf for older powerpc32 processors convert the results of __rint / __rintf to long long int, resulting in spurious exceptions from such casts in certain cases. This patch makes glibc work around the problems with the libgcc conversions when the compiler used to build glibc doesn't use the fctidz instruction for them. Tested for powerpc. [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.
-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) |