Work around powerpc32 integer 0 converting to -0 (bug 887, bug 19049, bug 19050).

On powerpc32 hard-float, older processors (ones where fcfid is not
available for 32-bit code), GCC generates conversions from integers to
floating point that wrongly convert integer 0 to -0 instead of +0 in
FE_DOWNWARD mode.  This in turn results in logb and a few other
functions wrongly returning -0 when they should return +0.

This patch works around this issue in glibc as I proposed in
<https://sourceware.org/ml/libc-alpha/2015-09/msg00728.html>, so that
the affected functions can be correct and the affected tests pass in
the absence of a GCC fix for this longstanding issue (GCC bug 67771 -
if fixed, of course we can put in GCC version conditionals, and
eventually phase out the workarounds).  A new macro
FIX_INT_FP_CONVERT_ZERO is added in a new sysdeps header
fix-int-fp-convert-zero.h, and the powerpc32/fpu version of that
header defines the macro based on the results of a configure test for
whether such conversions use the fcfid instruction.

Tested for x86_64 (that installed stripped shared libraries are
unchanged by the patch) and powerpc (that HAVE_PPC_FCFID comes out to
0 as expected and that the relevant tests are fixed).  Also tested a
build with GCC configured for -mcpu=power4 and verified that
HAVE_PPC_FCFID comes out to 1 in that case.

There are still some other issues to fix to get test-float and
test-double passing cleanly for older powerpc32 processors (apart from
the need for an ulps regeneration for powerpc).  (test-ldouble will be
harder to get passing cleanly, but with a combination of selected
fixes to ldbl-128ibm code that don't involve significant performance
issues, allowing spurious underflow and inexact exceptions for that
format, and lots of XFAILing for the default case of unpatched libgcc,
it should be doable.)

	[BZ #887]
	[BZ #19049]
	[BZ #19050]
	* sysdeps/generic/fix-int-fp-convert-zero.h: New file.
	* sysdeps/ieee754/dbl-64/e_log10.c: Include
	<fix-int-fp-convert-zero.h>.
	(__ieee754_log10): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
	* sysdeps/ieee754/dbl-64/e_log2.c: Include
	<fix-int-fp-convert-zero.h>.
	(__ieee754_log2): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
	* sysdeps/ieee754/dbl-64/s_erf.c: Include
	<fix-int-fp-convert-zero.h>.
	(__erfc): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
	* sysdeps/ieee754/dbl-64/s_logb.c: Include
	<fix-int-fp-convert-zero.h>.
	(__logb): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
	* sysdeps/ieee754/flt-32/e_log10f.c: Include
	<fix-int-fp-convert-zero.h>.
	(__ieee754_log10f): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
	* sysdeps/ieee754/flt-32/e_log2f.c: Include
	<fix-int-fp-convert-zero.h>.
	(__ieee754_log2f): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
	* sysdeps/ieee754/flt-32/s_erff.c: Include
	<fix-int-fp-convert-zero.h>.
	(__erfcf): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
	* sysdeps/ieee754/flt-32/s_logbf.c: Include
	<fix-int-fp-convert-zero.h>.
	(__logbf): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
	* sysdeps/ieee754/ldbl-128ibm/s_erfl.c: Include
	<fix-int-fp-convert-zero.h>.
	(__erfcl): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
	* sysdeps/ieee754/ldbl-128ibm/s_logbl.c: Include
	<fix-int-fp-convert-zero.h>.
	(__logbl): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
	* sysdeps/powerpc/powerpc32/fpu/configure.ac: New file.
	* sysdeps/powerpc/powerpc32/fpu/configure: New generated file.
	* sysdeps/powerpc/powerpc32/fpu/fix-int-fp-convert-zero.h: New
	file.
	* config.h.in [_LIBC] (HAVE_PPC_FCFID): New macro.
This commit is contained in:
Joseph Myers 2015-10-05 17:46:50 +00:00
parent 57352c2201
commit bc3753638a
17 changed files with 199 additions and 14 deletions

View File

@ -1,3 +1,45 @@
2015-10-05 Joseph Myers <joseph@codesourcery.com>
[BZ #887]
[BZ #19049]
[BZ #19050]
* sysdeps/generic/fix-int-fp-convert-zero.h: New file.
* sysdeps/ieee754/dbl-64/e_log10.c: Include
<fix-int-fp-convert-zero.h>.
(__ieee754_log10): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
* sysdeps/ieee754/dbl-64/e_log2.c: Include
<fix-int-fp-convert-zero.h>.
(__ieee754_log2): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
* sysdeps/ieee754/dbl-64/s_erf.c: Include
<fix-int-fp-convert-zero.h>.
(__erfc): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
* sysdeps/ieee754/dbl-64/s_logb.c: Include
<fix-int-fp-convert-zero.h>.
(__logb): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
* sysdeps/ieee754/flt-32/e_log10f.c: Include
<fix-int-fp-convert-zero.h>.
(__ieee754_log10f): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
* sysdeps/ieee754/flt-32/e_log2f.c: Include
<fix-int-fp-convert-zero.h>.
(__ieee754_log2f): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
* sysdeps/ieee754/flt-32/s_erff.c: Include
<fix-int-fp-convert-zero.h>.
(__erfcf): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
* sysdeps/ieee754/flt-32/s_logbf.c: Include
<fix-int-fp-convert-zero.h>.
(__logbf): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
* sysdeps/ieee754/ldbl-128ibm/s_erfl.c: Include
<fix-int-fp-convert-zero.h>.
(__erfcl): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
* sysdeps/ieee754/ldbl-128ibm/s_logbl.c: Include
<fix-int-fp-convert-zero.h>.
(__logbl): Adjust signs as needed if FIX_INT_FP_CONVERT_ZERO.
* sysdeps/powerpc/powerpc32/fpu/configure.ac: New file.
* sysdeps/powerpc/powerpc32/fpu/configure: New generated file.
* sysdeps/powerpc/powerpc32/fpu/fix-int-fp-convert-zero.h: New
file.
* config.h.in [_LIBC] (HAVE_PPC_FCFID): New macro.
2015-10-03 Paul Pluzhnikov <ppluzhnikov@google.com>
* sysdeps/x86_64/fpu/libm-test-ulps: Regenerated.

18
NEWS
View File

@ -9,15 +9,15 @@ Version 2.23
* The following bugs are resolved with this release:
2542, 2543, 2558, 2898, 4404, 6803, 14341, 14912, 15367, 15384, 15786,
15918, 16141, 16296, 16347, 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, 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, 19016, 19032, 19046, 19059.
887, 2542, 2543, 2558, 2898, 4404, 6803, 14341, 14912, 15367, 15384,
15786, 15918, 16141, 16296, 16347, 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, 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, 19016, 19032, 19046, 19049, 19050, 19059.
* The obsolete header <regexp.h> has been removed. Programs that require
this header must be updated to use <regex.h> instead.

View File

@ -260,4 +260,7 @@
/* The PowerPC64 ELFv2 ABI is being used. */
#undef HAVE_ELFV2_ABI
/* PowerPC32 uses fcfid for integer to floating point conversions. */
#define HAVE_PPC_FCFID 0
#endif

View File

@ -0,0 +1,27 @@
/* Fix for conversion of integer 0 to floating point. Generic version.
Copyright (C) 2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#ifndef FIX_INT_FP_CONVERT_ZERO_H
#define FIX_INT_FP_CONVERT_ZERO_H 1
/* Define this macro to 1 to work around conversions of integer 0 to
floating point returning -0 instead of the correct +0 in some
rounding modes. */
#define FIX_INT_FP_CONVERT_ZERO 0
#endif /* fix-int-fp-convert-zero.h */

View File

@ -45,6 +45,7 @@
#include <math.h>
#include <math_private.h>
#include <fix-int-fp-convert-zero.h>
static const double two54 = 1.80143985094819840000e+16; /* 0x43500000, 0x00000000 */
static const double ivln10 = 4.34294481903251816668e-01; /* 0x3FDBCB7B, 0x1526E50E */
@ -77,6 +78,8 @@ __ieee754_log10 (double x)
i = ((u_int32_t) k & 0x80000000) >> 31;
hx = (hx & 0x000fffff) | ((0x3ff - i) << 20);
y = (double) (k + i);
if (FIX_INT_FP_CONVERT_ZERO && y == 0.0)
y = 0.0;
SET_HIGH_WORD (x, hx);
z = y * log10_2lo + ivln10 * __ieee754_log (x);
return z + y * log10_2hi;

View File

@ -56,6 +56,7 @@
#include <math.h>
#include <math_private.h>
#include <fix-int-fp-convert-zero.h>
static const double ln2 = 0.69314718055994530942;
static const double two54 = 1.80143985094819840000e+16; /* 43500000 00000000 */
@ -101,7 +102,11 @@ __ieee754_log2 (double x)
if ((0x000fffff & (2 + hx)) < 3)
{ /* |f| < 2**-20 */
if (f == zero)
return dk;
{
if (FIX_INT_FP_CONVERT_ZERO && dk == 0.0)
dk = 0.0;
return dk;
}
R = f * f * (0.5 - 0.33333333333333333 * f);
return dk - (R - f) / ln2;
}

View File

@ -116,6 +116,7 @@ static char rcsid[] = "$NetBSD: s_erf.c,v 1.8 1995/05/10 20:47:05 jtc Exp $";
#include <float.h>
#include <math.h>
#include <math_private.h>
#include <fix-int-fp-convert-zero.h>
static const double
tiny = 1e-300,
@ -308,7 +309,10 @@ __erfc (double x)
ix = hx & 0x7fffffff;
if (ix >= 0x7ff00000) /* erfc(nan)=nan */
{ /* erfc(+-inf)=0,2 */
return (double) (((u_int32_t) hx >> 31) << 1) + one / x;
double ret = (double) (((u_int32_t) hx >> 31) << 1) + one / x;
if (FIX_INT_FP_CONVERT_ZERO && ret == 0.0)
return 0.0;
return ret;
}
if (ix < 0x3feb0000) /* |x|<0.84375 */

View File

@ -18,6 +18,7 @@
#include <math.h>
#include <math_private.h>
#include <fix-int-fp-convert-zero.h>
double
__logb (double x)
@ -41,6 +42,8 @@ __logb (double x)
ma = __builtin_clz (ix);
rix -= ma - 12;
}
if (FIX_INT_FP_CONVERT_ZERO && rix == 1023)
return 0.0;
return (double) (rix - 1023);
}
weak_alias (__logb, logb)

View File

@ -15,6 +15,7 @@
#include <math.h>
#include <math_private.h>
#include <fix-int-fp-convert-zero.h>
static const float
two25 = 3.3554432000e+07, /* 0x4c000000 */
@ -44,6 +45,8 @@ __ieee754_log10f(float x)
i = ((u_int32_t)k&0x80000000)>>31;
hx = (hx&0x007fffff)|((0x7f-i)<<23);
y = (float)(k+i);
if (FIX_INT_FP_CONVERT_ZERO && y == 0.0f)
y = 0.0f;
SET_FLOAT_WORD(x,hx);
z = y*log10_2lo + ivln10*__ieee754_logf(x);
return z+y*log10_2hi;

View File

@ -17,6 +17,7 @@
#include <math.h>
#include <math_private.h>
#include <fix-int-fp-convert-zero.h>
static const float
ln2 = 0.69314718055994530942,
@ -57,7 +58,12 @@ __ieee754_log2f(float x)
dk = (float)k;
f = x-(float)1.0;
if((0x007fffff&(15+ix))<16) { /* |f| < 2**-20 */
if(f==zero) return dk;
if(f==zero)
{
if (FIX_INT_FP_CONVERT_ZERO && dk == 0.0f)
dk = 0.0f;
return dk;
}
R = f*f*((float)0.5-(float)0.33333333333333333*f);
return dk-(R-f)/ln2;
}

View File

@ -21,6 +21,7 @@ static char rcsid[] = "$NetBSD: s_erff.c,v 1.4 1995/05/10 20:47:07 jtc Exp $";
#include <float.h>
#include <math.h>
#include <math_private.h>
#include <fix-int-fp-convert-zero.h>
static const float
tiny = 1e-30,
@ -161,7 +162,10 @@ float __erfcf(float x)
ix = hx&0x7fffffff;
if(ix>=0x7f800000) { /* erfc(nan)=nan */
/* erfc(+-inf)=0,2 */
return (float)(((u_int32_t)hx>>31)<<1)+one/x;
float ret = (float)(((u_int32_t)hx>>31)<<1)+one/x;
if (FIX_INT_FP_CONVERT_ZERO && ret == 0.0f)
return 0.0f;
return ret;
}
if(ix < 0x3f580000) { /* |x|<0.84375 */

View File

@ -15,6 +15,7 @@
#include <math.h>
#include <math_private.h>
#include <fix-int-fp-convert-zero.h>
float
__logbf (float x)
@ -33,6 +34,8 @@ __logbf (float x)
though it were normalized. */
rix -= __builtin_clz (ix) - 9;
}
if (FIX_INT_FP_CONVERT_ZERO && rix == 127)
return 0.0f;
return (float) (rix - 127);
}
weak_alias (__logbf, logbf)

View File

@ -106,6 +106,7 @@
#include <math.h>
#include <math_private.h>
#include <math_ldbl_opt.h>
#include <fix-int-fp-convert-zero.h>
/* Evaluate P[n] x^n + P[n-1] x^(n-1) + ... + P[0] */
@ -839,7 +840,10 @@ __erfcl (long double x)
if (ix >= 0x7ff00000)
{ /* erfc(nan)=nan */
/* erfc(+-inf)=0,2 */
return (long double) ((hx >> 31) << 1) + one / x;
long double ret = (long double) ((hx >> 31) << 1) + one / x;
if (FIX_INT_FP_CONVERT_ZERO && ret == 0.0L)
return 0.0L;
return ret;
}
if (ix < 0x3fd00000) /* |x| <1/4 */

View File

@ -22,6 +22,7 @@
#include <math.h>
#include <math_private.h>
#include <math_ldbl_opt.h>
#include <fix-int-fp-convert-zero.h>
long double
__logbl (long double x)
@ -53,6 +54,8 @@ __logbl (long double x)
if ((hxs ^ lx) < 0 && (lx & 0x7fffffffffffffffLL) != 0)
rhx--;
}
if (FIX_INT_FP_CONVERT_ZERO && rhx == 1023)
return 0.0L;
return (long double) (rhx - 1023);
}
#ifndef __logbl

29
sysdeps/powerpc/powerpc32/fpu/configure vendored Normal file
View File

@ -0,0 +1,29 @@
# This file is generated from configure.ac by Autoconf. DO NOT EDIT!
# Local configure fragment for sysdeps/powerpc/powerpc32/fpu.
# Test whether integer to floating point conversions use fcfid.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fcfid use" >&5
$as_echo_n "checking for fcfid use... " >&6; }
if ${libc_cv_ppc_fcfid+:} false; then :
$as_echo_n "(cached) " >&6
else
echo 'double foo (int x) { return (double) x; }' > conftest.c
libc_cv_ppc_fcfid=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 '[ ]fcfid' conftest.s > /dev/null 2>&1; then
libc_cv_ppc_fcfid=yes
fi
fi
rm -rf conftest*
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libc_cv_ppc_fcfid" >&5
$as_echo "$libc_cv_ppc_fcfid" >&6; }
if test $libc_cv_ppc_fcfid = yes; then
$as_echo "#define HAVE_PPC_FCFID 1" >>confdefs.h
fi

View File

@ -0,0 +1,18 @@
GLIBC_PROVIDES dnl See aclocal.m4 in the top level source directory.
# Local configure fragment for sysdeps/powerpc/powerpc32/fpu.
# Test whether integer to floating point conversions use fcfid.
AC_CACHE_CHECK([for fcfid use], [libc_cv_ppc_fcfid], [dnl
echo 'double foo (int x) { return (double) x; }' > conftest.c
libc_cv_ppc_fcfid=no
if AC_TRY_COMMAND(${CC-cc} -S $CFLAGS conftest.c -o conftest.s 1>&AS_MESSAGE_LOG_FD); then
changequote(,)dnl
if grep '[ ]fcfid' conftest.s > /dev/null 2>&1; then
libc_cv_ppc_fcfid=yes
fi
changequote([,])dnl
fi
rm -rf conftest*])
if test $libc_cv_ppc_fcfid = yes; then
AC_DEFINE([HAVE_PPC_FCFID])
fi

View File

@ -0,0 +1,28 @@
/* Fix for conversion of integer 0 to floating point. PowerPC version.
Copyright (C) 2015 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#ifndef FIX_INT_FP_CONVERT_ZERO_H
#define FIX_INT_FP_CONVERT_ZERO_H 1
/* The code sequences GCC generates for conversion of integers to
floating point result in -0 instead of +0 in FE_DOWNWARD mode when
the fcfid instruction is not used, as of GCC 5. See
<https://gcc.gnu.org/bugzilla/show_bug.cgi?id=67771>. */
#define FIX_INT_FP_CONVERT_ZERO (!HAVE_PPC_FCFID)
#endif /* fix-int-fp-convert-zero.h */