Skip to content

Commit

Permalink
Mac Arm64 Architecture fpe handling (#3447)
Browse files Browse the repository at this point in the history
## Summary
Handles floating pointing exception when compiled on arch64 and Apple
(for M1 and M2 chips). Only works for overflow currently, there is an
apparent limitation to these architectures for catching division by
zero.

## Additional background
SIGILL instead of SIGFPE is needed to catch arch64 signals, see ref:
https://developer.apple.com/forums/thread/689159

---------

Co-authored-by: Weiqun Zhang <[email protected]>
  • Loading branch information
johnson452 and WeiqunZhang authored Jul 28, 2023
1 parent f41e619 commit bba6d9c
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 0 deletions.
1 change: 1 addition & 0 deletions Docs/sphinx_documentation/source/Debugging.rst
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use of uninitialized values, AMReX also initializes ``FArrayBox``\ s in
``MulitFab``\ s and arrays allocated by ``bl_allocate`` to signaling NaNs when it is compiled
with ``TEST=TRUE`` or ``DEBUG=TRUE`` in GNU make, or with ``-DCMAKE_BUILD_TYPE=Debug`` in CMake.
One can also control the setting for ``FArrayBox`` using the runtime parameter, ``fab.init_snan``.
Note for Macs, M1 and M2 chips using Arm64 architecture are not able to trap division by zero.

One can get more information than the backtrace of the call stack by
instrumenting the code. Here is an example.
Expand Down
25 changes: 25 additions & 0 deletions Src/Base/AMReX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ namespace system
int handle_sigint;
int handle_sigabrt;
int handle_sigfpe;
int handle_sigill;
int call_addr2line;
int throw_exception;
int regtest_reduction;
Expand All @@ -127,6 +128,7 @@ namespace {
SignalHandler prev_handler_sigint = SIG_ERR; // NOLINT(performance-no-int-to-ptr)
SignalHandler prev_handler_sigabrt = SIG_ERR; // NOLINT(performance-no-int-to-ptr)
SignalHandler prev_handler_sigfpe = SIG_ERR; // NOLINT(performance-no-int-to-ptr)
SignalHandler prev_handler_sigill = SIG_ERR; // NOLINT(performance-no-int-to-ptr)
#if defined(__linux__)
int prev_fpe_excepts = 0;
int curr_fpe_excepts = 0;
Expand Down Expand Up @@ -329,6 +331,7 @@ amrex::Initialize (int& argc, char**& argv, bool build_parm_parse,
system::handle_sigint = 1;
system::handle_sigabrt = 1;
system::handle_sigfpe = 1;
system::handle_sigill = 1;
system::call_addr2line = 1;
system::throw_exception = 0;
system::osout = &a_osout;
Expand Down Expand Up @@ -509,6 +512,7 @@ amrex::Initialize (int& argc, char**& argv, bool build_parm_parse,
pp.queryAdd("handle_sigint" , system::handle_sigint );
pp.queryAdd("handle_sigabrt", system::handle_sigabrt);
pp.queryAdd("handle_sigfpe" , system::handle_sigfpe );
pp.queryAdd("handle_sigill" , system::handle_sigill );

// We save the singal handlers and restore them in Finalize.
if (system::handle_sigsegv) {
Expand Down Expand Up @@ -566,6 +570,26 @@ amrex::Initialize (int& argc, char**& argv, bool build_parm_parse,
}
#endif
}

prev_handler_sigill = SIG_ERR; // NOLINT(performance-no-int-to-ptr)
if (system::handle_sigill)
{
#if defined(__APPLE__) && defined(__aarch64__)
int invalid = 0, divbyzero=0, overflow=0;
pp.queryAdd("fpe_trap_invalid", invalid);
pp.queryAdd("fpe_trap_zero", divbyzero);
pp.queryAdd("fpe_trap_overflow", overflow);

fenv_t env;
fegetenv(&env);
if (invalid) env.__fpcr |= __fpcr_trap_invalid;
if (divbyzero) env.__fpcr |= __fpcr_trap_divbyzero;
if (overflow) env.__fpcr |= __fpcr_trap_overflow;
fesetenv(&env);
// SIGILL ref: https://developer.apple.com/forums/thread/689159
#endif
prev_handler_sigill = std::signal(SIGILL, BLBackTrace::handler);
}
}

#ifdef AMREX_USE_HYPRE
Expand Down Expand Up @@ -762,6 +786,7 @@ amrex::Finalize (amrex::AMReX* pamrex)
if (prev_handler_sigint != SIG_ERR) std::signal(SIGINT , prev_handler_sigint); // NOLINT(performance-no-int-to-ptr)
if (prev_handler_sigabrt != SIG_ERR) std::signal(SIGABRT, prev_handler_sigabrt); // NOLINT(performance-no-int-to-ptr)
if (prev_handler_sigfpe != SIG_ERR) std::signal(SIGFPE , prev_handler_sigfpe); // NOLINT(performance-no-int-to-ptr)
if (prev_handler_sigill != SIG_ERR) std::signal(SIGILL , prev_handler_sigill); // NOLINT(performance-no-int-to-ptr)
#if defined(__linux__)
#if !defined(__PGI) || (__PGIC__ >= 16)
if (curr_fpe_excepts != 0) {
Expand Down
3 changes: 3 additions & 0 deletions Src/Base/AMReX_BLBackTrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ BLBackTrace::handler(int s)
case SIGFPE:
amrex::ErrorStream() << "Erroneous arithmetic operation\n";
break;
case SIGILL:
amrex::ErrorStream() << "SIGILL Invalid, privileged, or ill-formed instruction\n";
break;
case SIGTERM:
amrex::ErrorStream() << "SIGTERM\n";
break;
Expand Down
1 change: 1 addition & 0 deletions Tools/CMake/AMReXFlagsTargets.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ target_compile_options ( Flags_FPE
$<${_cxx_cray}:-K trap=fp>
$<${_fortran_clang}:>
$<${_cxx_clang}:-ftrapv>
$<${_cxx_appleclang}:-ftrapv>
)

#
Expand Down

0 comments on commit bba6d9c

Please sign in to comment.