[PATCH] msvcrt: Don't set MXCSR register in __control87_2 if unchanged.
Myah Caron
qsniyg at protonmail.com
Sat Jul 4 13:45:40 CDT 2020
I've just tested the application linked in the bug report again. Though it is related to the bug, and a step forward to solving it, this patch doesn't actually solve the problem itself. I was testing with the wrong msvcrt version.
‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐
On Friday, July 3, 2020 11:34 AM, Myah Caron <qsniyg at protonmail.com> wrote:
> Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=27594
> Signed-off-by: Myah Caron qsniyg at protonmail.com
>
> I've only tested on x86 as I believe x64 is different enough to warrant a separate commit if the same issue is also present there.
>
> Though I suspect the x87 control word might need the same treatment, I couldn't create a test case that displayed a requirement for this, so I've left it untouched.
>
> ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
>
> dlls/kernel32/tests/thread.c | 36 +++++++++++++++++++++++++-----
> dlls/msvcrt/math.c | 43 ++++++++++++++++++++----------------
> 2 files changed, 55 insertions(+), 24 deletions(-)
>
> diff --git a/dlls/kernel32/tests/thread.c b/dlls/kernel32/tests/thread.c
> index b476e44cfc..9b12b5043d 100644
> --- a/dlls/kernel32/tests/thread.c
> +++ b/dlls/kernel32/tests/thread.c
> @@ -1829,6 +1829,19 @@ static inline unsigned long get_fpu_cw(void)
> #endif
> }
>
> +static inline void set_fpu_cw(unsigned int cw, unsigned int sse)
> +{
> +#if defined(i386) || defined(x86_64)
> +#ifdef _MSC_VER
>
> - __asm { fldcw [cw] }
> - __asm { ldmxcsr [sse] }
> +#else
>
> - asm volatile ("fldcw %0" : : "m" (cw));
> - asm volatile ("ldmxcsr %0" : : "m" (sse));
> +#endif
> +#endif
> +}
>
> -
>
> static DWORD WINAPI fpu_thread(void *param)
> {
> struct fpu_thread_ctx *ctx = param;
> @@ -1870,7 +1883,7 @@ static void test_thread_fpu_cw(void)
> {
> static const struct {
> unsigned int cw; unsigned long fpu_cw; unsigned long fpu_cw_broken;
>
> - } expected_cw[6] =
>
> - } expected_cw[7] =
> {
> #ifdef i386
> { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f80 ) },
> @@ -1878,27 +1891,30 @@ static void test_thread_fpu_cw(void)
> { _EM_INEXACT | _RC_CHOP | _PC_24, MAKELONG( 0xc60, 0x7000 ), MAKELONG( 0xc60, 0x1f80 ) },
> { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f80 ) },
> { _EM_INEXACT | _RC_CHOP | _PC_24, MAKELONG( 0xc60, 0x7000 ), MAKELONG( 0xc60, 0x1f80 ) },
>
>
> - { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f80 ) }
>
>
>
> - { _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f80 ) },
>
>
> - { _MCW_EM | _PC_24 | _RC_DOWN, MAKELONG( 0x47f, 0x3fa1 ) }
>
>
>
> #elif defined(x86_64)
> { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f80 ) },
> { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f80 ) },
> { _EM_INEXACT | _RC_CHOP | _PC_64, MAKELONG( 0x27f, 0x7000 ) },
> { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f80 ) },
> { _EM_INEXACT | _RC_CHOP | _PC_64, MAKELONG( 0x27f, 0x7000 ) },
>
> - { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f80 ) }
>
>
>
> - { _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f80 ) },
>
>
> - { 0xdeadbeef, 0xdeadbeef }
>
>
>
> #elif defined(aarch64)
> { _MCW_EM | _PC_64, 0 },
> { _MCW_EM | _PC_64, 0 },
> { _EM_INEXACT | _RC_CHOP | _PC_64, 0xc08f00 },
> { _MCW_EM | _PC_64, 0 },
> { _EM_INEXACT | _RC_CHOP | _PC_64, 0xc08f00 },
>
> - { _MCW_EM | _PC_64, 0 }
>
>
>
> - { _MCW_EM | _PC_64, 0 },
>
>
> - { 0xdeadbeef, 0xdeadbeef }
>
>
>
> #else
> { 0xdeadbeef, 0xdeadbeef }
> #endif
> };
> unsigned int initial_cw, cw;
>
> - unsigned long fpu_cw;
>
> - unsigned long initial_fpu_cw, fpu_cw;
>
> fpu_cw = get_fpu_cw();
> initial_cw = _control87( 0, 0 );
> @@ -1933,6 +1949,16 @@ static void test_thread_fpu_cw(void)
> fpu_cw = get_fpu_cw();
> ok(cw == expected_cw[5].cw, "expected %#x got %#x\n", expected_cw[5].cw, cw);
> ok(fpu_cw == expected_cw[5].fpu_cw, "expected %#lx got %#lx\n", expected_cw[5].fpu_cw, fpu_cw);
>
> -
>
> +#ifdef i386
>
> - initial_fpu_cw = get_fpu_cw();
> - set_fpu_cw(0x47f, 0x3fa1);
> - cw = _control87( _RC_DOWN, _MCW_RC );
> - fpu_cw = get_fpu_cw();
> - ok(cw == expected_cw[6].cw, "expected %#x got %#x\n", expected_cw[6].cw, cw);
> - ok(fpu_cw == expected_cw[6].fpu_cw, "expected %#lx got %#lx\n", expected_cw[6].fpu_cw, fpu_cw);
> - set_fpu_cw(initial_fpu_cw & 0xffff, (initial_fpu_cw >> 16) & 0xffff);
>
> +#endif
> }
>
> static const char manifest_dep[] =
> diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c
> index eae917076f..d11bd53acd 100644
> --- a/dlls/msvcrt/math.c
> +++ b/dlls/msvcrt/math.c
> @@ -1107,6 +1107,7 @@ int CDECL __control87_2( unsigned int newval, unsigned int mask,
> #ifdef GNUC
> unsigned long fpword;
> unsigned int flags;
>
> - unsigned int old_flags;
>
> if (x86_cw)
> {
> @@ -1196,29 +1197,33 @@ int CDECL __control87_2( unsigned int newval, unsigned int mask,
> TRACE( "sse2 flags=%08x newval=%08x mask=%08x\n", flags, newval, mask );
> if (mask)
> {
>
> - old_flags = flags;
> flags = (flags & ~mask) | (newval & mask);
>
>
>
> - /* Convert (masked) value back to fp word */
>
>
> - fpword = 0;
>
>
> - if (flags & MSVCRT__EM_INVALID) fpword |= 0x80;
>
>
> - if (flags & MSVCRT__EM_DENORMAL) fpword |= 0x100;
>
>
> - if (flags & MSVCRT__EM_ZERODIVIDE) fpword |= 0x200;
>
>
> - if (flags & MSVCRT__EM_OVERFLOW) fpword |= 0x400;
>
>
> - if (flags & MSVCRT__EM_UNDERFLOW) fpword |= 0x800;
>
>
> - if (flags & MSVCRT__EM_INEXACT) fpword |= 0x1000;
>
>
> - switch (flags & MSVCRT__MCW_RC)
>
>
>
> - if (flags != old_flags)
> {
>
>
>
> - case MSVCRT__RC_UP|MSVCRT__RC_DOWN: fpword |= 0x6000; break;
>
>
> - case MSVCRT__RC_UP: fpword |= 0x4000; break;
>
>
> - case MSVCRT__RC_DOWN: fpword |= 0x2000; break;
>
>
> - }
>
>
> - switch (flags & MSVCRT__MCW_DN)
>
>
> - {
>
>
> - case MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS: fpword |= 0x0040; break;
>
>
> - case MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS: fpword |= 0x8000; break;
>
>
> - case MSVCRT__DN_FLUSH: fpword |= 0x8040; break;
>
>
>
> - /* Convert (masked) value back to fp word */
>
>
> - fpword = 0;
>
>
> - if (flags & MSVCRT__EM_INVALID) fpword |= 0x80;
>
>
> - if (flags & MSVCRT__EM_DENORMAL) fpword |= 0x100;
>
>
> - if (flags & MSVCRT__EM_ZERODIVIDE) fpword |= 0x200;
>
>
> - if (flags & MSVCRT__EM_OVERFLOW) fpword |= 0x400;
>
>
> - if (flags & MSVCRT__EM_UNDERFLOW) fpword |= 0x800;
>
>
> - if (flags & MSVCRT__EM_INEXACT) fpword |= 0x1000;
>
>
> - switch (flags & MSVCRT__MCW_RC)
>
>
> - {
>
>
> - case MSVCRT__RC_UP|MSVCRT__RC_DOWN: fpword |= 0x6000; break;
>
>
> - case MSVCRT__RC_UP: fpword |= 0x4000; break;
>
>
> - case MSVCRT__RC_DOWN: fpword |= 0x2000; break;
>
>
> - }
>
>
> - switch (flags & MSVCRT__MCW_DN)
>
>
> - {
>
>
> - case MSVCRT__DN_FLUSH_OPERANDS_SAVE_RESULTS: fpword |= 0x0040; break;
>
>
> - case MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS: fpword |= 0x8000; break;
>
>
> - case MSVCRT__DN_FLUSH: fpword |= 0x8040; break;
>
>
> - }
>
>
> - __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
> }
>
>
>
> - __asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
> }
> *sse2_cw = flags;
>
>
> }
> --
> 2.26.2
>
More information about the wine-devel
mailing list