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