summaryrefslogtreecommitdiff
path: root/rts/RtsStartup.c
diff options
context:
space:
mode:
authorTamar Christina <tamar@zhox.com>2016-12-14 16:45:35 -0500
committerBen Gamari <ben@smart-cactus.org>2016-12-15 10:42:25 -0500
commit6f7d8279cea4aa1082fb07adf5da507297e21ee8 (patch)
treeae127f06d0fc89a5d6eaafbe0a5bb9af263d4690 /rts/RtsStartup.c
parent0c3341b23e0672fb9c05d9f6ab0be76f411d526e (diff)
downloadhaskell-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/RtsStartup.c')
-rw-r--r--rts/RtsStartup.c34
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();