summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog14
-rw-r--r--sysdeps/ieee754/ldbl-128ibm/s_nearbyintl.c109
-rw-r--r--sysdeps/ieee754/ldbl-128ibm/s_rintl.c14
-rw-r--r--sysdeps/powerpc/fpu/fenv_private.h4
4 files changed, 32 insertions, 109 deletions
diff --git a/ChangeLog b/ChangeLog
index 73a49a06e0..a6be76213e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2016-03-09  Joseph Myers  <joseph@codesourcery.com>
+
+	[BZ #19790]
+	* sysdeps/ieee754/ldbl-128ibm/s_rintl.c [USE_AS_NEARBYINTL]
+	(rintl): Define as macro.
+	[USE_AS_NEARBYINTL] (__rintl): Likewise.
+	(__rintl) [USE_AS_NEARBYINTL]: Use SET_RESTORE_ROUND_NOEX instead
+	of fesetround.  Ensure results are evaluated before end of scope.
+	* sysdeps/ieee754/ldbl-128ibm/s_nearbyintl.c: Define
+	USE_AS_NEARBYINTL and include s_rintl.c.
+	* sysdeps/powerpc/fpu/fenv_private.h (libc_feholdsetround_ppc):
+	Disable exception traps in new environment.
+	(libc_feholdsetround_ppc_ctx): Likewise.
+
 2016-03-08  Roland McGrath  <roland@hack.frob.com>
 
 	* sysdeps/x86_64/tst-audit10.c: #include <cpu-features.h>.
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_nearbyintl.c b/sysdeps/ieee754/ldbl-128ibm/s_nearbyintl.c
index 08134edd10..dfdefe3f02 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_nearbyintl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_nearbyintl.c
@@ -17,110 +17,5 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-/* This has been coded in assembler because GCC makes such a mess of it
-   when it's coded in C.  */
-
-#include <math.h>
-#include <math_private.h>
-#include <fenv.h>
-#include <math_ldbl_opt.h>
-#include <float.h>
-#include <ieee754.h>
-
-
-long double
-__nearbyintl (long double x)
-{
-  fenv_t env;
-  static const long double TWO52 = 4503599627370496.0L;
-  union ibm_extended_long_double u;
-  u.ld = x;
-
-  if (!isfinite (u.d[0].d))
-    return x;
-  else if (fabs (u.d[0].d) < TWO52)
-    {
-      double xh = u.d[0].d;
-      double high = u.d[0].d;
-      feholdexcept (&env);
-      if (high > 0.0)
-	{
-	  high += TWO52;
-	  high -= TWO52;
-          if (high == -0.0) high = 0.0;
-	}
-      else if (high < 0.0)
-	{
-	  high -= TWO52;
-	  high += TWO52;
-          if (high == 0.0) high = -0.0;
-	}
-      if (u.d[1].d > 0.0 && (xh - high == 0.5))
-        high += 1.0;
-      else if (u.d[1].d < 0.0 && (-(xh - high) == 0.5))
-        high -= 1.0;
-      u.d[0].d = high;
-      u.d[1].d = 0.0;
-      math_force_eval (u.d[0]);
-      math_force_eval (u.d[1]);
-      fesetenv (&env);
-    }
-  else if (fabs (u.d[1].d) < TWO52 && u.d[1].d != 0.0)
-    {
-      double high = u.d[0].d, low = u.d[1].d, tau;
-      /* In this case we have to round the low double and handle any
-         adjustment to the high double that may be caused by rounding
-         (up).  This is complicated by the fact that the high double
-         may already be rounded and the low double may have the
-         opposite sign to compensate.  */
-      feholdexcept (&env);
-      if (u.d[0].d > 0.0)
-	{
-	  if (u.d[1].d > 0.0)
-	    {
-	      /* If the high/low doubles are the same sign then simply
-	         round the low double.  */
-	    }
-	  else if (u.d[1].d < 0.0)
-	    {
-	      /* Else the high double is pre rounded and we need to
-	         adjust for that.  */
-
-	      tau = __nextafter (u.d[0].d, 0.0);
-	      tau = (u.d[0].d - tau) * 2.0;
-	      high -= tau;
-	      low += tau;
-	    }
-	  low += TWO52;
-	  low -= TWO52;
-	}
-      else if (u.d[0].d < 0.0)
-	{
-	  if (u.d[1].d < 0.0)
-	    {
-	      /* If the high/low doubles are the same sign then simply
-	         round the low double.  */
-	    }
-	  else if (u.d[1].d > 0.0)
-	    {
-	      /* Else the high double is pre rounded and we need to
-	         adjust for that.  */
-	      tau = __nextafter (u.d[0].d, 0.0);
-	      tau = (u.d[0].d - tau) * 2.0;
-	      high -= tau;
-	      low += tau;
-	    }
-	  low = TWO52 - low;
-	  low = -(low - TWO52);
-	}
-      u.d[0].d = high + low;
-      u.d[1].d = high - u.d[0].d + low;
-      math_force_eval (u.d[0]);
-      math_force_eval (u.d[1]);
-      fesetenv (&env);
-    }
-
-  return u.ld;
-}
-
-long_double_symbol (libm, __nearbyintl, nearbyintl);
+#define USE_AS_NEARBYINTL
+#include "s_rintl.c"
diff --git a/sysdeps/ieee754/ldbl-128ibm/s_rintl.c b/sysdeps/ieee754/ldbl-128ibm/s_rintl.c
index 8c51ded1d6..e4af01c9a0 100644
--- a/sysdeps/ieee754/ldbl-128ibm/s_rintl.c
+++ b/sysdeps/ieee754/ldbl-128ibm/s_rintl.c
@@ -26,6 +26,11 @@
 #include <float.h>
 #include <ieee754.h>
 
+#ifdef USE_AS_NEARBYINTL
+# define rintl nearbyintl
+# define __rintl __nearbyintl
+#endif
+
 
 long double
 __rintl (long double x)
@@ -44,7 +49,11 @@ __rintl (long double x)
 
       /* Long double arithmetic, including the canonicalisation below,
 	 only works in round-to-nearest mode.  */
+#ifdef USE_AS_NEARBYINTL
+      SET_RESTORE_ROUND_NOEX (FE_TONEAREST);
+#else
       fesetround (FE_TONEAREST);
+#endif
 
       /* Convert the high double to integer.  */
       orig_xh = xh;
@@ -103,7 +112,12 @@ __rintl (long double x)
       if (orig_xh < 0.0)
 	xh = -__builtin_fabs (xh);
 
+#ifdef USE_AS_NEARBYINTL
+      math_force_eval (xh);
+      math_force_eval (xl);
+#else
       fesetround (save_round);
+#endif
     }
 
   return ldbl_pack (xh, xl);
diff --git a/sysdeps/powerpc/fpu/fenv_private.h b/sysdeps/powerpc/fpu/fenv_private.h
index e1b02a3f80..02ac980909 100644
--- a/sysdeps/powerpc/fpu/fenv_private.h
+++ b/sysdeps/powerpc/fpu/fenv_private.h
@@ -146,7 +146,7 @@ libc_feholdsetround_ppc (fenv_t *e, int r)
 
   old.fenv = fegetenv_register ();
   /* Clear current precision and set newer one.  */
-  new.l = (old.l & ~0x3) | r;
+  new.l = (old.l & ~0x3 & ~_FPU_MASK_ALL) | r;
   *e = old.fenv;
 
   if ((old.l & _FPU_MASK_ALL) != 0)
@@ -240,7 +240,7 @@ libc_feholdsetround_ppc_ctx (struct rm_ctx *ctx, int r)
   fenv_union_t old, new;
 
   old.fenv = fegetenv_register ();
-  new.l = (old.l & ~0x3) | r;
+  new.l = (old.l & ~0x3 & ~_FPU_MASK_ALL) | r;
   ctx->env = old.fenv;
   if (__glibc_unlikely (new.l != old.l))
     {