aboutsummaryrefslogtreecommitdiff
path: root/math
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 /math
parentfb0f7a6755c1bfaec38f490fbfcaa39a66ee3604 (diff)
downloadglibc-ec94343f592df68ba1ba49bb2c558f7d2629387c.zip
glibc-ec94343f592df68ba1ba49bb2c558f7d2629387c.tar.gz
glibc-ec94343f592df68ba1ba49bb2c558f7d2629387c.tar.bz2
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 'math')
-rw-r--r--math/Makefile6
-rw-r--r--math/Versions2
-rw-r--r--math/fegetmode.c27
-rw-r--r--math/fenv.h18
-rw-r--r--math/fesetmode.c27
-rw-r--r--math/test-femode-traps.c149
-rw-r--r--math/test-femode.c231
7 files changed, 457 insertions, 3 deletions
diff --git a/math/Makefile b/math/Makefile
index 6a90a36..fc48960 100644
--- a/math/Makefile
+++ b/math/Makefile
@@ -41,7 +41,8 @@ libm-support = s_lib_version s_matherr s_signgam \
fclrexcpt fgetexcptflg fraiseexcpt fsetexcptflg \
ftestexcept fegetround fesetround fegetenv feholdexcpt \
fesetenv feupdateenv t_exp fedisblxcpt feenablxcpt \
- fegetexcept fesetexcept fetestexceptflag
+ fegetexcept fesetexcept fetestexceptflag fegetmode \
+ fesetmode
# Wrappers for these functions generated per type using a file named
# <func>_template.c and the appropriate math-type-macros-<TYPE>.h.
@@ -152,7 +153,8 @@ tests = test-matherr test-fenv atest-exp atest-sincos atest-exp2 basic-test \
test-signgam-uint test-signgam-uint-init test-signgam-ullong \
test-signgam-ullong-init test-nan-overflow test-nan-payload \
test-fexcept test-fexcept-traps test-fesetexcept \
- test-fesetexcept-traps test-fetestexceptflag $(tests-static)
+ test-fesetexcept-traps test-fetestexceptflag test-femode \
+ test-femode-traps $(tests-static)
tests-static = test-fpucw-static test-fpucw-ieee-static \
test-signgam-uchar-static test-signgam-uchar-init-static \
test-signgam-uint-static test-signgam-uint-init-static \
diff --git a/math/Versions b/math/Versions
index 1c1683f..a429221 100644
--- a/math/Versions
+++ b/math/Versions
@@ -215,6 +215,6 @@ libm {
nextdown; nextdownf; nextdownl;
}
GLIBC_2.25 {
- fesetexcept; fetestexceptflag;
+ fesetexcept; fetestexceptflag; fegetmode; fesetmode;
}
}
diff --git a/math/fegetmode.c b/math/fegetmode.c
new file mode 100644
index 0000000..25f299f
--- /dev/null
+++ b/math/fegetmode.c
@@ -0,0 +1,27 @@
+/* Store current floating-point control modes.
+ 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>
+
+int
+fegetmode (femode_t *modep)
+{
+ /* Nothing to do. */
+ return 0;
+}
+stub_warning (fegetmode)
diff --git a/math/fenv.h b/math/fenv.h
index 10d32db..9006aa2 100644
--- a/math/fenv.h
+++ b/math/fenv.h
@@ -38,6 +38,12 @@
fexcept_t type for object representing the floating-point exception
flags including status associated with the flags
+ femode_t type for object representing floating-point control modes
+
+ FE_DFL_MODE macro of type pointer to const femode_t to be used as the
+ argument to fesetmode; in this case the default control
+ modes will be used
+
The following macros are defined iff the implementation supports this
kind of exception.
FE_INEXACT inexact result
@@ -122,6 +128,18 @@ extern int fesetenv (const fenv_t *__envp) __THROW;
extern int feupdateenv (const fenv_t *__envp) __THROW;
+/* Control modes. */
+
+#if __GLIBC_USE (IEC_60559_BFP_EXT)
+/* Store the current floating-point control modes in the object
+ pointed to by MODEP. */
+extern int fegetmode (femode_t *__modep) __THROW;
+
+/* Establish the floating-point control modes represented by the
+ object pointed to by MODEP. */
+extern int fesetmode (const femode_t *__modep) __THROW;
+#endif
+
/* Include optimization. */
#ifdef __OPTIMIZE__
# include <bits/fenvinline.h>
diff --git a/math/fesetmode.c b/math/fesetmode.c
new file mode 100644
index 0000000..0d040e4
--- /dev/null
+++ b/math/fesetmode.c
@@ -0,0 +1,27 @@
+/* Install given floating-point control modes.
+ 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>
+
+int
+fesetmode (const femode_t *modep)
+{
+ /* Nothing to do. */
+ return 0;
+}
+stub_warning (fesetmode)
diff --git a/math/test-femode-traps.c b/math/test-femode-traps.c
new file mode 100644
index 0000000..dd22765
--- /dev/null
+++ b/math/test-femode-traps.c
@@ -0,0 +1,149 @@
+/* Test femode_t functions: test handling of exception traps.
+ 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 <stdio.h>
+#include <math-tests.h>
+
+static int
+test_ee (int exc1, int exc2)
+{
+ int result = 0;
+ printf ("testing %x %x\n", (unsigned int) exc1, (unsigned int) exc2);
+
+ fedisableexcept (FE_ALL_EXCEPT);
+ int ret = feenableexcept (exc1);
+ if (ret == -1)
+ {
+ if (EXCEPTION_ENABLE_SUPPORTED (exc1))
+ {
+ puts ("first feenableexcept failed unexpectedly");
+ result = 1;
+ }
+ else
+ puts ("first feenableexcept failed, cannot test");
+ return result;
+ }
+ femode_t saved;
+ ret = fegetmode (&saved);
+ if (ret != 0)
+ {
+ puts ("fegetmode failed");
+ result = 1;
+ return result;
+ }
+ fedisableexcept (FE_ALL_EXCEPT);
+ ret = feenableexcept (exc2);
+ if (ret == -1)
+ {
+ if (EXCEPTION_ENABLE_SUPPORTED (exc2))
+ {
+ puts ("second feenableexcept failed unexpectedly");
+ result = 1;
+ }
+ else
+ puts ("second feenableexcept failed, cannot test");
+ return result;
+ }
+ ret = fesetmode (&saved);
+ if (ret != 0)
+ {
+ puts ("fesetmode failed");
+ result = 1;
+ return result;
+ }
+ /* Verify that the set of enabled traps was restored. */
+ ret = fegetexcept ();
+ if (ret != exc1)
+ {
+ printf ("restored enabled traps %x not %x\n", (unsigned int) ret,
+ (unsigned int) exc1);
+ result = 1;
+ }
+ /* Likewise, with default modes. */
+ ret = fesetmode (FE_DFL_MODE);
+ if (ret != 0)
+ {
+ puts ("fesetmode (FE_DFL_MODE) failed");
+ result = 1;
+ return result;
+ }
+ ret = fegetexcept ();
+ if (ret != 0)
+ {
+ printf ("FE_DFL_MODE enabled traps %x not 0\n", (unsigned int) ret);
+ result = 1;
+ }
+
+ return result;
+}
+
+static int
+test_e (int exc1)
+{
+ int result = 0;
+
+ result |= test_ee (exc1, 0);
+ result |= test_ee (exc1, FE_ALL_EXCEPT);
+#ifdef FE_DIVBYZERO
+ result |= test_ee (exc1, FE_DIVBYZERO);
+#endif
+#ifdef FE_INEXACT
+ result |= test_ee (exc1, FE_INEXACT);
+#endif
+#ifdef FE_INVALID
+ result |= test_ee (exc1, FE_INVALID);
+#endif
+#ifdef FE_OVERFLOW
+ result |= test_ee (exc1, FE_OVERFLOW);
+#endif
+#ifdef FE_UNDERFLOW
+ result |= test_ee (exc1, FE_UNDERFLOW);
+#endif
+
+ return result;
+}
+
+static int
+do_test (void)
+{
+ int result = 0;
+
+ result |= test_e (0);
+ result |= test_e (FE_ALL_EXCEPT);
+#ifdef FE_DIVBYZERO
+ result |= test_e (FE_DIVBYZERO);
+#endif
+#ifdef FE_INEXACT
+ result |= test_e (FE_INEXACT);
+#endif
+#ifdef FE_INVALID
+ result |= test_e (FE_INVALID);
+#endif
+#ifdef FE_OVERFLOW
+ result |= test_e (FE_OVERFLOW);
+#endif
+#ifdef FE_UNDERFLOW
+ result |= test_e (FE_UNDERFLOW);
+#endif
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"
diff --git a/math/test-femode.c b/math/test-femode.c
new file mode 100644
index 0000000..1e80f32
--- /dev/null
+++ b/math/test-femode.c
@@ -0,0 +1,231 @@
+/* Test femode_t functions.
+ 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 <stdio.h>
+#include <math-tests.h>
+
+static int
+test_mmee (int mode1, int mode2, int exc1, int exc2)
+{
+ int result = 0;
+ printf ("testing %x %x %x %x\n", (unsigned int) mode1, (unsigned int) mode2,
+ (unsigned int) exc1, (unsigned int) exc2);
+
+ feclearexcept (FE_ALL_EXCEPT);
+ int ret = fesetround (mode1);
+ if (ret != 0)
+ {
+ if (ROUNDING_TESTS (float, mode1))
+ {
+ puts ("first fesetround failed unexpectedly");
+ result = 1;
+ }
+ else
+ puts ("first fesetround failed, cannot test");
+ return result;
+ }
+ ret = fesetexcept (exc1);
+ if (ret != 0)
+ {
+ if (EXCEPTION_TESTS (float) || exc1 == 0)
+ {
+ puts ("first fesetexcept failed unexpectedly");
+ result = 1;
+ }
+ else
+ puts ("first fesetexcept failed, cannot test");
+ return result;
+ }
+ femode_t saved;
+ ret = fegetmode (&saved);
+ if (ret != 0)
+ {
+ puts ("fegetmode failed");
+ result = 1;
+ return result;
+ }
+ feclearexcept (FE_ALL_EXCEPT);
+ ret = fesetround (mode2);
+ if (ret != 0)
+ {
+ if (ROUNDING_TESTS (float, mode2))
+ {
+ puts ("second fesetround failed unexpectedly");
+ result = 1;
+ }
+ else
+ puts ("second fesetround failed, cannot test");
+ return result;
+ }
+ ret = fesetexcept (exc2);
+ if (ret != 0)
+ {
+ if (EXCEPTION_TESTS (float) || exc2 == 0)
+ {
+ puts ("second fesetexcept failed unexpectedly");
+ result = 1;
+ }
+ else
+ puts ("second fesetexcept failed, cannot test");
+ return result;
+ }
+ ret = fesetmode (&saved);
+ if (ret != 0)
+ {
+ puts ("fesetmode failed");
+ result = 1;
+ return result;
+ }
+ /* Verify that the rounding mode was restored but the exception
+ flags remain unchanged. */
+ ret = fegetround ();
+ if (ret != mode1)
+ {
+ printf ("restored rounding mode %x not %x\n", (unsigned int) ret,
+ (unsigned int) mode1);
+ result = 1;
+ }
+ ret = fetestexcept (FE_ALL_EXCEPT);
+ if (ret != exc2)
+ {
+ printf ("exceptions %x not %x\n", (unsigned int) ret,
+ (unsigned int) exc2);
+ result = 1;
+ }
+ /* Likewise, with default modes. */
+ ret = fesetmode (FE_DFL_MODE);
+ if (ret != 0)
+ {
+ puts ("fesetmode (FE_DFL_MODE) failed");
+ result = 1;
+ return result;
+ }
+ ret = fegetround ();
+ if (ret != FE_TONEAREST)
+ {
+ printf ("FE_DFL_MODE rounding mode %x not %x\n", (unsigned int) ret,
+ (unsigned int) FE_TONEAREST);
+ result = 1;
+ }
+ ret = fetestexcept (FE_ALL_EXCEPT);
+ if (ret != exc2)
+ {
+ printf ("FE_DFL_MODE exceptions %x not %x\n", (unsigned int) ret,
+ (unsigned int) exc2);
+ result = 1;
+ }
+ return result;
+}
+
+static int
+test_mme (int mode1, int mode2, int exc1)
+{
+ int result = 0;
+
+ result |= test_mmee (mode1, mode2, exc1, 0);
+ result |= test_mmee (mode1, mode2, exc1, FE_ALL_EXCEPT);
+#ifdef FE_DIVBYZERO
+ result |= test_mmee (mode1, mode2, exc1, FE_DIVBYZERO);
+#endif
+#ifdef FE_INEXACT
+ result |= test_mmee (mode1, mode2, exc1, FE_INEXACT);
+#endif
+#ifdef FE_INVALID
+ result |= test_mmee (mode1, mode2, exc1, FE_INVALID);
+#endif
+#ifdef FE_OVERFLOW
+ result |= test_mmee (mode1, mode2, exc1, FE_OVERFLOW);
+#endif
+#ifdef FE_UNDERFLOW
+ result |= test_mmee (mode1, mode2, exc1, FE_UNDERFLOW);
+#endif
+
+ return result;
+}
+
+static int
+test_mm (int mode1, int mode2)
+{
+ int result = 0;
+
+ result |= test_mme (mode1, mode2, 0);
+ result |= test_mme (mode1, mode2, FE_ALL_EXCEPT);
+#ifdef FE_DIVBYZERO
+ result |= test_mme (mode1, mode2, FE_DIVBYZERO);
+#endif
+#ifdef FE_INEXACT
+ result |= test_mme (mode1, mode2, FE_INEXACT);
+#endif
+#ifdef FE_INVALID
+ result |= test_mme (mode1, mode2, FE_INVALID);
+#endif
+#ifdef FE_OVERFLOW
+ result |= test_mme (mode1, mode2, FE_OVERFLOW);
+#endif
+#ifdef FE_UNDERFLOW
+ result |= test_mme (mode1, mode2, FE_UNDERFLOW);
+#endif
+
+ return result;
+}
+
+static int
+test_m (int mode1)
+{
+ int result = 0;
+
+#ifdef FE_DOWNWARD
+ result |= test_mm (mode1, FE_DOWNWARD);
+#endif
+#ifdef FE_TONEAREST
+ result |= test_mm (mode1, FE_TONEAREST);
+#endif
+#ifdef FE_TOWARDZERO
+ result |= test_mm (mode1, FE_TOWARDZERO);
+#endif
+#ifdef FE_UPWARD
+ result |= test_mm (mode1, FE_UPWARD);
+#endif
+
+ return result;
+}
+
+static int
+do_test (void)
+{
+ int result = 0;
+
+#ifdef FE_DOWNWARD
+ result |= test_m (FE_DOWNWARD);
+#endif
+#ifdef FE_TONEAREST
+ result |= test_m (FE_TONEAREST);
+#endif
+#ifdef FE_TOWARDZERO
+ result |= test_m (FE_TOWARDZERO);
+#endif
+#ifdef FE_UPWARD
+ result |= test_m (FE_UPWARD);
+#endif
+
+ return result;
+}
+
+#define TEST_FUNCTION do_test ()
+#include "../test-skeleton.c"