diff options
Diffstat (limited to 'sysdeps/powerpc/powerpc32/fpu')
-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 |
4 files changed, 94 insertions, 2 deletions
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) |