Now that proper modules for tracking and trapping floating-point exceptions are in place (that work on all platforms, and with unit tests), the modules fpe-tracking and fpe-trapping can take advantage of them:
* The module fpe-tracking can be removed. fenv-exceptions-tracking-c99 is its replacement. (The module was not yet picked up by any package outside gnulib.) * The module fpe-trapping becomes a trivial combination of fenv-exceptions-tracking-c99 and fenv-exceptions-trapping. 2023-11-05 Bruno Haible <br...@clisp.org> fpe-trapping: Simplify. * lib/fpe-trapping.h (sigfpe_on_invalid): Remove all platform specific code. Just rely on feclearexcept and feenableexcept. * m4/fpe-trapping.m4: Renamed from m4/fpe.m4. (gl_FPE_TRAPPING): Greatly simplify. * modules/fpe-trapping (Files): Use m4/fpe-trapping.m4 instead of m4/fpe.m4. Remove m4/mathfunc.m4, m4/musl.m4. (Depends-on): Add fenv-exceptions-trapping. * tests/test-fenv-except-state-2.c (main): Update skip message. * tests/test-fenv-except-tracking-2.c (main): Likewise. * tests/test-fenv-except-tracking-3.c (main): Likewise. * tests/test-fenv-except-tracking-5.c (main): Likewise. * tests/test-nan-2.c (main): Likewise. * tests/test-snan-2.c (main): Likewise. 2023-11-05 Bruno Haible <br...@clisp.org> fpe-tracking: Remove module. * modules/fpe-tracking: Remove file. * m4/fpe.m4 (gl_FPE_TRACKING): Remove macro. (gl_FPE_TRAPPING): Require gl_FENV_EXCEPTIONS_TRACKING instead of gl_FPE_TRACKING. Use FENV_EXCEPTIONS_TRACKING_LIBM instead of FPE_TRACKING_LIBM. * modules/nan-tests (Depends-on): Add fenv-exceptions-tracking-c99. Remove fpe-tracking. (Makefile.am): Use FENV_EXCEPTIONS_TRACKING_LIBM instead of FPE_TRACKING_LIBM. * modules/snan-tests (Depends-on): Add fenv-exceptions-tracking-c99. Remove fpe-tracking. (Makefile.am): Use FENV_EXCEPTIONS_TRACKING_LIBM instead of FPE_TRACKING_LIBM. * tests/test-nan-1.c: Assume HAVE_FE_INVALID is 1. * tests/test-snan-1.c: Likewise.
>From 6facb2ddab273a8798374897af23e9ad45aba899 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 5 Nov 2023 14:27:47 +0100 Subject: [PATCH 1/2] fpe-tracking: Remove module. * modules/fpe-tracking: Remove file. * m4/fpe.m4 (gl_FPE_TRACKING): Remove macro. (gl_FPE_TRAPPING): Require gl_FENV_EXCEPTIONS_TRACKING instead of gl_FPE_TRACKING. Use FENV_EXCEPTIONS_TRACKING_LIBM instead of FPE_TRACKING_LIBM. * modules/nan-tests (Depends-on): Add fenv-exceptions-tracking-c99. Remove fpe-tracking. (Makefile.am): Use FENV_EXCEPTIONS_TRACKING_LIBM instead of FPE_TRACKING_LIBM. * modules/snan-tests (Depends-on): Add fenv-exceptions-tracking-c99. Remove fpe-tracking. (Makefile.am): Use FENV_EXCEPTIONS_TRACKING_LIBM instead of FPE_TRACKING_LIBM. * tests/test-nan-1.c: Assume HAVE_FE_INVALID is 1. * tests/test-snan-1.c: Likewise. --- ChangeLog | 19 ++++++++++++++++++ m4/fpe.m4 | 47 +++----------------------------------------- modules/fpe-tracking | 27 ------------------------- modules/nan-tests | 4 ++-- modules/snan-tests | 4 ++-- tests/test-nan-1.c | 27 +++++-------------------- tests/test-snan-1.c | 27 +++++-------------------- 7 files changed, 36 insertions(+), 119 deletions(-) delete mode 100644 modules/fpe-tracking diff --git a/ChangeLog b/ChangeLog index 0955567775..3b2951ff6e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2023-11-05 Bruno Haible <br...@clisp.org> + + fpe-tracking: Remove module. + * modules/fpe-tracking: Remove file. + * m4/fpe.m4 (gl_FPE_TRACKING): Remove macro. + (gl_FPE_TRAPPING): Require gl_FENV_EXCEPTIONS_TRACKING instead of + gl_FPE_TRACKING. Use FENV_EXCEPTIONS_TRACKING_LIBM instead of + FPE_TRACKING_LIBM. + * modules/nan-tests (Depends-on): Add fenv-exceptions-tracking-c99. + Remove fpe-tracking. + (Makefile.am): Use FENV_EXCEPTIONS_TRACKING_LIBM instead of + FPE_TRACKING_LIBM. + * modules/snan-tests (Depends-on): Add fenv-exceptions-tracking-c99. + Remove fpe-tracking. + (Makefile.am): Use FENV_EXCEPTIONS_TRACKING_LIBM instead of + FPE_TRACKING_LIBM. + * tests/test-nan-1.c: Assume HAVE_FE_INVALID is 1. + * tests/test-snan-1.c: Likewise. + 2023-11-05 Bruno Haible <br...@clisp.org> fenv-exceptions-trapping: Avoid test failure on NetBSD/sparc. diff --git a/m4/fpe.m4 b/m4/fpe.m4 index f8a81030a6..94ca0d5cc1 100644 --- a/m4/fpe.m4 +++ b/m4/fpe.m4 @@ -1,50 +1,9 @@ -# fpe.m4 serial 1 +# fpe.m4 serial 2 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. -# Prerequisites for tracking FE_INVALID exceptions. -AC_DEFUN_ONCE([gl_FPE_TRACKING], -[ - AC_CACHE_CHECK([whether FE_INVALID exceptions can be tracked], - [gl_cv_fenv_invalid_api], - [AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [[#include <fenv.h> - ]], - [[feclearexcept (FE_INVALID); - ]]) - ], - [gl_cv_fenv_invalid_api=yes], - [gl_cv_fenv_invalid_api=no]) - ]) - if test $gl_cv_fenv_invalid_api = yes; then - AC_DEFINE([HAVE_FE_INVALID], [1], - [Define if FE_INVALID exceptions can be programmatically tracked.]) - AC_CACHE_CHECK([whether feclearexcept can be used without linking with libm], - [gl_cv_func_feclearexcept_no_libm], - [AC_LINK_IFELSE( - [AC_LANG_PROGRAM( - [[#include <fenv.h> - ]], - [[feclearexcept (FE_INVALID); - ]]) - ], - [gl_cv_func_feclearexcept_no_libm=yes], - [gl_cv_func_feclearexcept_no_libm=no]) - ]) - if test $gl_cv_func_feclearexcept_no_libm != yes; then - FPE_TRACKING_LIBM=-lm - else - FPE_TRACKING_LIBM= - fi - else - FPE_TRACKING_LIBM= - fi - AC_SUBST([FPE_TRACKING_LIBM]) -]) - # Prerequisites for turning FE_INVALID exceptions into a SIGFPE signal. AC_DEFUN_ONCE([gl_FPE_TRAPPING], [ @@ -109,7 +68,7 @@ AC_DEFUN_ONCE([gl_FPE_TRAPPING] fi fi fi - AC_REQUIRE([gl_FPE_TRACKING]) - FPE_TRAPPING_LIBM="$FPE_TRAPPING_LIBM $FPE_TRACKING_LIBM" + AC_REQUIRE([gl_FENV_EXCEPTIONS_TRACKING]) + FPE_TRAPPING_LIBM="$FPE_TRAPPING_LIBM $FENV_EXCEPTIONS_TRACKING_LIBM" AC_SUBST([FPE_TRAPPING_LIBM]) ]) diff --git a/modules/fpe-tracking b/modules/fpe-tracking deleted file mode 100644 index d1afcf94f0..0000000000 --- a/modules/fpe-tracking +++ /dev/null @@ -1,27 +0,0 @@ -Description: -Tracking floating-point exceptions, i.e. determining whether -a floating-point exception has occurred during a certain computation. - -Files: -m4/fpe.m4 - -Depends-on: - -configure.ac: -gl_FPE_TRACKING - -Makefile.am: - -Include: -#if HAVE_FE_INVALID -# include <fenv.h> -#endif - -Link: -$(FPE_TRACKING_LIBM) - -License: -GPL - -Maintainer: -all diff --git a/modules/nan-tests b/modules/nan-tests index 607e35f63b..ec549b8919 100644 --- a/modules/nan-tests +++ b/modules/nan-tests @@ -4,7 +4,7 @@ tests/test-nan-2.c tests/macros.h Depends-on: -fpe-tracking +fenv-exceptions-tracking-c99 fpe-trapping configure.ac: @@ -12,5 +12,5 @@ configure.ac: Makefile.am: TESTS += test-nan-1 test-nan-2 check_PROGRAMS += test-nan-1 test-nan-2 -test_nan_1_LDADD = $(LDADD) @FPE_TRACKING_LIBM@ +test_nan_1_LDADD = $(LDADD) $(FENV_EXCEPTIONS_TRACKING_LIBM) test_nan_2_LDADD = $(LDADD) @FPE_TRAPPING_LIBM@ diff --git a/modules/snan-tests b/modules/snan-tests index 91210d2ea5..6779f6c0bf 100644 --- a/modules/snan-tests +++ b/modules/snan-tests @@ -6,7 +6,7 @@ tests/macros.h m4/math_h.m4 Depends-on: -fpe-tracking +fenv-exceptions-tracking-c99 fpe-trapping configure.ac: @@ -15,5 +15,5 @@ AC_REQUIRE([gl_LONG_DOUBLE_VS_DOUBLE]) Makefile.am: TESTS += test-snan-1 test-snan-2.sh check_PROGRAMS += test-snan-1 test-snan-2 -test_snan_1_LDADD = $(LDADD) @FPE_TRACKING_LIBM@ +test_snan_1_LDADD = $(LDADD) $(FENV_EXCEPTIONS_TRACKING_LIBM) test_snan_2_LDADD = $(LDADD) @FPE_TRAPPING_LIBM@ diff --git a/tests/test-nan-1.c b/tests/test-nan-1.c index 4ebe013e3c..9b48a6853f 100644 --- a/tests/test-nan-1.c +++ b/tests/test-nan-1.c @@ -21,11 +21,9 @@ /* Specification. */ #include "nan.h" -#include <stdio.h> +#if defined __GLIBC__ && defined __arm__ && defined __SOFTFP__ -#if HAVE_FE_INVALID - -# if defined __GLIBC__ && defined __arm__ && defined __SOFTFP__ +# include <stdio.h> /* The arm software floating-point emulation (used e.g. on armv5) does not set the floating-point exception bits. */ @@ -37,11 +35,11 @@ main () return 77; } -# else +#else -# include <fenv.h> +# include <fenv.h> -# include "macros.h" +# include "macros.h" float volatile resultf; double volatile resultd; @@ -80,19 +78,4 @@ main () return 0; } -# endif - -#else - -/* No <fenv.h> available. - We could use the various alternative approaches from - libgfortran/config/fpu-*.h, but that's not worth it. */ - -int -main () -{ - fputs ("Skipping test: feclearexcept, fetestexcept, FE_INVALID not available\n", stderr); - return 77; -} - #endif diff --git a/tests/test-snan-1.c b/tests/test-snan-1.c index 7b71b9a57b..3b1e0e9427 100644 --- a/tests/test-snan-1.c +++ b/tests/test-snan-1.c @@ -21,11 +21,9 @@ /* Specification. */ #include "snan.h" -#include <stdio.h> +#if defined __GLIBC__ && defined __arm__ && defined __SOFTFP__ -#if HAVE_FE_INVALID - -# if defined __GLIBC__ && defined __arm__ && defined __SOFTFP__ +# include <stdio.h> /* The arm software floating-point emulation (used e.g. on armv5) does not set the floating-point exception bits. */ @@ -37,11 +35,11 @@ main () return 77; } -# else +#else -# include <fenv.h> +# include <fenv.h> -# include "macros.h" +# include "macros.h" float volatile resultf; double volatile resultd; @@ -105,19 +103,4 @@ main () return 0; } -# endif - -#else - -/* No <fenv.h> available. - We could use the various alternative approaches from - libgfortran/config/fpu-*.h, but that's not worth it. */ - -int -main () -{ - fputs ("Skipping test: feclearexcept, fetestexcept, FE_INVALID not available\n", stderr); - return 77; -} - #endif -- 2.34.1
From 45d01c797646d9d89d44405b1841009c949ed325 Mon Sep 17 00:00:00 2001 From: Bruno Haible <br...@clisp.org> Date: Sun, 5 Nov 2023 14:34:39 +0100 Subject: [PATCH 2/2] fpe-trapping: Simplify. * lib/fpe-trapping.h (sigfpe_on_invalid): Remove all platform specific code. Just rely on feclearexcept and feenableexcept. * m4/fpe-trapping.m4: Renamed from m4/fpe.m4. (gl_FPE_TRAPPING): Greatly simplify. * modules/fpe-trapping (Files): Use m4/fpe-trapping.m4 instead of m4/fpe.m4. Remove m4/mathfunc.m4, m4/musl.m4. (Depends-on): Add fenv-exceptions-trapping. * tests/test-fenv-except-state-2.c (main): Update skip message. * tests/test-fenv-except-tracking-2.c (main): Likewise. * tests/test-fenv-except-tracking-3.c (main): Likewise. * tests/test-fenv-except-tracking-5.c (main): Likewise. * tests/test-nan-2.c (main): Likewise. * tests/test-snan-2.c (main): Likewise. --- ChangeLog | 17 + lib/fpe-trapping.h | 588 +--------------------------- m4/fpe-trapping.m4 | 20 + m4/fpe.m4 | 74 ---- modules/fpe-trapping | 5 +- tests/test-fenv-except-state-2.c | 2 +- tests/test-fenv-except-tracking-2.c | 2 +- tests/test-fenv-except-tracking-3.c | 2 +- tests/test-fenv-except-tracking-5.c | 2 +- tests/test-nan-2.c | 2 +- tests/test-snan-2.c | 2 +- 11 files changed, 51 insertions(+), 665 deletions(-) create mode 100644 m4/fpe-trapping.m4 delete mode 100644 m4/fpe.m4 diff --git a/ChangeLog b/ChangeLog index 3b2951ff6e..3e8c6cf2a7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2023-11-05 Bruno Haible <br...@clisp.org> + + fpe-trapping: Simplify. + * lib/fpe-trapping.h (sigfpe_on_invalid): Remove all platform specific + code. Just rely on feclearexcept and feenableexcept. + * m4/fpe-trapping.m4: Renamed from m4/fpe.m4. + (gl_FPE_TRAPPING): Greatly simplify. + * modules/fpe-trapping (Files): Use m4/fpe-trapping.m4 instead of + m4/fpe.m4. Remove m4/mathfunc.m4, m4/musl.m4. + (Depends-on): Add fenv-exceptions-trapping. + * tests/test-fenv-except-state-2.c (main): Update skip message. + * tests/test-fenv-except-tracking-2.c (main): Likewise. + * tests/test-fenv-except-tracking-3.c (main): Likewise. + * tests/test-fenv-except-tracking-5.c (main): Likewise. + * tests/test-nan-2.c (main): Likewise. + * tests/test-snan-2.c (main): Likewise. + 2023-11-05 Bruno Haible <br...@clisp.org> fpe-tracking: Remove module. diff --git a/lib/fpe-trapping.h b/lib/fpe-trapping.h index 9040a218ce..005ede6bf0 100644 --- a/lib/fpe-trapping.h +++ b/lib/fpe-trapping.h @@ -23,13 +23,8 @@ Returns >= 0 when successful, -1 upon failure. */ -#define HAVE_FPE_TRAPPING 1 - #include <fenv.h> -#if HAVE_FEENABLEEXCEPT -/* glibc, FreeBSD ≥ 6.0, NetBSD ≥ 7.0, OpenBSD ≥ 5.0, Cygwin ≥ 1.7.8, Android, Haiku. */ - static int sigfpe_on_invalid () { @@ -39,591 +34,20 @@ sigfpe_on_invalid () /* An FE_INVALID exception shall trigger a SIGFPE signal. This call may fail on arm, arm64, riscv64 CPUs. Also, possibly a bug in glibc/sysdeps/m68k/fpu/feenablxcpt.c: it sets - only bit 13, but should better set both bit 14 and bit 13 of the - control register. */ + only bit 13, but should better set bits 15, 14, 13 of the control + register together. See + <https://sourceware.org/bugzilla/show_bug.cgi?id=30993>. */ int ret = feenableexcept (FE_INVALID); if (ret == -1) return -1; - #if ((__GLIBC__ == 2 && __GLIBC_MINOR__ < 20) || defined __FreeBSD__ || defined __NetBSD__) && defined __aarch64__ - /* Work around a bug with glibc 2.19 and FreeBSD 12.2 on arm64 CPUs: - feenableexcept returns success even if the CPU does not support the - request. */ - fenv_t env; - fegetenv (&env); - #if __GLIBC__ >= 2 || defined __NetBSD__ - /* fenv_t is a struct { unsigned int __fpcr, __fpsr; } */ - if (((FE_INVALID << 8) & ~env.__fpcr) != 0) - return -1; - #else /* defined __FreeBSD__ */ - /* fenv_t is an 'uint64_t' that merges fpcr and fpsr. - But watch out for this incompatible change: - <https://cgit.freebsd.org/src/commit/?id=34cc08e336987a8ebc316595e3f552a4c09f1fd4> */ - #if __FreeBSD__ < 14 - if (((FE_INVALID << 8) & ~env) != 0) - #else - if (((FE_INVALID << 8) & ~(env >> 32)) != 0) - #endif - return -1; - #endif - #endif - - #if (defined __FreeBSD__ || defined __NetBSD__) && defined __arm__ - /* Work around a bug with FreeBSD 12.2 on arm CPUs: - feenableexcept returns success even if the CPU does not support the - request. */ - /* Test whether fpscr was actually changed as desired. */ - fenv_t env; - fegetenv (&env); - if (((FE_INVALID << 8) & ~env) != 0) - return -1; - #endif - return 0; } /* But it does not work on RISC-V. That's because the fcsr register has only bits for floating-point exception status, but no bits for trapping floating-point exceptions. */ -# if defined __riscv -# undef HAVE_FPE_TRAPPING -# endif - -#elif HAVE_FPSETMASK -/* FreeBSD ≥ 6.0, NetBSD ≥ 1.4, OpenBSD ≥ 3.1, IRIX, Solaris, Minix ≥ 3.2. */ - -# 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 int -sigfpe_on_invalid () -{ - /* Clear FE_INVALID exceptions from past operations. */ - feclearexcept (FE_INVALID); - - fpsetmask (fpgetmask () | FP_X_INV); - - #if defined __arm__ || defined __aarch64__ - /* Test whether the CPU supports the request. */ - if ((fpgetmask () & ~FP_X_INV) == 0) - return -1; - #endif - - return 0; -} - -#elif HAVE_FESETTRAPENABLE -/* HP-UX, QNX */ - -# include <fenv.h> - -static int -sigfpe_on_invalid () -{ - /* Clear FE_INVALID exceptions from past operations. */ - feclearexcept (FE_INVALID); - - fesettrapenable (fegettrapenable () | FE_INVALID); - - return 0; -} - -#elif defined _AIX -/* AIX */ - -# include <fptrap.h> - -static int -sigfpe_on_invalid () -{ - /* Clear FE_INVALID exceptions from past operations. */ - feclearexcept (FE_INVALID); - - /* Enable precise trapping mode. - Documentation: <https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-trap-subroutine> */ - fp_trap (FP_TRAP_SYNC); - /* 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> */ - fp_enable (TRP_INVALID); - - return 0; -} - -#elif __MINGW32__ && defined __x86_64__ -/* mingw/x86_64 */ - -# include <fenv.h> - -static int -sigfpe_on_invalid () -{ - /* Clear FE_INVALID exceptions from past operations. */ - feclearexcept (FE_INVALID); - - /* An FE_INVALID exception shall trigger a SIGFPE signal. - fctrl bits 5..2,0 indicate which floating-point exceptions shall, when - occurring in the 387 compatible floating-point unit, trigger a trap rather - than merely set the corresponding bit in the fstat register. - mxcsr bits 12..9,7 indicate which floating-point exceptions shall, when - occurring in the SSE registers floating-point unit, trigger a trap rather - than merely set the corresponding bit in the lower part of the mxcsr - register. */ - /* mingw's _controlfp_s implementation - <https://github.com/mingw-w64/mingw-w64/blob/master/mingw-w64-crt/secapi/_controlfp_s.c> - is broken. This code here works. */ - { - unsigned short fctrl, orig_fctrl; - unsigned int mxcsr, orig_mxcsr; - - __asm__ __volatile__ ("fstcw %0" : "=m" (*&fctrl)); - __asm__ __volatile__ ("stmxcsr %0" : "=m" (*&mxcsr)); - orig_fctrl = fctrl; - orig_mxcsr = mxcsr; - fctrl &= ~FE_INVALID; - mxcsr &= ~(FE_INVALID << 7); - if (!(fctrl == orig_fctrl && mxcsr == orig_mxcsr)) - { - __asm__ __volatile__ ("fldcw %0" : : "m" (*&fctrl)); - __asm__ __volatile__ ("ldmxcsr %0" : : "m" (*&mxcsr)); - } - } - - return 0; -} - -#elif defined _WIN32 && !defined __CYGWIN__ -/* native Windows */ - -# include <float.h> - -static int -sigfpe_on_invalid () -{ - /* Documentation: - <https://learn.microsoft.com/en-us/cpp/c-runtime-library/reference/controlfp-s> */ - unsigned int control; - if (_controlfp_s (&control, 0, 0) == 0) - if (_controlfp_s (&control, control & ~_EM_INVALID, _MCW_EM) == 0) - return 0; - - return -1; -} - -#elif MUSL_LIBC && defined __x86_64__ -/* musl libc/x86_64 */ - -# include <fenv.h> - -static int -sigfpe_on_invalid () -{ - fenv_t env, orig_env; - fegetenv (&env); - orig_env = env; - - /* Clear FE_INVALID exceptions from past operations. - fstat bits 5..2,0 indicate which floating-point exceptions have occurred - since the respective bit was last set to zero, in the 387 compatible - floating-point unit. - mxcsr bits 5..2,0 indicate which floating-point exceptions have occurred - since the respective bit was last set to zero, in the SSE registers - floating-point unit. */ - env.__status_word &= ~FE_INVALID; - env.__mxcsr &= ~FE_INVALID; - /* An FE_INVALID exception shall trigger a SIGFPE signal. - fctrl bits 5..2,0 indicate which floating-point exceptions shall, when - occurring in the 387 compatible floating-point unit, trigger a trap rather - than merely set the corresponding bit in the fstat register. - mxcsr bits 12..9,7 indicate which floating-point exceptions shall, when - occurring in the SSE registers floating-point unit, trigger a trap rather - than merely set the corresponding bit in the lower part of the mxcsr - register. */ - env.__control_word &= ~FE_INVALID; - env.__mxcsr &= ~(FE_INVALID << 7); - - if (!(env.__control_word == orig_env.__control_word - && env.__status_word == orig_env.__status_word - && env.__mxcsr == orig_env.__mxcsr)) - fesetenv (&env); - - return 0; -} - -#elif MUSL_LIBC && defined __i386__ -/* musl libc/x86 */ - -# include <fenv.h> - -static int -sigfpe_on_invalid () -{ - fenv_t env, orig_env; - fegetenv (&env); - orig_env = env; - - /* The mxcsr register exists, like for x86_64, but only if the CPU supports - SSE instructions. Here it is not part of fenv_t. Instead, it is - transparently handled by the fegetenv and fesetenv functions. */ - - /* Clear FE_INVALID exceptions from past operations. - fstat bits 5..2,0 indicate which floating-point exceptions have occurred - since the respective bit was last set to zero, in the 387 compatible - floating-point unit. */ - env.__status_word &= ~FE_INVALID; - /* An FE_INVALID exception shall trigger a SIGFPE signal. - fctrl bits 5..2,0 indicate which floating-point exceptions shall, when - occurring in the 387 compatible floating-point unit, trigger a trap rather - than merely set the corresponding bit in the fstat register. */ - env.__control_word &= ~FE_INVALID; - - if (!(env.__control_word == orig_env.__control_word - && env.__status_word == orig_env.__status_word)) - fesetenv (&env); - - return 0; -} - -#elif MUSL_LIBC && defined __aarch64__ -/* musl libc/arm64 */ - -# include <fenv.h> - -static int -sigfpe_on_invalid () -{ - fenv_t env, orig_env; - fegetenv (&env); - orig_env = env; - - /* Clear FE_INVALID exceptions from past operations. - fpsr bits 4..0 indicate which floating-point exceptions have occurred - since the respective bit was last set to zero. */ - env.__fpsr &= ~FE_INVALID; - /* An FE_INVALID exception shall trigger a SIGFPE signal. - fpcr bits 12..8 indicate which floating-point exceptions shall, when - occurring, trigger a trap rather than merely set the corresponding bit - in the fpsr register. */ - env.__fpcr |= (FE_INVALID << 8); - - if (!(env.__fpsr == orig_env.__fpsr && env.__fpcr == orig_env.__fpcr)) - { - fesetenv (&env); - /* Test whether __fpcr was actually changed as desired. */ - fenv_t new_env; - fegetenv (&new_env); - if (new_env.__fpcr != env.__fpcr) - return -1; - } - - return 0; -} - -#elif MUSL_LIBC && defined __arm__ -/* musl libc/arm */ - -# include <fenv.h> - -static int -sigfpe_on_invalid () -{ - fenv_t env; - unsigned int orig_fpscr; - fegetenv (&env); - orig_fpscr = env.__cw; - - /* Clear FE_INVALID exceptions from past operations. - fpscr bits 4..0 indicate which floating-point exceptions have occurred - since the respective bit was last set to zero. */ - env.__cw &= ~FE_INVALID; - /* An FE_INVALID exception shall trigger a SIGFPE signal. - fpscr bits 12..8 indicate which floating-point exceptions shall, when - occurring, trigger a trap rather than merely set the corresponding bit - in the fpscr register. */ - env.__cw |= (FE_INVALID << 8); - - if (!(env.__cw == orig_fpscr)) - { - fesetenv (&env); - /* Test whether fpscr was actually changed as desired. */ - fenv_t new_env; - fegetenv (&new_env); - if (new_env.__cw != env.__cw) - return -1; - } - - return 0; -} - -#elif MUSL_LIBC && defined __m68k__ -/* musl libc/m68k */ - -# include <fenv.h> - -static int -sigfpe_on_invalid () -{ - fenv_t env, orig_env; - fegetenv (&env); - orig_env = env; - - /* Clear FE_INVALID exceptions from past operations. - fpsr bits 7..3 indicate which floating-point exceptions have occurred - since the respective bit was last set to zero. */ - env.__status_register &= ~FE_INVALID; - /* An FE_INVALID exception shall trigger a SIGFPE signal. - fpcr bits 15..8 indicate which floating-point exceptions shall, when - occurring, trigger a trap rather than merely set the corresponding bit - in the fpsr register: - - bit 15: branch/set on unordered - - bit 14: signaling not-a-number - - bit 13: operand error - - bit 12: overflow - - bit 11: underflow - - bit 10: divide by zero - - bit 9: inexact operation - - bit 8: inexact decimal input - Although (FE_INVALID << 6) has bit 13 set, we need to set bit 14 and - bit 13. */ - env.__control_register |= (1U << 14) | (FE_INVALID << 6); - - if (!(env.__status_register == orig_env.__status_register - && env.__control_register == orig_env.__control_register)) - fesetenv (&env); - - return 0; -} - -#elif MUSL_LIBC && defined __mips__ -/* musl libc/mips64,mipsn32,mips32 */ - -# include <fenv.h> - -static int -sigfpe_on_invalid () -{ - fenv_t env, orig_env; - fegetenv (&env); - orig_env = env; - - /* Clear FE_INVALID exceptions from past operations. - fcsr bits 6..2 indicate which floating-point exceptions have occurred - since the respective bit was last set to zero. - fcsr bits 17..12 indicate which floating-point exceptions have occurred - in the most recent instruction. */ - env.__cw &= ~((FE_INVALID << 10) | FE_INVALID); - /* An FE_INVALID exception shall trigger a SIGFPE signal. - fcsr bits 11..7 indicate which floating-point exceptions shall, when - occurring, trigger a trap rather than merely set the corresponding bit - in the fcsr register. */ - env.__cw |= (FE_INVALID << 5); - - if (!(env.__cw == orig_env.__cw)) - fesetenv (&env); - - return 0; -} - -#elif MUSL_LIBC && (defined __powerpc__ || defined __powerpc64__) -/* musl libc/powerpc64,powerpc */ - -# include <fenv.h> -# include <sys/prctl.h> - -static int -sigfpe_on_invalid () -{ - /* fenv_t is a 'double'. */ - union { unsigned long long u; fenv_t f; } env, orig_env; - fegetenv (&env.f); - orig_env = env; - - /* Clear FE_INVALID exceptions from past operations. - fpscr bits 28..25 indicate which floating-point exceptions, other than - FE_INVALID, have occurred since the respective bit was last set to zero. - fpscr bits 24..19, 10..8 do the same thing, for various kinds of Invalid - Operation. fpscr bit 29 is the summary (the OR) of all these bits. - Instead of clearing FE_INVALID (= bit 29), we need to clear these - individual bits. */ - env.u &= ~FE_ALL_INVALID; /* not ~FE_INVALID ! */ - /* An FE_INVALID exception shall trigger a SIGFPE signal. - fpscr bits 7..3 indicate which floating-point exceptions shall, when - occurring, trigger a trap rather than merely set the corresponding bit - in the fpscr register. */ - env.u |= (FE_INVALID >> 22); - - if (!(env.u == orig_env.u)) - { - /* Enable precise trapping mode. */ - prctl (PR_SET_FPEXC, PR_FP_EXC_PRECISE); - - fesetenv (&env.f); - } - - return 0; -} - -#elif MUSL_LIBC && (defined __s390__ || defined __s390x__) -/* musl libc/s390x,s390 */ - -# include <fenv.h> - -static int -sigfpe_on_invalid () -{ - fenv_t env, orig_env; - fegetenv (&env); - orig_env = env; - - /* Clear FE_INVALID exceptions from past operations. - fpc bits 23..19 indicate which floating-point exceptions have occurred - since the respective bit was last set to zero. - fpc bits 15..11 are part of the "data exception code" (DXC) and have a - similar meaning if bits 9..8 are both zero. */ - env &= ~FE_INVALID; - if ((env & 0x00000300) == 0) - env &= ~(FE_INVALID >> 8); - /* An FE_INVALID exception shall trigger a SIGFPE signal. - fpc bits 31..27 indicate which floating-point exceptions shall, when - occurring, trigger a trap rather than merely set the corresponding bit - in the fpc register. */ - env |= ((unsigned int) FE_INVALID << 8); - - if (!(env == orig_env)) - fesetenv (&env); - - return 0; -} - -#elif MUSL_LIBC && defined __sh__ -/* musl libc/sh4 */ - -# include <fenv.h> - -static int -sigfpe_on_invalid () -{ - fenv_t env, orig_env; - fegetenv (&env); - orig_env = env; - - /* Clear FE_INVALID exceptions from past operations. - fpscr bits 6..2 indicate which floating-point exceptions have occurred - since the respective bit was last set to zero. */ - env.__cw &= ~FE_INVALID; - /* An FE_INVALID exception shall trigger a SIGFPE signal. - fpscr bits 11..7 indicate which floating-point exceptions shall, when - occurring, trigger a trap rather than merely set the corresponding bit - in the fpscr register. */ - env.__cw |= (FE_INVALID << 5); - - if (!(env.__cw == orig_env.__cw)) - fesetenv (&env); - - return 0; -} - -#elif (defined __APPLE__ && defined __MACH__) && (defined __i386__ || defined __x86_64__) -/* Mac OS X/i386,x86_64 */ - -# include <fenv.h> - -static int -sigfpe_on_invalid () -{ - fenv_t env, orig_env; - fegetenv (&env); - orig_env = env; - - /* Clear FE_INVALID exceptions from past operations. - fstat bits 5..2,0 indicate which floating-point exceptions have occurred - since the respective bit was last set to zero, in the 387 compatible - floating-point unit. - mxcsr bits 5..2,0 indicate which floating-point exceptions have occurred - since the respective bit was last set to zero, in the SSE registers - floating-point unit. */ - env.__status &= ~FE_INVALID; - env.__mxcsr &= ~FE_INVALID; - /* An FE_INVALID exception shall trigger a SIGFPE signal. - fctrl bits 5..2,0 indicate which floating-point exceptions shall, when - occurring in the 387 compatible floating-point unit, trigger a trap rather - than merely set the corresponding bit in the fstat register. - mxcsr bits 12..9,7 indicate which floating-point exceptions shall, when - occurring in the SSE registers floating-point unit, trigger a trap rather - than merely set the corresponding bit in the lower part of the mxcsr - register. */ - env.__control &= ~FE_INVALID; - env.__mxcsr &= ~(FE_INVALID << 7); - - if (!(env.__control == orig_env.__control - && env.__status == orig_env.__status - && env.__mxcsr == orig_env.__mxcsr)) - fesetenv (&env); - - return 0; -} - -#elif (defined __APPLE__ && defined __MACH__) && defined __aarch64__ -/* macOS/arm64 */ - -# include <fenv.h> - -static int -sigfpe_on_invalid () -{ - fenv_t env, orig_env; - fegetenv (&env); - orig_env = env; - - /* Clear FE_INVALID exceptions from past operations. - fpsr bits 4..0 indicate which floating-point exceptions have occurred - since the respective bit was last set to zero. */ - env.__fpsr &= ~FE_INVALID; - /* An FE_INVALID exception shall trigger a SIGILL signal. - fpcr bits 12..8 indicate which floating-point exceptions shall, when - occurring, trigger a trap rather than merely set the corresponding bit - in the fpsr register. */ - env.__fpcr |= (FE_INVALID << 8); /* __fpcr_trap_invalid */ - - if (!(env.__fpsr == orig_env.__fpsr && env.__fpcr == orig_env.__fpcr)) - fesetenv (&env); - - return 0; -} - -#elif (defined __APPLE__ && defined __MACH__) && defined __arm__ -/* macOS/arm */ - -# include <fenv.h> - -static int -sigfpe_on_invalid () -{ - fenv_t env; - unsigned int orig_fpscr; - fegetenv (&env); - orig_fpscr = env.__fpscr; - - /* Clear FE_INVALID exceptions from past operations. - fpscr bits 4..0 indicate which floating-point exceptions have occurred - since the respective bit was last set to zero. */ - env.__fpscr &= ~FE_INVALID; - /* An FE_INVALID exception shall trigger a signal. - fpscr bits 12..8 indicate which floating-point exceptions shall, when - occurring, trigger a trap rather than merely set the corresponding bit - in the fpscr register. */ - env.__fpscr |= (FE_INVALID << 8); /* __fpscr_trap_invalid */ - - if (!(env.__fpscr == orig_fpscr)) - fesetenv (&env); - - return 0; -} - -#else - -# undef HAVE_FPE_TRAPPING - +/* And it does not work on arm with software floating-point emulation. */ +#if !(defined __riscv || (defined __GLIBC__ && defined __arm__ && defined __SOFTFP__)) +# define HAVE_FPE_TRAPPING 1 #endif diff --git a/m4/fpe-trapping.m4 b/m4/fpe-trapping.m4 new file mode 100644 index 0000000000..a250d377f8 --- /dev/null +++ b/m4/fpe-trapping.m4 @@ -0,0 +1,20 @@ +# fpe-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. + +# Prerequisites for turning FE_INVALID exceptions into a SIGFPE signal. +AC_DEFUN_ONCE([gl_FPE_TRAPPING], +[ + dnl Get FENV_EXCEPTIONS_TRACKING_LIBM. + AC_REQUIRE([gl_FENV_EXCEPTIONS_TRACKING]) + dnl Get FENV_EXCEPTIONS_TRAPPING_LIBM. + AC_REQUIRE([gl_FENV_EXCEPTIONS_TRAPPING]) + + FPE_TRAPPING_LIBM="$FENV_EXCEPTIONS_TRACKING_LIBM" + if test -z "$FPE_TRAPPING_LIBM"; then + FPE_TRAPPING_LIBM="$FENV_EXCEPTIONS_TRAPPING_LIBM" + fi + AC_SUBST([FPE_TRAPPING_LIBM]) +]) diff --git a/m4/fpe.m4 b/m4/fpe.m4 deleted file mode 100644 index 94ca0d5cc1..0000000000 --- a/m4/fpe.m4 +++ /dev/null @@ -1,74 +0,0 @@ -# fpe.m4 serial 2 -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. - -# Prerequisites for turning FE_INVALID exceptions into a SIGFPE signal. -AC_DEFUN_ONCE([gl_FPE_TRAPPING], -[ - dnl Persuade glibc <fenv.h> to declare feenableexcept(). - AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) - - 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 - AC_DEFINE([HAVE_FEENABLEEXCEPT], [1], - [Define to 1 if you have the 'feenableexcept' function.]) - fi - - 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 - - gl_MUSL_LIBC - - if test $gl_cv_func_feenableexcept_no_libm = yes \ - || test $gl_cv_func_feenableexcept_in_libm = yes; then - if test $gl_cv_func_feenableexcept_no_libm != yes; then - FPE_TRAPPING_LIBM=-lm - else - FPE_TRAPPING_LIBM= - fi - else - if test $gl_cv_func_fpsetmask_no_libm = yes \ - || test $gl_cv_func_fpsetmask_in_libm = yes; then - if test $gl_cv_func_fpsetmask_no_libm != yes; then - FPE_TRAPPING_LIBM=-lm - else - FPE_TRAPPING_LIBM= - fi - else - if test $gl_cv_func_fesettrapenable_no_libm = yes \ - || test $gl_cv_func_fesettrapenable_in_libm = yes; then - if test $gl_cv_func_fesettrapenable_no_libm != yes; then - FPE_TRAPPING_LIBM=-lm - else - FPE_TRAPPING_LIBM= - fi - else - FPE_TRAPPING_LIBM= - fi - fi - fi - AC_REQUIRE([gl_FENV_EXCEPTIONS_TRACKING]) - FPE_TRAPPING_LIBM="$FPE_TRAPPING_LIBM $FENV_EXCEPTIONS_TRACKING_LIBM" - AC_SUBST([FPE_TRAPPING_LIBM]) -]) diff --git a/modules/fpe-trapping b/modules/fpe-trapping index 353e77bdef..f1d5ecc17f 100644 --- a/modules/fpe-trapping +++ b/modules/fpe-trapping @@ -4,13 +4,12 @@ into a signal. Files: lib/fpe-trapping.h -m4/fpe.m4 -m4/mathfunc.m4 -m4/musl.m4 +m4/fpe-trapping.m4 Depends-on: extensions fenv-exceptions-tracking-c99 +fenv-exceptions-trapping configure.ac: gl_FPE_TRAPPING diff --git a/tests/test-fenv-except-state-2.c b/tests/test-fenv-except-state-2.c index b87fbb5a87..bebcf5f590 100644 --- a/tests/test-fenv-except-state-2.c +++ b/tests/test-fenv-except-state-2.c @@ -86,7 +86,7 @@ main () int main () { - fputs ("Skipping test: feenableexcept or fpsetmask or fp_enable not available\n", stderr); + fputs ("Skipping test: feenableexcept not available\n", stderr); return 77; } diff --git a/tests/test-fenv-except-tracking-2.c b/tests/test-fenv-except-tracking-2.c index 1d8529ad04..9844166d81 100644 --- a/tests/test-fenv-except-tracking-2.c +++ b/tests/test-fenv-except-tracking-2.c @@ -94,7 +94,7 @@ main (int argc, char *argv[]) int main () { - fputs ("Skipping test: feenableexcept or fpsetmask or fp_enable not available\n", stderr); + fputs ("Skipping test: feenableexcept not available\n", stderr); return 77; } diff --git a/tests/test-fenv-except-tracking-3.c b/tests/test-fenv-except-tracking-3.c index a7ef77a206..63fabad48f 100644 --- a/tests/test-fenv-except-tracking-3.c +++ b/tests/test-fenv-except-tracking-3.c @@ -57,7 +57,7 @@ main () int main () { - fputs ("Skipping test: feenableexcept or fpsetmask or fp_enable not available\n", stderr); + fputs ("Skipping test: feenableexcept not available\n", stderr); return 77; } diff --git a/tests/test-fenv-except-tracking-5.c b/tests/test-fenv-except-tracking-5.c index 0efb5e6664..449c5d6a23 100644 --- a/tests/test-fenv-except-tracking-5.c +++ b/tests/test-fenv-except-tracking-5.c @@ -72,7 +72,7 @@ main () int main () { - fputs ("Skipping test: feenableexcept or fpsetmask or fp_enable not available\n", stderr); + fputs ("Skipping test: feenableexcept not available\n", stderr); return 77; } diff --git a/tests/test-nan-2.c b/tests/test-nan-2.c index b82ebabf4b..b0d65b0c06 100644 --- a/tests/test-nan-2.c +++ b/tests/test-nan-2.c @@ -77,7 +77,7 @@ main () int main () { - fputs ("Skipping test: feenableexcept or fpsetmask or fp_enable not available\n", stderr); + fputs ("Skipping test: feenableexcept not available\n", stderr); return 77; } diff --git a/tests/test-snan-2.c b/tests/test-snan-2.c index 5e5940609c..0a722a05ac 100644 --- a/tests/test-snan-2.c +++ b/tests/test-snan-2.c @@ -147,7 +147,7 @@ main (int argc, char *argv[]) int main () { - fputs ("Skipping test: feenableexcept or fpsetmask or fp_enable not available\n", stderr); + fputs ("Skipping test: feenableexcept not available\n", stderr); return 77; } -- 2.34.1