From: Bruno Haible Date: Wed, 11 Jun 2025 12:43:04 +0000 (+0200) Subject: fenv*: Fix compilation error with mingw 13. X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f3b9112a5926daf3072b161a41e0ec39bd490779;p=thirdparty%2Fgnulib.git fenv*: Fix compilation error with mingw 13. It's caused by an ABI change in mingw: . Reported by Collin Funk in . * 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. --- diff --git a/ChangeLog b/ChangeLog index 37713d5551..2e25657048 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,28 @@ +2025-06-11 Bruno Haible + + fenv*: Fix compilation error with mingw 13. + It's caused by an ABI change in mingw: + . + Reported by Collin Funk in + . + * 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 Silence 'time-stamp' warnings with bleeding-edge Emacs. diff --git a/doc/posix-functions/fesetenv.texi b/doc/posix-functions/fesetenv.texi index 649b85e929..e759d77683 100644 --- a/doc/posix-functions/fesetenv.texi +++ b/doc/posix-functions/fesetenv.texi @@ -15,7 +15,9 @@ FreeBSD 6.0, NetBSD 5.0, OpenBSD 3.8, Minix 3.1.8, AIX 5.1, Solaris 9, Cygwin 1. @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: diff --git a/doc/posix-functions/feupdateenv.texi b/doc/posix-functions/feupdateenv.texi index 6bff8768b2..5f9ae3a09f 100644 --- a/doc/posix-functions/feupdateenv.texi +++ b/doc/posix-functions/feupdateenv.texi @@ -22,7 +22,9 @@ This function does not work 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: diff --git a/lib/fenv-env.c b/lib/fenv-env.c index f363c5f2e2..637bc3e8c8 100644 --- a/lib/fenv-env.c +++ b/lib/fenv-env.c @@ -105,7 +105,8 @@ fesetenv (fenv_t const *envp) # 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]. @@ -118,6 +119,23 @@ fesetenv (fenv_t const *envp) _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 @@ -147,6 +165,38 @@ fegetenv (fenv_t *envp) | (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); @@ -230,6 +280,50 @@ fesetenv (fenv_t const *envp) | (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; diff --git a/lib/fenv-except-state-set.c b/lib/fenv-except-state-set.c index 3314a43ddf..d43db14b30 100644 --- a/lib/fenv-except-state-set.c +++ b/lib/fenv-except-state-set.c @@ -40,10 +40,11 @@ fesetexceptflag (fexcept_t const *saved_flags, int exceptions) 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); diff --git a/lib/fenv-except-tracking-clear.c b/lib/fenv-except-tracking-clear.c index a0bbc32d3c..32ba66d27a 100644 --- a/lib/fenv-except-tracking-clear.c +++ b/lib/fenv-except-tracking-clear.c @@ -33,10 +33,10 @@ feclearexcept (int exceptions) { 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); diff --git a/lib/fenv-except-tracking-set.c b/lib/fenv-except-tracking-set.c index 280a222990..0f0e008911 100644 --- a/lib/fenv-except-tracking-set.c +++ b/lib/fenv-except-tracking-set.c @@ -33,9 +33,10 @@ fesetexcept (int exceptions) { 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); diff --git a/lib/fenv-except-tracking-test.c b/lib/fenv-except-tracking-test.c index e9ce9751fe..77b9d1d2cb 100644 --- a/lib/fenv-except-tracking-test.c +++ b/lib/fenv-except-tracking-test.c @@ -70,6 +70,7 @@ fetestexcept (int exceptions) } return x86hardware_to_exceptions (fstat | mxcsr) & FE_ALL_EXCEPT & exceptions; + # endif } diff --git a/lib/fenv-except-trapping.c b/lib/fenv-except-trapping.c index fa09545191..62f2446157 100644 --- a/lib/fenv-except-trapping.c +++ b/lib/fenv-except-trapping.c @@ -33,10 +33,10 @@ feenableexcept (int exceptions) { 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); @@ -45,7 +45,6 @@ feenableexcept (int exceptions) _FPU_SETSSECW (mxcsr); unsigned int trapbits = 0x3f & ~(orig_mxcsr >> 7); - return x86hardware_to_exceptions (trapbits); # else @@ -66,9 +65,11 @@ feenableexcept (int exceptions) _FPU_SETSSECW (mxcsr); } - return FE_ALL_EXCEPT & ~orig_fctrl; + unsigned int trapbits = 0x3f & ~orig_fctrl; # endif + + return x86hardware_to_exceptions (trapbits); } int @@ -76,10 +77,10 @@ fedisableexcept (int exceptions) { 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); @@ -88,7 +89,6 @@ fedisableexcept (int exceptions) _FPU_SETSSECW (mxcsr); unsigned int trapbits = 0x3f & ~(orig_mxcsr >> 7); - return x86hardware_to_exceptions (trapbits); # else @@ -109,9 +109,11 @@ fedisableexcept (int exceptions) _FPU_SETSSECW (mxcsr); } - return FE_ALL_EXCEPT & ~orig_fctrl; + unsigned int trapbits = 0x3f & ~orig_fctrl; # endif + + return x86hardware_to_exceptions (trapbits); } int @@ -122,13 +124,14 @@ fegetexcept (void) 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 */ diff --git a/lib/fenv-private.h b/lib/fenv-private.h index 24755f1c32..772d8dce9d 100644 --- a/lib/fenv-private.h +++ b/lib/fenv-private.h @@ -95,9 +95,10 @@ typedef struct } 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) \ diff --git a/lib/fenv-round.c b/lib/fenv-round.c index 49a7e8abae..7303cef460 100644 --- a/lib/fenv-round.c +++ b/lib/fenv-round.c @@ -44,9 +44,9 @@ fegetround (void) 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 @@ -61,13 +61,13 @@ fegetround (void) 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 diff --git a/m4/fenv-environment.m4 b/m4/fenv-environment.m4 index 9667ba5771..e5f08be2ce 100644 --- a/m4/fenv-environment.m4 +++ b/m4/fenv-environment.m4 @@ -1,5 +1,5 @@ # 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, @@ -179,10 +179,12 @@ AC_DEFUN([gl_FENV_ENVIRONMENT], esac dnl The fesetenv function does not work on FreeBSD 12.2/arm64 (see dnl ), + 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], @@ -311,7 +313,9 @@ AC_DEFUN([gl_FENV_ENVIRONMENT], 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 ). + dnl ), + 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],