This uses _control87 for setting the control bits, and implements the mirror operation of _statusfp.
This fixes a bunch of tests in msvcr120.
Signed-off-by: Martin Storsjo martin@martin.st --- dlls/msvcrt/math.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c index 124cdf80098..81ae9b02a61 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -5988,6 +5988,19 @@ int CDECL fesetenv(const fenv_t *env) __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) ); }
+ return 0; +#elif defined(__aarch64__) + _control87(env->_Fe_ctl, 0xffffffff); + ULONG_PTR fpsr; + __asm__ __volatile__( "mrs %0, fpsr" : "=r" (fpsr) ); + fpsr &= ~0x9f; + if (env->_Fe_stat & _SW_INVALID) fpsr |= 0x1; + if (env->_Fe_stat & _SW_ZERODIVIDE) fpsr |= 0x2; + if (env->_Fe_stat & _SW_OVERFLOW) fpsr |= 0x4; + if (env->_Fe_stat & _SW_UNDERFLOW) fpsr |= 0x8; + if (env->_Fe_stat & _SW_INEXACT) fpsr |= 0x10; + if (env->_Fe_stat & _SW_DENORMAL) fpsr |= 0x80; + __asm__ __volatile__( "msr fpsr, %0" :: "r" (fpsr) ); return 0; #else FIXME( "not implemented\n" );
This is essentially the same as for aarch64, except the bits that are split over two registers, fpsr and fpcr in aarch64, are all located in one single register fpscr on arm.
Signed-off-by: Martin Storsjo martin@martin.st --- dlls/msvcrt/math.c | 66 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+)
diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c index 81ae9b02a61..3c85b1dc23b 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -5206,6 +5206,16 @@ unsigned int CDECL _statusfp(void) if (fpsr & 0x8) flags |= _SW_UNDERFLOW; if (fpsr & 0x10) flags |= _SW_INEXACT; if (fpsr & 0x80) flags |= _SW_DENORMAL; +#elif defined(__arm__) + DWORD fpscr; + + __asm__ __volatile__( "vmrs %0, fpscr" : "=r" (fpscr) ); + if (fpscr & 0x1) flags |= _SW_INVALID; + if (fpscr & 0x2) flags |= _SW_ZERODIVIDE; + if (fpscr & 0x4) flags |= _SW_OVERFLOW; + if (fpscr & 0x8) flags |= _SW_UNDERFLOW; + if (fpscr & 0x10) flags |= _SW_INEXACT; + if (fpscr & 0x80) flags |= _SW_DENORMAL; #else FIXME( "not implemented\n" ); #endif @@ -5253,6 +5263,18 @@ unsigned int CDECL _clearfp(void) if (fpsr & 0x80) flags |= _SW_DENORMAL; fpsr &= ~0x9f; __asm__ __volatile__( "msr fpsr, %0" :: "r" (fpsr) ); +#elif defined(__arm__) + DWORD fpscr; + + __asm__ __volatile__( "vmrs %0, fpscr" : "=r" (fpscr) ); + if (fpscr & 0x1) flags |= _SW_INVALID; + if (fpscr & 0x2) flags |= _SW_ZERODIVIDE; + if (fpscr & 0x4) flags |= _SW_OVERFLOW; + if (fpscr & 0x8) flags |= _SW_UNDERFLOW; + if (fpscr & 0x10) flags |= _SW_INEXACT; + if (fpscr & 0x80) flags |= _SW_DENORMAL; + fpscr &= ~0x9f; + __asm__ __volatile__( "vmsr fpscr, %0" :: "r" (fpscr) ); #else FIXME( "not implemented\n" ); #endif @@ -5535,6 +5557,37 @@ unsigned int CDECL _control87(unsigned int newval, unsigned int mask) case _RC_DOWN: fpcr |= 0x800000; break; } __asm__ __volatile__( "msr fpcr, %0" :: "r" (fpcr) ); +#elif defined(__arm__) + DWORD fpscr; + + __asm__ __volatile__( "vmrs %0, fpscr" : "=r" (fpscr) ); + if (!(fpscr & 0x100)) flags |= _EM_INVALID; + if (!(fpscr & 0x200)) flags |= _EM_ZERODIVIDE; + if (!(fpscr & 0x400)) flags |= _EM_OVERFLOW; + if (!(fpscr & 0x800)) flags |= _EM_UNDERFLOW; + if (!(fpscr & 0x1000)) flags |= _EM_INEXACT; + if (!(fpscr & 0x8000)) flags |= _EM_DENORMAL; + switch (fpscr & 0xc00000) + { + case 0x400000: flags |= _RC_UP; break; + case 0x800000: flags |= _RC_DOWN; break; + case 0xc00000: flags |= _RC_CHOP; break; + } + flags = (flags & ~mask) | (newval & mask); + fpscr &= ~0xc09f00ul; + if (!(flags & _EM_INVALID)) fpscr |= 0x100; + if (!(flags & _EM_ZERODIVIDE)) fpscr |= 0x200; + if (!(flags & _EM_OVERFLOW)) fpscr |= 0x400; + if (!(flags & _EM_UNDERFLOW)) fpscr |= 0x800; + if (!(flags & _EM_INEXACT)) fpscr |= 0x1000; + if (!(flags & _EM_DENORMAL)) fpscr |= 0x8000; + switch (flags & _MCW_RC) + { + case _RC_CHOP: fpscr |= 0xc00000; break; + case _RC_UP: fpscr |= 0x400000; break; + case _RC_DOWN: fpscr |= 0x800000; break; + } + __asm__ __volatile__( "vmsr fpscr, %0" :: "r" (fpscr) ); #else FIXME( "not implemented\n" ); #endif @@ -6002,6 +6055,19 @@ int CDECL fesetenv(const fenv_t *env) if (env->_Fe_stat & _SW_DENORMAL) fpsr |= 0x80; __asm__ __volatile__( "msr fpsr, %0" :: "r" (fpsr) ); return 0; +#elif defined(__arm__) + _control87(env->_Fe_ctl, 0xffffffff); + DWORD fpscr; + __asm__ __volatile__( "vmrs %0, fpscr" : "=r" (fpscr) ); + fpscr &= ~0x9f; + if (env->_Fe_stat & _SW_INVALID) fpscr |= 0x1; + if (env->_Fe_stat & _SW_ZERODIVIDE) fpscr |= 0x2; + if (env->_Fe_stat & _SW_OVERFLOW) fpscr |= 0x4; + if (env->_Fe_stat & _SW_UNDERFLOW) fpscr |= 0x8; + if (env->_Fe_stat & _SW_INEXACT) fpscr |= 0x10; + if (env->_Fe_stat & _SW_DENORMAL) fpscr |= 0x80; + __asm__ __volatile__( "vmsr fpscr, %0" :: "r" (fpscr) ); + return 0; #else FIXME( "not implemented\n" ); #endif
Hi Martin,
The patch looks good for me. Please split it so one function is modified in a patch.
Thanks, Piotr
Hi,
On Tue, 3 Aug 2021, Piotr Caban wrote:
The patch looks good for me. Please split it so one function is modified in a patch.
I sent the simple parts split now, but I left out the fesetenv parts for now as I want to test and study the fenv_decode/encode aspects wrt ARM a bit more before finalizing those functions.
// Martin
Hi Martin,
On 8/1/21 11:04 PM, Martin Storsjo wrote:
+#elif defined(__aarch64__)
- _control87(env->_Fe_ctl, 0xffffffff);
Please use fenv_decode helper so it can also work in ucrtbase where fegetenv uses fenv_encode.
- ULONG_PTR fpsr;
Please define new variables at the start of a block.
Thanks, Piotr
On Tue, 3 Aug 2021, Piotr Caban wrote:
Hi Martin,
On 8/1/21 11:04 PM, Martin Storsjo wrote:
+#elif defined(__aarch64__)
- _control87(env->_Fe_ctl, 0xffffffff);
Please use fenv_decode helper so it can also work in ucrtbase where fegetenv uses fenv_encode.
Oh, right, I missed how that aspect worked - will do.
- ULONG_PTR fpsr;
Please define new variables at the start of a block.
Oh, oops, will do.
// Martin