This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
[PATCH v5] Add i386 and x86_64 fenv support from Cygwin.
- From: joel at rtems dot org
- To: newlib at sourceware dot org
- Cc: Joel Sherrill <joel at rtems dot org>
- Date: Wed, 25 Sep 2019 10:09:14 -0500
- Subject: [PATCH v5] Add i386 and x86_64 fenv support from Cygwin.
- References: <1569424154-2566-1-git-send-email-joel@rtems.org>
From: Joel Sherrill <joel@rtems.org>
---
newlib/configure.host | 1 +
newlib/libc/machine/i386/sys/fenv.h | 1 +
newlib/libc/machine/x86_64/sys/fenv.h | 143 ++++++++
newlib/libm/fenv/fenv_stub.c | 23 ++
newlib/libm/machine/configure.in | 1 +
newlib/libm/machine/i386/Makefile.am | 6 +-
newlib/libm/machine/i386/feclearexcept.c | 1 +
newlib/libm/machine/i386/fegetenv.c | 1 +
newlib/libm/machine/i386/fegetexceptflag.c | 1 +
newlib/libm/machine/i386/fegetround.c | 1 +
newlib/libm/machine/i386/feholdexcept.c | 1 +
newlib/libm/machine/i386/fenv.c | 1 +
newlib/libm/machine/i386/feraiseexcept.c | 1 +
newlib/libm/machine/i386/fesetenv.c | 1 +
newlib/libm/machine/i386/fesetexceptflag.c | 1 +
newlib/libm/machine/i386/fesetround.c | 1 +
newlib/libm/machine/i386/fetestexcept.c | 1 +
newlib/libm/machine/i386/feupdateenv.c | 1 +
newlib/libm/machine/x86_64/Makefile.am | 20 ++
newlib/libm/machine/x86_64/configure.in | 25 ++
newlib/libm/machine/x86_64/feclearexcept.c | 1 +
newlib/libm/machine/x86_64/fegetenv.c | 1 +
newlib/libm/machine/x86_64/fegetexceptflag.c | 1 +
newlib/libm/machine/x86_64/fegetround.c | 1 +
newlib/libm/machine/x86_64/feholdexcept.c | 1 +
newlib/libm/machine/x86_64/fenv.c | 477 +++++++++++++++++++++++++++
newlib/libm/machine/x86_64/feraiseexcept.c | 1 +
newlib/libm/machine/x86_64/fesetenv.c | 1 +
newlib/libm/machine/x86_64/fesetexceptflag.c | 1 +
newlib/libm/machine/x86_64/fesetround.c | 1 +
newlib/libm/machine/x86_64/fetestexcept.c | 1 +
newlib/libm/machine/x86_64/feupdateenv.c | 1 +
32 files changed, 718 insertions(+), 2 deletions(-)
create mode 120000 newlib/libc/machine/i386/sys/fenv.h
create mode 100644 newlib/libc/machine/x86_64/sys/fenv.h
create mode 100644 newlib/libm/fenv/fenv_stub.c
create mode 120000 newlib/libm/machine/i386/feclearexcept.c
create mode 120000 newlib/libm/machine/i386/fegetenv.c
create mode 120000 newlib/libm/machine/i386/fegetexceptflag.c
create mode 120000 newlib/libm/machine/i386/fegetround.c
create mode 120000 newlib/libm/machine/i386/feholdexcept.c
create mode 120000 newlib/libm/machine/i386/fenv.c
create mode 120000 newlib/libm/machine/i386/feraiseexcept.c
create mode 120000 newlib/libm/machine/i386/fesetenv.c
create mode 120000 newlib/libm/machine/i386/fesetexceptflag.c
create mode 120000 newlib/libm/machine/i386/fesetround.c
create mode 120000 newlib/libm/machine/i386/fetestexcept.c
create mode 120000 newlib/libm/machine/i386/feupdateenv.c
create mode 100644 newlib/libm/machine/x86_64/Makefile.am
create mode 100644 newlib/libm/machine/x86_64/configure.in
create mode 120000 newlib/libm/machine/x86_64/feclearexcept.c
create mode 120000 newlib/libm/machine/x86_64/fegetenv.c
create mode 120000 newlib/libm/machine/x86_64/fegetexceptflag.c
create mode 120000 newlib/libm/machine/x86_64/fegetround.c
create mode 120000 newlib/libm/machine/x86_64/feholdexcept.c
create mode 100644 newlib/libm/machine/x86_64/fenv.c
create mode 120000 newlib/libm/machine/x86_64/feraiseexcept.c
create mode 120000 newlib/libm/machine/x86_64/fesetenv.c
create mode 120000 newlib/libm/machine/x86_64/fesetexceptflag.c
create mode 120000 newlib/libm/machine/x86_64/fesetround.c
create mode 120000 newlib/libm/machine/x86_64/fetestexcept.c
create mode 120000 newlib/libm/machine/x86_64/feupdateenv.c
diff --git a/newlib/configure.host b/newlib/configure.host
index 87bf78a..06b7bad 100644
--- a/newlib/configure.host
+++ b/newlib/configure.host
@@ -339,6 +339,7 @@ case "${host_cpu}" in
;;
x86_64)
machine_dir=x86_64
+ libm_machine_dir=x86_64
;;
xc16x*)
machine_dir=xc16x
diff --git a/newlib/libc/machine/i386/sys/fenv.h b/newlib/libc/machine/i386/sys/fenv.h
new file mode 120000
index 0000000..2180578
--- /dev/null
+++ b/newlib/libc/machine/i386/sys/fenv.h
@@ -0,0 +1 @@
+../../x86_64/sys/fenv.h
\ No newline at end of file
diff --git a/newlib/libc/machine/x86_64/sys/fenv.h b/newlib/libc/machine/x86_64/sys/fenv.h
new file mode 100644
index 0000000..70620d8
--- /dev/null
+++ b/newlib/libc/machine/x86_64/sys/fenv.h
@@ -0,0 +1,143 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2010-2019 Red Hat, Inc.
+ */
+
+#ifndef _SYS_FENV_H
+#define _SYS_FENV_H 1
+
+#include <sys/cdefs.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(R) 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 __uint32_t 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)
+
+/* The <fenv.h> header shall define the following constant, which is
+ simply the bitwise-inclusive OR of all floating-point exception
+ constants defined above: */
+
+/* in agreement w/ Linux the subnormal exception will always be masked */
+#define FE_ALL_EXCEPT \
+ (FE_INEXACT | FE_UNDERFLOW | FE_OVERFLOW | FE_DIVBYZERO | FE_INVALID)
+
+/* The <fenv.h> header shall define the following constants if and only
+ if the implementation supports getting and setting the represented
+ 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)
+
+/* Only Solaris and QNX implement fegetprec/fesetprec. As Solaris, use the
+ values defined by http://www.open-std.org/jtc1/sc22//WG14/www/docs/n752.htm
+ QNX defines different values. */
+#if __MISC_VISIBLE
+#define FE_FLTPREC (0)
+#define FE_DBLPREC (2)
+#define FE_LDBLPREC (3)
+#endif
+
+/* 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. */
+
+#if __GNU_VISIBLE
+/* 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_VISIBLE */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FENV_H */
diff --git a/newlib/libm/fenv/fenv_stub.c b/newlib/libm/fenv/fenv_stub.c
new file mode 100644
index 0000000..a4eb652
--- /dev/null
+++ b/newlib/libm/fenv/fenv_stub.c
@@ -0,0 +1,23 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * (c) Copyright 2019 Joel Sherrill <joel@rtems.org
+ */
+
+/*
+ * This file is intentionally empty.
+ *
+ * Newlib's build infrastructure needs a machine specific fiel to override
+ * the generic implementation in the library. When a target
+ * implementation of the fenv.h methods puts all methods in a single file
+ * (e.g. fenv.c) or some as inline methods in its <sys/fenv.h>, it will need
+ * to override the default implementation found in a file in this directory.
+ *
+ * For each file that the target's machine directory needs to override,
+ * this file should be symbolically linked to that specific file name
+ * in the target directory. For example, the target may use fe_dfl_env.c
+ * from the default implementation but need to override all others.
+ */
+
+/* deliberately empty */
+
diff --git a/newlib/libm/machine/configure.in b/newlib/libm/machine/configure.in
index 55e2d35..f43ae1b 100644
--- a/newlib/libm/machine/configure.in
+++ b/newlib/libm/machine/configure.in
@@ -31,6 +31,7 @@ if test -n "${libm_machine_dir}"; then
nds32) AC_CONFIG_SUBDIRS(nds32) ;;
spu) AC_CONFIG_SUBDIRS(spu) ;;
riscv) AC_CONFIG_SUBDIRS(riscv) ;;
+ x86_64) AC_CONFIG_SUBDIRS(x86_64) ;;
esac;
if test "${use_libtool}" = "yes"; then
machlib=${libm_machine_dir}/lib${libm_machine_dir}.${aext}
diff --git a/newlib/libm/machine/i386/Makefile.am b/newlib/libm/machine/i386/Makefile.am
index 6fade2d..249f876 100644
--- a/newlib/libm/machine/i386/Makefile.am
+++ b/newlib/libm/machine/i386/Makefile.am
@@ -12,8 +12,10 @@ LIB_SOURCES = \
f_log.S f_logf.S f_log10.S f_log10f.S \
f_ldexp.S f_ldexpf.S f_lrint.c f_lrintf.c f_lrintl.c \
f_pow.c f_powf.c f_rint.c f_rintf.c f_rintl.c \
- f_tan.S f_tanf.S f_math.h \
- i386mach.h
+ f_tan.S f_tanf.S f_math.h i386mach.h \
+ fenv.c feclearexcept.c fegetenv.c fegetexceptflag.c \
+ fegetround.c feholdexcept.c feraiseexcept.c fesetenv.c \
+ fesetexceptflag.c fesetround.c fetestexcept.c feupdateenv.c
libi386_la_LDFLAGS = -Xcompiler -nostdlib
diff --git a/newlib/libm/machine/i386/feclearexcept.c b/newlib/libm/machine/i386/feclearexcept.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/i386/feclearexcept.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/i386/fegetenv.c b/newlib/libm/machine/i386/fegetenv.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/i386/fegetenv.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/i386/fegetexceptflag.c b/newlib/libm/machine/i386/fegetexceptflag.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/i386/fegetexceptflag.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/i386/fegetround.c b/newlib/libm/machine/i386/fegetround.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/i386/fegetround.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/i386/feholdexcept.c b/newlib/libm/machine/i386/feholdexcept.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/i386/feholdexcept.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/i386/fenv.c b/newlib/libm/machine/i386/fenv.c
new file mode 120000
index 0000000..1d7c7a1
--- /dev/null
+++ b/newlib/libm/machine/i386/fenv.c
@@ -0,0 +1 @@
+../x86_64/fenv.c
\ No newline at end of file
diff --git a/newlib/libm/machine/i386/feraiseexcept.c b/newlib/libm/machine/i386/feraiseexcept.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/i386/feraiseexcept.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/i386/fesetenv.c b/newlib/libm/machine/i386/fesetenv.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/i386/fesetenv.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/i386/fesetexceptflag.c b/newlib/libm/machine/i386/fesetexceptflag.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/i386/fesetexceptflag.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/i386/fesetround.c b/newlib/libm/machine/i386/fesetround.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/i386/fesetround.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/i386/fetestexcept.c b/newlib/libm/machine/i386/fetestexcept.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/i386/fetestexcept.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/i386/feupdateenv.c b/newlib/libm/machine/i386/feupdateenv.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/i386/feupdateenv.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/x86_64/Makefile.am b/newlib/libm/machine/x86_64/Makefile.am
new file mode 100644
index 0000000..a48b1a0
--- /dev/null
+++ b/newlib/libm/machine/x86_64/Makefile.am
@@ -0,0 +1,20 @@
+## Process this file with automake to generate Makefile.in
+
+INCLUDES = -I $(newlib_basedir)/../newlib/libm/common $(NEWLIB_CFLAGS) \
+ $(CROSS_CFLAGS) $(TARGET_CFLAGS)
+
+LIB_SOURCES = \
+ feclearexcept.c fegetenv.c fegetexceptflag.c fegetround.c \
+ feholdexcept.c fenv.c feraiseexcept.c fesetenv.c fesetexceptflag.c \
+ fesetround.c fetestexcept.c feupdateenv.c
+
+noinst_LIBRARIES = lib.a
+lib_a_SOURCES = $(LIB_SOURCES)
+lib_a_CFLAGS = $(AM_CFLAGS)
+lib_a_CCASFLAGS = $(AM_CCASFLAGS)
+noinst_DATA =
+
+include $(srcdir)/../../../Makefile.shared
+
+ACLOCAL_AMFLAGS = -I ../../.. -I ../../../..
+CONFIG_STATUS_DEPENDENCIES = $(newlib_basedir)/configure.host
diff --git a/newlib/libm/machine/x86_64/configure.in b/newlib/libm/machine/x86_64/configure.in
new file mode 100644
index 0000000..29492a6
--- /dev/null
+++ b/newlib/libm/machine/x86_64/configure.in
@@ -0,0 +1,25 @@
+dnl This is the newlib/libc/machine/x86_64 configure.in file.
+dnl Process this file with autoconf to produce a configure script.
+
+AC_PREREQ(2.59)
+AC_INIT([newlib],[NEWLIB_VERSION])
+AC_CONFIG_SRCDIR([Makefile.am])
+
+dnl Can't be done in NEWLIB_CONFIGURE because that confuses automake.
+AC_CONFIG_AUX_DIR(../../../..)
+
+NEWLIB_CONFIGURE(../../..)
+
+dnl We have to add the following lines because automake detects the
+dnl references to libtool libraries from aclocal and tries to verify that
+dnl AM_PROG_LIBTOOL is being used. This code must occur after
+dnl NEWLIB_CONFIGURE.
+_LT_DECL_SED
+_LT_PROG_ECHO_BACKSLASH
+if test "${use_libtool}" = "yes"; then
+AC_LIBTOOL_WIN32_DLL
+AM_PROG_LIBTOOL
+fi
+
+AC_CONFIG_FILES([Makefile])
+AC_OUTPUT
diff --git a/newlib/libm/machine/x86_64/feclearexcept.c b/newlib/libm/machine/x86_64/feclearexcept.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/x86_64/feclearexcept.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/x86_64/fegetenv.c b/newlib/libm/machine/x86_64/fegetenv.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/x86_64/fegetenv.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/x86_64/fegetexceptflag.c b/newlib/libm/machine/x86_64/fegetexceptflag.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/x86_64/fegetexceptflag.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/x86_64/fegetround.c b/newlib/libm/machine/x86_64/fegetround.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/x86_64/fegetround.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/x86_64/feholdexcept.c b/newlib/libm/machine/x86_64/feholdexcept.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/x86_64/feholdexcept.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/x86_64/fenv.c b/newlib/libm/machine/x86_64/fenv.c
new file mode 100644
index 0000000..ccc08e2
--- /dev/null
+++ b/newlib/libm/machine/x86_64/fenv.c
@@ -0,0 +1,477 @@
+/*
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2010-2019 Red Hat, Inc.
+ */
+
+#define _GNU_SOURCE // for FE_NOMASK_ENV
+
+#include <fenv.h>
+#include <errno.h>
+#include <string.h> // for memcpy
+#include <stdbool.h>
+
+/* x87 supports subnormal numbers so we need it below. */
+#define __FE_DENORM (1 << 1)
+/* mask (= 0x3f) to disable all exceptions at initialization */
+#define __FE_ALL_EXCEPT_X86 (FE_ALL_EXCEPT | __FE_DENORM)
+
+/* Mask and shift amount for rounding bits. */
+#define FE_CW_ROUND_MASK (0x0c00)
+#define FE_CW_ROUND_SHIFT (10)
+/* 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_nomask_env;
+
+/* These pointers provide the outside world with read-only access to them. */
+const fenv_t *_fe_nomask_env = &fe_nomask_env;
+
+/* Assume i686 or above (hence SSE available) these days, with the
+ compiler feels free to use it (depending on compile- time flags of
+ course), but 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 inline bool use_sse(void)
+{
+ unsigned int edx, eax;
+
+ /* 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)) != 0)
+ return true;
+
+ return false;
+}
+
+/* forward declaration */
+static void _feinitialise (void);
+
+/* 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)
+{
+ /* 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) : );
+ 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)
+{
+ if ((envp == FE_DFL_ENV || envp == FE_NOMASK_ENV) &&
+ envp->_fpu._fpu_cw == 0)
+ _feinitialise ();
+
+ __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. */
+ *flagp = (sw | 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;
+ fenv._sse_mxcsr &= ~excepts;
+ fenv._sse_mxcsr |= excepts & *flagp;
+
+ /* 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_TONEAREST || round > FE_TOWARDZERO)
+ 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;
+}
+
+#if defined(__CYGWIN__)
+/* 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;
+}
+
+/* http://www.open-std.org/jtc1/sc22//WG14/www/docs/n752.htm:
+
+ The fesetprec function establishes the precision represented by its
+ argument prec. If the argument does not match a precision macro, the
+ precision is not changed.
+
+ The fesetprec function returns a nonzero value if and only if the
+ argument matches a precision macro (that is, if and only if the requested
+ precision can be established). */
+int
+fesetprec (int prec)
+{
+ unsigned short cw;
+
+ /* Will succeed for any valid value of the input parameter. */
+ switch (prec)
+ {
+ case FE_FLTPREC:
+ case FE_DBLPREC:
+ case FE_LDBLPREC:
+ break;
+ default:
+ return 0;
+ }
+
+ /* 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 1;
+}
+#endif
+
+/* Set up the FPU and SSE environment at the start of execution. */
+static void
+_feinitialise (void)
+{
+ extern fenv_t __fe_dfl_env;
+
+ /* 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. */
+
+ /* initialize the MXCSR register: mask all exceptions */
+ unsigned int mxcsr = __FE_ALL_EXCEPT_X86 << FE_SSE_EXCEPT_MASK_SHIFT;
+ if (use_sse())
+ __asm__ volatile ("ldmxcsr %0" :: "m" (mxcsr));
+
+ /* Setup unmasked environment, but leave __FE_DENORM masked. */
+ 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/newlib/libm/machine/x86_64/feraiseexcept.c b/newlib/libm/machine/x86_64/feraiseexcept.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/x86_64/feraiseexcept.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/x86_64/fesetenv.c b/newlib/libm/machine/x86_64/fesetenv.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/x86_64/fesetenv.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/x86_64/fesetexceptflag.c b/newlib/libm/machine/x86_64/fesetexceptflag.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/x86_64/fesetexceptflag.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/x86_64/fesetround.c b/newlib/libm/machine/x86_64/fesetround.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/x86_64/fesetround.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/x86_64/fetestexcept.c b/newlib/libm/machine/x86_64/fetestexcept.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/x86_64/fetestexcept.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
diff --git a/newlib/libm/machine/x86_64/feupdateenv.c b/newlib/libm/machine/x86_64/feupdateenv.c
new file mode 120000
index 0000000..f97d27d
--- /dev/null
+++ b/newlib/libm/machine/x86_64/feupdateenv.c
@@ -0,0 +1 @@
+../../fenv/fenv_stub.c
\ No newline at end of file
--
1.8.3.1