This is an archive of the discontinued LLVM Phabricator instance.

[ISEL][BitTestBlock] omit additional bit test when default destination is unreachable
ClosedPublic

Authored by nickdesaulniers on Sep 1 2021, 3:55 PM.

Details

Summary

Otherwise we end up with an extra conditional jump, following by an
unconditional jump off the end of a function. ie.

bb.0:
  BT32rr ..
  JCC_1 %bb.4 ...
bb.1:
  BT32rr ..
  JCC_1 %bb.2 ...
  JMP_1 %bb.3
bb.2:
  ...
bb.3.unreachable:
bb.4:
  ...

Should be equivalent to:
bb.0:
  BT32rr ..
  JCC_1 %bb.4 ...
  JMP_1 %bb.2
bb.1:
bb.2:
  ...
bb.3.unreachable:
bb.4:
  ...

This can occur since at the higher level IR (Instruction) SwitchInsts
are required to have BBs for default destinations, even when it can be
deduced that such BBs are unreachable.

For most programs, this isn't an issue, just wasted instructions since the
unreachable has been statically proven.

The x86_64 Linux kernel when built with CONFIG_LTO_CLANG_THIN=y fails to
boot though once D106056 is re-applied. D106056 makes it more likely
that correlation-propagation (CVP) can deduce that the default case of
SwitchInsts are unreachable. The x86_64 kernel uses a binary post
processor called objtool, which emits this warning:

vmlinux.o: warning: objtool: cfg80211_edmg_chandef_valid()+0x169: can't
find jump dest instruction at .text.cfg80211_edmg_chandef_valid+0x17b

I haven't debugged precisely why this causes a failure at boot time, but
fixing this very obvious jump off the end of the function fixes the
warning and boot problem.

Link: https://bugs.llvm.org/show_bug.cgi?id=50080
Fixes: https://github.com/ClangBuiltLinux/linux/issues/679
Fixes: https://github.com/ClangBuiltLinux/linux/issues/1440

Diff Detail

Event Timeline

nickdesaulniers created this revision.Sep 1 2021, 3:55 PM
nickdesaulniers requested review of this revision.Sep 1 2021, 3:55 PM
Herald added a project: Restricted Project. · View Herald TranscriptSep 1 2021, 3:55 PM
craig.topper edited the summary of this revision. (Show Details)Sep 1 2021, 3:58 PM
lebedev.ri added inline comments.Sep 1 2021, 3:59 PM
llvm/test/CodeGen/X86/SwitchLowering.ll
68

Precommit please

nickdesaulniers edited the summary of this revision. (Show Details)Sep 1 2021, 4:01 PM
nickdesaulniers edited the summary of this revision. (Show Details)
nickdesaulniers marked an inline comment as done.Sep 1 2021, 4:12 PM

ugh, global isel has this problem, too...

hans added inline comments.Sep 2 2021, 2:03 AM
llvm/lib/CodeGen/SwitchLoweringUtils.cpp
455 ↗(On Diff #370104)

I don't think this line is quite right.

The "default" for a bit test is not necessarily the same as the default for the SwitchInst -- it's just the block that control falls through to if all the bit tests fail, and that block could be one that handles other switch cases. (It would be better if BitTestBlock.Default was renamed to BitTestBlock.Fallthrough).

You can see how BitTestBlock.Default gets set in SelectionDAGBuilder::lowerWorkItem():

// Fill in fields of the BitTestBlock.                          
BTB->Parent = CurMBB;
BTB->Default = Fallthrough;

However, that code does know whether the fallthrough block is unreachable, and already uses that to set the BitTestBlock::OmitRangeCheck. Maybe OmitRangeCheck could be renamed to UnreachableDefault, and used for both omitting the range check and skipping the last bit test?

nickdesaulniers marked an inline comment as done.
  • reused OmitRangeCheck, remove UnreachableDefault
llvm/lib/CodeGen/SwitchLoweringUtils.cpp
455 ↗(On Diff #370104)

Oh, right, good point. Yeah, OmitRangeCheck is set based on the same criteria, I should just re-use that; then I don't need to add anything to BitTestBlock.

I think the identifier OmitRangeCheck is nice and explains what we're going to do, so I wont rename it to UnreachableDefault.

Should I fix GlobalISel in this patch, or do so in a follow up (renaming this from ISEL to SDAGISEL)?

I'm going to move llvm/test/CodeGen/X86/switch-bit-test-unreachable-default.ll to D109106 so that we can also see more easily what's changed by this commit. I'm also going to add a RUN with explicit -global-isel=0/-global-isel=1.

nickdesaulniers planned changes to this revision.Sep 2 2021, 11:54 AM
nickdesaulniers retitled this revision from [ISEL][BitTestBlock] omit additional bit test when default destination is unreachable to omit additional bit test when default destination is unreachable.
  • rebase on D109106; haven't fixed global isel yet.
  • fix global-isel, too
nickdesaulniers retitled this revision from omit additional bit test when default destination is unreachable to [ISEL][BitTestBlock] omit additional bit test when default destination is unreachable.
  • re-add [ISEL][BitTestBlock] I accidentally dropped when rebasing
hans accepted this revision.Sep 3 2021, 5:43 AM

Nice, lgtm. Only some nits about names from my side now.

llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
3022

I think UnreachableDefault (or UnreachableFallthrough) would be a better name now, since it doesn't just omit the range check, it also omits the last bit test.

Also some day we should unify all the switch lowering implementations in LLVM, I think there are four or so now :-)

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
10872–10873

The behaviour is really "skip the range check and last bit test", so the comment could either reflect that -- or if we rename the variable then maybe the comment becomes redundant and we can drop it.

This revision is now accepted and ready to land.Sep 3 2021, 5:43 AM
llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
3022

Should this be renamed for BitTestBlock AND JumpTableHeader?

llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp
3022

Created https://reviews.llvm.org/D109455 as a child revision. I'm going to land this as is to unblock https://reviews.llvm.org/D106056 ASAP (and get our failing boot tests back online).

This revision was landed with ongoing or failed builds.Sep 8 2021, 11:04 AM
This revision was automatically updated to reflect the committed changes.