diff options
author | Brian M. Rzycki <brzycki@gmail.com> | 2017-12-13 22:01:17 +0000 |
---|---|---|
committer | Brian M. Rzycki <brzycki@gmail.com> | 2017-12-13 22:01:17 +0000 |
commit | 580bc3c8fa1e01991e41174d513ab600f9015c51 (patch) | |
tree | 57406d9d75f1c5ae80e8043fd55840f7928bff3c /llvm | |
parent | 3c7a35de7fbc0a73505545cd9f68a3bbacb68e57 (diff) | |
download | bcm5719-llvm-580bc3c8fa1e01991e41174d513ab600f9015c51.tar.gz bcm5719-llvm-580bc3c8fa1e01991e41174d513ab600f9015c51.zip |
Reverting [JumpThreading] Preservation of DT and LVI across the pass
Stage 2 bootstrap failed:
http://lab.llvm.org:8011/builders/clang-x86_64-linux-selfhost-modules-2/builds/14434
llvm-svn: 320641
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/IR/DeferredDominance.h | 190 | ||||
-rw-r--r-- | llvm/include/llvm/Transforms/Scalar/JumpThreading.h | 6 | ||||
-rw-r--r-- | llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h | 3 | ||||
-rw-r--r-- | llvm/include/llvm/Transforms/Utils/Local.h | 21 | ||||
-rw-r--r-- | llvm/lib/IR/Dominators.cpp | 54 | ||||
-rw-r--r-- | llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp | 2 | ||||
-rw-r--r-- | llvm/lib/Transforms/Scalar/JumpThreading.cpp | 175 | ||||
-rw-r--r-- | llvm/lib/Transforms/Utils/BasicBlockUtils.cpp | 18 | ||||
-rw-r--r-- | llvm/lib/Transforms/Utils/Local.cpp | 205 | ||||
-rw-r--r-- | llvm/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll | 3 | ||||
-rw-r--r-- | llvm/test/Transforms/JumpThreading/ddt-crash.ll | 265 | ||||
-rw-r--r-- | llvm/test/Transforms/JumpThreading/lvi-tristate.ll | 50 |
12 files changed, 99 insertions, 893 deletions
diff --git a/llvm/include/llvm/IR/DeferredDominance.h b/llvm/include/llvm/IR/DeferredDominance.h deleted file mode 100644 index edf67d5d0d1..00000000000 --- a/llvm/include/llvm/IR/DeferredDominance.h +++ /dev/null @@ -1,190 +0,0 @@ -//===- DeferredDominance.h - Deferred Dominators ----------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// -// -// This file defines the DeferredDominance class, which provides deferred -// updates to Dominators. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_IR_DEFERREDDOMINANCE_H -#define LLVM_IR_DEFERREDDOMINANCE_H - -#include "llvm/ADT/SmallSet.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/Dominators.h" -#include "llvm/IR/Instructions.h" - -namespace llvm { - -/// \brief Class to defer updates to a DominatorTree. -/// -/// Definition: Applying updates to every edge insertion and deletion is -/// expensive and not necessary. When one needs the DominatorTree for analysis -/// they can request a flush() to perform a larger batch update. This has the -/// advantage of the DominatorTree inspecting the set of updates to find -/// duplicates or unnecessary subtree updates. -/// -/// The scope of DeferredDominance operates at a Function level. -/// -/// It is not necessary for the user to scrub the updates for duplicates or -/// updates that point to the same block (Delete, BB_A, BB_A). Performance -/// can be gained if the caller attempts to batch updates before submitting -/// to applyUpdates(ArrayRef) in cases where duplicate edge requests will -/// occur. -/// -/// It is required for the state of the LLVM IR to be applied *before* -/// submitting updates. The update routines must analyze the current state -/// between a pair of (From, To) basic blocks to determine if the update -/// needs to be queued. -/// Example (good): -/// TerminatorInstructionBB->removeFromParent(); -/// DDT->deleteEdge(BB, Successor); -/// Example (bad): -/// DDT->deleteEdge(BB, Successor); -/// TerminatorInstructionBB->removeFromParent(); -class DeferredDominance { -public: - DeferredDominance(DominatorTree &DT_) : DT(DT_) {} - - /// \brief Queues multiple updates and discards duplicates. - void applyUpdates(ArrayRef<DominatorTree::UpdateType> Updates) { - SmallVector<DominatorTree::UpdateType, 8> Seen; - for (auto U : Updates) - // Avoid duplicates to applyUpdate() to save on analysis. - if (std::none_of(Seen.begin(), Seen.end(), - [U](DominatorTree::UpdateType S) { return S == U; })) { - Seen.push_back(U); - applyUpdate(U.getKind(), U.getFrom(), U.getTo()); - } - } - - void insertEdge(BasicBlock *From, BasicBlock *To) { - applyUpdate(DominatorTree::Insert, From, To); - } - - void deleteEdge(BasicBlock *From, BasicBlock *To) { - applyUpdate(DominatorTree::Delete, From, To); - } - - /// \brief Delays the deletion of a basic block until a flush() event. - void deleteBB(BasicBlock *DelBB) { - assert(DelBB && "Invalid push_back of nullptr DelBB."); - assert(pred_empty(DelBB) && "DelBB has one or more predecessors."); - // DelBB is unreachable and all its instructions are dead. - while (!DelBB->empty()) { - Instruction &I = DelBB->back(); - // Replace used instructions with an arbitrary value (undef). - if (!I.use_empty()) - I.replaceAllUsesWith(llvm::UndefValue::get(I.getType())); - DelBB->getInstList().pop_back(); - } - // Make sure DelBB has a valid terminator instruction. As long as DelBB is - // a Child of Function F it must contain valid IR. - new UnreachableInst(DelBB->getContext(), DelBB); - DeletedBBs.insert(DelBB); - } - - /// \brief Returns true if DelBB is awaiting deletion at a flush() event. - bool pendingDeletedBB(BasicBlock *DelBB) { - if (DeletedBBs.empty()) - return false; - return DeletedBBs.count(DelBB) != 0; - } - - /// \brief Flushes all pending updates and block deletions. Returns a - /// correct DominatorTree reference to be used by the caller for analysis. - DominatorTree &flush() { - // Updates to DT must happen before blocks are deleted below. Otherwise the - // DT traversal will encounter badref blocks and assert. - if (!PendUpdates.empty()) { - DT.applyUpdates(PendUpdates); - PendUpdates.clear(); - } - flushDelBB(); - return DT; - } - - /// \brief Drops all internal state and forces a (slow) recalculation of the - /// DominatorTree based on the current state of the LLVM IR in F. This should - /// only be used in corner cases such as the Entry block of F being deleted. - void recalculate(Function &F) { - // flushDelBB must be flushed before the recalculation. The state of the IR - // must be consistent before the DT traversal algorithm determines the - // actual DT. - if (flushDelBB() || !PendUpdates.empty()) { - DT.recalculate(F); - PendUpdates.clear(); - } - } - - /// \brief Debug method to help view the state of pending updates. - LLVM_DUMP_METHOD void dump() const; - -private: - DominatorTree &DT; - SmallVector<DominatorTree::UpdateType, 16> PendUpdates; - SmallPtrSet<BasicBlock *, 8> DeletedBBs; - - /// Apply an update (Kind, From, To) to the internal queued updates. The - /// update is only added when determined to be necessary. Checks for - /// self-domination, unnecessary updates, duplicate requests, and balanced - /// pairs of requests are all performed. Returns true if the update is - /// queued and false if it is discarded. - bool applyUpdate(DominatorTree::UpdateKind Kind, BasicBlock *From, - BasicBlock *To) { - if (From == To) - return false; // Cannot dominate self; discard update. - - // Discard updates by inspecting the current state of successors of From. - // Since applyUpdate() must be called *after* the Terminator of From is - // altered we can determine if the update is unnecessary. - bool HasEdge = std::any_of(succ_begin(From), succ_end(From), - [To](BasicBlock *B) { return B == To; }); - if (Kind == DominatorTree::Insert && !HasEdge) - return false; // Unnecessary Insert: edge does not exist in IR. - if (Kind == DominatorTree::Delete && HasEdge) - return false; // Unnecessary Delete: edge still exists in IR. - - // Analyze pending updates to determine if the update is unnecessary. - DominatorTree::UpdateType Update = {Kind, From, To}; - DominatorTree::UpdateType Invert = {Kind != DominatorTree::Insert - ? DominatorTree::Insert - : DominatorTree::Delete, - From, To}; - for (auto I = PendUpdates.begin(), E = PendUpdates.end(); I != E; ++I) { - if (Update == *I) - return false; // Discard duplicate updates. - if (Invert == *I) { - // Update and Invert are both valid (equivalent to a no-op). Remove - // Invert from PendUpdates and discard the Update. - PendUpdates.erase(I); - return false; - } - } - PendUpdates.push_back(Update); // Save the valid update. - return true; - } - - /// Performs all pending basic block deletions. We have to defer the deletion - /// of these blocks until after the DominatorTree updates are applied. The - /// internal workings of the DominatorTree code expect every update's From - /// and To blocks to exist and to be a member of the same Function. - bool flushDelBB() { - if (DeletedBBs.empty()) - return false; - for (auto *BB : DeletedBBs) - BB->eraseFromParent(); - DeletedBBs.clear(); - return true; - } -}; - -} // end namespace llvm - -#endif // LLVM_IR_DEFERREDDOMINANCE_H diff --git a/llvm/include/llvm/Transforms/Scalar/JumpThreading.h b/llvm/include/llvm/Transforms/Scalar/JumpThreading.h index b3493a29249..a9466713b8e 100644 --- a/llvm/include/llvm/Transforms/Scalar/JumpThreading.h +++ b/llvm/include/llvm/Transforms/Scalar/JumpThreading.h @@ -34,7 +34,6 @@ class BinaryOperator; class BranchInst; class CmpInst; class Constant; -class DeferredDominance; class Function; class Instruction; class IntrinsicInst; @@ -78,7 +77,6 @@ class JumpThreadingPass : public PassInfoMixin<JumpThreadingPass> { TargetLibraryInfo *TLI; LazyValueInfo *LVI; AliasAnalysis *AA; - DeferredDominance *DDT; std::unique_ptr<BlockFrequencyInfo> BFI; std::unique_ptr<BranchProbabilityInfo> BPI; bool HasProfileData = false; @@ -109,8 +107,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_, bool HasProfileData_, + std::unique_ptr<BlockFrequencyInfo> BFI_, std::unique_ptr<BranchProbabilityInfo> BPI_); PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); diff --git a/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h b/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h index 6f0d2deac0a..74f75509f55 100644 --- a/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h +++ b/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h @@ -27,7 +27,6 @@ namespace llvm { class BlockFrequencyInfo; class BranchProbabilityInfo; -class DeferredDominance; class DominatorTree; class Function; class Instruction; @@ -39,7 +38,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); /// 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 diff --git a/llvm/include/llvm/Transforms/Utils/Local.h b/llvm/include/llvm/Transforms/Utils/Local.h index d8e4bd9a196..6d8d8591fa1 100644 --- a/llvm/include/llvm/Transforms/Utils/Local.h +++ b/llvm/include/llvm/Transforms/Utils/Local.h @@ -24,7 +24,6 @@ #include "llvm/IR/Constant.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" -#include "llvm/IR/DeferredDominance.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/GetElementPtrTypeIterator.h" #include "llvm/IR/Operator.h" @@ -110,8 +109,7 @@ struct SimplifyCFGOptions { /// conditions and indirectbr addresses this might make dead if /// DeleteDeadConditions is true. bool ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions = false, - const TargetLibraryInfo *TLI = nullptr, - DeferredDominance *DDT = nullptr); + const TargetLibraryInfo *TLI = nullptr); //===----------------------------------------------------------------------===// // Local dead code elimination. @@ -165,21 +163,18 @@ 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); +void RemovePredecessorAndSimplify(BasicBlock *BB, BasicBlock *Pred); /// 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, DominatorTree *DT = 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); +bool TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB); /// 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 @@ -379,8 +374,7 @@ unsigned removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB); /// Insert an unreachable instruction before the specified /// 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); + bool PreserveLCSSA = false); /// Convert the CallInst to InvokeInst with the specified unwind edge basic /// block. This also splits the basic block where CI is located, because @@ -395,13 +389,12 @@ 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); /// 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); +bool removeUnreachableBlocks(Function &F, LazyValueInfo *LVI = nullptr); /// Combine the metadata of two instructions so that K can replace J /// diff --git a/llvm/lib/IR/Dominators.cpp b/llvm/lib/IR/Dominators.cpp index 6a205524aa7..ad448a3f240 100644 --- a/llvm/lib/IR/Dominators.cpp +++ b/llvm/lib/IR/Dominators.cpp @@ -18,7 +18,6 @@ #include "llvm/ADT/DepthFirstIterator.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/IR/CFG.h" -#include "llvm/IR/DeferredDominance.h" #include "llvm/IR/Instructions.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/CommandLine.h" @@ -390,56 +389,3 @@ void DominatorTreeWrapperPass::print(raw_ostream &OS, const Module *) const { DT.print(OS); } -//===----------------------------------------------------------------------===// -// DeferredDominance Implementation -//===----------------------------------------------------------------------===// -// -// The implementation details of the DeferredDominance class which allows -// one to queue updates to a DominatorTree. -// -//===----------------------------------------------------------------------===// - -#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) -LLVM_DUMP_METHOD void DeferredDominance::dump() const { - raw_ostream &OS = llvm::dbgs(); - OS << "PendUpdates:\n"; - int I = 0; - for (auto U : PendUpdates) { - OS << " " << I << " : "; - ++I; - if (U.getKind() == DominatorTree::Insert) - OS << "Insert, "; - else - OS << "Delete, "; - BasicBlock *From = U.getFrom(); - if (From) { - auto S = From->getName(); - if (!From->hasName()) - S = "(no name)"; - OS << S << "(" << From << "), "; - } else { - OS << "(badref), "; - } - BasicBlock *To = U.getTo(); - if (To) { - auto S = To->getName(); - if (!To->hasName()) - S = "(no_name)"; - OS << S << "(" << To << ")\n"; - } else { - OS << "(badref)\n"; - } - } - OS << "DeletedBBs:\n"; - I = 0; - for (auto BB : DeletedBBs) { - OS << " " << I << " : "; - ++I; - if (BB->hasName()) - OS << BB->getName() << "("; - else - OS << "(no_name)("; - OS << BB << ")\n"; - } -} -#endif diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp index 535d43cdf9e..8f468ebf894 100644 --- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp +++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp @@ -77,7 +77,6 @@ namespace { bool runOnFunction(Function &F) override; void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequired<DominatorTreeWrapperPass>(); AU.addRequired<LazyValueInfoWrapperPass>(); AU.addPreserved<GlobalsAAWrapperPass>(); } @@ -89,7 +88,6 @@ char CorrelatedValuePropagation::ID = 0; INITIALIZE_PASS_BEGIN(CorrelatedValuePropagation, "correlated-propagation", "Value Propagation", false, false) -INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(LazyValueInfoWrapperPass) INITIALIZE_PASS_END(CorrelatedValuePropagation, "correlated-propagation", "Value Propagation", false, false) diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp index 95dd9d14df2..6b0377e0ecb 100644 --- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp +++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp @@ -37,7 +37,6 @@ #include "llvm/IR/ConstantRange.h" #include "llvm/IR/Constants.h" #include "llvm/IR/DataLayout.h" -#include "llvm/IR/DeferredDominance.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstrTypes.h" @@ -132,11 +131,10 @@ namespace { bool runOnFunction(Function &F) override; void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.addRequired<DominatorTreeWrapperPass>(); - AU.addPreserved<DominatorTreeWrapperPass>(); + if (PrintLVIAfterJumpThreading) + AU.addRequired<DominatorTreeWrapperPass>(); AU.addRequired<AAResultsWrapperPass>(); AU.addRequired<LazyValueInfoWrapperPass>(); - AU.addPreserved<LazyValueInfoWrapperPass>(); AU.addPreserved<GlobalsAAWrapperPass>(); AU.addRequired<TargetLibraryInfoWrapperPass>(); } @@ -150,7 +148,6 @@ char JumpThreading::ID = 0; INITIALIZE_PASS_BEGIN(JumpThreading, "jump-threading", "Jump Threading", false, false) -INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_DEPENDENCY(LazyValueInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(AAResultsWrapperPass) @@ -281,12 +278,8 @@ bool JumpThreading::runOnFunction(Function &F) { if (skipFunction(F)) return false; auto TLI = &getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); - // Get DT analysis before LVI. When LVI is initialized it conditionally adds - // DT if it's available. - auto DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree(); auto LVI = &getAnalysis<LazyValueInfoWrapperPass>().getLVI(); auto AA = &getAnalysis<AAResultsWrapperPass>().getAAResults(); - DeferredDominance DDT(*DT); std::unique_ptr<BlockFrequencyInfo> BFI; std::unique_ptr<BranchProbabilityInfo> BPI; bool HasProfileData = F.getEntryCount().hasValue(); @@ -296,11 +289,12 @@ bool JumpThreading::runOnFunction(Function &F) { BFI.reset(new BlockFrequencyInfo(F, *BPI, LI)); } - bool Changed = Impl.runImpl(F, TLI, LVI, AA, &DDT, HasProfileData, - std::move(BFI), std::move(BPI)); + bool Changed = Impl.runImpl(F, TLI, LVI, AA, HasProfileData, std::move(BFI), + std::move(BPI)); if (PrintLVIAfterJumpThreading) { dbgs() << "LVI for function '" << F.getName() << "':\n"; - LVI->printLVI(F, *DT, dbgs()); + LVI->printLVI(F, getAnalysis<DominatorTreeWrapperPass>().getDomTree(), + dbgs()); } return Changed; } @@ -308,12 +302,8 @@ bool JumpThreading::runOnFunction(Function &F) { PreservedAnalyses JumpThreadingPass::run(Function &F, FunctionAnalysisManager &AM) { auto &TLI = AM.getResult<TargetLibraryAnalysis>(F); - // Get DT analysis before LVI. When LVI is initialized it conditionally adds - // DT if it's available. - auto &DT = AM.getResult<DominatorTreeAnalysis>(F); auto &LVI = AM.getResult<LazyValueAnalysis>(F); auto &AA = AM.getResult<AAManager>(F); - DeferredDominance DDT(DT); std::unique_ptr<BlockFrequencyInfo> BFI; std::unique_ptr<BranchProbabilityInfo> BPI; @@ -324,28 +314,25 @@ PreservedAnalyses JumpThreadingPass::run(Function &F, BFI.reset(new BlockFrequencyInfo(F, *BPI, LI)); } - bool Changed = runImpl(F, &TLI, &LVI, &AA, &DDT, HasProfileData, - std::move(BFI), std::move(BPI)); + bool Changed = runImpl(F, &TLI, &LVI, &AA, HasProfileData, std::move(BFI), + std::move(BPI)); if (!Changed) return PreservedAnalyses::all(); PreservedAnalyses PA; PA.preserve<GlobalsAA>(); - PA.preserve<DominatorTreeAnalysis>(); - PA.preserve<LazyValueAnalysis>(); return PA; } bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_, LazyValueInfo *LVI_, AliasAnalysis *AA_, - DeferredDominance *DDT_, bool HasProfileData_, + bool HasProfileData_, std::unique_ptr<BlockFrequencyInfo> BFI_, std::unique_ptr<BranchProbabilityInfo> BPI_) { DEBUG(dbgs() << "Jump threading on function '" << F.getName() << "'\n"); TLI = TLI_; LVI = LVI_; AA = AA_; - DDT = DDT_; BFI.reset(); BPI.reset(); // When profile data is available, we need to update edge weights after @@ -367,7 +354,7 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_, // back edges. This works for normal cases but not for unreachable blocks as // they may have cycle with no back edge. bool EverChanged = false; - EverChanged |= removeUnreachableBlocks(F, LVI, DDT); + EverChanged |= removeUnreachableBlocks(F, LVI); FindLoopHeaders(F); @@ -382,10 +369,6 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_, ++I; - // Don't thread branches over a block that's slated for deletion. - if (DDT->pendingDeletedBB(BB)) - continue; - // If the block is trivially dead, zap it. This eliminates the successor // edges which simplifies the CFG. if (pred_empty(BB) && @@ -394,7 +377,7 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_, << "' with terminator: " << *BB->getTerminator() << '\n'); LoopHeaders.erase(BB); LVI->eraseBlock(BB); - DeleteDeadBlock(BB, DDT); + DeleteDeadBlock(BB); Changed = true; continue; } @@ -418,7 +401,7 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_, // awesome, but it allows us to use AssertingVH to prevent nasty // dangling pointer issues within LazyValueInfo. LVI->eraseBlock(BB); - if (TryToSimplifyUncondBranchFromEmptyBlock(BB, DDT)) + if (TryToSimplifyUncondBranchFromEmptyBlock(BB)) Changed = true; } } @@ -426,7 +409,6 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_, } while (Changed); LoopHeaders.clear(); - DDT->flush(); return EverChanged; } @@ -950,8 +932,8 @@ 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) || - (pred_empty(BB) && BB != &BB->getParent()->getEntryBlock())) + if (pred_empty(BB) && + BB != &BB->getParent()->getEntryBlock()) return false; // If this block has a single predecessor, and if that pred has a single @@ -967,7 +949,7 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { LoopHeaders.insert(BB); LVI->eraseBlock(SinglePred); - MergeBasicBlockIntoOnlyPred(BB, nullptr, DDT); + MergeBasicBlockIntoOnlyPred(BB); // 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 @@ -1050,23 +1032,18 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { // successors to branch to. Let GetBestDestForJumpOnUndef decide. if (isa<UndefValue>(Condition)) { unsigned BestSucc = GetBestDestForJumpOnUndef(BB); - std::vector<DominatorTree::UpdateType> Updates; // Fold the branch/switch. TerminatorInst *BBTerm = BB->getTerminator(); - Updates.reserve(BBTerm->getNumSuccessors()); for (unsigned i = 0, e = BBTerm->getNumSuccessors(); i != e; ++i) { if (i == BestSucc) continue; - BasicBlock *Succ = BBTerm->getSuccessor(i); - Succ->removePredecessor(BB, true); - Updates.push_back({DominatorTree::Delete, BB, Succ}); + BBTerm->getSuccessor(i)->removePredecessor(BB, true); } DEBUG(dbgs() << " In block '" << BB->getName() << "' folding undef terminator: " << *BBTerm << '\n'); BranchInst::Create(BBTerm->getSuccessor(BestSucc), BBTerm); BBTerm->eraseFromParent(); - DDT->applyUpdates(Updates); return true; } @@ -1077,7 +1054,7 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { DEBUG(dbgs() << " In block '" << BB->getName() << "' folding terminator: " << *BB->getTerminator() << '\n'); ++NumFolds; - ConstantFoldTerminator(BB, true, nullptr, DDT); + ConstantFoldTerminator(BB, true); return true; } @@ -1110,8 +1087,7 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { if (Ret != LazyValueInfo::Unknown) { unsigned ToRemove = Ret == LazyValueInfo::True ? 1 : 0; unsigned ToKeep = Ret == LazyValueInfo::True ? 0 : 1; - BasicBlock *ToRemoveSucc = CondBr->getSuccessor(ToRemove); - ToRemoveSucc->removePredecessor(BB, true); + CondBr->getSuccessor(ToRemove)->removePredecessor(BB, true); BranchInst::Create(CondBr->getSuccessor(ToKeep), CondBr); CondBr->eraseFromParent(); if (CondCmp->use_empty()) @@ -1129,7 +1105,6 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) { ConstantInt::getFalse(CondCmp->getType()); ReplaceFoldableUses(CondCmp, CI); } - DDT->deleteEdge(BB, ToRemoveSucc); return true; } @@ -1208,12 +1183,9 @@ bool JumpThreadingPass::ProcessImpliedCondition(BasicBlock *BB) { Optional<bool> Implication = isImpliedCondition(PBI->getCondition(), Cond, DL, CondIsTrue); if (Implication) { - BasicBlock *KeepSucc = BI->getSuccessor(*Implication ? 0 : 1); - BasicBlock *RemoveSucc = BI->getSuccessor(*Implication ? 1 : 0); - RemoveSucc->removePredecessor(BB); - BranchInst::Create(KeepSucc, BI); + BI->getSuccessor(*Implication ? 1 : 0)->removePredecessor(BB); + BranchInst::Create(BI->getSuccessor(*Implication ? 0 : 1), BI); BI->eraseFromParent(); - DDT->deleteEdge(BB, RemoveSucc); return true; } CurrentBB = CurrentPred; @@ -1606,22 +1578,17 @@ bool JumpThreadingPass::ProcessThreadableEdges(Value *Cond, BasicBlock *BB, if (PredWithKnownDest == (size_t)std::distance(pred_begin(BB), pred_end(BB))) { bool SeenFirstBranchToOnlyDest = false; - std::vector <DominatorTree::UpdateType> Updates; - Updates.reserve(BB->getTerminator()->getNumSuccessors() - 1); for (BasicBlock *SuccBB : successors(BB)) { - if (SuccBB == OnlyDest && !SeenFirstBranchToOnlyDest) { + if (SuccBB == OnlyDest && !SeenFirstBranchToOnlyDest) SeenFirstBranchToOnlyDest = true; // Don't modify the first branch. - } else { + else SuccBB->removePredecessor(BB, true); // This is unreachable successor. - Updates.push_back({DominatorTree::Delete, BB, SuccBB}); - } } // Finally update the terminator. TerminatorInst *Term = BB->getTerminator(); BranchInst::Create(OnlyDest, Term); Term->eraseFromParent(); - DDT->applyUpdates(Updates); // If the condition is now dead due to the removal of the old terminator, // erase it. @@ -1985,10 +1952,6 @@ bool JumpThreadingPass::ThreadEdge(BasicBlock *BB, PredTerm->setSuccessor(i, NewBB); } - DDT->applyUpdates({{DominatorTree::Insert, NewBB, SuccBB}, - {DominatorTree::Insert, PredBB, NewBB}, - {DominatorTree::Delete, PredBB, BB}}); - // At this point, the IR is fully up to date and consistent. Do a quick scan // over the new instructions and zap any that are constants or dead. This // frequently happens because of phi translation. @@ -2008,42 +1971,20 @@ bool JumpThreadingPass::ThreadEdge(BasicBlock *BB, BasicBlock *JumpThreadingPass::SplitBlockPreds(BasicBlock *BB, ArrayRef<BasicBlock *> Preds, const char *Suffix) { - SmallVector<BasicBlock *, 2> NewBBs; - // Collect the frequencies of all predecessors of BB, which will be used to - // update the edge weight of the result of splitting predecessors. - DenseMap<BasicBlock *, BlockFrequency> FreqMap; + // update the edge weight on BB->SuccBB. + BlockFrequency PredBBFreq(0); if (HasProfileData) for (auto Pred : Preds) - FreqMap.insert(std::make_pair( - Pred, BFI->getBlockFreq(Pred) * BPI->getEdgeProbability(Pred, BB))); - - // In the case when BB is a LandingPad block we create 2 new predecessors - // instead of just one. - if (BB->isLandingPad()) { - std::string NewName = std::string(Suffix) + ".split-lp"; - SplitLandingPadPredecessors(BB, Preds, Suffix, NewName.c_str(), NewBBs); - } else { - NewBBs.push_back(SplitBlockPredecessors(BB, Preds, Suffix)); - } + PredBBFreq += BFI->getBlockFreq(Pred) * BPI->getEdgeProbability(Pred, BB); - std::vector<DominatorTree::UpdateType> Updates; - Updates.reserve((2 * Preds.size()) + NewBBs.size()); - for (auto NewBB : NewBBs) { - BlockFrequency NewBBFreq(0); - Updates.push_back({DominatorTree::Insert, NewBB, BB}); - for (auto Pred : predecessors(NewBB)) { - Updates.push_back({DominatorTree::Delete, Pred, BB}); - Updates.push_back({DominatorTree::Insert, Pred, NewBB}); - if (HasProfileData) // Update frequencies between Pred -> NewBB. - NewBBFreq += FreqMap.lookup(Pred); - } - if (HasProfileData) // Apply the summed frequency to NewBB. - BFI->setBlockFreq(NewBB, NewBBFreq.getFrequency()); - } + BasicBlock *PredBB = SplitBlockPredecessors(BB, Preds, Suffix); - DDT->applyUpdates(Updates); - return NewBBs[0]; + // Set the block frequency of the newly created PredBB, which is the sum of + // frequencies of Preds. + if (HasProfileData) + BFI->setBlockFreq(PredBB, PredBBFreq.getFrequency()); + return PredBB; } bool JumpThreadingPass::doesBlockHaveProfileData(BasicBlock *BB) { @@ -2187,7 +2128,6 @@ bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred( } // And finally, do it! Start by factoring the predecessors if needed. - std::vector<DominatorTree::UpdateType> Updates; BasicBlock *PredBB; if (PredBBs.size() == 1) PredBB = PredBBs[0]; @@ -2196,7 +2136,6 @@ bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred( << " common predecessors.\n"); PredBB = SplitBlockPreds(BB, PredBBs, ".thr_comm"); } - Updates.push_back({DominatorTree::Delete, PredBB, BB}); // Okay, we decided to do this! Clone all the instructions in BB onto the end // of PredBB. @@ -2209,11 +2148,7 @@ bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred( BranchInst *OldPredBranch = dyn_cast<BranchInst>(PredBB->getTerminator()); if (!OldPredBranch || !OldPredBranch->isUnconditional()) { - BasicBlock *OldPredBB = PredBB; - PredBB = SplitEdge(OldPredBB, BB); - Updates.push_back({DominatorTree::Insert, OldPredBB, PredBB}); - Updates.push_back({DominatorTree::Insert, PredBB, BB}); - Updates.push_back({DominatorTree::Delete, OldPredBB, BB}); + PredBB = SplitEdge(PredBB, BB); OldPredBranch = cast<BranchInst>(PredBB->getTerminator()); } @@ -2255,10 +2190,6 @@ bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred( // Otherwise, insert the new instruction into the block. New->setName(BI->getName()); PredBB->getInstList().insert(OldPredBranch->getIterator(), New); - // Update Dominance from simplified New instruction operands. - for (unsigned i = 0, e = New->getNumOperands(); i != e; ++i) - if (BasicBlock *SuccBB = dyn_cast<BasicBlock>(New->getOperand(i))) - Updates.push_back({DominatorTree::Insert, PredBB, SuccBB}); } } @@ -2314,7 +2245,6 @@ bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred( // Remove the unconditional branch at the end of the PredBB block. OldPredBranch->eraseFromParent(); - DDT->applyUpdates(Updates); ++NumDupes; return true; @@ -2387,8 +2317,6 @@ bool JumpThreadingPass::TryToUnfoldSelect(CmpInst *CondCmp, BasicBlock *BB) { // The select is now dead. SI->eraseFromParent(); - DDT->applyUpdates({{DominatorTree::Insert, NewBB, BB}, - {DominatorTree::Insert, Pred, NewBB}}); // Update any other PHI nodes in BB. for (BasicBlock::iterator BI = BB->begin(); PHINode *Phi = dyn_cast<PHINode>(BI); ++BI) @@ -2467,25 +2395,11 @@ bool JumpThreadingPass::TryToUnfoldSelectInCurrBB(BasicBlock *BB) { // Expand the select. TerminatorInst *Term = SplitBlockAndInsertIfThen(SI->getCondition(), SI, false); - BasicBlock *SplitBB = SI->getParent(); - BasicBlock *NewBB = Term->getParent(); PHINode *NewPN = PHINode::Create(SI->getType(), 2, "", SI); NewPN->addIncoming(SI->getTrueValue(), Term->getParent()); NewPN->addIncoming(SI->getFalseValue(), BB); SI->replaceAllUsesWith(NewPN); SI->eraseFromParent(); - // NewBB and SplitBB are newly created blocks which require insertion. - std::vector<DominatorTree::UpdateType> Updates; - Updates.reserve((2 * SplitBB->getTerminator()->getNumSuccessors()) + 3); - 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. - for (auto *Succ : successors(SplitBB)) { - Updates.push_back({DominatorTree::Delete, BB, Succ}); - Updates.push_back({DominatorTree::Insert, SplitBB, Succ}); - } - DDT->applyUpdates(Updates); return true; } return false; @@ -2572,8 +2486,8 @@ bool JumpThreadingPass::ThreadGuard(BasicBlock *BB, IntrinsicInst *Guard, if (!TrueDestIsSafe && !FalseDestIsSafe) return false; - BasicBlock *PredUnguardedBlock = TrueDestIsSafe ? TrueDest : FalseDest; - BasicBlock *PredGuardedBlock = FalseDestIsSafe ? TrueDest : FalseDest; + BasicBlock *UnguardedBlock = TrueDestIsSafe ? TrueDest : FalseDest; + BasicBlock *GuardedBlock = FalseDestIsSafe ? TrueDest : FalseDest; ValueToValueMapTy UnguardedMapping, GuardedMapping; Instruction *AfterGuard = Guard->getNextNode(); @@ -2582,29 +2496,18 @@ bool JumpThreadingPass::ThreadGuard(BasicBlock *BB, IntrinsicInst *Guard, return false; // Duplicate all instructions before the guard and the guard itself to the // branch where implication is not proved. - BasicBlock *GuardedBlock = DuplicateInstructionsInSplitBetween( - BB, PredGuardedBlock, AfterGuard, GuardedMapping); + GuardedBlock = DuplicateInstructionsInSplitBetween( + BB, GuardedBlock, AfterGuard, GuardedMapping); assert(GuardedBlock && "Could not create the guarded block?"); // Duplicate all instructions before the guard in the unguarded branch. // Since we have successfully duplicated the guarded block and this block // has fewer instructions, we expect it to succeed. - BasicBlock *UnguardedBlock = DuplicateInstructionsInSplitBetween( - BB, PredUnguardedBlock, Guard, UnguardedMapping); + UnguardedBlock = DuplicateInstructionsInSplitBetween(BB, UnguardedBlock, + Guard, UnguardedMapping); assert(UnguardedBlock && "Could not create the unguarded block?"); DEBUG(dbgs() << "Moved guard " << *Guard << " to block " << GuardedBlock->getName() << "\n"); - // 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( - {// Guarded block split. - {DominatorTree::Delete, PredGuardedBlock, BB}, - {DominatorTree::Insert, PredGuardedBlock, GuardedBlock}, - {DominatorTree::Insert, GuardedBlock, BB}, - // Unguarded block split. - {DominatorTree::Delete, PredUnguardedBlock, BB}, - {DominatorTree::Insert, PredUnguardedBlock, UnguardedBlock}, - {DominatorTree::Insert, UnguardedBlock, BB}}); + // Some instructions before the guard may still have uses. For them, we need // to create Phi nodes merging their copies in both guarded and unguarded // branches. Those instructions that have no uses can be just removed. diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp index a44746d040e..606bd8bacca 100644 --- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp +++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp @@ -45,22 +45,16 @@ using namespace llvm; -void llvm::DeleteDeadBlock(BasicBlock *BB, DeferredDominance *DDT) { +void llvm::DeleteDeadBlock(BasicBlock *BB) { assert((pred_begin(BB) == pred_end(BB) || // Can delete self loop. BB->getSinglePredecessor() == BB) && "Block is not dead!"); TerminatorInst *BBTerm = BB->getTerminator(); - std::vector<DominatorTree::UpdateType> Updates; // Loop through all of our successors and make sure they know that one // of their predecessors is going away. - if (DDT) - Updates.reserve(BBTerm->getNumSuccessors()); - for (BasicBlock *Succ : BBTerm->successors()) { + for (BasicBlock *Succ : BBTerm->successors()) Succ->removePredecessor(BB); - if (DDT) - Updates.push_back({DominatorTree::Delete, BB, Succ}); - } // Zap all the instructions in the block. while (!BB->empty()) { @@ -75,12 +69,8 @@ void llvm::DeleteDeadBlock(BasicBlock *BB, DeferredDominance *DDT) { BB->getInstList().pop_back(); } - if (DDT) { - DDT->applyUpdates(Updates); - DDT->deleteBB(BB); // Deferred deletion of BB. - } else { - BB->eraseFromParent(); // Zap the block! - } + // Zap the block! + BB->eraseFromParent(); } void llvm::FoldSingleEntryPHINodes(BasicBlock *BB, diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 5b5868c23e2..3ee2d046513 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -100,8 +100,7 @@ STATISTIC(NumRemoved, "Number of unreachable basic blocks removed"); /// conditions and indirectbr addresses this might make dead if /// DeleteDeadConditions is true. bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, - const TargetLibraryInfo *TLI, - DeferredDominance *DDT) { + const TargetLibraryInfo *TLI) { TerminatorInst *T = BB->getTerminator(); IRBuilder<> Builder(T); @@ -128,8 +127,6 @@ 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); return true; } @@ -200,12 +197,9 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, createBranchWeights(Weights)); } // Remove this entry. - BasicBlock *ParentBB = SI->getParent(); - DefaultDest->removePredecessor(ParentBB); + DefaultDest->removePredecessor(SI->getParent()); i = SI->removeCase(i); e = SI->case_end(); - if (DDT) - DDT->deleteEdge(ParentBB, DefaultDest); continue; } @@ -231,20 +225,14 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, // Insert the new branch. Builder.CreateBr(TheOnlyDest); BasicBlock *BB = SI->getParent(); - std::vector <DominatorTree::UpdateType> Updates; - if (DDT) - Updates.reserve(SI->getNumSuccessors() - 1); // Remove entries from PHI nodes which we no longer branch to... for (BasicBlock *Succ : SI->successors()) { // Found case matching a constant operand? - if (Succ == TheOnlyDest) { + if (Succ == TheOnlyDest) TheOnlyDest = nullptr; // Don't modify the first branch to TheOnlyDest - } else { + else Succ->removePredecessor(BB); - if (DDT) - Updates.push_back({DominatorTree::Delete, BB, Succ}); - } } // Delete the old switch. @@ -252,8 +240,6 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, SI->eraseFromParent(); if (DeleteDeadConditions) RecursivelyDeleteTriviallyDeadInstructions(Cond, TLI); - if (DDT) - DDT->applyUpdates(Updates); return true; } @@ -299,23 +285,14 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, if (BlockAddress *BA = dyn_cast<BlockAddress>(IBI->getAddress()->stripPointerCasts())) { BasicBlock *TheOnlyDest = BA->getBasicBlock(); - std::vector <DominatorTree::UpdateType> Updates; - if (DDT) - Updates.reserve(IBI->getNumDestinations() - 1); - // Insert the new branch. Builder.CreateBr(TheOnlyDest); for (unsigned i = 0, e = IBI->getNumDestinations(); i != e; ++i) { - if (IBI->getDestination(i) == TheOnlyDest) { + if (IBI->getDestination(i) == TheOnlyDest) TheOnlyDest = nullptr; - } else { - BasicBlock *ParentBB = IBI->getParent(); - BasicBlock *DestBB = IBI->getDestination(i); - DestBB->removePredecessor(ParentBB); - if (DDT) - Updates.push_back({DominatorTree::Delete, ParentBB, DestBB}); - } + else + IBI->getDestination(i)->removePredecessor(IBI->getParent()); } Value *Address = IBI->getAddress(); IBI->eraseFromParent(); @@ -330,8 +307,6 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions, new UnreachableInst(BB->getContext(), BB); } - if (DDT) - DDT->applyUpdates(Updates); return true; } } @@ -608,8 +583,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) { +void llvm::RemovePredecessorAndSimplify(BasicBlock *BB, BasicBlock *Pred) { // This only adjusts blocks with PHI nodes. if (!isa<PHINode>(BB->begin())) return; @@ -632,18 +606,13 @@ void llvm::RemovePredecessorAndSimplify(BasicBlock *BB, BasicBlock *Pred, // of the block. if (PhiIt != OldPhiIt) PhiIt = &BB->front(); } - if (DDT) - DDT->deleteEdge(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, DominatorTree *DT) { // If BB has single-entry PHI nodes, fold them. while (PHINode *PN = dyn_cast<PHINode>(DestBB->begin())) { Value *NewVal = PN->getIncomingValue(0); @@ -656,23 +625,6 @@ void llvm::MergeBasicBlockIntoOnlyPred(BasicBlock *DestBB, DominatorTree *DT, BasicBlock *PredBB = DestBB->getSinglePredecessor(); assert(PredBB && "Block doesn't have a single predecessor!"); - bool ReplaceEntryBB = false; - 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. - std::vector <DominatorTree::UpdateType> Updates; - if (DDT && !ReplaceEntryBB) { - Updates.reserve((2 * std::distance(pred_begin(PredBB), pred_end(PredBB))) + - 1); - Updates.push_back({DominatorTree::Delete, PredBB, DestBB}); - for (auto I = pred_begin(PredBB), E = pred_end(PredBB); I != E; ++I) { - Updates.push_back({DominatorTree::Delete, *I, PredBB}); - Updates.push_back({DominatorTree::Insert, *I, DestBB}); - } - } - // Zap anything that took the address of DestBB. Not doing this will give the // address an invalid value. if (DestBB->hasAddressTaken()) { @@ -693,7 +645,7 @@ void llvm::MergeBasicBlockIntoOnlyPred(BasicBlock *DestBB, DominatorTree *DT, // If the PredBB is the entry block of the function, move DestBB up to // become the entry block after we erase PredBB. - if (ReplaceEntryBB) + if (PredBB == &DestBB->getParent()->getEntryBlock()) DestBB->moveAfter(PredBB); if (DT) { @@ -705,19 +657,8 @@ void llvm::MergeBasicBlockIntoOnlyPred(BasicBlock *DestBB, DominatorTree *DT, DT->eraseNode(PredBB); } } - - 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. - } + // Nuke BB. + PredBB->eraseFromParent(); } /// CanMergeValues - Return true if we can choose one of these values to use @@ -924,8 +865,7 @@ static void redirectValuesFromPredecessorsToPhi(BasicBlock *BB, /// potential side-effect free 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 llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB, - DeferredDominance *DDT) { +bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB) { assert(BB != &BB->getParent()->getEntryBlock() && "TryToSimplifyUncondBranchFromEmptyBlock called on entry block!"); @@ -966,17 +906,6 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB, DEBUG(dbgs() << "Killing Trivial BB: \n" << *BB); - std::vector<DominatorTree::UpdateType> Updates; - if (DDT) { - Updates.reserve((2 * std::distance(pred_begin(BB), pred_end(BB))) + 1); - Updates.push_back({DominatorTree::Delete, BB, Succ}); - // All predecessors of BB will be moved to Succ. - for (auto I = pred_begin(BB), E = pred_end(BB); I != E; ++I) { - Updates.push_back({DominatorTree::Delete, *I, BB}); - Updates.push_back({DominatorTree::Insert, *I, Succ}); - } - } - if (isa<PHINode>(Succ->begin())) { // If there is more than one pred of succ, and there are PHI nodes in // the successor, then we need to add incoming edges for the PHI nodes @@ -1021,13 +950,7 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB, // Everything that jumped to BB now goes to Succ. BB->replaceAllUsesWith(Succ); if (!Succ->hasName()) Succ->takeName(BB); - - if (DDT) { - DDT->deleteBB(BB); // Deferred deletion of the old basic block. - DDT->applyUpdates(Updates); - } else { - BB->eraseFromParent(); // Delete the old basic block. - } + BB->eraseFromParent(); // Delete the old basic block. return true; } @@ -1529,19 +1452,13 @@ unsigned llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) { } unsigned llvm::changeToUnreachable(Instruction *I, bool UseLLVMTrap, - bool PreserveLCSSA, DeferredDominance *DDT) { + bool PreserveLCSSA) { 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) - Updates.reserve(BB->getTerminator()->getNumSuccessors()); - for (BasicBlock *Successor : successors(BB)) { + for (BasicBlock *Successor : successors(BB)) Successor->removePredecessor(BB, PreserveLCSSA); - if (DDT) - Updates.push_back({DominatorTree::Delete, BB, Successor}); - } + // Insert a call to llvm.trap right before this. This turns the undefined // behavior into a hard fail instead of falling through into random code. if (UseLLVMTrap) { @@ -1561,13 +1478,11 @@ unsigned llvm::changeToUnreachable(Instruction *I, bool UseLLVMTrap, BB->getInstList().erase(BBI++); ++NumInstrsRemoved; } - if (DDT) - DDT->applyUpdates(Updates); return NumInstrsRemoved; } /// changeToCall - Convert the specified invoke into a normal call. -static void changeToCall(InvokeInst *II, DeferredDominance *DDT = nullptr) { +static void changeToCall(InvokeInst *II) { SmallVector<Value*, 8> Args(II->arg_begin(), II->arg_end()); SmallVector<OperandBundleDef, 1> OpBundles; II->getOperandBundlesAsDefs(OpBundles); @@ -1580,16 +1495,11 @@ static void changeToCall(InvokeInst *II, DeferredDominance *DDT = nullptr) { II->replaceAllUsesWith(NewCall); // Follow the call by a branch to the normal destination. - BasicBlock *NormalDestBB = II->getNormalDest(); - BranchInst::Create(NormalDestBB, II); + BranchInst::Create(II->getNormalDest(), II); // Update PHI nodes in the unwind destination - BasicBlock *BB = II->getParent(); - BasicBlock *UnwindDestBB = II->getUnwindDest(); - UnwindDestBB->removePredecessor(BB); + II->getUnwindDest()->removePredecessor(II->getParent()); II->eraseFromParent(); - if (DDT) - DDT->deleteEdge(BB, UnwindDestBB); } BasicBlock *llvm::changeToInvokeAndSplitBasicBlock(CallInst *CI, @@ -1630,8 +1540,7 @@ BasicBlock *llvm::changeToInvokeAndSplitBasicBlock(CallInst *CI, } static bool markAliveBlocks(Function &F, - SmallPtrSetImpl<BasicBlock*> &Reachable, - DeferredDominance *DDT = nullptr) { + SmallPtrSetImpl<BasicBlock*> &Reachable) { SmallVector<BasicBlock*, 128> Worklist; BasicBlock *BB = &F.front(); Worklist.push_back(BB); @@ -1651,7 +1560,7 @@ static bool markAliveBlocks(Function &F, if (II->getIntrinsicID() == Intrinsic::assume) { if (match(II->getArgOperand(0), m_CombineOr(m_Zero(), m_Undef()))) { // Don't insert a call to llvm.trap right before the unreachable. - changeToUnreachable(II, false, false, DDT); + changeToUnreachable(II, false); Changed = true; break; } @@ -1668,8 +1577,7 @@ static bool markAliveBlocks(Function &F, // still be useful for widening. if (match(II->getArgOperand(0), m_Zero())) if (!isa<UnreachableInst>(II->getNextNode())) { - changeToUnreachable(II->getNextNode(), /*UseLLVMTrap=*/false, - false, DDT); + changeToUnreachable(II->getNextNode(), /*UseLLVMTrap=*/ false); Changed = true; break; } @@ -1679,7 +1587,7 @@ static bool markAliveBlocks(Function &F, if (auto *CI = dyn_cast<CallInst>(&I)) { Value *Callee = CI->getCalledValue(); if (isa<ConstantPointerNull>(Callee) || isa<UndefValue>(Callee)) { - changeToUnreachable(CI, /*UseLLVMTrap=*/false, false, DDT); + changeToUnreachable(CI, /*UseLLVMTrap=*/false); Changed = true; break; } @@ -1689,7 +1597,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); Changed = true; } break; @@ -1708,7 +1616,7 @@ static bool markAliveBlocks(Function &F, if (isa<UndefValue>(Ptr) || (isa<ConstantPointerNull>(Ptr) && SI->getPointerAddressSpace() == 0)) { - changeToUnreachable(SI, true, false, DDT); + changeToUnreachable(SI, true); Changed = true; break; } @@ -1720,20 +1628,16 @@ static bool markAliveBlocks(Function &F, // Turn invokes that call 'nounwind' functions into ordinary calls. Value *Callee = II->getCalledValue(); if (isa<ConstantPointerNull>(Callee) || isa<UndefValue>(Callee)) { - changeToUnreachable(II, true, false, DDT); + changeToUnreachable(II, true); Changed = true; } else if (II->doesNotThrow() && canSimplifyInvokeNoUnwind(&F)) { if (II->use_empty() && II->onlyReadsMemory()) { // jump to the normal destination branch. - BasicBlock *NormalDestBB = II->getNormalDest(); - BasicBlock *UnwindDestBB = II->getUnwindDest(); - BranchInst::Create(NormalDestBB, II); - UnwindDestBB->removePredecessor(II->getParent()); + BranchInst::Create(II->getNormalDest(), II); + II->getUnwindDest()->removePredecessor(II->getParent()); II->eraseFromParent(); - if (DDT) - DDT->deleteEdge(BB, UnwindDestBB); } else - changeToCall(II, DDT); + changeToCall(II); Changed = true; } } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Terminator)) { @@ -1779,7 +1683,7 @@ static bool markAliveBlocks(Function &F, } } - Changed |= ConstantFoldTerminator(BB, true, nullptr, DDT); + Changed |= ConstantFoldTerminator(BB, true); for (BasicBlock *Successor : successors(BB)) if (Reachable.insert(Successor).second) Worklist.push_back(Successor); @@ -1787,11 +1691,11 @@ static bool markAliveBlocks(Function &F, return Changed; } -void llvm::removeUnwindEdge(BasicBlock *BB, DeferredDominance *DDT) { +void llvm::removeUnwindEdge(BasicBlock *BB) { TerminatorInst *TI = BB->getTerminator(); if (auto *II = dyn_cast<InvokeInst>(TI)) { - changeToCall(II, DDT); + changeToCall(II); return; } @@ -1819,18 +1723,15 @@ void llvm::removeUnwindEdge(BasicBlock *BB, DeferredDominance *DDT) { UnwindDest->removePredecessor(BB); TI->replaceAllUsesWith(NewTI); TI->eraseFromParent(); - if (DDT) - DDT->deleteEdge(BB, UnwindDest); } /// removeUnreachableBlocks - Remove blocks that are not reachable, even /// if they are in a dead cycle. Return true if a change was made, false /// otherwise. If `LVI` is passed, this function preserves LazyValueInfo /// after modifying the CFG. -bool llvm::removeUnreachableBlocks(Function &F, LazyValueInfo *LVI, - DeferredDominance *DDT) { +bool llvm::removeUnreachableBlocks(Function &F, LazyValueInfo *LVI) { SmallPtrSet<BasicBlock*, 16> Reachable; - bool Changed = markAliveBlocks(F, Reachable, DDT); + bool Changed = markAliveBlocks(F, Reachable); // If there are unreachable blocks in the CFG... if (Reachable.size() == F.size()) @@ -1840,39 +1741,25 @@ 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. - std::vector <DominatorTree::UpdateType> Updates; - for (Function::iterator I = ++F.begin(), E = F.end(); I != E; ++I) { - auto *BB = &*I; - if (Reachable.count(BB)) + // their internal references... + for (Function::iterator BB = ++F.begin(), E = F.end(); BB != E; ++BB) { + if (Reachable.count(&*BB)) continue; - for (BasicBlock *Successor : successors(BB)) { + + for (BasicBlock *Successor : successors(&*BB)) if (Reachable.count(Successor)) - Successor->removePredecessor(BB); - if (DDT) - Updates.push_back({DominatorTree::Delete, BB, Successor}); - } + Successor->removePredecessor(&*BB); if (LVI) - LVI->eraseBlock(BB); + LVI->eraseBlock(&*BB); BB->dropAllReferences(); } - 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. - ++I; - } else { + for (Function::iterator I = ++F.begin(); I != F.end();) + if (!Reachable.count(&*I)) I = F.getBasicBlockList().erase(I); - } - } + else + ++I; - if (DDT) - DDT->applyUpdates(Updates); return true; } diff --git a/llvm/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll b/llvm/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll index 27cd2263bea..41bb8c9c820 100644 --- a/llvm/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll +++ b/llvm/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll @@ -19,13 +19,10 @@ entry: ; CHECK-NEXT: ; LatticeVal for: 'i32 %a' is: overdefined ; CHECK-NEXT: ; LatticeVal for: 'i32 %length' is: overdefined ; CHECK-NEXT: ; LatticeVal for: ' %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]' in BB: '%backedge' is: constantrange<0, 400> -; CHECK-NEXT: ; LatticeVal for: ' %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ]' in BB: '%exit' is: constantrange<399, 400> ; CHECK-NEXT: %iv = phi i32 [ 0, %entry ], [ %iv.next, %backedge ] ; CHECK-NEXT: ; LatticeVal for: ' %iv.next = add nsw i32 %iv, 1' in BB: '%backedge' is: constantrange<1, 401> -; CHECK-NEXT: ; LatticeVal for: ' %iv.next = add nsw i32 %iv, 1' in BB: '%exit' is: constantrange<400, 401> ; CHECK-NEXT: %iv.next = add nsw i32 %iv, 1 ; CHECK-NEXT: ; LatticeVal for: ' %cont = icmp slt i32 %iv.next, 400' in BB: '%backedge' is: overdefined -; CHECK-NEXT: ; LatticeVal for: ' %cont = icmp slt i32 %iv.next, 400' in BB: '%exit' is: constantrange<0, -1> ; CHECK-NEXT: %cont = icmp slt i32 %iv.next, 400 ; CHECK-NOT: loop loop: diff --git a/llvm/test/Transforms/JumpThreading/ddt-crash.ll b/llvm/test/Transforms/JumpThreading/ddt-crash.ll deleted file mode 100644 index a5cf24d354c..00000000000 --- a/llvm/test/Transforms/JumpThreading/ddt-crash.ll +++ /dev/null @@ -1,265 +0,0 @@ -; RUN: opt < %s -jump-threading -disable-output - -%struct.ham = type { i8, i8, i16, i32 } -%struct.zot = type { i32 (...)** } -%struct.quux.0 = type { %struct.wombat } -%struct.wombat = type { %struct.zot } - -@global = external global %struct.ham*, align 8 -@global.1 = external constant i8* - -declare i32 @wombat.2() - -define void @blam() { -bb: - %tmp = load i32, i32* undef - %tmp1 = icmp eq i32 %tmp, 0 - br i1 %tmp1, label %bb11, label %bb2 - -bb2: - %tmp3 = tail call i32 @wombat.2() - switch i32 %tmp3, label %bb4 [ - i32 0, label %bb5 - i32 1, label %bb7 - i32 2, label %bb7 - i32 3, label %bb11 - ] - -bb4: - br label %bb7 - -bb5: - %tmp6 = tail call i32 @wombat.2() - br label %bb7 - -bb7: - %tmp8 = phi i32 [ 0, %bb5 ], [ 1, %bb4 ], [ 2, %bb2 ], [ 2, %bb2 ] - %tmp9 = icmp eq i32 %tmp8, 0 - br i1 %tmp9, label %bb11, label %bb10 - -bb10: - ret void - -bb11: - ret void -} - -define void @spam(%struct.ham* %arg) { -bb: - %tmp = load i8, i8* undef, align 8 - switch i8 %tmp, label %bb11 [ - i8 1, label %bb11 - i8 2, label %bb11 - i8 3, label %bb1 - i8 4, label %bb1 - ] - -bb1: - br label %bb2 - -bb2: - %tmp3 = phi i32 [ 0, %bb1 ], [ %tmp3, %bb8 ] - br label %bb4 - -bb4: - %tmp5 = load i8, i8* undef, align 8 - switch i8 %tmp5, label %bb11 [ - i8 0, label %bb11 - i8 1, label %bb10 - i8 2, label %bb10 - i8 3, label %bb6 - i8 4, label %bb6 - ] - -bb6: - br label %bb7 - -bb7: - br i1 undef, label %bb8, label %bb10 - -bb8: - %tmp9 = icmp eq %struct.ham* undef, %arg - br i1 %tmp9, label %bb10, label %bb2 - -bb10: - switch i32 %tmp3, label %bb4 [ - i32 0, label %bb14 - i32 1, label %bb11 - i32 2, label %bb12 - ] - -bb11: - unreachable - -bb12: - %tmp13 = load %struct.ham*, %struct.ham** undef - br label %bb14 - -bb14: - %tmp15 = phi %struct.ham* [ %tmp13, %bb12 ], [ null, %bb10 ] - br label %bb16 - -bb16: - %tmp17 = load i8, i8* undef, align 8 - switch i8 %tmp17, label %bb11 [ - i8 0, label %bb11 - i8 11, label %bb18 - i8 12, label %bb18 - ] - -bb18: - br label %bb19 - -bb19: - br label %bb20 - -bb20: - %tmp21 = load %struct.ham*, %struct.ham** undef - switch i8 undef, label %bb22 [ - i8 0, label %bb4 - i8 11, label %bb10 - i8 12, label %bb10 - ] - -bb22: - br label %bb23 - -bb23: - %tmp24 = icmp eq %struct.ham* %tmp21, null - br i1 %tmp24, label %bb35, label %bb25 - -bb25: - %tmp26 = icmp eq %struct.ham* %tmp15, null - br i1 %tmp26, label %bb34, label %bb27 - -bb27: - %tmp28 = load %struct.ham*, %struct.ham** undef - %tmp29 = icmp eq %struct.ham* %tmp28, %tmp21 - br i1 %tmp29, label %bb35, label %bb30 - -bb30: - br label %bb31 - -bb31: - %tmp32 = load i8, i8* undef, align 8 - %tmp33 = icmp eq i8 %tmp32, 0 - br i1 %tmp33, label %bb31, label %bb34 - -bb34: - br label %bb35 - -bb35: - %tmp36 = phi i1 [ true, %bb34 ], [ false, %bb23 ], [ true, %bb27 ] - br label %bb37 - -bb37: - %tmp38 = icmp eq %struct.ham* %tmp15, null - br i1 %tmp38, label %bb39, label %bb41 - -bb39: - %tmp40 = load %struct.ham*, %struct.ham** @global - br label %bb41 - -bb41: - %tmp42 = select i1 %tmp36, %struct.ham* undef, %struct.ham* undef - ret void -} - -declare i32 @foo(...) - -define void @zot() align 2 personality i8* bitcast (i32 (...)* @foo to i8*) { -bb: - invoke void @bar() - to label %bb1 unwind label %bb3 - -bb1: - invoke void @bar() - to label %bb2 unwind label %bb4 - -bb2: - invoke void @bar() - to label %bb6 unwind label %bb17 - -bb3: - %tmp = landingpad { i8*, i32 } - catch i8* bitcast (i8** @global.1 to i8*) - catch i8* null - unreachable - -bb4: - %tmp5 = landingpad { i8*, i32 } - catch i8* bitcast (i8** @global.1 to i8*) - catch i8* null - unreachable - -bb6: - invoke void @bar() - to label %bb7 unwind label %bb19 - -bb7: - invoke void @bar() - to label %bb10 unwind label %bb8 - -bb8: - %tmp9 = landingpad { i8*, i32 } - cleanup - catch i8* bitcast (i8** @global.1 to i8*) - catch i8* null - unreachable - -bb10: - %tmp11 = load i32 (%struct.zot*)*, i32 (%struct.zot*)** undef, align 8 - %tmp12 = invoke i32 %tmp11(%struct.zot* nonnull undef) - to label %bb13 unwind label %bb21 - -bb13: - invoke void @bar() - to label %bb14 unwind label %bb23 - -bb14: - %tmp15 = load i32 (%struct.zot*)*, i32 (%struct.zot*)** undef, align 8 - %tmp16 = invoke i32 %tmp15(%struct.zot* nonnull undef) - to label %bb26 unwind label %bb23 - -bb17: - %tmp18 = landingpad { i8*, i32 } - catch i8* bitcast (i8** @global.1 to i8*) - catch i8* null - unreachable - -bb19: - %tmp20 = landingpad { i8*, i32 } - catch i8* bitcast (i8** @global.1 to i8*) - catch i8* null - unreachable - -bb21: - %tmp22 = landingpad { i8*, i32 } - catch i8* bitcast (i8** @global.1 to i8*) - catch i8* null - unreachable - -bb23: - %tmp24 = phi %struct.quux.0* [ null, %bb26 ], [ null, %bb14 ], [ undef, %bb13 ] - %tmp25 = landingpad { i8*, i32 } - catch i8* bitcast (i8** @global.1 to i8*) - catch i8* null - br label %bb30 - -bb26: - %tmp27 = load i32 (%struct.zot*)*, i32 (%struct.zot*)** undef, align 8 - %tmp28 = invoke i32 %tmp27(%struct.zot* nonnull undef) - to label %bb29 unwind label %bb23 - -bb29: - unreachable - -bb30: - %tmp31 = icmp eq %struct.quux.0* %tmp24, null - br i1 %tmp31, label %bb32, label %bb29 - -bb32: - unreachable -} - -declare void @bar() diff --git a/llvm/test/Transforms/JumpThreading/lvi-tristate.ll b/llvm/test/Transforms/JumpThreading/lvi-tristate.ll deleted file mode 100644 index 0aa87383347..00000000000 --- a/llvm/test/Transforms/JumpThreading/lvi-tristate.ll +++ /dev/null @@ -1,50 +0,0 @@ -; RUN: opt -jump-threading -simplifycfg -S < %s | FileCheck %s -; CHECK-NOT: bb6: -; CHECK-NOT: bb7: -; CHECK-NOT: bb8: -; CHECK-NOT: bb11: -; CHECK-NOT: bb12: -; CHECK: bb: -; CHECK: bb2: -; CHECK: bb4: -; CHECK: bb10: -; CHECK: bb13: -declare void @ham() - -define void @hoge() { -bb: - %tmp = and i32 undef, 1073741823 - %tmp1 = icmp eq i32 %tmp, 2 - br i1 %tmp1, label %bb12, label %bb2 - -bb2: - %tmp3 = icmp eq i32 %tmp, 3 - br i1 %tmp3, label %bb13, label %bb4 - -bb4: - %tmp5 = icmp eq i32 %tmp, 5 - br i1 %tmp5, label %bb6, label %bb7 - -bb6: - tail call void @ham() - br label %bb7 - -bb7: - br i1 %tmp3, label %bb13, label %bb8 - -bb8: - %tmp9 = icmp eq i32 %tmp, 4 - br i1 %tmp9, label %bb13, label %bb10 - -bb10: - br i1 %tmp9, label %bb11, label %bb13 - -bb11: - br label %bb13 - -bb12: - br label %bb2 - -bb13: - ret void -} |