Corinna Vinschen
2018-08-15 16:03:01 UTC
https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=4c4c19f54865daac0b5d0343d8154910a7d79553
commit 4c4c19f54865daac0b5d0343d8154910a7d79553
Author: J.H. van de Water <***@xs4all.nl>
Date: Wed Aug 15 12:59:23 2018 +0200
Keep the denormal-operand exception masked; modify FE_ALL_EXCEPT accordingly.
By excluding the denormal-operand exception from FE_ALL_EXCEPT, it will not
be possible anymore to UNmask this exception by means of the API defined by
/usr/include/fenv.h
Note: terminology has changed since IEEE Std 854-1987; denormalized numbers
are called subnormal numbers nowadays.
This modification has basically been motivated by the fact that it is also
not possible on Linux to manipulate the denormal-operand exception by means
of the interface as defined by /usr/include/fenv.h. This has been the state
of affairs on Linux since 2001 (Andreas Jaeger).
The exceptions required by the standard (IEEE Std 754), in case they can be
supported by the implementation, are:
FE_INEXACT, FE_UNDERFLOW, FE_OVERFLOW, FE_DIVBYZERO and FE_INVALID.
Although it is allowed to define additional exceptions, there is no reason
to support the "denormal-operand exception" in this case (fenv.h), because
the subnormal numbers can be handled almost as fast the normalized numbers
by the hardware of the x86/x86_64 architecture. Said differently, a reason
to trap on the input of subnormal numbers does not exist. At least that is
what William Kahan and others at Intel asserted around 2000.
(that is William Kahan of the K-C-S draft, the precursor to the standard)
This commit modifies winsup/cygwin/include/fenv.h as follows:
- redefines FE_ALL_EXCEPT from 0x3f to 0x3d
- removes the definition for FE_DENORMAL
- introduces __FE_DENORM (0x2) (enum in Linux also uses __FE_DENORM)
- introduces FE_ALL_EXCEPT_X86 (0x3f), i.e. ALL x86/x86_64 FP exceptions
Diff:
---
winsup/cygwin/fenv.cc | 13 ++++++++++---
winsup/cygwin/include/fenv.h | 9 +++------
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/winsup/cygwin/fenv.cc b/winsup/cygwin/fenv.cc
index 066704b..3adc8a9 100644
--- a/winsup/cygwin/fenv.cc
+++ b/winsup/cygwin/fenv.cc
@@ -12,6 +12,11 @@ details. */
#include "wincap.h"
#include <string.h>
+/* x87 supports subnormal numbers so we need it below. */
+#define __FE_DENORM (1 << 1)
+/* mask (= 0x3f) to disable all exceptions at initialization */
+#define __FE_ALL_EXCEPT_X86 (FE_ALL_EXCEPT | __FE_DENORM)
+
/* Mask and shift amount for rounding bits. */
#define FE_CW_ROUND_MASK (0x0c00)
#define FE_CW_ROUND_SHIFT (10)
@@ -417,7 +422,7 @@ fesetprec (int prec)
void
_feinitialise (void)
{
- unsigned int edx, eax, mxcsr;
+ unsigned int edx, eax;
/* Check for presence of SSE: invoke CPUID #1, check EDX bit 25. */
eax = 1;
@@ -431,11 +436,13 @@ _feinitialise (void)
/* The default cw value, 0x37f, is rounding mode zero. The MXCSR has
no precision control, so the only thing to do is set the exception
mask bits. */
- mxcsr = FE_ALL_EXCEPT << FE_SSE_EXCEPT_MASK_SHIFT;
+
+ /* initialize the MXCSR register: mask all exceptions */
+ unsigned int mxcsr = __FE_ALL_EXCEPT_X86 << FE_SSE_EXCEPT_MASK_SHIFT;
if (use_sse)
__asm__ volatile ("ldmxcsr %0" :: "m" (mxcsr));
- /* Setup unmasked environment. */
+ /* Setup unmasked environment, but leave __FE_DENORM masked. */
feenableexcept (FE_ALL_EXCEPT);
fegetenv (&fe_nomask_env);
diff --git a/winsup/cygwin/include/fenv.h b/winsup/cygwin/include/fenv.h
index 7ec5d4d..7ce3a93 100644
--- a/winsup/cygwin/include/fenv.h
+++ b/winsup/cygwin/include/fenv.h
@@ -87,16 +87,13 @@ typedef __uint32_t fexcept_t;
#define FE_OVERFLOW (1 << 3)
#define FE_UNDERFLOW (1 << 4)
-/* This is not defined by Posix, but since x87 supports it we provide
- a definition according to the same naming scheme used above. */
-#define FE_DENORMAL (1 << 1)
-
/* The <fenv.h> header shall define the following constant, which is
simply the bitwise-inclusive OR of all floating-point exception
constants defined above: */
-#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID \
- | FE_OVERFLOW | FE_UNDERFLOW | FE_DENORMAL)
+/* in agreement w/ Linux the subnormal exception will always be masked */
+#define FE_ALL_EXCEPT \
+ (FE_INEXACT | FE_UNDERFLOW | FE_OVERFLOW | FE_DIVBYZERO | FE_INVALID)
/* The <fenv.h> header shall define the following constants if and only
if the implementation supports getting and setting the represented
commit 4c4c19f54865daac0b5d0343d8154910a7d79553
Author: J.H. van de Water <***@xs4all.nl>
Date: Wed Aug 15 12:59:23 2018 +0200
Keep the denormal-operand exception masked; modify FE_ALL_EXCEPT accordingly.
By excluding the denormal-operand exception from FE_ALL_EXCEPT, it will not
be possible anymore to UNmask this exception by means of the API defined by
/usr/include/fenv.h
Note: terminology has changed since IEEE Std 854-1987; denormalized numbers
are called subnormal numbers nowadays.
This modification has basically been motivated by the fact that it is also
not possible on Linux to manipulate the denormal-operand exception by means
of the interface as defined by /usr/include/fenv.h. This has been the state
of affairs on Linux since 2001 (Andreas Jaeger).
The exceptions required by the standard (IEEE Std 754), in case they can be
supported by the implementation, are:
FE_INEXACT, FE_UNDERFLOW, FE_OVERFLOW, FE_DIVBYZERO and FE_INVALID.
Although it is allowed to define additional exceptions, there is no reason
to support the "denormal-operand exception" in this case (fenv.h), because
the subnormal numbers can be handled almost as fast the normalized numbers
by the hardware of the x86/x86_64 architecture. Said differently, a reason
to trap on the input of subnormal numbers does not exist. At least that is
what William Kahan and others at Intel asserted around 2000.
(that is William Kahan of the K-C-S draft, the precursor to the standard)
This commit modifies winsup/cygwin/include/fenv.h as follows:
- redefines FE_ALL_EXCEPT from 0x3f to 0x3d
- removes the definition for FE_DENORMAL
- introduces __FE_DENORM (0x2) (enum in Linux also uses __FE_DENORM)
- introduces FE_ALL_EXCEPT_X86 (0x3f), i.e. ALL x86/x86_64 FP exceptions
Diff:
---
winsup/cygwin/fenv.cc | 13 ++++++++++---
winsup/cygwin/include/fenv.h | 9 +++------
2 files changed, 13 insertions(+), 9 deletions(-)
diff --git a/winsup/cygwin/fenv.cc b/winsup/cygwin/fenv.cc
index 066704b..3adc8a9 100644
--- a/winsup/cygwin/fenv.cc
+++ b/winsup/cygwin/fenv.cc
@@ -12,6 +12,11 @@ details. */
#include "wincap.h"
#include <string.h>
+/* x87 supports subnormal numbers so we need it below. */
+#define __FE_DENORM (1 << 1)
+/* mask (= 0x3f) to disable all exceptions at initialization */
+#define __FE_ALL_EXCEPT_X86 (FE_ALL_EXCEPT | __FE_DENORM)
+
/* Mask and shift amount for rounding bits. */
#define FE_CW_ROUND_MASK (0x0c00)
#define FE_CW_ROUND_SHIFT (10)
@@ -417,7 +422,7 @@ fesetprec (int prec)
void
_feinitialise (void)
{
- unsigned int edx, eax, mxcsr;
+ unsigned int edx, eax;
/* Check for presence of SSE: invoke CPUID #1, check EDX bit 25. */
eax = 1;
@@ -431,11 +436,13 @@ _feinitialise (void)
/* The default cw value, 0x37f, is rounding mode zero. The MXCSR has
no precision control, so the only thing to do is set the exception
mask bits. */
- mxcsr = FE_ALL_EXCEPT << FE_SSE_EXCEPT_MASK_SHIFT;
+
+ /* initialize the MXCSR register: mask all exceptions */
+ unsigned int mxcsr = __FE_ALL_EXCEPT_X86 << FE_SSE_EXCEPT_MASK_SHIFT;
if (use_sse)
__asm__ volatile ("ldmxcsr %0" :: "m" (mxcsr));
- /* Setup unmasked environment. */
+ /* Setup unmasked environment, but leave __FE_DENORM masked. */
feenableexcept (FE_ALL_EXCEPT);
fegetenv (&fe_nomask_env);
diff --git a/winsup/cygwin/include/fenv.h b/winsup/cygwin/include/fenv.h
index 7ec5d4d..7ce3a93 100644
--- a/winsup/cygwin/include/fenv.h
+++ b/winsup/cygwin/include/fenv.h
@@ -87,16 +87,13 @@ typedef __uint32_t fexcept_t;
#define FE_OVERFLOW (1 << 3)
#define FE_UNDERFLOW (1 << 4)
-/* This is not defined by Posix, but since x87 supports it we provide
- a definition according to the same naming scheme used above. */
-#define FE_DENORMAL (1 << 1)
-
/* The <fenv.h> header shall define the following constant, which is
simply the bitwise-inclusive OR of all floating-point exception
constants defined above: */
-#define FE_ALL_EXCEPT (FE_DIVBYZERO | FE_INEXACT | FE_INVALID \
- | FE_OVERFLOW | FE_UNDERFLOW | FE_DENORMAL)
+/* in agreement w/ Linux the subnormal exception will always be masked */
+#define FE_ALL_EXCEPT \
+ (FE_INEXACT | FE_UNDERFLOW | FE_OVERFLOW | FE_DIVBYZERO | FE_INVALID)
/* The <fenv.h> header shall define the following constants if and only
if the implementation supports getting and setting the represented