aboutsummaryrefslogtreecommitdiff
path: root/sysdeps/arm/feupdateenv.c
diff options
context:
space:
mode:
authorWilco <wdijkstr@arm.com>2014-06-24 13:53:04 +0000
committerWilco <wdijkstr@arm.com>2014-06-24 13:53:04 +0000
commitdb59bad394ef61bf6d6ef7916012f2a09d0b3d11 (patch)
tree9605e6411433339e020a53841702db0171efaf81 /sysdeps/arm/feupdateenv.c
parent001f7b773c637560ecfa686452a5e68d60d07db3 (diff)
downloadglibc-db59bad394ef61bf6d6ef7916012f2a09d0b3d11.zip
glibc-db59bad394ef61bf6d6ef7916012f2a09d0b3d11.tar.gz
glibc-db59bad394ef61bf6d6ef7916012f2a09d0b3d11.tar.bz2
Rewrite feupdateenv
This patch rewrites feupdateenv to improve performance by avoiding unnecessary FPSCR reads/writes. It fixes bug 16918 by passing the correct return value. 2014-06-24 Wilco <wdijkstr@arm.com> [BZ #16918] * sysdeps/arm/feupdateenv.c (feupdateenv): Rewrite to reduce FPSCR accesses and fix return value.
Diffstat (limited to 'sysdeps/arm/feupdateenv.c')
-rw-r--r--sysdeps/arm/feupdateenv.c44
1 files changed, 38 insertions, 6 deletions
diff --git a/sysdeps/arm/feupdateenv.c b/sysdeps/arm/feupdateenv.c
index 55a1502..d811678 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)