[Dominators] Convert existing passes and utils to use the DomTreeUpdater class

Summary:
This patch is the second in a series of patches related to the [[ http://lists.llvm.org/pipermail/llvm-dev/2018-June/123883.html | RFC - A new dominator tree updater for LLVM ]].

It converts passes (e.g. adce/jump-threading) and various functions which currently accept DDT in local.cpp and BasicBlockUtils.cpp to use the new DomTreeUpdater class.
These converted functions in utils can accept DomTreeUpdater with either UpdateStrategy and can deal with both DT and PDT held by the DomTreeUpdater.

Reviewers: brzycki, kuhar, dmgreen, grosser, davide

Reviewed By: brzycki

Subscribers: llvm-commits

Differential Revision: https://reviews.llvm.org/D48967

llvm-svn: 338814
This commit is contained in:
Chijun Sima 2018-08-03 05:08:17 +00:00
parent d092d0b179
commit 21a8b605a1
14 changed files with 474 additions and 214 deletions

View File

@ -23,6 +23,7 @@
#include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/BlockFrequencyInfo.h"
#include "llvm/Analysis/BranchProbabilityInfo.h"
#include "llvm/IR/DomTreeUpdater.h"
#include "llvm/IR/ValueHandle.h"
#include <memory>
#include <utility>
@ -34,7 +35,7 @@ class BinaryOperator;
class BranchInst;
class CmpInst;
class Constant;
class DeferredDominance;
class DomTreeUpdater;
class Function;
class Instruction;
class IntrinsicInst;
@ -78,7 +79,7 @@ class JumpThreadingPass : public PassInfoMixin<JumpThreadingPass> {
TargetLibraryInfo *TLI;
LazyValueInfo *LVI;
AliasAnalysis *AA;
DeferredDominance *DDT;
DomTreeUpdater *DTU;
std::unique_ptr<BlockFrequencyInfo> BFI;
std::unique_ptr<BranchProbabilityInfo> BPI;
bool HasProfileData = false;
@ -109,8 +110,8 @@ public:
// Glue for old PM.
bool runImpl(Function &F, TargetLibraryInfo *TLI_, LazyValueInfo *LVI_,
AliasAnalysis *AA_, DeferredDominance *DDT_,
bool HasProfileData_, std::unique_ptr<BlockFrequencyInfo> BFI_,
AliasAnalysis *AA_, DomTreeUpdater *DTU_, bool HasProfileData_,
std::unique_ptr<BlockFrequencyInfo> BFI_,
std::unique_ptr<BranchProbabilityInfo> BPI_);
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);

View File

@ -20,6 +20,7 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/DomTreeUpdater.h"
#include "llvm/IR/InstrTypes.h"
#include <cassert>
@ -27,8 +28,8 @@ namespace llvm {
class BlockFrequencyInfo;
class BranchProbabilityInfo;
class DeferredDominance;
class DominatorTree;
class DomTreeUpdater;
class Function;
class Instruction;
class LoopInfo;
@ -39,7 +40,7 @@ class TargetLibraryInfo;
class Value;
/// Delete the specified block, which must have no predecessors.
void DeleteDeadBlock(BasicBlock *BB, DeferredDominance *DDT = nullptr);
void DeleteDeadBlock(BasicBlock *BB, DomTreeUpdater *DTU = nullptr);
/// We know that BB has one predecessor. If there are any single-entry PHI nodes
/// in it, fold them away. This handles the case when all entries to the PHI
@ -56,10 +57,9 @@ bool DeleteDeadPHIs(BasicBlock *BB, const TargetLibraryInfo *TLI = nullptr);
/// Attempts to merge a block into its predecessor, if possible. The return
/// value indicates success or failure.
bool MergeBlockIntoPredecessor(BasicBlock *BB, DominatorTree *DT = nullptr,
bool MergeBlockIntoPredecessor(BasicBlock *BB, DomTreeUpdater *DTU = nullptr,
LoopInfo *LI = nullptr,
MemoryDependenceResults *MemDep = nullptr,
DeferredDominance *DDT = nullptr);
MemoryDependenceResults *MemDep = nullptr);
/// Replace all uses of an instruction (specified by BI) with a value, then
/// remove and delete the original instruction.

View File

@ -26,6 +26,7 @@
#include "llvm/IR/Constant.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DomTreeUpdater.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/GetElementPtrTypeIterator.h"
#include "llvm/IR/Operator.h"
@ -120,7 +121,7 @@ struct SimplifyCFGOptions {
/// DeleteDeadConditions is true.
bool ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions = false,
const TargetLibraryInfo *TLI = nullptr,
DeferredDominance *DDT = nullptr);
DomTreeUpdater *DTU = nullptr);
//===----------------------------------------------------------------------===//
// Local dead code elimination.
@ -187,20 +188,19 @@ bool SimplifyInstructionsInBlock(BasicBlock *BB,
/// .. and delete the predecessor corresponding to the '1', this will attempt to
/// recursively fold the 'and' to 0.
void RemovePredecessorAndSimplify(BasicBlock *BB, BasicBlock *Pred,
DeferredDominance *DDT = nullptr);
DomTreeUpdater *DTU = nullptr);
/// BB is a block with one predecessor and its predecessor is known to have one
/// successor (BB!). Eliminate the edge between them, moving the instructions in
/// the predecessor into BB. This deletes the predecessor block.
void MergeBasicBlockIntoOnlyPred(BasicBlock *BB, DominatorTree *DT = nullptr,
DeferredDominance *DDT = nullptr);
void MergeBasicBlockIntoOnlyPred(BasicBlock *BB, DomTreeUpdater *DTU = nullptr);
/// BB is known to contain an unconditional branch, and contains no instructions
/// other than PHI nodes, potential debug intrinsics and the branch. If
/// possible, eliminate BB by rewriting all the predecessors to branch to the
/// successor block and return true. If we can't transform, return false.
bool TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
DeferredDominance *DDT = nullptr);
DomTreeUpdater *DTU = nullptr);
/// Check for and eliminate duplicate PHI nodes in this block. This doesn't try
/// to be clever about PHI nodes which differ only in the order of the incoming
@ -359,7 +359,7 @@ unsigned removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB);
/// instruction, making it and the rest of the code in the block dead.
unsigned changeToUnreachable(Instruction *I, bool UseLLVMTrap,
bool PreserveLCSSA = false,
DeferredDominance *DDT = nullptr);
DomTreeUpdater *DTU = nullptr);
/// Convert the CallInst to InvokeInst with the specified unwind edge basic
/// block. This also splits the basic block where CI is located, because
@ -374,13 +374,13 @@ BasicBlock *changeToInvokeAndSplitBasicBlock(CallInst *CI,
///
/// \param BB Block whose terminator will be replaced. Its terminator must
/// have an unwind successor.
void removeUnwindEdge(BasicBlock *BB, DeferredDominance *DDT = nullptr);
void removeUnwindEdge(BasicBlock *BB, DomTreeUpdater *DTU = nullptr);
/// Remove all blocks that can not be reached from the function's entry.
///
/// Returns true if any basic block was removed.
bool removeUnreachableBlocks(Function &F, LazyValueInfo *LVI = nullptr,
DeferredDominance *DDT = nullptr);
DomTreeUpdater *DTU = nullptr);
/// Combine the metadata of two instructions so that K can replace J
///

View File

@ -30,9 +30,10 @@
#include "llvm/IR/CFG.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/DomTreeUpdater.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
@ -614,8 +615,8 @@ void AggressiveDeadCodeElimination::updateDeadRegions() {
}
}
DT.applyUpdates(DeletedEdges);
PDT.applyUpdates(DeletedEdges);
DomTreeUpdater(DT, PDT, DomTreeUpdater::UpdateStrategy::Eager)
.applyUpdates(DeletedEdges);
NumBranchesRemoved += 1;
}

View File

@ -19,7 +19,6 @@
#include "llvm/Analysis/GlobalsModRef.h"
#include "llvm/Analysis/InstructionSimplify.h"
#include "llvm/Analysis/LazyValueInfo.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
@ -28,6 +27,7 @@
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/DomTreeUpdater.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/InstrTypes.h"
@ -44,6 +44,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/Local.h"
#include <cassert>
#include <utility>
@ -308,6 +309,7 @@ static bool processCmp(CmpInst *C, LazyValueInfo *LVI) {
/// a case fires on every incoming edge then the entire switch can be removed
/// and replaced with a branch to the case destination.
static bool processSwitch(SwitchInst *SI, LazyValueInfo *LVI, DominatorTree *DT) {
DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Lazy);
Value *Cond = SI->getCondition();
BasicBlock *BB = SI->getParent();
@ -372,7 +374,7 @@ static bool processSwitch(SwitchInst *SI, LazyValueInfo *LVI, DominatorTree *DT)
++NumDeadCases;
Changed = true;
if (--SuccessorsCount[Succ] == 0)
DT->deleteEdge(BB, Succ);
DTU.deleteEdge(BB, Succ);
continue;
}
if (State == LazyValueInfo::True) {
@ -389,15 +391,11 @@ static bool processSwitch(SwitchInst *SI, LazyValueInfo *LVI, DominatorTree *DT)
++CI;
}
if (Changed) {
if (Changed)
// If the switch has been simplified to the point where it can be replaced
// by a branch then do so now.
DeferredDominance DDT(*DT);
ConstantFoldTerminator(BB, /*DeleteDeadConditions = */ false,
/*TLI = */ nullptr, &DDT);
DDT.flush();
}
/*TLI = */ nullptr, &DTU);
return Changed;
}

View File

@ -38,7 +38,6 @@
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/PHITransAddr.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/IR/Attributes.h"
@ -48,6 +47,7 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/DomTreeUpdater.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstrTypes.h"
@ -71,6 +71,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/SSAUpdater.h"
#include "llvm/Transforms/Utils/VNCoercion.h"
#include <algorithm>
@ -2028,12 +2029,13 @@ bool GVN::runImpl(Function &F, AssumptionCache &RunAC, DominatorTree &RunDT,
bool Changed = false;
bool ShouldContinue = true;
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
// Merge unconditional branches, allowing PRE to catch more
// optimization opportunities.
for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ) {
BasicBlock *BB = &*FI++;
bool removedBlock = MergeBlockIntoPredecessor(BB, DT, LI, MD);
bool removedBlock = MergeBlockIntoPredecessor(BB, &DTU, LI, MD);
if (removedBlock)
++NumGVNBlocks;

View File

@ -30,7 +30,6 @@
#include "llvm/Analysis/Loads.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
@ -38,6 +37,7 @@
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DomTreeUpdater.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstrTypes.h"
@ -65,6 +65,7 @@
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Cloning.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/SSAUpdater.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
#include <algorithm>
@ -285,7 +286,7 @@ bool JumpThreading::runOnFunction(Function &F) {
auto DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
auto LVI = &getAnalysis<LazyValueInfoWrapperPass>().getLVI();
auto AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
DeferredDominance DDT(*DT);
DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Lazy);
std::unique_ptr<BlockFrequencyInfo> BFI;
std::unique_ptr<BranchProbabilityInfo> BPI;
bool HasProfileData = F.hasProfileData();
@ -295,7 +296,7 @@ bool JumpThreading::runOnFunction(Function &F) {
BFI.reset(new BlockFrequencyInfo(F, *BPI, LI));
}
bool Changed = Impl.runImpl(F, TLI, LVI, AA, &DDT, HasProfileData,
bool Changed = Impl.runImpl(F, TLI, LVI, AA, &DTU, HasProfileData,
std::move(BFI), std::move(BPI));
if (PrintLVIAfterJumpThreading) {
dbgs() << "LVI for function '" << F.getName() << "':\n";
@ -312,7 +313,7 @@ PreservedAnalyses JumpThreadingPass::run(Function &F,
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
auto &LVI = AM.getResult<LazyValueAnalysis>(F);
auto &AA = AM.getResult<AAManager>(F);
DeferredDominance DDT(DT);
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
std::unique_ptr<BlockFrequencyInfo> BFI;
std::unique_ptr<BranchProbabilityInfo> BPI;
@ -322,7 +323,7 @@ PreservedAnalyses JumpThreadingPass::run(Function &F,
BFI.reset(new BlockFrequencyInfo(F, *BPI, LI));
}
bool Changed = runImpl(F, &TLI, &LVI, &AA, &DDT, HasProfileData,
bool Changed = runImpl(F, &TLI, &LVI, &AA, &DTU, HasProfileData,
std::move(BFI), std::move(BPI));
if (!Changed)
@ -336,14 +337,14 @@ PreservedAnalyses JumpThreadingPass::run(Function &F,
bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_,
LazyValueInfo *LVI_, AliasAnalysis *AA_,
DeferredDominance *DDT_, bool HasProfileData_,
DomTreeUpdater *DTU_, bool HasProfileData_,
std::unique_ptr<BlockFrequencyInfo> BFI_,
std::unique_ptr<BranchProbabilityInfo> BPI_) {
LLVM_DEBUG(dbgs() << "Jump threading on function '" << F.getName() << "'\n");
TLI = TLI_;
LVI = LVI_;
AA = AA_;
DDT = DDT_;
DTU = DTU_;
BFI.reset();
BPI.reset();
// When profile data is available, we need to update edge weights after
@ -360,7 +361,9 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_,
// JumpThreading must not processes blocks unreachable from entry. It's a
// waste of compute time and can potentially lead to hangs.
SmallPtrSet<BasicBlock *, 16> Unreachable;
DominatorTree &DT = DDT->flush();
assert(DTU && "DTU isn't passed into JumpThreading before using it.");
assert(DTU->hasDomTree() && "JumpThreading relies on DomTree to proceed.");
DominatorTree &DT = DTU->getDomTree();
for (auto &BB : F)
if (!DT.isReachableFromEntry(&BB))
Unreachable.insert(&BB);
@ -379,7 +382,7 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_,
// Stop processing BB if it's the entry or is now deleted. The following
// routines attempt to eliminate BB and locating a suitable replacement
// for the entry is non-trivial.
if (&BB == &F.getEntryBlock() || DDT->pendingDeletedBB(&BB))
if (&BB == &F.getEntryBlock() || DTU->isBBPendingDeletion(&BB))
continue;
if (pred_empty(&BB)) {
@ -390,7 +393,7 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_,
<< '\n');
LoopHeaders.erase(&BB);
LVI->eraseBlock(&BB);
DeleteDeadBlock(&BB, DDT);
DeleteDeadBlock(&BB, DTU);
Changed = true;
continue;
}
@ -404,9 +407,9 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_,
// Don't alter Loop headers and latches to ensure another pass can
// detect and transform nested loops later.
!LoopHeaders.count(&BB) && !LoopHeaders.count(BI->getSuccessor(0)) &&
TryToSimplifyUncondBranchFromEmptyBlock(&BB, DDT)) {
// BB is valid for cleanup here because we passed in DDT. F remains
// BB's parent until a DDT->flush() event.
TryToSimplifyUncondBranchFromEmptyBlock(&BB, DTU)) {
// BB is valid for cleanup here because we passed in DTU. F remains
// BB's parent until a DTU->getDomTree() event.
LVI->eraseBlock(&BB);
Changed = true;
}
@ -415,7 +418,8 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_,
} while (Changed);
LoopHeaders.clear();
DDT->flush();
// Flush only the Dominator Tree.
DTU->getDomTree();
LVI->enableDT();
return EverChanged;
}
@ -609,7 +613,7 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors(
// "X < 4" and "X < 3" is known true but "X < 4" itself is not available.
// Perhaps getConstantOnEdge should be smart enough to do this?
if (DDT->pending())
if (DTU->hasPendingDomTreeUpdates())
LVI->disableDT();
else
LVI->enableDT();
@ -626,7 +630,7 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors(
/// If I is a PHI node, then we know the incoming values for any constants.
if (PHINode *PN = dyn_cast<PHINode>(I)) {
if (DDT->pending())
if (DTU->hasPendingDomTreeUpdates())
LVI->disableDT();
else
LVI->enableDT();
@ -759,7 +763,7 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors(
const DataLayout &DL = PN->getModule()->getDataLayout();
// We can do this simplification if any comparisons fold to true or false.
// See if any do.
if (DDT->pending())
if (DTU->hasPendingDomTreeUpdates())
LVI->disableDT();
else
LVI->enableDT();
@ -806,7 +810,7 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors(
if (!isa<Instruction>(CmpLHS) ||
cast<Instruction>(CmpLHS)->getParent() != BB) {
if (DDT->pending())
if (DTU->hasPendingDomTreeUpdates())
LVI->disableDT();
else
LVI->enableDT();
@ -838,7 +842,7 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors(
match(CmpLHS, m_Add(m_Value(AddLHS), m_ConstantInt(AddConst)))) {
if (!isa<Instruction>(AddLHS) ||
cast<Instruction>(AddLHS)->getParent() != BB) {
if (DDT->pending())
if (DTU->hasPendingDomTreeUpdates())
LVI->disableDT();
else
LVI->enableDT();
@ -923,7 +927,7 @@ bool JumpThreadingPass::ComputeValueKnownInPredecessors(
}
// If all else fails, see if LVI can figure out a constant value for us.
if (DDT->pending())
if (DTU->hasPendingDomTreeUpdates())
LVI->disableDT();
else
LVI->enableDT();
@ -974,7 +978,7 @@ static bool hasAddressTakenAndUsed(BasicBlock *BB) {
bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) {
// If the block is trivially dead, just return and let the caller nuke it.
// This simplifies other transformations.
if (DDT->pendingDeletedBB(BB) ||
if (DTU->isBBPendingDeletion(BB) ||
(pred_empty(BB) && BB != &BB->getParent()->getEntryBlock()))
return false;
@ -991,7 +995,7 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) {
LoopHeaders.insert(BB);
LVI->eraseBlock(SinglePred);
MergeBasicBlockIntoOnlyPred(BB, nullptr, DDT);
MergeBasicBlockIntoOnlyPred(BB, DTU);
// Now that BB is merged into SinglePred (i.e. SinglePred Code followed by
// BB code within one basic block `BB`), we need to invalidate the LVI
@ -1088,7 +1092,7 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) {
<< "' folding undef terminator: " << *BBTerm << '\n');
BranchInst::Create(BBTerm->getSuccessor(BestSucc), BBTerm);
BBTerm->eraseFromParent();
DDT->applyUpdates(Updates);
DTU->applyUpdates(Updates);
return true;
}
@ -1100,7 +1104,7 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) {
<< "' folding terminator: " << *BB->getTerminator()
<< '\n');
++NumFolds;
ConstantFoldTerminator(BB, true, nullptr, DDT);
ConstantFoldTerminator(BB, true, nullptr, DTU);
return true;
}
@ -1127,7 +1131,7 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) {
// threading is concerned.
assert(CondBr->isConditional() && "Threading on unconditional terminator");
if (DDT->pending())
if (DTU->hasPendingDomTreeUpdates())
LVI->disableDT();
else
LVI->enableDT();
@ -1156,7 +1160,7 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) {
ConstantInt::getFalse(CondCmp->getType());
ReplaceFoldableUses(CondCmp, CI);
}
DDT->deleteEdge(BB, ToRemoveSucc);
DTU->deleteEdgeRelaxed(BB, ToRemoveSucc);
return true;
}
@ -1240,7 +1244,7 @@ bool JumpThreadingPass::ProcessImpliedCondition(BasicBlock *BB) {
RemoveSucc->removePredecessor(BB);
BranchInst::Create(KeepSucc, BI);
BI->eraseFromParent();
DDT->deleteEdge(BB, RemoveSucc);
DTU->deleteEdgeRelaxed(BB, RemoveSucc);
return true;
}
CurrentBB = CurrentPred;
@ -1667,7 +1671,7 @@ bool JumpThreadingPass::ProcessThreadableEdges(Value *Cond, BasicBlock *BB,
TerminatorInst *Term = BB->getTerminator();
BranchInst::Create(OnlyDest, Term);
Term->eraseFromParent();
DDT->applyUpdates(Updates);
DTU->applyUpdates(Updates);
// If the condition is now dead due to the removal of the old terminator,
// erase it.
@ -1945,7 +1949,7 @@ bool JumpThreadingPass::ThreadEdge(BasicBlock *BB,
<< "' with cost: " << JumpThreadCost
<< ", across block:\n " << *BB << "\n");
if (DDT->pending())
if (DTU->hasPendingDomTreeUpdates())
LVI->disableDT();
else
LVI->enableDT();
@ -2009,7 +2013,7 @@ bool JumpThreadingPass::ThreadEdge(BasicBlock *BB,
}
// Enqueue required DT updates.
DDT->applyUpdates({{DominatorTree::Insert, NewBB, SuccBB},
DTU->applyUpdates({{DominatorTree::Insert, NewBB, SuccBB},
{DominatorTree::Insert, PredBB, NewBB},
{DominatorTree::Delete, PredBB, BB}});
@ -2105,7 +2109,7 @@ BasicBlock *JumpThreadingPass::SplitBlockPreds(BasicBlock *BB,
BFI->setBlockFreq(NewBB, NewBBFreq.getFrequency());
}
DDT->applyUpdates(Updates);
DTU->applyUpdates(Updates);
return NewBBs[0];
}
@ -2378,7 +2382,7 @@ bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred(
// Remove the unconditional branch at the end of the PredBB block.
OldPredBranch->eraseFromParent();
DDT->applyUpdates(Updates);
DTU->applyUpdates(Updates);
++NumDupes;
return true;
@ -2421,7 +2425,7 @@ bool JumpThreadingPass::TryToUnfoldSelect(CmpInst *CondCmp, BasicBlock *BB) {
// Now check if one of the select values would allow us to constant fold the
// terminator in BB. We don't do the transform if both sides fold, those
// cases will be threaded in any case.
if (DDT->pending())
if (DTU->hasPendingDomTreeUpdates())
LVI->disableDT();
else
LVI->enableDT();
@ -2455,7 +2459,7 @@ bool JumpThreadingPass::TryToUnfoldSelect(CmpInst *CondCmp, BasicBlock *BB) {
// The select is now dead.
SI->eraseFromParent();
DDT->applyUpdates({{DominatorTree::Insert, NewBB, BB},
DTU->applyUpdates({{DominatorTree::Insert, NewBB, BB},
{DominatorTree::Insert, Pred, NewBB}});
// Update any other PHI nodes in BB.
for (BasicBlock::iterator BI = BB->begin();
@ -2548,12 +2552,12 @@ bool JumpThreadingPass::TryToUnfoldSelectInCurrBB(BasicBlock *BB) {
Updates.push_back({DominatorTree::Insert, BB, SplitBB});
Updates.push_back({DominatorTree::Insert, BB, NewBB});
Updates.push_back({DominatorTree::Insert, NewBB, SplitBB});
// BB's successors were moved to SplitBB, update DDT accordingly.
// BB's successors were moved to SplitBB, update DTU accordingly.
for (auto *Succ : successors(SplitBB)) {
Updates.push_back({DominatorTree::Delete, BB, Succ});
Updates.push_back({DominatorTree::Insert, SplitBB, Succ});
}
DDT->applyUpdates(Updates);
DTU->applyUpdates(Updates);
return true;
}
return false;
@ -2664,7 +2668,7 @@ bool JumpThreadingPass::ThreadGuard(BasicBlock *BB, IntrinsicInst *Guard,
// DuplicateInstructionsInSplitBetween inserts a new block "BB.split" between
// PredBB and BB. We need to perform two inserts and one delete for each of
// the above calls to update Dominators.
DDT->applyUpdates(
DTU->applyUpdates(
{// Guarded block split.
{DominatorTree::Delete, PredGuardedBlock, BB},
{DominatorTree::Insert, PredGuardedBlock, GuardedBlock},

View File

@ -27,6 +27,7 @@
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/IR/DomTreeUpdater.h"
#include "llvm/IR/Dominators.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Scalar/LoopPassManager.h"
@ -41,6 +42,7 @@ using namespace llvm;
static bool simplifyLoopCFG(Loop &L, DominatorTree &DT, LoopInfo &LI,
ScalarEvolution &SE) {
bool Changed = false;
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
// Copy blocks into a temporary array to avoid iterator invalidation issues
// as we remove them.
SmallVector<WeakTrackingVH, 16> Blocks(L.blocks());
@ -57,7 +59,7 @@ static bool simplifyLoopCFG(Loop &L, DominatorTree &DT, LoopInfo &LI,
continue;
// Merge Succ into Pred and delete it.
MergeBlockIntoPredecessor(Succ, &DT, &LI);
MergeBlockIntoPredecessor(Succ, &DTU, &LI);
SE.forgetLoop(&L);
Changed = true;

View File

@ -28,7 +28,6 @@
#include "llvm/ADT/iterator_range.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/IR/Argument.h"
#include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h"
@ -38,6 +37,7 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/DomTreeUpdater.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IRBuilder.h"
@ -65,6 +65,7 @@
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/PromoteMemToReg.h"
#include <algorithm>
#include <cassert>
@ -2534,9 +2535,10 @@ bool RewriteStatepointsForGC::runOnFunction(Function &F, DominatorTree &DT,
// Delete any unreachable statepoints so that we don't have unrewritten
// statepoints surviving this pass. This makes testing easier and the
// resulting IR less confusing to human readers.
DeferredDominance DD(DT);
bool MadeChange = removeUnreachableBlocks(F, nullptr, &DD);
DD.flush();
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Lazy);
bool MadeChange = removeUnreachableBlocks(F, nullptr, &DTU);
// Flush the Dominator Tree.
DTU.getDomTree();
// Gather all the statepoints which need rewritten. Be careful to only
// consider those in reachable code since we need to ask dominance queries

View File

@ -20,11 +20,12 @@
#include "llvm/Analysis/CFG.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/MemoryDependenceAnalysis.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DomTreeUpdater.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstrTypes.h"
@ -37,6 +38,7 @@
#include "llvm/IR/Value.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Casting.h"
#include "llvm/Transforms/Utils/Local.h"
#include <cassert>
#include <cstdint>
#include <string>
@ -45,7 +47,7 @@
using namespace llvm;
void llvm::DeleteDeadBlock(BasicBlock *BB, DeferredDominance *DDT) {
void llvm::DeleteDeadBlock(BasicBlock *BB, DomTreeUpdater *DTU) {
assert((pred_begin(BB) == pred_end(BB) ||
// Can delete self loop.
BB->getSinglePredecessor() == BB) && "Block is not dead!");
@ -54,11 +56,11 @@ void llvm::DeleteDeadBlock(BasicBlock *BB, DeferredDominance *DDT) {
// Loop through all of our successors and make sure they know that one
// of their predecessors is going away.
if (DDT)
if (DTU)
Updates.reserve(BBTerm->getNumSuccessors());
for (BasicBlock *Succ : BBTerm->successors()) {
Succ->removePredecessor(BB);
if (DDT)
if (DTU)
Updates.push_back({DominatorTree::Delete, BB, Succ});
}
@ -74,10 +76,15 @@ void llvm::DeleteDeadBlock(BasicBlock *BB, DeferredDominance *DDT) {
I.replaceAllUsesWith(UndefValue::get(I.getType()));
BB->getInstList().pop_back();
}
new UnreachableInst(BB->getContext(), BB);
assert(BB->getInstList().size() == 1 &&
isa<UnreachableInst>(BB->getTerminator()) &&
"The successor list of BB isn't empty before "
"applying corresponding DTU updates.");
if (DDT) {
DDT->applyUpdates(Updates);
DDT->deleteBB(BB); // Deferred deletion of BB.
if (DTU) {
DTU->applyUpdates(Updates, /*ForceRemoveDuplicates*/ true);
DTU->deleteBB(BB);
} else {
BB->eraseFromParent(); // Zap the block!
}
@ -115,11 +122,9 @@ bool llvm::DeleteDeadPHIs(BasicBlock *BB, const TargetLibraryInfo *TLI) {
return Changed;
}
bool llvm::MergeBlockIntoPredecessor(BasicBlock *BB, DominatorTree *DT,
bool llvm::MergeBlockIntoPredecessor(BasicBlock *BB, DomTreeUpdater *DTU,
LoopInfo *LI,
MemoryDependenceResults *MemDep,
DeferredDominance *DDT) {
assert(!(DT && DDT) && "Cannot call with both DT and DDT.");
MemoryDependenceResults *MemDep) {
if (BB->hasAddressTaken())
return false;
@ -154,10 +159,10 @@ bool llvm::MergeBlockIntoPredecessor(BasicBlock *BB, DominatorTree *DT,
FoldSingleEntryPHINodes(BB, MemDep);
}
// Deferred DT update: Collect all the edges that exit BB. These
// dominator edges will be redirected from Pred.
// DTU update: Collect all the edges that exit BB.
// These dominator edges will be redirected from Pred.
std::vector<DominatorTree::UpdateType> Updates;
if (DDT) {
if (DTU) {
Updates.reserve(1 + (2 * succ_size(BB)));
Updates.push_back({DominatorTree::Delete, PredBB, BB});
for (auto I = succ_begin(BB), E = succ_end(BB); I != E; ++I) {
@ -175,6 +180,7 @@ bool llvm::MergeBlockIntoPredecessor(BasicBlock *BB, DominatorTree *DT,
// Move all definitions in the successor to the predecessor...
PredBB->getInstList().splice(PredBB->end(), BB->getInstList());
new UnreachableInst(BB->getContext(), BB);
// Eliminate duplicate dbg.values describing the entry PHI node post-splice.
for (auto Incoming : IncomingValues) {
@ -195,28 +201,24 @@ bool llvm::MergeBlockIntoPredecessor(BasicBlock *BB, DominatorTree *DT,
if (!PredBB->hasName())
PredBB->takeName(BB);
// Finally, erase the old block and update dominator info.
if (DT)
if (DomTreeNode *DTN = DT->getNode(BB)) {
DomTreeNode *PredDTN = DT->getNode(PredBB);
SmallVector<DomTreeNode *, 8> Children(DTN->begin(), DTN->end());
for (DomTreeNode *DI : Children)
DT->changeImmediateDominator(DI, PredDTN);
DT->eraseNode(BB);
}
if (LI)
LI->removeBlock(BB);
if (MemDep)
MemDep->invalidateCachedPredecessors();
if (DDT) {
DDT->deleteBB(BB); // Deferred deletion of BB.
DDT->applyUpdates(Updates);
} else {
BB->eraseFromParent(); // Nuke BB.
// Finally, erase the old block and update dominator info.
if (DTU) {
assert(BB->getInstList().size() == 1 &&
isa<UnreachableInst>(BB->getTerminator()) &&
"The successor list of BB isn't empty before "
"applying corresponding DTU updates.");
DTU->applyUpdates(Updates, /*ForceRemoveDuplicates*/ true);
DTU->deleteBB(BB);
}
else {
BB->eraseFromParent(); // Nuke BB if DTU is nullptr.
}
return true;
}

View File

@ -47,6 +47,7 @@
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DebugLoc.h"
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/DomTreeUpdater.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GetElementPtrTypeIterator.h"
@ -102,7 +103,7 @@ STATISTIC(NumRemoved, "Number of unreachable basic blocks removed");
/// DeleteDeadConditions is true.
bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
const TargetLibraryInfo *TLI,
DeferredDominance *DDT) {
DomTreeUpdater *DTU) {
TerminatorInst *T = BB->getTerminator();
IRBuilder<> Builder(T);
@ -125,8 +126,8 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
// Replace the conditional branch with an unconditional one.
Builder.CreateBr(Destination);
BI->eraseFromParent();
if (DDT)
DDT->deleteEdge(BB, OldDest);
if (DTU)
DTU->deleteEdgeRelaxed(BB, OldDest);
return true;
}
@ -201,8 +202,8 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
DefaultDest->removePredecessor(ParentBB);
i = SI->removeCase(i);
e = SI->case_end();
if (DDT)
DDT->deleteEdge(ParentBB, DefaultDest);
if (DTU)
DTU->deleteEdgeRelaxed(ParentBB, DefaultDest);
continue;
}
@ -229,7 +230,7 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
Builder.CreateBr(TheOnlyDest);
BasicBlock *BB = SI->getParent();
std::vector <DominatorTree::UpdateType> Updates;
if (DDT)
if (DTU)
Updates.reserve(SI->getNumSuccessors() - 1);
// Remove entries from PHI nodes which we no longer branch to...
@ -239,7 +240,7 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
TheOnlyDest = nullptr; // Don't modify the first branch to TheOnlyDest
} else {
Succ->removePredecessor(BB);
if (DDT)
if (DTU)
Updates.push_back({DominatorTree::Delete, BB, Succ});
}
}
@ -249,8 +250,8 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
SI->eraseFromParent();
if (DeleteDeadConditions)
RecursivelyDeleteTriviallyDeadInstructions(Cond, TLI);
if (DDT)
DDT->applyUpdates(Updates);
if (DTU)
DTU->applyUpdates(Updates, /*ForceRemoveDuplicates*/ true);
return true;
}
@ -297,7 +298,7 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
dyn_cast<BlockAddress>(IBI->getAddress()->stripPointerCasts())) {
BasicBlock *TheOnlyDest = BA->getBasicBlock();
std::vector <DominatorTree::UpdateType> Updates;
if (DDT)
if (DTU)
Updates.reserve(IBI->getNumDestinations() - 1);
// Insert the new branch.
@ -310,7 +311,7 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
BasicBlock *ParentBB = IBI->getParent();
BasicBlock *DestBB = IBI->getDestination(i);
DestBB->removePredecessor(ParentBB);
if (DDT)
if (DTU)
Updates.push_back({DominatorTree::Delete, ParentBB, DestBB});
}
}
@ -327,8 +328,8 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
new UnreachableInst(BB->getContext(), BB);
}
if (DDT)
DDT->applyUpdates(Updates);
if (DTU)
DTU->applyUpdates(Updates, /*ForceRemoveDuplicates*/ true);
return true;
}
}
@ -626,7 +627,7 @@ bool llvm::SimplifyInstructionsInBlock(BasicBlock *BB,
/// .. and delete the predecessor corresponding to the '1', this will attempt to
/// recursively fold the and to 0.
void llvm::RemovePredecessorAndSimplify(BasicBlock *BB, BasicBlock *Pred,
DeferredDominance *DDT) {
DomTreeUpdater *DTU) {
// This only adjusts blocks with PHI nodes.
if (!isa<PHINode>(BB->begin()))
return;
@ -649,17 +650,16 @@ void llvm::RemovePredecessorAndSimplify(BasicBlock *BB, BasicBlock *Pred,
// of the block.
if (PhiIt != OldPhiIt) PhiIt = &BB->front();
}
if (DDT)
DDT->deleteEdge(Pred, BB);
if (DTU)
DTU->deleteEdgeRelaxed(Pred, BB);
}
/// MergeBasicBlockIntoOnlyPred - DestBB is a block with one predecessor and its
/// predecessor is known to have one successor (DestBB!). Eliminate the edge
/// between them, moving the instructions in the predecessor into DestBB and
/// deleting the predecessor block.
void llvm::MergeBasicBlockIntoOnlyPred(BasicBlock *DestBB, DominatorTree *DT,
DeferredDominance *DDT) {
assert(!(DT && DDT) && "Cannot call with both DT and DDT.");
void llvm::MergeBasicBlockIntoOnlyPred(BasicBlock *DestBB,
DomTreeUpdater *DTU) {
// If BB has single-entry PHI nodes, fold them.
while (PHINode *PN = dyn_cast<PHINode>(DestBB->begin())) {
@ -677,10 +677,11 @@ void llvm::MergeBasicBlockIntoOnlyPred(BasicBlock *DestBB, DominatorTree *DT,
if (PredBB == &DestBB->getParent()->getEntryBlock())
ReplaceEntryBB = true;
// Deferred DT update: Collect all the edges that enter PredBB. These
// dominator edges will be redirected to DestBB.
// DTU updates: Collect all the edges that enter
// PredBB. These dominator edges will be redirected to DestBB.
std::vector <DominatorTree::UpdateType> Updates;
if (DDT && !ReplaceEntryBB) {
if (DTU) {
Updates.reserve(1 + (2 * pred_size(PredBB)));
Updates.push_back({DominatorTree::Delete, PredBB, DestBB});
for (auto I = pred_begin(PredBB), E = pred_end(PredBB); I != E; ++I) {
@ -708,33 +709,32 @@ void llvm::MergeBasicBlockIntoOnlyPred(BasicBlock *DestBB, DominatorTree *DT,
// Splice all the instructions from PredBB to DestBB.
PredBB->getTerminator()->eraseFromParent();
DestBB->getInstList().splice(DestBB->begin(), PredBB->getInstList());
new UnreachableInst(PredBB->getContext(), PredBB);
// If the PredBB is the entry block of the function, move DestBB up to
// become the entry block after we erase PredBB.
if (ReplaceEntryBB)
DestBB->moveAfter(PredBB);
if (DT) {
// For some irreducible CFG we end up having forward-unreachable blocks
// so check if getNode returns a valid node before updating the domtree.
if (DomTreeNode *DTN = DT->getNode(PredBB)) {
BasicBlock *PredBBIDom = DTN->getIDom()->getBlock();
DT->changeImmediateDominator(DestBB, PredBBIDom);
DT->eraseNode(PredBB);
if (DTU) {
assert(PredBB->getInstList().size() == 1 &&
isa<UnreachableInst>(PredBB->getTerminator()) &&
"The successor list of PredBB isn't empty before "
"applying corresponding DTU updates.");
DTU->applyUpdates(Updates, /*ForceRemoveDuplicates*/ true);
DTU->deleteBB(PredBB);
// Recalculation of DomTree is needed when updating a forward DomTree and
// the Entry BB is replaced.
if (ReplaceEntryBB && DTU->hasDomTree()) {
// The entry block was removed and there is no external interface for
// the dominator tree to be notified of this change. In this corner-case
// we recalculate the entire tree.
DTU->recalculate(*(DestBB->getParent()));
}
}
if (DDT) {
DDT->deleteBB(PredBB); // Deferred deletion of BB.
if (ReplaceEntryBB)
// The entry block was removed and there is no external interface for the
// dominator tree to be notified of this change. In this corner-case we
// recalculate the entire tree.
DDT->recalculate(*(DestBB->getParent()));
else
DDT->applyUpdates(Updates);
} else {
PredBB->eraseFromParent(); // Nuke BB.
else {
PredBB->eraseFromParent(); // Nuke BB if DTU is nullptr.
}
}
@ -945,7 +945,7 @@ static void redirectValuesFromPredecessorsToPhi(BasicBlock *BB,
/// eliminate BB by rewriting all the predecessors to branch to the successor
/// block and return true. If we can't transform, return false.
bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
DeferredDominance *DDT) {
DomTreeUpdater *DTU) {
assert(BB != &BB->getParent()->getEntryBlock() &&
"TryToSimplifyUncondBranchFromEmptyBlock called on entry block!");
@ -987,7 +987,7 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
LLVM_DEBUG(dbgs() << "Killing Trivial BB: \n" << *BB);
std::vector<DominatorTree::UpdateType> Updates;
if (DDT) {
if (DTU) {
Updates.reserve(1 + (2 * pred_size(BB)));
Updates.push_back({DominatorTree::Delete, BB, Succ});
// All predecessors of BB will be moved to Succ.
@ -1044,9 +1044,16 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
BB->replaceAllUsesWith(Succ);
if (!Succ->hasName()) Succ->takeName(BB);
if (DDT) {
DDT->deleteBB(BB); // Deferred deletion of the old basic block.
DDT->applyUpdates(Updates);
// Clear the successor list of BB to match updates applying to DTU later.
if (BB->getTerminator())
BB->getInstList().pop_back();
new UnreachableInst(BB->getContext(), BB);
assert(succ_empty(BB) && "The successor list of BB isn't empty before "
"applying corresponding DTU updates.");
if (DTU) {
DTU->applyUpdates(Updates, /*ForceRemoveDuplicates*/ true);
DTU->deleteBB(BB);
} else {
BB->eraseFromParent(); // Delete the old basic block.
}
@ -1902,17 +1909,17 @@ unsigned llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) {
}
unsigned llvm::changeToUnreachable(Instruction *I, bool UseLLVMTrap,
bool PreserveLCSSA, DeferredDominance *DDT) {
bool PreserveLCSSA, DomTreeUpdater *DTU) {
BasicBlock *BB = I->getParent();
std::vector <DominatorTree::UpdateType> Updates;
// Loop over all of the successors, removing BB's entry from any PHI
// nodes.
if (DDT)
if (DTU)
Updates.reserve(BB->getTerminator()->getNumSuccessors());
for (BasicBlock *Successor : successors(BB)) {
Successor->removePredecessor(BB, PreserveLCSSA);
if (DDT)
if (DTU)
Updates.push_back({DominatorTree::Delete, BB, Successor});
}
// Insert a call to llvm.trap right before this. This turns the undefined
@ -1934,13 +1941,13 @@ unsigned llvm::changeToUnreachable(Instruction *I, bool UseLLVMTrap,
BB->getInstList().erase(BBI++);
++NumInstrsRemoved;
}
if (DDT)
DDT->applyUpdates(Updates);
if (DTU)
DTU->applyUpdates(Updates, /*ForceRemoveDuplicates*/ true);
return NumInstrsRemoved;
}
/// changeToCall - Convert the specified invoke into a normal call.
static void changeToCall(InvokeInst *II, DeferredDominance *DDT = nullptr) {
static void changeToCall(InvokeInst *II, DomTreeUpdater *DTU = nullptr) {
SmallVector<Value*, 8> Args(II->arg_begin(), II->arg_end());
SmallVector<OperandBundleDef, 1> OpBundles;
II->getOperandBundlesAsDefs(OpBundles);
@ -1961,8 +1968,8 @@ static void changeToCall(InvokeInst *II, DeferredDominance *DDT = nullptr) {
BasicBlock *UnwindDestBB = II->getUnwindDest();
UnwindDestBB->removePredecessor(BB);
II->eraseFromParent();
if (DDT)
DDT->deleteEdge(BB, UnwindDestBB);
if (DTU)
DTU->deleteEdgeRelaxed(BB, UnwindDestBB);
}
BasicBlock *llvm::changeToInvokeAndSplitBasicBlock(CallInst *CI,
@ -2003,8 +2010,8 @@ BasicBlock *llvm::changeToInvokeAndSplitBasicBlock(CallInst *CI,
}
static bool markAliveBlocks(Function &F,
SmallPtrSetImpl<BasicBlock*> &Reachable,
DeferredDominance *DDT = nullptr) {
SmallPtrSetImpl<BasicBlock *> &Reachable,
DomTreeUpdater *DTU = nullptr) {
SmallVector<BasicBlock*, 128> Worklist;
BasicBlock *BB = &F.front();
Worklist.push_back(BB);
@ -2029,7 +2036,7 @@ static bool markAliveBlocks(Function &F,
if (IntrinsicID == Intrinsic::assume) {
if (match(CI->getArgOperand(0), m_CombineOr(m_Zero(), m_Undef()))) {
// Don't insert a call to llvm.trap right before the unreachable.
changeToUnreachable(CI, false, false, DDT);
changeToUnreachable(CI, false, false, DTU);
Changed = true;
break;
}
@ -2046,7 +2053,7 @@ static bool markAliveBlocks(Function &F,
if (match(CI->getArgOperand(0), m_Zero()))
if (!isa<UnreachableInst>(CI->getNextNode())) {
changeToUnreachable(CI->getNextNode(), /*UseLLVMTrap=*/false,
false, DDT);
false, DTU);
Changed = true;
break;
}
@ -2054,7 +2061,7 @@ static bool markAliveBlocks(Function &F,
} else if ((isa<ConstantPointerNull>(Callee) &&
!NullPointerIsDefined(CI->getFunction())) ||
isa<UndefValue>(Callee)) {
changeToUnreachable(CI, /*UseLLVMTrap=*/false, false, DDT);
changeToUnreachable(CI, /*UseLLVMTrap=*/false, false, DTU);
Changed = true;
break;
}
@ -2064,7 +2071,7 @@ static bool markAliveBlocks(Function &F,
// though.
if (!isa<UnreachableInst>(CI->getNextNode())) {
// Don't insert a call to llvm.trap right before the unreachable.
changeToUnreachable(CI->getNextNode(), false, false, DDT);
changeToUnreachable(CI->getNextNode(), false, false, DTU);
Changed = true;
}
break;
@ -2083,7 +2090,7 @@ static bool markAliveBlocks(Function &F,
(isa<ConstantPointerNull>(Ptr) &&
!NullPointerIsDefined(SI->getFunction(),
SI->getPointerAddressSpace()))) {
changeToUnreachable(SI, true, false, DDT);
changeToUnreachable(SI, true, false, DTU);
Changed = true;
break;
}
@ -2097,7 +2104,7 @@ static bool markAliveBlocks(Function &F,
if ((isa<ConstantPointerNull>(Callee) &&
!NullPointerIsDefined(BB->getParent())) ||
isa<UndefValue>(Callee)) {
changeToUnreachable(II, true, false, DDT);
changeToUnreachable(II, true, false, DTU);
Changed = true;
} else if (II->doesNotThrow() && canSimplifyInvokeNoUnwind(&F)) {
if (II->use_empty() && II->onlyReadsMemory()) {
@ -2107,10 +2114,10 @@ static bool markAliveBlocks(Function &F,
BranchInst::Create(NormalDestBB, II);
UnwindDestBB->removePredecessor(II->getParent());
II->eraseFromParent();
if (DDT)
DDT->deleteEdge(BB, UnwindDestBB);
if (DTU)
DTU->deleteEdgeRelaxed(BB, UnwindDestBB);
} else
changeToCall(II, DDT);
changeToCall(II, DTU);
Changed = true;
}
} else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Terminator)) {
@ -2156,7 +2163,7 @@ static bool markAliveBlocks(Function &F,
}
}
Changed |= ConstantFoldTerminator(BB, true, nullptr, DDT);
Changed |= ConstantFoldTerminator(BB, true, nullptr, DTU);
for (BasicBlock *Successor : successors(BB))
if (Reachable.insert(Successor).second)
Worklist.push_back(Successor);
@ -2164,11 +2171,11 @@ static bool markAliveBlocks(Function &F,
return Changed;
}
void llvm::removeUnwindEdge(BasicBlock *BB, DeferredDominance *DDT) {
void llvm::removeUnwindEdge(BasicBlock *BB, DomTreeUpdater *DTU) {
TerminatorInst *TI = BB->getTerminator();
if (auto *II = dyn_cast<InvokeInst>(TI)) {
changeToCall(II, DDT);
changeToCall(II, DTU);
return;
}
@ -2196,8 +2203,8 @@ void llvm::removeUnwindEdge(BasicBlock *BB, DeferredDominance *DDT) {
UnwindDest->removePredecessor(BB);
TI->replaceAllUsesWith(NewTI);
TI->eraseFromParent();
if (DDT)
DDT->deleteEdge(BB, UnwindDest);
if (DTU)
DTU->deleteEdgeRelaxed(BB, UnwindDest);
}
/// removeUnreachableBlocks - Remove blocks that are not reachable, even
@ -2205,9 +2212,9 @@ void llvm::removeUnwindEdge(BasicBlock *BB, DeferredDominance *DDT) {
/// otherwise. If `LVI` is passed, this function preserves LazyValueInfo
/// after modifying the CFG.
bool llvm::removeUnreachableBlocks(Function &F, LazyValueInfo *LVI,
DeferredDominance *DDT) {
DomTreeUpdater *DTU) {
SmallPtrSet<BasicBlock*, 16> Reachable;
bool Changed = markAliveBlocks(F, Reachable, DDT);
bool Changed = markAliveBlocks(F, Reachable, DTU);
// If there are unreachable blocks in the CFG...
if (Reachable.size() == F.size())
@ -2217,7 +2224,7 @@ bool llvm::removeUnreachableBlocks(Function &F, LazyValueInfo *LVI,
NumRemoved += F.size()-Reachable.size();
// Loop over all of the basic blocks that are not reachable, dropping all of
// their internal references. Update DDT and LVI if available.
// their internal references. Update DTU and LVI if available.
std::vector <DominatorTree::UpdateType> Updates;
for (Function::iterator I = ++F.begin(), E = F.end(); I != E; ++I) {
auto *BB = &*I;
@ -2226,30 +2233,40 @@ bool llvm::removeUnreachableBlocks(Function &F, LazyValueInfo *LVI,
for (BasicBlock *Successor : successors(BB)) {
if (Reachable.count(Successor))
Successor->removePredecessor(BB);
if (DDT)
if (DTU)
Updates.push_back({DominatorTree::Delete, BB, Successor});
}
if (LVI)
LVI->eraseBlock(BB);
BB->dropAllReferences();
}
SmallVector<BasicBlock *, 8> ToDeleteBBs;
for (Function::iterator I = ++F.begin(); I != F.end();) {
auto *BB = &*I;
if (Reachable.count(BB)) {
++I;
continue;
}
if (DDT) {
DDT->deleteBB(BB); // deferred deletion of BB.
if (DTU) {
ToDeleteBBs.push_back(BB);
// Remove the TerminatorInst of BB to clear the successor list of BB.
if (BB->getTerminator())
BB->getInstList().pop_back();
new UnreachableInst(BB->getContext(), BB);
assert(succ_empty(BB) && "The successor list of BB isn't empty before "
"applying corresponding DTU updates.");
++I;
} else {
I = F.getBasicBlockList().erase(I);
}
}
if (DDT)
DDT->applyUpdates(Updates);
if (DTU) {
DTU->applyUpdates(Updates, /*ForceRemoveDuplicates*/ true);
for (auto *BB : ToDeleteBBs)
DTU->deleteBB(BB);
}
return true;
}

View File

@ -23,10 +23,10 @@
#include "llvm/Analysis/ScalarEvolution.h"
#include "llvm/Analysis/ScalarEvolutionAliasAnalysis.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/CFG.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DomTreeUpdater.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/IntrinsicInst.h"
@ -35,6 +35,7 @@
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Transforms/Utils/LoopUtils.h"
#include "llvm/Transforms/Utils/SSAUpdater.h"
#include "llvm/Transforms/Utils/ValueMapper.h"
@ -476,7 +477,8 @@ bool LoopRotate::rotateLoop(Loop *L, bool SimplifiedLatch) {
// the OrigHeader block into OrigLatch. This will succeed if they are
// connected by an unconditional branch. This is just a cleanup so the
// emitted code isn't too gross in this common case.
MergeBlockIntoPredecessor(OrigHeader, DT, LI);
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
MergeBlockIntoPredecessor(OrigHeader, &DTU, LI);
LLVM_DEBUG(dbgs() << "LoopRotation: into "; L->dump());

View File

@ -26,6 +26,7 @@
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/DomTreeUpdater.h"
#include "llvm/IR/Dominators.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Module.h"
@ -1425,12 +1426,13 @@ void llvm::deleteDeadLoop(Loop *L, DominatorTree *DT = nullptr,
// Remove the old branch.
Preheader->getTerminator()->eraseFromParent();
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
if (DT) {
// Update the dominator tree by informing it about the new edge from the
// preheader to the exit.
DT->insertEdge(Preheader, ExitBlock);
DTU.insertEdge(Preheader, ExitBlock);
// Inform the dominator tree about the removed edge.
DT->deleteEdge(Preheader, L->getHeader());
DTU.deleteEdge(Preheader, L->getHeader());
}
// Given LCSSA form is satisfied, we should not have users of instructions

View File

@ -8,9 +8,11 @@
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/Utils/Local.h"
#include "llvm/Analysis/PostDominators.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/DIBuilder.h"
#include "llvm/IR/DomTreeUpdater.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/IntrinsicInst.h"
@ -176,9 +178,10 @@ static void runWithDomTree(
TEST(Local, MergeBasicBlockIntoOnlyPred) {
LLVMContext C;
std::unique_ptr<Module> M = parseIR(C,
R"(
std::unique_ptr<Module> M;
auto resetIR = [&]() {
M = parseIR(C,
R"(
define i32 @f(i8* %str) {
entry:
br label %bb2.i
@ -195,18 +198,137 @@ TEST(Local, MergeBasicBlockIntoOnlyPred) {
ret i32 0
}
)");
runWithDomTree(
*M, "f", [&](Function &F, DominatorTree *DT) {
for (Function::iterator I = F.begin(), E = F.end(); I != E;) {
BasicBlock *BB = &*I++;
BasicBlock *SinglePred = BB->getSinglePredecessor();
if (!SinglePred || SinglePred == BB || BB->hasAddressTaken()) continue;
BranchInst *Term = dyn_cast<BranchInst>(SinglePred->getTerminator());
if (Term && !Term->isConditional())
MergeBasicBlockIntoOnlyPred(BB, DT);
}
EXPECT_TRUE(DT->verify());
});
};
auto resetIRReplaceEntry = [&]() {
M = parseIR(C,
R"(
define i32 @f() {
entry:
br label %bb2.i
bb2.i: ; preds = %entry
ret i32 0
}
)");
};
auto Test = [&](Function &F, DomTreeUpdater &DTU) {
for (Function::iterator I = F.begin(), E = F.end(); I != E;) {
BasicBlock *BB = &*I++;
BasicBlock *SinglePred = BB->getSinglePredecessor();
if (!SinglePred || SinglePred == BB || BB->hasAddressTaken())
continue;
BranchInst *Term = dyn_cast<BranchInst>(SinglePred->getTerminator());
if (Term && !Term->isConditional())
MergeBasicBlockIntoOnlyPred(BB, &DTU);
}
if (DTU.hasDomTree())
EXPECT_TRUE(DTU.getDomTree().verify());
if (DTU.hasPostDomTree())
EXPECT_TRUE(DTU.getPostDomTree().verify());
};
// Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with
// both DT and PDT.
resetIR();
runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {
PostDominatorTree PDT = PostDominatorTree(F);
DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Eager);
Test(F, DTU);
});
// Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with
// DT.
resetIR();
runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {
DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Eager);
Test(F, DTU);
});
// Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with
// PDT.
resetIR();
runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {
PostDominatorTree PDT = PostDominatorTree(F);
DomTreeUpdater DTU(PDT, DomTreeUpdater::UpdateStrategy::Eager);
Test(F, DTU);
});
// Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with
// both DT and PDT.
resetIR();
runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {
PostDominatorTree PDT = PostDominatorTree(F);
DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);
Test(F, DTU);
});
// Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with
// PDT.
resetIR();
runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {
PostDominatorTree PDT = PostDominatorTree(F);
DomTreeUpdater DTU(PDT, DomTreeUpdater::UpdateStrategy::Lazy);
Test(F, DTU);
});
// Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with DT.
resetIR();
runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {
DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Lazy);
Test(F, DTU);
});
// Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with
// both DT and PDT.
resetIRReplaceEntry();
runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {
PostDominatorTree PDT = PostDominatorTree(F);
DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Eager);
Test(F, DTU);
});
// Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with
// DT.
resetIRReplaceEntry();
runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {
DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Eager);
Test(F, DTU);
});
// Test MergeBasicBlockIntoOnlyPred working under Eager UpdateStrategy with
// PDT.
resetIRReplaceEntry();
runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {
PostDominatorTree PDT = PostDominatorTree(F);
DomTreeUpdater DTU(PDT, DomTreeUpdater::UpdateStrategy::Eager);
Test(F, DTU);
});
// Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with
// both DT and PDT.
resetIRReplaceEntry();
runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {
PostDominatorTree PDT = PostDominatorTree(F);
DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);
Test(F, DTU);
});
// Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with
// PDT.
resetIRReplaceEntry();
runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {
PostDominatorTree PDT = PostDominatorTree(F);
DomTreeUpdater DTU(PDT, DomTreeUpdater::UpdateStrategy::Lazy);
Test(F, DTU);
});
// Test MergeBasicBlockIntoOnlyPred working under Lazy UpdateStrategy with DT.
resetIRReplaceEntry();
runWithDomTree(*M, "f", [&](Function &F, DominatorTree *DT) {
DomTreeUpdater DTU(*DT, DomTreeUpdater::UpdateStrategy::Lazy);
Test(F, DTU);
});
}
TEST(Local, ConstantFoldTerminator) {
@ -310,27 +432,55 @@ TEST(Local, ConstantFoldTerminator) {
}
)");
auto CFAllTerminators = [&](Function &F, DominatorTree *DT) {
DeferredDominance DDT(*DT);
auto CFAllTerminatorsEager = [&](Function &F, DominatorTree *DT) {
PostDominatorTree PDT = PostDominatorTree(F);
DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Eager);
for (Function::iterator I = F.begin(), E = F.end(); I != E;) {
BasicBlock *BB = &*I++;
ConstantFoldTerminator(BB, true, nullptr, &DDT);
ConstantFoldTerminator(BB, true, nullptr, &DTU);
}
EXPECT_TRUE(DDT.flush().verify());
EXPECT_TRUE(DTU.getDomTree().verify());
EXPECT_TRUE(DTU.getPostDomTree().verify());
};
runWithDomTree(*M, "br_same_dest", CFAllTerminators);
runWithDomTree(*M, "br_different_dest", CFAllTerminators);
runWithDomTree(*M, "switch_2_different_dest", CFAllTerminators);
runWithDomTree(*M, "switch_2_different_dest_default", CFAllTerminators);
runWithDomTree(*M, "switch_3_different_dest", CFAllTerminators);
runWithDomTree(*M, "switch_variable_2_default_dest", CFAllTerminators);
runWithDomTree(*M, "switch_constant_2_default_dest", CFAllTerminators);
runWithDomTree(*M, "switch_constant_3_repeated_dest", CFAllTerminators);
runWithDomTree(*M, "indirectbr", CFAllTerminators);
runWithDomTree(*M, "indirectbr_repeated", CFAllTerminators);
runWithDomTree(*M, "indirectbr_unreachable", CFAllTerminators);
auto CFAllTerminatorsLazy = [&](Function &F, DominatorTree *DT) {
PostDominatorTree PDT = PostDominatorTree(F);
DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);
for (Function::iterator I = F.begin(), E = F.end(); I != E;) {
BasicBlock *BB = &*I++;
ConstantFoldTerminator(BB, true, nullptr, &DTU);
}
EXPECT_TRUE(DTU.getDomTree().verify());
EXPECT_TRUE(DTU.getPostDomTree().verify());
};
// Test ConstantFoldTerminator under Eager UpdateStrategy.
runWithDomTree(*M, "br_same_dest", CFAllTerminatorsEager);
runWithDomTree(*M, "br_different_dest", CFAllTerminatorsEager);
runWithDomTree(*M, "switch_2_different_dest", CFAllTerminatorsEager);
runWithDomTree(*M, "switch_2_different_dest_default", CFAllTerminatorsEager);
runWithDomTree(*M, "switch_3_different_dest", CFAllTerminatorsEager);
runWithDomTree(*M, "switch_variable_2_default_dest", CFAllTerminatorsEager);
runWithDomTree(*M, "switch_constant_2_default_dest", CFAllTerminatorsEager);
runWithDomTree(*M, "switch_constant_3_repeated_dest", CFAllTerminatorsEager);
runWithDomTree(*M, "indirectbr", CFAllTerminatorsEager);
runWithDomTree(*M, "indirectbr_repeated", CFAllTerminatorsEager);
runWithDomTree(*M, "indirectbr_unreachable", CFAllTerminatorsEager);
// Test ConstantFoldTerminator under Lazy UpdateStrategy.
runWithDomTree(*M, "br_same_dest", CFAllTerminatorsLazy);
runWithDomTree(*M, "br_different_dest", CFAllTerminatorsLazy);
runWithDomTree(*M, "switch_2_different_dest", CFAllTerminatorsLazy);
runWithDomTree(*M, "switch_2_different_dest_default", CFAllTerminatorsLazy);
runWithDomTree(*M, "switch_3_different_dest", CFAllTerminatorsLazy);
runWithDomTree(*M, "switch_variable_2_default_dest", CFAllTerminatorsLazy);
runWithDomTree(*M, "switch_constant_2_default_dest", CFAllTerminatorsLazy);
runWithDomTree(*M, "switch_constant_3_repeated_dest", CFAllTerminatorsLazy);
runWithDomTree(*M, "indirectbr", CFAllTerminatorsLazy);
runWithDomTree(*M, "indirectbr_repeated", CFAllTerminatorsLazy);
runWithDomTree(*M, "indirectbr_unreachable", CFAllTerminatorsLazy);
}
struct SalvageDebugInfoTest : ::testing::Test {
@ -618,3 +768,80 @@ TEST(Local, ReplaceAllDbgUsesWith) {
verifyModule(*M, &errs(), &BrokenDebugInfo);
ASSERT_FALSE(BrokenDebugInfo);
}
TEST(Local, RemoveUnreachableBlocks) {
LLVMContext C;
std::unique_ptr<Module> M = parseIR(C,
R"(
define void @br_simple() {
entry:
br label %bb0
bb0:
ret void
bb1:
ret void
}
define void @br_self_loop() {
entry:
br label %bb0
bb0:
br i1 true, label %bb1, label %bb0
bb1:
br i1 true, label %bb0, label %bb2
bb2:
br label %bb2
}
define void @br_constant() {
entry:
br label %bb0
bb0:
br i1 true, label %bb1, label %bb2
bb1:
br i1 true, label %bb0, label %bb2
bb2:
br label %bb2
}
define void @br_loop() {
entry:
br label %bb0
bb0:
br label %bb0
bb1:
br label %bb2
bb2:
br label %bb1
}
)");
auto runEager = [&](Function &F, DominatorTree *DT) {
PostDominatorTree PDT = PostDominatorTree(F);
DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Eager);
removeUnreachableBlocks(F, nullptr, &DTU);
EXPECT_TRUE(DTU.getDomTree().verify());
EXPECT_TRUE(DTU.getPostDomTree().verify());
};
auto runLazy = [&](Function &F, DominatorTree *DT) {
PostDominatorTree PDT = PostDominatorTree(F);
DomTreeUpdater DTU(*DT, PDT, DomTreeUpdater::UpdateStrategy::Lazy);
removeUnreachableBlocks(F, nullptr, &DTU);
EXPECT_TRUE(DTU.getDomTree().verify());
EXPECT_TRUE(DTU.getPostDomTree().verify());
};
// Test removeUnreachableBlocks under Eager UpdateStrategy.
runWithDomTree(*M, "br_simple", runEager);
runWithDomTree(*M, "br_self_loop", runEager);
runWithDomTree(*M, "br_constant", runEager);
runWithDomTree(*M, "br_loop", runEager);
// Test removeUnreachableBlocks under Lazy UpdateStrategy.
runWithDomTree(*M, "br_simple", runLazy);
runWithDomTree(*M, "br_self_loop", runLazy);
runWithDomTree(*M, "br_constant", runLazy);
runWithDomTree(*M, "br_loop", runLazy);
}