msvcrt: Don't reset MXCSR status in __control87_2 if control information is not changed.
Signed-off-by: Myah Caron <qsniyg@protonmail.com> Signed-off-by: Piotr Caban <piotr@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
68204a86a2
commit
f2a804b9ea
|
@ -22,6 +22,7 @@
|
|||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
/* the tests intentionally pass invalid pointers and need an exception handler */
|
||||
#define WINE_NO_INLINE_STRING
|
||||
|
@ -1829,6 +1830,28 @@ static inline unsigned long get_fpu_cw(void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static inline void fpu_invalid_operation(void)
|
||||
{
|
||||
double d;
|
||||
|
||||
#if defined(__i386__)
|
||||
unsigned int sse;
|
||||
#ifdef _MSC_VER
|
||||
__asm { stmxcsr [sse] }
|
||||
sse |= 1; /* invalid operation flag */
|
||||
__asm { ldmxcsr [sse] }
|
||||
#else
|
||||
__asm__ volatile ("stmxcsr %0" : "=m" (sse));
|
||||
sse |= 1;
|
||||
__asm__ volatile ("ldmxcsr %0" : : "m" (sse));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
d = acos(2.0);
|
||||
ok(_isnan(d), "d = %lf\n", d);
|
||||
ok(_statusfp() == _SW_INVALID, "_statusfp() = %x\n", _statusfp());
|
||||
}
|
||||
|
||||
static DWORD WINAPI fpu_thread(void *param)
|
||||
{
|
||||
struct fpu_thread_ctx *ctx = param;
|
||||
|
@ -1870,7 +1893,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[8] =
|
||||
{
|
||||
#ifdef __i386__
|
||||
{ _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f80 ) },
|
||||
|
@ -1878,20 +1901,26 @@ 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_53, MAKELONG( 0x27f, 0x1f81 ) },
|
||||
{ _MCW_EM | _PC_53, MAKELONG( 0x27f, 0x1f81 ) }
|
||||
#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 ) },
|
||||
{ _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f81 ) },
|
||||
{ _MCW_EM | _PC_64, MAKELONG( 0x27f, 0x1f81 ) }
|
||||
#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 },
|
||||
{ _MCW_EM | _PC_64, 0 }
|
||||
#else
|
||||
{ 0xdeadbeef, 0xdeadbeef }
|
||||
|
@ -1933,6 +1962,18 @@ 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);
|
||||
|
||||
fpu_invalid_operation();
|
||||
cw = _control87( 0, 0 );
|
||||
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);
|
||||
|
||||
cw = _control87( initial_cw, _MCW_EM | _MCW_RC | _MCW_PC );
|
||||
fpu_cw = get_fpu_cw();
|
||||
ok(cw == expected_cw[7].cw, "expected %#x got %#x\n", expected_cw[6].cw, cw);
|
||||
ok(fpu_cw == expected_cw[7].fpu_cw, "expected %#lx got %#lx\n", expected_cw[6].fpu_cw, fpu_cw);
|
||||
_clearfp();
|
||||
}
|
||||
|
||||
static const char manifest_dep[] =
|
||||
|
|
|
@ -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,34 @@ 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;
|
||||
mask &= MSVCRT__MCW_EM | MSVCRT__MCW_RC | MSVCRT__MCW_DN;
|
||||
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;
|
||||
/* 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) );
|
||||
}
|
||||
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) );
|
||||
}
|
||||
*sse2_cw = flags;
|
||||
}
|
||||
|
@ -1246,6 +1252,7 @@ unsigned int CDECL _control87(unsigned int newval, unsigned int mask)
|
|||
if ((flags ^ sse2_cw) & (MSVCRT__MCW_EM | MSVCRT__MCW_RC)) flags |= MSVCRT__EM_AMBIGUOUS;
|
||||
#elif defined(__x86_64__)
|
||||
unsigned long fpword;
|
||||
unsigned int old_flags;
|
||||
|
||||
__asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
|
||||
if (fpword & 0x80) flags |= MSVCRT__EM_INVALID;
|
||||
|
@ -1266,27 +1273,32 @@ unsigned int CDECL _control87(unsigned int newval, unsigned int mask)
|
|||
case 0x8000: flags |= MSVCRT__DN_SAVE_OPERANDS_FLUSH_RESULTS; break;
|
||||
case 0x8040: flags |= MSVCRT__DN_FLUSH; break;
|
||||
}
|
||||
old_flags = flags;
|
||||
mask &= MSVCRT__MCW_EM | MSVCRT__MCW_RC | MSVCRT__MCW_DN;
|
||||
flags = (flags & ~mask) | (newval & mask);
|
||||
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_CHOP: fpword |= 0x6000; break;
|
||||
case MSVCRT__RC_UP: fpword |= 0x4000; break;
|
||||
case MSVCRT__RC_DOWN: fpword |= 0x2000; break;
|
||||
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_CHOP: 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) );
|
||||
}
|
||||
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) );
|
||||
#elif defined(__aarch64__)
|
||||
unsigned long fpcr;
|
||||
|
||||
|
|
|
@ -134,6 +134,8 @@ extern "C" {
|
|||
#define _CW_DEFAULT (_RC_NEAR + _PC_64 + _EM_INVALID + _EM_ZERODIVIDE + _EM_OVERFLOW + _EM_UNDERFLOW + _EM_INEXACT + _EM_DENORMAL)
|
||||
#endif
|
||||
|
||||
unsigned int __cdecl _clearfp(void);
|
||||
unsigned int __cdecl _statusfp(void);
|
||||
_ACRTIMP int __cdecl __fpe_flt_rounds(void);
|
||||
unsigned int __cdecl _control87(unsigned int, unsigned int);
|
||||
unsigned int __cdecl _controlfp(unsigned int, unsigned int);
|
||||
|
|
Loading…
Reference in New Issue