Open WaffleLapkin opened 2 years ago
@rustbot label +A-codegen +C-enhancement +I-slow +T-compiler
I think there's an LLVM bug here, despite your clang example.
Here's a demonstration using just opt
that it doesn't notice the defaultdest
is unreachable, and thus leaves the infinite loop there: https://llvm.godbolt.org/z/GcG1dM3sq
In LLVM, when the optimization fires, the unreachable bb is replaced with .unreachabledefault
(https://llvm.godbolt.org/z/jWeeWYKhE), so we can tell it's created by createUnreachableSwitchDefault
, called from here: https://github.com/llvm/llvm-project/blob/c25ba3c79020246b24aa658ac02770be07eee0f5/llvm/lib/Transforms/Utils/SimplifyCFG.cpp#L4990.
That code determines whether or not the default condition is reachable based on the number of significant bits in the condition, which is why it doesn't work until you have power-of-2-minus-1
cases. It could be made more precise. (I'm looking into this.)
I believe https://reviews.llvm.org/D106056 has already fixed this. Unfortunately, this exposed some compile-time issues in the backend, which haven't been resolved yet, so the patch is reverted for now.
Looks like this will be handled better in LLVM 18 (after #120055): https://godbolt.org/z/reaf5oKcb
@erikdesjardins I believe the relevant change has been reverted.
There is a PR that adds unreachable like that: https://github.com/rust-lang/rust/pull/120268
There is a PR that adds unreachable like that: #120268
It only solves enum scenarios. https://github.com/llvm/llvm-project/pull/76669 will partially solve the issue. It was also reverted due to some codegen issues.
I believe https://reviews.llvm.org/D106056 has already fixed this. Unfortunately, this exposed some compile-time issues in the backend, which haven't been resolved yet, so the patch is reverted for now.
Looks like the same issue I'm having.
There is a PR that adds unreachable like that: #120268
It only solves enum scenarios. The enum scenario has been solved, this PR is an extension.
https://github.com/llvm/llvm-project/pull/76669 will partially solve the issue. It was also reverted due to some backend issues.
llvm/llvm-project#76669 will partially solve the issue. It was also reverted due to some backend issues.
That change got unreverted and was included in the recent LLVM 19 upgrade, so I believe this is now fixed: https://godbolt.org/z/1MvffeWff
@rustbot label E-needs-test
This is probably fixed by https://github.com/llvm/llvm-project/pull/79993.
Hmm, looks like 1.78 has fixed this: https://rust.godbolt.org/z/n4fbG4xj4.
Consider this example:
It currently generates similar LLVM-IR:
Even though the default branch is unreachable (
x % 5
can't be greater than 4) it is still generated.But, when un-commenting
5 | 6 | 7 => loop{}
line (still unreachable branch, that does the same as default) the default branch becomesunreachable
:So, adding an unreachable branch that does the same as the default helps optimize the code.
Some notes:
5 | 6 | 7
is commented-out5..=7
) do not help5 | 6 | 7 | _
doesn't help eitherN
inx % N
that is not a power of two -- adding unreachable branches until the last branch has a power-of-two-minus-one-value helps optimizing the codeN = 3
(3 =>
)N = 9
(9 | 10 | 11 | 12 | 13 | 14 | 15 =>
)N = 14
(14 | 15 =>
)loop{}
s can be replaced with anything else, for exampleunreachable!()
orpanic!()
, effect is still the sameloop{}
s to make diffs less noisyif-else-if
chains are identical tomatch
herellvm-ir
, instead of generating anunreachable
one