diff options
-rw-r--r-- | ChangeLog | 19 | ||||
-rw-r--r-- | NEWS | 24 | ||||
-rw-r--r-- | sysdeps/i386/fpu/fesetenv.c | 40 | ||||
-rw-r--r-- | sysdeps/x86/fpu/Makefile | 3 | ||||
-rw-r--r-- | sysdeps/x86/fpu/test-fenv-sse-2.c | 176 | ||||
-rw-r--r-- | sysdeps/x86/fpu/test-fenv-x87.c | 169 | ||||
-rw-r--r-- | sysdeps/x86_64/fpu/fesetenv.c | 40 |
7 files changed, 438 insertions, 33 deletions
diff --git a/ChangeLog b/ChangeLog index 52cd9f3977..9ef00a7a32 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 9b343917f5..0831d35881 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 910aa0991c..f3b9cefee5 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 d38497cff3..b561995658 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 0000000000..12946e63ce --- /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 0000000000..2f74471eac --- /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 9950aa734a..381540f687 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; |