[PATCH] [powerpc] SET_RESTORE_ROUND optimizations and bug fix
Paul E Murphy
murphyp@linux.ibm.com
Tue Sep 10 22:06:00 GMT 2019
On 9/10/19 1:15 PM, Paul A. Clarke wrote:
> From: "Paul A. Clarke" <pc@us.ibm.com>
>
> 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 commit e905212627350d54b58426214b5a54ddc852b0c9.
>
> 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.
>
> Fixes: e905212627350d54b58426214b5a54ddc852b0c9
>
> 2019-09-10 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.
> ---
> sysdeps/powerpc/fpu/fenv_libc.h | 32 ++++++++++++++++++++++++++++++++
> sysdeps/powerpc/fpu/fenv_private.h | 23 ++++-------------------
> 2 files changed, 36 insertions(+), 19 deletions(-)
>
> diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h
> index 0aad897..3173bc2 100644
> --- a/sysdeps/powerpc/fpu/fenv_libc.h
> +++ b/sysdeps/powerpc/fpu/fenv_libc.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; \
> + })
OK
> +
> +/* 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
Is the conditional code faster than unconditionally calling
__fesetround_inline?
> +
> /* Equivalent to fesetenv, but takes a fenv_t instead of a pointer. */
> #define fesetenv_register(env) \
> do { \
> diff --git a/sysdeps/powerpc/fpu/fenv_private.h b/sysdeps/powerpc/fpu/fenv_private.h
> index 3286b4e..504f7b8 100644
> --- a/sysdeps/powerpc/fpu/fenv_private.h
> +++ b/sysdeps/powerpc/fpu/fenv_private.h
> @@ -101,11 +101,7 @@ static __always_inline void
> libc_feresetround_ppc (fenv_t *envp)
> {
> fenv_union_t new = { .fenv = *envp };
> -
> - __TEST_AND_EXIT_NON_STOP (-1ULL, new.l);
> -
> - /* Atomically enable and raise (if appropriate) exceptions set in `new'. */
> - fesetenv_mode (new.fenv);
> + fegetenv_and_set_rn (new.l & FPSCR_RN_MASK);
> }
OK
>
> static __always_inline int
> @@ -147,21 +143,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;
> -
> - old.fenv = fegetenv_status ();
> + fenv_union_t old;
>
> - new.l = (old.l & ~(FPSCR_ENABLES_MASK|FPSCR_RN_MASK)) | r;
> -
> - ctx->env = old.fenv;
> - if (__glibc_unlikely (new.l != old.l))
> - {
> - __TEST_AND_ENTER_NON_STOP (old.l, 0ULL);
> - 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))OK
More information about the Libc-alpha
mailing list