зеркало из https://github.com/mozilla/gecko-dev.git
2216 строки
84 KiB
Diff
2216 строки
84 KiB
Diff
|
From 90f447e9556a9e094890a3da1affbb4f84fecb44 Mon Sep 17 00:00:00 2001
|
||
|
From: "Brian M. Rzycki" <brzycki@gmail.com>
|
||
|
Date: Fri, 12 Jan 2018 21:06:48 +0000
|
||
|
Subject: [PATCH 1/2] [JumpThreading] Preservation of DT and LVI across the
|
||
|
pass
|
||
|
|
||
|
Summary:
|
||
|
See D37528 for a previous (non-deferred) version of this
|
||
|
patch and its description.
|
||
|
|
||
|
Preserves dominance in a deferred manner using a new class
|
||
|
DeferredDominance. This reduces the performance impact of
|
||
|
updating the DominatorTree at every edge insertion and
|
||
|
deletion. A user may call DDT->flush() within JumpThreading
|
||
|
for an up-to-date DT. This patch currently has one flush()
|
||
|
at the end of runImpl() to ensure DT is preserved across
|
||
|
the pass.
|
||
|
|
||
|
LVI is also preserved to help subsequent passes such as
|
||
|
CorrelatedValuePropagation. LVI is simpler to maintain and
|
||
|
is done immediately (not deferred). The code to perform the
|
||
|
preversation was minimally altered and simply marked as
|
||
|
preserved for the PassManager to be informed.
|
||
|
|
||
|
This extends the analysis available to JumpThreading for
|
||
|
future enhancements such as threading across loop headers.
|
||
|
|
||
|
Reviewers: dberlin, kuhar, sebpop
|
||
|
|
||
|
Reviewed By: kuhar, sebpop
|
||
|
|
||
|
Subscribers: mgorny, dmgreen, kuba, rnk, rsmith, hiraditya, llvm-commits
|
||
|
|
||
|
Differential Revision: https://reviews.llvm.org/D40146
|
||
|
|
||
|
|
||
|
|
||
|
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@322401 91177308-0d34-0410-b5e6-96231b3b80d8
|
||
|
---
|
||
|
include/llvm/IR/Dominators.h | 84 +++++
|
||
|
.../llvm/Transforms/Scalar/JumpThreading.h | 6 +-
|
||
|
.../llvm/Transforms/Utils/BasicBlockUtils.h | 3 +-
|
||
|
include/llvm/Transforms/Utils/Local.h | 20 +-
|
||
|
lib/IR/Dominators.cpp | 188 ++++++++++
|
||
|
.../Scalar/CorrelatedValuePropagation.cpp | 2 +
|
||
|
lib/Transforms/Scalar/JumpThreading.cpp | 174 +++++++--
|
||
|
lib/Transforms/Utils/BasicBlockUtils.cpp | 18 +-
|
||
|
lib/Transforms/Utils/Local.cpp | 209 ++++++++---
|
||
|
.../lvi-after-jumpthreading.ll | 3 +
|
||
|
test/Transforms/JumpThreading/ddt-crash.ll | 265 ++++++++++++++
|
||
|
test/Transforms/JumpThreading/ddt-crash2.ll | 40 ++
|
||
|
test/Transforms/JumpThreading/lvi-tristate.ll | 50 +++
|
||
|
unittests/IR/CMakeLists.txt | 1 +
|
||
|
unittests/IR/DeferredDominanceTest.cpp | 344 ++++++++++++++++++
|
||
|
15 files changed, 1308 insertions(+), 99 deletions(-)
|
||
|
create mode 100644 test/Transforms/JumpThreading/ddt-crash.ll
|
||
|
create mode 100644 test/Transforms/JumpThreading/ddt-crash2.ll
|
||
|
create mode 100644 test/Transforms/JumpThreading/lvi-tristate.ll
|
||
|
create mode 100644 unittests/IR/DeferredDominanceTest.cpp
|
||
|
|
||
|
diff --git a/llvm/include/llvm/IR/Dominators.h b/llvm/include/llvm/IR/Dominators.h
|
||
|
index 6ad99e516fb..c5373376ade 100644
|
||
|
--- a/llvm/include/llvm/IR/Dominators.h
|
||
|
+++ b/llvm/include/llvm/IR/Dominators.h
|
||
|
@@ -290,6 +290,90 @@ public:
|
||
|
void print(raw_ostream &OS, const Module *M = nullptr) const override;
|
||
|
};
|
||
|
|
||
|
+//===-------------------------------------
|
||
|
+/// \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);
|
||
|
+
|
||
|
+ /// \brief Helper method for a single edge insertion. It's almost always
|
||
|
+ /// better to batch updates and call applyUpdates to quickly remove duplicate
|
||
|
+ /// edges. This is best used when there is only a single insertion needed to
|
||
|
+ /// update Dominators.
|
||
|
+ void insertEdge(BasicBlock *From, BasicBlock *To);
|
||
|
+
|
||
|
+ /// \brief Helper method for a single edge deletion. It's almost always better
|
||
|
+ /// to batch updates and call applyUpdates to quickly remove duplicate edges.
|
||
|
+ /// This is best used when there is only a single deletion needed to update
|
||
|
+ /// Dominators.
|
||
|
+ void deleteEdge(BasicBlock *From, BasicBlock *To);
|
||
|
+
|
||
|
+ /// \brief Delays the deletion of a basic block until a flush() event.
|
||
|
+ void deleteBB(BasicBlock *DelBB);
|
||
|
+
|
||
|
+ /// \brief Returns true if DelBB is awaiting deletion at a flush() event.
|
||
|
+ bool pendingDeletedBB(BasicBlock *DelBB);
|
||
|
+
|
||
|
+ /// \brief Flushes all pending updates and block deletions. Returns a
|
||
|
+ /// correct DominatorTree reference to be used by the caller for analysis.
|
||
|
+ DominatorTree &flush();
|
||
|
+
|
||
|
+ /// \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);
|
||
|
+
|
||
|
+ /// \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);
|
||
|
+
|
||
|
+ /// 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();
|
||
|
+};
|
||
|
+
|
||
|
} // end namespace llvm
|
||
|
|
||
|
#endif // LLVM_IR_DOMINATORS_H
|
||
|
diff --git a/llvm/include/llvm/Transforms/Scalar/JumpThreading.h b/llvm/include/llvm/Transforms/Scalar/JumpThreading.h
|
||
|
index a9466713b8e..b3493a29249 100644
|
||
|
--- a/llvm/include/llvm/Transforms/Scalar/JumpThreading.h
|
||
|
+++ b/llvm/include/llvm/Transforms/Scalar/JumpThreading.h
|
||
|
@@ -34,6 +34,7 @@ class BinaryOperator;
|
||
|
class BranchInst;
|
||
|
class CmpInst;
|
||
|
class Constant;
|
||
|
+class DeferredDominance;
|
||
|
class Function;
|
||
|
class Instruction;
|
||
|
class IntrinsicInst;
|
||
|
@@ -77,6 +78,7 @@ 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;
|
||
|
@@ -107,8 +109,8 @@ public:
|
||
|
|
||
|
// Glue for old PM.
|
||
|
bool runImpl(Function &F, TargetLibraryInfo *TLI_, LazyValueInfo *LVI_,
|
||
|
- AliasAnalysis *AA_, bool HasProfileData_,
|
||
|
- std::unique_ptr<BlockFrequencyInfo> BFI_,
|
||
|
+ AliasAnalysis *AA_, DeferredDominance *DDT_,
|
||
|
+ 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 74f75509f55..6f0d2deac0a 100644
|
||
|
--- a/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
|
||
|
+++ b/llvm/include/llvm/Transforms/Utils/BasicBlockUtils.h
|
||
|
@@ -27,6 +27,7 @@ namespace llvm {
|
||
|
|
||
|
class BlockFrequencyInfo;
|
||
|
class BranchProbabilityInfo;
|
||
|
+class DeferredDominance;
|
||
|
class DominatorTree;
|
||
|
class Function;
|
||
|
class Instruction;
|
||
|
@@ -38,7 +39,7 @@ class TargetLibraryInfo;
|
||
|
class Value;
|
||
|
|
||
|
/// Delete the specified block, which must have no predecessors.
|
||
|
-void DeleteDeadBlock(BasicBlock *BB);
|
||
|
+void DeleteDeadBlock(BasicBlock *BB, DeferredDominance *DDT = 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
|
||
|
diff --git a/llvm/include/llvm/Transforms/Utils/Local.h b/llvm/include/llvm/Transforms/Utils/Local.h
|
||
|
index 01db88bc15c..eb1f4c41b44 100644
|
||
|
--- a/llvm/include/llvm/Transforms/Utils/Local.h
|
||
|
+++ b/llvm/include/llvm/Transforms/Utils/Local.h
|
||
|
@@ -117,7 +117,8 @@ 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);
|
||
|
+ const TargetLibraryInfo *TLI = nullptr,
|
||
|
+ DeferredDominance *DDT = nullptr);
|
||
|
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
// Local dead code elimination.
|
||
|
@@ -171,18 +172,21 @@ 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);
|
||
|
+void RemovePredecessorAndSimplify(BasicBlock *BB, BasicBlock *Pred,
|
||
|
+ DeferredDominance *DDT = 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);
|
||
|
+void MergeBasicBlockIntoOnlyPred(BasicBlock *BB, DominatorTree *DT = nullptr,
|
||
|
+ DeferredDominance *DDT = 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);
|
||
|
+bool TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
|
||
|
+ DeferredDominance *DDT = 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
|
||
|
@@ -382,7 +386,8 @@ 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);
|
||
|
+ bool PreserveLCSSA = false,
|
||
|
+ DeferredDominance *DDT = nullptr);
|
||
|
|
||
|
/// Convert the CallInst to InvokeInst with the specified unwind edge basic
|
||
|
/// block. This also splits the basic block where CI is located, because
|
||
|
@@ -397,12 +402,13 @@ BasicBlock *changeToInvokeAndSplitBasicBlock(CallInst *CI,
|
||
|
///
|
||
|
/// \param BB Block whose terminator will be replaced. Its terminator must
|
||
|
/// have an unwind successor.
|
||
|
-void removeUnwindEdge(BasicBlock *BB);
|
||
|
+void removeUnwindEdge(BasicBlock *BB, DeferredDominance *DDT = 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);
|
||
|
+bool removeUnreachableBlocks(Function &F, LazyValueInfo *LVI = nullptr,
|
||
|
+ DeferredDominance *DDT = 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 ad448a3f240..e44e845b324 100644
|
||
|
--- a/llvm/lib/IR/Dominators.cpp
|
||
|
+++ b/llvm/lib/IR/Dominators.cpp
|
||
|
@@ -18,6 +18,7 @@
|
||
|
#include "llvm/ADT/DepthFirstIterator.h"
|
||
|
#include "llvm/ADT/SmallPtrSet.h"
|
||
|
#include "llvm/IR/CFG.h"
|
||
|
+#include "llvm/IR/Constants.h"
|
||
|
#include "llvm/IR/Instructions.h"
|
||
|
#include "llvm/IR/PassManager.h"
|
||
|
#include "llvm/Support/CommandLine.h"
|
||
|
@@ -389,3 +390,190 @@ 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.
|
||
|
+//
|
||
|
+//===----------------------------------------------------------------------===//
|
||
|
+
|
||
|
+/// \brief Queues multiple updates and discards duplicates.
|
||
|
+void DeferredDominance::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());
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+/// \brief Helper method for a single edge insertion. It's almost always better
|
||
|
+/// to batch updates and call applyUpdates to quickly remove duplicate edges.
|
||
|
+/// This is best used when there is only a single insertion needed to update
|
||
|
+/// Dominators.
|
||
|
+void DeferredDominance::insertEdge(BasicBlock *From, BasicBlock *To) {
|
||
|
+ applyUpdate(DominatorTree::Insert, From, To);
|
||
|
+}
|
||
|
+
|
||
|
+/// \brief Helper method for a single edge deletion. It's almost always better
|
||
|
+/// to batch updates and call applyUpdates to quickly remove duplicate edges.
|
||
|
+/// This is best used when there is only a single deletion needed to update
|
||
|
+/// Dominators.
|
||
|
+void DeferredDominance::deleteEdge(BasicBlock *From, BasicBlock *To) {
|
||
|
+ applyUpdate(DominatorTree::Delete, From, To);
|
||
|
+}
|
||
|
+
|
||
|
+/// \brief Delays the deletion of a basic block until a flush() event.
|
||
|
+void DeferredDominance::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 DeferredDominance::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 &DeferredDominance::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 DeferredDominance::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.
|
||
|
+#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
|
||
|
+
|
||
|
+/// 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 DeferredDominance::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 DeferredDominance::flushDelBB() {
|
||
|
+ if (DeletedBBs.empty())
|
||
|
+ return false;
|
||
|
+ for (auto *BB : DeletedBBs)
|
||
|
+ BB->eraseFromParent();
|
||
|
+ DeletedBBs.clear();
|
||
|
+ return true;
|
||
|
+}
|
||
|
diff --git a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
|
||
|
index 8f468ebf894..535d43cdf9e 100644
|
||
|
--- a/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
|
||
|
+++ b/llvm/lib/Transforms/Scalar/CorrelatedValuePropagation.cpp
|
||
|
@@ -77,6 +77,7 @@ namespace {
|
||
|
bool runOnFunction(Function &F) override;
|
||
|
|
||
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||
|
+ AU.addRequired<DominatorTreeWrapperPass>();
|
||
|
AU.addRequired<LazyValueInfoWrapperPass>();
|
||
|
AU.addPreserved<GlobalsAAWrapperPass>();
|
||
|
}
|
||
|
@@ -88,6 +89,7 @@ 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 141c9938bf8..4d366e8e392 100644
|
||
|
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
|
||
|
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
|
||
|
@@ -131,10 +131,11 @@ namespace {
|
||
|
bool runOnFunction(Function &F) override;
|
||
|
|
||
|
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||
|
- if (PrintLVIAfterJumpThreading)
|
||
|
- AU.addRequired<DominatorTreeWrapperPass>();
|
||
|
+ AU.addRequired<DominatorTreeWrapperPass>();
|
||
|
+ AU.addPreserved<DominatorTreeWrapperPass>();
|
||
|
AU.addRequired<AAResultsWrapperPass>();
|
||
|
AU.addRequired<LazyValueInfoWrapperPass>();
|
||
|
+ AU.addPreserved<LazyValueInfoWrapperPass>();
|
||
|
AU.addPreserved<GlobalsAAWrapperPass>();
|
||
|
AU.addRequired<TargetLibraryInfoWrapperPass>();
|
||
|
}
|
||
|
@@ -148,6 +149,7 @@ 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)
|
||
|
@@ -278,8 +280,12 @@ 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.hasProfileData();
|
||
|
@@ -289,12 +295,11 @@ bool JumpThreading::runOnFunction(Function &F) {
|
||
|
BFI.reset(new BlockFrequencyInfo(F, *BPI, LI));
|
||
|
}
|
||
|
|
||
|
- bool Changed = Impl.runImpl(F, TLI, LVI, AA, HasProfileData, std::move(BFI),
|
||
|
- std::move(BPI));
|
||
|
+ bool Changed = Impl.runImpl(F, TLI, LVI, AA, &DDT, HasProfileData,
|
||
|
+ std::move(BFI), std::move(BPI));
|
||
|
if (PrintLVIAfterJumpThreading) {
|
||
|
dbgs() << "LVI for function '" << F.getName() << "':\n";
|
||
|
- LVI->printLVI(F, getAnalysis<DominatorTreeWrapperPass>().getDomTree(),
|
||
|
- dbgs());
|
||
|
+ LVI->printLVI(F, *DT, dbgs());
|
||
|
}
|
||
|
return Changed;
|
||
|
}
|
||
|
@@ -302,8 +307,12 @@ 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;
|
||
|
@@ -313,25 +322,28 @@ PreservedAnalyses JumpThreadingPass::run(Function &F,
|
||
|
BFI.reset(new BlockFrequencyInfo(F, *BPI, LI));
|
||
|
}
|
||
|
|
||
|
- bool Changed = runImpl(F, &TLI, &LVI, &AA, HasProfileData, std::move(BFI),
|
||
|
- std::move(BPI));
|
||
|
+ bool Changed = runImpl(F, &TLI, &LVI, &AA, &DDT, 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_,
|
||
|
- bool HasProfileData_,
|
||
|
+ DeferredDominance *DDT_, 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
|
||
|
@@ -353,7 +365,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);
|
||
|
+ EverChanged |= removeUnreachableBlocks(F, LVI, DDT);
|
||
|
|
||
|
FindLoopHeaders(F);
|
||
|
|
||
|
@@ -368,6 +380,10 @@ 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) &&
|
||
|
@@ -376,7 +392,7 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_,
|
||
|
<< "' with terminator: " << *BB->getTerminator() << '\n');
|
||
|
LoopHeaders.erase(BB);
|
||
|
LVI->eraseBlock(BB);
|
||
|
- DeleteDeadBlock(BB);
|
||
|
+ DeleteDeadBlock(BB, DDT);
|
||
|
Changed = true;
|
||
|
continue;
|
||
|
}
|
||
|
@@ -400,7 +416,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))
|
||
|
+ if (TryToSimplifyUncondBranchFromEmptyBlock(BB, DDT))
|
||
|
Changed = true;
|
||
|
}
|
||
|
}
|
||
|
@@ -408,6 +424,7 @@ bool JumpThreadingPass::runImpl(Function &F, TargetLibraryInfo *TLI_,
|
||
|
} while (Changed);
|
||
|
|
||
|
LoopHeaders.clear();
|
||
|
+ DDT->flush();
|
||
|
return EverChanged;
|
||
|
}
|
||
|
|
||
|
@@ -931,8 +948,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 (pred_empty(BB) &&
|
||
|
- BB != &BB->getParent()->getEntryBlock())
|
||
|
+ if (DDT->pendingDeletedBB(BB) ||
|
||
|
+ (pred_empty(BB) && BB != &BB->getParent()->getEntryBlock()))
|
||
|
return false;
|
||
|
|
||
|
// If this block has a single predecessor, and if that pred has a single
|
||
|
@@ -948,7 +965,7 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) {
|
||
|
LoopHeaders.insert(BB);
|
||
|
|
||
|
LVI->eraseBlock(SinglePred);
|
||
|
- MergeBasicBlockIntoOnlyPred(BB);
|
||
|
+ MergeBasicBlockIntoOnlyPred(BB, nullptr, DDT);
|
||
|
|
||
|
// 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
|
||
|
@@ -1031,18 +1048,23 @@ 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;
|
||
|
- BBTerm->getSuccessor(i)->removePredecessor(BB, true);
|
||
|
+ BasicBlock *Succ = BBTerm->getSuccessor(i);
|
||
|
+ Succ->removePredecessor(BB, true);
|
||
|
+ Updates.push_back({DominatorTree::Delete, BB, Succ});
|
||
|
}
|
||
|
|
||
|
DEBUG(dbgs() << " In block '" << BB->getName()
|
||
|
<< "' folding undef terminator: " << *BBTerm << '\n');
|
||
|
BranchInst::Create(BBTerm->getSuccessor(BestSucc), BBTerm);
|
||
|
BBTerm->eraseFromParent();
|
||
|
+ DDT->applyUpdates(Updates);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
@@ -1053,7 +1075,7 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) {
|
||
|
DEBUG(dbgs() << " In block '" << BB->getName()
|
||
|
<< "' folding terminator: " << *BB->getTerminator() << '\n');
|
||
|
++NumFolds;
|
||
|
- ConstantFoldTerminator(BB, true);
|
||
|
+ ConstantFoldTerminator(BB, true, nullptr, DDT);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
@@ -1086,7 +1108,8 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) {
|
||
|
if (Ret != LazyValueInfo::Unknown) {
|
||
|
unsigned ToRemove = Ret == LazyValueInfo::True ? 1 : 0;
|
||
|
unsigned ToKeep = Ret == LazyValueInfo::True ? 0 : 1;
|
||
|
- CondBr->getSuccessor(ToRemove)->removePredecessor(BB, true);
|
||
|
+ BasicBlock *ToRemoveSucc = CondBr->getSuccessor(ToRemove);
|
||
|
+ ToRemoveSucc->removePredecessor(BB, true);
|
||
|
BranchInst::Create(CondBr->getSuccessor(ToKeep), CondBr);
|
||
|
CondBr->eraseFromParent();
|
||
|
if (CondCmp->use_empty())
|
||
|
@@ -1104,6 +1127,7 @@ bool JumpThreadingPass::ProcessBlock(BasicBlock *BB) {
|
||
|
ConstantInt::getFalse(CondCmp->getType());
|
||
|
ReplaceFoldableUses(CondCmp, CI);
|
||
|
}
|
||
|
+ DDT->deleteEdge(BB, ToRemoveSucc);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
@@ -1182,9 +1206,12 @@ bool JumpThreadingPass::ProcessImpliedCondition(BasicBlock *BB) {
|
||
|
Optional<bool> Implication =
|
||
|
isImpliedCondition(PBI->getCondition(), Cond, DL, CondIsTrue);
|
||
|
if (Implication) {
|
||
|
- BI->getSuccessor(*Implication ? 1 : 0)->removePredecessor(BB);
|
||
|
- BranchInst::Create(BI->getSuccessor(*Implication ? 0 : 1), BI);
|
||
|
+ BasicBlock *KeepSucc = BI->getSuccessor(*Implication ? 0 : 1);
|
||
|
+ BasicBlock *RemoveSucc = BI->getSuccessor(*Implication ? 1 : 0);
|
||
|
+ RemoveSucc->removePredecessor(BB);
|
||
|
+ BranchInst::Create(KeepSucc, BI);
|
||
|
BI->eraseFromParent();
|
||
|
+ DDT->deleteEdge(BB, RemoveSucc);
|
||
|
return true;
|
||
|
}
|
||
|
CurrentBB = CurrentPred;
|
||
|
@@ -1591,17 +1618,22 @@ 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.
|
||
|
@@ -1964,6 +1996,10 @@ 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.
|
||
|
@@ -1983,20 +2019,42 @@ 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 on BB->SuccBB.
|
||
|
- BlockFrequency PredBBFreq(0);
|
||
|
+ // update the edge weight of the result of splitting predecessors.
|
||
|
+ DenseMap<BasicBlock *, BlockFrequency> FreqMap;
|
||
|
if (HasProfileData)
|
||
|
for (auto Pred : Preds)
|
||
|
- PredBBFreq += BFI->getBlockFreq(Pred) * BPI->getEdgeProbability(Pred, BB);
|
||
|
+ 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));
|
||
|
+ }
|
||
|
|
||
|
- BasicBlock *PredBB = SplitBlockPredecessors(BB, Preds, Suffix);
|
||
|
+ 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());
|
||
|
+ }
|
||
|
|
||
|
- // 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;
|
||
|
+ DDT->applyUpdates(Updates);
|
||
|
+ return NewBBs[0];
|
||
|
}
|
||
|
|
||
|
bool JumpThreadingPass::doesBlockHaveProfileData(BasicBlock *BB) {
|
||
|
@@ -2140,6 +2198,7 @@ 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];
|
||
|
@@ -2148,6 +2207,7 @@ 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.
|
||
|
@@ -2160,7 +2220,11 @@ bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred(
|
||
|
BranchInst *OldPredBranch = dyn_cast<BranchInst>(PredBB->getTerminator());
|
||
|
|
||
|
if (!OldPredBranch || !OldPredBranch->isUnconditional()) {
|
||
|
- PredBB = SplitEdge(PredBB, BB);
|
||
|
+ 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});
|
||
|
OldPredBranch = cast<BranchInst>(PredBB->getTerminator());
|
||
|
}
|
||
|
|
||
|
@@ -2202,6 +2266,10 @@ 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});
|
||
|
}
|
||
|
}
|
||
|
|
||
|
@@ -2257,6 +2325,7 @@ bool JumpThreadingPass::DuplicateCondBranchOnPHIIntoPred(
|
||
|
|
||
|
// Remove the unconditional branch at the end of the PredBB block.
|
||
|
OldPredBranch->eraseFromParent();
|
||
|
+ DDT->applyUpdates(Updates);
|
||
|
|
||
|
++NumDupes;
|
||
|
return true;
|
||
|
@@ -2329,6 +2398,8 @@ 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)
|
||
|
@@ -2407,11 +2478,25 @@ 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;
|
||
|
@@ -2498,8 +2583,8 @@ bool JumpThreadingPass::ThreadGuard(BasicBlock *BB, IntrinsicInst *Guard,
|
||
|
if (!TrueDestIsSafe && !FalseDestIsSafe)
|
||
|
return false;
|
||
|
|
||
|
- BasicBlock *UnguardedBlock = TrueDestIsSafe ? TrueDest : FalseDest;
|
||
|
- BasicBlock *GuardedBlock = FalseDestIsSafe ? TrueDest : FalseDest;
|
||
|
+ BasicBlock *PredUnguardedBlock = TrueDestIsSafe ? TrueDest : FalseDest;
|
||
|
+ BasicBlock *PredGuardedBlock = FalseDestIsSafe ? TrueDest : FalseDest;
|
||
|
|
||
|
ValueToValueMapTy UnguardedMapping, GuardedMapping;
|
||
|
Instruction *AfterGuard = Guard->getNextNode();
|
||
|
@@ -2508,18 +2593,29 @@ 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.
|
||
|
- GuardedBlock = DuplicateInstructionsInSplitBetween(
|
||
|
- BB, GuardedBlock, AfterGuard, GuardedMapping);
|
||
|
+ BasicBlock *GuardedBlock = DuplicateInstructionsInSplitBetween(
|
||
|
+ BB, PredGuardedBlock, 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.
|
||
|
- UnguardedBlock = DuplicateInstructionsInSplitBetween(BB, UnguardedBlock,
|
||
|
- Guard, UnguardedMapping);
|
||
|
+ BasicBlock *UnguardedBlock = DuplicateInstructionsInSplitBetween(
|
||
|
+ BB, PredUnguardedBlock, 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 8f59913e14b..f3a5f148def 100644
|
||
|
--- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
|
||
|
+++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
|
||
|
@@ -45,16 +45,22 @@
|
||
|
|
||
|
using namespace llvm;
|
||
|
|
||
|
-void llvm::DeleteDeadBlock(BasicBlock *BB) {
|
||
|
+void llvm::DeleteDeadBlock(BasicBlock *BB, DeferredDominance *DDT) {
|
||
|
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.
|
||
|
- for (BasicBlock *Succ : BBTerm->successors())
|
||
|
+ if (DDT)
|
||
|
+ Updates.reserve(BBTerm->getNumSuccessors());
|
||
|
+ 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()) {
|
||
|
@@ -69,8 +75,12 @@ void llvm::DeleteDeadBlock(BasicBlock *BB) {
|
||
|
BB->getInstList().pop_back();
|
||
|
}
|
||
|
|
||
|
- // Zap the block!
|
||
|
- BB->eraseFromParent();
|
||
|
+ if (DDT) {
|
||
|
+ DDT->applyUpdates(Updates);
|
||
|
+ DDT->deleteBB(BB); // Deferred deletion of BB.
|
||
|
+ } else {
|
||
|
+ BB->eraseFromParent(); // Zap the block!
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
void llvm::FoldSingleEntryPHINodes(BasicBlock *BB,
|
||
|
diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp
|
||
|
index acccf7abf80..6564e18856c 100644
|
||
|
--- a/llvm/lib/Transforms/Utils/Local.cpp
|
||
|
+++ b/llvm/lib/Transforms/Utils/Local.cpp
|
||
|
@@ -100,7 +100,8 @@ 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) {
|
||
|
+ const TargetLibraryInfo *TLI,
|
||
|
+ DeferredDominance *DDT) {
|
||
|
TerminatorInst *T = BB->getTerminator();
|
||
|
IRBuilder<> Builder(T);
|
||
|
|
||
|
@@ -123,6 +124,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);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
@@ -193,9 +196,12 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
|
||
|
createBranchWeights(Weights));
|
||
|
}
|
||
|
// Remove this entry.
|
||
|
- DefaultDest->removePredecessor(SI->getParent());
|
||
|
+ BasicBlock *ParentBB = SI->getParent();
|
||
|
+ DefaultDest->removePredecessor(ParentBB);
|
||
|
i = SI->removeCase(i);
|
||
|
e = SI->case_end();
|
||
|
+ if (DDT)
|
||
|
+ DDT->deleteEdge(ParentBB, DefaultDest);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
@@ -221,14 +227,20 @@ 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.
|
||
|
@@ -236,6 +248,8 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
|
||
|
SI->eraseFromParent();
|
||
|
if (DeleteDeadConditions)
|
||
|
RecursivelyDeleteTriviallyDeadInstructions(Cond, TLI);
|
||
|
+ if (DDT)
|
||
|
+ DDT->applyUpdates(Updates);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
@@ -281,14 +295,23 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
|
||
|
if (auto *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
|
||
|
- IBI->getDestination(i)->removePredecessor(IBI->getParent());
|
||
|
+ } else {
|
||
|
+ BasicBlock *ParentBB = IBI->getParent();
|
||
|
+ BasicBlock *DestBB = IBI->getDestination(i);
|
||
|
+ DestBB->removePredecessor(ParentBB);
|
||
|
+ if (DDT)
|
||
|
+ Updates.push_back({DominatorTree::Delete, ParentBB, DestBB});
|
||
|
+ }
|
||
|
}
|
||
|
Value *Address = IBI->getAddress();
|
||
|
IBI->eraseFromParent();
|
||
|
@@ -303,6 +326,8 @@ bool llvm::ConstantFoldTerminator(BasicBlock *BB, bool DeleteDeadConditions,
|
||
|
new UnreachableInst(BB->getContext(), BB);
|
||
|
}
|
||
|
|
||
|
+ if (DDT)
|
||
|
+ DDT->applyUpdates(Updates);
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
@@ -579,7 +604,8 @@ 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) {
|
||
|
+void llvm::RemovePredecessorAndSimplify(BasicBlock *BB, BasicBlock *Pred,
|
||
|
+ DeferredDominance *DDT) {
|
||
|
// This only adjusts blocks with PHI nodes.
|
||
|
if (!isa<PHINode>(BB->begin()))
|
||
|
return;
|
||
|
@@ -602,13 +628,18 @@ 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) {
|
||
|
+void llvm::MergeBasicBlockIntoOnlyPred(BasicBlock *DestBB, DominatorTree *DT,
|
||
|
+ DeferredDominance *DDT) {
|
||
|
+ assert(!(DT && DDT) && "Cannot call with both DT and DDT.");
|
||
|
+
|
||
|
// If BB has single-entry PHI nodes, fold them.
|
||
|
while (PHINode *PN = dyn_cast<PHINode>(DestBB->begin())) {
|
||
|
Value *NewVal = PN->getIncomingValue(0);
|
||
|
@@ -621,6 +652,25 @@ 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(1 +
|
||
|
+ (2 * std::distance(pred_begin(PredBB), pred_end(PredBB))));
|
||
|
+ 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});
|
||
|
+ // This predecessor of PredBB may already have DestBB as a successor.
|
||
|
+ if (llvm::find(successors(*I), DestBB) == succ_end(*I))
|
||
|
+ 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()) {
|
||
|
@@ -641,7 +691,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 (PredBB == &DestBB->getParent()->getEntryBlock())
|
||
|
+ if (ReplaceEntryBB)
|
||
|
DestBB->moveAfter(PredBB);
|
||
|
|
||
|
if (DT) {
|
||
|
@@ -653,8 +703,19 @@ void llvm::MergeBasicBlockIntoOnlyPred(BasicBlock *DestBB, DominatorTree *DT) {
|
||
|
DT->eraseNode(PredBB);
|
||
|
}
|
||
|
}
|
||
|
- // Nuke BB.
|
||
|
- PredBB->eraseFromParent();
|
||
|
+
|
||
|
+ 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.
|
||
|
+ }
|
||
|
}
|
||
|
|
||
|
/// CanMergeValues - Return true if we can choose one of these values to use
|
||
|
@@ -861,7 +922,8 @@ 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) {
|
||
|
+bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB,
|
||
|
+ DeferredDominance *DDT) {
|
||
|
assert(BB != &BB->getParent()->getEntryBlock() &&
|
||
|
"TryToSimplifyUncondBranchFromEmptyBlock called on entry block!");
|
||
|
|
||
|
@@ -902,6 +964,19 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB) {
|
||
|
|
||
|
DEBUG(dbgs() << "Killing Trivial BB: \n" << *BB);
|
||
|
|
||
|
+ std::vector<DominatorTree::UpdateType> Updates;
|
||
|
+ if (DDT) {
|
||
|
+ Updates.reserve(1 + (2 * std::distance(pred_begin(BB), pred_end(BB))));
|
||
|
+ 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});
|
||
|
+ // This predecessor of BB may already have Succ as a successor.
|
||
|
+ if (llvm::find(successors(*I), Succ) == succ_end(*I))
|
||
|
+ 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
|
||
|
@@ -946,7 +1021,13 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB) {
|
||
|
// Everything that jumped to BB now goes to Succ.
|
||
|
BB->replaceAllUsesWith(Succ);
|
||
|
if (!Succ->hasName()) Succ->takeName(BB);
|
||
|
- BB->eraseFromParent(); // Delete the old basic block.
|
||
|
+
|
||
|
+ if (DDT) {
|
||
|
+ DDT->deleteBB(BB); // Deferred deletion of the old basic block.
|
||
|
+ DDT->applyUpdates(Updates);
|
||
|
+ } else {
|
||
|
+ BB->eraseFromParent(); // Delete the old basic block.
|
||
|
+ }
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
@@ -1448,13 +1529,19 @@ unsigned llvm::removeAllNonTerminatorAndEHPadInstructions(BasicBlock *BB) {
|
||
|
}
|
||
|
|
||
|
unsigned llvm::changeToUnreachable(Instruction *I, bool UseLLVMTrap,
|
||
|
- bool PreserveLCSSA) {
|
||
|
+ bool PreserveLCSSA, DeferredDominance *DDT) {
|
||
|
BasicBlock *BB = I->getParent();
|
||
|
+ std::vector <DominatorTree::UpdateType> Updates;
|
||
|
+
|
||
|
// Loop over all of the successors, removing BB's entry from any PHI
|
||
|
// nodes.
|
||
|
- for (BasicBlock *Successor : successors(BB))
|
||
|
+ if (DDT)
|
||
|
+ Updates.reserve(BB->getTerminator()->getNumSuccessors());
|
||
|
+ 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) {
|
||
|
@@ -1474,11 +1561,13 @@ 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) {
|
||
|
+static void changeToCall(InvokeInst *II, DeferredDominance *DDT = nullptr) {
|
||
|
SmallVector<Value*, 8> Args(II->arg_begin(), II->arg_end());
|
||
|
SmallVector<OperandBundleDef, 1> OpBundles;
|
||
|
II->getOperandBundlesAsDefs(OpBundles);
|
||
|
@@ -1491,11 +1580,16 @@ static void changeToCall(InvokeInst *II) {
|
||
|
II->replaceAllUsesWith(NewCall);
|
||
|
|
||
|
// Follow the call by a branch to the normal destination.
|
||
|
- BranchInst::Create(II->getNormalDest(), II);
|
||
|
+ BasicBlock *NormalDestBB = II->getNormalDest();
|
||
|
+ BranchInst::Create(NormalDestBB, II);
|
||
|
|
||
|
// Update PHI nodes in the unwind destination
|
||
|
- II->getUnwindDest()->removePredecessor(II->getParent());
|
||
|
+ BasicBlock *BB = II->getParent();
|
||
|
+ BasicBlock *UnwindDestBB = II->getUnwindDest();
|
||
|
+ UnwindDestBB->removePredecessor(BB);
|
||
|
II->eraseFromParent();
|
||
|
+ if (DDT)
|
||
|
+ DDT->deleteEdge(BB, UnwindDestBB);
|
||
|
}
|
||
|
|
||
|
BasicBlock *llvm::changeToInvokeAndSplitBasicBlock(CallInst *CI,
|
||
|
@@ -1536,7 +1630,8 @@ BasicBlock *llvm::changeToInvokeAndSplitBasicBlock(CallInst *CI,
|
||
|
}
|
||
|
|
||
|
static bool markAliveBlocks(Function &F,
|
||
|
- SmallPtrSetImpl<BasicBlock*> &Reachable) {
|
||
|
+ SmallPtrSetImpl<BasicBlock*> &Reachable,
|
||
|
+ DeferredDominance *DDT = nullptr) {
|
||
|
SmallVector<BasicBlock*, 128> Worklist;
|
||
|
BasicBlock *BB = &F.front();
|
||
|
Worklist.push_back(BB);
|
||
|
@@ -1556,7 +1651,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);
|
||
|
+ changeToUnreachable(II, false, false, DDT);
|
||
|
Changed = true;
|
||
|
break;
|
||
|
}
|
||
|
@@ -1573,7 +1668,8 @@ 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);
|
||
|
+ changeToUnreachable(II->getNextNode(), /*UseLLVMTrap=*/false,
|
||
|
+ false, DDT);
|
||
|
Changed = true;
|
||
|
break;
|
||
|
}
|
||
|
@@ -1583,7 +1679,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);
|
||
|
+ changeToUnreachable(CI, /*UseLLVMTrap=*/false, false, DDT);
|
||
|
Changed = true;
|
||
|
break;
|
||
|
}
|
||
|
@@ -1593,7 +1689,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);
|
||
|
+ changeToUnreachable(CI->getNextNode(), false, false, DDT);
|
||
|
Changed = true;
|
||
|
}
|
||
|
break;
|
||
|
@@ -1612,7 +1708,7 @@ static bool markAliveBlocks(Function &F,
|
||
|
if (isa<UndefValue>(Ptr) ||
|
||
|
(isa<ConstantPointerNull>(Ptr) &&
|
||
|
SI->getPointerAddressSpace() == 0)) {
|
||
|
- changeToUnreachable(SI, true);
|
||
|
+ changeToUnreachable(SI, true, false, DDT);
|
||
|
Changed = true;
|
||
|
break;
|
||
|
}
|
||
|
@@ -1624,16 +1720,20 @@ 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);
|
||
|
+ changeToUnreachable(II, true, false, DDT);
|
||
|
Changed = true;
|
||
|
} else if (II->doesNotThrow() && canSimplifyInvokeNoUnwind(&F)) {
|
||
|
if (II->use_empty() && II->onlyReadsMemory()) {
|
||
|
// jump to the normal destination branch.
|
||
|
- BranchInst::Create(II->getNormalDest(), II);
|
||
|
- II->getUnwindDest()->removePredecessor(II->getParent());
|
||
|
+ BasicBlock *NormalDestBB = II->getNormalDest();
|
||
|
+ BasicBlock *UnwindDestBB = II->getUnwindDest();
|
||
|
+ BranchInst::Create(NormalDestBB, II);
|
||
|
+ UnwindDestBB->removePredecessor(II->getParent());
|
||
|
II->eraseFromParent();
|
||
|
+ if (DDT)
|
||
|
+ DDT->deleteEdge(BB, UnwindDestBB);
|
||
|
} else
|
||
|
- changeToCall(II);
|
||
|
+ changeToCall(II, DDT);
|
||
|
Changed = true;
|
||
|
}
|
||
|
} else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Terminator)) {
|
||
|
@@ -1679,7 +1779,7 @@ static bool markAliveBlocks(Function &F,
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- Changed |= ConstantFoldTerminator(BB, true);
|
||
|
+ Changed |= ConstantFoldTerminator(BB, true, nullptr, DDT);
|
||
|
for (BasicBlock *Successor : successors(BB))
|
||
|
if (Reachable.insert(Successor).second)
|
||
|
Worklist.push_back(Successor);
|
||
|
@@ -1687,11 +1787,11 @@ static bool markAliveBlocks(Function &F,
|
||
|
return Changed;
|
||
|
}
|
||
|
|
||
|
-void llvm::removeUnwindEdge(BasicBlock *BB) {
|
||
|
+void llvm::removeUnwindEdge(BasicBlock *BB, DeferredDominance *DDT) {
|
||
|
TerminatorInst *TI = BB->getTerminator();
|
||
|
|
||
|
if (auto *II = dyn_cast<InvokeInst>(TI)) {
|
||
|
- changeToCall(II);
|
||
|
+ changeToCall(II, DDT);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
@@ -1719,15 +1819,18 @@ void llvm::removeUnwindEdge(BasicBlock *BB) {
|
||
|
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) {
|
||
|
+bool llvm::removeUnreachableBlocks(Function &F, LazyValueInfo *LVI,
|
||
|
+ DeferredDominance *DDT) {
|
||
|
SmallPtrSet<BasicBlock*, 16> Reachable;
|
||
|
- bool Changed = markAliveBlocks(F, Reachable);
|
||
|
+ bool Changed = markAliveBlocks(F, Reachable, DDT);
|
||
|
|
||
|
// If there are unreachable blocks in the CFG...
|
||
|
if (Reachable.size() == F.size())
|
||
|
@@ -1737,25 +1840,39 @@ 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...
|
||
|
- for (Function::iterator BB = ++F.begin(), E = F.end(); BB != E; ++BB) {
|
||
|
- if (Reachable.count(&*BB))
|
||
|
+ // 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))
|
||
|
continue;
|
||
|
-
|
||
|
- for (BasicBlock *Successor : successors(&*BB))
|
||
|
+ for (BasicBlock *Successor : successors(BB)) {
|
||
|
if (Reachable.count(Successor))
|
||
|
- Successor->removePredecessor(&*BB);
|
||
|
+ Successor->removePredecessor(BB);
|
||
|
+ if (DDT)
|
||
|
+ Updates.push_back({DominatorTree::Delete, BB, Successor});
|
||
|
+ }
|
||
|
if (LVI)
|
||
|
- LVI->eraseBlock(&*BB);
|
||
|
+ LVI->eraseBlock(BB);
|
||
|
BB->dropAllReferences();
|
||
|
}
|
||
|
|
||
|
- for (Function::iterator I = ++F.begin(); I != F.end();)
|
||
|
- if (!Reachable.count(&*I))
|
||
|
- I = F.getBasicBlockList().erase(I);
|
||
|
- else
|
||
|
+ 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 {
|
||
|
+ I = F.getBasicBlockList().erase(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 41bb8c9c820..27cd2263bea 100644
|
||
|
--- a/llvm/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll
|
||
|
+++ b/llvm/test/Analysis/LazyValueAnalysis/lvi-after-jumpthreading.ll
|
||
|
@@ -19,10 +19,13 @@ 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
|
||
|
new file mode 100644
|
||
|
index 00000000000..a5cf24d354c
|
||
|
--- /dev/null
|
||
|
+++ b/llvm/test/Transforms/JumpThreading/ddt-crash.ll
|
||
|
@@ -0,0 +1,265 @@
|
||
|
+; 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/ddt-crash2.ll b/llvm/test/Transforms/JumpThreading/ddt-crash2.ll
|
||
|
new file mode 100644
|
||
|
index 00000000000..92bea6a7dff
|
||
|
--- /dev/null
|
||
|
+++ b/llvm/test/Transforms/JumpThreading/ddt-crash2.ll
|
||
|
@@ -0,0 +1,40 @@
|
||
|
+; RUN: opt < %s -jump-threading -disable-output
|
||
|
+
|
||
|
+%struct.aaa = type { i8 }
|
||
|
+
|
||
|
+define void @chrome(%struct.aaa* noalias sret %arg) local_unnamed_addr #0 align 2 personality i8* bitcast (i32 (...)* @chrome2 to i8*) {
|
||
|
+bb:
|
||
|
+ %tmp = load i32, i32* undef, align 4
|
||
|
+ %tmp1 = icmp eq i32 %tmp, 0
|
||
|
+ br i1 %tmp1, label %bb2, label %bb13
|
||
|
+
|
||
|
+bb2:
|
||
|
+ %tmp3 = getelementptr inbounds %struct.aaa, %struct.aaa* %arg, i64 0, i32 0
|
||
|
+ %tmp4 = load i8, i8* %tmp3, align 1
|
||
|
+ %tmp5 = icmp eq i8 %tmp4, 0
|
||
|
+ br i1 %tmp5, label %bb6, label %bb7
|
||
|
+
|
||
|
+bb6:
|
||
|
+ store i8 0, i8* %tmp3, align 1
|
||
|
+ br label %bb7
|
||
|
+
|
||
|
+bb7:
|
||
|
+ %tmp8 = load i8, i8* %tmp3, align 1
|
||
|
+ %tmp9 = icmp ne i8 %tmp8, 0
|
||
|
+ %tmp10 = select i1 %tmp9, i1 true, i1 false
|
||
|
+ br i1 %tmp10, label %bb12, label %bb11
|
||
|
+
|
||
|
+bb11:
|
||
|
+ br label %bb12
|
||
|
+
|
||
|
+bb12:
|
||
|
+ br i1 %tmp9, label %bb14, label %bb13
|
||
|
+
|
||
|
+bb13:
|
||
|
+ unreachable
|
||
|
+
|
||
|
+bb14:
|
||
|
+ ret void
|
||
|
+}
|
||
|
+
|
||
|
+declare i32 @chrome2(...)
|
||
|
diff --git a/llvm/test/Transforms/JumpThreading/lvi-tristate.ll b/llvm/test/Transforms/JumpThreading/lvi-tristate.ll
|
||
|
new file mode 100644
|
||
|
index 00000000000..0aa87383347
|
||
|
--- /dev/null
|
||
|
+++ b/llvm/test/Transforms/JumpThreading/lvi-tristate.ll
|
||
|
@@ -0,0 +1,50 @@
|
||
|
+; 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
|
||
|
+}
|
||
|
diff --git a/llvm/unittests/IR/CMakeLists.txt b/llvm/unittests/IR/CMakeLists.txt
|
||
|
index 83f9dfd3176..15f869c6bd4 100644
|
||
|
--- a/llvm/unittests/IR/CMakeLists.txt
|
||
|
+++ b/llvm/unittests/IR/CMakeLists.txt
|
||
|
@@ -15,6 +15,7 @@ set(IRSources
|
||
|
ConstantsTest.cpp
|
||
|
DebugInfoTest.cpp
|
||
|
DebugTypeODRUniquingTest.cpp
|
||
|
+ DeferredDominanceTest.cpp
|
||
|
DominatorTreeTest.cpp
|
||
|
DominatorTreeBatchUpdatesTest.cpp
|
||
|
FunctionTest.cpp
|
||
|
diff --git a/llvm/unittests/IR/DeferredDominanceTest.cpp b/llvm/unittests/IR/DeferredDominanceTest.cpp
|
||
|
new file mode 100644
|
||
|
index 00000000000..96156f89a74
|
||
|
--- /dev/null
|
||
|
+++ b/llvm/unittests/IR/DeferredDominanceTest.cpp
|
||
|
@@ -0,0 +1,344 @@
|
||
|
+//===- llvm/unittests/IR/DeferredDominanceTest.cpp - DDT unit tests -------===//
|
||
|
+//
|
||
|
+// The LLVM Compiler Infrastructure
|
||
|
+//
|
||
|
+// This file is distributed under the University of Illinois Open Source
|
||
|
+// License. See LICENSE.TXT for details.
|
||
|
+//
|
||
|
+//===----------------------------------------------------------------------===//
|
||
|
+
|
||
|
+#include "llvm/AsmParser/Parser.h"
|
||
|
+#include "llvm/IR/Constants.h"
|
||
|
+#include "llvm/IR/Dominators.h"
|
||
|
+#include "llvm/IR/Instructions.h"
|
||
|
+#include "llvm/IR/LLVMContext.h"
|
||
|
+#include "llvm/IR/Module.h"
|
||
|
+#include "llvm/Support/SourceMgr.h"
|
||
|
+#include "gtest/gtest.h"
|
||
|
+
|
||
|
+using namespace llvm;
|
||
|
+
|
||
|
+static std::unique_ptr<Module> makeLLVMModule(LLVMContext &Context,
|
||
|
+ StringRef ModuleStr) {
|
||
|
+ SMDiagnostic Err;
|
||
|
+ std::unique_ptr<Module> M = parseAssemblyString(ModuleStr, Err, Context);
|
||
|
+ assert(M && "Bad LLVM IR?");
|
||
|
+ return M;
|
||
|
+}
|
||
|
+
|
||
|
+TEST(DeferredDominance, BasicOperations) {
|
||
|
+ StringRef FuncName = "f";
|
||
|
+ StringRef ModuleString =
|
||
|
+ "define i32 @f(i32 %i, i32 *%p) {\n"
|
||
|
+ " bb0:\n"
|
||
|
+ " store i32 %i, i32 *%p\n"
|
||
|
+ " switch i32 %i, label %bb1 [\n"
|
||
|
+ " i32 0, label %bb2\n"
|
||
|
+ " i32 1, label %bb2\n"
|
||
|
+ " i32 2, label %bb3\n"
|
||
|
+ " ]\n"
|
||
|
+ " bb1:\n"
|
||
|
+ " ret i32 1\n"
|
||
|
+ " bb2:\n"
|
||
|
+ " ret i32 2\n"
|
||
|
+ " bb3:\n"
|
||
|
+ " ret i32 3\n"
|
||
|
+ "}\n";
|
||
|
+ // Make the module.
|
||
|
+ LLVMContext Context;
|
||
|
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
|
||
|
+ Function *F = M->getFunction(FuncName);
|
||
|
+ ASSERT_NE(F, nullptr) << "Couldn't get function " << FuncName << ".";
|
||
|
+
|
||
|
+ // Make the DDT.
|
||
|
+ DominatorTree DT(*F);
|
||
|
+ DeferredDominance DDT(DT);
|
||
|
+ ASSERT_TRUE(DDT.flush().verify());
|
||
|
+
|
||
|
+ Function::iterator FI = F->begin();
|
||
|
+ BasicBlock *BB0 = &*FI++;
|
||
|
+ BasicBlock *BB1 = &*FI++;
|
||
|
+ BasicBlock *BB2 = &*FI++;
|
||
|
+ BasicBlock *BB3 = &*FI++;
|
||
|
+
|
||
|
+ // Test discards of invalid self-domination updates. These use the single
|
||
|
+ // short-hand interface but are still queued inside DDT.
|
||
|
+ DDT.deleteEdge(BB0, BB0);
|
||
|
+ DDT.insertEdge(BB1, BB1);
|
||
|
+
|
||
|
+ // Delete edge bb0 -> bb3 and push the update twice to verify duplicate
|
||
|
+ // entries are discarded.
|
||
|
+ std::vector<DominatorTree::UpdateType> Updates;
|
||
|
+ Updates.reserve(4);
|
||
|
+ Updates.push_back({DominatorTree::Delete, BB0, BB3});
|
||
|
+ Updates.push_back({DominatorTree::Delete, BB0, BB3});
|
||
|
+
|
||
|
+ // Unnecessary Insert: no edge bb1 -> bb2 after change to bb0.
|
||
|
+ Updates.push_back({DominatorTree::Insert, BB1, BB2});
|
||
|
+ // Unnecessary Delete: edge exists bb0 -> bb1 after change to bb0.
|
||
|
+ Updates.push_back({DominatorTree::Delete, BB0, BB1});
|
||
|
+
|
||
|
+ // CFG Change: remove edge bb0 -> bb3 and one duplicate edge bb0 -> bb2.
|
||
|
+ EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 4u);
|
||
|
+ BB0->getTerminator()->eraseFromParent();
|
||
|
+ BranchInst::Create(BB1, BB2, ConstantInt::getTrue(F->getContext()), BB0);
|
||
|
+ EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 2u);
|
||
|
+
|
||
|
+ // Deletion of a BasicBlock is an immediate event. We remove all uses to the
|
||
|
+ // contained Instructions and change the Terminator to "unreachable" when
|
||
|
+ // queued for deletion. Its parent is still F until DDT.flush() is called. We
|
||
|
+ // don't defer this action because it can cause problems for other transforms
|
||
|
+ // or analysis as it's part of the actual CFG. We only defer updates to the
|
||
|
+ // DominatorTree. This code will crash if it is placed before the
|
||
|
+ // BranchInst::Create() call above.
|
||
|
+ ASSERT_FALSE(isa<UnreachableInst>(BB3->getTerminator()));
|
||
|
+ EXPECT_FALSE(DDT.pendingDeletedBB(BB3));
|
||
|
+ DDT.deleteBB(BB3);
|
||
|
+ EXPECT_TRUE(DDT.pendingDeletedBB(BB3));
|
||
|
+ ASSERT_TRUE(isa<UnreachableInst>(BB3->getTerminator()));
|
||
|
+ EXPECT_EQ(BB3->getParent(), F);
|
||
|
+
|
||
|
+ // Verify. Updates to DDT must be applied *after* all changes to the CFG
|
||
|
+ // (including block deletion).
|
||
|
+ DDT.applyUpdates(Updates);
|
||
|
+ ASSERT_TRUE(DDT.flush().verify());
|
||
|
+}
|
||
|
+
|
||
|
+TEST(DeferredDominance, PairedUpdate) {
|
||
|
+ StringRef FuncName = "f";
|
||
|
+ StringRef ModuleString =
|
||
|
+ "define i32 @f(i32 %i, i32 *%p) {\n"
|
||
|
+ " bb0:\n"
|
||
|
+ " store i32 %i, i32 *%p\n"
|
||
|
+ " switch i32 %i, label %bb1 [\n"
|
||
|
+ " i32 0, label %bb2\n"
|
||
|
+ " i32 1, label %bb2\n"
|
||
|
+ " ]\n"
|
||
|
+ " bb1:\n"
|
||
|
+ " ret i32 1\n"
|
||
|
+ " bb2:\n"
|
||
|
+ " ret i32 2\n"
|
||
|
+ "}\n";
|
||
|
+ // Make the module.
|
||
|
+ LLVMContext Context;
|
||
|
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
|
||
|
+ Function *F = M->getFunction(FuncName);
|
||
|
+ ASSERT_NE(F, nullptr) << "Couldn't get function " << FuncName << ".";
|
||
|
+
|
||
|
+ // Make the DDT.
|
||
|
+ DominatorTree DT(*F);
|
||
|
+ DeferredDominance DDT(DT);
|
||
|
+ ASSERT_TRUE(DDT.flush().verify());
|
||
|
+
|
||
|
+ Function::iterator FI = F->begin();
|
||
|
+ BasicBlock *BB0 = &*FI++;
|
||
|
+ BasicBlock *BB1 = &*FI++;
|
||
|
+ BasicBlock *BB2 = &*FI++;
|
||
|
+
|
||
|
+ // CFG Change: only edge from bb0 is bb0 -> bb1.
|
||
|
+ EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 3u);
|
||
|
+ BB0->getTerminator()->eraseFromParent();
|
||
|
+ BranchInst::Create(BB1, BB0);
|
||
|
+ EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 1u);
|
||
|
+
|
||
|
+ // Must be done after the CFG change. The applyUpdate() routine analyzes the
|
||
|
+ // current state of the CFG.
|
||
|
+ DDT.deleteEdge(BB0, BB2);
|
||
|
+
|
||
|
+ // CFG Change: bb0 now has bb0 -> bb1 and bb0 -> bb2.
|
||
|
+ // With this change no dominance has been altered from the original IR. DT
|
||
|
+ // doesn't care if the type of TerminatorInstruction changed, only if the
|
||
|
+ // unique edges have.
|
||
|
+ EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 1u);
|
||
|
+ BB0->getTerminator()->eraseFromParent();
|
||
|
+ BranchInst::Create(BB1, BB2, ConstantInt::getTrue(F->getContext()), BB0);
|
||
|
+ EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 2u);
|
||
|
+
|
||
|
+ // Must be done after the CFG change. The applyUpdate() routine analyzes the
|
||
|
+ // current state of the CFG. This DDT update pairs with the previous one and
|
||
|
+ // is cancelled out before ever applying updates to DT.
|
||
|
+ DDT.insertEdge(BB0, BB2);
|
||
|
+
|
||
|
+ // Test the empty DeletedBB list.
|
||
|
+ EXPECT_FALSE(DDT.pendingDeletedBB(BB0));
|
||
|
+ EXPECT_FALSE(DDT.pendingDeletedBB(BB1));
|
||
|
+ EXPECT_FALSE(DDT.pendingDeletedBB(BB2));
|
||
|
+
|
||
|
+ // The DT has no changes, this flush() simply returns a reference to the
|
||
|
+ // internal DT calculated at the beginning of this test.
|
||
|
+ ASSERT_TRUE(DDT.flush().verify());
|
||
|
+}
|
||
|
+
|
||
|
+TEST(DeferredDominance, ReplaceEntryBB) {
|
||
|
+ StringRef FuncName = "f";
|
||
|
+ StringRef ModuleString =
|
||
|
+ "define i32 @f() {\n"
|
||
|
+ "bb0:\n"
|
||
|
+ " br label %bb1\n"
|
||
|
+ " bb1:\n"
|
||
|
+ " ret i32 1\n"
|
||
|
+ "}\n";
|
||
|
+ // Make the module.
|
||
|
+ LLVMContext Context;
|
||
|
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
|
||
|
+ Function *F = M->getFunction(FuncName);
|
||
|
+ ASSERT_NE(F, nullptr) << "Couldn't get function " << FuncName << ".";
|
||
|
+
|
||
|
+ // Make the DDT.
|
||
|
+ DominatorTree DT(*F);
|
||
|
+ DeferredDominance DDT(DT);
|
||
|
+ ASSERT_TRUE(DDT.flush().verify());
|
||
|
+
|
||
|
+ Function::iterator FI = F->begin();
|
||
|
+ BasicBlock *BB0 = &*FI++;
|
||
|
+ BasicBlock *BB1 = &*FI++;
|
||
|
+
|
||
|
+ // Add a block as the new function entry BB. We also link it to BB0.
|
||
|
+ BasicBlock *NewEntry =
|
||
|
+ BasicBlock::Create(F->getContext(), "new_entry", F, BB0);
|
||
|
+ BranchInst::Create(BB0, NewEntry);
|
||
|
+ EXPECT_EQ(F->begin()->getName(), NewEntry->getName());
|
||
|
+ EXPECT_TRUE(&F->getEntryBlock() == NewEntry);
|
||
|
+
|
||
|
+ // Insert the new edge between new_eentry -> bb0. Without this the
|
||
|
+ // recalculate() call below will not actually recalculate the DT as there
|
||
|
+ // are no changes pending and no blocks deleted.
|
||
|
+ DDT.insertEdge(NewEntry, BB0);
|
||
|
+
|
||
|
+ // Changing the Entry BB requires a full recalulation.
|
||
|
+ DDT.recalculate(*F);
|
||
|
+ ASSERT_TRUE(DDT.flush().verify());
|
||
|
+
|
||
|
+ // CFG Change: remove new_edge -> bb0 and redirect to new_edge -> bb1.
|
||
|
+ EXPECT_EQ(NewEntry->getTerminator()->getNumSuccessors(), 1u);
|
||
|
+ NewEntry->getTerminator()->eraseFromParent();
|
||
|
+ BranchInst::Create(BB1, NewEntry);
|
||
|
+ EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 1u);
|
||
|
+
|
||
|
+ // Update the DDT. At this point bb0 now has no predecessors but is still a
|
||
|
+ // Child of F.
|
||
|
+ DDT.applyUpdates({{DominatorTree::Delete, NewEntry, BB0},
|
||
|
+ {DominatorTree::Insert, NewEntry, BB1}});
|
||
|
+ ASSERT_TRUE(DDT.flush().verify());
|
||
|
+
|
||
|
+ // Now remove bb0 from F.
|
||
|
+ ASSERT_FALSE(isa<UnreachableInst>(BB0->getTerminator()));
|
||
|
+ EXPECT_FALSE(DDT.pendingDeletedBB(BB0));
|
||
|
+ DDT.deleteBB(BB0);
|
||
|
+ EXPECT_TRUE(DDT.pendingDeletedBB(BB0));
|
||
|
+ ASSERT_TRUE(isa<UnreachableInst>(BB0->getTerminator()));
|
||
|
+ EXPECT_EQ(BB0->getParent(), F);
|
||
|
+
|
||
|
+ // Perform a full recalculation of the DDT. It is not necessary here but we
|
||
|
+ // do this to test the case when there are no pending DT updates but there are
|
||
|
+ // pending deleted BBs.
|
||
|
+ DDT.recalculate(*F);
|
||
|
+ ASSERT_TRUE(DDT.flush().verify());
|
||
|
+}
|
||
|
+
|
||
|
+TEST(DeferredDominance, InheritedPreds) {
|
||
|
+ StringRef FuncName = "f";
|
||
|
+ StringRef ModuleString =
|
||
|
+ "define i32 @f(i32 %i, i32 *%p) {\n"
|
||
|
+ " bb0:\n"
|
||
|
+ " store i32 %i, i32 *%p\n"
|
||
|
+ " switch i32 %i, label %bb1 [\n"
|
||
|
+ " i32 2, label %bb2\n"
|
||
|
+ " i32 3, label %bb3\n"
|
||
|
+ " ]\n"
|
||
|
+ " bb1:\n"
|
||
|
+ " br label %bb3\n"
|
||
|
+ " bb2:\n"
|
||
|
+ " br label %bb3\n"
|
||
|
+ " bb3:\n"
|
||
|
+ " ret i32 3\n"
|
||
|
+ "}\n";
|
||
|
+ // Make the module.
|
||
|
+ LLVMContext Context;
|
||
|
+ std::unique_ptr<Module> M = makeLLVMModule(Context, ModuleString);
|
||
|
+ Function *F = M->getFunction(FuncName);
|
||
|
+ ASSERT_NE(F, nullptr) << "Couldn't get function " << FuncName << ".";
|
||
|
+
|
||
|
+ // Make the DDT.
|
||
|
+ DominatorTree DT(*F);
|
||
|
+ DeferredDominance DDT(DT);
|
||
|
+ ASSERT_TRUE(DDT.flush().verify());
|
||
|
+
|
||
|
+ Function::iterator FI = F->begin();
|
||
|
+ BasicBlock *BB0 = &*FI++;
|
||
|
+ BasicBlock *BB1 = &*FI++;
|
||
|
+ BasicBlock *BB2 = &*FI++;
|
||
|
+ BasicBlock *BB3 = &*FI++;
|
||
|
+
|
||
|
+ // There are several CFG locations where we have:
|
||
|
+ //
|
||
|
+ // pred1..predN
|
||
|
+ // | |
|
||
|
+ // +> curr <+ converted into: pred1..predN curr
|
||
|
+ // | | |
|
||
|
+ // v +> succ <+
|
||
|
+ // succ
|
||
|
+ //
|
||
|
+ // There is a specific shape of this we have to be careful of:
|
||
|
+ //
|
||
|
+ // pred1..predN
|
||
|
+ // || |
|
||
|
+ // |+> curr <+ converted into: pred1..predN curr
|
||
|
+ // | | | |
|
||
|
+ // | v +> succ <+
|
||
|
+ // +-> succ
|
||
|
+ //
|
||
|
+ // While the final CFG form is functionally identical the updates to
|
||
|
+ // DDT are not. In the first case we must have DDT.insertEdge(Pred1, Succ)
|
||
|
+ // while in the latter case we must *NOT* have DDT.insertEdge(Pred1, Succ).
|
||
|
+
|
||
|
+ // CFG Change: bb0 now only has bb0 -> bb1 and bb0 -> bb3. We are preparing to
|
||
|
+ // remove bb2.
|
||
|
+ EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 3u);
|
||
|
+ BB0->getTerminator()->eraseFromParent();
|
||
|
+ BranchInst::Create(BB1, BB3, ConstantInt::getTrue(F->getContext()), BB0);
|
||
|
+ EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 2u);
|
||
|
+
|
||
|
+ // Remove bb2 from F. This has to happen before the call to applyUpdates() for
|
||
|
+ // DDT to detect there is no longer an edge between bb2 -> bb3. The deleteBB()
|
||
|
+ // method converts bb2's TI into "unreachable".
|
||
|
+ ASSERT_FALSE(isa<UnreachableInst>(BB2->getTerminator()));
|
||
|
+ EXPECT_FALSE(DDT.pendingDeletedBB(BB2));
|
||
|
+ DDT.deleteBB(BB2);
|
||
|
+ EXPECT_TRUE(DDT.pendingDeletedBB(BB2));
|
||
|
+ ASSERT_TRUE(isa<UnreachableInst>(BB2->getTerminator()));
|
||
|
+ EXPECT_EQ(BB2->getParent(), F);
|
||
|
+
|
||
|
+ // Queue up the DDT updates.
|
||
|
+ std::vector<DominatorTree::UpdateType> Updates;
|
||
|
+ Updates.reserve(4);
|
||
|
+ Updates.push_back({DominatorTree::Delete, BB0, BB2});
|
||
|
+ Updates.push_back({DominatorTree::Delete, BB2, BB3});
|
||
|
+
|
||
|
+ // Handle the specific shape case next.
|
||
|
+ // CFG Change: bb0 now only branches to bb3. We are preparing to remove bb1.
|
||
|
+ EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 2u);
|
||
|
+ BB0->getTerminator()->eraseFromParent();
|
||
|
+ BranchInst::Create(BB3, BB0);
|
||
|
+ EXPECT_EQ(BB0->getTerminator()->getNumSuccessors(), 1u);
|
||
|
+
|
||
|
+ // Remove bb1 from F. This has to happen before the call to applyUpdates() for
|
||
|
+ // DDT to detect there is no longer an edge between bb1 -> bb3. The deleteBB()
|
||
|
+ // method converts bb1's TI into "unreachable".
|
||
|
+ ASSERT_FALSE(isa<UnreachableInst>(BB1->getTerminator()));
|
||
|
+ EXPECT_FALSE(DDT.pendingDeletedBB(BB1));
|
||
|
+ DDT.deleteBB(BB1);
|
||
|
+ EXPECT_TRUE(DDT.pendingDeletedBB(BB1));
|
||
|
+ ASSERT_TRUE(isa<UnreachableInst>(BB1->getTerminator()));
|
||
|
+ EXPECT_EQ(BB1->getParent(), F);
|
||
|
+
|
||
|
+ // Update the DDT. In this case we don't call DDT.insertEdge(BB0, BB3) because
|
||
|
+ // the edge previously existed at the start of this test when DT was first
|
||
|
+ // created.
|
||
|
+ Updates.push_back({DominatorTree::Delete, BB0, BB1});
|
||
|
+ Updates.push_back({DominatorTree::Delete, BB1, BB3});
|
||
|
+
|
||
|
+ // Verify everything.
|
||
|
+ DDT.applyUpdates(Updates);
|
||
|
+ ASSERT_TRUE(DDT.flush().verify());
|
||
|
+}
|
||
|
--
|
||
|
2.18.0
|
||
|
|