diff --git a/ChangeLog b/ChangeLog index 8b9cfb5bdb..4007295165 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2014-04-28 Adhemerval Zanella + + * sysdeps/powerpc/fpu/fclrexcpt.c (__feclearexcept): Do not update + FPSCR if value do not change. + * sysdeps/powerpc/fpu/fedisblxcpt.c (fedisableexcept): Likewise. + * sysdeps/powerpc/fpu/feenablxcpt.c (feenableexcept): Likewise. + * sysdeps/powerpc/fpu/feholdexcpt.c (feholdexcept): Likewise. + * sysdeps/powerpc/fpu/fesetenv.c (__fesetenv): Likewise. + * sysdeps/powerpc/fpu/fsetexcptflg.c (__fesetexceptflag): Likewise. + * sysdeps/powerpc/fpu/fenv_libc.h (fenv_reg_to_exceptions): New helper + function. + 2014-05-29 Carlos O'Donell * sysdeps/hppa: Move directory from ports/sysdeps/hppa. diff --git a/sysdeps/powerpc/fpu/fclrexcpt.c b/sysdeps/powerpc/fpu/fclrexcpt.c index cda2810120..4607f62bb1 100644 --- a/sysdeps/powerpc/fpu/fclrexcpt.c +++ b/sysdeps/powerpc/fpu/fclrexcpt.c @@ -22,17 +22,18 @@ int __feclearexcept (int excepts) { - fenv_union_t u; + fenv_union_t u, n; /* Get the current state. */ u.fenv = fegetenv_register (); /* Clear the relevant bits. */ - u.l = u.l & ~((-(excepts >> (31 - FPSCR_VX) & 1) & FE_ALL_INVALID) + n.l = u.l & ~((-(excepts >> (31 - FPSCR_VX) & 1) & FE_ALL_INVALID) | (excepts & FPSCR_STICKY_BITS)); /* Put the new state in effect. */ - fesetenv_register (u.fenv); + if (u.l != n.l) + fesetenv_register (n.fenv); /* Success. */ return 0; diff --git a/sysdeps/powerpc/fpu/fedisblxcpt.c b/sysdeps/powerpc/fpu/fedisblxcpt.c index 5883e09263..94c01abb86 100644 --- a/sysdeps/powerpc/fpu/fedisblxcpt.c +++ b/sysdeps/powerpc/fpu/fedisblxcpt.c @@ -22,15 +22,17 @@ int fedisableexcept (int excepts) { - fenv_union_t fe; - int result, new; + fenv_union_t fe, curr; + int result = 0, new; - result = __fegetexcept (); + /* Get current exception mask to return. */ + fe.fenv = curr.fenv = fegetenv_register (); + result = fenv_reg_to_exceptions (fe.l); if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID) excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID; - fe.fenv = fegetenv_register (); + /* Sets the new exception mask. */ if (excepts & FE_INEXACT) fe.l &= ~(1 << (31 - FPSCR_XE)); if (excepts & FE_DIVBYZERO) @@ -41,7 +43,9 @@ fedisableexcept (int excepts) fe.l &= ~(1 << (31 - FPSCR_OE)); if (excepts & FE_INVALID) fe.l &= ~(1 << (31 - FPSCR_VE)); - fesetenv_register (fe.fenv); + + if (fe.l != curr.l) + fesetenv_register (fe.fenv); new = __fegetexcept (); if (new == 0 && result != 0) diff --git a/sysdeps/powerpc/fpu/feenablxcpt.c b/sysdeps/powerpc/fpu/feenablxcpt.c index 8ad0f97ac7..01a68cf086 100644 --- a/sysdeps/powerpc/fpu/feenablxcpt.c +++ b/sysdeps/powerpc/fpu/feenablxcpt.c @@ -22,15 +22,17 @@ int feenableexcept (int excepts) { - fenv_union_t fe; - int result, new; + fenv_union_t fe, curr; + int result = 0, new; - result = __fegetexcept (); + /* Get current exception mask to return. */ + fe.fenv = curr.fenv = fegetenv_register (); + result = fenv_reg_to_exceptions (fe.l); if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID) excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID; - fe.fenv = fegetenv_register (); + /* Sets the new exception mask. */ if (excepts & FE_INEXACT) fe.l |= (1 << (31 - FPSCR_XE)); if (excepts & FE_DIVBYZERO) @@ -41,7 +43,9 @@ feenableexcept (int excepts) fe.l |= (1 << (31 - FPSCR_OE)); if (excepts & FE_INVALID) fe.l |= (1 << (31 - FPSCR_VE)); - fesetenv_register (fe.fenv); + + if (fe.l != curr.l) + fesetenv_register (fe.fenv); new = __fegetexcept (); if (new != 0 && result == 0) diff --git a/sysdeps/powerpc/fpu/feholdexcpt.c b/sysdeps/powerpc/fpu/feholdexcpt.c index 1375a2f5ad..764dd38f3d 100644 --- a/sysdeps/powerpc/fpu/feholdexcpt.c +++ b/sysdeps/powerpc/fpu/feholdexcpt.c @@ -32,6 +32,9 @@ feholdexcept (fenv_t *envp) flag. */ new.l = old.l & 0xffffffff00000007LL; + if (new.l == old.l) + return 0; + /* If the old env had any enabled exceptions, then mask SIGFPE in the MSR FE0/FE1 bits. This may allow the FPU to run faster because it always takes the default action and can not generate SIGFPE. */ diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h index 28e4d1f7c9..c1df5ce091 100644 --- a/sysdeps/powerpc/fpu/fenv_libc.h +++ b/sysdeps/powerpc/fpu/fenv_libc.h @@ -146,6 +146,23 @@ enum { /* the remaining two least-significant bits keep the rounding mode */ }; +static inline int +fenv_reg_to_exceptions (unsigned long long l) +{ + int result = 0; + if (l & (1 << (31 - FPSCR_XE))) + result |= FE_INEXACT; + if (l & (1 << (31 - FPSCR_ZE))) + result |= FE_DIVBYZERO; + if (l & (1 << (31 - FPSCR_UE))) + result |= FE_UNDERFLOW; + if (l & (1 << (31 - FPSCR_OE))) + result |= FE_OVERFLOW; + if (l & (1 << (31 - FPSCR_VE))) + result |= FE_INVALID; + return result; +} + #ifdef _ARCH_PWR6 /* Not supported in ISA 2.05. Provided for source compat only. */ # define FPSCR_NI 29 diff --git a/sysdeps/powerpc/fpu/fesetenv.c b/sysdeps/powerpc/fpu/fesetenv.c index fa99ddbd40..138bde0685 100644 --- a/sysdeps/powerpc/fpu/fesetenv.c +++ b/sysdeps/powerpc/fpu/fesetenv.c @@ -29,6 +29,8 @@ __fesetenv (const fenv_t *envp) /* get the currently set exceptions. */ new.fenv = *envp; old.fenv = fegetenv_register (); + if (old.l == new.l) + return 0; /* If the old env has no enabled exceptions and the new env has any enabled exceptions, then unmask SIGFPE in the MSR FE0/FE1 bits. This will put the diff --git a/sysdeps/powerpc/fpu/fsetexcptflg.c b/sysdeps/powerpc/fpu/fsetexcptflg.c index 95193c1010..cee6682b64 100644 --- a/sysdeps/powerpc/fpu/fsetexcptflg.c +++ b/sysdeps/powerpc/fpu/fsetexcptflg.c @@ -21,7 +21,7 @@ int __fesetexceptflag (const fexcept_t *flagp, int excepts) { - fenv_union_t u; + fenv_union_t u, n; fexcept_t flag; /* Get the current state. */ @@ -31,7 +31,7 @@ __fesetexceptflag (const fexcept_t *flagp, int excepts) flag = *flagp & excepts; /* Replace the exception status */ - u.l = ((u.l & ~(FPSCR_STICKY_BITS & excepts)) + n.l = ((u.l & ~(FPSCR_STICKY_BITS & excepts)) | (flag & FPSCR_STICKY_BITS) | (flag >> ((31 - FPSCR_VX) - (31 - FPSCR_VXSOFT)) & FE_INVALID_SOFTWARE)); @@ -39,7 +39,8 @@ __fesetexceptflag (const fexcept_t *flagp, int excepts) /* Store the new status word (along with the rest of the environment). This may cause floating-point exceptions if the restored state requests it. */ - fesetenv_register (u.fenv); + if (n.l != u.l) + fesetenv_register (u.fenv); /* Deal with FE_INVALID_SOFTWARE not being implemented on some chips. */ if (flag & FE_INVALID)