[SimplifyCFG] SUCCESS! Teach createUnreachableSwitchDefault() to preserve DomTree

This pretty much concludes patch series for updating SimplifyCFG
to preserve DomTree. All 318 dedicated `-simplifycfg` tests now pass
with `-simplifycfg-require-and-preserve-domtree=1`.

There are a few leftovers that apparently don't have good test coverage.
I do not yet know what gaps in test coverage will the wider-scale testing
reveal, but the default flip might be close.
This commit is contained in:
Roman Lebedev 2021-01-01 03:19:17 +03:00
parent e1440d43bc
commit 831636b0e6
No known key found for this signature in database
GPG Key ID: 083C3EBB4A1689E0
2 changed files with 28 additions and 6 deletions

View File

@ -4783,15 +4783,29 @@ static bool CasesAreContiguous(SmallVectorImpl<ConstantInt *> &Cases) {
return true;
}
static void createUnreachableSwitchDefault(SwitchInst *Switch) {
static void createUnreachableSwitchDefault(SwitchInst *Switch,
DomTreeUpdater *DTU) {
LLVM_DEBUG(dbgs() << "SimplifyCFG: switch default is dead.\n");
auto *BB = Switch->getParent();
BasicBlock *NewDefaultBlock =
SplitBlockPredecessors(Switch->getDefaultDest(), Switch->getParent(), "");
SplitBlockPredecessors(Switch->getDefaultDest(), Switch->getParent(), "",
DTU ? &DTU->getDomTree() : nullptr);
auto *OrigDefaultBlock = Switch->getDefaultDest();
Switch->setDefaultDest(&*NewDefaultBlock);
SplitBlock(&*NewDefaultBlock, &NewDefaultBlock->front());
if (DTU)
DTU->applyUpdatesPermissive(
{{DominatorTree::Delete, BB, OrigDefaultBlock},
{DominatorTree::Insert, BB, &*NewDefaultBlock}});
SplitBlock(&*NewDefaultBlock, &NewDefaultBlock->front(),
DTU ? &DTU->getDomTree() : nullptr);
SmallVector<DominatorTree::UpdateType, 2> Updates;
for (auto *Successor : successors(NewDefaultBlock))
Updates.push_back({DominatorTree::Delete, NewDefaultBlock, Successor});
auto *NewTerminator = NewDefaultBlock->getTerminator();
new UnreachableInst(Switch->getContext(), NewTerminator);
EraseTerminatorAndDCECond(NewTerminator);
if (DTU)
DTU->applyUpdatesPermissive(Updates);
}
/// Turn a switch with two reachable destinations into an integer range
@ -4803,6 +4817,8 @@ bool SimplifyCFGOpt::TurnSwitchRangeIntoICmp(SwitchInst *SI,
bool HasDefault =
!isa<UnreachableInst>(SI->getDefaultDest()->getFirstNonPHIOrDbg());
auto *BB = SI->getParent();
// Partition the cases into two sets with different destinations.
BasicBlock *DestA = HasDefault ? SI->getDefaultDest() : nullptr;
BasicBlock *DestB = nullptr;
@ -4906,11 +4922,17 @@ bool SimplifyCFGOpt::TurnSwitchRangeIntoICmp(SwitchInst *SI,
// Clean up the default block - it may have phis or other instructions before
// the unreachable terminator.
if (!HasDefault)
createUnreachableSwitchDefault(SI);
createUnreachableSwitchDefault(SI, DTU);
auto *UnreachableDefault = SI->getDefaultDest();
// Drop the switch.
SI->eraseFromParent();
if (!HasDefault && DTU)
DTU->applyUpdatesPermissive(
{{DominatorTree::Delete, BB, UnreachableDefault}});
return true;
}
@ -4957,7 +4979,7 @@ static bool eliminateDeadSwitchCases(SwitchInst *SI, DomTreeUpdater *DTU,
if (HasDefault && DeadCases.empty() &&
NumUnknownBits < 64 /* avoid overflow */ &&
SI->getNumCases() == (1ULL << NumUnknownBits)) {
createUnreachableSwitchDefault(SI);
createUnreachableSwitchDefault(SI, /*DTU=*/nullptr);
return true;
}

View File

@ -1,5 +1,5 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt %s -simplifycfg -S | FileCheck %s
; RUN: opt %s -simplifycfg -simplifycfg-require-and-preserve-domtree=1 -S | FileCheck %s
declare i32 @f(i32)