summaryrefslogtreecommitdiff
path: root/rts/RtsStartup.c
diff options
context:
space:
mode:
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();