Skip to content

Commit 8687854

Browse files
committed
cmake: add USE_FLOAT_EXCEPTIONS to enable floating point exceptions
1 parent 7504b63 commit 8687854

File tree

2 files changed

+103
-2
lines changed

2 files changed

+103
-2
lines changed

cmake/DaemonFlags.cmake

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,20 @@ else()
148148
set(WARNMODE "no-")
149149
endif()
150150

151+
# Compiler options
152+
option(USE_FLOAT_EXCEPTIONS "Use floating point exceptions" OFF)
151153
option(USE_FAST_MATH "Use fast math" ON)
152154

153-
# Compiler options
155+
if (USE_FLOAT_EXCEPTIONS)
156+
add_definitions(-DDAEMON_USE_FLOAT_EXCEPTIONS)
157+
endif()
158+
154159
if (MSVC)
155160
set_c_cxx_flag("/MP")
156161

157-
if (USE_FAST_MATH)
162+
if (USE_FLOAT_EXCEPTIONS)
163+
set_c_cxx_flag("/fp:strict")
164+
elseif (USE_FAST_MATH)
158165
set_c_cxx_flag("/fp:fast")
159166
endif()
160167

@@ -248,6 +255,12 @@ else()
248255
set_c_cxx_flag("-ffast-math")
249256
endif()
250257

258+
if (USE_FLOAT_EXCEPTIONS)
259+
# Floating point exceptions requires trapping math
260+
# to avoid false positives on architectures with SSE.
261+
set_c_cxx_flag("-ftrapping-math")
262+
endif()
263+
251264
# Use hidden symbol visibility if possible.
252265
try_c_cxx_flag(FVISIBILITY_HIDDEN "-fvisibility=hidden")
253266

src/engine/framework/System.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,29 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5151
#include <sys/file.h>
5252
#endif
5353

54+
#if defined(DAEMON_USE_FLOAT_EXCEPTIONS)
55+
#if defined(__USE_GNU) || defined (__APPLE__)
56+
#include <cfenv>
57+
#define DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE
58+
#elif defined(_MSC_VER)
59+
#include <float.h>
60+
#pragma fenv_access (on)
61+
#define DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE
62+
#endif
63+
#endif
64+
65+
#if defined(DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE)
66+
static Cvar::Cvar<bool> common_floatExceptions_invalid("common.floatExceptions.invalid",
67+
"enable floating point exception for operation with NaN",
68+
Cvar::INIT, false);
69+
static Cvar::Cvar<bool> common_floatExceptions_divByZero("common.floatExceptions.divByZero",
70+
"enable floating point exception for division-by-zero operation",
71+
Cvar::INIT, false);
72+
static Cvar::Cvar<bool> common_floatExceptions_overflow("common.floatExceptions.overflow",
73+
"enable floating point exception for operation producing an overflow",
74+
Cvar::INIT, false);
75+
#endif
76+
5477
namespace Sys {
5578
static Cvar::Cvar<bool> cvar_common_shutdownOnDrop("common.shutdownOnDrop", "shut down engine on game drop", Cvar::TEMPORARY, false);
5679

@@ -276,6 +299,69 @@ static void CloseSingletonSocket()
276299
#endif
277300
}
278301

302+
static void SetFloatingPointExceptions()
303+
{
304+
// Must be done after Sys::Init() to read cvars from command line.
305+
#if defined(DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE)
306+
#if defined(__USE_GNU) || defined(__APPLE__)
307+
int exceptions = 0;
308+
#elif defined(_MSC_VER)
309+
unsigned int exceptions = 0;
310+
#endif
311+
312+
// Operations with NaN.
313+
if (common_floatExceptions_invalid.Get())
314+
{
315+
#if defined(__USE_GNU)
316+
exceptions |= FE_INVALID;
317+
#elif defined(__APPLE__)
318+
exceptions |= __fpscr_trap_invalid;
319+
#elif defined(_MSC_VER)
320+
exceptions |= _EM_INVALID
321+
#endif
322+
}
323+
324+
// Division by zero.
325+
if (common_floatExceptions_divByZero.Get())
326+
{
327+
#if defined(__USE_GNU)
328+
exceptions |= FE_DIVBYZERO;
329+
#elif defined(__APPLE__)
330+
exceptions |= __fpscr_trap_divbyzero;
331+
#elif defined(_MSC_VER)
332+
exceptions |= _EM_ZERODIVIDE;
333+
#endif
334+
}
335+
336+
// Operations producing an overflow.
337+
if (common_floatExceptions_overflow.Get())
338+
{
339+
#if defined(__USE_GNU)
340+
exceptions |= FE_OVERFLOW;
341+
#elif defined(__APPLE__)
342+
exceptions |= __fpscr_trap_overflow;
343+
#elif defined(_MSC_VER)
344+
exceptions |= _EM_OVERFLOW;
345+
#endif
346+
}
347+
348+
#if defined(__USE_GNU)
349+
// https://www.gnu.org/savannah-checkouts/gnu/libc/manual/html_node/Control-Functions.html
350+
feenableexcept(exceptions);
351+
#elif defined(__APPLE__)
352+
// https://stackoverflow.com/a/71792418
353+
fenv_t env;
354+
fegetenv(&env);
355+
env.__fpcr = env.__fpcr | exceptions;
356+
fesetenv(&env);
357+
#elif defined(_MSC_VER)
358+
// https://learn.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2012/c9676k6h(v=vs.110)
359+
unsigned int current;
360+
_controlfp_s(&current, exceptions, _MCW_EM);
361+
#endif
362+
#endif
363+
}
364+
279365
// Common code for fatal and non-fatal exit
280366
// TODO: Handle shutdown requests coming from multiple threads (could happen from the *nix signal thread)
281367
static void Shutdown(bool error, Str::StringRef message)
@@ -656,6 +742,8 @@ static void Init(int argc, char** argv)
656742
// Set cvars set from the command line having the Cvar::INIT flag
657743
SetCvarsWithInitFlag(cmdlineArgs);
658744

745+
SetFloatingPointExceptions();
746+
659747
// Initialize the filesystem. For pakpaths, the libpath is added first and has the
660748
// lowest priority, while the homepath is added last and has the highest.
661749
cmdlineArgs.pakPaths.insert(cmdlineArgs.pakPaths.begin(), FS::Path::Build(cmdlineArgs.libPath, "pkg"));

0 commit comments

Comments
 (0)