diff --git a/ttg/ttg/util/bug.cpp b/ttg/ttg/util/bug.cpp index 1e91e8fd2..27b743096 100644 --- a/ttg/ttg/util/bug.cpp +++ b/ttg/ttg/util/bug.cpp @@ -28,6 +28,7 @@ #include "bug.h" #include +#include #include #include #include @@ -46,6 +47,103 @@ using namespace std; using namespace ttg; +namespace ttg { + void initialize_fpe() { +#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 + +#ifndef HAVE_FEENABLEEXCEPT + auto feenableexcept = [](int excepts) -> int { + static fenv_t fenv; + const auto new_excepts = excepts & FE_ALL_EXCEPT; + + if (fegetenv(&fenv)) { + return -1; + } +#if defined(__x86_64__) + // previous masks + const unsigned int old_excepts = fenv.__control & FE_ALL_EXCEPT; + + // unmask + fenv.__control &= ~new_excepts; + fenv.__mxcsr &= ~(new_excepts << 7); +#elif defined(__arm64__) + if (new_excepts & FE_INVALID) fenv.__fpcr |= __fpcr_trap_invalid; + if (new_excepts & FE_DIVBYZERO) fenv.__fpcr |= __fpcr_trap_divbyzero; + if (new_excepts & FE_OVERFLOW) fenv.__fpcr |= __fpcr_trap_overflow; + if (new_excepts & FE_UNDERFLOW) fenv.__fpcr |= __fpcr_trap_underflow; + if (new_excepts & FE_INEXACT) fenv.__fpcr |= __fpcr_trap_inexact; +#else +#error "MacOS on unknown architecture" +#endif + return fesetenv(&fenv); + }; +#define HAVE_FEENABLEEXCEPT 1 +#endif // not defined HAVE_FEENABLEEXCEPT + +#ifndef HAVE_FEDISABLEEXCEPT + auto fedisableexcept = [](int excepts) -> int { + static fenv_t fenv; + const auto new_excepts = excepts & FE_ALL_EXCEPT; + // all previous masks + + if (fegetenv(&fenv)) { + return -1; + } +#if defined(__x86_64__) + const unsigned int old_excepts = fenv.__control & FE_ALL_EXCEPT; + + // mask + fenv.__control |= new_excepts; + fenv.__mxcsr |= new_excepts << 7; +#elif defined(__arm64__) + if (new_excepts & FE_INVALID) fenv.__fpcr &= ~__fpcr_trap_invalid; + if (new_excepts & FE_DIVBYZERO) fenv.__fpcr &= ~__fpcr_trap_divbyzero; + if (new_excepts & FE_OVERFLOW) fenv.__fpcr &= ~__fpcr_trap_overflow; + if (new_excepts & FE_UNDERFLOW) fenv.__fpcr &= ~__fpcr_trap_underflow; + if (new_excepts & FE_INEXACT) fenv.__fpcr &= ~__fpcr_trap_inexact; +#else +#error "MacOS on unknown architecture" +#endif + + return fesetenv(&fenv); + }; + +#define HAVE_FEDISABLEEXCEPT 1 +#endif // not defined HAVE_FEDISABLEEXCEPT +#endif // mac + +#ifdef HAVE_FEENABLEEXCEPT + // this uses a glibc extension to trap on individual exceptions + int enable_excepts = 0; +#ifdef FE_DIVBYZERO + enable_excepts |= FE_DIVBYZERO; +#endif +#ifdef FE_INVALID + enable_excepts |= FE_INVALID; +#endif +#ifdef FE_OVERFLOW + enable_excepts |= FE_OVERFLOW; +#endif + feenableexcept(enable_excepts); +#endif + +#ifdef HAVE_FEDISABLEEXCEPT + // this uses a glibc extension to not trap on individual exceptions + int disable_excepts = 0; +#ifdef FE_UNDERFLOW + disable_excepts |= FE_UNDERFLOW; +#endif +#ifdef FE_INEXACT + disable_excepts |= FE_INEXACT; +#endif + fedisableexcept(disable_excepts); +#endif + } +} + ////////////////////////////////////////////////////////////////////// // static variables diff --git a/ttg/ttg/util/bug.h b/ttg/ttg/util/bug.h index 27212a809..df2791908 100644 --- a/ttg/ttg/util/bug.h +++ b/ttg/ttg/util/bug.h @@ -250,6 +250,15 @@ namespace ttg { } // namespace detail + /// @brief Initializes the floating point exceptions. + /// + /// Enables (if available) FE_DIVBYZERO, FE_INVALID, and FE_OVERFLOW; + /// FE_UNDERFLOW and FE_INEXACT are disabled (if available). + /// @warning This should be called from the main thread *before* any threads + /// have been created (i.e. before madness::initialize()), + /// so that all threads inherit the same floating point environment. + void initialize_fpe(); + /** * The Debugger class describes what should be done when a catastrophic * error causes unexpected program termination. It can try things such as