winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
/* fenv.cc
|
|
|
|
|
|
|
|
This file is part of Cygwin.
|
|
|
|
|
|
|
|
This software is a copyrighted work licensed under the terms of the
|
|
|
|
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
|
|
|
details. */
|
|
|
|
|
2011-03-20 16:34:29 +01:00
|
|
|
#include "winsup.h"
|
winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
#include "fenv.h"
|
|
|
|
#include "errno.h"
|
2011-03-20 16:34:29 +01:00
|
|
|
#include "wincap.h"
|
|
|
|
#include <string.h>
|
winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
|
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
2018-08-15 12:59:23 +02:00
|
|
|
/* 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)
|
|
|
|
|
winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
/* Mask and shift amount for rounding bits. */
|
|
|
|
#define FE_CW_ROUND_MASK (0x0c00)
|
|
|
|
#define FE_CW_ROUND_SHIFT (10)
|
|
|
|
/* Same, for SSE MXCSR. */
|
|
|
|
#define FE_MXCSR_ROUND_MASK (0x6000)
|
|
|
|
#define FE_MXCSR_ROUND_SHIFT (13)
|
|
|
|
|
|
|
|
/* Mask and shift amount for precision bits. */
|
|
|
|
#define FE_CW_PREC_MASK (0x0300)
|
|
|
|
#define FE_CW_PREC_SHIFT (8)
|
|
|
|
|
|
|
|
/* In x87, exception status bits and mask bits occupy
|
|
|
|
corresponding bit positions in the status and control
|
|
|
|
registers, respectively. In SSE, they are both located
|
|
|
|
in the control-and-status register, with the status bits
|
|
|
|
corresponding to the x87 positions, and the mask bits
|
|
|
|
shifted by this amount to the left. */
|
|
|
|
#define FE_SSE_EXCEPT_MASK_SHIFT (7)
|
|
|
|
|
|
|
|
/* These are writable so we can initialise them at startup. */
|
|
|
|
static fenv_t fe_dfl_env;
|
|
|
|
static fenv_t fe_nomask_env;
|
|
|
|
|
|
|
|
/* These pointers provide the outside world with read-only access to them. */
|
|
|
|
const fenv_t *_fe_dfl_env = &fe_dfl_env;
|
|
|
|
const fenv_t *_fe_nomask_env = &fe_nomask_env;
|
|
|
|
|
|
|
|
/* Although Cygwin assumes i686 or above (hence SSE available) these
|
|
|
|
days, and the compiler feels free to use it (depending on compile-
|
|
|
|
time flags of course), we should avoid needlessly breaking any
|
|
|
|
purely integer mode apps (or apps compiled with -mno-sse), so we
|
|
|
|
only manage SSE state in this fenv module if we detect that SSE
|
|
|
|
instructions are available at runtime. If we didn't do this, all
|
|
|
|
applications run on older machines would bomb out with an invalid
|
|
|
|
instruction exception right at startup; let's not be *that* WJM! */
|
|
|
|
static bool use_sse = false;
|
|
|
|
|
|
|
|
/* This function enables traps for each of the exceptions as indicated
|
|
|
|
by the parameter except. The individual exceptions are described in
|
|
|
|
[ ... glibc manual xref elided ...]. Only the specified exceptions are
|
|
|
|
enabled, the status of the other exceptions is not changed.
|
|
|
|
The function returns the previous enabled exceptions in case the
|
|
|
|
operation was successful, -1 otherwise. */
|
|
|
|
int
|
|
|
|
feenableexcept (int excepts)
|
|
|
|
{
|
|
|
|
unsigned short cw, old_cw;
|
|
|
|
unsigned int mxcsr = 0;
|
|
|
|
|
|
|
|
if (excepts & ~FE_ALL_EXCEPT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Get control words. */
|
|
|
|
__asm__ volatile ("fnstcw %0" : "=m" (old_cw) : );
|
|
|
|
if (use_sse)
|
|
|
|
__asm__ volatile ("stmxcsr %0" : "=m" (mxcsr) : );
|
|
|
|
|
|
|
|
/* Enable exceptions by clearing mask bits. */
|
|
|
|
cw = old_cw & ~excepts;
|
|
|
|
mxcsr &= ~(excepts << FE_SSE_EXCEPT_MASK_SHIFT);
|
|
|
|
|
|
|
|
/* Store updated control words. */
|
|
|
|
__asm__ volatile ("fldcw %0" :: "m" (cw));
|
|
|
|
if (use_sse)
|
|
|
|
__asm__ volatile ("ldmxcsr %0" :: "m" (mxcsr));
|
|
|
|
|
|
|
|
/* Return old value. We assume SSE and x87 stay in sync. Note that
|
|
|
|
we are returning a mask of enabled exceptions, which is the opposite
|
|
|
|
of the flags in the register, which are set to disable (mask) their
|
|
|
|
related exceptions. */
|
|
|
|
return (~old_cw) & FE_ALL_EXCEPT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function disables traps for each of the exceptions as indicated
|
|
|
|
by the parameter except. The individual exceptions are described in
|
|
|
|
[ ... glibc manual xref elided ...]. Only the specified exceptions are
|
|
|
|
disabled, the status of the other exceptions is not changed.
|
|
|
|
The function returns the previous enabled exceptions in case the
|
|
|
|
operation was successful, -1 otherwise. */
|
|
|
|
int
|
|
|
|
fedisableexcept (int excepts)
|
|
|
|
{
|
|
|
|
unsigned short cw, old_cw;
|
|
|
|
unsigned int mxcsr = 0;
|
|
|
|
|
|
|
|
if (excepts & ~FE_ALL_EXCEPT)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* Get control words. */
|
|
|
|
__asm__ volatile ("fnstcw %0" : "=m" (old_cw) : );
|
|
|
|
if (use_sse)
|
|
|
|
__asm__ volatile ("stmxcsr %0" : "=m" (mxcsr) : );
|
|
|
|
|
|
|
|
/* Disable exceptions by setting mask bits. */
|
|
|
|
cw = old_cw | excepts;
|
|
|
|
mxcsr |= (excepts << FE_SSE_EXCEPT_MASK_SHIFT);
|
|
|
|
|
|
|
|
/* Store updated control words. */
|
|
|
|
__asm__ volatile ("fldcw %0" :: "m" (cw));
|
|
|
|
if (use_sse)
|
|
|
|
__asm__ volatile ("ldmxcsr %0" :: "m" (mxcsr));
|
|
|
|
|
|
|
|
/* Return old value. We assume SSE and x87 stay in sync. Note that
|
|
|
|
we are returning a mask of enabled exceptions, which is the opposite
|
|
|
|
of the flags in the register, which are set to disable (mask) their
|
|
|
|
related exceptions. */
|
|
|
|
return (~old_cw) & FE_ALL_EXCEPT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function returns a bitmask of all currently enabled exceptions. It
|
|
|
|
returns -1 in case of failure. */
|
|
|
|
int
|
|
|
|
fegetexcept (void)
|
|
|
|
{
|
|
|
|
unsigned short cw;
|
|
|
|
|
|
|
|
/* Get control word. We assume SSE and x87 stay in sync. */
|
|
|
|
__asm__ volatile ("fnstcw %0" : "=m" (cw) : );
|
|
|
|
|
|
|
|
/* Exception is *dis*abled when mask bit is set. */
|
|
|
|
return (~cw) & FE_ALL_EXCEPT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Store the floating-point environment in the variable pointed to by envp.
|
|
|
|
The function returns zero in case the operation was successful, a non-zero
|
|
|
|
value otherwise. */
|
|
|
|
int
|
|
|
|
fegetenv (fenv_t *envp)
|
|
|
|
{
|
Cygwin: fegetenv() should not disable exceptions
fnstenv MUST be followed by fldenv in fegetenv(), as the former disables all
exceptions in the x87 FPU, which is not appropriate here (fegetenv() ).
fldenv after fnstenv should reload the x87 FPU w/ the configuration that was
saved by fnstenv, i.e. a configuration that might have exceptions enabled.
Note: x86_64 uses SSE for floating-point, not the x87 FPU. However, because
feraiseexcept() attempts to provoke an exception using the x87 FPU, the bug
in fegetenv() will make this attempt futile here (x86_64).
Note: WoW uses the x87 FPU for floating-point, not SSE. Here anything that
would normally result in triggering an exception, not only feraiseexcept(),
will not be able to, as result of the bug in fegetenv().
2018-08-03 01:45:12 +02:00
|
|
|
/* fnstenv disables all exceptions in the x87 FPU; as this is not what is
|
|
|
|
desired here, reload the cfg saved from the x87 FPU, back to the FPU */
|
|
|
|
__asm__ volatile ("fnstenv %0\n\
|
|
|
|
fldenv %0"
|
|
|
|
: "=m" (envp->_fpu) : );
|
winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
if (use_sse)
|
|
|
|
__asm__ volatile ("stmxcsr %0" : "=m" (envp->_sse_mxcsr) : );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Store the current floating-point environment in the object pointed to
|
|
|
|
by envp. Then clear all exception flags, and set the FPU to trap no
|
|
|
|
exceptions. Not all FPUs support trapping no exceptions; if feholdexcept
|
|
|
|
cannot set this mode, it returns nonzero value. If it succeeds, it
|
|
|
|
returns zero. */
|
|
|
|
int
|
|
|
|
feholdexcept (fenv_t *envp)
|
|
|
|
{
|
|
|
|
unsigned int mxcsr;
|
|
|
|
fegetenv (envp);
|
|
|
|
mxcsr = envp->_sse_mxcsr & ~FE_ALL_EXCEPT;
|
|
|
|
if (use_sse)
|
|
|
|
__asm__ volatile ("ldmxcsr %0" :: "m" (mxcsr));
|
|
|
|
__asm__ volatile ("fnclex");
|
|
|
|
fedisableexcept (FE_ALL_EXCEPT);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set the floating-point environment to that described by envp. The
|
|
|
|
function returns zero in case the operation was successful, a non-zero
|
|
|
|
value otherwise. */
|
|
|
|
int
|
|
|
|
fesetenv (const fenv_t *envp)
|
|
|
|
{
|
|
|
|
__asm__ volatile ("fldenv %0" :: "m" (envp->_fpu) );
|
|
|
|
if (use_sse)
|
|
|
|
__asm__ volatile ("ldmxcsr %0" :: "m" (envp->_sse_mxcsr));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Like fesetenv, this function sets the floating-point environment to
|
|
|
|
that described by envp. However, if any exceptions were flagged in the
|
|
|
|
status word before feupdateenv was called, they remain flagged after
|
|
|
|
the call. In other words, after feupdateenv is called, the status
|
|
|
|
word is the bitwise OR of the previous status word and the one saved
|
|
|
|
in envp. The function returns zero in case the operation was successful,
|
|
|
|
a non-zero value otherwise. */
|
|
|
|
int
|
|
|
|
feupdateenv (const fenv_t *envp)
|
|
|
|
{
|
|
|
|
fenv_t envcopy;
|
|
|
|
unsigned int mxcsr = 0;
|
|
|
|
unsigned short sw;
|
|
|
|
|
|
|
|
/* Don't want to modify *envp, but want to update environment atomically,
|
|
|
|
so take a copy and merge the existing exceptions into it. */
|
|
|
|
memcpy (&envcopy, envp, sizeof *envp);
|
|
|
|
__asm__ volatile ("fnstsw %0" : "=m" (sw) : );
|
|
|
|
if (use_sse)
|
|
|
|
__asm__ volatile ("stmxcsr %0" : "=m" (mxcsr) : );
|
|
|
|
envcopy._fpu._fpu_sw |= (sw & FE_ALL_EXCEPT);
|
|
|
|
envcopy._sse_mxcsr |= (mxcsr & FE_ALL_EXCEPT);
|
|
|
|
|
|
|
|
return fesetenv (&envcopy);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function clears all of the supported exception flags indicated by
|
|
|
|
excepts. The function returns zero in case the operation was successful,
|
|
|
|
a non-zero value otherwise. */
|
|
|
|
int
|
|
|
|
feclearexcept (int excepts)
|
|
|
|
{
|
|
|
|
fenv_t fenv;
|
|
|
|
|
|
|
|
if (excepts & ~FE_ALL_EXCEPT)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
/* Need to save/restore whole environment to modify status word. */
|
|
|
|
fegetenv (&fenv);
|
|
|
|
|
|
|
|
/* Mask undesired bits out. */
|
|
|
|
fenv._fpu._fpu_sw &= ~excepts;
|
|
|
|
fenv._sse_mxcsr &= ~excepts;
|
|
|
|
|
|
|
|
/* Set back into FPU state. */
|
|
|
|
return fesetenv (&fenv);
|
|
|
|
}
|
|
|
|
|
2011-06-06 07:02:13 +02:00
|
|
|
/* This function raises the supported exceptions indicated by
|
winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
excepts. If more than one exception bit in excepts is set the order
|
|
|
|
in which the exceptions are raised is undefined except that overflow
|
|
|
|
(FE_OVERFLOW) or underflow (FE_UNDERFLOW) are raised before inexact
|
|
|
|
(FE_INEXACT). Whether for overflow or underflow the inexact exception
|
|
|
|
is also raised is also implementation dependent. The function returns
|
|
|
|
zero in case the operation was successful, a non-zero value otherwise. */
|
|
|
|
int
|
|
|
|
feraiseexcept (int excepts)
|
|
|
|
{
|
|
|
|
fenv_t fenv;
|
|
|
|
|
|
|
|
if (excepts & ~FE_ALL_EXCEPT)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
/* Need to save/restore whole environment to modify status word. */
|
|
|
|
__asm__ volatile ("fnstenv %0" : "=m" (fenv) : );
|
|
|
|
|
|
|
|
/* Set desired exception bits. */
|
|
|
|
fenv._fpu._fpu_sw |= excepts;
|
|
|
|
|
|
|
|
/* Set back into FPU state. */
|
|
|
|
__asm__ volatile ("fldenv %0" :: "m" (fenv));
|
|
|
|
|
|
|
|
/* And trigger them - whichever are unmasked. */
|
|
|
|
__asm__ volatile ("fwait");
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test whether the exception flags indicated by the parameter except
|
|
|
|
are currently set. If any of them are, a nonzero value is returned
|
|
|
|
which specifies which exceptions are set. Otherwise the result is zero. */
|
|
|
|
int
|
|
|
|
fetestexcept (int excepts)
|
|
|
|
{
|
|
|
|
unsigned short sw;
|
|
|
|
unsigned int mxcsr = 0;
|
|
|
|
|
|
|
|
if (excepts & ~FE_ALL_EXCEPT)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
/* Get status registers. */
|
|
|
|
__asm__ volatile ("fnstsw %0" : "=m" (sw) : );
|
|
|
|
if (use_sse)
|
|
|
|
__asm__ volatile ("stmxcsr %0" : "=m" (mxcsr) : );
|
|
|
|
|
|
|
|
/* Mask undesired bits out and return result. */
|
|
|
|
return (sw | mxcsr) & excepts;
|
|
|
|
}
|
|
|
|
/* This function stores in the variable pointed to by flagp an
|
|
|
|
implementation-defined value representing the current setting of the
|
|
|
|
exception flags indicated by excepts. The function returns zero in
|
|
|
|
case the operation was successful, a non-zero value otherwise. */
|
|
|
|
int
|
|
|
|
fegetexceptflag (fexcept_t *flagp, int excepts)
|
|
|
|
{
|
|
|
|
unsigned short sw;
|
|
|
|
unsigned int mxcsr = 0;
|
|
|
|
|
|
|
|
if (excepts & ~FE_ALL_EXCEPT)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
/* Get status registers. */
|
|
|
|
__asm__ volatile ("fnstsw %0" : "=m" (sw) : );
|
|
|
|
if (use_sse)
|
|
|
|
__asm__ volatile ("stmxcsr %0" : "=m" (mxcsr) : );
|
|
|
|
|
2016-03-30 00:12:22 +02:00
|
|
|
/* Mask undesired bits out and set result. */
|
|
|
|
*flagp = (sw | mxcsr) & excepts;
|
winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* This function restores the flags for the exceptions indicated by
|
|
|
|
excepts to the values stored in the variable pointed to by flagp. */
|
|
|
|
int
|
|
|
|
fesetexceptflag (const fexcept_t *flagp, int excepts)
|
|
|
|
{
|
|
|
|
fenv_t fenv;
|
|
|
|
|
|
|
|
if (excepts & ~FE_ALL_EXCEPT)
|
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
/* Need to save/restore whole environment to modify status word. */
|
|
|
|
fegetenv (&fenv);
|
|
|
|
|
|
|
|
/* Set/Clear desired exception bits. */
|
|
|
|
fenv._fpu._fpu_sw &= ~excepts;
|
2016-03-30 00:12:22 +02:00
|
|
|
fenv._fpu._fpu_sw |= excepts & *flagp;
|
winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
fenv._sse_mxcsr &= ~excepts;
|
2016-03-30 00:12:22 +02:00
|
|
|
fenv._sse_mxcsr |= excepts & *flagp;
|
winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
|
|
|
|
/* Set back into FPU state. */
|
|
|
|
return fesetenv (&fenv);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns the currently selected rounding mode, represented by one of the
|
|
|
|
values of the defined rounding mode macros. */
|
|
|
|
int
|
|
|
|
fegetround (void)
|
|
|
|
{
|
|
|
|
unsigned short cw;
|
|
|
|
|
|
|
|
/* Get control word. We assume SSE and x87 stay in sync. */
|
|
|
|
__asm__ volatile ("fnstcw %0" : "=m" (cw) : );
|
|
|
|
|
|
|
|
return (cw & FE_CW_ROUND_MASK) >> FE_CW_ROUND_SHIFT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Changes the currently selected rounding mode to round. If round does
|
|
|
|
not correspond to one of the supported rounding modes nothing is changed.
|
|
|
|
fesetround returns zero if it changed the rounding mode, a nonzero value
|
|
|
|
if the mode is not supported. */
|
|
|
|
int
|
|
|
|
fesetround (int round)
|
|
|
|
{
|
|
|
|
unsigned short cw;
|
|
|
|
unsigned int mxcsr = 0;
|
|
|
|
|
|
|
|
/* Will succeed for any valid value of the input parameter. */
|
2012-05-02 09:42:08 +02:00
|
|
|
if (round < FE_TONEAREST || round > FE_TOWARDZERO)
|
winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
/* Get control words. */
|
|
|
|
__asm__ volatile ("fnstcw %0" : "=m" (cw) : );
|
|
|
|
if (use_sse)
|
|
|
|
__asm__ volatile ("stmxcsr %0" : "=m" (mxcsr) : );
|
|
|
|
|
|
|
|
/* Twiddle bits. */
|
|
|
|
cw &= ~FE_CW_ROUND_MASK;
|
|
|
|
cw |= (round << FE_CW_ROUND_SHIFT);
|
|
|
|
mxcsr &= ~FE_MXCSR_ROUND_MASK;
|
|
|
|
mxcsr |= (round << FE_MXCSR_ROUND_SHIFT);
|
|
|
|
|
|
|
|
/* Set back into FPU state. */
|
|
|
|
__asm__ volatile ("fldcw %0" :: "m" (cw));
|
|
|
|
if (use_sse)
|
|
|
|
__asm__ volatile ("ldmxcsr %0" :: "m" (mxcsr));
|
|
|
|
|
|
|
|
/* Indicate success. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns the currently selected precision, represented by one of the
|
|
|
|
values of the defined precision macros. */
|
|
|
|
int
|
|
|
|
fegetprec (void)
|
|
|
|
{
|
|
|
|
unsigned short cw;
|
|
|
|
|
|
|
|
/* Get control word. */
|
|
|
|
__asm__ volatile ("fnstcw %0" : "=m" (cw) : );
|
|
|
|
|
|
|
|
return (cw & FE_CW_PREC_MASK) >> FE_CW_PREC_SHIFT;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Changes the currently selected precision to prec. If prec does not
|
|
|
|
correspond to one of the supported rounding modes nothing is changed.
|
|
|
|
fesetprec returns zero if it changed the precision, or a nonzero value
|
|
|
|
if the mode is not supported. */
|
|
|
|
int
|
|
|
|
fesetprec (int prec)
|
|
|
|
{
|
|
|
|
unsigned short cw;
|
|
|
|
|
|
|
|
/* Will succeed for any valid value of the input parameter. */
|
2012-05-02 09:42:08 +02:00
|
|
|
if (prec < FE_SINGLEPREC || prec > FE_EXTENDEDPREC)
|
winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
return EINVAL;
|
|
|
|
|
|
|
|
/* Get control word. */
|
|
|
|
__asm__ volatile ("fnstcw %0" : "=m" (cw) : );
|
|
|
|
|
|
|
|
/* Twiddle bits. */
|
|
|
|
cw &= ~FE_CW_PREC_MASK;
|
|
|
|
cw |= (prec << FE_CW_PREC_SHIFT);
|
|
|
|
|
|
|
|
/* Set back into FPU state. */
|
|
|
|
__asm__ volatile ("fldcw %0" :: "m" (cw));
|
|
|
|
|
|
|
|
/* Indicate success. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Set up the FPU and SSE environment at the start of execution. */
|
|
|
|
void
|
|
|
|
_feinitialise (void)
|
|
|
|
{
|
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
2018-08-15 12:59:23 +02:00
|
|
|
unsigned int edx, eax;
|
winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
|
|
|
|
/* Check for presence of SSE: invoke CPUID #1, check EDX bit 25. */
|
|
|
|
eax = 1;
|
|
|
|
__asm__ volatile ("cpuid" : "=d" (edx), "+a" (eax) :: "%ecx", "%ebx");
|
2013-04-23 11:44:36 +02:00
|
|
|
/* If this flag isn't set we'll avoid trying to execute any SSE. */
|
Drop NT4 support.
* autoload.cc (DnsQuery_A): Fatal if not available.
(DnsRecordListFree): Ditto.
(DsGetDcNameW): Ditto.
(NetGetAnyDCName): Remove.
(NetGetDCName): Remove.
(EnumProcessModules): Fatal if not available.
(GetModuleFileNameExW): Ditto.
(GetModuleInformation): Ditto.
(GetProcessMemoryInfo): Ditto.
(QueryWorkingSet): Ditto.
(LsaRegisterLogonProcess): Ditto.
* fenv.cc (_feinitialise): Drop supports_sse condition.
* fhandler_disk_file.cc (path_conv::isgood_inode): Fix comment.
(fhandler_base::fstat_by_name): Drop has_fileid_dirinfo condition.
(fhandler_disk_file::opendir): Ditto.
* fhandler_netdrive.cc (fhandler_netdrive::readdir): Fix comment.
* fhandler_proc.cc (format_proc_partitions): Drop NT4-only code.
* fhandler_process.cc (get_process_state): Ditto.
* kernel32.cc (GetWindowsDirectoryW): Remove.
(GetWindowsDirectoryA): Remove.
* miscfuncs.cc (nice_to_winprio): Drop NT4-only code.
* mount.cc (fs_info::update): Fix comments.
* net.cc (get_2k_ifs): Drop NT4-only code.
* sec_auth.cc (get_logon_server): Ditto.
(lsaauth): Drop NT4-specific error handling.
* security.cc (alloc_sd): Set SE_DACL_PROTECTED unconditionally.
* select.cc (select_stuff::wait): Always use MWMO_INPUTAVAILABLE.
(peek_windows): Drop NT4-only condition in call to PeekMessage.
* syscalls.cc (gethostid): Remove NT4-only workaround.
* wincap.cc: Througout, drop has_dacl_protect,
has_broken_if_oper_status, has_process_io_counters,
has_terminal_services, has_extended_priority_class, has_guid_volumes,
has_fileid_dirinfo, has_mwmo_inputavailable and supports_sse from
wincaps.
(wincap_nt4sp4): Remove.
(wincap_minimal): Set to wincap_2000.
(wincapc::init): Rely on availability of OSVERSIONINFOEX structure.
Treat error from GetVersionEx as fatal. Treat NT4 as fatal.
* wincap.h (struct wincaps): Drop has_dacl_protect,
has_broken_if_oper_status, has_process_io_counters,
has_terminal_services, has_extended_priority_class, has_guid_volumes,
has_fileid_dirinfo, has_mwmo_inputavailable and supports_sse flags
and methods.
* winlean.h (GetWindowsDirectoryW) Define as GetSystemWindowsDirectoryW.
(GetWindowsDirectoryA): Define as GetSystemWindowsDirectoryA.
2011-04-04 14:23:36 +02:00
|
|
|
if ((edx & (1 << 25)) != 0)
|
winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
use_sse = true;
|
|
|
|
|
|
|
|
/* Reset FPU: extended prec, all exceptions cleared and masked off. */
|
|
|
|
__asm__ volatile ("fninit");
|
|
|
|
/* 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. */
|
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
2018-08-15 12:59:23 +02:00
|
|
|
|
|
|
|
/* initialize the MXCSR register: mask all exceptions */
|
|
|
|
unsigned int mxcsr = __FE_ALL_EXCEPT_X86 << FE_SSE_EXCEPT_MASK_SHIFT;
|
winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
if (use_sse)
|
|
|
|
__asm__ volatile ("ldmxcsr %0" :: "m" (mxcsr));
|
|
|
|
|
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
2018-08-15 12:59:23 +02:00
|
|
|
/* Setup unmasked environment, but leave __FE_DENORM masked. */
|
winsup/cygwin/ChangeLog:
* Makefile.in (DLL_OFILES): Add new fenv.o module.
(fenv_CFLAGS): New flags definition for fenv.o compile.
* autoload.cc (std_dll_init): Use fenv.h functions instead of direct
manipulation of x87 FPU registers.
* crt0.c (mainCRTStartup): Likewise.
* cygwin.din (feclearexcept, fegetexceptflag, feraiseexcept,
fesetexceptflag, fetestexcept, fegetround, fesetround, fegetenv,
feholdexcept, fesetenv, feupdateenv, fegetprec, fesetprec,
feenableexcept, fedisableexcept, fegetexcept, _feinitialise,
_fe_dfl_env, _fe_nomask_env): Export new functions and data items.
* fenv.cc: New file.
* posix.sgml: Update status of newly-implemented APIs.
* include/fenv.h: Likewise related header.
* include/cygwin/version.h (CYGWIN_VERSION_API_MINOR): Bump.
2010-09-11 08:53:28 +02:00
|
|
|
feenableexcept (FE_ALL_EXCEPT);
|
|
|
|
fegetenv (&fe_nomask_env);
|
|
|
|
|
|
|
|
/* Restore default exception masking (all masked). */
|
|
|
|
fedisableexcept (FE_ALL_EXCEPT);
|
|
|
|
|
|
|
|
/* Finally cache state as default environment. */
|
|
|
|
fegetenv (&fe_dfl_env);
|
|
|
|
}
|
|
|
|
|