It's caused by an ABI change in mingw:
<https://sourceforge.net/p/mingw-w64/mingw-w64/ci/
5c5973cf5f021db8fd75e9667e63881ccd169320/>.
Reported by Collin Funk in
<https://lists.gnu.org/archive/html/bug-gnulib/2025-04/msg00215.html>.
* m4/fenv-environment.m4 (gl_FENV_ENVIRONMENT): Update comments for
mingw 13.
* lib/fenv-private.h (exceptions_to_x86hardware,
x86hardware_to_exceptions): On mingw >= 13, define these like on MSVC.
* lib/fenv-round.c (fegetround, fesetround): Do the safe mapping also on
mingw >= 13.
* lib/fenv-except-state-set.c (fesetexceptflag): Do the
exceptions_to_x86hardware conversion also on other platforms than MSVC.
* lib/fenv-except-tracking-clear.c (feclearexcept): Likewise.
* lib/fenv-except-tracking-set.c (fesetexcept): Likewise.
* lib/fenv-except-trapping.c (feenableexcept, fedisableexcept,
fegetexcept): Do the exceptions_to_x86hardware and
x86hardware_to_exceptions conversions also on other platforms than MSVC.
* lib/fenv-env.c (fegetenv, fesetenv): Add new implementation for
mingw >= 13.
* doc/posix-functions/fesetenv.texi: Mention the new mingw bug.
* doc/posix-functions/feupdateenv.texi: Mention the new mingw bug.
+2025-06-11 Bruno Haible <bruno@clisp.org>
+
+ fenv*: Fix compilation error with mingw 13.
+ It's caused by an ABI change in mingw:
+ <https://sourceforge.net/p/mingw-w64/mingw-w64/ci/5c5973cf5f021db8fd75e9667e63881ccd169320/>.
+ Reported by Collin Funk in
+ <https://lists.gnu.org/archive/html/bug-gnulib/2025-04/msg00215.html>.
+ * m4/fenv-environment.m4 (gl_FENV_ENVIRONMENT): Update comments for
+ mingw 13.
+ * lib/fenv-private.h (exceptions_to_x86hardware,
+ x86hardware_to_exceptions): On mingw >= 13, define these like on MSVC.
+ * lib/fenv-round.c (fegetround, fesetround): Do the safe mapping also on
+ mingw >= 13.
+ * lib/fenv-except-state-set.c (fesetexceptflag): Do the
+ exceptions_to_x86hardware conversion also on other platforms than MSVC.
+ * lib/fenv-except-tracking-clear.c (feclearexcept): Likewise.
+ * lib/fenv-except-tracking-set.c (fesetexcept): Likewise.
+ * lib/fenv-except-trapping.c (feenableexcept, fedisableexcept,
+ fegetexcept): Do the exceptions_to_x86hardware and
+ x86hardware_to_exceptions conversions also on other platforms than MSVC.
+ * lib/fenv-env.c (fegetenv, fesetenv): Add new implementation for
+ mingw >= 13.
+ * doc/posix-functions/fesetenv.texi: Mention the new mingw bug.
+ * doc/posix-functions/feupdateenv.texi: Mention the new mingw bug.
+
2025-06-09 Collin Funk <collin.funk1@gmail.com>
Silence 'time-stamp' warnings with bleeding-edge Emacs.
@item
This function does not work on some platforms:
@c https://cgit.freebsd.org/src/commit/?id=34cc08e336987a8ebc316595e3f552a4c09f1fd4
-FreeBSD 12.2/arm64.
+FreeBSD 12.2/arm64,
+@c fesetenv (FE_DFL_ENV) does not reset the rounding direction.
+mingw 13.
@item
This function does not restore the floating-point exception trap bits
on some platforms:
@c https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=a8c79c4088e8c04e4297936efa0dee6c8e6e974d
glibc 2.5/ia64,
@c https://cgit.freebsd.org/src/commit/?id=34cc08e336987a8ebc316595e3f552a4c09f1fd4
-FreeBSD 12.2/arm64.
+FreeBSD 12.2/arm64,
+@c feupdateenv (FE_DFL_ENV) does not restore the rounding direction.
+mingw 13.
@item
This function forgets about the currently set floating-point exception flags
on some platforms:
# if (defined __x86_64__ || defined _M_X64) || (defined __i386 || defined _M_IX86)
-/* On all OSes except MSVC, macOS, Solaris, fenv_t is binary-equivalent to
+/* On all OSes except MSVC, mingw ≥ 13, macOS, Solaris, fenv_t is
+ binary-equivalent to
- either a x86_387_fenv_t (7 'unsigned int' words)
where mxcsr is stored:
- for glibc/i386: in __eip = more[1].
_Fe_ctl bits 9..8 are the rounding direction,
_Fe_ctl bits 4..0 are the exception trap bits (inverted),
_Fe_stat bits 4..0 are the exception flags.
+ On mingw ≥ 13, it's a
+ struct { unsigned int _Fe_ctl, _Fe_stat; }, where
+ _Fe_ctl bits 9..8 are the rounding direction,
+ _Fe_ctl bits 23..22 are the rounding direction
+ from the 387 compatible floating-point unit,
+ _Fe_ctl bits 31..30 are the rounding direction
+ from the SSE compatible floating-point unit,
+ _Fe_ctl bits 4..0 are the exception trap bits (inverted),
+ _Fe_ctl bits 20..16 are the exception trap bits (inverted)
+ from the 387 compatible floating-point unit,
+ _Fe_ctl bits 28..24 are the exception trap bits (inverted)
+ from the SSE compatible floating-point unit,
+ _Fe_stat bits 4..0 are the exception flags,
+ _Fe_stat bits 20..16 are the exception flags
+ from the 387 compatible floating-point unit,
+ _Fe_stat bits 28..24 are the exception flags
+ from the SSE compatible floating-point unit.
On macOS, it's a
struct { unsigned short __control, __status; unsigned int __mxcsr; ... }.
On Solaris, it's a
| (mxcsr & (1 << 4) ? FE_UNDERFLOW : 0)
| (mxcsr & (1 << 5) ? FE_INEXACT : 0);
+# elif (defined __MINGW32__ && FE_INVALID != 0x01) /* mingw ≥ 13 */
+
+ x86_387_fenv_t env387;
+
+ __asm__ __volatile__ ("fnstenv %0" : "=m" (*&env387));
+ /* Note: fnstenv masks all floating-point exceptions until the fldcw
+ below. */
+ __asm__ __volatile__ ("fldcw %0" : : "m" (env387.__control_word));
+
+ /* rounding direction */
+ unsigned int round_387 = (env387.__control_word & 0x0C00) >> 2;
+ /* exception trap bits (inverted) */
+ unsigned int trapbits_387 = x86hardware_to_exceptions (env387.__control_word);
+ /* exception flags */
+ unsigned int excflags_387 = x86hardware_to_exceptions (env387.__status_word);
+
+ unsigned int mxcsr;
+ _FPU_GETSSECW (mxcsr);
+
+ /* rounding direction */
+ unsigned int round_sse = (mxcsr & 0x6000) >> 5;
+ /* exception trap bits (inverted) */
+ unsigned int trapbits_sse = x86hardware_to_exceptions (mxcsr >> 7);
+ /* exception flags */
+ unsigned int excflags_sse = x86hardware_to_exceptions (mxcsr);
+
+ envp->_Fe_ctl =
+ (round_sse << 22) | (round_387 << 14) | round_sse | round_387
+ | (trapbits_sse << 24) | (trapbits_387 << 16) | trapbits_sse | trapbits_387;
+ envp->_Fe_stat =
+ (excflags_sse << 24) | (excflags_387 << 16) | excflags_sse | excflags_387;
+
# elif defined __APPLE__ && defined __MACH__ /* macOS */
_FPU_GETCW (envp->__control);
| (envp->_Fe_stat & FE_INEXACT ? 1 << 5 : 0);
_FPU_SETSSECW (mxcsr);
+# elif (defined __MINGW32__ && FE_INVALID != 0x01) /* mingw ≥ 13 */
+
+ unsigned short env_fctrl;
+ unsigned short env_fstat;
+ unsigned int env_mxcsr;
+ /* On mingw, FE_DFL_ENV is NULL. */
+ if (envp == FE_DFL_ENV)
+ {
+ env_fctrl = 0x3F;
+ env_fstat = 0;
+ env_mxcsr = 0x3F << 7;
+ }
+ else
+ {
+ /* rounding direction */
+ unsigned int round_387 = (envp->_Fe_ctl >> 14) & 0x0300;
+ unsigned int round_sse = (envp->_Fe_ctl >> 22) & 0x0300;
+ /* exception trap bits (inverted) */
+ unsigned int trapbits_387 = (envp->_Fe_ctl >> 16) & 0x1F;
+ unsigned int trapbits_sse = (envp->_Fe_ctl >> 24) & 0x1F;
+ /* exception flags */
+ unsigned int excflags_387 = (envp->_Fe_stat >> 16) & 0x1F;
+ unsigned int excflags_sse = (envp->_Fe_stat >> 24) & 0x1F;
+
+ env_fctrl = (round_387 << 2) | exceptions_to_x86hardware (trapbits_387);
+ env_fstat = exceptions_to_x86hardware (excflags_387);
+ env_mxcsr = (round_sse << 5)
+ | (exceptions_to_x86hardware (trapbits_sse) << 7)
+ | exceptions_to_x86hardware (excflags_sse);
+ }
+
+ /* In the SSE unit. */
+ unsigned int mxcsr = env_mxcsr;
+ _FPU_SETSSECW (mxcsr);
+
+ /* In the 387 unit. */
+ x86_387_fenv_t env387;
+ __asm__ __volatile__ ("fnstenv %0" : "=m" (*&env387));
+ /* Note: fnstenv masks all floating-point exceptions until the fldenv
+ below. */
+ env387.__control_word = env_fctrl;
+ env387.__status_word = env_fstat;
+ __asm__ __volatile__ ("fldenv %0" : : "m" (*&env387));
+
# elif defined __APPLE__ && defined __MACH__ /* macOS */
unsigned short fctrl;
unsigned int desired_flags = (unsigned int) *saved_flags;
-# if defined _MSC_VER
exceptions = exceptions_to_x86hardware (exceptions);
desired_flags = exceptions_to_x86hardware (desired_flags);
+# if defined _MSC_VER
+
/* Modify the flags in the SSE unit. */
unsigned int mxcsr, orig_mxcsr;
_FPU_GETSSECW (orig_mxcsr);
{
exceptions &= FE_ALL_EXCEPT;
-# if defined _MSC_VER
-
exceptions = exceptions_to_x86hardware (exceptions);
+# if defined _MSC_VER
+
/* Clear the bits only in the SSE unit. */
unsigned int mxcsr, orig_mxcsr;
_FPU_GETSSECW (orig_mxcsr);
{
exceptions &= FE_ALL_EXCEPT;
-# if defined _MSC_VER
exceptions = exceptions_to_x86hardware (exceptions);
+# if defined _MSC_VER
+
/* Set the flags in the SSE unit. */
unsigned int mxcsr, orig_mxcsr;
_FPU_GETSSECW (orig_mxcsr);
}
return x86hardware_to_exceptions (fstat | mxcsr) & FE_ALL_EXCEPT & exceptions;
+
# endif
}
{
exceptions &= FE_ALL_EXCEPT;
-# if defined _MSC_VER
-
exceptions = exceptions_to_x86hardware (exceptions);
+# if defined _MSC_VER
+
/* Enable the traps only in the SSE unit. */
unsigned int mxcsr, orig_mxcsr;
_FPU_GETSSECW (orig_mxcsr);
_FPU_SETSSECW (mxcsr);
unsigned int trapbits = 0x3f & ~(orig_mxcsr >> 7);
- return x86hardware_to_exceptions (trapbits);
# else
_FPU_SETSSECW (mxcsr);
}
- return FE_ALL_EXCEPT & ~orig_fctrl;
+ unsigned int trapbits = 0x3f & ~orig_fctrl;
# endif
+
+ return x86hardware_to_exceptions (trapbits);
}
int
{
exceptions &= FE_ALL_EXCEPT;
-# if defined _MSC_VER
-
exceptions = exceptions_to_x86hardware (exceptions);
+# if defined _MSC_VER
+
/* Disable the traps only in the SSE unit. */
unsigned int mxcsr, orig_mxcsr;
_FPU_GETSSECW (orig_mxcsr);
_FPU_SETSSECW (mxcsr);
unsigned int trapbits = 0x3f & ~(orig_mxcsr >> 7);
- return x86hardware_to_exceptions (trapbits);
# else
_FPU_SETSSECW (mxcsr);
}
- return FE_ALL_EXCEPT & ~orig_fctrl;
+ unsigned int trapbits = 0x3f & ~orig_fctrl;
# endif
+
+ return x86hardware_to_exceptions (trapbits);
}
int
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;
+ unsigned int trapbits = 0x3f & ~fctrl;
# endif
+
+ return x86hardware_to_exceptions (trapbits);
}
# elif defined __aarch64__ /* arm64 */
}
x86_387_fenv_t;
-# if defined _MSC_VER
-/* The MSVC header files have different values for the floating-point exceptions
- than all the other platforms. Define some handy macros for conversion. */
+# if defined _MSC_VER || (defined __MINGW32__ && FE_INVALID != 0x01)
+/* The MSVC and mingw ≥ 13 header files have different values for the
+ floating-point exceptions than all the other platforms. Define some
+ handy macros for conversion. */
# define exceptions_to_x86hardware(exceptions) \
( ((exceptions) & FE_INVALID ? 0x01 : 0) \
| ((exceptions) & FE_DIVBYZERO ? 0x04 : 0) \
unsigned short fctrl;
_FPU_GETCW (fctrl);
# endif
-# ifdef _MSC_VER
+# if defined _MSC_VER || (defined __MINGW32__ && FE_INVALID != 0x01)
/* The MSVC header files have different values for the rounding directions
- than all the other platforms, and the even changed between MSVC 14 and
+ than all the other platforms, and they even changed between MSVC 14 and
MSVC 14.30 (!). Map
0x0000 -> FE_TONEAREST = 0
0x0400 -> FE_DOWNWARD
int
fesetround (int rounding_direction)
{
-# ifdef _MSC_VER
+# if defined _MSC_VER || (defined __MINGW32__ && FE_INVALID != 0x01)
/* The MSVC header files have different values for the rounding directions
than all the other platforms. */
if ((rounding_direction & ~0x0300) != 0)
return -1;
/* The MSVC header files have different values for the rounding directions
- than all the other platforms, and the even changed between MSVC 14 and
+ than all the other platforms, and they even changed between MSVC 14 and
MSVC 14.30 (!). Map
FE_TONEAREST = 0 -> 0x0000
FE_DOWNWARD -> 0x0400
# fenv-environment.m4
-# serial 4
+# serial 5
dnl Copyright (C) 2023-2025 Free Software Foundation, Inc.
dnl This file is free software; the Free Software Foundation
dnl gives unlimited permission to copy and/or distribute it,
esac
dnl The fesetenv function does not work on FreeBSD 12.2/arm64 (see
dnl <https://cgit.freebsd.org/src/commit/?id=34cc08e336987a8ebc316595e3f552a4c09f1fd4>),
+ dnl on mingw 13 (where fesetenv (FE_DFL_ENV) does not reset the rounding
+ dnl direction),
dnl on musl libc/{i386,x86_64} and AIX and Solaris and MSVC 14 (where it
dnl fails to restore the exception trap bits),
- dnl on mingw (where calling it with FE_DFL_ENV argument has no effect on
- dnl the mxcsr register),
+ dnl on mingw < 13 (where calling it with FE_DFL_ENV argument has no effect
+ dnl on the mxcsr register),
dnl and on NetBSD/m68k.
AC_CACHE_CHECK([whether fesetenv works],
[gl_cv_func_fesetenv_works],
dnl and on musl libc/{i386,x86_64} and AIX and Solaris and mingw 10 (where
dnl it fails to restore the exception trap bits),
dnl and on FreeBSD 12.2/arm64 (see
- dnl <https://cgit.freebsd.org/src/commit/?id=34cc08e336987a8ebc316595e3f552a4c09f1fd4>).
+ dnl <https://cgit.freebsd.org/src/commit/?id=34cc08e336987a8ebc316595e3f552a4c09f1fd4>),
+ dnl and on mingw 13 (where feupdateenv (FE_DFL_ENV) does not restore the
+ dnl rounding direction).
dnl On MSVC 14 it may even fail.
AC_CACHE_CHECK([whether feupdateenv works],
[gl_cv_func_feupdateenv_works],