From 63f3f4283f89366d8c83857e4c93666fa60ac73b Mon Sep 17 00:00:00 2001 From: Piotr Caban Date: Wed, 4 Aug 2021 18:05:06 +0200 Subject: [PATCH] msvcrt: Introduce _setfp helper on aarch64. Signed-off-by: Piotr Caban Signed-off-by: Alexandre Julliard --- dlls/msvcrt/math.c | 169 +++++++++++++++++++++++---------------------- 1 file changed, 85 insertions(+), 84 deletions(-) diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c index b27b6391a6f..ff945ff4bae 100644 --- a/dlls/msvcrt/math.c +++ b/dlls/msvcrt/math.c @@ -5235,7 +5235,7 @@ static BOOL _setfp_sse( unsigned int *cw, unsigned int cw_mask, } #endif -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) static BOOL _setfp( unsigned int *cw, unsigned int cw_mask, unsigned int *sw, unsigned int sw_mask ) { @@ -5355,6 +5355,86 @@ static BOOL _setfp( unsigned int *cw, unsigned int cw_mask, return TRUE; #elif defined(__x86_64__) return _setfp_sse(cw, cw_mask, sw, sw_mask); +#elif defined(__aarch64__) + ULONG_PTR old_fpsr = 0, fpsr = 0, old_fpcr = 0, fpcr = 0; + unsigned int flags; + + cw_mask &= _MCW_EM | _MCW_RC; + sw_mask &= _MCW_EM; + + if (sw) + { + __asm__ __volatile__( "mrs %0, fpsr" : "=r" (fpsr) ); + old_fpsr = fpsr; + + flags = 0; + if (fpsr & 0x1) flags |= _SW_INVALID; + if (fpsr & 0x2) flags |= _SW_ZERODIVIDE; + if (fpsr & 0x4) flags |= _SW_OVERFLOW; + if (fpsr & 0x8) flags |= _SW_UNDERFLOW; + if (fpsr & 0x10) flags |= _SW_INEXACT; + if (fpsr & 0x80) flags |= _SW_DENORMAL; + + *sw = (flags & ~sw_mask) | (*sw & sw_mask); + TRACE("aarch64 update sw %08x to %08x\n", flags, *sw); + fpsr &= ~0x9f; + if (*sw & _SW_INVALID) fpsr |= 0x1; + if (*sw & _SW_ZERODIVIDE) fpsr |= 0x2; + if (*sw & _SW_OVERFLOW) fpsr |= 0x4; + if (*sw & _SW_UNDERFLOW) fpsr |= 0x8; + if (*sw & _SW_INEXACT) fpsr |= 0x10; + if (*sw & _SW_DENORMAL) fpsr |= 0x80; + *sw = flags; + } + + if (cw) + { + __asm__ __volatile__( "mrs %0, fpcr" : "=r" (fpcr) ); + old_fpcr = fpcr; + + flags = 0; + if (!(fpcr & 0x100)) flags |= _EM_INVALID; + if (!(fpcr & 0x200)) flags |= _EM_ZERODIVIDE; + if (!(fpcr & 0x400)) flags |= _EM_OVERFLOW; + if (!(fpcr & 0x800)) flags |= _EM_UNDERFLOW; + if (!(fpcr & 0x1000)) flags |= _EM_INEXACT; + if (!(fpcr & 0x8000)) flags |= _EM_DENORMAL; + switch (fpcr & 0xc00000) + { + case 0x400000: flags |= _RC_UP; break; + case 0x800000: flags |= _RC_DOWN; break; + case 0xc00000: flags |= _RC_CHOP; break; + } + + *cw = (flags & ~cw_mask) | (*cw & cw_mask); + TRACE("aarch64 update cw %08x to %08x\n", flags, *cw); + fpcr &= ~0xc09f00ul; + if (!(*cw & _EM_INVALID)) fpcr |= 0x100; + if (!(*cw & _EM_ZERODIVIDE)) fpcr |= 0x200; + if (!(*cw & _EM_OVERFLOW)) fpcr |= 0x400; + if (!(*cw & _EM_UNDERFLOW)) fpcr |= 0x800; + if (!(*cw & _EM_INEXACT)) fpcr |= 0x1000; + if (!(*cw & _EM_DENORMAL)) fpcr |= 0x8000; + switch (*cw & _MCW_RC) + { + case _RC_CHOP: fpcr |= 0xc00000; break; + case _RC_UP: fpcr |= 0x400000; break; + case _RC_DOWN: fpcr |= 0x800000; break; + } + } + + /* mask exceptions if needed */ + if (old_fpcr != fpcr && ~(old_fpcr >> 8) & fpsr & 0x9f != fpsr & 0x9f) + { + ULONG_PTR mask = fpcr & ~0x9f00; + __asm__ __volatile__( "msr fpcr, %0" :: "r" (mask) ); + } + + if (old_fpsr != fpsr) + __asm__ __volatile__( "msr fpsr, %0" :: "r" (fpsr) ); + if (old_fpcr != fpcr) + __asm__ __volatile__( "msr fpcr, %0" :: "r" (fpcr) ); + return TRUE; #endif #else FIXME("not implemented\n"); @@ -5392,18 +5472,8 @@ unsigned int CDECL _statusfp(void) _statusfp2( &x86_sw, &sse2_sw ); /* FIXME: there's no definition for ambiguous status, just return all status bits for now */ flags = x86_sw | sse2_sw; -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined(__aarch64__) _setfp(NULL, 0, &flags, 0); -#elif defined(__aarch64__) - ULONG_PTR fpsr; - - __asm__ __volatile__( "mrs %0, fpsr" : "=r" (fpsr) ); - if (fpsr & 0x1) flags |= _SW_INVALID; - if (fpsr & 0x2) flags |= _SW_ZERODIVIDE; - if (fpsr & 0x4) flags |= _SW_OVERFLOW; - if (fpsr & 0x8) flags |= _SW_UNDERFLOW; - if (fpsr & 0x10) flags |= _SW_INEXACT; - if (fpsr & 0x80) flags |= _SW_DENORMAL; #elif defined(__arm__) && !defined(__SOFTFP__) DWORD fpscr; @@ -5435,20 +5505,8 @@ unsigned int CDECL _clearfp(void) _setfp_sse(NULL, 0, &sse_sw, _MCW_EM); flags |= sse_sw; } -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined(__aarch64__) _setfp(NULL, 0, &flags, _MCW_EM); -#elif defined(__aarch64__) - ULONG_PTR fpsr; - - __asm__ __volatile__( "mrs %0, fpsr" : "=r" (fpsr) ); - if (fpsr & 0x1) flags |= _SW_INVALID; - if (fpsr & 0x2) flags |= _SW_ZERODIVIDE; - if (fpsr & 0x4) flags |= _SW_OVERFLOW; - if (fpsr & 0x8) flags |= _SW_UNDERFLOW; - if (fpsr & 0x10) flags |= _SW_INEXACT; - if (fpsr & 0x80) flags |= _SW_DENORMAL; - fpsr &= ~0x9f; - __asm__ __volatile__( "msr fpsr, %0" :: "r" (fpsr) ); #elif defined(__arm__) && !defined(__SOFTFP__) DWORD fpscr; @@ -5550,40 +5608,9 @@ unsigned int CDECL _control87(unsigned int newval, unsigned int mask) if ((flags ^ sse2_cw) & (_MCW_EM | _MCW_RC)) flags |= _EM_AMBIGUOUS; flags |= sse2_cw; -#elif defined(__x86_64__) +#elif defined(__x86_64__) || defined(__aarch64__) flags = newval; _setfp(&flags, mask, NULL, 0); -#elif defined(__aarch64__) - ULONG_PTR fpcr; - - __asm__ __volatile__( "mrs %0, fpcr" : "=r" (fpcr) ); - if (!(fpcr & 0x100)) flags |= _EM_INVALID; - if (!(fpcr & 0x200)) flags |= _EM_ZERODIVIDE; - if (!(fpcr & 0x400)) flags |= _EM_OVERFLOW; - if (!(fpcr & 0x800)) flags |= _EM_UNDERFLOW; - if (!(fpcr & 0x1000)) flags |= _EM_INEXACT; - if (!(fpcr & 0x8000)) flags |= _EM_DENORMAL; - switch (fpcr & 0xc00000) - { - case 0x400000: flags |= _RC_UP; break; - case 0x800000: flags |= _RC_DOWN; break; - case 0xc00000: flags |= _RC_CHOP; break; - } - flags = (flags & ~mask) | (newval & mask); - fpcr &= ~0xc09f00ul; - if (!(flags & _EM_INVALID)) fpcr |= 0x100; - if (!(flags & _EM_ZERODIVIDE)) fpcr |= 0x200; - if (!(flags & _EM_OVERFLOW)) fpcr |= 0x400; - if (!(flags & _EM_UNDERFLOW)) fpcr |= 0x800; - if (!(flags & _EM_INEXACT)) fpcr |= 0x1000; - if (!(flags & _EM_DENORMAL)) fpcr |= 0x8000; - switch (flags & _MCW_RC) - { - case _RC_CHOP: fpcr |= 0xc00000; break; - case _RC_UP: fpcr |= 0x400000; break; - case _RC_DOWN: fpcr |= 0x800000; break; - } - __asm__ __volatile__( "msr fpcr, %0" :: "r" (fpcr) ); #elif defined(__arm__) && !defined(__SOFTFP__) DWORD fpscr; @@ -5966,7 +5993,7 @@ void CDECL _fpreset(void) */ int CDECL fesetenv(const fenv_t *env) { -#if defined(__i386__) || defined(__x86_64__) +#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) unsigned int x87_cw, cw, x87_stat, stat; unsigned int mask; @@ -6003,32 +6030,6 @@ int CDECL fesetenv(const fenv_t *env) return 1; return 0; #endif -#elif defined(__aarch64__) - ULONG_PTR fpsr; - unsigned int tmp, fp_cw, fp_stat; - - if (!env->_Fe_ctl && !env->_Fe_stat) { - _fpreset(); - return 0; - } - - if (!fenv_decode(env->_Fe_ctl, &tmp, &fp_cw)) - return 1; - if (!fenv_decode(env->_Fe_stat, &tmp, &fp_stat)) - return 1; - - _control87(_MCW_EM, _MCW_EM); - __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) ); - _control87(fp_cw, 0xffffffff); - return 0; #elif defined(__arm__) && !defined(__SOFTFP__) DWORD fpscr; unsigned int tmp, fp_cw, fp_stat;