Paul Gofman : msvcrt: Save and restore rounding mode in fegetenv() / fesetenv().
Alexandre Julliard
julliard at winehq.org
Wed Nov 18 15:48:01 CST 2020
Module: wine
Branch: master
Commit: 3acd68b24171e7c4b9fd82b4449dbe879df29884
URL: https://source.winehq.org/git/wine.git/?a=commit;h=3acd68b24171e7c4b9fd82b4449dbe879df29884
Author: Paul Gofman <pgofman at codeweavers.com>
Date: Tue Nov 17 23:07:49 2020 +0300
msvcrt: Save and restore rounding mode in fegetenv() / fesetenv().
Fixes Serious Sam 4 flickering in Vulkan mode.
Signed-off-by: Paul Gofman <pgofman at codeweavers.com>
Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
---
dlls/msvcr120/tests/msvcr120.c | 23 ++++++++++++++++++++---
dlls/msvcrt/math.c | 19 +++++++++++++++----
2 files changed, 35 insertions(+), 7 deletions(-)
diff --git a/dlls/msvcr120/tests/msvcr120.c b/dlls/msvcr120/tests/msvcr120.c
index 52531ddad72..8663fc81ee8 100644
--- a/dlls/msvcr120/tests/msvcr120.c
+++ b/dlls/msvcr120/tests/msvcr120.c
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <float.h>
#include <math.h>
+#include <fenv.h>
#include <limits.h>
#include <wctype.h>
@@ -183,6 +184,9 @@ static float (CDECL *p_wcstof)(const wchar_t*, wchar_t**);
static double (CDECL *p_remainder)(double, double);
static int* (CDECL *p_errno)(void);
static int (CDECL *p_fegetenv)(fenv_t*);
+static int (CDECL *p_fesetenv)(const fenv_t*);
+static int (CDECL *p_fegetround)(void);
+static int (CDECL *p_fesetround)(int);
static int (CDECL *p__clearfp)(void);
static _locale_t (__cdecl *p_wcreate_locale)(int, const wchar_t *);
static void (__cdecl *p_free_locale)(_locale_t);
@@ -254,6 +258,10 @@ static BOOL init(void)
p_free_locale = (void*)GetProcAddress(module, "_free_locale");
SET(p_wctype, "wctype");
SET(p_fegetenv, "fegetenv");
+ SET(p_fesetenv, "fesetenv");
+ SET(p_fegetround, "fegetround");
+ SET(p_fesetround, "fesetround");
+
SET(p__clearfp, "_clearfp");
SET(p_vsscanf, "vsscanf");
SET(p__Cbuild, "_Cbuild");
@@ -780,18 +788,27 @@ static void test_critical_section(void)
call_func1(p_critical_section_dtor, &cs);
}
-static void test_fegetenv(void)
+static void test_feenv(void)
{
+ fenv_t env, env2;
int ret;
- fenv_t env;
p__clearfp();
ret = p_fegetenv(&env);
ok(!ret, "fegetenv returned %x\n", ret);
+ p_fesetround(FE_UPWARD);
ok(env.control == (_EM_INEXACT|_EM_UNDERFLOW|_EM_OVERFLOW|_EM_ZERODIVIDE|_EM_INVALID),
"env.control = %x\n", env.control);
ok(!env.status, "env.status = %x\n", env.status);
+ ret = p_fegetenv(&env2);
+ ok(!ret, "fegetenv returned %x\n", ret);
+ ok(env2.control == (_EM_INEXACT|_EM_UNDERFLOW|_EM_OVERFLOW|_EM_ZERODIVIDE|_EM_INVALID | FE_UPWARD),
+ "env2.control = %x\n", env2.control);
+ ret = p_fesetenv(&env);
+ ok(!ret, "fesetenv returned %x\n", ret);
+ ret = p_fegetround();
+ ok(ret == FE_TONEAREST, "Got unexpected round mode %#x.\n", ret);
}
static void test__wcreate_locale(void)
@@ -1110,7 +1127,7 @@ START_TEST(msvcr120)
test__strtof();
test_remainder();
test_critical_section();
- test_fegetenv();
+ test_feenv();
test__wcreate_locale();
test__Condition_variable();
test_wctype();
diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c
index af6216e0ea8..25a9b5e096d 100644
--- a/dlls/msvcrt/math.c
+++ b/dlls/msvcrt/math.c
@@ -2074,7 +2074,7 @@ int CDECL _controlfp_s(unsigned int *cur, unsigned int newval, unsigned int mask
int CDECL MSVCRT_fegetenv(MSVCRT_fenv_t *env)
{
env->control = _controlfp(0, 0) & (MSVCRT__EM_INEXACT | MSVCRT__EM_UNDERFLOW |
- MSVCRT__EM_OVERFLOW | MSVCRT__EM_ZERODIVIDE | MSVCRT__EM_INVALID);
+ MSVCRT__EM_OVERFLOW | MSVCRT__EM_ZERODIVIDE | MSVCRT__EM_INVALID | MSVCRT__RC_CHOP);
env->status = _statusfp();
return 0;
}
@@ -2193,12 +2193,18 @@ int CDECL MSVCRT_fesetenv(const MSVCRT_fenv_t *env)
__asm__ __volatile__( "fnstenv %0" : "=m" (fenv) );
- fenv.control_word &= ~0x3d;
+ fenv.control_word &= ~0xc3d;
if (env->control & MSVCRT__EM_INVALID) fenv.control_word |= 0x1;
if (env->control & MSVCRT__EM_ZERODIVIDE) fenv.control_word |= 0x4;
if (env->control & MSVCRT__EM_OVERFLOW) fenv.control_word |= 0x8;
if (env->control & MSVCRT__EM_UNDERFLOW) fenv.control_word |= 0x10;
if (env->control & MSVCRT__EM_INEXACT) fenv.control_word |= 0x20;
+ switch (env->control & MSVCRT__MCW_RC)
+ {
+ case MSVCRT__RC_UP|MSVCRT__RC_DOWN: fenv.control_word |= 0xc00; break;
+ case MSVCRT__RC_UP: fenv.control_word |= 0x800; break;
+ case MSVCRT__RC_DOWN: fenv.control_word |= 0x400; break;
+ }
fenv.status_word &= ~0x3d;
if (env->status & MSVCRT__SW_INVALID) fenv.status_word |= 0x1;
@@ -2213,14 +2219,19 @@ int CDECL MSVCRT_fesetenv(const MSVCRT_fenv_t *env)
if (sse2_supported)
{
DWORD fpword;
-
__asm__ __volatile__( "stmxcsr %0" : "=m" (fpword) );
- fpword &= ~0x1e80;
+ fpword &= ~0x7e80;
if (env->control & MSVCRT__EM_INVALID) fpword |= 0x80;
if (env->control & MSVCRT__EM_ZERODIVIDE) fpword |= 0x200;
if (env->control & MSVCRT__EM_OVERFLOW) fpword |= 0x400;
if (env->control & MSVCRT__EM_UNDERFLOW) fpword |= 0x800;
if (env->control & MSVCRT__EM_INEXACT) fpword |= 0x1000;
+ switch (env->control & MSVCRT__MCW_RC)
+ {
+ case MSVCRT__RC_CHOP: fpword |= 0x6000; break;
+ case MSVCRT__RC_UP: fpword |= 0x4000; break;
+ case MSVCRT__RC_DOWN: fpword |= 0x2000; break;
+ }
__asm__ __volatile__( "ldmxcsr %0" : : "m" (fpword) );
}
More information about the wine-cvs
mailing list