about summary refs log tree commit diff
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2017-09-28 01:59:02 +0000
committerJoseph Myers <joseph@codesourcery.com>2017-09-28 01:59:02 +0000
commitf124cb381116b5809de198327690ad0bd8d1478e (patch)
tree9366d5952d3f1730b45bf757b257bff5ad260837
parent7edd06916d0f18714f323b180b890f1fea39e1ff (diff)
downloadglibc-f124cb381116b5809de198327690ad0bd8d1478e.tar.gz
glibc-f124cb381116b5809de198327690ad0bd8d1478e.tar.xz
glibc-f124cb381116b5809de198327690ad0bd8d1478e.zip
Fix nearbyint arithmetic moved before feholdexcept (bug 22225).
In <https://sourceware.org/ml/libc-alpha/2013-05/msg00722.html> I
remarked on the possibility of arithmetic in various nearbyint
implementations being scheduled before feholdexcept calls, resulting
in spurious "inexact" exceptions.

I'm now actually observing this occurring in glibc built for ARM with
GCC 7 (in fact, both copies of the same addition/subtraction sequence
being combined and moved out before the conditionals and
feholdexcept/fesetenv pairs), resulting in test failures.

This patch makes the nearbyint implementations with this particular
feholdexcept / arithmetic / fesetenv pattern consistently use
math_opt_barrier on the function argument when first used in
arithmetic, and also consistently use math_force_eval before fesetenv
(the latter was generally already done, but the dbl-64/wordsize-64
implementation used math_opt_barrier instead, and as
math_opt_barrier's intended effect is through its output value being
used, such a use that doesn't use the return value is suspect).

Tested for x86_64 (--disable-multi-arch so more of these
implementations get used), and for ARM in a configuration where I saw
the problem scheduling.

	[BZ #22225]
	* sysdeps/ieee754/dbl-64/s_nearbyint.c (__nearbyint): Use
	math_opt_barrier on argument when doing arithmetic on it.
	* sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c (__nearbyint):
	Likewise.  Use math_force_eval not math_opt_barrier after
	arithmetic.
	* sysdeps/ieee754/flt-32/s_nearbyintf.c (__nearbyintf): Use
	math_opt_barrier on argument when doing arithmetic on it.
	* sysdeps/ieee754/ldbl-128/s_nearbyintl.c (__nearbyintl):
	Likewise.
-rw-r--r--ChangeLog13
-rw-r--r--sysdeps/ieee754/dbl-64/s_nearbyint.c4
-rw-r--r--sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c8
-rw-r--r--sysdeps/ieee754/flt-32/s_nearbyintf.c4
-rw-r--r--sysdeps/ieee754/ldbl-128/s_nearbyintl.c4
5 files changed, 23 insertions, 10 deletions
diff --git a/ChangeLog b/ChangeLog
index 2e29752af7..60c9521e6b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2017-09-28  Joseph Myers  <joseph@codesourcery.com>
+
+	[BZ #22225]
+	* sysdeps/ieee754/dbl-64/s_nearbyint.c (__nearbyint): Use
+	math_opt_barrier on argument when doing arithmetic on it.
+	* sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c (__nearbyint):
+	Likewise.  Use math_force_eval not math_opt_barrier after
+	arithmetic.
+	* sysdeps/ieee754/flt-32/s_nearbyintf.c (__nearbyintf): Use
+	math_opt_barrier on argument when doing arithmetic on it.
+	* sysdeps/ieee754/ldbl-128/s_nearbyintl.c (__nearbyintl):
+	Likewise.
+
 2017-09-27  H.J. Lu  <hongjiu.lu@intel.com>
 
 	* sysdeps/unix/sysv/linux/ifaddrs.c (__getifaddrs): Add
diff --git a/sysdeps/ieee754/dbl-64/s_nearbyint.c b/sysdeps/ieee754/dbl-64/s_nearbyint.c
index dec0c5d6ee..6e3f8316b1 100644
--- a/sysdeps/ieee754/dbl-64/s_nearbyint.c
+++ b/sysdeps/ieee754/dbl-64/s_nearbyint.c
@@ -48,7 +48,7 @@ __nearbyint (double x)
       if (j0 < 0)
 	{
 	  libc_feholdexcept (&env);
-	  w = TWO52[sx] + x;
+	  w = TWO52[sx] + math_opt_barrier (x);
 	  t = w - TWO52[sx];
 	  math_force_eval (t);
 	  libc_fesetenv (&env);
@@ -65,7 +65,7 @@ __nearbyint (double x)
 	return x;                       /* x is integral */
     }
   libc_feholdexcept (&env);
-  w = TWO52[sx] + x;
+  w = TWO52[sx] + math_opt_barrier (x);
   t = w - TWO52[sx];
   math_force_eval (t);
   libc_fesetenv (&env);
diff --git a/sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c b/sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c
index 8293819981..7d135b54e4 100644
--- a/sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c
+++ b/sysdeps/ieee754/dbl-64/wordsize-64/s_nearbyint.c
@@ -42,9 +42,9 @@ __nearbyint(double x)
 	if(__builtin_expect(j0<52, 1)) {
 	    if(j0<0) {
 		libc_feholdexcept (&env);
-		double w = TWO52[sx]+x;
+		double w = TWO52[sx] + math_opt_barrier (x);
 		double t =  w-TWO52[sx];
-		math_opt_barrier(t);
+		math_force_eval (t);
 		libc_fesetenv (&env);
 		return __copysign (t, x);
 	    }
@@ -53,9 +53,9 @@ __nearbyint(double x)
 	    else return x;		/* x is integral */
 	}
 	libc_feholdexcept (&env);
-	double w = TWO52[sx]+x;
+	double w = TWO52[sx] + math_opt_barrier (x);
 	double t = w-TWO52[sx];
-	math_opt_barrier (t);
+	math_force_eval (t);
 	libc_fesetenv (&env);
 	return t;
 }
diff --git a/sysdeps/ieee754/flt-32/s_nearbyintf.c b/sysdeps/ieee754/flt-32/s_nearbyintf.c
index afacdef67c..a8af8948ec 100644
--- a/sysdeps/ieee754/flt-32/s_nearbyintf.c
+++ b/sysdeps/ieee754/flt-32/s_nearbyintf.c
@@ -38,7 +38,7 @@ __nearbyintf(float x)
 	if(j0<23) {
 	    if(j0<0) {
 		libc_feholdexceptf (&env);
-		w = TWO23[sx]+x;
+		w = TWO23[sx] + math_opt_barrier (x);
 		t =  w-TWO23[sx];
 		math_force_eval (t);
 		libc_fesetenvf (&env);
@@ -51,7 +51,7 @@ __nearbyintf(float x)
 	    else return x;		/* x is integral */
 	}
 	libc_feholdexceptf (&env);
-	w = TWO23[sx]+x;
+	w = TWO23[sx] + math_opt_barrier (x);
 	t = w-TWO23[sx];
 	math_force_eval (t);
 	libc_fesetenvf (&env);
diff --git a/sysdeps/ieee754/ldbl-128/s_nearbyintl.c b/sysdeps/ieee754/ldbl-128/s_nearbyintl.c
index 631b0e0c71..c1ee68be63 100644
--- a/sysdeps/ieee754/ldbl-128/s_nearbyintl.c
+++ b/sysdeps/ieee754/ldbl-128/s_nearbyintl.c
@@ -45,7 +45,7 @@ _Float128 __nearbyintl(_Float128 x)
 	if(j0<112) {
 	    if(j0<0) {
 		feholdexcept (&env);
-	        w = TWO112[sx]+x;
+	        w = TWO112[sx] + math_opt_barrier (x);
 	        t = w-TWO112[sx];
 		math_force_eval (t);
 	        fesetenv (&env);
@@ -58,7 +58,7 @@ _Float128 __nearbyintl(_Float128 x)
 	    else return x;		/* x is integral */
 	}
 	feholdexcept (&env);
-	w = TWO112[sx]+x;
+	w = TWO112[sx] + math_opt_barrier (x);
 	t = w-TWO112[sx];
 	math_force_eval (t);
 	fesetenv (&env);