]> Savannah Git Hosting - gnulib.git/commitdiff
fenv-exceptions-trapping: New module.
authorBruno Haible <bruno@clisp.org>
Tue, 31 Oct 2023 20:46:13 +0000 (21:46 +0100)
committerBruno Haible <bruno@clisp.org>
Tue, 31 Oct 2023 20:54:20 +0000 (21:54 +0100)
* lib/fenv.in.h (feenableexcept, fedisableexcept, fegetexcept): New
declarations.
* lib/fenv-except-trapping.c: New file, based on glibc.
* m4/fenv_h.m4 (gl_FENV_H): Test also whether fegetexcept is declared.
* m4/fenv-exceptions-trapping.m4: New file.
* modules/fenv-exceptions-trapping: New file.
* doc/glibc-functions/fegetexcept.texi: Mention the new module.
* doc/glibc-functions/fedisableexcept.texi: Likewise.
* doc/glibc-functions/feenableexcept.texi: Likewise. Mention the glibc,
macOS, FreeBSD bugs.

ChangeLog
doc/glibc-functions/fedisableexcept.texi
doc/glibc-functions/feenableexcept.texi
doc/glibc-functions/fegetexcept.texi
lib/fenv-except-trapping.c [new file with mode: 0644]
lib/fenv.in.h
m4/fenv-exceptions-trapping.m4 [new file with mode: 0644]
m4/fenv_h.m4
modules/fenv-exceptions-trapping [new file with mode: 0644]

index 0476828c50fc864fbd9106d870b551b55a9eff56..f7d1a2237e600d7b9f8bf491a7a2ce0e3f7d6299 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,17 @@
+2023-10-31  Bruno Haible  <bruno@clisp.org>
+
+       fenv-exceptions-trapping: New module.
+       * lib/fenv.in.h (feenableexcept, fedisableexcept, fegetexcept): New
+       declarations.
+       * lib/fenv-except-trapping.c: New file, based on glibc.
+       * m4/fenv_h.m4 (gl_FENV_H): Test also whether fegetexcept is declared.
+       * m4/fenv-exceptions-trapping.m4: New file.
+       * modules/fenv-exceptions-trapping: New file.
+       * doc/glibc-functions/fegetexcept.texi: Mention the new module.
+       * doc/glibc-functions/fedisableexcept.texi: Likewise.
+       * doc/glibc-functions/feenableexcept.texi: Likewise. Mention the glibc,
+       macOS, FreeBSD bugs.
+
 2023-10-30  Bruno Haible  <bruno@clisp.org>
 
        fenv-exceptions-state-c99: Fix the x86_64 and i386 case.
index 8b41ae4d878c4e42a5bc57cafbd61ea269db62d9..d26397f44f2c964302c54d133b15641a5bc5b25f 100644 (file)
@@ -17,15 +17,15 @@ Documentation:
 @uref{https://www.kernel.org/doc/man-pages/online/pages/man3/fedisableexcept.3.html,,man fedisableexcept}.
 @end itemize
 
-Gnulib module: ---
+Gnulib module: fenv-exceptions-trapping
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+This function is missing on some platforms:
+macOS 11.1, musl libc, FreeBSD 5.2.1, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 11.4, Cygwin 1.7.7, mingw, MSVC 14, Android 4.4.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-This function is missing on some platforms:
-macOS 11.1, FreeBSD 5.2.1, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 11.4, Cygwin 1.7.7, mingw, MSVC 14, Android 4.4.
 @end itemize
index dfca91f2a7f5d39375f336e6efb06af8c2d14a9a..a858b4d6c6f2a9b5d5faa4475af28185bfeff26c 100644 (file)
@@ -17,15 +17,22 @@ Documentation:
 @uref{https://www.kernel.org/doc/man-pages/online/pages/man3/feenableexcept.3.html,,man feenableexcept}.
 @end itemize
 
-Gnulib module: ---
+Gnulib module: fenv-exceptions-trapping
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+This function is missing on some platforms:
+macOS 11.1, musl libc, FreeBSD 5.2.1, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 11.4, Cygwin 1.7.7, mingw, MSVC 14, Android 4.4.
+@item
+This function does not detect failures on
+glibc 2.19/aarch64, FreeBSD 12.2/arm, FreeBSD 12.2/arm64.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
 @item
-This function is missing on some platforms:
-macOS 11.1, FreeBSD 5.2.1, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 11.4, Cygwin 1.7.7, mingw, MSVC 14, Android 4.4.
+The resulting signal is @code{SIGILL} instead of @code{SIGFPE}
+on some platforms:
+macOS 12.5/arm64.
 @end itemize
index e3e3e43959bbbc7128a2f2d9758ccd4b41f6bb11..eaa1882d839e11c367d3f5e0e90d4e4c8d339f5f 100644 (file)
@@ -17,15 +17,15 @@ Documentation:
 @uref{https://www.kernel.org/doc/man-pages/online/pages/man3/fegetexcept.3.html,,man fegetexcept}.
 @end itemize
 
-Gnulib module: ---
+Gnulib module: fenv-exceptions-trapping
 
 Portability problems fixed by Gnulib:
 @itemize
+@item
+This function is missing on many non-glibc platforms:
+macOS 11.1, musl libc, FreeBSD 13.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 11.4, Cygwin 1.7.7, mingw, MSVC 14, Android 4.4.
 @end itemize
 
 Portability problems not fixed by Gnulib:
 @itemize
-@item
-This function is missing on many non-glibc platforms:
-macOS 11.1, FreeBSD 13.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, HP-UX 11, IRIX 6.5, Solaris 11.4, Cygwin 1.7.7, mingw, MSVC 14, Android 4.4.
 @end itemize
diff --git a/lib/fenv-except-trapping.c b/lib/fenv-except-trapping.c
new file mode 100644 (file)
index 0000000..a86cbd2
--- /dev/null
@@ -0,0 +1,951 @@
+/* Functions for turning floating-point exceptions into traps (signals).
+   Copyright (C) 1997-2023 Free Software Foundation, Inc.
+
+   This file 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.
+
+   This file 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 this program.  If not, see <https://www.gnu.org/licenses/>.  */
+
+/* Based on glibc/sysdeps/<cpu>/{feenablxcpt.c,fedisblxcpt.c,fegetexcept.c}
+   together with glibc/sysdeps/<cpu>/{fpu_control.h,fenv_private.h,fenv_libc.h}.  */
+
+#include <config.h>
+
+/* Specification.  */
+#include <fenv.h>
+
+#include "fenv-private.h"
+
+#if defined __GNUC__ || defined __clang__ || defined _MSC_VER
+
+# if (defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86)
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+#  if defined _MSC_VER
+
+  exceptions = exceptions_to_x86hardware (exceptions);
+
+  /* Enable the traps only in the SSE unit.  */
+  unsigned int mxcsr, orig_mxcsr;
+  _FPU_GETSSECW (orig_mxcsr);
+  mxcsr = orig_mxcsr & ~(exceptions << 7);
+  if (mxcsr != orig_mxcsr)
+    _FPU_SETSSECW (mxcsr);
+
+  unsigned int trapbits = 0x3f & ~(orig_mxcsr >> 7);
+  return x86hardware_to_exceptions (trapbits);
+
+#  else
+
+  /* Enable the traps in the 387 unit.  */
+  unsigned short fctrl, orig_fctrl;
+  _FPU_GETCW (orig_fctrl);
+  fctrl = orig_fctrl & ~exceptions;
+  if (fctrl != orig_fctrl)
+    _FPU_SETCW (fctrl);
+
+  if (CPU_HAS_SSE ())
+    {
+      /* Enable the traps in the SSE unit as well.  */
+      unsigned int mxcsr, orig_mxcsr;
+      _FPU_GETSSECW (orig_mxcsr);
+      mxcsr = orig_mxcsr & ~(exceptions << 7);
+      if (mxcsr != orig_mxcsr)
+        _FPU_SETSSECW (mxcsr);
+    }
+
+  return FE_ALL_EXCEPT & ~orig_fctrl;
+
+#  endif
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+#  if defined _MSC_VER
+
+  exceptions = exceptions_to_x86hardware (exceptions);
+
+  /* Disable the traps only in the SSE unit.  */
+  unsigned int mxcsr, orig_mxcsr;
+  _FPU_GETSSECW (orig_mxcsr);
+  mxcsr = orig_mxcsr | (exceptions << 7);
+  if (mxcsr != orig_mxcsr)
+    _FPU_SETSSECW (mxcsr);
+
+  unsigned int trapbits = 0x3f & ~(orig_mxcsr >> 7);
+  return x86hardware_to_exceptions (trapbits);
+
+#  else
+
+  /* Disable the traps in the 387 unit.  */
+  unsigned short fctrl, orig_fctrl;
+  _FPU_GETCW (orig_fctrl);
+  fctrl = orig_fctrl | exceptions;
+  if (fctrl != orig_fctrl)
+    _FPU_SETCW (fctrl);
+
+  if (CPU_HAS_SSE ())
+    {
+      /* Disable the traps in the SSE unit as well.  */
+      unsigned int mxcsr, orig_mxcsr;
+      _FPU_GETSSECW (orig_mxcsr);
+      mxcsr = orig_mxcsr | (exceptions << 7);
+      if (mxcsr != orig_mxcsr)
+        _FPU_SETSSECW (mxcsr);
+    }
+
+  return FE_ALL_EXCEPT & ~orig_fctrl;
+
+#  endif
+}
+
+int
+fegetexcept (void)
+{
+#  if defined _MSC_VER
+  /* Look at the trap bits in the SSE unit.  */
+  unsigned int mxcsr;
+  _FPU_GETSSECW (mxcsr);
+  unsigned int trapbits = 0x3f & ~(mxcsr >> 7);
+  return x86hardware_to_exceptions (trapbits);
+#  else
+  /* Look at the trap bits in the 387 unit.  */
+  unsigned short fctrl;
+  _FPU_GETCW (fctrl);
+  return FE_ALL_EXCEPT & ~fctrl;
+#  endif
+}
+
+# elif defined __aarch64__ /* arm64 */
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned long fpcr, orig_fpcr;
+  _FPU_GETCW (orig_fpcr);
+  fpcr = orig_fpcr | (exceptions << 8);
+  if (fpcr != orig_fpcr)
+    {
+      _FPU_SETCW (fpcr);
+      /* Test whether fpcr was actually changed as desired.  */
+      unsigned long new_fpcr;
+      _FPU_GETCW (new_fpcr);
+      if (new_fpcr != fpcr)
+        return -1;
+    }
+
+  return FE_ALL_EXCEPT & (orig_fpcr >> 8);
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned long fpcr, orig_fpcr;
+  _FPU_GETCW (orig_fpcr);
+  fpcr = orig_fpcr & ~(exceptions << 8);
+  if (fpcr != orig_fpcr)
+    {
+      _FPU_SETCW (fpcr);
+      /* Testing whether fpcr was actually changed as desired is not needed
+         here, since we only cleared some bits.  */
+    }
+
+  return FE_ALL_EXCEPT & (orig_fpcr >> 8);
+}
+
+int
+fegetexcept (void)
+{
+  unsigned long fpcr;
+  _FPU_GETCW (fpcr);
+  return FE_ALL_EXCEPT & (fpcr >> 8);
+}
+
+# elif defined __arm__
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+#  ifdef __SOFTFP__
+  if (exceptions != 0)
+    return -1;
+  return 0;
+#  else
+  unsigned int fpscr, orig_fpscr;
+  _FPU_GETCW (orig_fpscr);
+  fpscr = orig_fpscr | (exceptions << 8);
+  if (fpscr != orig_fpscr)
+    {
+      _FPU_SETCW (fpscr);
+      /* Test whether fpscr was actually changed as desired.  */
+      unsigned int new_fpscr;
+      _FPU_GETCW (new_fpscr);
+      if (new_fpscr != fpscr)
+        return -1;
+    }
+
+  return FE_ALL_EXCEPT & (orig_fpscr >> 8);
+#  endif
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+#  ifdef __SOFTFP__
+  return 0;
+#  else
+  unsigned int fpscr, orig_fpscr;
+  _FPU_GETCW (orig_fpscr);
+  fpscr = orig_fpscr & ~(exceptions << 8);
+  if (fpscr != orig_fpscr)
+    {
+      _FPU_SETCW (fpscr);
+      /* Testing whether fpscr was actually changed as desired is not needed
+         here, since we only cleared some bits.  */
+    }
+
+  return FE_ALL_EXCEPT & (orig_fpscr >> 8);
+#  endif
+}
+
+int
+fegetexcept (void)
+{
+#  ifdef __SOFTFP__
+  return 0;
+#  else
+  unsigned int fpscr;
+  _FPU_GETCW (fpscr);
+  return FE_ALL_EXCEPT & (fpscr >> 8);
+#  endif
+}
+
+# elif defined __alpha
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned long swcr, orig_swcr;
+  orig_swcr = __ieee_get_fp_control ();
+  swcr = orig_swcr | ((unsigned long) exceptions >> 16);
+  if (swcr != orig_swcr)
+    __ieee_set_fp_control (swcr);
+
+  return FE_ALL_EXCEPT & (orig_swcr << 16);
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned long swcr, orig_swcr;
+  orig_swcr = __ieee_get_fp_control ();
+  swcr = orig_swcr & ~((unsigned long) exceptions >> 16);
+  if (swcr != orig_swcr)
+    __ieee_set_fp_control (swcr);
+
+  return FE_ALL_EXCEPT & (orig_swcr << 16);
+}
+
+int
+fegetexcept (void)
+{
+  unsigned long swcr = __ieee_get_fp_control ();
+  return FE_ALL_EXCEPT & (swcr << 16);
+}
+
+# elif defined __hppa
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  union { unsigned long long fpreg; unsigned int halfreg[2]; } s;
+  /* Get the current status word. */
+  __asm__ __volatile__ ("fstd %%fr0,0(%1)" : "=m" (s.fpreg) : "r" (&s.fpreg) : "%r0");
+  unsigned int old_halfreg0 = s.halfreg[0];
+  /* Set all the relevant bits. */
+  s.halfreg[0] |= (unsigned int) exceptions;
+  if (s.halfreg[0] != old_halfreg0)
+    {
+      /* Store the new status word.  */
+      __asm__ __volatile__ ("fldd 0(%0),%%fr0" : : "r" (&s.fpreg), "m" (s.fpreg) : "%r0");
+    }
+
+  return FE_ALL_EXCEPT & old_halfreg0;
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  union { unsigned long long fpreg; unsigned int halfreg[2]; } s;
+  /* Get the current status word. */
+  __asm__ __volatile__ ("fstd %%fr0,0(%1)" : "=m" (s.fpreg) : "r" (&s.fpreg) : "%r0");
+  unsigned int old_halfreg0 = s.halfreg[0];
+  /* Clear all the relevant bits. */
+  s.halfreg[0] &= ~ (unsigned int) exceptions;
+  if (s.halfreg[0] != old_halfreg0)
+    {
+      /* Store the new status word.  */
+      __asm__ __volatile__ ("fldd 0(%0),%%fr0" : : "r" (&s.fpreg), "m" (s.fpreg) : "%r0");
+    }
+
+  return FE_ALL_EXCEPT & old_halfreg0;
+}
+
+int
+fegetexcept (void)
+{
+  union { unsigned long long fpreg; unsigned int halfreg[2]; } s;
+  /* Get the current status word. */
+  __asm__ __volatile__ ("fstd %%fr0,0(%1)" : "=m" (s.fpreg) : "r" (&s.fpreg) : "%r0");
+
+  return FE_ALL_EXCEPT & s.halfreg[0];
+}
+
+# elif defined __ia64__
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned long fpsr, orig_fpsr;
+  _FPU_GETCW (orig_fpsr);
+  fpsr = orig_fpsr & ~ (unsigned long) exceptions;
+  if (fpsr != orig_fpsr)
+    _FPU_SETCW (fpsr);
+
+  return FE_ALL_EXCEPT & ~orig_fpsr;
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned long fpsr, orig_fpsr;
+  _FPU_GETCW (orig_fpsr);
+  fpsr = orig_fpsr | (unsigned long) exceptions;
+  if (fpsr != orig_fpsr)
+    _FPU_SETCW (fpsr);
+
+  return FE_ALL_EXCEPT & ~orig_fpsr;
+}
+
+int
+fegetexcept (void)
+{
+  unsigned long fpsr;
+  _FPU_GETCW (fpsr);
+  return FE_ALL_EXCEPT & ~fpsr;
+}
+
+# elif defined __m68k__
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned int fpcr, orig_fpcr;
+  _FPU_GETCW (orig_fpcr);
+  fpcr = orig_fpcr | ((exceptions << 6) | (exceptions & FE_INVALID ? 0xc000 : 0));
+  if (fpcr != orig_fpcr)
+    _FPU_SETCW (fpcr);
+
+  return FE_ALL_EXCEPT & (orig_fpcr >> 6);
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned int fpcr, orig_fpcr;
+  _FPU_GETCW (orig_fpcr);
+  fpcr = orig_fpcr & ~ ((exceptions << 6) | (exceptions & FE_INVALID ? 0xc000 : 0));
+  if (fpcr != orig_fpcr)
+    _FPU_SETCW (fpcr);
+
+  return FE_ALL_EXCEPT & (orig_fpcr >> 6);
+}
+
+int
+fegetexcept (void)
+{
+  unsigned int fpcr;
+  _FPU_GETCW (fpcr);
+  return FE_ALL_EXCEPT & (fpcr >> 6);
+}
+
+# elif defined __mips__
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned int fcsr, orig_fcsr;
+  _FPU_GETCW (orig_fcsr);
+  fcsr = orig_fcsr | (exceptions << 5);
+  if (fcsr != orig_fcsr)
+    _FPU_SETCW (fcsr);
+
+  return FE_ALL_EXCEPT & (orig_fcsr >> 5);
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned int fcsr, orig_fcsr;
+  _FPU_GETCW (orig_fcsr);
+  fcsr = orig_fcsr & ~ (exceptions << 5);
+  if (fcsr != orig_fcsr)
+    _FPU_SETCW (fcsr);
+
+  return FE_ALL_EXCEPT & (orig_fcsr >> 5);
+}
+
+int
+fegetexcept (void)
+{
+  unsigned int fcsr;
+  _FPU_GETCW (fcsr);
+  return FE_ALL_EXCEPT & (fcsr >> 5);
+}
+
+# elif defined __loongarch__
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned int fcsr, orig_fcsr;
+  _FPU_GETCW (orig_fcsr);
+  fcsr = orig_fcsr | (exceptions >> 16);
+  if (fcsr != orig_fcsr)
+    _FPU_SETCW (fcsr);
+
+  return FE_ALL_EXCEPT & (orig_fcsr << 16);
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned int fcsr, orig_fcsr;
+  _FPU_GETCW (orig_fcsr);
+  fcsr = orig_fcsr & ~ (exceptions >> 16);
+  if (fcsr != orig_fcsr)
+    _FPU_SETCW (fcsr);
+
+  return FE_ALL_EXCEPT & (orig_fcsr << 16);
+}
+
+int
+fegetexcept (void)
+{
+  unsigned int fcsr;
+  _FPU_GETCW (fcsr);
+  return FE_ALL_EXCEPT & (fcsr << 16);
+}
+
+# elif defined __powerpc__
+
+#  if defined __linux__
+#   include <sys/prctl.h>
+#  elif defined _AIX
+#   include <fptrap.h>
+#  endif
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  union { unsigned long long u; double f; } memenv, orig_memenv;
+  _FPU_GETCW_AS_DOUBLE (memenv.f);
+  orig_memenv = memenv;
+
+  memenv.u |= ((unsigned int) exceptions >> 22);
+
+  if (!(memenv.u == orig_memenv.u))
+    {
+      if ((orig_memenv.u & 0x000000f7) == 0 && (memenv.u & 0x000000f7) != 0)
+        {
+          /* Put the thread into precise trapping mode.  */
+#  if defined __linux__ || defined __NetBSD__
+          prctl (PR_SET_FPEXC, PR_FP_EXC_PRECISE);
+#  elif defined _AIX
+          /* Documentation: <https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-trap-subroutine>  */
+          fp_trap (FP_TRAP_SYNC);
+#  endif
+        }
+
+      _FPU_SETCW_AS_DOUBLE (memenv.f);
+    }
+
+  return FE_ALL_EXCEPT & ((unsigned int) orig_memenv.u << 22);
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  union { unsigned long long u; double f; } memenv, orig_memenv;
+  _FPU_GETCW_AS_DOUBLE (memenv.f);
+  orig_memenv = memenv;
+
+  memenv.u &= ~ ((unsigned int) exceptions >> 22);
+
+  if (!(memenv.u == orig_memenv.u))
+    {
+      _FPU_SETCW_AS_DOUBLE (memenv.f);
+
+      if ((orig_memenv.u & 0x000000f7) != 0 && (memenv.u & 0x000000f7) == 0)
+        {
+          /* Put the thread into no-trapping mode.  */
+#  if defined __linux__ || defined __NetBSD__
+          prctl (PR_SET_FPEXC, PR_FP_EXC_DISABLED);
+#  elif defined _AIX
+          /* Documentation: <https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-trap-subroutine>  */
+          fp_trap (FP_TRAP_OFF);
+#  endif
+        }
+    }
+
+  return FE_ALL_EXCEPT & ((unsigned int) orig_memenv.u << 22);
+}
+
+int
+fegetexcept (void)
+{
+  union { unsigned long long u; double f; } memenv;
+  _FPU_GETCW_AS_DOUBLE (memenv.f);
+
+  return FE_ALL_EXCEPT & ((unsigned int) memenv.u << 22);
+}
+
+# elif defined __riscv
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  if (exceptions != 0)
+    return -1;
+  return 0;
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  return 0;
+}
+
+int
+fegetexcept (void)
+{
+  return 0;
+}
+
+# elif defined __s390__ || defined __s390x__
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned int fpc, orig_fpc;
+  _FPU_GETCW (orig_fpc);
+#  if FE_INEXACT == 8 /* glibc compatible FE_* values */
+  fpc = orig_fpc | ((unsigned int) exceptions << 24);
+#  else /* musl libc compatible FE_* values */
+  fpc = orig_fpc | ((unsigned int) exceptions << 8);
+#  endif
+  if (fpc != orig_fpc)
+    _FPU_SETCW (fpc);
+
+#  if FE_INEXACT == 8 /* glibc compatible FE_* values */
+  return FE_ALL_EXCEPT & (orig_fpc >> 24);
+#  else /* musl libc compatible FE_* values */
+  return FE_ALL_EXCEPT & (orig_fpc >> 8);
+#  endif
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned int fpc, orig_fpc;
+  _FPU_GETCW (orig_fpc);
+#  if FE_INEXACT == 8 /* glibc compatible FE_* values */
+  fpc = orig_fpc & ~((unsigned int) exceptions << 24);
+#  else /* musl libc compatible FE_* values */
+  fpc = orig_fpc & ~((unsigned int) exceptions << 8);
+#  endif
+  if (fpc != orig_fpc)
+    _FPU_SETCW (fpc);
+
+#  if FE_INEXACT == 8 /* glibc compatible FE_* values */
+  return FE_ALL_EXCEPT & (orig_fpc >> 24);
+#  else /* musl libc compatible FE_* values */
+  return FE_ALL_EXCEPT & (orig_fpc >> 8);
+#  endif
+}
+
+int
+fegetexcept (void)
+{
+  unsigned int fpc;
+  _FPU_GETCW (fpc);
+#  if FE_INEXACT == 8 /* glibc compatible FE_* values */
+  return FE_ALL_EXCEPT & (fpc >> 24);
+#  else /* musl libc compatible FE_* values */
+  return FE_ALL_EXCEPT & (fpc >> 8);
+#  endif
+}
+
+# elif defined __sh__
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned int fpscr, orig_fpscr;
+  _FPU_GETCW (orig_fpscr);
+  fpscr = orig_fpscr | ((unsigned int) exceptions << 5);
+  if (fpscr != orig_fpscr)
+    _FPU_SETCW (fpscr);
+
+  return FE_ALL_EXCEPT & (orig_fpscr >> 5);
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned int fpscr, orig_fpscr;
+  _FPU_GETCW (orig_fpscr);
+  fpscr = orig_fpscr & ~ ((unsigned int) exceptions << 5);
+  if (fpscr != orig_fpscr)
+    _FPU_SETCW (fpscr);
+
+  return FE_ALL_EXCEPT & (orig_fpscr >> 5);
+}
+
+int
+fegetexcept (void)
+{
+  unsigned int fpscr;
+  _FPU_GETCW (fpscr);
+  return FE_ALL_EXCEPT & (fpscr >> 5);
+}
+
+# elif defined __sparc
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned long fsr, orig_fsr;
+  _FPU_GETCW (orig_fsr);
+#  if FE_INEXACT == 32 /* glibc compatible FE_* values */
+  fsr = orig_fsr | (exceptions << 18);
+#  else /* Solaris compatible FE_* values */
+  fsr = orig_fsr | (exceptions << 23);
+#  endif
+  if (fsr != orig_fsr)
+    _FPU_SETCW (fsr);
+
+#  if FE_INEXACT == 32 /* glibc compatible FE_* values */
+  return FE_ALL_EXCEPT & (orig_fsr >> 18);
+#  else /* Solaris compatible FE_* values */
+  return FE_ALL_EXCEPT & (orig_fsr >> 23);
+#  endif
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  unsigned long fsr, orig_fsr;
+  _FPU_GETCW (orig_fsr);
+#  if FE_INEXACT == 32 /* glibc compatible FE_* values */
+  fsr = orig_fsr & ~(exceptions << 18);
+#  else /* Solaris compatible FE_* values */
+  fsr = orig_fsr & ~(exceptions << 23);
+#  endif
+  if (fsr != orig_fsr)
+    _FPU_SETCW (fsr);
+
+#  if FE_INEXACT == 32 /* glibc compatible FE_* values */
+  return FE_ALL_EXCEPT & (orig_fsr >> 18);
+#  else /* Solaris compatible FE_* values */
+  return FE_ALL_EXCEPT & (orig_fsr >> 23);
+#  endif
+}
+
+int
+fegetexcept (void)
+{
+  unsigned long fsr;
+  _FPU_GETCW (fsr);
+#  if FE_INEXACT == 32 /* glibc compatible FE_* values */
+  return FE_ALL_EXCEPT & (fsr >> 18);
+#  else /* Solaris compatible FE_* values */
+  return FE_ALL_EXCEPT & (fsr >> 23);
+#  endif
+}
+
+# else
+
+#  if defined __GNUC__ || defined __clang__
+#   warning "Unknown CPU / architecture. Please report your platform and compiler to <bug-gnulib@gnu.org>."
+#  endif
+#  define NEED_FALLBACK 1
+
+# endif
+
+#else
+
+/* The compiler does not support __asm__ statements or equivalent
+   intrinsics.  */
+
+# if HAVE_FPSETMASK
+/* FreeBSD ≥ 3.1, NetBSD ≥ 1.1, OpenBSD, IRIX, Solaris, Minix ≥ 3.2.  */
+
+/* Get fpgetmask, fpsetmask.  */
+#  include <ieeefp.h>
+
+/* The type is called 'fp_except_t' on FreeBSD, but 'fp_except' on
+   all other systems.  */
+#  if !defined __FreeBSD__
+#   define fp_except_t fp_except
+#  endif
+
+static fp_except_t
+exceptions_to_mask (int exceptions)
+{
+  fp_except_t m = 0;
+  if (exceptions & FE_INVALID)
+    m |= FP_X_INV;
+  if (exceptions & FE_DIVBYZERO)
+    m |= FP_X_DZ;
+  if (exceptions & FE_OVERFLOW)
+    m |= FP_X_OFL;
+  if (exceptions & FE_UNDERFLOW)
+    m |= FP_X_UFL;
+  if (exceptions & FE_INEXACT)
+    m |= FP_X_IMP;
+  return m;
+}
+
+static int
+mask_to_exceptions (fp_except_t m)
+{
+  int exceptions = 0;
+  if (m & FP_X_INV)
+    exceptions |= FE_INVALID;
+  if (m & FP_X_DZ)
+    exceptions |= FE_DIVBYZERO;
+  if (m & FP_X_OFL)
+    exceptions |= FE_OVERFLOW;
+  if (m & FP_X_UFL)
+    exceptions |= FE_UNDERFLOW;
+  if (m & FP_X_IMP)
+    exceptions |= FE_INEXACT;
+  return exceptions;
+}
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  fp_except_t trapbits = fpgetmask ();
+  fpsetmask (trapbits | exceptions_to_mask (exceptions));
+  return mask_to_exceptions (trapbits);
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  fp_except_t trapbits = fpgetmask ();
+  fpsetmask (trapbits & ~ exceptions_to_mask (exceptions));
+  return mask_to_exceptions (trapbits);
+}
+
+int
+fegetexcept (void)
+{
+  fp_except_t trapbits = fpgetmask ();
+  return mask_to_exceptions (trapbits);
+}
+
+# elif defined _AIX && defined __powerpc__ /* AIX */
+
+#  include <fptrap.h>
+/* Documentation:
+   <https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-any-enable-fp-is-enabled-fp-enable-all-fp-enable-fp-disable-all-fp-disable-subroutine>
+   <https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-trap-subroutine>  */
+
+/* Convert from an 'int exceptions' to an fptrap_t.  */
+#  if 0 /* Unoptimized */
+#   define exceptions_to_fptrap(exceptions) \
+      (  ((exceptions) & FE_INVALID   ? TRP_INVALID     : 0) \
+       | ((exceptions) & FE_DIVBYZERO ? TRP_DIV_BY_ZERO : 0) \
+       | ((exceptions) & FE_OVERFLOW  ? TRP_OVERFLOW    : 0) \
+       | ((exceptions) & FE_UNDERFLOW ? TRP_UNDERFLOW   : 0) \
+       | ((exceptions) & FE_INEXACT   ? TRP_INEXACT     : 0))
+#  else /* Optimized */
+#   define exceptions_to_fptrap(exceptions) \
+      (((unsigned int) (exceptions) & FE_ALL_EXCEPT) >> 22)
+#  endif
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  int prev_enabled = fegetexcept ();
+  if (exceptions != 0)
+    {
+      fp_enable (exceptions_to_fptrap (exceptions));
+      if (prev_enabled == 0 /* && fegetexcept () != 0 */)
+        /* Enable precise trapping mode.  */
+        fp_trap (FP_TRAP_SYNC);
+    }
+  return prev_enabled;
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  int prev_enabled = fegetexcept ();
+  if (exceptions != 0)
+    {
+      fp_disable (exceptions_to_fptrap (exceptions));
+      if (prev_enabled != 0 && fegetexcept () == 0)
+        /* Disable precise trapping mode.  */
+        fp_trap (FP_TRAP_OFF);
+    }
+  return prev_enabled;
+}
+
+int
+fegetexcept (void)
+{
+  return fegetexcept_impl ();
+}
+
+# elif HAVE_FESETTRAPENABLE
+/* HP-UX, QNX */
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  int prev_enabled = fegettrapenable ();
+  if (exceptions != 0)
+    fesettrapenable (prev_enabled | exceptions);
+  return prev_enabled;
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+
+  int prev_enabled = fegettrapenable ();
+  if (exceptions != 0)
+    fesettrapenable (prev_enabled & ~exceptions);
+  return prev_enabled;
+}
+
+int
+fegetexcept (void)
+{
+  return fegettrapenable ();
+}
+
+# else
+
+#  define NEED_FALLBACK 1
+
+# endif
+
+#endif
+
+#if NEED_FALLBACK
+
+/* A dummy fallback.  */
+
+int
+feenableexcept (int exceptions)
+{
+  exceptions &= FE_ALL_EXCEPT;
+  if (exceptions != 0)
+    return -1;
+  return 0;
+}
+
+int
+fedisableexcept (int exceptions)
+{
+  return 0;
+}
+
+int
+fegetexcept (void)
+{
+  return 0;
+}
+
+#endif
index 2b2f770e2c66fb8ec779416c974f6815c277e8a3..4fd5ea2f1a03e34d4dc27f61d6957d090e0dff8f 100644 (file)
@@ -542,6 +542,100 @@ _GL_WARN_ON_USE (fesetexcept, "fesetexcept is unportable - "
 #endif
 
 
+/* GNU extensions.  */
+
+#if @GNULIB_FEENABLEEXCEPT@
+/* Enables trapping for the floating-point exceptions denoted by the bit mask
+   EXCEPTIONS.
+   Returns the bit mask of floating-point exceptions for which trapping was
+   enabled before the call, or -1 upon failure.
+   Note: This function is a misnomer.  It does not enable the specified
+   floating-point exceptions; it enables *trapping* on them.  It should better
+   be called 'feenabletraps'.  */
+# if @REPLACE_FEENABLEEXCEPT@ || (!@HAVE_FEENABLEEXCEPT@ && defined __FreeBSD__) /* has an inline definition */
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef feenableexcept
+#   define feenableexcept rpl_feenableexcept
+#  endif
+_GL_FUNCDECL_RPL (feenableexcept, int, (int exceptions));
+_GL_CXXALIAS_RPL (feenableexcept, int, (int exceptions));
+# else
+#  if !@HAVE_FEENABLEEXCEPT@
+_GL_FUNCDECL_SYS (feenableexcept, int, (int exceptions));
+#  endif
+_GL_CXXALIAS_SYS (feenableexcept, int, (int exceptions));
+# endif
+_GL_CXXALIASWARN (feenableexcept);
+#elif defined GNULIB_POSIXCHECK
+# undef feenableexcept
+# if HAVE_RAW_DECL_FEENABLEEXCEPT
+_GL_WARN_ON_USE (feenableexcept, "feenableexcept is unportable - "
+                 "use gnulib module fenv-exceptions-trapping for portability");
+# endif
+#endif
+
+#if @GNULIB_FEDISABLEEXCEPT@
+/* Disables trapping for the floating-point exceptions denoted by the bit mask
+   EXCEPTIONS.
+   Returns the bit mask of floating-point exceptions for which trapping was
+   enabled before the call, or -1 upon failure.
+   Note: This function is a misnomer.  It does not disable the specified
+   floating-point exceptions; it disables *trapping* on them.  It should better
+   be called 'fedisabletraps'.  */
+# if @REPLACE_FEDISABLEEXCEPT@ || (!@HAVE_FEDISABLEEXCEPT@ && defined __FreeBSD__) /* has an inline definition */
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef fedisableexcept
+#   define fedisableexcept rpl_fedisableexcept
+#  endif
+_GL_FUNCDECL_RPL (fedisableexcept, int, (int exceptions));
+_GL_CXXALIAS_RPL (fedisableexcept, int, (int exceptions));
+# else
+#  if !@HAVE_FEDISABLEEXCEPT@
+_GL_FUNCDECL_SYS (fedisableexcept, int, (int exceptions));
+#  endif
+_GL_CXXALIAS_SYS (fedisableexcept, int, (int exceptions));
+# endif
+_GL_CXXALIASWARN (fedisableexcept);
+#elif defined GNULIB_POSIXCHECK
+# undef fedisableexcept
+# if HAVE_RAW_DECL_FEDISABLEEXCEPT
+_GL_WARN_ON_USE (fedisableexcept, "fedisableexcept is unportable - "
+                 "use gnulib module fenv-exceptions-trapping for portability");
+# endif
+#endif
+
+#if @GNULIB_FEGETEXCEPT@
+/* Returns the bit mask of floating-point exceptions for which trapping is
+   enabled.
+   Note: This function is an even bigger misnomer:
+     - It does not test for the specified floating-point exceptions;
+       fetestexcept() does that.  It tests whether *trapping* on these
+       exceptions is enabled.
+     - It is in no way the opposite of fesetexcept().
+   It should better be called 'fegettraps'.  */
+# if @REPLACE_FEGETEXCEPT@ || (!@HAVE_FEGETEXCEPT@ && defined __FreeBSD__) /* has an inline definition */
+#  if !(defined __cplusplus && defined GNULIB_NAMESPACE)
+#   undef fegetexcept
+#   define fegetexcept rpl_fegetexcept
+#  endif
+_GL_FUNCDECL_RPL (fegetexcept, int, (void));
+_GL_CXXALIAS_RPL (fegetexcept, int, (void));
+# else
+#  if !@HAVE_FEGETEXCEPT@
+_GL_FUNCDECL_SYS (fegetexcept, int, (void));
+#  endif
+_GL_CXXALIAS_SYS (fegetexcept, int, (void));
+# endif
+_GL_CXXALIASWARN (fegetexcept);
+#elif defined GNULIB_POSIXCHECK
+# undef fegetexcept
+# if HAVE_RAW_DECL_FEGETEXCEPT
+_GL_WARN_ON_USE (fegetexcept, "fegetexcept is unportable - "
+                 "use gnulib module fenv-exceptions-trapping for portability");
+# endif
+#endif
+
+
 /* ISO C 99 § 7.6.2 Floating-point exceptions
    ISO C 23 § 7.6.4 Floating-point exceptions
    API with fexcept_t.
diff --git a/m4/fenv-exceptions-trapping.m4 b/m4/fenv-exceptions-trapping.m4
new file mode 100644 (file)
index 0000000..f85e356
--- /dev/null
@@ -0,0 +1,117 @@
+# fenv-exceptions-trapping.m4 serial 1
+dnl Copyright (C) 2023 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+AC_DEFUN_ONCE([gl_FENV_EXCEPTIONS_TRAPPING],
+[
+  AC_REQUIRE([gl_FENV_H_DEFAULTS])
+  dnl Persuade glibc <fenv.h> to declare feenableexcept().
+  AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
+  AC_REQUIRE([AC_CANONICAL_HOST])
+
+  gl_MATHFUNC([feenableexcept], [int], [(int)], [#include <fenv.h>])
+  if test $gl_cv_func_feenableexcept_no_libm = yes \
+     || test $gl_cv_func_feenableexcept_in_libm = yes; then
+    dnl On glibc 2.19/aarch64, feenableexcept does not detect failures.
+    dnl Fixed through
+    dnl <https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=302949e2940a9da3f6364a1574619e621b7e1e71>.
+    dnl Similarly on FreeBSD 12.2/arm and FreeBSD 12.2/arm64.
+    case "$host" in
+      aarch64*-*-linux*)
+        AC_CACHE_CHECK([whether feenableexcept works],
+          [gl_cv_func_feenableexcept_works],
+          [AC_COMPILE_IFELSE(
+             [AC_LANG_PROGRAM([[
+                #include <string.h> /* for __GNU_LIBRARY__ */
+                #ifdef __GNU_LIBRARY__
+                 #include <features.h>
+                 #if __GLIBC__ == 2 && __GLIBC_MINOR__ <= 19
+                  Unlucky user
+                 #endif
+                #endif
+                ]],
+                [])],
+             [gl_cv_func_feenableexcept_works="guessing yes"],
+             [gl_cv_func_feenableexcept_works="guessing no"])
+          ])
+        case "$gl_cv_func_feenableexcept_works" in
+          *yes) ;;
+          *) REPLACE_FEENABLEEXCEPT=1 ;;
+        esac
+        ;;
+      arm*-*-freebsd* | aarch64*-*-freebsd*)
+        REPLACE_FEENABLEEXCEPT=1
+        ;;
+    esac
+    if test $REPLACE_FEENABLEEXCEPT = 1; then
+      dnl Two more functions are defined in the same compilation unit.
+      dnl Override them as well.
+      REPLACE_FEDISABLEEXCEPT=1
+      REPLACE_FEGETEXCEPT=1
+      FENV_EXCEPTIONS_TRAPPING_LIBM=
+    else
+      dnl It needs linking with -lm on glibc.
+      if test $gl_cv_func_feenableexcept_no_libm = yes; then
+        FENV_EXCEPTIONS_TRAPPING_LIBM=
+      else
+        FENV_EXCEPTIONS_TRAPPING_LIBM=-lm
+      fi
+    fi
+  else
+    HAVE_FEENABLEEXCEPT=0
+    HAVE_FEDISABLEEXCEPT=0
+    HAVE_FEGETEXCEPT=0
+    case "$host" in
+      alpha*-*-linux*)
+        dnl For feenableexcept, which we take from libm.
+        FENV_EXCEPTIONS_TRAPPING_LIBM=-lm
+        ;;
+      *)
+        FENV_EXCEPTIONS_TRAPPING_LIBM=
+        ;;
+    esac
+  fi
+  if test $HAVE_FEENABLEEXCEPT = 0 || test $REPLACE_FEENABLEEXCEPT = 1; then
+    gl_PREREQ_FENV_EXCEPTIONS_TRAPPING
+    dnl Possibly need -lm for fpgetmask(), fpsetmask().
+    if test $gl_cv_func_fpsetmask_no_libm = no \
+       && test $gl_cv_func_fpsetmask_in_libm = yes \
+       && test -z "$FENV_EXCEPTIONS_TRAPPING_LIBM"; then
+      FENV_EXCEPTIONS_TRAPPING_LIBM=-lm
+    fi
+    dnl Possibly need -lm for fegettrapenable(), fesettrapenable().
+    if test $gl_cv_func_fesettrapenable_no_libm = no \
+       && test $gl_cv_func_fesettrapenable_in_libm = yes \
+       && test -z "$FENV_EXCEPTIONS_TRAPPING_LIBM"; then
+      FENV_EXCEPTIONS_TRAPPING_LIBM=-lm
+    fi
+  fi
+  AC_SUBST([FENV_EXCEPTIONS_TRAPPING_LIBM])
+])
+
+dnl Prerequisites of lib/fenv-except-trapping.c.
+AC_DEFUN([gl_PREREQ_FENV_EXCEPTIONS_TRAPPING],
+[
+  gl_MATHFUNC([fpsetmask], [fp_except_t], [(fp_except_t)],
+    [#include <ieeefp.h>
+     /* The type is called 'fp_except_t' on FreeBSD, but 'fp_except' on
+        all other systems.  */
+     #if !defined __FreeBSD__
+     #define fp_except_t fp_except
+     #endif
+    ])
+  if test $gl_cv_func_fpsetmask_no_libm = yes \
+     || test $gl_cv_func_fpsetmask_in_libm = yes; then
+    AC_DEFINE([HAVE_FPSETMASK], [1],
+      [Define to 1 if you have the 'fpsetmask' function.])
+  fi
+
+  gl_MATHFUNC([fesettrapenable], [int], [(int)], [#include <fenv.h>])
+  if test $gl_cv_func_fesettrapenable_no_libm = yes \
+     || test $gl_cv_func_fesettrapenable_in_libm = yes; then
+    AC_DEFINE([HAVE_FESETTRAPENABLE], [1],
+      [Define to 1 if you have the 'fesettrapenable' function.])
+  fi
+])
index 9e7c809d0651fbd0224202fab272aeeb1d3da7e1..853f66e5a9bbfdffb92022fba26e3df3e774b90d 100644 (file)
@@ -22,7 +22,8 @@ AC_DEFUN_ONCE([gl_FENV_H],
   dnl corresponding gnulib module is not in use, and which is not
   dnl guaranteed by C99.
   gl_WARN_ON_USE_PREPARE([[#include <fenv.h>
-    ]], [fedisableexcept feenableexcept fesetexcept fetestexceptflag])
+    ]], [fedisableexcept feenableexcept fegetexcept fesetexcept
+    fetestexceptflag])
 ])
 
 # gl_FENV_MODULE_INDICATOR([modulename])
diff --git a/modules/fenv-exceptions-trapping b/modules/fenv-exceptions-trapping
new file mode 100644 (file)
index 0000000..7ce55fc
--- /dev/null
@@ -0,0 +1,40 @@
+Description:
+Functions for turning floating-point exceptions into traps (signals):
+feenableexcept, fedisableexcept, fegetexcept.
+
+Files:
+lib/fenv-except-trapping.c
+lib/fenv-private.h
+m4/fenv-exceptions-trapping.m4
+m4/mathfunc.m4
+m4/musl.m4
+
+Depends-on:
+fenv
+extensions
+
+configure.ac:
+gl_FENV_EXCEPTIONS_TRAPPING
+gl_CONDITIONAL([GL_COND_OBJ_FENV_EXCEPTIONS_TRAPPING],
+               [test $HAVE_FEENABLEEXCEPT = 0 || test $REPLACE_FEENABLEEXCEPT = 1])
+gl_FENV_MODULE_INDICATOR([feenableexcept])
+gl_FENV_MODULE_INDICATOR([fedisableexcept])
+gl_FENV_MODULE_INDICATOR([fegetexcept])
+gl_MODULE_INDICATOR([feenableexcept])
+
+Makefile.am:
+if GL_COND_OBJ_FENV_EXCEPTIONS_TRAPPING
+lib_SOURCES += fenv-except-trapping.c
+endif
+
+Include:
+#include <fenv.h>
+
+Link:
+$(FENV_EXCEPTIONS_TRAPPING_LIBM)
+
+License:
+LGPLv2+
+
+Maintainer:
+all