mirror of
https://sourceware.org/git/glibc.git
synced 2025-01-11 11:50:06 +00:00
[powerpc] SET_RESTORE_ROUND optimizations and bug fix
SET_RESTORE_ROUND brackets a block of code, temporarily setting and restoring the rounding mode and letting everything else, including exceptions generated within the block, pass through. On powerpc, the current code clears the exception enables, which will hide exceptions generated within the block. This issue was introduced by me in commite905212627
. Fix this by not clearing exception enable bits in the prologue. Also, since we are no longer changing the enable bits in either the prologue or the epilogue, there is no need to test for entering/exiting non-stop mode. Also, optimize the prologue get/save/set rounding mode operations for POWER9 and later by using 'mffscrn' when possible. Suggested-by: Paul E. Murphy <murphyp@linux.ibm.com> Reviewed-by: Paul E. Murphy <murphyp@linux.ibm.com> Fixes:e905212627
2019-09-19 Paul A. Clarke <pc@us.ibm.com> * sysdeps/powerpc/fpu/fenv_libc.h (fegetenv_and_set_rn): New. (__fe_mffscrn): New. * sysdeps/powerpc/fpu/fenv_private.h (libc_feholdsetround_ppc_ctx): Do not clear enable bits, remove obsolete code, use fegetenv_and_set_rn. (libc_feresetround_ppc): Remove obsolete code, use fegetenv_and_set_rn.
This commit is contained in:
parent
64fab3633a
commit
f1c56cdff0
10
ChangeLog
10
ChangeLog
@ -1,3 +1,13 @@
|
||||
2019-09-19 Paul A. Clarke <pc@us.ibm.com>
|
||||
|
||||
* sysdeps/powerpc/fpu/fenv_libc.h (fegetenv_and_set_rn): New.
|
||||
(__fe_mffscrn): New.
|
||||
* sysdeps/powerpc/fpu/fenv_private.h (libc_feholdsetround_ppc_ctx):
|
||||
Do not clear enable bits, remove obsolete code, use
|
||||
fegetenv_and_set_rn.
|
||||
(libc_feresetround_ppc): Remove obsolete code, use
|
||||
fegetenv_and_set_rn.
|
||||
|
||||
2019-09-19 Stefan Liebler <stli@linux.ibm.com>
|
||||
|
||||
* support/support_ptrace.c: Remove inclusion of sys/prctl.h.
|
||||
|
@ -48,6 +48,38 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden;
|
||||
__fr; \
|
||||
})
|
||||
|
||||
#define __fe_mffscrn(rn) \
|
||||
({register fenv_union_t __fr; \
|
||||
if (__builtin_constant_p (rn)) \
|
||||
__asm__ __volatile__ ( \
|
||||
".machine push; .machine \"power9\"; mffscrni %0,%1; .machine pop" \
|
||||
: "=f" (__fr.fenv) : "i" (rn)); \
|
||||
else \
|
||||
{ \
|
||||
__fr.l = (rn); \
|
||||
__asm__ __volatile__ ( \
|
||||
".machine push; .machine \"power9\"; mffscrn %0,%1; .machine pop" \
|
||||
: "=f" (__fr.fenv) : "f" (__fr.fenv)); \
|
||||
} \
|
||||
__fr.fenv; \
|
||||
})
|
||||
|
||||
/* Like fegetenv_status, but also sets the rounding mode. */
|
||||
#ifdef _ARCH_PWR9
|
||||
#define fegetenv_and_set_rn(rn) __fe_mffscrn (rn)
|
||||
#else
|
||||
/* 'mffscrn' will decode to 'mffs' on ARCH < 3_00, which is still necessary
|
||||
but not sufficient, because it does not set the rounding mode.
|
||||
Explicitly set the rounding mode when 'mffscrn' actually doesn't. */
|
||||
#define fegetenv_and_set_rn(rn) \
|
||||
({register fenv_union_t __fr; \
|
||||
__fr.fenv = __fe_mffscrn (rn); \
|
||||
if (__glibc_unlikely (!(GLRO(dl_hwcap2) & PPC_FEATURE2_ARCH_3_00))) \
|
||||
__fesetround_inline (rn); \
|
||||
__fr.fenv; \
|
||||
})
|
||||
#endif
|
||||
|
||||
/* Equivalent to fesetenv, but takes a fenv_t instead of a pointer. */
|
||||
#define fesetenv_register(env) \
|
||||
do { \
|
||||
|
@ -133,16 +133,7 @@ static __always_inline void
|
||||
libc_feresetround_ppc (fenv_t *envp)
|
||||
{
|
||||
fenv_union_t new = { .fenv = *envp };
|
||||
|
||||
/* 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
|
||||
hardware into "precise mode" and may cause the FPU to run slower on some
|
||||
hardware. */
|
||||
if ((new.l & _FPU_ALL_TRAPS) != 0)
|
||||
(void) __fe_nomask_env_priv ();
|
||||
|
||||
/* Atomically enable and raise (if appropriate) exceptions set in `new'. */
|
||||
fesetenv_mode (new.fenv);
|
||||
fegetenv_and_set_rn (new.l & FPSCR_RN_MASK);
|
||||
}
|
||||
|
||||
static __always_inline int
|
||||
@ -184,22 +175,10 @@ libc_feupdateenv_ppc (fenv_t *e)
|
||||
static __always_inline void
|
||||
libc_feholdsetround_ppc_ctx (struct rm_ctx *ctx, int r)
|
||||
{
|
||||
fenv_union_t old, new;
|
||||
fenv_union_t old;
|
||||
|
||||
old.fenv = fegetenv_status ();
|
||||
|
||||
new.l = (old.l & ~(FPSCR_ENABLES_MASK|FPSCR_RN_MASK)) | r;
|
||||
|
||||
ctx->env = old.fenv;
|
||||
if (__glibc_unlikely (new.l != old.l))
|
||||
{
|
||||
if ((old.l & _FPU_ALL_TRAPS) != 0)
|
||||
(void) __fe_mask_env ();
|
||||
fesetenv_mode (new.fenv);
|
||||
ctx->updated_status = true;
|
||||
}
|
||||
else
|
||||
ctx->updated_status = false;
|
||||
ctx->env = old.fenv = fegetenv_and_set_rn (r);
|
||||
ctx->updated_status = (r != (old.l & FPSCR_RN_MASK));
|
||||
}
|
||||
|
||||
static __always_inline void
|
||||
|
Loading…
Reference in New Issue
Block a user