1
0
mirror of https://git.savannah.gnu.org/git/gnulib.git synced 2025-08-10 04:43:00 +03:00

fenv-exceptions-state-c99: New module.

* lib/fenv.in.h (fegetexceptflag, fesetexceptflag): New declarations.
* lib/fenv-except-state-get.c: New file, baed on glibc.
* lib/fenv-except-state-set.c: New file, baed on glibc.
* m4/mathfunc.m4 (gl_MATHFUNC): Handle also the 'fexcept_t *' type.
* m4/fenv-exceptions-state.m4: New file.
* modules/fenv-exceptions-state-c99: New file.
* doc/posix-functions/fegetexceptflag.texi: Mention the new module.
* doc/posix-functions/fesetexceptflag.texi: Mention the new module and
the glibc, musl libc, macOS, AIX, mingw bugs.
This commit is contained in:
Bruno Haible
2023-10-30 16:39:19 +01:00
parent 6d2dfab57d
commit ee6460d256
9 changed files with 1304 additions and 13 deletions

View File

@@ -1,3 +1,16 @@
2023-10-30 Bruno Haible <bruno@clisp.org>
fenv-exceptions-state-c99: New module.
* lib/fenv.in.h (fegetexceptflag, fesetexceptflag): New declarations.
* lib/fenv-except-state-get.c: New file, baed on glibc.
* lib/fenv-except-state-set.c: New file, baed on glibc.
* m4/mathfunc.m4 (gl_MATHFUNC): Handle also the 'fexcept_t *' type.
* m4/fenv-exceptions-state.m4: New file.
* modules/fenv-exceptions-state-c99: New file.
* doc/posix-functions/fegetexceptflag.texi: Mention the new module.
* doc/posix-functions/fesetexceptflag.texi: Mention the new module and
the glibc, musl libc, macOS, AIX, mingw bugs.
2023-10-30 Bruno Haible <bruno@clisp.org> 2023-10-30 Bruno Haible <bruno@clisp.org>
fenv-exceptions-tracking-{c99,c23}: Fix the x86_64 and i386 case. fenv-exceptions-tracking-{c99,c23}: Fix the x86_64 and i386 case.

View File

@@ -4,15 +4,15 @@
POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/fegetexceptflag.html} POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/fegetexceptflag.html}
Gnulib module: --- Gnulib module: fenv-exceptions-state-c99
Portability problems fixed by Gnulib: Portability problems fixed by Gnulib:
@itemize @itemize
@end itemize
Portability problems not fixed by Gnulib:
@itemize
@item @item
This function is missing on some platforms: This function is missing on some platforms:
FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, IRIX 6.5, Solaris 9, Cygwin 1.7.7, MSVC 9, Android 4.4. FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, IRIX 6.5, Solaris 9, Cygwin 1.7.7, MSVC 9, Android 4.4.
@end itemize @end itemize
Portability problems not fixed by Gnulib:
@itemize
@end itemize

View File

@@ -4,15 +4,30 @@
POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/fesetexceptflag.html} POSIX specification:@* @url{https://pubs.opengroup.org/onlinepubs/9699919799/functions/fesetexceptflag.html}
Gnulib module: --- Gnulib module: fenv-exceptions-state-c99
Portability problems fixed by Gnulib: Portability problems fixed by Gnulib:
@itemize @itemize
@end itemize
Portability problems not fixed by Gnulib:
@itemize
@item @item
This function is missing on some platforms: This function is missing on some platforms:
FreeBSD 5.2.1, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, IRIX 6.5, Solaris 9, Cygwin 1.7.7, MSVC 9, Android 4.4. FreeBSD 5.2.1, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, IRIX 6.5, Solaris 9, Cygwin 1.7.7, MSVC 9, Android 4.4.
@item
This function triggers floating-point exception traps although it shouldn't, on
@c https://sourceware.org/bugzilla/show_bug.cgi?id=30990
glibc 2.37/i386, glibc 2.37/x86_64,
@c https://sourceware.org/bugzilla/show_bug.cgi?id=30988
glibc 2.37/powerpc,
musl libc, Mac OS X 10.5, mingw.
@item
This function clears too many floating-point exception flags on
@c https://sourceware.org/bugzilla/show_bug.cgi?id=30998
glibc 2.37/alpha.
@item
This function is also buggy on
@c Without the override, the unit test test-fenv-except-state-1 fails.
AIX 7.3.1.
@end itemize
Portability problems not fixed by Gnulib:
@itemize
@end itemize @end itemize

353
lib/fenv-except-state-get.c Normal file
View File

@@ -0,0 +1,353 @@
/* Functions for saving the floating-point exception status flags.
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>/{fgetexcptflg.c,fsetexcptflg.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)
/* On most OSes, fexcept_t is binary-equivalent to an 'unsigned short'.
On NetBSD, OpenBSD, Solaris, Cygwin, MSVC, Android/x86_64, Minix, fexcept_t
is equivalent to an 'unsigned int'.
A simple C cast does the necessary conversion. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
# if defined _MSC_VER
unsigned int mxcsr;
_FPU_GETSSECW (mxcsr);
*saved_flags = x86hardware_to_exceptions (mxcsr) & FE_ALL_EXCEPT & exceptions;
# else
unsigned short fstat;
_FPU_GETSTAT (fstat);
unsigned int mxcsr = 0;
if (CPU_HAS_SSE ())
{
/* Look at the flags in the SSE unit as well. */
_FPU_GETSSECW (mxcsr);
}
*saved_flags = x86hardware_to_exceptions (fstat | mxcsr)
& FE_ALL_EXCEPT & exceptions;
# endif
return 0;
}
# elif defined __aarch64__ /* arm64 */
/* On Linux, NetBSD, and Android, fexcept_t is binary-equivalent to
an 'unsigned int'.
On macOS, fexcept_t is binary-equivalent to an 'unsigned short'.
On FreeBSD and OpenBSD, fexcept_t is binary-equivalent to an 'unsigned long'.
A simple C cast does the necessary conversion. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
unsigned long fpsr;
_FPU_GETFPSR (fpsr);
*saved_flags = fpsr & FE_ALL_EXCEPT & exceptions;
return 0;
}
# elif defined __arm__
/* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
# ifdef __SOFTFP__
return -1;
# else
unsigned int fpscr;
_FPU_GETCW (fpscr);
*saved_flags = fpscr & FE_ALL_EXCEPT & exceptions;
return 0;
# endif
}
# elif defined __alpha
/* On all OSes except NetBSD and OpenBSD, fexcept_t is binary-equivalent to
an 'unsigned long'.
On NetBSD, it is equivalent to an 'unsigned short'.
On OpenBSD, it is equivalent to an 'unsigned int'.
A simple C cast does the necessary conversion. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
unsigned long swcr = __ieee_get_fp_control ();
*saved_flags = swcr & FE_ALL_EXCEPT & exceptions;
return 0;
}
# elif defined __hppa
/* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
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");
*saved_flags = (s.halfreg[0] >> 27) & FE_ALL_EXCEPT & exceptions;
return 0;
}
# elif defined __ia64__
/* On all OSes except NetBSD, fexcept_t is binary-equivalent to
an 'unsigned long'.
On NetBSD, it is equivalent to an 'unsigned short'.
A simple C cast does the necessary conversion. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
unsigned long fpsr;
_FPU_GETCW (fpsr);
*saved_flags = (fpsr >> 13) & FE_ALL_EXCEPT & exceptions;
return 0;
}
# elif defined __m68k__
/* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
unsigned int fpsr;
_FPU_GETFPSR (fpsr);
*saved_flags = fpsr & FE_ALL_EXCEPT & exceptions;
return 0;
}
# elif defined __mips__
/* On all OSes except NetBSD and OpenBSD, fexcept_t is binary-equivalent to
an 'unsigned short'.
On NetBSD and OpenBSD, it is equivalent to an 'unsigned int'.
A simple C cast does the necessary conversion. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
unsigned int fcsr;
_FPU_GETCW (fcsr);
*saved_flags = fcsr & FE_ALL_EXCEPT & exceptions;
return 0;
}
# elif defined __loongarch__
/* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
unsigned int fcsr;
_FPU_GETCW (fcsr);
*saved_flags = fcsr & FE_ALL_EXCEPT & exceptions;
return 0;
}
# elif defined __powerpc__
/* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
union { unsigned long long u; double f; } memenv;
_FPU_GETCW_AS_DOUBLE (memenv.f);
*saved_flags = memenv.u & FE_ALL_EXCEPT & exceptions;
return 0;
}
# elif defined __riscv
/* On all OSes except FreeBSD, fexcept_t is binary-equivalent to
an 'unsigned int'.
On FreeBSD, it is equivalent to an 'unsigned long'.
A simple C cast does the necessary conversion. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
unsigned int flags;
__asm__ __volatile__ ("frflags %0" : "=r" (flags)); /* same as "csrr %0, fflags" */
*saved_flags = flags & FE_ALL_EXCEPT & exceptions;
return 0;
}
# elif defined __s390__ || defined __s390x__
/* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
unsigned int fpc;
_FPU_GETCW (fpc);
# if FE_INEXACT == 8 /* glibc compatible FE_* values */
*saved_flags = ((fpc >> 16) | ((fpc & 0x00000300) == 0 ? fpc >> 8 : 0))
& FE_ALL_EXCEPT & exceptions;
# else /* musl libc compatible FE_* values */
*saved_flags = (fpc | ((fpc & 0x00000300) == 0 ? fpc << 8 : 0))
& FE_ALL_EXCEPT & exceptions;
# endif
return 0;
}
# elif defined __sh__
/* On glibc, fexcept_t is binary-equivalent to an 'unsigned short'.
On all other OSes, fexcept_t is binary-equivalent to an 'unsigned int'.
A simple C cast does the necessary conversion. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
unsigned int fpscr;
_FPU_GETCW (fpscr);
*saved_flags = fpscr & FE_ALL_EXCEPT & exceptions;
return 0;
}
# elif defined __sparc
/* On all OSes except Solaris, fexcept_t is binary-equivalent to an 'unsigned long'.
On Solaris, fexcept_t is an 'int'.
A simple C cast does the necessary conversion. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
unsigned long fsr;
_FPU_GETCW (fsr);
# if FE_INEXACT == 32 /* glibc compatible FE_* values */
*saved_flags = fsr & FE_ALL_EXCEPT & exceptions;
# else /* Solaris compatible FE_* values */
*saved_flags = (fsr >> 5) & FE_ALL_EXCEPT & exceptions;
# endif
return 0;
}
# 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_FPSETSTICKY
/* FreeBSD ≥ 3.1, NetBSD ≥ 1.1, OpenBSD, IRIX, Solaris, Minix ≥ 3.2. */
/* Get fpgetsticky, fpsetsticky. */
# 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
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
fp_except_t flags = fpgetsticky ();
*saved_flags = flags & FE_ALL_EXCEPT & exceptions;
return 0;
}
# elif defined _AIX && defined __powerpc__ /* AIX */
# include <float.h>
# include <fpxcp.h>
/* Documentation:
<https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-clr-flag-fp-set-flag-fp-read-flag-fp-swap-flag-subroutine> */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
fpflag_t flags = fp_read_flag ();
*saved_flags = fpflag_to_exceptions (flags) & FE_ALL_EXCEPT & exceptions;
return 0;
}
# else
# define NEED_FALLBACK 1
# endif
#endif
#if NEED_FALLBACK
/* A dummy fallback. */
int
fegetexceptflag (fexcept_t *saved_flags, int exceptions)
{
/* Just like fetestexcept. */
*saved_flags = 0;
return 0;
}
#endif

597
lib/fenv-except-state-set.c Normal file
View File

@@ -0,0 +1,597 @@
/* Functions for saving the floating-point exception status flags.
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>/{fgetexcptflg.c,fsetexcptflg.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)
/* On most OSes, fexcept_t is binary-equivalent to an 'unsigned short'.
On NetBSD, OpenBSD, Solaris, Cygwin, MSVC, Android/x86_64, Minix, fexcept_t
is equivalent to an 'unsigned int'.
A simple C cast does the necessary conversion. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
exceptions &= FE_ALL_EXCEPT;
unsigned int desired_flags = (unsigned int) *saved_flags;
# if defined _MSC_VER
exceptions = exceptions_to_x86hardware (exceptions);
desired_flags = exceptions_to_x86hardware (desired_flags);
/* Modify the flags in the SSE unit. */
unsigned int mxcsr, orig_mxcsr;
_FPU_GETSSECW (orig_mxcsr);
mxcsr = orig_mxcsr ^ ((orig_mxcsr ^ desired_flags) & exceptions);
if (mxcsr != orig_mxcsr)
_FPU_SETSSECW (mxcsr);
# else
/* The flags can be set in the 387 unit or in the SSE unit.
When we need to clear a flag, we need to do so in both units,
due to the way fetestexcept() is implemented.
When we need to set a flag, it is sufficient to do it in the SSE unit,
because that is guaranteed to not trap. However, on i386 CPUs that have
only a 387 unit, set the flags in the 387, as long as this cannot trap. */
if (CPU_HAS_SSE ())
{
/* Modify the flags in the SSE unit. */
unsigned int mxcsr, orig_mxcsr;
_FPU_GETSSECW (orig_mxcsr);
mxcsr = orig_mxcsr ^ ((orig_mxcsr ^ desired_flags) & exceptions);
if (mxcsr != orig_mxcsr)
_FPU_SETSSECW (mxcsr);
/* Modify the flags in the 387 unit, but only by clearing bits, not by
setting bits. */
x86_387_fenv_t env;
unsigned short orig_status_word;
__asm__ __volatile__ ("fnstenv %0" : "=m" (*&env));
orig_status_word = env.__status_word;
env.__status_word &= ~ (exceptions & ~desired_flags);
if (env.__status_word != orig_status_word)
__asm__ __volatile__ ("fldenv %0" : : "m" (*&env));
}
# if !(defined __x86_64__ || defined _M_X64)
else
{
/* Modify the flags in the 387 unit. */
x86_387_fenv_t env;
unsigned short orig_status_word;
__asm__ __volatile__ ("fnstenv %0" : "=m" (*&env));
orig_status_word = env.__status_word;
env.__status_word ^= ((env.__status_word ^ desired_flags) & exceptions);
if (env.__status_word != orig_status_word)
{
if ((~env.__control_word) & env.__status_word & exceptions)
{
/* Setting the exception flags may trigger a trap (at the next
floating-point instruction, but that does not matter).
ISO C 23 § 7.6.4.5 does not allow it. */
return -1;
}
__asm__ __volatile__ ("fldenv %0" : : "m" (*&env));
}
}
# endif
# endif
return 0;
}
# elif defined __aarch64__ /* arm64 */
/* On Linux, NetBSD, and Android, fexcept_t is binary-equivalent to
an 'unsigned int'.
On macOS, fexcept_t is binary-equivalent to an 'unsigned short'.
On FreeBSD and OpenBSD, fexcept_t is binary-equivalent to an 'unsigned long'.
A simple C cast does the necessary conversion. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
unsigned long desired_flags = (unsigned long) *saved_flags;
unsigned long fpsr, orig_fpsr;
_FPU_GETFPSR (orig_fpsr);
fpsr = orig_fpsr ^ ((orig_fpsr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
if (fpsr != orig_fpsr)
_FPU_SETFPSR (fpsr);
/* Possibly some new exception flags have been set. But just storing them
does not cause a trap to be executed (when traps are enabled). */
return 0;
}
# elif defined __arm__
/* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
# ifdef __SOFTFP__
if (exceptions != 0)
return -1;
# else
unsigned int desired_flags = (unsigned int) *saved_flags;
unsigned int fpscr, orig_fpscr;
_FPU_GETCW (orig_fpscr);
fpscr = orig_fpscr ^ ((orig_fpscr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
if (fpscr != orig_fpscr)
_FPU_SETCW (fpscr);
# endif
return 0;
}
# elif defined __alpha
/* On all OSes except NetBSD and OpenBSD, fexcept_t is binary-equivalent to
an 'unsigned long'.
On NetBSD, it is equivalent to an 'unsigned short'.
On OpenBSD, it is equivalent to an 'unsigned int'.
A simple C cast does the necessary conversion. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
unsigned long desired_flags = (unsigned long) *saved_flags;
unsigned long swcr, orig_swcr;
orig_swcr = __ieee_get_fp_control ();
swcr = orig_swcr ^ ((orig_swcr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
if (swcr != orig_swcr)
__ieee_set_fp_control (swcr);
/* Possibly some new exception flags have been set. But just storing them
does not cause a trap to be executed (when traps are enabled). */
return 0;
}
# elif defined __hppa
/* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
unsigned int desired_flags = (unsigned int) *saved_flags;
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];
/* Modify all the relevant bits. */
s.halfreg[0] ^= (s.halfreg[0] ^ (desired_flags << 27)) & ((FE_ALL_EXCEPT & exceptions) << 27);
if (s.halfreg[0] != old_halfreg0)
{
/* Store the new status word. */
__asm__ __volatile__ ("fldd 0(%0),%%fr0" : : "r" (&s.fpreg), "m" (s.fpreg) : "%r0");
}
/* Possibly some new exception flags have been set. But just storing them
does not cause a trap to be executed (when traps are enabled). */
return 0;
}
# elif defined __ia64__
/* On all OSes except NetBSD, fexcept_t is binary-equivalent to
an 'unsigned long'.
On NetBSD, it is equivalent to an 'unsigned short'.
A simple C cast does the necessary conversion. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
unsigned long desired_flags = (unsigned long) *saved_flags;
unsigned long fpsr, orig_fpsr;
_FPU_GETCW (orig_fpsr);
fpsr = orig_fpsr ^ ((orig_fpsr ^ (desired_flags << 13)) & ((FE_ALL_EXCEPT & exceptions) << 13));
if (fpsr != orig_fpsr)
_FPU_SETCW (fpsr);
/* Possibly some new exception flags have been set. But just storing them
does not cause a trap to be executed (when traps are enabled). */
return 0;
}
# elif defined __m68k__
/* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
unsigned int desired_flags = (unsigned int) *saved_flags;
unsigned int fpsr, orig_fpsr;
_FPU_GETFPSR (orig_fpsr);
fpsr = orig_fpsr ^ ((orig_fpsr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
if (fpsr != orig_fpsr)
_FPU_SETFPSR (fpsr);
/* Possibly some new exception flags have been set. But just storing them
does not cause a trap to be executed (when traps are enabled). */
return 0;
}
# elif defined __mips__
/* On all OSes except NetBSD and OpenBSD, fexcept_t is binary-equivalent to
an 'unsigned short'.
On NetBSD and OpenBSD, it is equivalent to an 'unsigned int'.
A simple C cast does the necessary conversion. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
unsigned int desired_flags = (unsigned int) *saved_flags;
unsigned int fcsr, orig_fcsr;
_FPU_GETCW (orig_fcsr);
fcsr = orig_fcsr ^ ((orig_fcsr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
if (fcsr != orig_fcsr)
_FPU_SETCW (fcsr);
return 0;
}
# elif defined __loongarch__
/* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
unsigned int desired_flags = (unsigned int) *saved_flags;
unsigned int fcsr, orig_fcsr;
_FPU_GETCW (orig_fcsr);
fcsr = orig_fcsr ^ ((orig_fcsr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
if (fcsr != orig_fcsr)
_FPU_SETCW (fcsr);
/* Possibly some new exception flags have been set. But just storing them
does not cause a trap to be executed (when traps are enabled). */
return 0;
}
# elif defined __powerpc__
/* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
/* The hardware does not support setting an exception flag without triggering
a trap, except through the "Ignore Exceptions Mode", bits FE0 and FE1 of
the MSR register set to zero, that can be obtained through a system call:
- On Linux and NetBSD: prctl (PR_SET_FPEXC, PR_FP_EXC_DISABLED);
- On AIX: fp_trap (FP_TRAP_OFF);
But that is not what we need here, as it would have a persistent effect on
the thread. */
exceptions &= FE_ALL_EXCEPT;
unsigned int desired_flags = (unsigned int) *saved_flags;
desired_flags &= exceptions;
union { unsigned long long u; double f; } memenv, orig_memenv;
_FPU_GETCW_AS_DOUBLE (memenv.f);
orig_memenv = memenv;
/* Instead of clearing FE_INVALID (= bit 29), we need to clear the
individual bits. */
memenv.u &= ~ (exceptions & FE_INVALID
? (exceptions & ~FE_INVALID) | 0x01F80700U
: exceptions);
/* Instead of setting FE_INVALID (= bit 29), we need to set one of the
individual bits: bit 10 or, if that does not work, bit 24. */
memenv.u |= (desired_flags & FE_INVALID
? (desired_flags & ~FE_INVALID) | (1U << 10)
: desired_flags);
if (!(memenv.u == orig_memenv.u))
{
if (memenv.u & (exceptions >> 22))
{
/* Setting the exception flags may trigger a trap.
ISO C 23 § 7.6.4.5 does not allow it. */
return -1;
}
_FPU_SETCW_AS_DOUBLE (memenv.f);
if (desired_flags & FE_INVALID)
{
/* Did it work? */
_FPU_GETCW_AS_DOUBLE (memenv.f);
if ((memenv.u & FE_INVALID) == 0)
{
memenv.u |= (1U << 24);
_FPU_SETCW_AS_DOUBLE (memenv.f);
}
}
}
return 0;
}
# elif defined __riscv
/* On all OSes except FreeBSD, fexcept_t is binary-equivalent to
an 'unsigned int'.
On FreeBSD, it is equivalent to an 'unsigned long'.
A simple C cast does the necessary conversion. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
# if 1 /* both should be equivalent */
exceptions &= FE_ALL_EXCEPT;
unsigned int desired_flags = (unsigned int) *saved_flags;
desired_flags &= exceptions;
__asm__ __volatile__ ("csrc fflags, %0" : : "r" (exceptions));
__asm__ __volatile__ ("csrs fflags, %0" : : "r" (desired_flags));
# else
unsigned int desired_flags = (unsigned int) *saved_flags;
unsigned int fcsr, orig_fcsr;
__asm__ __volatile__ ("frflags %0" : "=r" (orig_fcsr)); /* same as "csrr %0, fflags" */
fcsr = orig_fcsr ^ ((orig_fcsr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
if (fcsr != orig_fcsr)
__asm__ __volatile__ ("fsflags %0" : : "r" (fcsr)); /* same as "csrw fflags, %0" */
# endif
return 0;
}
# elif defined __s390__ || defined __s390x__
/* On all OSes, fexcept_t is binary-equivalent to an 'unsigned int'. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
unsigned int desired_flags = (unsigned int) *saved_flags;
unsigned int fpc, orig_fpc;
_FPU_GETCW (orig_fpc);
# if FE_INEXACT == 8 /* glibc compatible FE_* values */
fpc = orig_fpc ^ ((orig_fpc ^ (desired_flags << 16)) & ((FE_ALL_EXCEPT & exceptions) << 16));
if ((fpc & 0x00000300) == 0)
/* Clear the corresponding bits of the "data exception code". */
fpc &= ~((FE_ALL_EXCEPT & exceptions) << 8);
# else /* musl libc compatible FE_* values */
fpc = orig_fpc ^ ((orig_fpc ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
if ((fpc & 0x00000300) == 0)
/* Clear the corresponding bits of the "data exception code". */
fpc &= ~((FE_ALL_EXCEPT & exceptions) >> 8);
# endif
if (fpc != orig_fpc)
_FPU_SETCW (fpc);
/* Possibly some new exception flags have been set. But just storing them
does not cause a trap to be executed (when traps are enabled). */
return 0;
}
# elif defined __sh__
/* On glibc, fexcept_t is binary-equivalent to an 'unsigned short'.
On all other OSes, fexcept_t is binary-equivalent to an 'unsigned int'.
A simple C cast does the necessary conversion. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
unsigned int desired_flags = (unsigned int) *saved_flags;
unsigned int fpscr, orig_fpscr;
_FPU_GETCW (orig_fpscr);
fpscr = orig_fpscr ^ ((orig_fpscr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
if (fpscr != orig_fpscr)
_FPU_SETCW (fpscr);
/* Possibly some new exception flags have been set. But just storing them
does not cause a trap to be executed (when traps are enabled). */
return 0;
}
# elif defined __sparc
/* On all OSes except Solaris, fexcept_t is binary-equivalent to an 'unsigned long'.
On Solaris, fexcept_t is an 'int'.
A simple C cast does the necessary conversion. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
unsigned long desired_flags = (unsigned long) *saved_flags;
unsigned long fsr, orig_fsr;
_FPU_GETCW (orig_fsr);
# if FE_INEXACT == 32 /* glibc compatible FE_* values */
fsr = orig_fsr ^ ((orig_fsr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
# else /* Solaris compatible FE_* values */
fsr = orig_fsr ^ ((orig_fsr ^ (desired_flags << 5)) & ((FE_ALL_EXCEPT & exceptions) << 5));
# endif
if (fsr != orig_fsr)
_FPU_SETCW (fsr);
/* Possibly some new exception flags have been set. But just storing them
does not cause a trap to be executed (when traps are enabled). */
return 0;
}
# 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 defined __sun && ((defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86)) && defined __SUNPRO_C
/* Solaris/i386, Solaris/x86_64. */
/* On these platforms, fpsetsticky cannot be used here, because it may generate
traps (since fpsetsticky calls _putsw, which modifies the control word of the
387 unit). Instead, we need to modify only the flags in the SSE unit. */
/* Accessors for the mxcsr register. Fortunately, the Solaris cc supports a
poor form of 'asm'. */
static void
getssecw (unsigned int *mxcsr_p)
{
# if defined __x86_64__ || defined _M_X64
asm ("stmxcsr (%rdi)");
# else
/* The compiler generates a stack frame. Therefore the first argument is in
8(%ebp), not in 4(%esp). */
asm ("movl 8(%ebp),%eax");
asm ("stmxcsr (%eax)");
# endif
}
static void
setssecw (unsigned int const *mxcsr_p)
{
# if defined __x86_64__ || defined _M_X64
asm ("ldmxcsr (%rdi)");
# else
/* The compiler generates a stack frame. Therefore the first argument is in
8(%ebp), not in 4(%esp). */
asm ("movl 8(%ebp),%eax");
asm ("ldmxcsr (%eax)");
# endif
}
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
exceptions &= FE_ALL_EXCEPT;
unsigned int desired_flags = (unsigned int) *saved_flags;
/* Modify the flags in the SSE unit. */
unsigned int mxcsr, orig_mxcsr;
getssecw (&orig_mxcsr);
mxcsr = orig_mxcsr ^ ((orig_mxcsr ^ desired_flags) & exceptions);
if (mxcsr != orig_mxcsr)
setssecw (&mxcsr);
return 0;
}
# elif HAVE_FPSETSTICKY
/* FreeBSD ≥ 3.1, NetBSD ≥ 1.1, OpenBSD, IRIX, Solaris, Minix ≥ 3.2. */
/* Get fpgetsticky, fpsetsticky. */
# 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
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
unsigned long desired_flags = (unsigned long) *saved_flags;
fp_except_t flags, orig_flags;
orig_flags = fpgetsticky ();
flags = orig_flags ^ ((orig_fsr ^ desired_flags) & FE_ALL_EXCEPT & exceptions);
if (flags != orig_flags)
fpsetsticky (flags);
/* Possibly some new exception flags have been set. But just storing them
does not cause a trap to be executed (when traps are enabled). */
return 0;
}
# elif defined _AIX && defined __powerpc__ /* AIX */
# include <float.h>
# include <fpxcp.h>
# include <fptrap.h>
/* Documentation:
<https://www.ibm.com/docs/en/aix/7.3?topic=f-fp-clr-flag-fp-set-flag-fp-read-flag-fp-swap-flag-subroutine> */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
exceptions &= FE_ALL_EXCEPT;
unsigned int desired_flags = (unsigned int) *saved_flags;
int exceptions_to_clear = exceptions & ~desired_flags;
int exceptions_to_set = exceptions & desired_flags;
fpflag_t orig_flags = fp_read_flag ();
/* In addition to clearing FE_INVALID (= bit 29), we also need to clear the
individual bits. */
fpflag_t f_to_clear =
exceptions_to_fpflag (exceptions_to_clear)
| (exceptions_to_clear & FE_INVALID ? 0x01F80700U : 0);
/* Instead of setting FE_INVALID (= bit 29), we need to set one of the
individual bits: bit 10 or, if that does not work, bit 24. */
fpflag_t f_to_set =
(exceptions_to_set & FE_INVALID
? exceptions_to_fpflag (exceptions_to_set & ~FE_INVALID) | (1U << 10)
: exceptions_to_fpflag (exceptions_to_set));
if (f_to_clear != 0)
fp_clr_flag (f_to_clear);
if (f_to_set != 0)
{
if ((fegetexcept_impl () & exceptions) != 0)
{
/* Setting the exception flags may trigger a trap.
ISO C 23 § 7.6.4.5 does not allow it. */
return -1;
}
fp_set_flag (f_to_set);
if (exceptions & FE_INVALID)
{
/* Did it work? */
if ((fp_read_flag () & FP_INVALID) == 0)
fp_set_flag (1U << 24);
}
}
return 0;
}
# else
# define NEED_FALLBACK 1
# endif
#endif
#if NEED_FALLBACK
/* A dummy fallback. */
int
fesetexceptflag (fexcept_t const *saved_flags, int exceptions)
{
if (exceptions != 0)
return -1;
return 0;
}
#endif

View File

@@ -544,7 +544,8 @@ _GL_WARN_ON_USE (fesetexcept, "fesetexcept is unportable - "
/* ISO C 99 § 7.6.2 Floating-point exceptions /* ISO C 99 § 7.6.2 Floating-point exceptions
ISO C 23 § 7.6.4 Floating-point exceptions ISO C 23 § 7.6.4 Floating-point exceptions
API with fexcept_t */ API with fexcept_t.
The return type changed from 'void' to 'int' in ISO C 11. */
#if !@HAVE_FENV_H@ #if !@HAVE_FENV_H@
@@ -610,6 +611,52 @@ typedef unsigned long fexcept_t;
#endif #endif
#if @GNULIB_FEGETEXCEPTFLAG@
/* Stores the current floating-point exception status flags denoted
by EXCEPTIONS in *SAVED_FLAGS. */
# if @REPLACE_FEGETEXCEPTFLAG@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
# undef fegetexceptflag
# define fegetexceptflag rpl_fegetexceptflag
# endif
_GL_FUNCDECL_RPL (fegetexceptflag, int,
(fexcept_t *saved_flags, int exceptions));
_GL_CXXALIAS_RPL (fegetexceptflag, int,
(fexcept_t *saved_flags, int exceptions));
# else
# if !@HAVE_FEGETEXCEPTFLAG@
_GL_FUNCDECL_SYS (fegetexceptflag, int,
(fexcept_t *saved_flags, int exceptions));
# endif
_GL_CXXALIAS_SYS (fegetexceptflag, int,
(fexcept_t *saved_flags, int exceptions));
# endif
_GL_CXXALIASWARN (fegetexceptflag);
#endif
#if @GNULIB_FESETEXCEPTFLAG@
/* Copies the flags denoted by EXCEPTIONS from *SAVED_FLAGS to the
floating-point exception status flags. */
# if @REPLACE_FESETEXCEPTFLAG@
# if !(defined __cplusplus && defined GNULIB_NAMESPACE)
# undef fesetexceptflag
# define fesetexceptflag rpl_fesetexceptflag
# endif
_GL_FUNCDECL_RPL (fesetexceptflag, int,
(fexcept_t const *saved_flags, int exceptions));
_GL_CXXALIAS_RPL (fesetexceptflag, int,
(fexcept_t const *saved_flags, int exceptions));
# else
# if !@HAVE_FESETEXCEPTFLAG@
_GL_FUNCDECL_SYS (fesetexceptflag, int,
(fexcept_t const *saved_flags, int exceptions));
# endif
_GL_CXXALIAS_SYS (fesetexceptflag, int,
(fexcept_t const *saved_flags, int exceptions));
# endif
_GL_CXXALIASWARN (fesetexceptflag);
#endif
#endif /* _@GUARD_PREFIX@_FENV_H */ #endif /* _@GUARD_PREFIX@_FENV_H */
#endif /* _@GUARD_PREFIX@_FENV_H */ #endif /* _@GUARD_PREFIX@_FENV_H */

221
m4/fenv-exceptions-state.m4 Normal file
View File

@@ -0,0 +1,221 @@
# fenv-exceptions-state.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([gl_FENV_EXCEPTIONS_STATE],
[
AC_REQUIRE([gl_FENV_H_DEFAULTS])
AC_REQUIRE([AC_CANONICAL_HOST])
gl_MATHFUNC([fesetexceptflag], [int], [(fexcept_t const *, int)],
[#include <fenv.h>
fexcept_t fx_ret;
])
if test $gl_cv_func_fesetexceptflag_no_libm = yes \
|| test $gl_cv_func_fesetexceptflag_in_libm = yes; then
dnl It needs linking with -lm on
dnl glibc, FreeBSD, NetBSD, OpenBSD, AIX, HP-UX, IRIX, Solaris, Android.
if test $gl_cv_func_fesetexceptflag_no_libm = yes; then
FENV_EXCEPTIONS_STATE_LIBM=
else
FENV_EXCEPTIONS_STATE_LIBM=-lm
fi
dnl On glibc 2.19/s390,s390x, fegetexceptflag is not consistent with the
dnl generic implementation of fetestexceptflag, leading to a failure of
dnl test-fenv-except-state-3. Fixed through
dnl <https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=5d96fe8c0dc3450bafe6c2aae2dabc76819df3e0>.
case "$host" in
s390*-*-linux*)
AC_CACHE_CHECK([whether fegetexceptflag works],
[gl_cv_func_fegetexceptflag_works],
[AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[
#include <string.h> /* for __GNU_LIBRARY__ */
#ifdef __GNU_LIBRARY__
#include <features.h>
#if __GLIBC__ == 2 && __GLIBC_MINOR__ <= 22
Unlucky user
#endif
#endif
]],
[])],
[gl_cv_func_fegetexceptflag_works="guessing yes"],
[gl_cv_func_fegetexceptflag_works="guessing no"])
])
case "$gl_cv_func_fegetexceptflag_works" in
*yes) ;;
*)
REPLACE_FEGETEXCEPTFLAG=1
REPLACE_FESETEXCEPTFLAG=1
;;
esac
;;
esac
if test $REPLACE_FESETEXCEPTFLAG = 0; then
dnl Persuade glibc <fenv.h> to declare feenableexcept().
AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS])
gl_MATHFUNC([feenableexcept], [int], [(int)], [#include <fenv.h>])
dnl On glibc 2.37 for PowerPC, i386, x86_64, fesetexceptflag may raise
dnl traps. Likewise on Mac OS X 10.5.8 on i386, x86_64 and on mingw.
AC_CACHE_CHECK([whether fesetexceptflag is guaranteed non-trapping],
[gl_cv_func_fesetexceptflag_works1],
[if test $gl_cv_func_feenableexcept_no_libm = yes \
|| test $gl_cv_func_feenableexcept_in_libm = yes; then
dnl A platform that has feenableexcept.
save_LIBS="$LIBS"
if test $gl_cv_func_feenableexcept_no_libm != yes; then
LIBS="$LIBS -lm"
fi
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <fenv.h>
static volatile double a, b;
static volatile long double al, bl;
]],
[[fexcept_t saved_flags;
if (feraiseexcept (FE_INVALID) == 0
&& fegetexceptflag (&saved_flags, FE_INVALID) == 0
&& feclearexcept (FE_INVALID) == 0
&& feenableexcept (FE_INVALID) == 0
&& fesetexceptflag (&saved_flags, FE_INVALID) == 0)
{
a = 1.0; b = a + a;
al = 1.0L; bl = al + al;
}
return 0;
]])
],
[gl_cv_func_fesetexceptflag_works1=yes],
[gl_cv_func_fesetexceptflag_works1=no],
[case "$host_os" in
# Guess yes or no on glibc systems, depending on CPU.
*-gnu*)
case "$host_cpu" in
changequote(,)dnl
powerpc* | i[34567]86 | x86_64)
changequote([,])dnl
gl_cv_func_fesetexceptflag_works1="guessing no" ;;
*)
gl_cv_func_fesetexceptflag_works1="guessing yes" ;;
esac
;;
# If we don't know, obey --enable-cross-guesses.
*) gl_cv_func_fesetexceptflag_works1="$gl_cross_guess_normal" ;;
esac
])
LIBS="$save_LIBS"
else
case "$host_os" in
# Guess no on musl libc.
# In musl/src/fenv/fesetexceptflag.c, fesetexceptflag() explicitly
# invokes feraiseexcept(). It's mentioned in
# <https://wiki.musl-libc.org/functional-differences-from-glibc.html>.
*-musl* | midipix*)
gl_cv_func_fesetexceptflag_works1="guessing no"
;;
# Guess no on macOS.
darwin*)
gl_cv_func_fesetexceptflag_works1="guessing no"
;;
# Guess no on mingw.
mingw* | windows*)
AC_EGREP_CPP([Problem], [
#ifdef __MINGW32__
Problem
#endif
],
[gl_cv_func_fesetexceptflag_works1="guessing no"],
[gl_cv_func_fesetexceptflag_works1="guessing yes"])
;;
*) gl_cv_func_fesetexceptflag_works1="guessing yes" ;;
esac
fi
])
dnl On glibc 2.37 for alpha, fesetexceptflag clears too many flag bits.
AC_CACHE_CHECK([whether fesetexceptflag obeys its arguments],
[gl_cv_func_fesetexceptflag_works2],
[save_LIBS="$LIBS"
LIBS="$LIBS $FENV_EXCEPTIONS_STATE_LIBM"
AC_RUN_IFELSE(
[AC_LANG_PROGRAM([[
#include <fenv.h>
]],
[[fexcept_t f1, f2;
if (feraiseexcept (FE_DIVBYZERO | FE_OVERFLOW | FE_INEXACT) == 0
&& fegetexceptflag (&f1, FE_DIVBYZERO | FE_OVERFLOW | FE_INEXACT) == 0
&& feclearexcept (FE_OVERFLOW | FE_INEXACT) == 0
&& fegetexceptflag (&f2, FE_OVERFLOW) == 0
&& fesetexceptflag (&f1, FE_DIVBYZERO | FE_OVERFLOW) == 0
&& fesetexceptflag (&f2, FE_OVERFLOW) == 0
&& fetestexcept (FE_DIVBYZERO) != FE_DIVBYZERO)
return 1;
return 0;
]])
],
[gl_cv_func_fesetexceptflag_works2=yes],
[gl_cv_func_fesetexceptflag_works2=no],
[case "$host_os" in
# Guess yes or no on glibc systems, depending on CPU.
*-gnu*)
case "$host_cpu" in
alpha*)
gl_cv_func_fesetexceptflag_works2="guessing no" ;;
*)
gl_cv_func_fesetexceptflag_works2="guessing yes" ;;
esac
;;
# If we don't know, obey --enable-cross-guesses.
*) gl_cv_func_fesetexceptflag_works2="$gl_cross_guess_normal" ;;
esac
])
LIBS="$save_LIBS"
])
case "$gl_cv_func_fesetexceptflag_works1" in
*yes) ;;
*) REPLACE_FESETEXCEPTFLAG=1 ;;
esac
case "$gl_cv_func_fesetexceptflag_works2" in
*yes) ;;
*) REPLACE_FESETEXCEPTFLAG=1 ;;
esac
dnl Additionally, on AIX, the unit test test-fenv-except-state-1 fails
dnl if we don't override fesetexceptflag.
case "$host" in
powerpc*-*-aix*) REPLACE_FESETEXCEPTFLAG=1 ;;
esac
dnl Additionally, on MSVC, we want the bits in the saved state to be
dnl identified by the FE_* macros, so that the fetestexceptflag function
dnl can be implemented like on other platforms. This requires conversions
dnl (exceptions_to_x86hardware, x86hardware_to_exceptions) in both
dnl of the fegetexceptflag, fesetexceptflag functions.
case "$host_os" in
mingw* | windows*)
AC_EGREP_CPP([Problem], [
#ifndef __MINGW32__
Problem
#endif
],
[REPLACE_FEGETEXCEPTFLAG=1; REPLACE_FESETEXCEPTFLAG=1],
[])
;;
esac
fi
else
HAVE_FEGETEXCEPTFLAG=0
HAVE_FESETEXCEPTFLAG=0
FENV_EXCEPTIONS_STATE_LIBM=
fi
if { test $HAVE_FEGETEXCEPTFLAG = 0 || test $REPLACE_FEGETEXCEPTFLAG = 1; } \
|| { test $HAVE_FESETEXCEPTFLAG = 0 || test $REPLACE_FESETEXCEPTFLAG = 1; }; then
gl_PREREQ_FENV_EXCEPTIONS
dnl Possibly need -lm for fpgetsticky(), fpsetsticky().
if test $gl_cv_func_fpsetsticky_no_libm = no \
&& test $gl_cv_func_fpsetsticky_in_libm = yes \
&& test -z "$FENV_EXCEPTIONS_STATE_LIBM"; then
FENV_EXCEPTIONS_STATE_LIBM=-lm
fi
fi
AC_SUBST([FENV_EXCEPTIONS_STATE_LIBM])
])

View File

@@ -1,4 +1,4 @@
# mathfunc.m4 serial 15 # mathfunc.m4 serial 16
dnl Copyright (C) 2010-2023 Free Software Foundation, Inc. dnl Copyright (C) 2010-2023 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it, dnl gives unlimited permission to copy and/or distribute it,
@@ -39,9 +39,11 @@ AC_DEFUN([gl_MATHFUNC],
[m4_bpatsubst( [m4_bpatsubst(
[m4_bpatsubst( [m4_bpatsubst(
[m4_bpatsubst( [m4_bpatsubst(
[m4_bpatsubst(
[m4_bpatsubst( [m4_bpatsubst(
[m4_bpatsubst( [m4_bpatsubst(
[$3], [$3],
[fexcept_t\( const\)? \*], [&fx_ret])],
[int\( const\)? \*], [int\( const\)? \*],
[&i_ret])], [&i_ret])],
[float\( const\)? \*], [&f_ret])], [float\( const\)? \*], [&f_ret])],

View File

@@ -0,0 +1,43 @@
Description:
Functions for saving the floating-point exception status flags:
fegetexceptflag, fesetexceptflag.
Files:
lib/fenv-except-state-get.c
lib/fenv-except-state-set.c
lib/fenv-private.h
m4/fenv-exceptions-state.m4
m4/fenv-exceptions.m4
m4/mathfunc.m4
Depends-on:
fenv
configure.ac:
gl_FENV_EXCEPTIONS_STATE
gl_CONDITIONAL([GL_COND_OBJ_FENV_EXCEPTIONS_STATE_GET],
[test $HAVE_FEGETEXCEPTFLAG = 0 || test $REPLACE_FEGETEXCEPTFLAG = 1])
gl_CONDITIONAL([GL_COND_OBJ_FENV_EXCEPTIONS_STATE_SET],
[test $HAVE_FESETEXCEPTFLAG = 0 || test $REPLACE_FESETEXCEPTFLAG = 1])
gl_FENV_MODULE_INDICATOR([fegetexceptflag])
gl_FENV_MODULE_INDICATOR([fesetexceptflag])
Makefile.am:
if GL_COND_OBJ_FENV_EXCEPTIONS_STATE_GET
lib_SOURCES += fenv-except-state-get.c
endif
if GL_COND_OBJ_FENV_EXCEPTIONS_STATE_SET
lib_SOURCES += fenv-except-state-set.c
endif
Include:
#include <fenv.h>
Link:
$(FENV_EXCEPTIONS_STATE_LIBM)
License:
LGPLv2+
Maintainer:
all