dfa500
commit 7413c188c77adb26a15cf0e98e0a991d09d73c65
dfa500
Author: Paul A. Clarke <pc@us.ibm.com>
dfa500
Date:   Thu Sep 19 11:18:33 2019 -0500
dfa500
dfa500
    [powerpc] libc_feupdateenv_test: optimize FPSCR access
dfa500
    
dfa500
    ROUND_TO_ODD and a couple of other places use libc_feupdateenv_test to
dfa500
    restore the rounding mode and exception enables, preserve exception flags,
dfa500
    and test whether given exception(s) were generated.
dfa500
    
dfa500
    If the exception flags haven't changed, then it is sufficient and a bit
dfa500
    more efficient to just restore the rounding mode and enables, rather than
dfa500
    writing the full Floating-Point Status and Control Register (FPSCR).
dfa500
    
dfa500
    Reviewed-by: Paul E. Murphy <murphyp@linux.ibm.com>
dfa500
dfa500
diff --git a/sysdeps/powerpc/fpu/fenv_libc.h b/sysdeps/powerpc/fpu/fenv_libc.h
dfa500
index 36b639c3939586f6..86ae7fda016abd8b 100644
dfa500
--- a/sysdeps/powerpc/fpu/fenv_libc.h
dfa500
+++ b/sysdeps/powerpc/fpu/fenv_libc.h
dfa500
@@ -257,6 +257,10 @@ enum {
dfa500
   (FPSCR_VE_MASK|FPSCR_OE_MASK|FPSCR_UE_MASK|FPSCR_ZE_MASK|FPSCR_XE_MASK)
dfa500
 #define FPSCR_BASIC_EXCEPTIONS_MASK \
dfa500
   (FPSCR_VX_MASK|FPSCR_OX_MASK|FPSCR_UX_MASK|FPSCR_ZX_MASK|FPSCR_XX_MASK)
dfa500
+#define FPSCR_EXCEPTIONS_MASK (FPSCR_BASIC_EXCEPTIONS_MASK| \
dfa500
+  FPSCR_VXSNAN_MASK|FPSCR_VXISI_MASK|FPSCR_VXIDI_MASK|FPSCR_VXZDZ_MASK| \
dfa500
+  FPSCR_VXIMZ_MASK|FPSCR_VXVC_MASK|FPSCR_VXSOFT_MASK|FPSCR_VXSQRT_MASK| \
dfa500
+  FPSCR_VXCVI_MASK)
dfa500
 #define FPSCR_FPRF_MASK \
dfa500
   (FPSCR_FPRF_C_MASK|FPSCR_FPRF_FL_MASK|FPSCR_FPRF_FG_MASK| \
dfa500
    FPSCR_FPRF_FE_MASK|FPSCR_FPRF_FU_MASK)
dfa500
diff --git a/sysdeps/powerpc/fpu/fenv_private.h b/sysdeps/powerpc/fpu/fenv_private.h
dfa500
index c236d45db2f399a4..86a3611b3ef41759 100644
dfa500
--- a/sysdeps/powerpc/fpu/fenv_private.h
dfa500
+++ b/sysdeps/powerpc/fpu/fenv_private.h
dfa500
@@ -52,8 +52,20 @@ __libc_femergeenv_ppc (const fenv_t *envp, unsigned long long old_mask,
dfa500
   __TEST_AND_EXIT_NON_STOP (old.l, new.l);
dfa500
   __TEST_AND_ENTER_NON_STOP (old.l, new.l);
dfa500
 
dfa500
-  /* Atomically enable and raise (if appropriate) exceptions set in `new'.  */
dfa500
-  fesetenv_register (new.fenv);
dfa500
+  /* If requesting to keep status, replace control, and merge exceptions,
dfa500
+     and exceptions haven't changed, we can just set new control instead
dfa500
+     of the whole FPSCR.  */
dfa500
+  if ((old_mask & (FPSCR_CONTROL_MASK|FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK))
dfa500
+      == (FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK) &&
dfa500
+      (new_mask & (FPSCR_CONTROL_MASK|FPSCR_STATUS_MASK|FPSCR_EXCEPTIONS_MASK))
dfa500
+      == (FPSCR_CONTROL_MASK|FPSCR_EXCEPTIONS_MASK) &&
dfa500
+      (old.l & FPSCR_EXCEPTIONS_MASK) == (new.l & FPSCR_EXCEPTIONS_MASK))
dfa500
+  {
dfa500
+    fesetenv_mode (new.fenv);
dfa500
+  }
dfa500
+  else
dfa500
+    /* Atomically enable and raise (if appropriate) exceptions set in `new'.  */
dfa500
+    fesetenv_register (new.fenv);
dfa500
 
dfa500
   return old.l;
dfa500
 }