Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDave Korn <dave.korn.cygwin@gmail.com>2010-09-11 10:53:28 +0400
committerDave Korn <dave.korn.cygwin@gmail.com>2010-09-11 10:53:28 +0400
commit0f81b5d4bcaa5c840031796d94df9ba6d6fae4d0 (patch)
tree167292d4f6250ddb23f2abfe2660049054117f91
parentf7dea7f23347d847b6abd3d8b5f7e1b00f21262f (diff)
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.
-rw-r--r--winsup/cygwin/ChangeLog17
-rw-r--r--winsup/cygwin/Makefile.in3
-rw-r--r--winsup/cygwin/autoload.cc7
-rw-r--r--winsup/cygwin/crt0.c20
-rw-r--r--winsup/cygwin/cygwin.din19
-rwxr-xr-xwinsup/cygwin/fenv.cc445
-rw-r--r--winsup/cygwin/include/cygwin/version.h3
-rwxr-xr-xwinsup/cygwin/include/fenv.h176
-rw-r--r--winsup/cygwin/posix.sgml27
9 files changed, 683 insertions, 34 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index cde4f2f13..18b92a794 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -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>
* syscalls.cc (rename): Limit retry loop in case of sharing violation
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index 59f229c01..10743eab8 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -137,7 +137,7 @@ MT_SAFE_OBJECTS:=
#
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 \
- 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_dsp.o fhandler_fifo.o fhandler_floppy.o fhandler_mailslot.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
dtable_CFLAGS:=-fomit-frame-pointer -fcheck-new
fcntl_CFLAGS:=-fomit-frame-pointer
+fenv_CFLAGS:=-fomit-frame-pointer
fhandler_CFLAGS:=-fomit-frame-pointer
fhandler_clipboard_CFLAGS:=-fomit-frame-pointer
fhandler_console_CFLAGS:=-fomit-frame-pointer
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 07272af53..5054f6808 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -11,6 +11,7 @@ details. */
#include "winsup.h"
#include "miscfuncs.h"
+#include "fenv.h"
#define USE_SYS_TYPES_FD_SET
#include <winsock2.h>
@@ -222,13 +223,13 @@ std_dll_init ()
while (InterlockedIncrement (&dll->here));
else if (!dll->handle)
{
- unsigned fpu_control = 0;
- __asm__ __volatile__ ("fnstcw %0": "=m" (fpu_control));
+ fenv_t fpuenv;
+ fegetenv (&fpuenv);
/* http://www.microsoft.com/technet/security/advisory/2269637.mspx */
wcpcpy (wcpcpy (dll_path, windows_system_directory), dll->name);
if ((h = LoadLibraryW (dll_path)) != NULL)
{
- __asm__ __volatile__ ("fldcw %0": : "m" (fpu_control));
+ fesetenv (&fpuenv);
dll->handle = h;
}
else if (!(func->decoration & 1))
diff --git a/winsup/cygwin/crt0.c b/winsup/cygwin/crt0.c
index d716d9be5..aa6a5f18f 100644
--- a/winsup/cygwin/crt0.c
+++ b/winsup/cygwin/crt0.c
@@ -13,11 +13,7 @@ details. */
#include "winlean.h"
#include <sys/cygwin.h>
-#ifdef __i386__
-#define FPU_RESERVED 0xF0C0
-#define FPU_DEFAULT 0x033f
-
-#endif
+#include "fenv.h"
extern int main (int argc, char **argv);
@@ -29,19 +25,7 @@ mainCRTStartup ()
#ifdef __i386__
(void)__builtin_return_address(1);
asm volatile ("andl $-16,%%esp" ::: "%esp");
- {
- 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));
- }
+ _feinitialise ();
#endif
cygwin_crt0 (main);
diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din
index 9253d2cbe..3edaaf061 100644
--- a/winsup/cygwin/cygwin.din
+++ b/winsup/cygwin/cygwin.din
@@ -453,10 +453,29 @@ fdopen SIGFE
_fdopen = fdopen SIGFE
_fdopen64 = fdopen64 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 = feof SIGFE
+feraiseexcept SIGFE
ferror SIGFE
_ferror = ferror SIGFE
+fesetenv SIGFE
+fesetexceptflag SIGFE
+fesetprec NOSIGFE
+fesetround NOSIGFE
+fetestexcept NOSIGFE
+feupdateenv SIGFE
fexecve SIGFE
fflush SIGFE
_fflush = fflush SIGFE
diff --git a/winsup/cygwin/fenv.cc b/winsup/cygwin/fenv.cc
new file mode 100755
index 000000000..63670f7ab
--- /dev/null
+++ b/winsup/cygwin/fenv.cc
@@ -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);
+}
+
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index 66356ff27..fc2fd1a98 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -390,12 +390,13 @@ details. */
228: CW_STRERROR added.
229: Add mkostemp, mkostemps.
230: Add CLOCK_MONOTONIC.
+ 231: Add fenv.h functions.
*/
/* Note that we forgot to bump the api for ualarm, strtoll, strtoull */
#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
shared memory regions. It is incremented when incompatible
diff --git a/winsup/cygwin/include/fenv.h b/winsup/cygwin/include/fenv.h
new file mode 100755
index 000000000..89e3d48c4
--- /dev/null
+++ b/winsup/cygwin/include/fenv.h
@@ -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_ */
diff --git a/winsup/cygwin/posix.sgml b/winsup/cygwin/posix.sgml
index 294247631..276b75413 100644
--- a/winsup/cygwin/posix.sgml
+++ b/winsup/cygwin/posix.sgml
@@ -150,8 +150,19 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
fdimf
fdopen
fdopendir
+ feclearexcept
+ fegetenv
+ fegetexceptflag
+ fegetround
+ feholdexcept
feof
+ feraiseexcept
ferror
+ fesetenv
+ fesetexceptflag
+ fesetround
+ fetestexcept
+ feupdateenv
fexecve
fflush
ffs
@@ -1024,6 +1035,11 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
exp10f
fcloseall
fcloseall_r
+ fegetprec
+ fesetprec
+ feenableexcept
+ fedisableexcept
+ fegetexcept
fgetxattr
flistxattr
fopencookie
@@ -1277,17 +1293,6 @@ also IEEE Std 1003.1-2008 (POSIX.1-2008).</para>
fabsl
fattach
fdiml
- feclearexcept
- fegetenv
- fegetexceptflag
- fegetround
- feholdexcept
- feraiseexcept
- fesetenv
- fesetexceptflag
- fesetround
- fetestexcept
- feupdateenv
floorl
fmal
fmaxl