]> sourceware.org Git - glibc.git/commitdiff
[powerpc] fe{en,dis}ableexcept, fesetmode: optimize FPSCR accesses
authorPaul A. Clarke <pc@us.ibm.com>
Fri, 19 Jul 2019 00:37:13 +0000 (19:37 -0500)
committerPaul A. Clarke <pc@us.ibm.com>
Wed, 28 Aug 2019 18:50:06 +0000 (13:50 -0500)
Since fe{en,dis}ableexcept() and fesetmode() read-modify-write just the
"mode" (exception enable and rounding mode) bits of the Floating Point Status
Control Register (FPSCR), the lighter weight 'mffsl' instruction can be used
to read the FPSCR (enables and rounding mode), and 'mtfsf 0b00000011' can be
used to write just those bits back to the FPSCR.  The net is better performance.

In addition, fe{en,dis}ableexcept() read the FPSCR again after writing it, or
they determine that it doesn't need to be written because it is not changing.
In either case, the local variable holds the current values of the enable
bits in the FPSCR.  This local variable can be used instead of again reading
the FPSCR.

Also, that value of the FPSCR which is read the second time is validated
against the requested enables.  Since the write can't fail, this validation
step is unnecessary, and can be removed.  Instead, the exceptions to be
enabled (or disabled) are transformed into available bits in the FPSCR,
then validated after being transformed back, to ensure that all requested
bits are actually being set.  For example, FE_INVALID_SQRT can be
requested, but cannot actually be set.  This bit is not mapped during the
transformations, so a test for that bit being set before and after
transformations will show the bit would not be set, and the function will
return -1 for failure.

Finally, convert the local macros in fesetmode.c to more generally useful
macros in fenv_libc.h.

ChangeLog
sysdeps/powerpc/fpu/fedisblxcpt.c
sysdeps/powerpc/fpu/feenablxcpt.c
sysdeps/powerpc/fpu/fenv_libc.h
sysdeps/powerpc/fpu/fesetmode.c

index c2d70717ecc165a82e8c40b6838885f79205b9ff..1609d16e00f697847d3933f374936e1b8d68c507 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2019-08-28  Paul A. Clarke  <pc@us.ibm.com>
+    
+       * sysdeps/powerpc/fpu/fenv_libc.h (fesetenv_mode): New.
+       (FPSCR_FPRF_MASK): New. (FPSCR_STATUS_MASK): New.
+       * sysdeps/powerpc/fpu/feenablxcpt.c (feenableexcept): Use lighter-
+       weight access to FPSCR; remove unnecessary second FPSCR read and
+       validate.
+       * sysdeps/powerpc/fpu/fedisblxcpt.c (fedisableexcept): Likewise.
+       * sysdeps/powerpc/fpu/fesetmode.c (fesetmode): Use lighter-weight
+       access to FPSCR; Use macros in fenv_libc.h in favor of local.
+
 2019-08-28  Paul A. Clarke  <pc@us.ibm.com>
     
        * sysdeps/powerpc/fpu/fenv_libc.h: Define FPSCR bitmasks.
index 5cc87992f044c1980b6e3ae086cd602748fe3101..a2b7addf20225ef3e1018b95c2390b449f0f4929 100644 (file)
@@ -26,23 +26,25 @@ fedisableexcept (int excepts)
   int result, new;
 
   /* Get current exception mask to return.  */
-  fe.fenv = curr.fenv = fegetenv_register ();
+  fe.fenv = curr.fenv = fegetenv_status ();
   result = fenv_reg_to_exceptions (fe.l);
 
   if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID)
     excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID;
 
+  new = fenv_exceptions_to_reg (excepts);
+
+  if (fenv_reg_to_exceptions (new) != excepts)
+    return -1;
+
   /* Sets the new exception mask.  */
-  fe.l &= ~ fenv_exceptions_to_reg (excepts);
+  fe.l &= ~new;
 
   if (fe.l != curr.l)
-    fesetenv_register (fe.fenv);
+    fesetenv_mode (fe.fenv);
 
-  new = __fegetexcept ();
   if (new == 0 && result != 0)
     (void)__fe_mask_env ();
 
-  if ((new & excepts) != 0)
-    result = -1;
   return result;
 }
index 3b64398ff185517cdcb081ba21ca8c1c25f467aa..c06a7fdb72c2b9cf554ef74376917bb3895822ee 100644 (file)
@@ -26,24 +26,25 @@ feenableexcept (int excepts)
   int result, new;
 
   /* Get current exception mask to return.  */
-  fe.fenv = curr.fenv = fegetenv_register ();
+  fe.fenv = curr.fenv = fegetenv_status ();
   result = fenv_reg_to_exceptions (fe.l);
 
   if ((excepts & FE_ALL_INVALID) == FE_ALL_INVALID)
     excepts = (excepts | FE_INVALID) & ~ FE_ALL_INVALID;
 
+  new = fenv_exceptions_to_reg (excepts);
+
+  if (fenv_reg_to_exceptions (new) != excepts)
+    return -1;
+
   /* Sets the new exception mask.  */
-  fe.l |= fenv_exceptions_to_reg (excepts);
+  fe.l |= new;
 
   if (fe.l != curr.l)
-    fesetenv_register (fe.fenv);
+    fesetenv_mode (fe.fenv);
 
-  new = __fegetexcept ();
   if (new != 0 && result == 0)
     (void) __fe_nomask_env_priv ();
 
-  if ((new & excepts) != excepts)
-    result = -1;
-
   return result;
 }
index 9956136a13085565962bc8e389fb2602f9d6d16b..4144d413a25fe6db3f1373b6ba137486d82ef5d1 100644 (file)
@@ -70,6 +70,11 @@ extern const fenv_t *__fe_mask_env (void) attribute_hidden;
            __builtin_mtfsf (0xff, d); \
        } while(0)
 
+/* Set the last 2 nibbles of the FPSCR, which contain the
+   exception enables and the rounding mode.
+   'fegetenv_status' retrieves these bits by reading the FPSCR.  */
+#define fesetenv_mode(env) __builtin_mtfsf (0b00000011, (env));
+
 /* This very handy macro:
    - Sets the rounding mode to 'round to nearest';
    - Sets the processor into IEEE mode; and
@@ -208,8 +213,11 @@ enum {
   (FPSCR_VE_MASK|FPSCR_OE_MASK|FPSCR_UE_MASK|FPSCR_ZE_MASK|FPSCR_XE_MASK)
 #define FPSCR_BASIC_EXCEPTIONS_MASK \
   (FPSCR_VX_MASK|FPSCR_OX_MASK|FPSCR_UX_MASK|FPSCR_ZX_MASK|FPSCR_XX_MASK)
-
+#define FPSCR_FPRF_MASK \
+  (FPSCR_FPRF_C_MASK|FPSCR_FPRF_FL_MASK|FPSCR_FPRF_FG_MASK| \
+   FPSCR_FPRF_FE_MASK|FPSCR_FPRF_FU_MASK)
 #define FPSCR_CONTROL_MASK (FPSCR_ENABLES_MASK|FPSCR_NI_MASK|FPSCR_RN_MASK)
+#define FPSCR_STATUS_MASK (FPSCR_FR_MASK|FPSCR_FI_MASK|FPSCR_FPRF_MASK)
 
 /* The bits in the FENV(1) ABI for exceptions correspond one-to-one with bits
    in the FPSCR, albeit shifted to different but corresponding locations.
index 4f4f71a3ba2eebf96f9a31c74e1866d30ddcb675..e92559b6d5ad3cadf2b79e4cfe602d7e6c5c7fde 100644 (file)
 #include <fenv_libc.h>
 #include <fpu_control.h>
 
-#define _FPU_MASK_ALL (_FPU_MASK_ZM | _FPU_MASK_OM | _FPU_MASK_UM      \
-                      | _FPU_MASK_XM | _FPU_MASK_IM)
-
-#define FPU_STATUS 0xbffff700ULL
-
 int
 fesetmode (const femode_t *modep)
 {
@@ -32,18 +27,18 @@ fesetmode (const femode_t *modep)
   /* Logic regarding enabled exceptions as in fesetenv.  */
 
   new.fenv = *modep;
-  old.fenv = fegetenv_register ();
-  new.l = (new.l & ~FPU_STATUS) | (old.l & FPU_STATUS);
+  old.fenv = fegetenv_status ();
+  new.l = (new.l & ~FPSCR_STATUS_MASK) | (old.l & FPSCR_STATUS_MASK);
 
   if (old.l == new.l)
     return 0;
 
-  if ((old.l & _FPU_MASK_ALL) == 0 && (new.l & _FPU_MASK_ALL) != 0)
+  if ((old.l & FPSCR_ENABLES_MASK) == 0 && (new.l & FPSCR_ENABLES_MASK) != 0)
     (void) __fe_nomask_env_priv ();
 
-  if ((old.l & _FPU_MASK_ALL) != 0 && (new.l & _FPU_MASK_ALL) == 0)
+  if ((old.l & FPSCR_ENABLES_MASK) != 0 && (new.l & FPSCR_ENABLES_MASK) == 0)
     (void) __fe_mask_env ();
 
-  fesetenv_register (new.fenv);
+  fesetenv_mode (new.fenv);
   return 0;
 }
This page took 0.075718 seconds and 5 git commands to generate.