crt/misc/fesetenv.c: Do not clobber `env` with `FNSTENV`
... and do not involve `STMXCSR` unless SSE is supported.
This can be shown by the following program:
```
int main(void)
{
/* Compute 1.0/3.0 in default FPU mode */
volatile float somefloat = 1.0;
somefloat /= 3.0;
/* Output it in float and hex formats */
printf("%.9g\thex: %x\n", somefloat, *(int *)&somefloat);
fenv_t a, b;
fegetenv(&a); /* Save fpu env */
fesetround(FE_TOWARDZERO); /* Set round mode */
fesetenv(&a); /* Restore fpu env (round mode must also be restored) */
fegetenv(&b); /* Get current fpu env */
/* Compute 1.0/3.0 after changing and restoring fpu env */
volatile float somefloat2 = 1.0;
somefloat2 /= 3.0;
/* Output it in float and hex formats */
printf("%.9g\thex: %x\n", somefloat2, *(int *)&somefloat2);
/* Output FPU control words */
printf ("FPU control words: %x, %x\n", a.__control_word, b.__control_word);
return 0;
}
```
On Linux, compiling and running this program gives the following result:
```
lh_mouse@lhmouse-ideapad ~/Desktop $ gcc -v 2>&1 | egrep '^Target:'
Target: x86_64-linux-gnu
lh_mouse@lhmouse-ideapad ~/Desktop $ gcc test.c -lm -m32 && ./a.out
0.333333343 hex: 3eaaaaab
0.333333343 hex: 3eaaaaab
FPU control words: 37f, 37f
lh_mouse@lhmouse-ideapad ~/Desktop $ gcc test.c -lm -m64 && ./a.out
0.333333343 hex: 3eaaaaab
0.333333343 hex: 3eaaaaab
FPU control words: 37f, 37f
```
, while before this commit, our CRT produced wrong results because the FPU
control word would be clobbered:
```
E:\Desktop>gcc test.c && a.exe
0.333333343 hex: 3eaaaaab
0.333333313 hex: 3eaaaaaa
FPU control words: 37f, f7f
```
Reference: https://sourceforge.net/p/mingw-w64/mailman/message/36596484/
Signed-off-by: Liu Hao <lh_mouse@126.com>
diff --git a/mingw-w64-crt/misc/fesetenv.c b/mingw-w64-crt/misc/fesetenv.c
index f998017..9b44fab 100644
--- a/mingw-w64-crt/misc/fesetenv.c
+++ b/mingw-w64-crt/misc/fesetenv.c
@@ -65,16 +65,17 @@
else
{
fenv_t env = *envp;
+ int has_sse = __mingw_has_sse ();
int _mxcsr;
- __asm__ ("fnstenv %0\n"
- "stmxcsr %1" : "=m" (*&env), "=m" (*&_mxcsr));
/*_mxcsr = ((int)envp->__unused0 << 16) | (int)envp->__unused1; *//* mxcsr low and high */
+ if (has_sse)
+ __asm__ ("stmxcsr %0" : "=m" (*&_mxcsr));
env.__unused0 = 0xffff;
env.__unused1 = 0xffff;
__asm__ volatile ("fldenv %0" : : "m" (env)
: "st", "st(1)", "st(2)", "st(3)", "st(4)",
"st(5)", "st(6)", "st(7)");
- if (__mingw_has_sse ())
+ if (has_sse)
__asm__ volatile ("ldmxcsr %0" : : "m" (*&_mxcsr));
}