-
Notifications
You must be signed in to change notification settings - Fork 11.9k
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
Compile time evaluation doesn't match runtime evaluation with -ffp-contract=on #98197
Comments
@llvm/issue-subscribers-clang-frontend Author: Basile Fraboni (bfraboni)
Hey LLVM team,
I found out a while ago that when
I think the expected result should be that these two evaluations match all the time, and it seems that the compile time evaluation always use fma even when it is not forced with -mfma. I still don't get what's the exact difference between ffp-contract and mfma but it might something to look into. Thank you 🙏 |
Correct. The runtime lowering is target dependent so -mfma happens to make x86 use a native fma instruction |
Note, in C++, it is a recommended practice but not a normative requirement for floating-point operations to have the same behavior at compile time and runtime: https://eel.is/c++draft/expr.const#15 However, in C, it's a semantic requirement (see C23 6.6p17: "The semantic rules for the evaluation of a constant expression are the same as for nonconstant expressions.") C23 has So I think this is somewhere between "bug" and "feature request", but I think Clang should aim to implement the recommended practice whenever possible (though I think C's requirement is overreaching). However, there are a lot of floating-point flags that change the behavior and I'm not certain we're equipped to handle the combinatorial explosion that comes from trying to support them all in constant expressions. CC @jcranmer-intel @hubert-reinterpretcast @tbaederr @zahiraam |
6.5p8: "Otherwise, whether or how expressions are contracted is implementation-defined." Arguably, we can implementation-define that we don't contract in constant expressions. This is a bit of a malicious reading of the standard, but it is perhaps enough cover to say that our failure to consistently execute the same at compile-time versus runtime.
Beyond the combinatorial issue with all the different floating point modes, there's also the fun fact that contract can do things other than FMA, a fact many people tend to miss. I can virtually guarantee that people in the backend adding new combines that take advantage of contraction will neglect to implement the same combines in the frontend, and to be frank, the contractions in practice will to some degree rely on serendipity as to whether or not optimizations will nudge the instructions to the right position or not. (Although C also limits contraction to within single expressions, which is not how it's implemented in the backend!) |
@AaronBallman does that mean in C++ I can't trust any
@arsenm so the flag |
The FMA instructions in x86 aren't available in all hardware. You need the |
The documentation page states the following about
I guess what I'm trying to understand is more the difference between |
Within the compiler, if it sees a Note that it is possible to make an fma operation even without hardware FMA support ( In short, there's three decisions going on here:
|
Thank you @jcranmer-intel for the detailed answer, that makes more sense now ! |
Back to the issue, I'm still concerned about this backend VS frontend discrepancy. I applied a "make constexpr everything I can" policy lately for performance reasons, but knowing that operations are not enforced to be the same makes me doubt robustness now. I agree with @AaronBallman saying that clang should be complying with recommendations here. It is not advertised / warned anywhere that constexpr can return inconsistent results with floating points and I think operations should try to respect the flags they are compiled with, otherwise it makes constexpr fp a lot less useful. There is maybe another good reason but even when I only use constexpr I can get inconsistent results in compile time when evaluating the exact same line of code inside or outside a function: https://godbolt.org/z/vTd5PWexz |
Not consistently @arsenm , see the above godbolt repro , the compile time eval doesn't match all the time ☝️ |
This is the behavior for cases where llvm.fmuladd is emitted, which is always treated as FMA. I don't know what clang is doing in the constexpr evaluation case |
Fast-math flags (which include |
I get it now that for frontend vs backend it is not simple to give the same answer all the time. However, I still have no clue why the frontend does not always give the same answer for the same constexpr line of code, see : https://godbolt.org/z/vTd5PWexz |
Ok I found out, the function call inside the printf does not enforce constexpr result, so it is probably evaluated with a different code path. If I assign the result to a constexpr variable first, I get the same result. That's tricky. Thanks all for your insights @arsenm @jcranmer-intel @AaronBallman , I know better how things work now . Closing this one! |
Hey LLVM team,
I found out a while ago that when
-ffp-contract=on
the compile time evaluation mismatch the runtime one for some expressions, but I identified that too late to get any traction. Next are some godbolt examples for repro:-O1 -ffp-contract=on
: https://godbolt.org/z/3qTda8KP9-O1 -ffp-contract=on -mfma
: https://godbolt.org/z/vjjoP35W8-O1 -ffp-contract=off
: https://godbolt.org/z/6q1vfbWbT-O1 -ffp-contract=fast
: https://godbolt.org/z/e7Ms55xv1I think the expected result should be that these two evaluations match all the time, and it seems that the compile time evaluation always use fma even when it is not forced with -mfma. I still don't get what's the exact difference between ffp-contract and mfma but it might something to look into.
Thank you 🙏
The text was updated successfully, but these errors were encountered: