-
Notifications
You must be signed in to change notification settings - Fork 12k
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
Behavior of overflowing floating-point to integer conversions #66603
Comments
Some additional info - in the C standard, Annex F, Granted, LLVM does not, to my understanding, claim to support Annex F, but this is a nudge towards making the result unspecified instead of undefined (which would mean that |
Clang considers this undefined behavior by default, but you can use |
Thanks, that's a useful note. Though unfortunately it saturating means significantly more generated code on x86-64 & risc-v, so it's not much better in my case where I do want it to be as fast as possible. I suppose, with, |
As we don't seem to promise any specific behavior in the documentation, it might be possible to change it use freeze(fptoui) instead of fptui.sat, which would be about what you want. Not sure whether people rely on the current saturating implementation. |
Seems adding a |
Simpler example: https://godbolt.org/z/afeaEf8oo This does look like a miscompile to me. We have this type-legalized SDAG:
Which gets DAGCombined to:
Note that the freeze was moved past the AssertSext. This happens because these are explicitly listed as not creation undef/poison: llvm-project/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp Lines 5006 to 5007 in 3f4bf99
This looks incorrect to me. |
This was introduced in 7e294e676e32f by @RKSimon. What was the rationale for that change? Wouldn't these nodes return poison if the assertion does not hold? |
IIRC the descriptions at the moment doesn't allow for cases where the assert nodes don't hold. |
Feel free to remove the assertzext/sext cases if it's causing a problem and we can revisit this. |
Some issues remain - without a changed And, less importantly, there's the missed optimization for x86-64 of dropping |
I would perhaps propose Also,
which might've been the case back then (it definitely doesn't saturate at least on clang≤13), but since clang 14 it's rather inaccurate as x86's native behavior isn't saturating. |
This issue is either:
a) a missed optimization in the x86-64 backend; or
b) a wrong optimization in the aarch64 backend.Consider the following code:
As per the C standard, these functions invoke undefined behavior if given arguments that, rounded to an integer, don't fit in the desired type. Thus,
is_i8
can always be replaced withis_i32
(alive2 proof from the optimized IR).However, the x86-64 backend does not do this, and thus
is_i8
has an unnecessarymovsx eax, al
instruction that can be eliminated. The aarch64 backend does do this optimization. compiler explorer.GCC preserves the int8_t cast on both x86-64 and ARM64 (and everything else I tested in CE): https://godbolt.org/z/78MbdGbPz. (EDIT: on gcc≤13.2, this is only the case with
-ftrapping-math
, which gcc has on by default - adding-fno-trapping-math
(and-msse4.1
on x86-64) it'll convert it to a round-comparison; on gcc≥13.3 it keeps the integer conversion always as far as I can tell)And while C does allow the optimization in question, it means that
x == (T)x
cannot be used as a check for whether the floating-point valuex
fits in the integer typeT
(even though it would work if the conversion gave any valid value ofT
in place of UB/poison). And, as far as I can tell, there is no alternative way to do a check like this anywhere near as performantly, without writing platform-specific assembly, which is, IMO, a quite problematic issue, though not really a clang-specific one.The text was updated successfully, but these errors were encountered: