about summary refs log tree commit diff
path: root/sysdeps
diff options
context:
space:
mode:
authorCarlos O'Donell <carlos@systemhalted.org>2015-03-11 02:42:27 -0400
committerCarlos O'Donell <carlos@systemhalted.org>2015-03-11 02:48:59 -0400
commite4363cfb5760d88a9f353c69383b15d5c2705070 (patch)
treed45136a41ea523d4ee293b62fcbe98b2095a16d6 /sysdeps
parentfae1aa8d226ce860124efd67ede03004b19b89e2 (diff)
downloadglibc-e4363cfb5760d88a9f353c69383b15d5c2705070.tar.gz
glibc-e4363cfb5760d88a9f353c69383b15d5c2705070.tar.xz
glibc-e4363cfb5760d88a9f353c69383b15d5c2705070.zip
hppa: Fix feupdateenv and fesetexceptflag (Bug 18111).
The function feupdateenv has been fixed to correctly handle FE_DFL_ENV
and FE_NOMASK_ENV.

The fesetexceptflag function has been fixed to correctly handle setting
the new flags instead of just OR-ing the existing flags.

This fixes the test-fenv-return and test-fenvinline failures on hppa.
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/hppa/fpu/feupdateenv.c19
-rw-r--r--sysdeps/hppa/fpu/fpu_control.h7
-rw-r--r--sysdeps/hppa/fpu/fsetexcptflg.c18
3 files changed, 34 insertions, 10 deletions
diff --git a/sysdeps/hppa/fpu/feupdateenv.c b/sysdeps/hppa/fpu/feupdateenv.c
index 931f7e6292..345559edab 100644
--- a/sysdeps/hppa/fpu/feupdateenv.c
+++ b/sysdeps/hppa/fpu/feupdateenv.c
@@ -29,9 +29,22 @@ __feupdateenv (const fenv_t *envp)
   __asm__ ("fstd %%fr0,0(%1)	\n\t"
            "fldd 0(%1),%%fr0	\n\t"
 	   : "=m" (s.l) : "r" (&s.l));
-  memcpy(&temp, envp, sizeof(fenv_t));
-  /* Currently raised exceptions not cleared */
-  temp.__status_word |= s.sw[0] & (FE_ALL_EXCEPT << 27);
+
+  /* Given environment with exception flags not cleared.  */
+  if ((envp != FE_DFL_ENV) && (envp != FE_NOMASK_ENV))
+    {
+      memcpy(&temp, envp, sizeof(fenv_t));
+      temp.__status_word |= s.sw[0] & (FE_ALL_EXCEPT << 27);
+    }
+
+  /* Default environment with exception flags not cleared.  */
+  if (envp == FE_DFL_ENV)
+    temp.__status_word = s.sw[0] & (FE_ALL_EXCEPT << 27);
+
+  /* All traps enabled and current exception flags not cleared.  */
+  if (envp == FE_NOMASK_ENV)
+    temp.__status_word = (s.sw[0] & (FE_ALL_EXCEPT << 27)) | FE_ALL_EXCEPT;
+
   /* Install new environment.  */
   __fesetenv (&temp);
   /* Success.  */
diff --git a/sysdeps/hppa/fpu/fpu_control.h b/sysdeps/hppa/fpu/fpu_control.h
index ba9692fe63..2087928496 100644
--- a/sysdeps/hppa/fpu/fpu_control.h
+++ b/sysdeps/hppa/fpu/fpu_control.h
@@ -19,7 +19,7 @@
 #ifndef _FPU_CONTROL_H
 #define _FPU_CONTROL_H
 
-/* Masking of interrupts */
+/* Masking of interrupts.  */
 #define _FPU_MASK_PM	0x00000001	/* Inexact (I) */
 #define _FPU_MASK_UM	0x00000002	/* Underflow (U) */
 #define _FPU_MASK_OM	0x00000004	/* Overflow (O) */
@@ -30,6 +30,8 @@
 #define _FPU_HPPA_MASK_RM	0x00000600	/* Rounding mode mask */
 /* Masking of interrupt enable bits.  */
 #define _FPU_HPPA_MASK_INT	0x0000001f	/* Interrupt mask */
+/* Shift by 27 to install flag bits.  */
+#define _FPU_HPPA_SHIFT_FLAGS	27
 
 /* There are no reserved bits in the PA fpsr (though some are undefined).  */
 #define _FPU_RESERVED	0x00000000
@@ -55,6 +57,9 @@ typedef unsigned int fpu_control_t;
 #define _FPU_SETCW(cw) \
 ({										\
   union { __extension__ unsigned long long __fpreg; unsigned int __halfreg[2]; } __fullfp;	\
+  /* Get the current status word and set the control word.  */			\
+  __asm__ ("fstd %%fr0,0(%1)\n\t"						\
+	   : "=m" (__fullfp.__fpreg) : "r" (&__fullfp.__fpreg) : "%r0");	\
   __fullfp.__halfreg[0] = cw;							\
   __asm__ ("fldd 0(%1),%%fr0\n\t"						\
 	   : : "m" (__fullfp.__fpreg), "r" (&__fullfp.__fpreg) : "%r0" );	\
diff --git a/sysdeps/hppa/fpu/fsetexcptflg.c b/sysdeps/hppa/fpu/fsetexcptflg.c
index 2c34a1e287..c31de8bbe4 100644
--- a/sysdeps/hppa/fpu/fsetexcptflg.c
+++ b/sysdeps/hppa/fpu/fsetexcptflg.c
@@ -18,19 +18,25 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <fenv.h>
-#include <math.h>
+#include <fpu_control.h>
 
 int
 fesetexceptflag (const fexcept_t *flagp, int excepts)
 {
-  union { unsigned long long l; unsigned int sw[2]; } s;
+  fpu_control_t fpsr;
+  fpu_control_t fpsr_new;
 
   /* Get the current status word. */
-  __asm__ ("fstd %%fr0,0(%1)" : "=m" (s.l) : "r" (&s.l) : "%r0");
-  /* Install new raised trap bits */
-  s.sw[0] |= (*flagp & excepts & FE_ALL_EXCEPT) << 27;
+  _FPU_GETCW (fpsr);
+  excepts &= FE_ALL_EXCEPT;
+
+  /* Install new raised flags.  */
+  fpsr_new = fpsr & ~(excepts << _FPU_HPPA_SHIFT_FLAGS);
+  fpsr_new |= (*flagp & excepts) << _FPU_HPPA_SHIFT_FLAGS;
+
   /* Store the new status word.  */
-  __asm__ ("fldd 0(%0),%%fr0" : : "r" (&s.l), "m" (s.l) : "%r0");
+  if (fpsr != fpsr_new)
+    _FPU_SETCW (fpsr_new);
 
   /* Success.  */
   return 0;