aboutsummaryrefslogtreecommitdiff
path: root/sysdeps
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/powerpc/fpu/fenv_libc.h32
-rw-r--r--sysdeps/powerpc/fpu/fenv_private.h29
2 files changed, 36 insertions, 25 deletions
diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h
index b030e6e..59c3d57 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; \
+ })
+
+/* 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 { \
diff --git a/sysdeps/powerpc/fpu/fenv_private.h b/sysdeps/powerpc/fpu/fenv_private.h
index 5f1bcab..92a3e92 100644
--- a/sysdeps/powerpc/fpu/fenv_private.h
+++ b/sysdeps/powerpc/fpu/fenv_private.h
@@ -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