diff --git a/ChangeLog b/ChangeLog index 73a49a06e0..a6be76213e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2016-03-09 Joseph Myers + + [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 * sysdeps/x86_64/tst-audit10.c: #include . 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 . */ -/* This has been coded in assembler because GCC makes such a mess of it - when it's coded in C. */ - -#include -#include -#include -#include -#include -#include - - -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 #include +#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)) {