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 #include #include +#include #include #include @@ -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) ); }