about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPjotr Prins2018-08-25 15:49:47 +0000
committerPjotr Prins2018-08-25 15:49:47 +0000
commit4c74f1374e6e7a48a14724e61178953d08c571d4 (patch)
tree6f8b7aa035fff9ee0606d7558b76a0fe03da0859
parentbe551a1b3c324dc96750cf992b6a5784e2b92ec7 (diff)
downloadpangemma-4c74f1374e6e7a48a14724e61178953d08c571d4.tar.gz
debug: feenableexcept for MacOS and limit to Intel x64 machines
-rw-r--r--src/debug.cpp56
1 files changed, 53 insertions, 3 deletions
diff --git a/src/debug.cpp b/src/debug.cpp
index 0b9c19d..c998ffe 100644
--- a/src/debug.cpp
+++ b/src/debug.cpp
@@ -82,16 +82,66 @@ You can disable floating point tests with the -no-check switch (use at your own
    this is an Intel hardware feature that does not slow down computations.
 */
 
+#if defined(__APPLE__) && defined(__MACH__)
+
+// Public domain polyfill for feenableexcept on OS X
+// http://www-personal.umich.edu/~williams/archive/computation/fe-handling-example.c
+
+inline int feenableexcept(unsigned int excepts)
+{
+    static fenv_t fenv;
+    unsigned int new_excepts = excepts & FE_ALL_EXCEPT;
+    // previous masks
+    unsigned int old_excepts;
+
+    if (fegetenv(&fenv)) {
+        return -1;
+    }
+    old_excepts = fenv.__control & FE_ALL_EXCEPT;
+
+    // unmask
+    fenv.__control &= ~new_excepts;
+    fenv.__mxcsr   &= ~(new_excepts << 7);
+
+    return fesetenv(&fenv) ? -1 : old_excepts;
+}
+
+inline int fedisableexcept(unsigned int excepts)
+{
+    static fenv_t fenv;
+    unsigned int new_excepts = excepts & FE_ALL_EXCEPT;
+    // all previous masks
+    unsigned int old_excepts;
+
+    if (fegetenv(&fenv)) {
+        return -1;
+    }
+    old_excepts = fenv.__control & FE_ALL_EXCEPT;
+
+    // mask
+    fenv.__control |= new_excepts;
+    fenv.__mxcsr   |= new_excepts << 7;
+
+    return fesetenv(&fenv) ? -1 : old_excepts;
+}
+
+#endif
+
 void enable_segfpe() {
   #ifdef __GNUC__
-  signal(SIGFPE, sighandler);
-  feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW);
+    #if defined(__x86_64__)
+       debug_msg("enable segfpe hardware floating point error detection");
+       signal(SIGFPE, sighandler);
+       feenableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW);
+    #endif
   #endif
 }
 
 void disable_segfpe() {
   #ifdef __GNUC__
-  fedisableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW);
+    #if defined(__x86_64__)
+      fedisableexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW);
+    #endif
   #endif
 }