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.
This commit is contained in:
Joseph Myers 2015-10-13 00:52:54 +00:00
parent 5b1766a0cd
commit e8dab9477f
7 changed files with 123 additions and 12 deletions

View File

@ -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]

20
NEWS
View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)