diff options
author | Tamar Christina <tamar@zhox.com> | 2016-12-14 16:45:35 -0500 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2016-12-15 10:42:25 -0500 |
commit | 6f7d8279cea4aa1082fb07adf5da507297e21ee8 (patch) | |
tree | ae127f06d0fc89a5d6eaafbe0a5bb9af263d4690 /rts | |
parent | 0c3341b23e0672fb9c05d9f6ab0be76f411d526e (diff) | |
download | haskell-6f7d8279cea4aa1082fb07adf5da507297e21ee8.tar.gz |
Reset FPU precision back to MSVCRT defaults
Mingw-w64 does a stupid thing. They set the FPU precision to extended
mode by default. The reasoning is that it's for compatibility with GNU
Linux ported libraries. However the problem is this is incompatible with
the standard Windows double precision mode. In fact, if we create a new
OS thread then Windows will reset the FPU to double precision mode. So
we end up with a weird state where the main thread by default has a
different precision than any child threads.
Test Plan: ./validate new test T7289
Reviewers: simonmar, austin, bgamari, erikd
Reviewed By: simonmar
Subscribers: thomie, #ghc_windows_task_force
Differential Revision: https://phabricator.haskell.org/D2819
GHC Trac Issues: #7289
Diffstat (limited to 'rts')
-rw-r--r-- | rts/RtsStartup.c | 34 |
1 files changed, 30 insertions, 4 deletions
diff --git a/rts/RtsStartup.c b/rts/RtsStartup.c index dd4efa69e0..955ad13b4b 100644 --- a/rts/RtsStartup.c +++ b/rts/RtsStartup.c @@ -46,7 +46,9 @@ #include "win32/AsyncIO.h" #endif -#if !defined(mingw32_HOST_OS) +#if defined(mingw32_HOST_OS) +#include <fenv.h> +#else #include "posix/TTY.h" #endif @@ -69,10 +71,18 @@ static void flushStdHandles(void); #define X86_INIT_FPU 0 -#if X86_INIT_FPU static void x86_init_fpu ( void ) { +#if defined(mingw32_HOST_OS) && !X86_INIT_FPU + /* Mingw-w64 does a stupid thing. They set the FPU precision to extended mode by default. + The reasoning is that it's for compatibility with GNU Linux ported libraries. However the + problem is this is incompatible with the standard Windows double precision mode. In fact, + if we create a new OS thread then Windows will reset the FPU to double precision mode. + So we end up with a weird state where the main thread by default has a different precision + than any child threads. */ + fesetenv(FE_PC53_ENV); +#elif X86_INIT_FPU __volatile unsigned short int fpu_cw; // Grab the control word @@ -87,8 +97,26 @@ x86_init_fpu ( void ) // Store the new control word back __asm __volatile ("fldcw %0" : : "m" (fpu_cw)); +#else + return; +#endif +} + +#if defined(mingw32_HOST_OS) +/* And now we have to override the build in ones in Mingw-W64's CRT. */ +void _fpreset(void) +{ + x86_init_fpu(); +} + +#ifdef __GNUC__ +void __attribute__((alias("_fpreset"))) fpreset(void); +#else +void fpreset(void) { + _fpreset(); } #endif +#endif /* ----------------------------------------------------------------------------- Starting up the RTS @@ -244,9 +272,7 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config) startupAsyncIO(); #endif -#if X86_INIT_FPU x86_init_fpu(); -#endif startupHpc(); |