aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--sysdeps/arm/feupdateenv.c44
2 files changed, 44 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 0b0f61affa..3330b0b98b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,11 @@
2014-06-24 Wilco <wdijkstr@arm.com>
+ [BZ #16918]
+ * sysdeps/arm/feupdateenv.c (feupdateenv):
+ Rewrite to reduce FPSCR accesses and fix return value.
+
+2014-06-24 Wilco <wdijkstr@arm.com>
+
* sysdeps/arm/fclrexcpt.c (feclearexcept):
Optimize to avoid unnecessary FPSCR writes.
* sysdeps/arm/fedisblxcpt.c (fedisableexcept): Likewise.
diff --git a/sysdeps/arm/feupdateenv.c b/sysdeps/arm/feupdateenv.c
index 55a15025c6..d8116789d0 100644
--- a/sysdeps/arm/feupdateenv.c
+++ b/sysdeps/arm/feupdateenv.c
@@ -18,26 +18,58 @@
<http://www.gnu.org/licenses/>. */
#include <fenv.h>
-#include <fpu_control.h>
#include <arm-features.h>
int
feupdateenv (const fenv_t *envp)
{
- fpu_control_t fpscr;
+ fpu_control_t fpscr, new_fpscr, updated_fpscr;
+ int excepts;
/* Fail if a VFP unit isn't present. */
if (!ARM_HAVE_VFP)
return 1;
_FPU_GETCW (fpscr);
+ excepts = fpscr & FE_ALL_EXCEPT;
- /* Install new environment. */
- fesetenv (envp);
+ if ((envp != FE_DFL_ENV) && (envp != FE_NOMASK_ENV))
+ {
+ /* Merge current exception flags with the saved fenv. */
+ new_fpscr = envp->__cw | excepts;
+
+ /* Write new FPSCR if different (ignoring NZCV flags). */
+ if (((fpscr ^ new_fpscr) & ~_FPU_MASK_NZCV) != 0)
+ _FPU_SETCW (new_fpscr);
+
+ /* Raise the exceptions if enabled in the new FP state. */
+ if (excepts & (new_fpscr >> FE_EXCEPT_SHIFT))
+ return feraiseexcept (excepts);
+
+ return 0;
+ }
+
+ /* Preserve the reserved FPSCR flags. */
+ new_fpscr = fpscr & (_FPU_RESERVED | FE_ALL_EXCEPT);
+ new_fpscr |= (envp == FE_DFL_ENV) ? _FPU_DEFAULT : _FPU_IEEE;
+
+ if (((new_fpscr ^ fpscr) & ~_FPU_MASK_NZCV) != 0)
+ {
+ _FPU_SETCW (new_fpscr);
+
+ /* Not all VFP architectures support trapping exceptions, so
+ test whether the relevant bits were set and fail if not. */
+ _FPU_GETCW (updated_fpscr);
+
+ if (new_fpscr & ~updated_fpscr)
+ return 1;
+ }
+
+ /* Raise the exceptions if enabled in the new FP state. */
+ if (excepts & (new_fpscr >> FE_EXCEPT_SHIFT))
+ return feraiseexcept (excepts);
- /* Raise the saved exceptions. */
- feraiseexcept (fpscr & FE_ALL_EXCEPT);
return 0;
}
libm_hidden_def (feupdateenv)