forked from OSchip/llvm-project
[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:
parent
e1440d43bc
commit
831636b0e6
|
@ -4783,15 +4783,29 @@ static bool CasesAreContiguous(SmallVectorImpl<ConstantInt *> &Cases) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void createUnreachableSwitchDefault(SwitchInst *Switch) {
|
static void createUnreachableSwitchDefault(SwitchInst *Switch,
|
||||||
|
DomTreeUpdater *DTU) {
|
||||||
LLVM_DEBUG(dbgs() << "SimplifyCFG: switch default is dead.\n");
|
LLVM_DEBUG(dbgs() << "SimplifyCFG: switch default is dead.\n");
|
||||||
|
auto *BB = Switch->getParent();
|
||||||
BasicBlock *NewDefaultBlock =
|
BasicBlock *NewDefaultBlock =
|
||||||
SplitBlockPredecessors(Switch->getDefaultDest(), Switch->getParent(), "");
|
SplitBlockPredecessors(Switch->getDefaultDest(), Switch->getParent(), "",
|
||||||
|
DTU ? &DTU->getDomTree() : nullptr);
|
||||||
|
auto *OrigDefaultBlock = Switch->getDefaultDest();
|
||||||
Switch->setDefaultDest(&*NewDefaultBlock);
|
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();
|
auto *NewTerminator = NewDefaultBlock->getTerminator();
|
||||||
new UnreachableInst(Switch->getContext(), NewTerminator);
|
new UnreachableInst(Switch->getContext(), NewTerminator);
|
||||||
EraseTerminatorAndDCECond(NewTerminator);
|
EraseTerminatorAndDCECond(NewTerminator);
|
||||||
|
if (DTU)
|
||||||
|
DTU->applyUpdatesPermissive(Updates);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Turn a switch with two reachable destinations into an integer range
|
/// Turn a switch with two reachable destinations into an integer range
|
||||||
|
@ -4803,6 +4817,8 @@ bool SimplifyCFGOpt::TurnSwitchRangeIntoICmp(SwitchInst *SI,
|
||||||
bool HasDefault =
|
bool HasDefault =
|
||||||
!isa<UnreachableInst>(SI->getDefaultDest()->getFirstNonPHIOrDbg());
|
!isa<UnreachableInst>(SI->getDefaultDest()->getFirstNonPHIOrDbg());
|
||||||
|
|
||||||
|
auto *BB = SI->getParent();
|
||||||
|
|
||||||
// Partition the cases into two sets with different destinations.
|
// Partition the cases into two sets with different destinations.
|
||||||
BasicBlock *DestA = HasDefault ? SI->getDefaultDest() : nullptr;
|
BasicBlock *DestA = HasDefault ? SI->getDefaultDest() : nullptr;
|
||||||
BasicBlock *DestB = 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
|
// Clean up the default block - it may have phis or other instructions before
|
||||||
// the unreachable terminator.
|
// the unreachable terminator.
|
||||||
if (!HasDefault)
|
if (!HasDefault)
|
||||||
createUnreachableSwitchDefault(SI);
|
createUnreachableSwitchDefault(SI, DTU);
|
||||||
|
|
||||||
|
auto *UnreachableDefault = SI->getDefaultDest();
|
||||||
|
|
||||||
// Drop the switch.
|
// Drop the switch.
|
||||||
SI->eraseFromParent();
|
SI->eraseFromParent();
|
||||||
|
|
||||||
|
if (!HasDefault && DTU)
|
||||||
|
DTU->applyUpdatesPermissive(
|
||||||
|
{{DominatorTree::Delete, BB, UnreachableDefault}});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4957,7 +4979,7 @@ static bool eliminateDeadSwitchCases(SwitchInst *SI, DomTreeUpdater *DTU,
|
||||||
if (HasDefault && DeadCases.empty() &&
|
if (HasDefault && DeadCases.empty() &&
|
||||||
NumUnknownBits < 64 /* avoid overflow */ &&
|
NumUnknownBits < 64 /* avoid overflow */ &&
|
||||||
SI->getNumCases() == (1ULL << NumUnknownBits)) {
|
SI->getNumCases() == (1ULL << NumUnknownBits)) {
|
||||||
createUnreachableSwitchDefault(SI);
|
createUnreachableSwitchDefault(SI, /*DTU=*/nullptr);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
; 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)
|
declare i32 @f(i32)
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue