-
Notifications
You must be signed in to change notification settings - Fork 62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add USE_FLOAT_EXCEPTIONS
to enable floating point exceptions
#1451
base: master
Are you sure you want to change the base?
Conversation
…vars to enable floating point exceptions
I have not tested the Apple and MSVC code. |
f05b27f
to
4993a7f
Compare
USE_DEBUG_FPE
to enable floating point exceptionsUSE_FLOAT_EXCEPTIONS
to enable floating point exceptions
4993a7f
to
8687854
Compare
I renamed the cmake option to |
b878d3a
to
7c60e69
Compare
src/engine/framework/System.cpp
Outdated
static void SetFloatingPointExceptions() | ||
{ | ||
// Must be done after Sys::Init() to read cvars from command line. | ||
#if defined(DAEMON_USE_FLOAT_EXCEPTIONS_AVAILABLE) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Our code style is to have these on the left side and never indent them based on indentation of non-preprocessor code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's bad practice within a block, really.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What? This style is used very consistently in our code and is common in other code bases too. Preprocessor and non-preprocessor lines do not syntactically nest with each other, so it makes a sort of sense that neither one affects the other's indentation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When the ifdef
is just a precompiled replacement for a test that would be doable at run time, it's better to keep them readable the same way, really.
Not indenting some ifdef
is only a good solution when something can't be indented properly, like in a single operation, function call with optional parameters, or things like that…
We better use nested ifdef
when it's possible, it makes things much more readable.
I modified the code to not indent the first level of ifdef
, but keeping the other indentations makes it it much more readable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This has been done the same way throughout the history of the codebase so we should keep doing it that way instead of worsening the mixture of styles, regardless of some arguments that a different one would be better if starting from scratch.
src/engine/framework/System.cpp
Outdated
unsigned int exceptions = 0; | ||
#endif | ||
|
||
// Operations with NaN. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not very accurate, cos(1.001)
also does this for example
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are you sure?
Warn: Computing √-1…
Warn: Result of √-1: -nan
Warn: Computing cos(1.001)…
Warn: Result of cos(1.001): 0.539
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And the invalid
exception isn't caught with cos(1.001)
, but is caught with sqrt(-1)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Typo, I meant acos
(inverse cosine)
cmake/DaemonFlags.cmake
Outdated
@@ -148,13 +148,20 @@ else() | |||
set(WARNMODE "no-") | |||
endif() | |||
|
|||
# Compiler options | |||
option(USE_FLOAT_EXCEPTIONS "Use floating point exceptions" OFF) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The use description of this is not quite accurate. It doesn't turn on exceptions; it alters compiler options in a way that makes the exceptions more likely to be useful. Maybe you could call it USE_FLOAT_DEBUG_MODE or something
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually I think the name is fine but it would be good to mention the cvars. Enable floating point exceptions with common.floatException.* cvars
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
7c60e69
to
a65cdc7
Compare
Hmm, my mac doesn't support more than Catalina, so no more than macOS 10.15.7 with Clang 12.0.0, and I get these errors:
So I cannot test macOS right now. |
10070cb
to
4086988
Compare
I face a weird cmake bug, if I do that: if (USE_FLOAT_EXCEPTIONS)
message(STATUS "test true")
# Floating point exceptions requires trapping math
# to avoid false positives on architectures with SSE.
set_c_cxx_flag("-ffp-model=strict")
endif() The “test true” message is printed, but the But if I do: set_c_cxx_flag("-ffp-model=strict")
if (USE_FLOAT_EXCEPTIONS)
message(STATUS "test true")
# Floating point exceptions requires trapping math
# to avoid false positives on architectures with SSE.
endif() The flag is set. So to sum it up:
but the whole combination doesn't work… |
If I do instead: if (USE_FLOAT_EXCEPTIONS)
message(STATUS "test true")
try_c_cxx_flag(FFP_MODEL_STRICT "-ffp-model=strict")
# Floating point exceptions requires trapping math
# to avoid false positives on architectures with SSE.
endif() I get this printed:
But the flag is not added to the compiler command line. On the contrary if I do that: try_c_cxx_flag(FFP_MODEL_STRICT "-ffp-model=strict")
if (USE_FLOAT_EXCEPTIONS)
message(STATUS "test true")
# Floating point exceptions requires trapping math
# to avoid false positives on architectures with SSE.
endif() I get this printed:
And the flag is added to the compiler command line. |
8417ef8
to
9fa7434
Compare
278fa37
to
7c8ac23
Compare
9e5dd3a
to
da7a0e5
Compare
That looks ready to me. I've added a cvar named |
I only tested on Linux. I can't test on macOS:
I don't use MSVC. |
Note: people says on the Internet that on macOS this code will only work on amd64, not on arm64, I haven't implemented the macOS arm64 workaround: https://stackoverflow.com/a/71792418 |
_controlfp_s(¤t, exceptions, _MCW_EM); | ||
#endif | ||
|
||
if (common_floatExceptions_test.Get()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The injectFault
command can already do this. If more types of exception are needed they should be added there
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The purpose of this test is not only to test if the exception is caught when raised, but also to make sure that when doing the mistake for real the exception is raised.
As reported on chat, I noticed that doesn't raise an exception:
float f = std::numeric_limits<float>::max();
Log::Warn("Result of 2×%.0f: %.0f", f, 2*f);
But doing that raises an exception:
volatile float f = std::numeric_limits<float>::max();
Log::Warn("Result of 2×%.0f: %.0f", static_cast<float>(f), 2*f);
I want to test that.
We can also do some injectFault()
calls, but to me that should only be done after those tests are done (basically to test that the exception catching works even if the error did not happened, so we can investigate while the error did not happened).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An injectFault
fault flavor need not be guaranteed to crash in all circumstances. I don't see any reason why this stuff wouldn't fit well there.
|
||
VectorScale( v, ilength, v ); | ||
#if DAEMON_USE_FLOAT_EXCEPTIONS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The program should not change its behavior like that when the debugging thing is used. That nullifies the whole point of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not changing this behavior nullifies the whole point of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole point of it is:
- Making possible to debug everything that is not
Q_rsqrt_fast()
as called byVectorNormalizeFast()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole point of it is:
* Making possible to debug everything that is not `Q_rsqrt_fast()` as called by `VectorNormalizeFast()`.
Why? There should be some explanation for this.
da7a0e5
to
0c354c4
Compare
Using MacOS Sequoia… the symbols were still missing, and I discovered the symbols I was missing were arm64-only. 🤦♀️️ Now I have a code that works for amd64 on macOS. It probably already works for arm64 on macOS as I actually ported an arm64 code to also support amd64. |
|
USE_FLOAT_EXCEPTIONS
to enable floating point exceptions (disabled by default)USE_FAST_MATH
to enable or disable fast math (enabled by default)When
USE_FLOAT_EXCEPTIONS
is used, nothing is done unless some of those cvars are enabled:common.floatExceptions.invalid
common.floatExceptions.divByZero
common.floatExceptions.overflow
The
USE_FLOAT_EXCEPTIONS
option is required to specialize the build to make it possible to enable them.The
common.floatExceptions.test
cvar enables some code doing bad floating point operations on purpose to test how they are handled.