The x86 style x87/sse split of status bits isn't present on arm64.
Also include a couple cases of missing fenv_encode() in test printouts, to avoid surprising error messages like "expected 1, got 1".
Signed-off-by: Martin Storsjö martin@martin.st --- The test talks about "too old ucrtbase", but neither the UCRT in Windows 11 nor the one statically linked with VS 2022 17.0 preview 2 does the x86 style status bit duplication/shifting, so I'm concluding that this behaviour isn't expected/intended on non-x86 architectures. --- dlls/ucrtbase/tests/misc.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-)
diff --git a/dlls/ucrtbase/tests/misc.c b/dlls/ucrtbase/tests/misc.c index 96dd1acfe54..eb323997e68 100644 --- a/dlls/ucrtbase/tests/misc.c +++ b/dlls/ucrtbase/tests/misc.c @@ -1377,14 +1377,15 @@ static unsigned long fenv_encode(unsigned int e)
#if defined(__i386__) return e<<24 | e<<16 | e; -#else +#elif defined(__x86_64__) return e<<24 | e; +#else + return e; #endif }
static void test_fenv(void) { -#if defined(__i386__) || defined(__x86_64__) static const int tests[] = { 0, FE_INEXACT, @@ -1425,11 +1426,13 @@ static void test_fenv(void)
ret = fegetenv(&env); ok(!ret, "fegetenv returned %x\n", ret); +#if defined(__i386__) || defined(__x86_64__) if (env._Fe_ctl >> 24 != (env._Fe_ctl & 0xff)) { win_skip("fenv_t format not supported (too old ucrtbase)\n"); return; } +#endif fesetround(FE_UPWARD); ok(!env._Fe_stat, "env._Fe_stat = %lx\n", env._Fe_stat); ret = fegetenv(&env2); @@ -1485,13 +1488,13 @@ static void test_fenv(void) ret = fegetexceptflag(&except, ~0); ok(!ret, "Test %d: fegetexceptflag returned %x.\n", i, ret); ok(except == fenv_encode(flags), - "Test %d: expected %x, got %lx\n", i, flags, except); + "Test %d: expected %x, got %lx\n", i, fenv_encode(flags), except);
except = ~0; ret = fegetexceptflag(&except, tests[i]); ok(!ret, "Test %d: fegetexceptflag returned %x.\n", i, ret); ok(except == fenv_encode(tests[i]), - "Test %d: expected %x, got %lx\n", i, tests[i], except); + "Test %d: expected %x, got %lx\n", i, fenv_encode(tests[i]), except); }
for(i=0; i<ARRAY_SIZE(tests); i++) { @@ -1534,7 +1537,6 @@ static void test_fenv(void) ok(!ret, "feclearexceptflag returned %x\n", ret); except = fetestexcept(FE_ALL_EXCEPT); ok(!except, "expected 0, got %lx\n", except); -#endif }
START_TEST(misc)
This uses _control87 for setting the control bits, and implements the mirror operation of _statusfp.
Fix the implementation of fenv_encode for non-x86 architectures to not do the x87/sse bit duplication.
Signed-off-by: Martin Storsjö martin@martin.st --- This uses fenv_decode for consistency with the other codepaths, even if it's a no-op on this architecture. --- dlls/msvcrt/math.c | 32 +++++++++++++++++++++++++++----- 1 file changed, 27 insertions(+), 5 deletions(-)
diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c index 2ba810a9903..6f98d2ffaff 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -5626,7 +5626,7 @@ int CDECL _controlfp_s(unsigned int *cur, unsigned int newval, unsigned int mask return 0; }
-#if _MSVCR_VER >= 140 +#if _MSVCR_VER >= 140 && (defined(__i386__) || defined(__x86_64__)) enum fenv_masks { FENV_X_INVALID = 0x00100010, @@ -5689,7 +5689,6 @@ static __msvcrt_ulong fenv_encode(unsigned int x, unsigned int y) }
/* decodes x87/sse control/status word, returns FALSE on error */ -#if (defined(__i386__) || defined(__x86_64__)) static BOOL fenv_decode(__msvcrt_ulong enc, unsigned int *x, unsigned int *y) { *x = *y = 0; @@ -5723,21 +5722,18 @@ static BOOL fenv_decode(__msvcrt_ulong enc, unsigned int *x, unsigned int *y) } return TRUE; } -#endif #elif _MSVCR_VER >= 120 static __msvcrt_ulong fenv_encode(unsigned int x, unsigned int y) { return x | y; }
-#if (defined(__i386__) || defined(__x86_64__)) static BOOL fenv_decode(__msvcrt_ulong enc, unsigned int *x, unsigned int *y) { *x = *y = enc; return TRUE; } #endif -#endif
#if _MSVCR_VER>=120 /********************************************************************* @@ -6038,6 +6034,32 @@ int CDECL fesetenv(const fenv_t *env) __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) ); }
+ return 0; +#elif defined(__aarch64__) + ULONG_PTR fpsr; + unsigned int unused_cw, fp_cw, unused_stat, fp_stat; + + if (!env->_Fe_ctl && !env->_Fe_stat) { + _fpreset(); + return 0; + } + + if (!fenv_decode(env->_Fe_ctl, &unused_cw, &fp_cw)) + return 1; + if (!fenv_decode(env->_Fe_stat, &unused_stat, &fp_stat)) + return 1; + + _control87(fp_cw, 0xffffffff); + + __asm__ __volatile__( "mrs %0, fpsr" : "=r" (fpsr) ); + fpsr &= ~0x9f; + if (fp_stat & _SW_INVALID) fpsr |= 0x1; + if (fp_stat & _SW_ZERODIVIDE) fpsr |= 0x2; + if (fp_stat & _SW_OVERFLOW) fpsr |= 0x4; + if (fp_stat & _SW_UNDERFLOW) fpsr |= 0x8; + if (fp_stat & _SW_INEXACT) fpsr |= 0x10; + if (fp_stat & _SW_DENORMAL) fpsr |= 0x80; + __asm__ __volatile__( "msr fpsr, %0" :: "r" (fpsr) ); return 0; #else FIXME( "not implemented\n" );
Signed-off-by: Martin Storsjö martin@martin.st --- dlls/msvcrt/math.c | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+)
diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c index 6f98d2ffaff..57345e634fe 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -6061,6 +6061,32 @@ int CDECL fesetenv(const fenv_t *env) if (fp_stat & _SW_DENORMAL) fpsr |= 0x80; __asm__ __volatile__( "msr fpsr, %0" :: "r" (fpsr) ); return 0; +#elif defined(__arm__) && !defined(__SOFTFP__) + DWORD fpscr; + unsigned int unused_cw, fp_cw, unused_stat, fp_stat; + + if (!env->_Fe_ctl && !env->_Fe_stat) { + _fpreset(); + return 0; + } + + if (!fenv_decode(env->_Fe_ctl, &unused_cw, &fp_cw)) + return 1; + if (!fenv_decode(env->_Fe_stat, &unused_stat, &fp_stat)) + return 1; + + _control87(fp_cw, 0xffffffff); + + __asm__ __volatile__( "vmrs %0, fpscr" : "=r" (fpscr) ); + fpscr &= ~0x9f; + if (fp_stat & _SW_INVALID) fpscr |= 0x1; + if (fp_stat & _SW_ZERODIVIDE) fpscr |= 0x2; + if (fp_stat & _SW_OVERFLOW) fpscr |= 0x4; + if (fp_stat & _SW_UNDERFLOW) fpscr |= 0x8; + if (fp_stat & _SW_INEXACT) fpscr |= 0x10; + if (fp_stat & _SW_DENORMAL) fpscr |= 0x80; + __asm__ __volatile__( "vmsr fpscr, %0" :: "r" (fpscr) ); + return 0; #else FIXME( "not implemented\n" ); #endif