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