aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog19
-rw-r--r--NEWS24
-rw-r--r--sysdeps/i386/fpu/fesetenv.c40
-rw-r--r--sysdeps/x86/fpu/Makefile3
-rw-r--r--sysdeps/x86/fpu/test-fenv-sse-2.c176
-rw-r--r--sysdeps/x86/fpu/test-fenv-x87.c169
-rw-r--r--sysdeps/x86_64/fpu/fesetenv.c40
7 files changed, 438 insertions, 33 deletions
diff --git a/ChangeLog b/ChangeLog
index 52cd9f3..9ef00a7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,24 @@
2015-10-28 Joseph Myers <joseph@codesourcery.com>
+ [BZ #16068]
+ * sysdeps/i386/fpu/fesetenv.c: Include <fpu_control.h>.
+ (FE_ALL_EXCEPT_X86): New macro.
+ (__fesetenv): Use FE_ALL_EXCEPT_X86 in most places instead of
+ FE_ALL_EXCEPT. Ensure precision control is included in
+ floating-point state. Ensure that FE_DFL_ENV and FE_NOMASK_ENV
+ handle "denormal operand exception" and clear FZ and DAZ bits.
+ * sysdeps/x86_64/fpu/fesetenv.c: Include <fpu_control.h>.
+ (FE_ALL_EXCEPT_X86): New macro.
+ (__fesetenv): Use FE_ALL_EXCEPT_X86 in most places instead of
+ FE_ALL_EXCEPT. Ensure precision control is included in
+ floating-point state. Ensure that FE_DFL_ENV and FE_NOMASK_ENV
+ handle "denormal operand exception" and clear FZ and DAZ bits.
+ * sysdeps/x86/fpu/test-fenv-sse-2.c: New file.
+ * sysdeps/x86/fpu/test-fenv-x87.c: Likewise.
+ * sysdeps/x86/fpu/Makefile [$(subdir) = math] (tests): Add
+ test-fenv-x87 and test-fenv-sse-2.
+ [$(subdir) = math] (CFLAGS-test-fenv-sse-2.c): New variable.
+
* math/libm-test.inc (BUILD_COMPLEX): Remove macro.
* math/test-double.h (BUILD_COMPLEX): New macro.
* math/test-float.h (BUILD_COMPLEX): Likewise.
diff --git a/NEWS b/NEWS
index 9b34391..0831d35 100644
--- a/NEWS
+++ b/NEWS
@@ -10,18 +10,18 @@ Version 2.23
* The following bugs are resolved with this release:
887, 2542, 2543, 2558, 2898, 4404, 6803, 10432, 14341, 14912, 15367,
- 15384, 15470, 15491, 15786, 15918, 16141, 16296, 16347, 16399, 16415,
- 16422, 16517, 16519, 16520, 16521, 16620, 16734, 16973, 16985, 17118,
- 17243, 17244, 17250, 17404, 17441, 17787, 17886, 17887, 17905, 18084,
- 18086, 18240, 18265, 18370, 18421, 18480, 18525, 18595, 18589, 18610,
- 18611, 18618, 18647, 18661, 18674, 18675, 18681, 18699, 18724, 18743,
- 18757, 18778, 18781, 18787, 18789, 18790, 18795, 18796, 18803, 18820,
- 18823, 18824, 18825, 18857, 18863, 18870, 18872, 18873, 18875, 18887,
- 18918, 18921, 18928, 18951, 18952, 18953, 18956, 18961, 18966, 18967,
- 18969, 18970, 18977, 18980, 18981, 18982, 18985, 19003, 19007, 19012,
- 19016, 19018, 19032, 19046, 19048, 19049, 19050, 19059, 19071, 19074,
- 19076, 19077, 19078, 19079, 19085, 19086, 19088, 19094, 19095, 19124,
- 19125, 19129, 19134, 19137, 19156, 19174, 19181.
+ 15384, 15470, 15491, 15786, 15918, 16068, 16141, 16296, 16347, 16399,
+ 16415, 16422, 16517, 16519, 16520, 16521, 16620, 16734, 16973, 16985,
+ 17118, 17243, 17244, 17250, 17404, 17441, 17787, 17886, 17887, 17905,
+ 18084, 18086, 18240, 18265, 18370, 18421, 18480, 18525, 18595, 18589,
+ 18610, 18611, 18618, 18647, 18661, 18674, 18675, 18681, 18699, 18724,
+ 18743, 18757, 18778, 18781, 18787, 18789, 18790, 18795, 18796, 18803,
+ 18820, 18823, 18824, 18825, 18857, 18863, 18870, 18872, 18873, 18875,
+ 18887, 18918, 18921, 18928, 18951, 18952, 18953, 18956, 18961, 18966,
+ 18967, 18969, 18970, 18977, 18980, 18981, 18982, 18985, 19003, 19007,
+ 19012, 19016, 19018, 19032, 19046, 19048, 19049, 19050, 19059, 19071,
+ 19074, 19076, 19077, 19078, 19079, 19085, 19086, 19088, 19094, 19095,
+ 19124, 19125, 19129, 19134, 19137, 19156, 19174, 19181.
* A defect in the malloc implementation, present since glibc 2.15 (2012) or
glibc 2.10 via --enable-experimental-malloc (2009), could result in the
diff --git a/sysdeps/i386/fpu/fesetenv.c b/sysdeps/i386/fpu/fesetenv.c
index 910aa09..f3b9cef 100644
--- a/sysdeps/i386/fpu/fesetenv.c
+++ b/sysdeps/i386/fpu/fesetenv.c
@@ -18,12 +18,18 @@
<http://www.gnu.org/licenses/>. */
#include <fenv.h>
+#include <fpu_control.h>
#include <assert.h>
#include <unistd.h>
#include <ldsodefs.h>
#include <dl-procinfo.h>
+/* All exceptions, including the x86-specific "denormal operand"
+ exception. */
+#define FE_ALL_EXCEPT_X86 (FE_ALL_EXCEPT | __FE_DENORM)
+
+
int
__fesetenv (const fenv_t *envp)
{
@@ -40,22 +46,30 @@ __fesetenv (const fenv_t *envp)
if (envp == FE_DFL_ENV)
{
- temp.__control_word |= FE_ALL_EXCEPT;
+ temp.__control_word |= FE_ALL_EXCEPT_X86;
temp.__control_word &= ~FE_TOWARDZERO;
- temp.__status_word &= ~FE_ALL_EXCEPT;
+ temp.__control_word |= _FPU_EXTENDED;
+ temp.__status_word &= ~FE_ALL_EXCEPT_X86;
}
else if (envp == FE_NOMASK_ENV)
{
temp.__control_word &= ~(FE_ALL_EXCEPT | FE_TOWARDZERO);
- temp.__status_word &= ~FE_ALL_EXCEPT;
+ /* Keep the "denormal operand" exception masked. */
+ temp.__control_word |= __FE_DENORM;
+ temp.__control_word |= _FPU_EXTENDED;
+ temp.__status_word &= ~FE_ALL_EXCEPT_X86;
}
else
{
- temp.__control_word &= ~(FE_ALL_EXCEPT | FE_TOWARDZERO);
+ temp.__control_word &= ~(FE_ALL_EXCEPT_X86
+ | FE_TOWARDZERO
+ | _FPU_EXTENDED);
temp.__control_word |= (envp->__control_word
- & (FE_ALL_EXCEPT | FE_TOWARDZERO));
- temp.__status_word &= ~FE_ALL_EXCEPT;
- temp.__status_word |= envp->__status_word & FE_ALL_EXCEPT;
+ & (FE_ALL_EXCEPT_X86
+ | FE_TOWARDZERO
+ | _FPU_EXTENDED));
+ temp.__status_word &= ~FE_ALL_EXCEPT_X86;
+ temp.__status_word |= envp->__status_word & FE_ALL_EXCEPT_X86;
}
temp.__eip = 0;
temp.__cs_selector = 0;
@@ -73,22 +87,28 @@ __fesetenv (const fenv_t *envp)
if (envp == FE_DFL_ENV)
{
/* Clear SSE exceptions. */
- mxcsr &= ~FE_ALL_EXCEPT;
+ mxcsr &= ~FE_ALL_EXCEPT_X86;
/* Set mask for SSE MXCSR. */
- mxcsr |= (FE_ALL_EXCEPT << 7);
+ mxcsr |= (FE_ALL_EXCEPT_X86 << 7);
/* Set rounding to FE_TONEAREST. */
mxcsr &= ~0x6000;
mxcsr |= (FE_TONEAREST << 3);
+ /* Clear the FZ and DAZ bits. */
+ mxcsr &= ~0x8040;
}
else if (envp == FE_NOMASK_ENV)
{
/* Clear SSE exceptions. */
- mxcsr &= ~FE_ALL_EXCEPT;
+ mxcsr &= ~FE_ALL_EXCEPT_X86;
/* Do not mask exceptions. */
mxcsr &= ~(FE_ALL_EXCEPT << 7);
+ /* Keep the "denormal operand" exception masked. */
+ mxcsr |= (__FE_DENORM << 7);
/* Set rounding to FE_TONEAREST. */
mxcsr &= ~0x6000;
mxcsr |= (FE_TONEAREST << 3);
+ /* Clear the FZ and DAZ bits. */
+ mxcsr &= ~0x8040;
}
else
mxcsr = envp->__eip;
diff --git a/sysdeps/x86/fpu/Makefile b/sysdeps/x86/fpu/Makefile
index d38497c..b561995 100644
--- a/sysdeps/x86/fpu/Makefile
+++ b/sysdeps/x86/fpu/Makefile
@@ -1,6 +1,7 @@
ifeq ($(subdir),math)
libm-support += powl_helper
-tests += test-fenv-sse test-fenv-clear-sse
+tests += test-fenv-sse test-fenv-clear-sse test-fenv-x87 test-fenv-sse-2
CFLAGS-test-fenv-sse.c += -msse2 -mfpmath=sse
CFLAGS-test-fenv-clear-sse.c += -msse2 -mfpmath=sse
+CFLAGS-test-fenv-sse-2.c += -msse2 -mfpmath=sse
endif
diff --git a/sysdeps/x86/fpu/test-fenv-sse-2.c b/sysdeps/x86/fpu/test-fenv-sse-2.c
new file mode 100644
index 0000000..12946e6
--- /dev/null
+++ b/sysdeps/x86/fpu/test-fenv-sse-2.c
@@ -0,0 +1,176 @@
+/* Test x86-specific floating-point environment (bug 16068): SSE part.
+ Copyright (C) 2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <cpuid.h>
+#include <fenv.h>
+#include <float.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+
+static bool
+have_sse2 (void)
+{
+ unsigned int eax, ebx, ecx, edx;
+
+ if (!__get_cpuid (1, &eax, &ebx, &ecx, &edx))
+ return false;
+
+ return (edx & bit_SSE2) != 0;
+}
+
+static uint32_t
+get_sse_mxcsr (void)
+{
+ uint32_t temp;
+ __asm__ __volatile__ ("stmxcsr %0" : "=m" (temp));
+ return temp;
+}
+
+static void
+set_sse_mxcsr (uint32_t val)
+{
+ __asm__ __volatile__ ("ldmxcsr %0" : : "m" (val));
+}
+
+static void
+set_sse_mxcsr_bits (uint32_t mask, uint32_t bits)
+{
+ uint32_t mxcsr = get_sse_mxcsr ();
+ mxcsr = (mxcsr & ~mask) | bits;
+ set_sse_mxcsr (mxcsr);
+}
+
+static int
+test_sse_mxcsr_bits (const char *test, uint32_t mask, uint32_t bits)
+{
+ uint32_t mxcsr = get_sse_mxcsr ();
+ printf ("Testing %s: mxcsr = %x\n", test, mxcsr);
+ if ((mxcsr & mask) == bits)
+ {
+ printf ("PASS: %s\n", test);
+ return 0;
+ }
+ else
+ {
+ printf ("FAIL: %s\n", test);
+ return 1;
+ }
+}
+
+#define MXCSR_FZ 0x8000
+#define MXCSR_DAZ 0x40
+#define MXCSR_DE 0x2
+#define MXCSR_DM 0x100
+
+static __attribute__ ((noinline)) int
+sse_tests (void)
+{
+ int result = 0;
+ fenv_t env1, env2;
+ /* Test FZ bit. */
+ fegetenv (&env1);
+ set_sse_mxcsr_bits (MXCSR_FZ, MXCSR_FZ);
+ fegetenv (&env2);
+ fesetenv (&env1);
+ result |= test_sse_mxcsr_bits ("fesetenv FZ restoration",
+ MXCSR_FZ, 0);
+ set_sse_mxcsr_bits (MXCSR_FZ, 0);
+ fesetenv (&env2);
+ result |= test_sse_mxcsr_bits ("fesetenv FZ restoration 2",
+ MXCSR_FZ, MXCSR_FZ);
+ set_sse_mxcsr_bits (MXCSR_FZ, MXCSR_FZ);
+ fesetenv (FE_NOMASK_ENV);
+ result |= test_sse_mxcsr_bits ("fesetenv (FE_NOMASK_ENV) FZ restoration",
+ MXCSR_FZ, 0);
+ set_sse_mxcsr_bits (MXCSR_FZ, MXCSR_FZ);
+ fesetenv (FE_DFL_ENV);
+ result |= test_sse_mxcsr_bits ("fesetenv (FE_DFL_ENV) FZ restoration",
+ MXCSR_FZ, 0);
+ /* Test DAZ bit. */
+ set_sse_mxcsr_bits (MXCSR_DAZ, MXCSR_DAZ);
+ fegetenv (&env2);
+ fesetenv (&env1);
+ result |= test_sse_mxcsr_bits ("fesetenv DAZ restoration",
+ MXCSR_DAZ, 0);
+ set_sse_mxcsr_bits (MXCSR_DAZ, 0);
+ fesetenv (&env2);
+ result |= test_sse_mxcsr_bits ("fesetenv DAZ restoration 2",
+ MXCSR_DAZ, MXCSR_DAZ);
+ set_sse_mxcsr_bits (MXCSR_DAZ, MXCSR_DAZ);
+ fesetenv (FE_NOMASK_ENV);
+ result |= test_sse_mxcsr_bits ("fesetenv (FE_NOMASK_ENV) DAZ restoration",
+ MXCSR_DAZ, 0);
+ set_sse_mxcsr_bits (MXCSR_DAZ, MXCSR_DAZ);
+ fesetenv (FE_DFL_ENV);
+ result |= test_sse_mxcsr_bits ("fesetenv (FE_DFL_ENV) DAZ restoration",
+ MXCSR_DAZ, 0);
+ /* Test DM bit. */
+ set_sse_mxcsr_bits (MXCSR_DM, 0);
+ fegetenv (&env2);
+ fesetenv (&env1);
+ result |= test_sse_mxcsr_bits ("fesetenv DM restoration",
+ MXCSR_DM, MXCSR_DM);
+ set_sse_mxcsr_bits (MXCSR_DM, MXCSR_DM);
+ fesetenv (&env2);
+ result |= test_sse_mxcsr_bits ("fesetenv DM restoration 2",
+ MXCSR_DM, 0);
+ set_sse_mxcsr_bits (MXCSR_DM, 0);
+ /* Presume FE_NOMASK_ENV should leave the "denormal operand"
+ exception masked, as not a standard exception. */
+ fesetenv (FE_NOMASK_ENV);
+ result |= test_sse_mxcsr_bits ("fesetenv (FE_NOMASK_ENV) DM restoration",
+ MXCSR_DM, MXCSR_DM);
+ set_sse_mxcsr_bits (MXCSR_DM, 0);
+ fesetenv (FE_DFL_ENV);
+ result |= test_sse_mxcsr_bits ("fesetenv (FE_DFL_ENV) DM restoration",
+ MXCSR_DM, MXCSR_DM);
+ /* Test DE bit. */
+ set_sse_mxcsr_bits (MXCSR_DE, MXCSR_DE);
+ fegetenv (&env2);
+ fesetenv (&env1);
+ result |= test_sse_mxcsr_bits ("fesetenv DE restoration",
+ MXCSR_DE, 0);
+ set_sse_mxcsr_bits (MXCSR_DE, 0);
+ fesetenv (&env2);
+ result |= test_sse_mxcsr_bits ("fesetenv DE restoration 2",
+ MXCSR_DE, MXCSR_DE);
+ set_sse_mxcsr_bits (MXCSR_DE, MXCSR_DE);
+ fesetenv (FE_NOMASK_ENV);
+ result |= test_sse_mxcsr_bits ("fesetenv (FE_NOMASK_ENV) DE restoration",
+ MXCSR_DE, 0);
+ set_sse_mxcsr_bits (MXCSR_DE, MXCSR_DE);
+ fesetenv (FE_DFL_ENV);
+ result |= test_sse_mxcsr_bits ("fesetenv (FE_DFL_ENV) DE restoration",
+ MXCSR_DE, 0);
+ return result;
+}
+
+static int
+do_test (void)
+{
+ if (!have_sse2 ())
+ {
+ puts ("CPU does not support SSE2, cannot test");
+ return 0;
+ }
+ return sse_tests ();
+}
+
+#define TEST_FUNCTION do_test ()
+#include <test-skeleton.c>
diff --git a/sysdeps/x86/fpu/test-fenv-x87.c b/sysdeps/x86/fpu/test-fenv-x87.c
new file mode 100644
index 0000000..2f74471
--- /dev/null
+++ b/sysdeps/x86/fpu/test-fenv-x87.c
@@ -0,0 +1,169 @@
+/* Test x86-specific floating-point environment (bug 16068): x87 part.
+ Copyright (C) 2015 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <fenv.h>
+#include <float.h>
+#include <fpu_control.h>
+#include <stdint.h>
+#include <stdio.h>
+
+static uint16_t
+get_x87_cw (void)
+{
+ fpu_control_t cw;
+ _FPU_GETCW (cw);
+ return cw;
+}
+
+static void
+set_x87_cw (uint16_t val)
+{
+ fpu_control_t cw = val;
+ _FPU_SETCW (cw);
+}
+
+static void
+set_x87_cw_bits (uint16_t mask, uint16_t bits)
+{
+ uint16_t cw = get_x87_cw ();
+ cw = (cw & ~mask) | bits;
+ set_x87_cw (cw);
+}
+
+static int
+test_x87_cw_bits (const char *test, uint16_t mask, uint16_t bits)
+{
+ uint16_t cw = get_x87_cw ();
+ printf ("Testing %s: cw = %x\n", test, cw);
+ if ((cw & mask) == bits)
+ {
+ printf ("PASS: %s\n", test);
+ return 0;
+ }
+ else
+ {
+ printf ("FAIL: %s\n", test);
+ return 1;
+ }
+}
+
+static uint16_t
+get_x87_sw (void)
+{
+ uint16_t temp;
+ __asm__ __volatile__ ("fnstsw %0" : "=a" (temp));
+ return temp;
+}
+
+static void
+set_x87_sw_bits (uint16_t mask, uint16_t bits)
+{
+ fenv_t temp;
+ __asm__ __volatile__ ("fnstenv %0" : "=m" (temp));
+ temp.__status_word = (temp.__status_word & ~mask) | bits;
+ __asm__ __volatile__ ("fldenv %0" : : "m" (temp));
+}
+
+static int
+test_x87_sw_bits (const char *test, uint16_t mask, uint16_t bits)
+{
+ uint16_t sw = get_x87_sw ();
+ printf ("Testing %s: sw = %x\n", test, sw);
+ if ((sw & mask) == bits)
+ {
+ printf ("PASS: %s\n", test);
+ return 0;
+ }
+ else
+ {
+ printf ("FAIL: %s\n", test);
+ return 1;
+ }
+}
+
+#define X87_CW_PREC_MASK _FPU_EXTENDED
+
+static int
+do_test (void)
+{
+ int result = 0;
+ fenv_t env1, env2;
+ /* Test precision mask. */
+ fegetenv (&env1);
+ set_x87_cw_bits (X87_CW_PREC_MASK, _FPU_SINGLE);
+ fegetenv (&env2);
+ fesetenv (&env1);
+ result |= test_x87_cw_bits ("fesetenv precision restoration",
+ X87_CW_PREC_MASK, _FPU_EXTENDED);
+ set_x87_cw_bits (X87_CW_PREC_MASK, _FPU_EXTENDED);
+ fesetenv (&env2);
+ result |= test_x87_cw_bits ("fesetenv precision restoration 2",
+ X87_CW_PREC_MASK, _FPU_SINGLE);
+ set_x87_cw_bits (X87_CW_PREC_MASK, _FPU_DOUBLE);
+ fesetenv (FE_NOMASK_ENV);
+ result |= test_x87_cw_bits ("fesetenv (FE_NOMASK_ENV) precision restoration",
+ X87_CW_PREC_MASK, _FPU_EXTENDED);
+ set_x87_cw_bits (X87_CW_PREC_MASK, _FPU_SINGLE);
+ fesetenv (FE_DFL_ENV);
+ result |= test_x87_cw_bits ("fesetenv (FE_DFL_ENV) precision restoration",
+ X87_CW_PREC_MASK, _FPU_EXTENDED);
+ /* Test x87 denormal operand masking. */
+ set_x87_cw_bits (_FPU_MASK_DM, 0);
+ fegetenv (&env2);
+ fesetenv (&env1);
+ result |= test_x87_cw_bits ("fesetenv denormal mask restoration",
+ _FPU_MASK_DM, _FPU_MASK_DM);
+ set_x87_cw_bits (_FPU_MASK_DM, _FPU_MASK_DM);
+ fesetenv (&env2);
+ result |= test_x87_cw_bits ("fesetenv denormal mask restoration 2",
+ _FPU_MASK_DM, 0);
+ set_x87_cw_bits (_FPU_MASK_DM, 0);
+ /* Presume FE_NOMASK_ENV should leave the "denormal operand"
+ exception masked, as not a standard exception. */
+ fesetenv (FE_NOMASK_ENV);
+ result |= test_x87_cw_bits ("fesetenv (FE_NOMASK_ENV) denormal mask "
+ "restoration",
+ _FPU_MASK_DM, _FPU_MASK_DM);
+ set_x87_cw_bits (_FPU_MASK_DM, 0);
+ fesetenv (FE_DFL_ENV);
+ result |= test_x87_cw_bits ("fesetenv (FE_DFL_ENV) denormal mask "
+ "restoration",
+ _FPU_MASK_DM, _FPU_MASK_DM);
+ /* Test x87 denormal operand exception. */
+ set_x87_sw_bits (__FE_DENORM, __FE_DENORM);
+ fegetenv (&env2);
+ fesetenv (&env1);
+ result |= test_x87_sw_bits ("fesetenv denormal exception restoration",
+ __FE_DENORM, 0);
+ set_x87_sw_bits (__FE_DENORM, 0);
+ fesetenv (&env2);
+ result |= test_x87_sw_bits ("fesetenv denormal exception restoration 2",
+ __FE_DENORM, __FE_DENORM);
+ set_x87_sw_bits (__FE_DENORM, __FE_DENORM);
+ fesetenv (FE_NOMASK_ENV);
+ result |= test_x87_sw_bits ("fesetenv (FE_NOMASK_ENV) exception restoration",
+ __FE_DENORM, 0);
+ set_x87_sw_bits (__FE_DENORM, __FE_DENORM);
+ fesetenv (FE_DFL_ENV);
+ result |= test_x87_sw_bits ("fesetenv (FE_DFL_ENV) exception restoration",
+ __FE_DENORM, 0);
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include <test-skeleton.c>
diff --git a/sysdeps/x86_64/fpu/fesetenv.c b/sysdeps/x86_64/fpu/fesetenv.c
index 9950aa7..381540f 100644
--- a/sysdeps/x86_64/fpu/fesetenv.c
+++ b/sysdeps/x86_64/fpu/fesetenv.c
@@ -17,9 +17,15 @@
<http://www.gnu.org/licenses/>. */
#include <fenv.h>
+#include <fpu_control.h>
#include <assert.h>
+/* All exceptions, including the x86-specific "denormal operand"
+ exception. */
+#define FE_ALL_EXCEPT_X86 (FE_ALL_EXCEPT | __FE_DENORM)
+
+
int
__fesetenv (const fenv_t *envp)
{
@@ -34,47 +40,61 @@ __fesetenv (const fenv_t *envp)
if (envp == FE_DFL_ENV)
{
- temp.__control_word |= FE_ALL_EXCEPT;
+ temp.__control_word |= FE_ALL_EXCEPT_X86;
temp.__control_word &= ~FE_TOWARDZERO;
- temp.__status_word &= ~FE_ALL_EXCEPT;
+ temp.__control_word |= _FPU_EXTENDED;
+ temp.__status_word &= ~FE_ALL_EXCEPT_X86;
temp.__eip = 0;
temp.__cs_selector = 0;
temp.__opcode = 0;
temp.__data_offset = 0;
temp.__data_selector = 0;
/* Clear SSE exceptions. */
- temp.__mxcsr &= ~FE_ALL_EXCEPT;
+ temp.__mxcsr &= ~FE_ALL_EXCEPT_X86;
/* Set mask for SSE MXCSR. */
- temp.__mxcsr |= (FE_ALL_EXCEPT << 7);
+ temp.__mxcsr |= (FE_ALL_EXCEPT_X86 << 7);
/* Set rounding to FE_TONEAREST. */
temp.__mxcsr &= ~ 0x6000;
temp.__mxcsr |= (FE_TONEAREST << 3);
+ /* Clear the FZ and DAZ bits. */
+ temp.__mxcsr &= ~0x8040;
}
else if (envp == FE_NOMASK_ENV)
{
temp.__control_word &= ~(FE_ALL_EXCEPT | FE_TOWARDZERO);
- temp.__status_word &= ~FE_ALL_EXCEPT;
+ /* Keep the "denormal operand" exception masked. */
+ temp.__control_word |= __FE_DENORM;
+ temp.__control_word |= _FPU_EXTENDED;
+ temp.__status_word &= ~FE_ALL_EXCEPT_X86;
temp.__eip = 0;
temp.__cs_selector = 0;
temp.__opcode = 0;
temp.__data_offset = 0;
temp.__data_selector = 0;
/* Clear SSE exceptions. */
- temp.__mxcsr &= ~FE_ALL_EXCEPT;
+ temp.__mxcsr &= ~FE_ALL_EXCEPT_X86;
/* Set mask for SSE MXCSR. */
/* Set rounding to FE_TONEAREST. */
temp.__mxcsr &= ~ 0x6000;
temp.__mxcsr |= (FE_TONEAREST << 3);
/* Do not mask exceptions. */
temp.__mxcsr &= ~(FE_ALL_EXCEPT << 7);
+ /* Keep the "denormal operand" exception masked. */
+ temp.__mxcsr |= (__FE_DENORM << 7);
+ /* Clear the FZ and DAZ bits. */
+ temp.__mxcsr &= ~0x8040;
}
else
{
- temp.__control_word &= ~(FE_ALL_EXCEPT | FE_TOWARDZERO);
+ temp.__control_word &= ~(FE_ALL_EXCEPT_X86
+ | FE_TOWARDZERO
+ | _FPU_EXTENDED);
temp.__control_word |= (envp->__control_word
- & (FE_ALL_EXCEPT | FE_TOWARDZERO));
- temp.__status_word &= ~FE_ALL_EXCEPT;
- temp.__status_word |= envp->__status_word & FE_ALL_EXCEPT;
+ & (FE_ALL_EXCEPT_X86
+ | FE_TOWARDZERO
+ | _FPU_EXTENDED));
+ temp.__status_word &= ~FE_ALL_EXCEPT_X86;
+ temp.__status_word |= envp->__status_word & FE_ALL_EXCEPT_X86;
temp.__eip = envp->__eip;
temp.__cs_selector = envp->__cs_selector;
temp.__opcode = envp->__opcode;