about summary refs log tree commit diff
path: root/sysdeps
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2016-09-07 16:40:09 +0000
committerJoseph Myers <joseph@codesourcery.com>2016-09-07 16:40:09 +0000
commitec94343f592df68ba1ba49bb2c558f7d2629387c (patch)
tree7430394b9a38cb5527558363186ffdb4546761b7 /sysdeps
parentfb0f7a6755c1bfaec38f490fbfcaa39a66ee3604 (diff)
downloadglibc-ec94343f592df68ba1ba49bb2c558f7d2629387c.tar.gz
glibc-ec94343f592df68ba1ba49bb2c558f7d2629387c.tar.xz
glibc-ec94343f592df68ba1ba49bb2c558f7d2629387c.zip
Add femode_t functions.
TS 18661-1 defines a type femode_t to represent the set of dynamic
floating-point control modes (such as the rounding mode and trap
enablement modes), and functions fegetmode and fesetmode to manipulate
those modes (without affecting other state such as the raised
exception flags) and a corresponding macro FE_DFL_MODE.

This patch series implements those interfaces for glibc.  This first
patch adds the architecture-independent pieces, the x86 and x86_64
implementations, and the <bits/fenv.h> and ABI baseline updates for
all architectures so glibc keeps building and passing the ABI tests on
all architectures.  Subsequent patches add the fegetmode and fesetmode
implementations for other architectures.

femode_t is generally an integer type - the same type as fenv_t, or as
the single element of fenv_t where fenv_t is a structure containing a
single integer (or the single relevant element, where it has elements
for both status and control registers) - except where architecture
properties or consistency with the fenv_t implementation indicate
otherwise.  FE_DFL_MODE follows FE_DFL_ENV in whether it's a magic
pointer value (-1 cast to const femode_t *), a value that can be
distinguished from valid pointers by its high bits but otherwise
contains a representation of the desired register contents, or a
pointer to a constant variable (the powerpc case; __fe_dfl_mode is
added as an exported constant object, an alias to __fe_dfl_env).

Note that where architectures (that share a register between control
and status bits) gain definitions of new floating-point control or
status bits in future, the implementations of fesetmode for those
architectures may need updating (depending on whether the new bits are
control or status bits and what the implementation does with
previously unknown bits), just like existing implementations of
<fenv.h> functions that take care not to touch reserved bits may need
updating when the set of reserved bits changes.  (As any new bits are
outside the scope of ISO C, that's just a quality-of-implementation
issue for supporting them, not a conformance issue.)

As with fenv_t, femode_t should properly include any software DFP
rounding mode (and for both fenv_t and femode_t I'd consider that
fragment of DFP support appropriate for inclusion in glibc even in the
absence of the rest of libdfp; hardware DFP rounding modes should
already be included if the definitions of which bits are status /
control bits are correct).

Tested for x86_64, x86, mips64 (hard float, and soft float to test the
fallback version), arm (hard float) and powerpc (hard float, soft
float and e500).  Other architecture versions are untested.

	* math/fegetmode.c: New file.
	* math/fesetmode.c: Likewise.
	* sysdeps/i386/fpu/fegetmode.c: Likewise.
	* sysdeps/i386/fpu/fesetmode.c: Likewise.
	* sysdeps/x86_64/fpu/fegetmode.c: Likewise.
	* sysdeps/x86_64/fpu/fesetmode.c: Likewise.
	* math/fenv.h: Update comment on inclusion of <bits/fenv.h>.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (fegetmode): New function
	declaration.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (fesetmode): Likewise.
	* bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)] (femode_t): New
	typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/aarch64/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/alpha/fpu/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/arm/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/hppa/fpu/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/ia64/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/m68k/fpu/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/microblaze/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/mips/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/nios2/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/powerpc/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (__fe_dfl_mode): New variable
	declaration.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/s390/fpu/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/sh/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/sparc/fpu/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/tile/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* sysdeps/x86/fpu/bits/fenv.h [__GLIBC_USE (IEC_60559_BFP_EXT)]
	(femode_t): New typedef.
	[__GLIBC_USE (IEC_60559_BFP_EXT)] (FE_DFL_MODE): New macro.
	* manual/arith.texi (FE_DFL_MODE): Document macro.
	(fegetmode): Document function.
	(fesetmode): Likewise.
	* math/Versions (fegetmode): New libm symbol at version
	GLIBC_2.25.
	(fesetmode): Likewise.
	* math/Makefile (libm-support): Add fegetmode and fesetmode.
	(tests): Add test-femode and test-femode-traps.
	* math/test-femode-traps.c: New file.
	* math/test-femode.c: Likewise.
	* sysdeps/powerpc/fpu/fenv_const.c (__fe_dfl_mode): Declare as
	alias for __fe_dfl_env.
	* sysdeps/powerpc/nofpu/fenv_const.c (__fe_dfl_mode): Likewise.
	* sysdeps/powerpc/powerpc32/e500/nofpu/fenv_const.c
	(__fe_dfl_mode): Likewise.
	* sysdeps/powerpc/Versions (__fe_dfl_mode): New libm symbol at
	version GLIBC_2.25.
	* sysdeps/nacl/libm.abilist: Update.
	* sysdeps/unix/sysv/linux/aarch64/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/alpha/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/arm/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/hppa/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/i386/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/ia64/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/coldfire/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/m68k/m680x0/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/microblaze/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips32/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/mips/mips64/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/nios2/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libm.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libm.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libm-le.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/powerpc/powerpc64/libm.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-32/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/s390/s390-64/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sh/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc32/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/sparc/sparc64/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libm.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libm.abilist:
	Likewise.
	* sysdeps/unix/sysv/linux/tile/tilepro/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/64/libm.abilist: Likewise.
	* sysdeps/unix/sysv/linux/x86_64/x32/libm.abilist: Likewise.
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/aarch64/bits/fenv.h8
-rw-r--r--sysdeps/alpha/fpu/bits/fenv.h8
-rw-r--r--sysdeps/arm/bits/fenv.h8
-rw-r--r--sysdeps/hppa/fpu/bits/fenv.h8
-rw-r--r--sysdeps/i386/fpu/fegetmode.c32
-rw-r--r--sysdeps/i386/fpu/fesetmode.c54
-rw-r--r--sysdeps/ia64/bits/fenv.h8
-rw-r--r--sysdeps/m68k/fpu/bits/fenv.h8
-rw-r--r--sysdeps/microblaze/bits/fenv.h8
-rw-r--r--sysdeps/mips/bits/fenv.h8
-rw-r--r--sysdeps/nacl/libm.abilist2
-rw-r--r--sysdeps/nios2/bits/fenv.h8
-rw-r--r--sysdeps/powerpc/Versions3
-rw-r--r--sysdeps/powerpc/bits/fenv.h9
-rw-r--r--sysdeps/powerpc/fpu/fenv_const.c4
-rw-r--r--sysdeps/powerpc/nofpu/fenv_const.c4
-rw-r--r--sysdeps/powerpc/powerpc32/e500/nofpu/fenv_const.c4
-rw-r--r--sysdeps/s390/fpu/bits/fenv.h8
-rw-r--r--sysdeps/sh/bits/fenv.h8
-rw-r--r--sysdeps/sparc/fpu/bits/fenv.h8
-rw-r--r--sysdeps/tile/bits/fenv.h8
-rw-r--r--sysdeps/unix/sysv/linux/aarch64/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/alpha/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/arm/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/hppa/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/i386/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/ia64/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/m68k/coldfire/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/m68k/m680x0/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/microblaze/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips32/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/mips/mips64/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/nios2/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libm.abilist3
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libm.abilist3
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc64/libm-le.abilist3
-rw-r--r--sysdeps/unix/sysv/linux/powerpc/powerpc64/libm.abilist3
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-32/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/s390/s390-64/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/sh/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc32/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/sparc/sparc64/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/tile/tilepro/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/64/libm.abilist2
-rw-r--r--sysdeps/unix/sysv/linux/x86_64/x32/libm.abilist2
-rw-r--r--sysdeps/x86/fpu/bits/fenv.h14
-rw-r--r--sysdeps/x86_64/fpu/fegetmode.c28
-rw-r--r--sysdeps/x86_64/fpu/fesetmode.c50
50 files changed, 364 insertions, 0 deletions
diff --git a/sysdeps/aarch64/bits/fenv.h b/sysdeps/aarch64/bits/fenv.h
index aced0d33b2..9df57a1bbf 100644
--- a/sysdeps/aarch64/bits/fenv.h
+++ b/sysdeps/aarch64/bits/fenv.h
@@ -72,3 +72,11 @@ fenv_t;
 /* Floating-point environment where none of the exceptions are masked.  */
 # define FE_NOMASK_ENV  ((const fenv_t *) -2)
 #endif
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef unsigned int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) -1L)
+#endif
diff --git a/sysdeps/alpha/fpu/bits/fenv.h b/sysdeps/alpha/fpu/bits/fenv.h
index b7da4a0eae..0688898ce7 100644
--- a/sysdeps/alpha/fpu/bits/fenv.h
+++ b/sysdeps/alpha/fpu/bits/fenv.h
@@ -131,3 +131,11 @@ typedef unsigned long int fenv_t;
 /* The system calls to talk to the kernel's FP code.  */
 extern unsigned long int __ieee_get_fp_control (void) __THROW;
 extern void __ieee_set_fp_control (unsigned long int __value) __THROW;
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef unsigned long int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) 0x8800000000000000UL)
+#endif
diff --git a/sysdeps/arm/bits/fenv.h b/sysdeps/arm/bits/fenv.h
index 8e89fc1819..c82fecb48f 100644
--- a/sysdeps/arm/bits/fenv.h
+++ b/sysdeps/arm/bits/fenv.h
@@ -80,3 +80,11 @@ fenv_t;
 /* Floating-point environment where none of the exceptions are masked.  */
 # define FE_NOMASK_ENV  ((const fenv_t *) -2)
 #endif
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef unsigned int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) -1L)
+#endif
diff --git a/sysdeps/hppa/fpu/bits/fenv.h b/sysdeps/hppa/fpu/bits/fenv.h
index cae9daeb04..e35e3553f9 100644
--- a/sysdeps/hppa/fpu/bits/fenv.h
+++ b/sysdeps/hppa/fpu/bits/fenv.h
@@ -89,3 +89,11 @@ typedef struct
 /* Floating-point environment where none of the exceptions are masked.  */
 # define FE_NOMASK_ENV	((const fenv_t *) -2)
 #endif
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef unsigned int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) -1L)
+#endif
diff --git a/sysdeps/i386/fpu/fegetmode.c b/sysdeps/i386/fpu/fegetmode.c
new file mode 100644
index 0000000000..06d4d84768
--- /dev/null
+++ b/sysdeps/i386/fpu/fegetmode.c
@@ -0,0 +1,32 @@
+/* Store current floating-point control modes.  i386 version.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <dl-procinfo.h>
+
+int
+fegetmode (femode_t *modep)
+{
+  _FPU_GETCW (modep->__control_word);
+  if ((GLRO(dl_hwcap) & HWCAP_I386_XMM) != 0)
+    __asm__ ("stmxcsr %0" : "=m" (modep->__mxcsr));
+  return 0;
+}
diff --git a/sysdeps/i386/fpu/fesetmode.c b/sysdeps/i386/fpu/fesetmode.c
new file mode 100644
index 0000000000..cca5a1ad0c
--- /dev/null
+++ b/sysdeps/i386/fpu/fesetmode.c
@@ -0,0 +1,54 @@
+/* Install given floating-point control modes.  i386 version.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+#include <unistd.h>
+#include <ldsodefs.h>
+#include <dl-procinfo.h>
+
+/* All exceptions, including the x86-specific "denormal operand"
+   exception.  */
+#define FE_ALL_EXCEPT_X86 (FE_ALL_EXCEPT | __FE_DENORM)
+
+int
+fesetmode (const femode_t *modep)
+{
+  fpu_control_t cw;
+  if (modep == FE_DFL_MODE)
+    cw = _FPU_DEFAULT;
+  else
+    cw = modep->__control_word;
+  _FPU_SETCW (cw);
+  if ((GLRO(dl_hwcap) & HWCAP_I386_XMM) != 0)
+    {
+      unsigned int mxcsr;
+      __asm__ ("stmxcsr %0" : "=m" (mxcsr));
+      /* Preserve SSE exception flags but restore other state in
+	 MXCSR.  */
+      mxcsr &= FE_ALL_EXCEPT_X86;
+      if (modep == FE_DFL_MODE)
+	/* Default MXCSR state has all bits zero except for those
+	   masking exceptions.  */
+	mxcsr |= FE_ALL_EXCEPT_X86 << 7;
+      else
+	mxcsr |= modep->__mxcsr & ~FE_ALL_EXCEPT_X86;
+      __asm__ ("ldmxcsr %0" : : "m" (mxcsr));
+    }
+  return 0;
+}
diff --git a/sysdeps/ia64/bits/fenv.h b/sysdeps/ia64/bits/fenv.h
index 9bb20de27b..5945380889 100644
--- a/sysdeps/ia64/bits/fenv.h
+++ b/sysdeps/ia64/bits/fenv.h
@@ -94,3 +94,11 @@ typedef unsigned long int fenv_t;
    s0, s2, and s3.  */
 # define FE_NONIEEE_ENV ((const fenv_t *) 0xc009a04d0270037fUL)
 #endif
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef unsigned long int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) 0xc009804c0270033fUL)
+#endif
diff --git a/sysdeps/m68k/fpu/bits/fenv.h b/sysdeps/m68k/fpu/bits/fenv.h
index 2228861624..b8e52b290e 100644
--- a/sysdeps/m68k/fpu/bits/fenv.h
+++ b/sysdeps/m68k/fpu/bits/fenv.h
@@ -85,3 +85,11 @@ fenv_t;
 /* Floating-point environment where none of the exceptions are masked.  */
 # define FE_NOMASK_ENV	((const fenv_t *) -2)
 #endif
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef unsigned int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) -1L)
+#endif
diff --git a/sysdeps/microblaze/bits/fenv.h b/sysdeps/microblaze/bits/fenv.h
index 3891f4a186..0d2ab2bc58 100644
--- a/sysdeps/microblaze/bits/fenv.h
+++ b/sysdeps/microblaze/bits/fenv.h
@@ -40,3 +40,11 @@ typedef unsigned int fenv_t;
 
 /* If the default argument is used we use this value.  */
 #define FE_DFL_ENV	((const fenv_t *) -1l)
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef unsigned int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) -1L)
+#endif
diff --git a/sysdeps/mips/bits/fenv.h b/sysdeps/mips/bits/fenv.h
index f829bd3807..6341ee279e 100644
--- a/sysdeps/mips/bits/fenv.h
+++ b/sysdeps/mips/bits/fenv.h
@@ -83,3 +83,11 @@ fenv_t;
 /* Floating-point environment where none of the exception is masked.  */
 # define FE_NOMASK_ENV  ((const fenv_t *) -2)
 #endif
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef unsigned int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) -1L)
+#endif
diff --git a/sysdeps/nacl/libm.abilist b/sysdeps/nacl/libm.abilist
index 28897730fa..85ee684a1a 100644
--- a/sysdeps/nacl/libm.abilist
+++ b/sysdeps/nacl/libm.abilist
@@ -380,5 +380,7 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
diff --git a/sysdeps/nios2/bits/fenv.h b/sysdeps/nios2/bits/fenv.h
index 9d046217c8..8ac3831ed9 100644
--- a/sysdeps/nios2/bits/fenv.h
+++ b/sysdeps/nios2/bits/fenv.h
@@ -42,3 +42,11 @@ typedef unsigned int fenv_t;
 
 /* If the default argument is used we use this value.  */
 #define FE_DFL_ENV	((const fenv_t *) -1)
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef unsigned int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) -1L)
+#endif
diff --git a/sysdeps/powerpc/Versions b/sysdeps/powerpc/Versions
index b959ea49fe..95849668f2 100644
--- a/sysdeps/powerpc/Versions
+++ b/sysdeps/powerpc/Versions
@@ -3,6 +3,9 @@ libm {
     # symbols used in macros from sysdeps/powerpc/bits/fenv.h
     __fe_dfl_env; __fe_enabled_env; __fe_nonieee_env; __fe_nomask_env;
   }
+  GLIBC_2.25 {
+    __fe_dfl_mode;
+  }
 }
 
 libc {
diff --git a/sysdeps/powerpc/bits/fenv.h b/sysdeps/powerpc/bits/fenv.h
index d2a6d34a99..8d2bf3d163 100644
--- a/sysdeps/powerpc/bits/fenv.h
+++ b/sysdeps/powerpc/bits/fenv.h
@@ -169,3 +169,12 @@ extern const fenv_t __fe_nonieee_env;
 # define FE_MASK_ENV	FE_DFL_ENV
 
 #endif
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef double femode_t;
+
+/* Default floating-point control modes.  */
+extern const femode_t __fe_dfl_mode;
+# define FE_DFL_MODE	(&__fe_dfl_mode)
+#endif
diff --git a/sysdeps/powerpc/fpu/fenv_const.c b/sysdeps/powerpc/fpu/fenv_const.c
index b061daf578..93a4375430 100644
--- a/sysdeps/powerpc/fpu/fenv_const.c
+++ b/sysdeps/powerpc/fpu/fenv_const.c
@@ -23,6 +23,10 @@
 const unsigned long long __fe_dfl_env __attribute__ ((aligned (8))) =
 0xfff8000000000000ULL;
 
+/* The same representation is used for femode_t.  */
+extern const unsigned long long __fe_dfl_mode
+  __attribute__ ((aligned (8), alias ("__fe_dfl_env")));
+
 /* Floating-point environment where none of the exceptions are masked.  */
 const unsigned long long __fe_enabled_env __attribute__ ((aligned (8))) =
 0xfff80000000000f8ULL;
diff --git a/sysdeps/powerpc/nofpu/fenv_const.c b/sysdeps/powerpc/nofpu/fenv_const.c
index ebf5c68fc5..ce1da3c197 100644
--- a/sysdeps/powerpc/nofpu/fenv_const.c
+++ b/sysdeps/powerpc/nofpu/fenv_const.c
@@ -25,6 +25,10 @@
 const unsigned long long __fe_dfl_env __attribute__ ((aligned (8))) =
 0x000000003e000000ULL;
 
+/* The same representation is used for femode_t.  */
+extern const unsigned long long __fe_dfl_mode
+  __attribute__ ((aligned (8), alias ("__fe_dfl_env")));
+
 /* Floating-point environment where none of the exceptions are masked.  */
 const unsigned long long __fe_enabled_env __attribute__ ((aligned (8))) =
 0x0000000000000000ULL;
diff --git a/sysdeps/powerpc/powerpc32/e500/nofpu/fenv_const.c b/sysdeps/powerpc/powerpc32/e500/nofpu/fenv_const.c
index 11e24ca182..eab47c8c0f 100644
--- a/sysdeps/powerpc/powerpc32/e500/nofpu/fenv_const.c
+++ b/sysdeps/powerpc/powerpc32/e500/nofpu/fenv_const.c
@@ -28,6 +28,10 @@
 const unsigned long long __fe_dfl_env __attribute__ ((aligned (8))) =
   0x3cULL;
 
+/* The same representation is used for femode_t.  */
+extern const unsigned long long __fe_dfl_mode
+  __attribute__ ((aligned (8), alias ("__fe_dfl_env")));
+
 /* Floating-point environment where none of the exceptions are masked.  */
 const unsigned long long __fe_enabled_env __attribute__ ((aligned (8))) =
   (((unsigned long long) (PR_FP_EXC_DIV
diff --git a/sysdeps/s390/fpu/bits/fenv.h b/sysdeps/s390/fpu/bits/fenv.h
index 6de74b9939..d33f5d921d 100644
--- a/sysdeps/s390/fpu/bits/fenv.h
+++ b/sysdeps/s390/fpu/bits/fenv.h
@@ -90,3 +90,11 @@ typedef struct
 /* Floating-point environment where none of the exceptions are masked.  */
 # define FE_NOMASK_ENV	((const fenv_t *) -2)
 #endif
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef unsigned int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) -1L)
+#endif
diff --git a/sysdeps/sh/bits/fenv.h b/sysdeps/sh/bits/fenv.h
index 254c50fb97..200b53899b 100644
--- a/sysdeps/sh/bits/fenv.h
+++ b/sysdeps/sh/bits/fenv.h
@@ -74,3 +74,11 @@ fenv_t;
 
 /* If the default argument is used we use this value.  */
 #define FE_DFL_ENV	((const fenv_t *) -1)
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef unsigned int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) -1L)
+#endif
diff --git a/sysdeps/sparc/fpu/bits/fenv.h b/sysdeps/sparc/fpu/bits/fenv.h
index 29328f714f..37c82ff5eb 100644
--- a/sysdeps/sparc/fpu/bits/fenv.h
+++ b/sysdeps/sparc/fpu/bits/fenv.h
@@ -91,3 +91,11 @@ typedef unsigned long int fenv_t;
 # define __fenv_stfsr(X)   __asm__ __volatile__ ("st %%fsr,%0" : "=m" (X))
 # define __fenv_ldfsr(X)   __asm__ __volatile__ ("ld %0,%%fsr" : : "m" (X))
 #endif
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef unsigned long int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) -1L)
+#endif
diff --git a/sysdeps/tile/bits/fenv.h b/sysdeps/tile/bits/fenv.h
index a87a39fc28..eee9e011cc 100644
--- a/sysdeps/tile/bits/fenv.h
+++ b/sysdeps/tile/bits/fenv.h
@@ -43,3 +43,11 @@ typedef unsigned int fenv_t;
 
 /* If the default argument is used we use this value.  */
 #define FE_DFL_ENV	((const fenv_t *) -1l)
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef unsigned int femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) -1L)
+#endif
diff --git a/sysdeps/unix/sysv/linux/aarch64/libm.abilist b/sysdeps/unix/sysv/linux/aarch64/libm.abilist
index 1f475cd5c1..aee63a105c 100644
--- a/sysdeps/unix/sysv/linux/aarch64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/aarch64/libm.abilist
@@ -411,5 +411,7 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
diff --git a/sysdeps/unix/sysv/linux/alpha/libm.abilist b/sysdeps/unix/sysv/linux/alpha/libm.abilist
index 11b76e9a10..339b896ac7 100644
--- a/sysdeps/unix/sysv/linux/alpha/libm.abilist
+++ b/sysdeps/unix/sysv/linux/alpha/libm.abilist
@@ -421,7 +421,9 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.3.4 GLIBC_2.3.4 A
 GLIBC_2.3.4 __c1_cabsf F
diff --git a/sysdeps/unix/sysv/linux/arm/libm.abilist b/sysdeps/unix/sysv/linux/arm/libm.abilist
index 1fc1804bd5..f7b824413b 100644
--- a/sysdeps/unix/sysv/linux/arm/libm.abilist
+++ b/sysdeps/unix/sysv/linux/arm/libm.abilist
@@ -69,7 +69,9 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 _LIB_VERSION D 0x4
diff --git a/sysdeps/unix/sysv/linux/hppa/libm.abilist b/sysdeps/unix/sysv/linux/hppa/libm.abilist
index ed734881dd..576b514a53 100644
--- a/sysdeps/unix/sysv/linux/hppa/libm.abilist
+++ b/sysdeps/unix/sysv/linux/hppa/libm.abilist
@@ -381,7 +381,9 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 exp2l F
diff --git a/sysdeps/unix/sysv/linux/i386/libm.abilist b/sysdeps/unix/sysv/linux/i386/libm.abilist
index 3a6dcaf064..63b8da9985 100644
--- a/sysdeps/unix/sysv/linux/i386/libm.abilist
+++ b/sysdeps/unix/sysv/linux/i386/libm.abilist
@@ -423,6 +423,8 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
diff --git a/sysdeps/unix/sysv/linux/ia64/libm.abilist b/sysdeps/unix/sysv/linux/ia64/libm.abilist
index ec9916b52e..611a84ff57 100644
--- a/sysdeps/unix/sysv/linux/ia64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/ia64/libm.abilist
@@ -352,6 +352,8 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
diff --git a/sysdeps/unix/sysv/linux/m68k/coldfire/libm.abilist b/sysdeps/unix/sysv/linux/m68k/coldfire/libm.abilist
index 1fc1804bd5..f7b824413b 100644
--- a/sysdeps/unix/sysv/linux/m68k/coldfire/libm.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/coldfire/libm.abilist
@@ -69,7 +69,9 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 _LIB_VERSION D 0x4
diff --git a/sysdeps/unix/sysv/linux/m68k/m680x0/libm.abilist b/sysdeps/unix/sysv/linux/m68k/m680x0/libm.abilist
index 32931f1677..77f9c7bed7 100644
--- a/sysdeps/unix/sysv/linux/m68k/m680x0/libm.abilist
+++ b/sysdeps/unix/sysv/linux/m68k/m680x0/libm.abilist
@@ -421,6 +421,8 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
diff --git a/sysdeps/unix/sysv/linux/microblaze/libm.abilist b/sysdeps/unix/sysv/linux/microblaze/libm.abilist
index cab693a4e4..c59437fe73 100644
--- a/sysdeps/unix/sysv/linux/microblaze/libm.abilist
+++ b/sysdeps/unix/sysv/linux/microblaze/libm.abilist
@@ -380,5 +380,7 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
diff --git a/sysdeps/unix/sysv/linux/mips/mips32/libm.abilist b/sysdeps/unix/sysv/linux/mips/mips32/libm.abilist
index 20a80ccbf2..31d6f9eb70 100644
--- a/sysdeps/unix/sysv/linux/mips/mips32/libm.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips32/libm.abilist
@@ -382,7 +382,9 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 exp2l F
diff --git a/sysdeps/unix/sysv/linux/mips/mips64/libm.abilist b/sysdeps/unix/sysv/linux/mips/mips64/libm.abilist
index 02379f78bf..83e031125b 100644
--- a/sysdeps/unix/sysv/linux/mips/mips64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/mips/mips64/libm.abilist
@@ -413,6 +413,8 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
diff --git a/sysdeps/unix/sysv/linux/nios2/libm.abilist b/sysdeps/unix/sysv/linux/nios2/libm.abilist
index b4b377ba19..151574d670 100644
--- a/sysdeps/unix/sysv/linux/nios2/libm.abilist
+++ b/sysdeps/unix/sysv/linux/nios2/libm.abilist
@@ -380,5 +380,7 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libm.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libm.abilist
index 7eea14aded..456f47e912 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libm.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/fpu/libm.abilist
@@ -422,7 +422,10 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __fe_dfl_mode D 0x8
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 __clog10l F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libm.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libm.abilist
index 5eb2e9bb40..b2e4a73fd6 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libm.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc32/nofpu/libm.abilist
@@ -421,7 +421,10 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __fe_dfl_mode D 0x8
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 __clog10l F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm-le.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm-le.abilist
index 36b8e77d47..907d8b7936 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm-le.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm-le.abilist
@@ -416,5 +416,8 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __fe_dfl_mode D 0x8
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
diff --git a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm.abilist b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm.abilist
index 2efd4ebb33..307423dc80 100644
--- a/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/powerpc/powerpc64/libm.abilist
@@ -97,7 +97,10 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 __fe_dfl_mode D 0x8
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.3 GLIBC_2.3 A
 GLIBC_2.3 _LIB_VERSION D 0x4
diff --git a/sysdeps/unix/sysv/linux/s390/s390-32/libm.abilist b/sysdeps/unix/sysv/linux/s390/s390-32/libm.abilist
index 62f75baa36..377cea952a 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-32/libm.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-32/libm.abilist
@@ -411,7 +411,9 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 __clog10l F
diff --git a/sysdeps/unix/sysv/linux/s390/s390-64/libm.abilist b/sysdeps/unix/sysv/linux/s390/s390-64/libm.abilist
index c41344a9ff..dafbff15a6 100644
--- a/sysdeps/unix/sysv/linux/s390/s390-64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/s390/s390-64/libm.abilist
@@ -409,7 +409,9 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 __clog10l F
diff --git a/sysdeps/unix/sysv/linux/sh/libm.abilist b/sysdeps/unix/sysv/linux/sh/libm.abilist
index 3baecfb400..a38baceb8f 100644
--- a/sysdeps/unix/sysv/linux/sh/libm.abilist
+++ b/sysdeps/unix/sysv/linux/sh/libm.abilist
@@ -381,7 +381,9 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 exp2l F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc32/libm.abilist b/sysdeps/unix/sysv/linux/sparc/sparc32/libm.abilist
index dd5390c313..27166beb55 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc32/libm.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc32/libm.abilist
@@ -414,7 +414,9 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
 GLIBC_2.4 __clog10l F
diff --git a/sysdeps/unix/sysv/linux/sparc/sparc64/libm.abilist b/sysdeps/unix/sysv/linux/sparc/sparc64/libm.abilist
index 394c29b9b5..46f7973465 100644
--- a/sysdeps/unix/sysv/linux/sparc/sparc64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/sparc/sparc64/libm.abilist
@@ -412,6 +412,8 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libm.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libm.abilist
index d66c886ca5..ec6f0b3600 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libm.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx32/libm.abilist
@@ -381,5 +381,7 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
diff --git a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libm.abilist b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libm.abilist
index d66c886ca5..ec6f0b3600 100644
--- a/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilegx/tilegx64/libm.abilist
@@ -381,5 +381,7 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
diff --git a/sysdeps/unix/sysv/linux/tile/tilepro/libm.abilist b/sysdeps/unix/sysv/linux/tile/tilepro/libm.abilist
index d66c886ca5..ec6f0b3600 100644
--- a/sysdeps/unix/sysv/linux/tile/tilepro/libm.abilist
+++ b/sysdeps/unix/sysv/linux/tile/tilepro/libm.abilist
@@ -381,5 +381,7 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
diff --git a/sysdeps/unix/sysv/linux/x86_64/64/libm.abilist b/sysdeps/unix/sysv/linux/x86_64/64/libm.abilist
index dd79dc4626..65e5baed84 100644
--- a/sysdeps/unix/sysv/linux/x86_64/64/libm.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/64/libm.abilist
@@ -412,6 +412,8 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
 GLIBC_2.4 GLIBC_2.4 A
diff --git a/sysdeps/unix/sysv/linux/x86_64/x32/libm.abilist b/sysdeps/unix/sysv/linux/x86_64/x32/libm.abilist
index 45abb4fa71..ff520cb084 100644
--- a/sysdeps/unix/sysv/linux/x86_64/x32/libm.abilist
+++ b/sysdeps/unix/sysv/linux/x86_64/x32/libm.abilist
@@ -411,5 +411,7 @@ GLIBC_2.24 nextup F
 GLIBC_2.24 nextupf F
 GLIBC_2.24 nextupl F
 GLIBC_2.25 GLIBC_2.25 A
+GLIBC_2.25 fegetmode F
 GLIBC_2.25 fesetexcept F
+GLIBC_2.25 fesetmode F
 GLIBC_2.25 fetestexceptflag F
diff --git a/sysdeps/x86/fpu/bits/fenv.h b/sysdeps/x86/fpu/bits/fenv.h
index 8c8503bd7e..688407281c 100644
--- a/sysdeps/x86/fpu/bits/fenv.h
+++ b/sysdeps/x86/fpu/bits/fenv.h
@@ -101,6 +101,20 @@ fenv_t;
 # define FE_NOMASK_ENV	((const fenv_t *) -2)
 #endif
 
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Type representing floating-point control modes.  */
+typedef struct
+  {
+    unsigned short int __control_word;
+    unsigned short int __glibc_reserved;
+    unsigned int __mxcsr;
+  }
+femode_t;
+
+/* Default floating-point control modes.  */
+# define FE_DFL_MODE	((const femode_t *) -1L)
+#endif
+
 
 #ifdef __USE_EXTERN_INLINES
 __BEGIN_DECLS
diff --git a/sysdeps/x86_64/fpu/fegetmode.c b/sysdeps/x86_64/fpu/fegetmode.c
new file mode 100644
index 0000000000..f4a179d36b
--- /dev/null
+++ b/sysdeps/x86_64/fpu/fegetmode.c
@@ -0,0 +1,28 @@
+/* Store current floating-point control modes.  x86_64 version.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+
+int
+fegetmode (femode_t *modep)
+{
+  _FPU_GETCW (modep->__control_word);
+  __asm__ ("stmxcsr %0" : "=m" (modep->__mxcsr));
+  return 0;
+}
diff --git a/sysdeps/x86_64/fpu/fesetmode.c b/sysdeps/x86_64/fpu/fesetmode.c
new file mode 100644
index 0000000000..19173f91cb
--- /dev/null
+++ b/sysdeps/x86_64/fpu/fesetmode.c
@@ -0,0 +1,50 @@
+/* Install given floating-point control modes.  x86_64 version.
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <fenv.h>
+#include <fpu_control.h>
+
+/* All exceptions, including the x86-specific "denormal operand"
+   exception.  */
+#define FE_ALL_EXCEPT_X86 (FE_ALL_EXCEPT | __FE_DENORM)
+
+int
+fesetmode (const femode_t *modep)
+{
+  fpu_control_t cw;
+  unsigned int mxcsr;
+  __asm__ ("stmxcsr %0" : "=m" (mxcsr));
+  /* Preserve SSE exception flags but restore other state in
+     MXCSR.  */
+  mxcsr &= FE_ALL_EXCEPT_X86;
+  if (modep == FE_DFL_MODE)
+    {
+      cw = _FPU_DEFAULT;
+      /* Default MXCSR state has all bits zero except for those
+	 masking exceptions.  */
+      mxcsr |= FE_ALL_EXCEPT_X86 << 7;
+    }
+  else
+    {
+      cw = modep->__control_word;
+      mxcsr |= modep->__mxcsr & ~FE_ALL_EXCEPT_X86;
+    }
+  _FPU_SETCW (cw);
+  __asm__ ("ldmxcsr %0" : : "m" (mxcsr));
+  return 0;
+}