diff options
Diffstat (limited to 'lib/IR/Dominators.cpp')
| -rw-r--r-- | lib/IR/Dominators.cpp | 245 | 
1 files changed, 209 insertions, 36 deletions
diff --git a/lib/IR/Dominators.cpp b/lib/IR/Dominators.cpp index ad448a3f240c..d8971e05f476 100644 --- a/lib/IR/Dominators.cpp +++ b/lib/IR/Dominators.cpp @@ -17,7 +17,9 @@  #include "llvm/IR/Dominators.h"  #include "llvm/ADT/DepthFirstIterator.h"  #include "llvm/ADT/SmallPtrSet.h" +#include "llvm/Config/llvm-config.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" @@ -27,16 +29,17 @@  #include <algorithm>  using namespace llvm; -// Always verify dominfo if expensive checking is enabled. -#ifdef EXPENSIVE_CHECKS -bool llvm::VerifyDomInfo = true; -#else  bool llvm::VerifyDomInfo = false; -#endif  static cl::opt<bool, true>      VerifyDomInfoX("verify-dom-info", cl::location(VerifyDomInfo), cl::Hidden,                     cl::desc("Verify dominator info (time consuming)")); +#ifdef EXPENSIVE_CHECKS +static constexpr bool ExpensiveChecksEnabled = true; +#else +static constexpr bool ExpensiveChecksEnabled = false; +#endif +  bool BasicBlockEdge::isSingleEdge() const {    const TerminatorInst *TI = Start->getTerminator();    unsigned NumEdgesToEnd = 0; @@ -87,9 +90,11 @@ template void llvm::DomTreeBuilder::ApplyUpdates<DomTreeBuilder::BBPostDomTree>(      DomTreeBuilder::BBPostDomTree &DT, DomTreeBuilder::BBUpdates);  template bool llvm::DomTreeBuilder::Verify<DomTreeBuilder::BBDomTree>( -    const DomTreeBuilder::BBDomTree &DT); +    const DomTreeBuilder::BBDomTree &DT, +    DomTreeBuilder::BBDomTree::VerificationLevel VL);  template bool llvm::DomTreeBuilder::Verify<DomTreeBuilder::BBPostDomTree>( -    const DomTreeBuilder::BBPostDomTree &DT); +    const DomTreeBuilder::BBPostDomTree &DT, +    DomTreeBuilder::BBPostDomTree::VerificationLevel VL);  bool DominatorTree::invalidate(Function &F, const PreservedAnalyses &PA,                                 FunctionAnalysisManager::Invalidator &) { @@ -302,31 +307,6 @@ bool DominatorTree::isReachableFromEntry(const Use &U) const {    return isReachableFromEntry(I->getParent());  } -void DominatorTree::verifyDomTree() const { -  // Perform the expensive checks only when VerifyDomInfo is set. -  if (VerifyDomInfo && !verify()) { -    errs() << "\n~~~~~~~~~~~\n\t\tDomTree verification failed!\n~~~~~~~~~~~\n"; -    print(errs()); -    abort(); -  } - -  Function &F = *getRoot()->getParent(); - -  DominatorTree OtherDT; -  OtherDT.recalculate(F); -  if (compare(OtherDT)) { -    errs() << "DominatorTree for function " << F.getName() -           << " is not up to date!\nComputed:\n"; -    print(errs()); -    errs() << "\nActual:\n"; -    OtherDT.print(errs()); -    errs() << "\nCFG:\n"; -    F.print(errs()); -    errs().flush(); -    abort(); -  } -} -  //===----------------------------------------------------------------------===//  //  DominatorTreeAnalysis and related pass implementations  //===----------------------------------------------------------------------===// @@ -357,8 +337,9 @@ PreservedAnalyses DominatorTreePrinterPass::run(Function &F,  PreservedAnalyses DominatorTreeVerifierPass::run(Function &F,                                                   FunctionAnalysisManager &AM) { -  AM.getResult<DominatorTreeAnalysis>(F).verifyDomTree(); - +  auto &DT = AM.getResult<DominatorTreeAnalysis>(F); +  assert(DT.verify()); +  (void)DT;    return PreservedAnalyses::all();  } @@ -381,11 +362,203 @@ bool DominatorTreeWrapperPass::runOnFunction(Function &F) {  }  void DominatorTreeWrapperPass::verifyAnalysis() const { -    if (VerifyDomInfo) -      DT.verifyDomTree(); +  if (VerifyDomInfo) +    assert(DT.verify(DominatorTree::VerificationLevel::Full)); +  else if (ExpensiveChecksEnabled) +    assert(DT.verify(DominatorTree::VerificationLevel::Basic));  }  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. +// +//===----------------------------------------------------------------------===// + +/// 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()); +    } +} + +/// 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); +} + +/// 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); +} + +/// 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); +} + +/// 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; +} + +/// Returns true if pending DT updates are queued for a flush() event. +bool DeferredDominance::pending() { return !PendUpdates.empty(); } + +/// 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; +} + +/// 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(); +  } +} + +/// 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; +}  | 
