Skip to content

Commit

Permalink
cmake: add USE_FLOAT_EXCEPTIONS to enable floating point exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
illwieckz committed Mar 22, 2023
1 parent 0da2f6d commit 10d2daf
Show file tree
Hide file tree
Showing 2 changed files with 105 additions and 2 deletions.
20 changes: 18 additions & 2 deletions cmake/DaemonFlags.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -148,13 +148,20 @@ else()
set(WARNMODE "no-")
endif()

# Compiler options
option(USE_FLOAT_EXCEPTIONS "Use floating point exceptions" OFF)
option(USE_FAST_MATH "Use fast math" ON)

# Compiler options
if (USE_FLOAT_EXCEPTIONS)
add_definitions(-DDAEMON_USE_FLOAT_EXCEPTIONS)
endif()

if (MSVC)
set_c_cxx_flag("/MP")

if (USE_FAST_MATH)
if (USE_FLOAT_EXCEPTIONS)
set_c_cxx_flag("/fp:strict")
elseif (USE_FAST_MATH)
set_c_cxx_flag("/fp:fast")
endif()

Expand Down Expand Up @@ -248,6 +255,15 @@ else()
set_c_cxx_flag("-ffast-math")
endif()

if (USE_FLOAT_EXCEPTIONS)
# Floating point exceptions requires trapping math
# to avoid false positives on architectures with SSE.
set_c_cxx_flag("-ftrapping-math")
# GCC prints noisy warnings saying -ftrapping-math implies this.
set_c_cxx_flag("-fno-associative-math")
# Other optimizations from -ffast-math can be kept.
endif()

# Use hidden symbol visibility if possible.
try_c_cxx_flag(FVISIBILITY_HIDDEN "-fvisibility=hidden")

Expand Down
87 changes: 87 additions & 0 deletions src/engine/framework/System.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,28 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <sys/file.h>
#endif

#if defined(DAEMON_USE_FLOAT_EXCEPTIONS)
#if defined(__USE_GNU) || defined (__APPLE__)
#include <cfenv>
#define DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE
#elif defined(_MSC_VER)
#include <cfloat>
#define DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE
#endif
#endif

#if defined(DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE)
static Cvar::Cvar<bool> common_floatExceptions_invalid("common.floatExceptions.invalid",
"enable floating point exception for operation with NaN",
Cvar::INIT, false);
static Cvar::Cvar<bool> common_floatExceptions_divByZero("common.floatExceptions.divByZero",
"enable floating point exception for division-by-zero operation",
Cvar::INIT, false);
static Cvar::Cvar<bool> common_floatExceptions_overflow("common.floatExceptions.overflow",
"enable floating point exception for operation producing an overflow",
Cvar::INIT, false);
#endif

namespace Sys {
static Cvar::Cvar<bool> cvar_common_shutdownOnDrop("common.shutdownOnDrop", "shut down engine on game drop", Cvar::TEMPORARY, false);

Expand Down Expand Up @@ -276,6 +298,69 @@ static void CloseSingletonSocket()
#endif
}

static void SetFloatingPointExceptions()
{
// Must be done after Sys::Init() to read cvars from command line.
#if defined(DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE)
#if defined(__USE_GNU) || defined(__APPLE__)
int exceptions = 0;
#elif defined(_MSC_VER)
unsigned int exceptions = 0;
#endif

// Operations with NaN.
if (common_floatExceptions_invalid.Get())
{
#if defined(__USE_GNU)
exceptions |= FE_INVALID;
#elif defined(__APPLE__)
exceptions |= __fpcr_trap_invalid;
#elif defined(_MSC_VER)
exceptions |= _EM_INVALID
#endif
}

// Division by zero.
if (common_floatExceptions_divByZero.Get())
{
#if defined(__USE_GNU)
exceptions |= FE_DIVBYZERO;
#elif defined(__APPLE__)
exceptions |= __fpcr_trap_divbyzero;
#elif defined(_MSC_VER)
exceptions |= _EM_ZERODIVIDE;
#endif
}

// Operations producing an overflow.
if (common_floatExceptions_overflow.Get())
{
#if defined(__USE_GNU)
exceptions |= FE_OVERFLOW;
#elif defined(__APPLE__)
exceptions |= __fpcr_trap_overflow;
#elif defined(_MSC_VER)
exceptions |= _EM_OVERFLOW;
#endif
}

#if defined(__USE_GNU)
// https://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Control-Functions.html
feenableexcept(exceptions);
#elif defined(__APPLE__)
// https://stackoverflow.com/a/71792418
fenv_t env;
fegetenv(&env);
env.__fpcr = env.__fpcr | exceptions;
fesetenv(&env);
#elif defined(_MSC_VER)
// https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2012/c9676k6h(v=vs.110)
unsigned int current;
_controlfp_s(&current, exceptions, _MCW_EM);
#endif
#endif
}

// Common code for fatal and non-fatal exit
// TODO: Handle shutdown requests coming from multiple threads (could happen from the *nix signal thread)
static void Shutdown(bool error, Str::StringRef message)
Expand Down Expand Up @@ -656,6 +741,8 @@ static void Init(int argc, char** argv)
// Set cvars set from the command line having the Cvar::INIT flag
SetCvarsWithInitFlag(cmdlineArgs);

SetFloatingPointExceptions();

// Initialize the filesystem. For pakpaths, the libpath is added first and has the
// lowest priority, while the homepath is added last and has the highest.
cmdlineArgs.pakPaths.insert(cmdlineArgs.pakPaths.begin(), FS::Path::Build(cmdlineArgs.libPath, "pkg"));
Expand Down

0 comments on commit 10d2daf

Please sign in to comment.