about summary refs log tree commit diff
diff options
context:
space:
mode:
authorWilco <wdijkstr@arm.com>2014-06-02 12:20:17 +0100
committerMarcus Shawcroft <marcus.shawcroft@arm.com>2014-06-02 12:36:34 +0100
commitc95b3011018893fcc473279768a67a24a73bbef2 (patch)
tree1f1bb0d68007030ff5bb22a54d62ff621e0abd7a
parent6b4d7a909ffeb49a7b91ba5d0bac5b4f9c5b6d1b (diff)
downloadglibc-c95b3011018893fcc473279768a67a24a73bbef2.tar.gz
glibc-c95b3011018893fcc473279768a67a24a73bbef2.tar.xz
glibc-c95b3011018893fcc473279768a67a24a73bbef2.zip
[AArch64] Rewrite feupdateenv (BZ 17009).
-rw-r--r--ChangeLog6
-rw-r--r--NEWS3
-rw-r--r--sysdeps/aarch64/fpu/feupdateenv.c59
3 files changed, 62 insertions, 6 deletions
diff --git a/ChangeLog b/ChangeLog
index 62375be14a..b20156cb0c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2014-06-02  Wilco  <wdijkstr@arm.com>
+
+	[BZ #17009]
+	* sysdeps/aarch64/fpu/feupdateenv (feupdateenv):
+	Rewrite to reduce FPCR/FPSR accesses.
+
 2014-06-01  David S. Miller  <davem@davemloft.net>
 
 	* sysdeps/sparc/fpu/libm-test-ulps: Update.
diff --git a/NEWS b/NEWS
index 52d5714d44..f6ace19d5f 100644
--- a/NEWS
+++ b/NEWS
@@ -18,7 +18,8 @@ Version 2.20
   16758, 16759, 16760, 16770, 16786, 16789, 16791, 16796, 16799, 16800,
   16815, 16823, 16824, 16831, 16838, 16849, 16854, 16876, 16877, 16878,
   16885, 16888, 16890, 16912, 16915, 16916, 16917, 16922, 16927, 16928,
-  16932, 16943, 16958, 16966, 16967, 16965, 16977, 16978, 16984, 16990.
+  16932, 16943, 16958, 16966, 16967, 16965, 16977, 16978, 16984, 16990,
+  17009.
 
 * The minimum Linux kernel version that this version of the GNU C Library
   can be used with is 2.6.32.
diff --git a/sysdeps/aarch64/fpu/feupdateenv.c b/sysdeps/aarch64/fpu/feupdateenv.c
index 6d64a9b727..ac2f6fe7f8 100644
--- a/sysdeps/aarch64/fpu/feupdateenv.c
+++ b/sysdeps/aarch64/fpu/feupdateenv.c
@@ -22,16 +22,65 @@
 int
 feupdateenv (const fenv_t *envp)
 {
+  fpu_control_t fpcr;
+  fpu_control_t fpcr_new;
+  fpu_control_t updated_fpcr;
   fpu_fpsr_t fpsr;
+  fpu_fpsr_t fpsr_new;
+  int excepts;
 
-  /* Get the current exception state.  */
+  _FPU_GETCW (fpcr);
   _FPU_GETFPSR (fpsr);
+  excepts = fpsr & FE_ALL_EXCEPT;
 
-  /* Install new environment.  */
-  fesetenv (envp);
+  if ((envp != FE_DFL_ENV) && (envp != FE_NOMASK_ENV))
+    {
+      fpcr_new = envp->__fpcr;
+      fpsr_new = envp->__fpsr | excepts;
 
-  /* Raise the saved exceptions.  */
-  feraiseexcept (fpsr & FE_ALL_EXCEPT);
+      if (fpcr != fpcr_new)
+        _FPU_SETCW (fpcr_new);
+
+      if (fpsr != fpsr_new)
+        _FPU_SETFPSR (fpsr_new);
+
+      if (excepts & (fpcr_new >> FE_EXCEPT_SHIFT))
+        return feraiseexcept (excepts);
+
+      return 0;
+    }
+
+  fpcr_new = fpcr & _FPU_RESERVED;
+  fpsr_new = fpsr & (_FPU_FPSR_RESERVED | FE_ALL_EXCEPT);
+
+  if (envp == FE_DFL_ENV)
+    {
+      fpcr_new |= _FPU_DEFAULT;
+      fpsr_new |= _FPU_FPSR_DEFAULT;
+    }
+  else
+    {
+      fpcr_new |= _FPU_FPCR_IEEE;
+      fpsr_new |= _FPU_FPSR_IEEE;
+    }
+
+  _FPU_SETFPSR (fpsr_new);
+
+  if (fpcr != fpcr_new)
+    {
+      _FPU_SETCW (fpcr_new);
+
+      /* Trapping exceptions are optional in AArch64; the relevant enable
+	 bits in FPCR are RES0 hence the absence of support can be detected
+	 by reading back the FPCR and comparing with the required value.  */
+      _FPU_GETCW (updated_fpcr);
+
+      if (fpcr_new & ~updated_fpcr)
+        return 1;
+    }
+
+  if (excepts & (fpcr_new >> FE_EXCEPT_SHIFT))
+    return feraiseexcept (excepts);
 
   return 0;
 }