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.
This commit is contained in:
parent
f7dea7f233
commit
0f81b5d4bc
|
@ -1,3 +1,20 @@
|
||||||
|
2010-09-11 Dave Korn <dave.korn.cygwin@gmail.com>
|
||||||
|
|
||||||
|
* 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-10 Corinna Vinschen <corinna@vinschen.de>
|
2010-09-10 Corinna Vinschen <corinna@vinschen.de>
|
||||||
|
|
||||||
* syscalls.cc (rename): Limit retry loop in case of sharing violation
|
* syscalls.cc (rename): Limit retry loop in case of sharing violation
|
||||||
|
|
|
@ -137,7 +137,7 @@ MT_SAFE_OBJECTS:=
|
||||||
#
|
#
|
||||||
DLL_OFILES:=assert.o autoload.o bsdlib.o ctype.o cxx.o cygheap.o cygthread.o \
|
DLL_OFILES:=assert.o autoload.o bsdlib.o ctype.o cxx.o cygheap.o cygthread.o \
|
||||||
cygtls.o cygxdr.o dcrt0.o debug.o devices.o dir.o dlfcn.o dll_init.o \
|
cygtls.o cygxdr.o dcrt0.o debug.o devices.o dir.o dlfcn.o dll_init.o \
|
||||||
dtable.o environ.o errno.o exceptions.o exec.o external.o fcntl.o \
|
dtable.o environ.o errno.o exceptions.o exec.o external.o fcntl.o fenv.o \
|
||||||
fhandler.o fhandler_clipboard.o fhandler_console.o fhandler_disk_file.o \
|
fhandler.o fhandler_clipboard.o fhandler_console.o fhandler_disk_file.o \
|
||||||
fhandler_dsp.o fhandler_fifo.o fhandler_floppy.o fhandler_mailslot.o \
|
fhandler_dsp.o fhandler_fifo.o fhandler_floppy.o fhandler_mailslot.o \
|
||||||
fhandler_mem.o fhandler_netdrive.o fhandler_nodevice.o fhandler_proc.o \
|
fhandler_mem.o fhandler_netdrive.o fhandler_nodevice.o fhandler_proc.o \
|
||||||
|
@ -244,6 +244,7 @@ dlfcn_CFLAGS:=-fomit-frame-pointer
|
||||||
dll_init_CFLAGS:=-fomit-frame-pointer
|
dll_init_CFLAGS:=-fomit-frame-pointer
|
||||||
dtable_CFLAGS:=-fomit-frame-pointer -fcheck-new
|
dtable_CFLAGS:=-fomit-frame-pointer -fcheck-new
|
||||||
fcntl_CFLAGS:=-fomit-frame-pointer
|
fcntl_CFLAGS:=-fomit-frame-pointer
|
||||||
|
fenv_CFLAGS:=-fomit-frame-pointer
|
||||||
fhandler_CFLAGS:=-fomit-frame-pointer
|
fhandler_CFLAGS:=-fomit-frame-pointer
|
||||||
fhandler_clipboard_CFLAGS:=-fomit-frame-pointer
|
fhandler_clipboard_CFLAGS:=-fomit-frame-pointer
|
||||||
fhandler_console_CFLAGS:=-fomit-frame-pointer
|
fhandler_console_CFLAGS:=-fomit-frame-pointer
|
||||||
|
|
|
@ -11,6 +11,7 @@ details. */
|
||||||
|
|
||||||
#include "winsup.h"
|
#include "winsup.h"
|
||||||
#include "miscfuncs.h"
|
#include "miscfuncs.h"
|
||||||
|
#include "fenv.h"
|
||||||
#define USE_SYS_TYPES_FD_SET
|
#define USE_SYS_TYPES_FD_SET
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
|
||||||
|
@ -222,13 +223,13 @@ std_dll_init ()
|
||||||
while (InterlockedIncrement (&dll->here));
|
while (InterlockedIncrement (&dll->here));
|
||||||
else if (!dll->handle)
|
else if (!dll->handle)
|
||||||
{
|
{
|
||||||
unsigned fpu_control = 0;
|
fenv_t fpuenv;
|
||||||
__asm__ __volatile__ ("fnstcw %0": "=m" (fpu_control));
|
fegetenv (&fpuenv);
|
||||||
/* http://www.microsoft.com/technet/security/advisory/2269637.mspx */
|
/* http://www.microsoft.com/technet/security/advisory/2269637.mspx */
|
||||||
wcpcpy (wcpcpy (dll_path, windows_system_directory), dll->name);
|
wcpcpy (wcpcpy (dll_path, windows_system_directory), dll->name);
|
||||||
if ((h = LoadLibraryW (dll_path)) != NULL)
|
if ((h = LoadLibraryW (dll_path)) != NULL)
|
||||||
{
|
{
|
||||||
__asm__ __volatile__ ("fldcw %0": : "m" (fpu_control));
|
fesetenv (&fpuenv);
|
||||||
dll->handle = h;
|
dll->handle = h;
|
||||||
}
|
}
|
||||||
else if (!(func->decoration & 1))
|
else if (!(func->decoration & 1))
|
||||||
|
|
|
@ -13,11 +13,7 @@ details. */
|
||||||
|
|
||||||
#include "winlean.h"
|
#include "winlean.h"
|
||||||
#include <sys/cygwin.h>
|
#include <sys/cygwin.h>
|
||||||
#ifdef __i386__
|
#include "fenv.h"
|
||||||
#define FPU_RESERVED 0xF0C0
|
|
||||||
#define FPU_DEFAULT 0x033f
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
extern int main (int argc, char **argv);
|
extern int main (int argc, char **argv);
|
||||||
|
|
||||||
|
@ -29,19 +25,7 @@ mainCRTStartup ()
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
(void)__builtin_return_address(1);
|
(void)__builtin_return_address(1);
|
||||||
asm volatile ("andl $-16,%%esp" ::: "%esp");
|
asm volatile ("andl $-16,%%esp" ::: "%esp");
|
||||||
{
|
_feinitialise ();
|
||||||
volatile unsigned short cw;
|
|
||||||
|
|
||||||
/* Get Control Word */
|
|
||||||
__asm__ volatile ("fnstcw %0" : "=m" (cw) : );
|
|
||||||
|
|
||||||
/* mask in */
|
|
||||||
cw &= FPU_RESERVED;
|
|
||||||
cw |= FPU_DEFAULT;
|
|
||||||
|
|
||||||
/* set cw */
|
|
||||||
__asm__ volatile ("fldcw %0" :: "m" (cw));
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
cygwin_crt0 (main);
|
cygwin_crt0 (main);
|
||||||
|
|
|
@ -453,10 +453,29 @@ fdopen SIGFE
|
||||||
_fdopen = fdopen SIGFE
|
_fdopen = fdopen SIGFE
|
||||||
_fdopen64 = fdopen64 SIGFE
|
_fdopen64 = fdopen64 SIGFE
|
||||||
fdopendir SIGFE
|
fdopendir SIGFE
|
||||||
|
_fe_dfl_env DATA
|
||||||
|
_fe_nomask_env DATA
|
||||||
|
feclearexcept NOSIGFE
|
||||||
|
fedisableexcept NOSIGFE
|
||||||
|
feenableexcept SIGFE
|
||||||
|
fegetenv NOSIGFE
|
||||||
|
fegetexcept NOSIGFE
|
||||||
|
fegetexceptflag NOSIGFE
|
||||||
|
fegetprec NOSIGFE
|
||||||
|
fegetround NOSIGFE
|
||||||
|
feholdexcept SIGFE
|
||||||
|
_feinitialise NOSIGFE
|
||||||
feof SIGFE
|
feof SIGFE
|
||||||
_feof = feof SIGFE
|
_feof = feof SIGFE
|
||||||
|
feraiseexcept SIGFE
|
||||||
ferror SIGFE
|
ferror SIGFE
|
||||||
_ferror = ferror SIGFE
|
_ferror = ferror SIGFE
|
||||||
|
fesetenv SIGFE
|
||||||
|
fesetexceptflag SIGFE
|
||||||
|
fesetprec NOSIGFE
|
||||||
|
fesetround NOSIGFE
|
||||||
|
fetestexcept NOSIGFE
|
||||||
|
feupdateenv SIGFE
|
||||||
fexecve SIGFE
|
fexecve SIGFE
|
||||||
fflush SIGFE
|
fflush SIGFE
|
||||||
_fflush = fflush SIGFE
|
_fflush = fflush SIGFE
|
||||||
|
|
|
@ -0,0 +1,445 @@
|
||||||
|
/* fenv.cc
|
||||||
|
|
||||||
|
Copyright 2010 Red Hat, Inc.
|
||||||
|
|
||||||
|
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. */
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include "fenv.h"
|
||||||
|
#include "errno.h"
|
||||||
|
|
||||||
|
/* 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)
|
||||||
|
{
|
||||||
|
__asm__ volatile ("fnstenv %0" : "=m" (envp->_fpu) : );
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This function raises the supported exceptions indicated by
|
||||||
|
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) : );
|
||||||
|
|
||||||
|
/* Mask undesired bits out and set result struct. */
|
||||||
|
flagp->_fpu_exceptions = (sw & excepts);
|
||||||
|
flagp->_sse_exceptions = (mxcsr & excepts);
|
||||||
|
|
||||||
|
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;
|
||||||
|
fenv._fpu._fpu_sw |= (excepts & flagp->_fpu_exceptions);
|
||||||
|
fenv._sse_mxcsr &= ~excepts;
|
||||||
|
fenv._sse_mxcsr |= (excepts & flagp->_sse_exceptions);
|
||||||
|
|
||||||
|
/* 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. */
|
||||||
|
if (round & ~(FE_CW_ROUND_MASK >> FE_CW_PREC_SHIFT))
|
||||||
|
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. */
|
||||||
|
if (prec & ~(FE_CW_PREC_MASK >> FE_CW_PREC_SHIFT) || prec == FE_RESERVEDPREC)
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
unsigned int edx, eax, mxcsr;
|
||||||
|
|
||||||
|
/* Check for presence of SSE: invoke CPUID #1, check EDX bit 25. */
|
||||||
|
eax = 1;
|
||||||
|
__asm__ volatile ("cpuid" : "=d" (edx), "+a" (eax) :: "%ecx", "%ebx");
|
||||||
|
/* If this flag isn't set, we'll avoid trying to execute any SSE. */
|
||||||
|
if (edx & (1 << 25))
|
||||||
|
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. */
|
||||||
|
mxcsr = FE_ALL_EXCEPT << FE_SSE_EXCEPT_MASK_SHIFT;
|
||||||
|
if (use_sse)
|
||||||
|
__asm__ volatile ("ldmxcsr %0" :: "m" (mxcsr));
|
||||||
|
|
||||||
|
/* Setup unmasked environment. */
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -390,12 +390,13 @@ details. */
|
||||||
228: CW_STRERROR added.
|
228: CW_STRERROR added.
|
||||||
229: Add mkostemp, mkostemps.
|
229: Add mkostemp, mkostemps.
|
||||||
230: Add CLOCK_MONOTONIC.
|
230: Add CLOCK_MONOTONIC.
|
||||||
|
231: Add fenv.h functions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Note that we forgot to bump the api for ualarm, strtoll, strtoull */
|
/* Note that we forgot to bump the api for ualarm, strtoll, strtoull */
|
||||||
|
|
||||||
#define CYGWIN_VERSION_API_MAJOR 0
|
#define CYGWIN_VERSION_API_MAJOR 0
|
||||||
#define CYGWIN_VERSION_API_MINOR 230
|
#define CYGWIN_VERSION_API_MINOR 231
|
||||||
|
|
||||||
/* There is also a compatibity version number associated with the
|
/* There is also a compatibity version number associated with the
|
||||||
shared memory regions. It is incremented when incompatible
|
shared memory regions. It is incremented when incompatible
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
/* fenv.h
|
||||||
|
|
||||||
|
Copyright 2010 Red Hat, Inc.
|
||||||
|
|
||||||
|
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. */
|
||||||
|
|
||||||
|
#ifndef _FENV_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Primary sources:
|
||||||
|
|
||||||
|
The Open Group Base Specifications Issue 6:
|
||||||
|
http://www.opengroup.org/onlinepubs/000095399/basedefs/fenv.h.html
|
||||||
|
|
||||||
|
C99 Language spec (draft n1256):
|
||||||
|
<url unknown>
|
||||||
|
|
||||||
|
Intel® 64 and IA-32 Architectures Software Developer’s Manuals:
|
||||||
|
http://www.intel.com/products/processor/manuals/
|
||||||
|
|
||||||
|
GNU C library manual pages:
|
||||||
|
http://www.gnu.org/software/libc/manual/html_node/Control-Functions.html
|
||||||
|
http://www.gnu.org/software/libc/manual/html_node/Rounding.html
|
||||||
|
http://www.gnu.org/software/libc/manual/html_node/FP-Exceptions.html
|
||||||
|
http://www.gnu.org/software/libc/manual/html_node/Status-bit-operations.html
|
||||||
|
|
||||||
|
Linux online man page(s):
|
||||||
|
http://linux.die.net/man/3/fegetexcept
|
||||||
|
|
||||||
|
The documentation quotes these sources for reference. All definitions and
|
||||||
|
code have been developed solely based on the information from these specs.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Represents the entire floating-point environment. The floating-point
|
||||||
|
environment refers collectively to any floating-point status flags and
|
||||||
|
control modes supported by the implementation.
|
||||||
|
In this implementation, the struct contains the state information from
|
||||||
|
the fstenv/fnstenv instructions and a copy of the SSE MXCSR, since GCC
|
||||||
|
uses SSE for a lot of floating-point operations. (Cygwin assumes i686
|
||||||
|
or above these days, as does the compiler.) */
|
||||||
|
|
||||||
|
typedef struct _fenv_t
|
||||||
|
{
|
||||||
|
struct _fpu_env_info {
|
||||||
|
unsigned int _fpu_cw; /* low 16 bits only. */
|
||||||
|
unsigned int _fpu_sw; /* low 16 bits only. */
|
||||||
|
unsigned int _fpu_tagw; /* low 16 bits only. */
|
||||||
|
unsigned int _fpu_ipoff;
|
||||||
|
unsigned int _fpu_ipsel;
|
||||||
|
unsigned int _fpu_opoff;
|
||||||
|
unsigned int _fpu_opsel; /* low 16 bits only. */
|
||||||
|
} _fpu;
|
||||||
|
unsigned int _sse_mxcsr;
|
||||||
|
} fenv_t;
|
||||||
|
|
||||||
|
/* Represents the floating-point status flags collectively, including
|
||||||
|
any status the implementation associates with the flags. A floating-point
|
||||||
|
status flag is a system variable whose value is set (but never cleared)
|
||||||
|
when a floating-point exception is raised, which occurs as a side effect
|
||||||
|
of exceptional floating-point arithmetic to provide auxiliary information.
|
||||||
|
A floating-point control mode is a system variable whose value may be
|
||||||
|
set by the user to affect the subsequent behavior of floating-point
|
||||||
|
arithmetic. */
|
||||||
|
|
||||||
|
typedef struct _fexcept_t
|
||||||
|
{
|
||||||
|
unsigned short _fpu_exceptions;
|
||||||
|
unsigned short _sse_exceptions;
|
||||||
|
} fexcept_t;
|
||||||
|
|
||||||
|
/* The <fenv.h> header shall define the following constants if and only
|
||||||
|
if the implementation supports the floating-point exception by means
|
||||||
|
of the floating-point functions feclearexcept(), fegetexceptflag(),
|
||||||
|
feraiseexcept(), fesetexceptflag(), and fetestexcept(). Each expands to
|
||||||
|
an integer constant expression with values such that bitwise-inclusive
|
||||||
|
ORs of all combinations of the constants result in distinct values. */
|
||||||
|
|
||||||
|
#define FE_DIVBYZERO (1 << 2)
|
||||||
|
#define FE_INEXACT (1 << 5)
|
||||||
|
#define FE_INVALID (1 << 0)
|
||||||
|
#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)
|
||||||
|
|
||||||
|
/* The <fenv.h> header shall define the following constants if and only
|
||||||
|
if the implementation supports getting and setting the represented
|
||||||
|
rounding direction by means of the fegetround() and fesetround()
|
||||||
|
functions. Each expands to an integer constant expression whose values
|
||||||
|
are distinct non-negative vales. */
|
||||||
|
|
||||||
|
#define FE_DOWNWARD (1)
|
||||||
|
#define FE_TONEAREST (0)
|
||||||
|
#define FE_TOWARDZERO (3)
|
||||||
|
#define FE_UPWARD (2)
|
||||||
|
|
||||||
|
/* Precision bit values. Not defined by Posix, but follow logically. */
|
||||||
|
#define FE_SINGLEPREC (0)
|
||||||
|
#define FE_RESERVEDPREC (1)
|
||||||
|
#define FE_DOUBLEPREC (2)
|
||||||
|
#define FE_EXTENDEDPREC (3)
|
||||||
|
|
||||||
|
/* The <fenv.h> header shall define the following constant, which
|
||||||
|
represents the default floating-point environment (that is, the one
|
||||||
|
installed at program startup) and has type pointer to const-qualified
|
||||||
|
fenv_t. It can be used as an argument to the functions within the
|
||||||
|
<fenv.h> header that manage the floating-point environment. */
|
||||||
|
|
||||||
|
extern const fenv_t *_fe_dfl_env;
|
||||||
|
#define FE_DFL_ENV (_fe_dfl_env)
|
||||||
|
|
||||||
|
/* Additional implementation-defined environments, with macro
|
||||||
|
definitions beginning with FE_ and an uppercase letter,and having
|
||||||
|
type "pointer to const-qualified fenv_t",may also be specified by
|
||||||
|
the implementation. */
|
||||||
|
|
||||||
|
#ifdef _GNU_SOURCE
|
||||||
|
/* If possible, the GNU C Library defines a macro FE_NOMASK_ENV which
|
||||||
|
represents an environment where every exception raised causes a trap
|
||||||
|
to occur. You can test for this macro using #ifdef. It is only defined
|
||||||
|
if _GNU_SOURCE is defined. */
|
||||||
|
extern const fenv_t *_fe_nomask_env;
|
||||||
|
#define FE_NOMASK_ENV (_fe_nomask_env)
|
||||||
|
#endif /* _GNU_SOURCE */
|
||||||
|
|
||||||
|
|
||||||
|
/* The following shall be declared as functions and may also be
|
||||||
|
defined as macros. Function prototypes shall be provided. */
|
||||||
|
extern int feclearexcept (int excepts);
|
||||||
|
extern int fegetexceptflag (fexcept_t *flagp, int excepts);
|
||||||
|
extern int feraiseexcept (int excepts);
|
||||||
|
extern int fesetexceptflag (const fexcept_t *flagp, int excepts);
|
||||||
|
extern int fetestexcept (int excepts);
|
||||||
|
extern int fegetround (void);
|
||||||
|
extern int fesetround (int round);
|
||||||
|
extern int fegetenv (fenv_t *envp);
|
||||||
|
extern int feholdexcept (fenv_t *envp);
|
||||||
|
extern int fesetenv (const fenv_t *envp);
|
||||||
|
extern int feupdateenv (const fenv_t *envp);
|
||||||
|
|
||||||
|
/* These are not defined in Posix, but make sense by obvious extension. */
|
||||||
|
extern int fegetprec (void);
|
||||||
|
extern int fesetprec (int prec);
|
||||||
|
|
||||||
|
/* This is Cygwin-custom, not from the standard, for use in the Cygwin CRT. */
|
||||||
|
extern void _feinitialise (void);
|
||||||
|
|
||||||
|
/* These are GNU extensions defined in glibc. */
|
||||||
|
extern int feenableexcept (int excepts);
|
||||||
|
extern int fedisableexcept (int excepts);
|
||||||
|
extern int fegetexcept (void);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _FENV_H_ */
|
|
@ -150,8 +150,19 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
|
||||||
fdimf
|
fdimf
|
||||||
fdopen
|
fdopen
|
||||||
fdopendir
|
fdopendir
|
||||||
|
feclearexcept
|
||||||
|
fegetenv
|
||||||
|
fegetexceptflag
|
||||||
|
fegetround
|
||||||
|
feholdexcept
|
||||||
feof
|
feof
|
||||||
|
feraiseexcept
|
||||||
ferror
|
ferror
|
||||||
|
fesetenv
|
||||||
|
fesetexceptflag
|
||||||
|
fesetround
|
||||||
|
fetestexcept
|
||||||
|
feupdateenv
|
||||||
fexecve
|
fexecve
|
||||||
fflush
|
fflush
|
||||||
ffs
|
ffs
|
||||||
|
@ -1024,6 +1035,11 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
|
||||||
exp10f
|
exp10f
|
||||||
fcloseall
|
fcloseall
|
||||||
fcloseall_r
|
fcloseall_r
|
||||||
|
fegetprec
|
||||||
|
fesetprec
|
||||||
|
feenableexcept
|
||||||
|
fedisableexcept
|
||||||
|
fegetexcept
|
||||||
fgetxattr
|
fgetxattr
|
||||||
flistxattr
|
flistxattr
|
||||||
fopencookie
|
fopencookie
|
||||||
|
@ -1277,17 +1293,6 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
|
||||||
fabsl
|
fabsl
|
||||||
fattach
|
fattach
|
||||||
fdiml
|
fdiml
|
||||||
feclearexcept
|
|
||||||
fegetenv
|
|
||||||
fegetexceptflag
|
|
||||||
fegetround
|
|
||||||
feholdexcept
|
|
||||||
feraiseexcept
|
|
||||||
fesetenv
|
|
||||||
fesetexceptflag
|
|
||||||
fesetround
|
|
||||||
fetestexcept
|
|
||||||
feupdateenv
|
|
||||||
floorl
|
floorl
|
||||||
fmal
|
fmal
|
||||||
fmaxl
|
fmaxl
|
||||||
|
|
Loading…
Reference in New Issue