On 10.03.2025 14:48, Martin Storsjö wrote:
On Wed, 5 Mar 2025, Jacek Caban wrote:
Based on Wine code by Piotr Caban and Alexandre Julliard, who granted
permission to use it under the mingw-w64 license.
Unlike earlier versions, msvcr120 and UCRT implement fenv.h, but
their representation differs from what mingw-w64
has used so far. fenv_t has a target-independent layout and flags,
requiring translation to and from machine-specific
flags. Generic helpers handle this conversion.
Side note nitpick: The commit message here has longer lines than the
common git standard; it makes it more readable in 80 char wide
terminals if it would be word wrapped to the usual git commit message
width :-)
I didn't know we're sticking with that, I will change it.
It's probably clearer elsewhere, but is the case that x is a fenv word
for x87, and y is one for sse?
It's also kinda hard to look at the constant definitions, as part of
them is identical across FENV_X, but part of them isn't (the upper
bits). For people not intimately familiar with the x86-isms, it would
be nice with some comment somewhere, but I'm not sure where that would
be best placed.
Yes, I will add a comment.
This could really warrant a comment explaining what it does, as 0x20
isn't a named constant.
It originates from your Wine patch:
https://gitlab.winehq.org/wine/wine/-/commit/6391a9f8978b42b71b37c27b673a0a13c21ea577
I guess it's based on testing Windows behavior, I don't know why Windows
does it. I can add a comment like "for Windows compatibility".
BTW, I realized I missed your authorship of the code in the commit
message. Sorry about that, I will fix it.
diff --git a/mingw-w64-crt/misc/fegetenv.c
b/mingw-w64-crt/misc/fegetenv.c
index e17fd491c..cadaf4572 100644
--- a/mingw-w64-crt/misc/fegetenv.c
+++ b/mingw-w64-crt/misc/fegetenv.c
@@ -4,34 +4,25 @@
* No warranty is given; refer to the file DISCLAIMER.PD within this
package.
*/
-#include <fenv.h>
#include <internal.h>
/* 7.6.4.1
The fegetenv function stores the current floating-point environment
in the object pointed to by envp. */
-int fegetenv (fenv_t * envp)
+int fegetenv(fenv_t *env)
{
-#if defined(_ARM_) || defined(__arm__)
- __asm__ volatile ("fmrx %0, FPSCR" : "=r" (*envp));
-#elif defined(_ARM64_) || defined(__aarch64__)
- unsigned __int64 fpcr;
- __asm__ volatile ("mrs %0, fpcr" : "=r" (fpcr));
- envp->__cw = fpcr;
+#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__))
+ unsigned int x87, sse;
+ __mingw_control87_2(0, 0, &x87, &sse);
+ env->_Fe_ctl = fenv_encode(x87, sse);
+ __mingw_setfp(NULL, 0, &x87, 0);
+ __mingw_setfp_sse(NULL, 0, &sse, 0);
+ env->_Fe_stat = fenv_encode(x87, sse);
#else
- __asm__ __volatile__ ("fnstenv %0;": "=m" (*envp));
- /* fnstenv sets control word to non-stop for all exceptions, so we
- need to reload our env to restore the original mask. */
- __asm__ __volatile__ ("fldenv %0" : : "m" (*envp));
- if (__mingw_has_sse ())
- {
- int _mxcsr;
- __asm__ __volatile__ ("stmxcsr %0" : "=m" (_mxcsr));
- envp->__unused0 = (((unsigned int) _mxcsr) >> 16);
- envp->__unused1 = (((unsigned int) _mxcsr) & 0xffff);
- }
-#endif /* defined(_ARM_) || defined(__arm__) || defined(_ARM64_) ||
defined(__aarch64__) */
+ env->_Fe_ctl = fenv_encode(0, _controlfp(0, 0));
+ env->_Fe_stat = fenv_encode(0, _statusfp());
This bit feels a bit asymetrical; in fesetenv we use our own
__mingw_setfp for setting things, but in fegetenv we just use
_controlfp() and _statusfp() from the CRT. (This is also a bit of a
functional change as we've been entirely detached from the CRT's
handling of this bit so far.)
It's probably fine though, but I'm wondering if this would be clearer
if we'd have our own __mingw_controlfp/__mingw_setupfp at first for
ARM/AArch64 too, so we'd have the full loop of both setting and
getting in our own code, just like before. Then we could convert
__mingw_controlfp into a call to the CRT's _controlfp in a separate step.
I will change it.
It doesn't make this patch smaller or easier, but it makes it
marginally easier to grasp the full picture. The separate step of
taking CRT's _controlfp and _statusfp into use would then be easier to
consider on its own. I presume the UCRT's _controlfp/_statusfp works
as it should, but e.g. for msvcrt.dll I'm not sure if anybody has
tested them? (I did testrun these patches with both UCRT and msvcrt on
all 4 architectures, and it does seem to run fine.)
I'd assume so, although Wine testing on ARM is admittedly much less
widespread than on x86. The main source of weird things the fact that
x86 has two separate ways of dealing with floats, ARM doesn't have this
problem.
Aside from that, I think this mostly looks good. Most of the fe*
function are kinda straightforward and everything boils down to calls
to the internal helper functions. As this is based on Wine with quite
well tested implementations, I'm fairly certain that those aspects are ok.
Thanks for the review!
Jacek
_______________________________________________
Mingw-w64-public mailing list
Mingw-w64-public@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public