[1/2] ARM: Improve fenv implementation

Message ID 000c01cf6ad1$6629ac70$327d0550$@com
State Committed
Headers

Commit Message

Wilco Dijkstra May 8, 2014, 3:23 p.m. UTC
  Hi Marcus,

Since this has been approved by Joseph, could you check this in?

Wilco

ChangeLog:
2014-05-08  Wilco  <wdijkstr@arm.com>

	* sysdeps/arm/fclrexcpt.c: Cleanup.
	* sysdeps/arm/fedisblxcpt.c: Cleanup.
	* sysdeps/arm/feenablxcpt.c: Cleanup.
	* sysdeps/arm/fegetenv.c: Cleanup.
	* sysdeps/arm/fegetexcept.c: Cleanup.
	* sysdeps/arm/fegetround.c: Cleanup.
	* sysdeps/arm/feholdexcpt.c: Cleanup.
	* sysdeps/arm/fesetenv.c: Cleanup.
	* sysdeps/arm/fesetround.c: Cleanup.
	* sysdeps/arm/feupdateenv.c: Cleanup.
	* sysdeps/arm/fgetexcptflg.c: Cleanup.
	* sysdeps/arm/fraiseexcpt.c: Cleanup.
	* sysdeps/arm/fsetexcptflg.c: Cleanup.
	* sysdeps/arm/ftestexcept.c: Cleanup.
	* sysdeps/arm/get-rounding-mode.h: Cleanup.
	* sysdeps/arm/setfpucw.c: Cleanup.

-----Original Message-----
From: Wilco [mailto:wdijkstr@arm.com] 
Sent: 25 April 2014 11:50
To: 'libc-alpha@sourceware.org'
Subject: [PATCH 1/2] ARM: Improve fenv implementation

Hi,

This is a series of patches which improves the fenv implementation to make it more similar to the
inline functions in fenv_private.h.

The first patch is a cleanup with no functional changes. It uses fpu_control_t consistently with
meaningful variable names, fixes some coding style mistakes, improves comments and avoids
unnecessary indentation due to the ARM_HAVE_VFP check.

Wilco
---
 sysdeps/arm/fclrexcpt.c         |   27 +++++++------------
 sysdeps/arm/fedisblxcpt.c       |   24 +++++++----------
 sysdeps/arm/feenablxcpt.c       |   42 ++++++++++++-----------------
 sysdeps/arm/fegetenv.c          |   21 +++++++--------
 sysdeps/arm/fegetexcept.c       |   14 +++++-----
 sysdeps/arm/fegetround.c        |   17 +++++-------
 sysdeps/arm/feholdexcpt.c       |   28 +++++++++-----------
 sysdeps/arm/fesetenv.c          |   56 +++++++++++++++++++--------------------
 sysdeps/arm/fesetround.c        |   39 +++++++++++----------------
 sysdeps/arm/feupdateenv.c       |   25 +++++++----------
 sysdeps/arm/fgetexcptflg.c      |   19 +++++--------
 sysdeps/arm/fraiseexcpt.c       |   10 +++----
 sysdeps/arm/fsetexcptflg.c      |   27 ++++++++-----------
 sysdeps/arm/ftestexcept.c       |   16 +++++------
 sysdeps/arm/get-rounding-mode.h |   16 +++++------
 sysdeps/arm/setfpucw.c          |   23 ++++++++--------
 16 files changed, 171 insertions(+), 233 deletions(-)
  

Patch

diff --git a/sysdeps/arm/fclrexcpt.c b/sysdeps/arm/fclrexcpt.c
index 8b54114..098a9bb 100644
--- a/sysdeps/arm/fclrexcpt.c
+++ b/sysdeps/arm/fclrexcpt.c
@@ -24,28 +24,21 @@ 
 int
 __feclearexcept (int excepts)
 {
-  if (ARM_HAVE_VFP)
-    {
-      unsigned long int temp;
+  fpu_control_t fpscr;
 
-      /* Mask out unsupported bits/exceptions.  */
-      excepts &= FE_ALL_EXCEPT;
+  /* Fail if a VFP unit isn't present unless nothing needs to be done.  */
+  if (!ARM_HAVE_VFP)
+    return (excepts != 0);
 
-      /* Get the current floating point status. */
-      _FPU_GETCW (temp);
+  _FPU_GETCW (fpscr);
+  excepts &= FE_ALL_EXCEPT;
 
-      /* Clear the relevant bits.  */
-      temp = (temp & ~FE_ALL_EXCEPT) | (temp & FE_ALL_EXCEPT & ~excepts);
+  /* Clear the relevant bits.  */
+  fpscr = (fpscr & ~FE_ALL_EXCEPT) | (fpscr & FE_ALL_EXCEPT & ~excepts);
 
-      /* Put the new data in effect.  */
-      _FPU_SETCW (temp);
+  _FPU_SETCW (fpscr);
 
-      /* Success.  */
-      return 0;
-    }
-
-  /* Unsupported, so fail unless nothing needs to be done.  */
-  return (excepts != 0);
+  return 0;
 }
 
 #include <shlib-compat.h>
diff --git a/sysdeps/arm/fedisblxcpt.c b/sysdeps/arm/fedisblxcpt.c
index 88da539..f2956cd 100644
--- a/sysdeps/arm/fedisblxcpt.c
+++ b/sysdeps/arm/fedisblxcpt.c
@@ -25,23 +25,17 @@ 
 int
 fedisableexcept (int excepts)
 {
-  if (ARM_HAVE_VFP)
-    {
-      unsigned long int new_exc, old_exc;
+  fpu_control_t fpscr, new_fpscr;
 
-      _FPU_GETCW(new_exc);
+  /* Fail if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return -1;
 
-      old_exc = (new_exc >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT;
+  _FPU_GETCW (fpscr);
+  excepts &= FE_ALL_EXCEPT;
+  new_fpscr = fpscr & ~(excepts << FE_EXCEPT_SHIFT);
 
-      excepts &= FE_ALL_EXCEPT;
+  _FPU_SETCW (new_fpscr);
 
-      new_exc &= ~(excepts << FE_EXCEPT_SHIFT);
-
-      _FPU_SETCW(new_exc);
-
-      return old_exc;
-    }
-
-  /* Unsupported, so return -1 for failure.  */
-  return -1;
+  return (fpscr >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT;
 }
diff --git a/sysdeps/arm/feenablxcpt.c b/sysdeps/arm/feenablxcpt.c
index b286ec5..afd8943 100644
--- a/sysdeps/arm/feenablxcpt.c
+++ b/sysdeps/arm/feenablxcpt.c
@@ -25,35 +25,27 @@ 
 int
 feenableexcept (int excepts)
 {
-  if (ARM_HAVE_VFP)
-    {
-      unsigned long int new_exc, old_exc;
-
-      _FPU_GETCW(new_exc);
-
-      old_exc = (new_exc >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT;
+  fpu_control_t fpscr, new_fpscr;
 
-      excepts &= FE_ALL_EXCEPT;
+  /* Fail if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return -1;
 
-      new_exc |= (excepts << FE_EXCEPT_SHIFT);
+  _FPU_GETCW (fpscr);
+  excepts &= FE_ALL_EXCEPT;
+  new_fpscr = fpscr | (excepts << FE_EXCEPT_SHIFT);
 
-      _FPU_SETCW(new_exc);
+  _FPU_SETCW (new_fpscr);
 
-      if (excepts != 0)
-	{
-	  /* VFPv3 and VFPv4 do not support trapping exceptions, so
-	     test whether the relevant bits were set and fail if
-	     not.  */
-	  unsigned int temp;
-	  _FPU_GETCW (temp);
-	  if ((temp & (excepts << FE_EXCEPT_SHIFT))
-	      != (excepts << FE_EXCEPT_SHIFT))
-	    return -1;
-	}
-
-      return old_exc;
+  if (excepts != 0)
+    {
+      /* Not all VFP architectures support trapping exceptions, so
+	 test whether the relevant bits were set and fail if not.  */
+      _FPU_GETCW (new_fpscr);
+      if ((new_fpscr & (excepts << FE_EXCEPT_SHIFT))
+	  != (excepts << FE_EXCEPT_SHIFT))
+	return -1;
     }
 
-  /* Unsupported, so return -1 for failure.  */
-  return -1;
+  return (fpscr >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT;
 }
diff --git a/sysdeps/arm/fegetenv.c b/sysdeps/arm/fegetenv.c
index 7003a01..8dc043b 100644
--- a/sysdeps/arm/fegetenv.c
+++ b/sysdeps/arm/fegetenv.c
@@ -24,18 +24,15 @@ 
 int
 __fegetenv (fenv_t *envp)
 {
-  if (ARM_HAVE_VFP)
-    {
-      unsigned long int temp;
-      _FPU_GETCW (temp);
-      envp->__cw = temp;
-
-      /* Success.  */
-      return 0;
-    }
-
-  /* Unsupported, so fail.  */
-  return 1;
+  fpu_control_t fpscr;
+
+  /* Fail if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return 1;
+
+  _FPU_GETCW (fpscr);
+  envp->__cw = fpscr;
+  return 0;
 }
 
 #include <shlib-compat.h>
diff --git a/sysdeps/arm/fegetexcept.c b/sysdeps/arm/fegetexcept.c
index 5974c63..aa244d0 100644
--- a/sysdeps/arm/fegetexcept.c
+++ b/sysdeps/arm/fegetexcept.c
@@ -25,15 +25,13 @@ 
 int
 fegetexcept (void)
 {
-  if (ARM_HAVE_VFP)
-    {
-      unsigned long temp;
+  fpu_control_t fpscr;
 
-      _FPU_GETCW (temp);
+  /* Return with all exceptions disabled if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return 0;
 
-      return (temp >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT;
-    }
+  _FPU_GETCW (fpscr);
 
-  /* Unsupported. Return all exceptions disabled.  */
-  return 0;
+  return (fpscr >> FE_EXCEPT_SHIFT) & FE_ALL_EXCEPT;
 }
diff --git a/sysdeps/arm/fegetround.c b/sysdeps/arm/fegetround.c
index cb4cf1b..1c9c151 100644
--- a/sysdeps/arm/fegetround.c
+++ b/sysdeps/arm/fegetround.c
@@ -24,17 +24,14 @@ 
 int
 fegetround (void)
 {
-  if (ARM_HAVE_VFP)
-    {
-      unsigned int temp;
+  fpu_control_t fpscr;
 
-      /* Get the current environment.  */
-      _FPU_GETCW (temp);
+  /* FE_TONEAREST is the only supported rounding mode
+     if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return FE_TONEAREST;
 
-      return temp & FE_TOWARDZERO;
-    }
-
-  /* The current soft-float implementation only handles TONEAREST.  */
-  return FE_TONEAREST;
+  _FPU_GETCW (fpscr);
+  return fpscr & FE_TOWARDZERO;
 }
 libm_hidden_def (fegetround)
diff --git a/sysdeps/arm/feholdexcpt.c b/sysdeps/arm/feholdexcpt.c
index 9ca673c..258ba66 100644
--- a/sysdeps/arm/feholdexcpt.c
+++ b/sysdeps/arm/feholdexcpt.c
@@ -24,27 +24,23 @@ 
 int
 feholdexcept (fenv_t *envp)
 {
-  if (ARM_HAVE_VFP)
-    {
-      unsigned long int temp;
+  fpu_control_t fpscr;
 
-      /* Store the environment.  */
-      _FPU_GETCW(temp);
-      envp->__cw = temp;
+  /* Fail if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return 1;
 
-      /* Now set all exceptions to non-stop.  */
-      temp &= ~(FE_ALL_EXCEPT << FE_EXCEPT_SHIFT);
+  _FPU_GETCW (fpscr);
+  envp->__cw = fpscr;
 
-      /* And clear all exception flags.  */
-      temp &= ~FE_ALL_EXCEPT;
+  /* Now set all exceptions to non-stop.  */
+  fpscr &= ~(FE_ALL_EXCEPT << FE_EXCEPT_SHIFT);
 
-      _FPU_SETCW(temp);
+  /* And clear all exception flags.  */
+  fpscr &= ~FE_ALL_EXCEPT;
 
-      return 0;
-    }
-
-  /* Unsupported, so fail.  */
-  return 1;
+  _FPU_SETCW (fpscr);
+  return 0;
 }
 
 libm_hidden_def (feholdexcept)
diff --git a/sysdeps/arm/fesetenv.c b/sysdeps/arm/fesetenv.c
index af4f25d..43b9b47 100644
--- a/sysdeps/arm/fesetenv.c
+++ b/sysdeps/arm/fesetenv.c
@@ -24,38 +24,36 @@ 
 int
 __fesetenv (const fenv_t *envp)
 {
-  if (ARM_HAVE_VFP)
+  fpu_control_t fpscr;
+
+  /* Fail if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return 1;
+
+  _FPU_GETCW (fpscr);
+
+  /* Preserve the reserved FPSCR flags.  */
+  fpscr &= _FPU_RESERVED;
+
+  if (envp == FE_DFL_ENV)
+    fpscr |= _FPU_DEFAULT;
+  else if (envp == FE_NOMASK_ENV)
+    fpscr |= _FPU_IEEE;
+  else
+    fpscr |= envp->__cw & ~_FPU_RESERVED;
+
+  _FPU_SETCW (fpscr);
+
+  if (envp == FE_NOMASK_ENV)
     {
-      unsigned int temp;
-
-      _FPU_GETCW (temp);
-      temp &= _FPU_RESERVED;
-
-      if (envp == FE_DFL_ENV)
-	temp |= _FPU_DEFAULT;
-      else if (envp == FE_NOMASK_ENV)
-	temp |= _FPU_IEEE;
-      else
-	temp |= envp->__cw & ~_FPU_RESERVED;
-
-      _FPU_SETCW (temp);
-
-      if (envp == FE_NOMASK_ENV)
-	{
-	  /* VFPv3 and VFPv4 do not support trapping exceptions, so
-	     test whether the relevant bits were set and fail if
-	     not.  */
-	  _FPU_GETCW (temp);
-	  if ((temp & _FPU_IEEE) != _FPU_IEEE)
-	    return 1;
-	}
-
-      /* Success.  */
-      return 0;
+      /* Not all VFP architectures support trapping exceptions, so
+	 test whether the relevant bits were set and fail if not.  */
+      _FPU_GETCW (fpscr);
+      if ((fpscr & _FPU_IEEE) != _FPU_IEEE)
+	return 1;
     }
 
-  /* Unsupported, so fail.  */
-  return 1;
+  return 0;
 }
 
 #include <shlib-compat.h>
diff --git a/sysdeps/arm/fesetround.c b/sysdeps/arm/fesetround.c
index 6f533d1..d1b92dc 100644
--- a/sysdeps/arm/fesetround.c
+++ b/sysdeps/arm/fesetround.c
@@ -24,30 +24,21 @@ 
 int
 fesetround (int round)
 {
-  if (ARM_HAVE_VFP)
-    {
-      fpu_control_t temp;
-
-      switch (round)
-	{
-	case FE_TONEAREST:
-	case FE_UPWARD:
-	case FE_DOWNWARD:
-	case FE_TOWARDZERO:
-	  _FPU_GETCW (temp);
-	  temp = (temp & ~FE_TOWARDZERO) | round;
-	  _FPU_SETCW (temp);
-	  return 0;
-	default:
-	  return 1;
-	}
-    }
-  else if (round == FE_TONEAREST)
-    /* This is the only supported rounding mode for soft-fp.  */
-    return 0;
-
-  /* Unsupported, so fail.  */
-  return 1;
+  fpu_control_t fpscr;
+
+  /* FE_TONEAREST is the only supported rounding mode
+     if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return (round == FE_TONEAREST) ? 0 : 1;
+
+  /* Fail if the rounding mode is not valid.  */
+  if (round & ~FE_TOWARDZERO)
+    return 1;
+
+  _FPU_GETCW (fpscr);
+  fpscr = (fpscr & ~FE_TOWARDZERO) | round;
+  _FPU_SETCW (fpscr);
+  return 0;
 }
 
 libm_hidden_def (fesetround)
diff --git a/sysdeps/arm/feupdateenv.c b/sysdeps/arm/feupdateenv.c
index 58ec5f6..7cf6206 100644
--- a/sysdeps/arm/feupdateenv.c
+++ b/sysdeps/arm/feupdateenv.c
@@ -25,25 +25,20 @@ 
 int
 __feupdateenv (const fenv_t *envp)
 {
-  if (ARM_HAVE_VFP)
-    {
-      unsigned int temp;
+  fpu_control_t fpscr;
 
-      /* Get the current exception state.  */
-      _FPU_GETCW (temp);
+  /* Fail if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return 1;
 
-      /* Install new environment.  */
-      fesetenv (envp);
+  _FPU_GETCW (fpscr);
 
-      /* Raise the saved exceptions.  */
-      feraiseexcept (temp & FE_ALL_EXCEPT);
+  /* Install new environment.  */
+  fesetenv (envp);
 
-      /* Success.  */
-      return 0;
-    }
-
-  /* Unsupported, so fail.  */
-  return 1;
+  /* Raise the saved exceptions.  */
+  feraiseexcept (fpscr & FE_ALL_EXCEPT);
+  return 0;
 }
 
 #include <shlib-compat.h>
diff --git a/sysdeps/arm/fgetexcptflg.c b/sysdeps/arm/fgetexcptflg.c
index 1145979..e1eb420 100644
--- a/sysdeps/arm/fgetexcptflg.c
+++ b/sysdeps/arm/fgetexcptflg.c
@@ -25,21 +25,16 @@ 
 int
 __fegetexceptflag (fexcept_t *flagp, int excepts)
 {
-  if (ARM_HAVE_VFP)
-    {
-      unsigned long temp;
+  fpu_control_t fpscr;
 
-      /* Get the current exceptions.  */
-      _FPU_GETCW (temp);
+  /* Fail if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return 1;
 
-      *flagp = temp & excepts & FE_ALL_EXCEPT;
+  _FPU_GETCW (fpscr);
 
-      /* Success.  */
-      return 0;
-    }
-
-  /* Unsupported, so fail.  */
-  return 1;
+  *flagp = fpscr & excepts & FE_ALL_EXCEPT;
+  return 0;
 }
 
 #include <shlib-compat.h>
diff --git a/sysdeps/arm/fraiseexcpt.c b/sysdeps/arm/fraiseexcpt.c
index 8b32065..a964cb0 100644
--- a/sysdeps/arm/fraiseexcpt.c
+++ b/sysdeps/arm/fraiseexcpt.c
@@ -25,9 +25,12 @@ 
 int
 feraiseexcept (int excepts)
 {
-  if (ARM_HAVE_VFP)
+  /* Fail if a VFP unit isn't present unless nothing needs to be done.  */
+  if (!ARM_HAVE_VFP)
+    return (excepts != 0);
+  else
     {
-      int fpscr;
+      fpu_control_t fpscr;
       const float fp_zero = 0.0, fp_one = 1.0, fp_max = FLT_MAX,
                   fp_min = FLT_MIN, fp_1e32 = 1.0e32f, fp_two = 2.0,
 		  fp_three = 3.0;
@@ -98,9 +101,6 @@  feraiseexcept (int excepts)
       /* Success.  */
       return 0;
     }
-
-  /* Unsupported, so fail unless nothing needs to be done.  */
-  return (excepts != 0);
 }
 
 libm_hidden_def (feraiseexcept)
diff --git a/sysdeps/arm/fsetexcptflg.c b/sysdeps/arm/fsetexcptflg.c
index 0c88c0f..a594e15 100644
--- a/sysdeps/arm/fsetexcptflg.c
+++ b/sysdeps/arm/fsetexcptflg.c
@@ -25,26 +25,21 @@ 
 int
 __fesetexceptflag (const fexcept_t *flagp, int excepts)
 {
-  if (ARM_HAVE_VFP)
-    {
-      fexcept_t temp;
+  fpu_control_t fpscr;
 
-      /* Get the current environment.  */
-      _FPU_GETCW (temp);
+  /* Fail if a VFP unit isn't present unless nothing needs to be done.  */
+  if (!ARM_HAVE_VFP)
+    return (excepts != 0);
 
-      /* Set the desired exception mask.  */
-      temp &= ~(excepts & FE_ALL_EXCEPT);
-      temp |= (*flagp & excepts & FE_ALL_EXCEPT);
+  _FPU_GETCW (fpscr);
 
-      /* Save state back to the FPU.  */
-      _FPU_SETCW (temp);
+  /* Set the desired exception mask.  */
+  fpscr &= ~(excepts & FE_ALL_EXCEPT);
+  fpscr |= (*flagp & excepts & FE_ALL_EXCEPT);
 
-      /* Success.  */
-      return 0;
-    }
-
-  /* Unsupported, so fail unless nothing needs to be done.  */
-  return (excepts != 0);
+  /* Save state back to the FPU.  */
+  _FPU_SETCW (fpscr);
+  return 0;
 }
 
 #include <shlib-compat.h>
diff --git a/sysdeps/arm/ftestexcept.c b/sysdeps/arm/ftestexcept.c
index 9295c0f..de082b2 100644
--- a/sysdeps/arm/ftestexcept.c
+++ b/sysdeps/arm/ftestexcept.c
@@ -24,17 +24,15 @@ 
 int
 fetestexcept (int excepts)
 {
-  if (ARM_HAVE_VFP)
-    {
-      fexcept_t temp;
+  fpu_control_t fpscr;
 
-      /* Get current exceptions.  */
-      _FPU_GETCW(temp);
+  /* Return no exception flags if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return 0;
 
-      return temp & excepts & FE_ALL_EXCEPT;
-    }
+  /* Get current exceptions.  */
+  _FPU_GETCW (fpscr);
 
-  /* Unsupported, return 0.  */
-  return 0;
+  return fpscr & excepts & FE_ALL_EXCEPT;
 }
 libm_hidden_def (fetestexcept)
diff --git a/sysdeps/arm/get-rounding-mode.h b/sysdeps/arm/get-rounding-mode.h
index 7d6054c..a1ecf51 100644
--- a/sysdeps/arm/get-rounding-mode.h
+++ b/sysdeps/arm/get-rounding-mode.h
@@ -28,15 +28,15 @@ 
 static inline int
 get_rounding_mode (void)
 {
-  if (ARM_HAVE_VFP)
-    {
-      fpu_control_t fc;
-
-      _FPU_GETCW (fc);
-      return fc & FE_TOWARDZERO;
-    }
-  else
+  fpu_control_t fpscr;
+
+  /* FE_TONEAREST is the only supported rounding mode
+     if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
     return FE_TONEAREST;
+
+  _FPU_GETCW (fpscr);
+  return fpscr & FE_TOWARDZERO;
 }
 
 #endif /* get-rounding-mode.h */
diff --git a/sysdeps/arm/setfpucw.c b/sysdeps/arm/setfpucw.c
index 92333eb..7416377 100644
--- a/sysdeps/arm/setfpucw.c
+++ b/sysdeps/arm/setfpucw.c
@@ -24,20 +24,19 @@ 
 void
 __setfpucw (fpu_control_t set)
 {
-  if (ARM_HAVE_VFP)
-    {
-      fpu_control_t cw;
+  fpu_control_t fpscr;
 
-      /* Fetch the current control word.  */
-      _FPU_GETCW (cw);
+  /* Do nothing if a VFP unit isn't present.  */
+  if (!ARM_HAVE_VFP)
+    return;
 
-      /* Preserve the reserved bits, and set the rest as the user
-	 specified (or the default, if the user gave zero).  */
-      cw &= _FPU_RESERVED;
-      cw |= set & ~_FPU_RESERVED;
+  /* Fetch the current control word.  */
+  _FPU_GETCW (fpscr);
 
-      _FPU_SETCW (cw);
-    }
+  /* Preserve the reserved bits, and set the rest as the user
+     specified (or the default, if the user gave zero).  */
+  fpscr &= _FPU_RESERVED;
+  fpscr |= set & ~_FPU_RESERVED;
 
-  /* Do nothing if a VFP unit isn't present.  */
+  _FPU_SETCW (fpscr);
 }