This is an archive of the discontinued LLVM Phabricator instance.

Teach SimplifyCFG to fold switches into lookup tables in more cases.
ClosedPublic

Authored by resistor on Sep 9 2021, 10:13 PM.

Details

Summary

In particular, it couldn't handle cases where lookup table constant
expressions involved bitcasts. This does not seem to come up
frequently in C++, but comes up reasonably often in Rust via
#[derive(Debug)].

Originally reported by pcwalton.

Diff Detail

Event Timeline

resistor created this revision.Sep 9 2021, 10:13 PM
resistor requested review of this revision.Sep 9 2021, 10:13 PM
Herald added a project: Restricted Project. · View Herald TranscriptSep 9 2021, 10:13 PM

Looks fine to me. Note that to trigger on Debug we also need the frontend changes at https://github.com/rust-lang/rust/pull/88832.

Won't this also skip non-zero-offset GEP's?
Are you sure you don't want stripPointerCasts()/stripPointerCastsAndAliases()/stripPointerCastsSameRepresentation() instead?

nikic added inline comments.Sep 10 2021, 2:20 PM
llvm/lib/Transforms/Utils/SimplifyCFG.cpp
5060

Note that GEPs are already handled below, so we should either drop that handling, or handle bitcasts in the same way. The current GEP handling uses "no notional overindexing" as the condition, which I agree is an unnecessary requirement here -- your choice of "inbounds with constant offsets" is the right one. Whether there is notional overindexing really shouldn't matter in this context, the relocation only cares about offsets.

However, something your implementation changes is that shouldBuildLookupTablesForConstant() no longer gets called on the original constant, only on the stripped one. It looks like only ARM uses this hook and wouldn't be affected by the change (because the stripped bitcasts/GEPs do not affect whether the constant requires relocation), but I think it would be in the spirit of the hook to continue calling it on the original constant.

resistor added inline comments.Sep 10 2021, 3:26 PM
llvm/lib/Transforms/Utils/SimplifyCFG.cpp
5060

Good point. I will update to account for this.

resistor updated this revision to Diff 372023.Sep 10 2021, 3:29 PM

Update based on comments to preserve original behavior of shouldBuildLookupTablesForConstant().

Won't this also skip non-zero-offset GEP's?

Yes, that's intentional. See the comment and the other thread of discussion.

nikic added inline comments.Sep 11 2021, 12:14 PM
llvm/test/Transforms/SimplifyCFG/switch-to-lookup-bitcast.ll
3 ↗(On Diff #372023)

This target triple either needs to be dropped (if the test works without it), or the test should be moved in to the X86 subdirectory.

16 ↗(On Diff #372023)

It would be good to reduce the number of switch cases in this test -- we probably don't need 12 to produce a lookup table.

llvm/test/Transforms/SimplifyCFG/switch-to-lookup-gep.ll
80 ↗(On Diff #372023)

This only tests a GEP with a zero offset, which is a degenerate case. It would be better to test a non-zero offset.

We could also have a negative test that no lookup table is created if a GEP index is not a constant integer (but rather something like ptrtoint i8* @g to i64.

resistor updated this revision to Diff 372168.Sep 12 2021, 11:13 PM
resistor marked an inline comment as done.

Update for comments.

llvm/test/Transforms/SimplifyCFG/switch-to-lookup-bitcast.ll
3 ↗(On Diff #372023)

The test does not work without it.

llvm/test/Transforms/SimplifyCFG/switch-to-lookup-gep.ll
80 ↗(On Diff #372023)

Updated test to use non-zero offsets. The proposed negative test doesn't fail, and it's not clear to me that it should fail.

resistor updated this revision to Diff 372493.Sep 14 2021, 8:44 AM

Update for comments.

nikic added inline comments.Sep 15 2021, 1:08 PM
llvm/lib/Transforms/Utils/SimplifyCFG.cpp
5072

Shouldn't this condition be StrippedC == C ||? What you're doing now is effectively allowing all constant expressions for which nothing can be stripped.

nikic added inline comments.Sep 15 2021, 1:09 PM
llvm/test/Transforms/SimplifyCFG/switch-to-lookup-gep.ll
80 ↗(On Diff #372023)

This would effectively correspond to a "global1 + global2" expression, which is not a generally (or at all?) supported relocation type.

resistor updated this revision to Diff 372784.Sep 15 2021, 1:16 PM

Update for comments.

resistor marked an inline comment as done.Sep 15 2021, 1:17 PM
resistor added inline comments.
llvm/lib/Transforms/Utils/SimplifyCFG.cpp
5072

Done

resistor marked an inline comment as done.Sep 15 2021, 1:18 PM
resistor added inline comments.
llvm/test/Transforms/SimplifyCFG/switch-to-lookup-gep.ll
80 ↗(On Diff #372023)

The proposed test is dicey. I'm not sure that "global1 + global2" can ever be correctly marked as inbounds, in which case it's a semantically invalid input.

nikic added inline comments.Sep 15 2021, 1:18 PM
llvm/lib/Transforms/Utils/SimplifyCFG.cpp
5072

This still needs a negative test for unsupported constant expressions.

resistor updated this revision to Diff 372786.Sep 15 2021, 1:24 PM

Add a negative test for non-inbounds GEPs.

resistor marked an inline comment as done.Sep 15 2021, 1:25 PM
nikic added inline comments.Sep 15 2021, 1:31 PM
llvm/test/Transforms/SimplifyCFG/switch-to-lookup-gep.ll
80 ↗(On Diff #372023)

Unless LLVM can prove that it's not inbounds, it doesn't really matter. Say global2 is a weak symbol and you know that it will actually always be NULL and thus the addition is inbounds. We just use ptrtoint of globals as an easy way to produce an unfoldable expression.

resistor added inline comments.Sep 15 2021, 2:03 PM
llvm/test/Transforms/SimplifyCFG/switch-to-lookup-gep.ll
80 ↗(On Diff #372023)

In that case we have to weaken the stripping - inbounds isn't a strong enough condition to correctness.

nikic added inline comments.Sep 15 2021, 2:05 PM
llvm/test/Transforms/SimplifyCFG/switch-to-lookup-gep.ll
80 ↗(On Diff #372023)

The condition is already "inbounds with constant offsets". While not obvious from the name, "constant offsets" here means ConstantInt offsets and already excludes constant expression GEP operands.

resistor updated this revision to Diff 372800.Sep 15 2021, 2:10 PM

Add negative test for ptrtoint.

resistor marked 2 inline comments as done.Sep 15 2021, 2:10 PM
resistor added inline comments.
llvm/test/Transforms/SimplifyCFG/switch-to-lookup-gep.ll
80 ↗(On Diff #372023)

Added a test for this scenario.

nikic accepted this revision.Sep 15 2021, 2:12 PM

LGTM, thanks!

This revision is now accepted and ready to land.Sep 15 2021, 2:12 PM
This revision was automatically updated to reflect the committed changes.
resistor marked an inline comment as done.