Skip to content

Commit b878d3a

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

File tree

2 files changed

+102
-2
lines changed

2 files changed

+102
-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: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,28 @@ 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+
#define DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE
61+
#endif
62+
#endif
63+
64+
#if defined(DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE)
65+
static Cvar::Cvar<bool> common_floatExceptions_invalid("common.floatExceptions.invalid",
66+
"enable floating point exception for operation with NaN",
67+
Cvar::INIT, false);
68+
static Cvar::Cvar<bool> common_floatExceptions_divByZero("common.floatExceptions.divByZero",
69+
"enable floating point exception for division-by-zero operation",
70+
Cvar::INIT, false);
71+
static Cvar::Cvar<bool> common_floatExceptions_overflow("common.floatExceptions.overflow",
72+
"enable floating point exception for operation producing an overflow",
73+
Cvar::INIT, false);
74+
#endif
75+
5476
namespace Sys {
5577
static Cvar::Cvar<bool> cvar_common_shutdownOnDrop("common.shutdownOnDrop", "shut down engine on game drop", Cvar::TEMPORARY, false);
5678

@@ -276,6 +298,69 @@ static void CloseSingletonSocket()
276298
#endif
277299
}
278300

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

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

0 commit comments

Comments
 (0)