aboutsummaryrefslogtreecommitdiff
path: root/sysdeps
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2015-10-05 17:46:50 +0000
committerJoseph Myers <joseph@codesourcery.com>2015-10-05 17:46:50 +0000
commitbc3753638a1c3c93dea071414909ce2729e3ca50 (patch)
tree220d602aa00397fc2b472dc4b38f168865ff5ef7 /sysdeps
parent57352c2201678ee52e7e8ea6fb6e115a9ec4e711 (diff)
downloadglibc-bc3753638a1c3c93dea071414909ce2729e3ca50.zip
glibc-bc3753638a1c3c93dea071414909ce2729e3ca50.tar.gz
glibc-bc3753638a1c3c93dea071414909ce2729e3ca50.tar.bz2
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.
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/generic/fix-int-fp-convert-zero.h27
-rw-r--r--sysdeps/ieee754/dbl-64/e_log10.c3
-rw-r--r--sysdeps/ieee754/dbl-64/e_log2.c7
-rw-r--r--sysdeps/ieee754/dbl-64/s_erf.c6
-rw-r--r--sysdeps/ieee754/dbl-64/s_logb.c3
-rw-r--r--sysdeps/ieee754/flt-32/e_log10f.c3
-rw-r--r--sysdeps/ieee754/flt-32/e_log2f.c8
-rw-r--r--sysdeps/ieee754/flt-32/s_erff.c6
-rw-r--r--sysdeps/ieee754/flt-32/s_logbf.c3
-rw-r--r--sysdeps/ieee754/ldbl-128ibm/s_erfl.c6
-rw-r--r--sysdeps/ieee754/ldbl-128ibm/s_logbl.c3
-rw-r--r--sysdeps/powerpc/powerpc32/fpu/configure29
-rw-r--r--sysdeps/powerpc/powerpc32/fpu/configure.ac18
-rw-r--r--sysdeps/powerpc/powerpc32/fpu/fix-int-fp-convert-zero.h28
14 files changed, 145 insertions, 5 deletions
diff --git a/sysdeps/generic/fix-int-fp-convert-zero.h b/sysdeps/generic/fix-int-fp-convert-zero.h
new file mode 100644
index 0000000..b7fd38e
--- /dev/null
+++ b/sysdeps/generic/fix-int-fp-convert-zero.h
@@ -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 */
diff --git a/sysdeps/ieee754/dbl-64/e_log10.c b/sysdeps/ieee754/dbl-64/e_log10.c
index 8548ee3..df59d9d 100644
--- a/sysdeps/ieee754/dbl-64/e_log10.c
+++ b/sysdeps/ieee754/dbl-64/e_log10.c
@@ -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;
diff --git a/sysdeps/ieee754/dbl-64/e_log2.c b/sysdeps/ieee754/dbl-64/e_log2.c
index 997d7ce..bc6a341 100644
--- a/sysdeps/ieee754/dbl-64/e_log2.c
+++ b/sysdeps/ieee754/dbl-64/e_log2.c
@@ -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;
}
diff --git a/sysdeps/ieee754/dbl-64/s_erf.c b/sysdeps/ieee754/dbl-64/s_erf.c
index e59f5f3..b4975a8 100644
--- a/sysdeps/ieee754/dbl-64/s_erf.c
+++ b/sysdeps/ieee754/dbl-64/s_erf.c
@@ -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 */
diff --git a/sysdeps/ieee754/dbl-64/s_logb.c b/sysdeps/ieee754/dbl-64/s_logb.c
index 7a6c49a..3a26b18 100644
--- a/sysdeps/ieee754/dbl-64/s_logb.c
+++ b/sysdeps/ieee754/dbl-64/s_logb.c
@@ -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)
diff --git a/sysdeps/ieee754/flt-32/e_log10f.c b/sysdeps/ieee754/flt-32/e_log10f.c
index 1daeef7..2cd01b4 100644
--- a/sysdeps/ieee754/flt-32/e_log10f.c
+++ b/sysdeps/ieee754/flt-32/e_log10f.c
@@ -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;
diff --git a/sysdeps/ieee754/flt-32/e_log2f.c b/sysdeps/ieee754/flt-32/e_log2f.c
index 245be4e..857d13f 100644
--- a/sysdeps/ieee754/flt-32/e_log2f.c
+++ b/sysdeps/ieee754/flt-32/e_log2f.c
@@ -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;
}
diff --git a/sysdeps/ieee754/flt-32/s_erff.c b/sysdeps/ieee754/flt-32/s_erff.c
index 3162d81..c8b6287 100644
--- a/sysdeps/ieee754/flt-32/s_erff.c
+++ b/sysdeps/ieee754/flt-32/s_erff.c
@@ -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 */
diff --git a/sysdeps/ieee754/flt-32/s_logbf.c b/sysdeps/ieee754/flt-32/s_logbf.c
index ba0267e..9ae20e3 100644
--- a/sysdeps/ieee754/flt-32/s_logbf.c
+++ b/sysdeps/ieee754/flt-32/s_logbf.c
@@ -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)
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_erfl.c b/sysdeps/ieee754/ldbl-128ibm/s_erfl.c
index 455c645..82d889d 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_erfl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_erfl.c
@@ -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 */
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_logbl.c b/sysdeps/ieee754/ldbl-128ibm/s_logbl.c
index 22e5fc2..3c07c5e 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_logbl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_logbl.c
@@ -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
diff --git a/sysdeps/powerpc/powerpc32/fpu/configure b/sysdeps/powerpc/powerpc32/fpu/configure
new file mode 100644
index 0000000..69a151b
--- /dev/null
+++ b/sysdeps/powerpc/powerpc32/fpu/configure
@@ -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
diff --git a/sysdeps/powerpc/powerpc32/fpu/configure.ac b/sysdeps/powerpc/powerpc32/fpu/configure.ac
new file mode 100644
index 0000000..e596e79
--- /dev/null
+++ b/sysdeps/powerpc/powerpc32/fpu/configure.ac
@@ -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
diff --git a/sysdeps/powerpc/powerpc32/fpu/fix-int-fp-convert-zero.h b/sysdeps/powerpc/powerpc32/fpu/fix-int-fp-convert-zero.h
new file mode 100644
index 0000000..9ab8fad
--- /dev/null
+++ b/sysdeps/powerpc/powerpc32/fpu/fix-int-fp-convert-zero.h
@@ -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 */