From: Vedant Kumar Date: Mon, 19 Nov 2018 19:54:27 +0000 (+0000) Subject: [IR] Add hasNPredecessors, hasNPredecessorsOrMore to BasicBlock X-Git-Tag: llvmorg-8.0.0-rc1~3913 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4de31bba51b884bdfc7eb688958d9dc517da8353;p=platform%2Fupstream%2Fllvm.git [IR] Add hasNPredecessors, hasNPredecessorsOrMore to BasicBlock Add methods to BasicBlock which make it easier to efficiently check whether a block has N (or more) predecessors. This can be more efficient than using pred_size(), which is a linear time operation. We might consider adding similar methods for successors. I haven't done so in this patch because succ_size() is already O(1). With this patch applied, I measured a 0.065% compile-time reduction in user time for running `opt -O3` on the sqlite3 amalgamation (30 trials). The change in mergeStoreIntoSuccessor alone saves 45 million linked list iterations in a stage2 Release build of llc. See llvm.org/PR39702 for a harder but more general way of achieving similar results. Differential Revision: https://reviews.llvm.org/D54686 llvm-svn: 347256 --- diff --git a/llvm/include/llvm/ADT/STLExtras.h b/llvm/include/llvm/ADT/STLExtras.h index 4a93ee5..ba31392 100644 --- a/llvm/include/llvm/ADT/STLExtras.h +++ b/llvm/include/llvm/ADT/STLExtras.h @@ -1405,6 +1405,40 @@ auto apply_tuple(F &&f, Tuple &&t) -> decltype(detail::apply_tuple_impl( Indices{}); } +/// Return true if the sequence [Begin, End) has exactly N items. Runs in O(N) +/// time. Not meant for use with random-access iterators. +template +bool hasNItems( + IterTy &&Begin, IterTy &&End, unsigned N, + typename std::enable_if< + !std::is_same< + typename std::iterator_traits::type>::iterator_category, + std::random_access_iterator_tag>::value, + void>::type * = nullptr) { + for (; N; --N, ++Begin) + if (Begin == End) + return false; // Too few. + return Begin == End; +} + +/// Return true if the sequence [Begin, End) has N or more items. Runs in O(N) +/// time. Not meant for use with random-access iterators. +template +bool hasNItemsOrMore( + IterTy &&Begin, IterTy &&End, unsigned N, + typename std::enable_if< + !std::is_same< + typename std::iterator_traits::type>::iterator_category, + std::random_access_iterator_tag>::value, + void>::type * = nullptr) { + for (; N; --N, ++Begin) + if (Begin == End) + return false; // Too few. + return true; +} + } // end namespace llvm #endif // LLVM_ADT_STLEXTRAS_H diff --git a/llvm/include/llvm/IR/BasicBlock.h b/llvm/include/llvm/IR/BasicBlock.h index 7244bba..99eac33 100644 --- a/llvm/include/llvm/IR/BasicBlock.h +++ b/llvm/include/llvm/IR/BasicBlock.h @@ -237,6 +237,12 @@ public: static_cast(this)->getUniquePredecessor()); } + /// Return true if this block has exactly N predecessors. + bool hasNPredecessors(unsigned N) const; + + /// Return true if this block has N predecessors or more. + bool hasNPredecessorsOrMore(unsigned N) const; + /// Return the successor of this block if it has a single successor. /// Otherwise return a null pointer. /// diff --git a/llvm/include/llvm/IR/CFG.h b/llvm/include/llvm/IR/CFG.h index 4140c8a..8385c46 100644 --- a/llvm/include/llvm/IR/CFG.h +++ b/llvm/include/llvm/IR/CFG.h @@ -117,6 +117,8 @@ inline const_pred_iterator pred_end(const BasicBlock *BB) { inline bool pred_empty(const BasicBlock *BB) { return pred_begin(BB) == pred_end(BB); } +/// Get the number of predecessors of \p BB. This is a linear time operation. +/// Use \ref BasicBlock::hasNPredecessors() or hasNPredecessorsOrMore if able. inline unsigned pred_size(const BasicBlock *BB) { return std::distance(pred_begin(BB), pred_end(BB)); } diff --git a/llvm/lib/Analysis/MemorySSAUpdater.cpp b/llvm/lib/Analysis/MemorySSAUpdater.cpp index 1ac5818..6c817d2 100644 --- a/llvm/lib/Analysis/MemorySSAUpdater.cpp +++ b/llvm/lib/Analysis/MemorySSAUpdater.cpp @@ -1022,7 +1022,7 @@ void MemorySSAUpdater::wireOldPredecessorsToNewImmediatePredecessor( MemoryPhi *Phi = MSSA->getMemoryAccess(Old); if (!Phi) return; - if (pred_size(Old) == 1) { + if (Old->hasNPredecessors(1)) { assert(pred_size(New) == Preds.size() && "Should have moved all predecessors."); MSSA->moveTo(Phi, New, MemorySSA::Beginning); diff --git a/llvm/lib/IR/BasicBlock.cpp b/llvm/lib/IR/BasicBlock.cpp index 12ab2e2..e9eb686 100644 --- a/llvm/lib/IR/BasicBlock.cpp +++ b/llvm/lib/IR/BasicBlock.cpp @@ -260,6 +260,14 @@ const BasicBlock *BasicBlock::getUniquePredecessor() const { return PredBB; } +bool BasicBlock::hasNPredecessors(unsigned N) const { + return hasNItems(pred_begin(this), pred_end(this), N); +} + +bool BasicBlock::hasNPredecessorsOrMore(unsigned N) const { + return hasNItemsOrMore(pred_begin(this), pred_end(this), N); +} + const BasicBlock *BasicBlock::getSingleSuccessor() const { succ_const_iterator SI = succ_begin(this), E = succ_end(this); if (SI == E) return nullptr; // no successors diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp index 6dc48ad..dc8af6b 100644 --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -130,20 +130,11 @@ void Value::destroyValueName() { } bool Value::hasNUses(unsigned N) const { - const_use_iterator UI = use_begin(), E = use_end(); - - for (; N; --N, ++UI) - if (UI == E) return false; // Too few. - return UI == E; + return hasNItems(use_begin(), use_end(), N); } bool Value::hasNUsesOrMore(unsigned N) const { - const_use_iterator UI = use_begin(), E = use_end(); - - for (; N; --N, ++UI) - if (UI == E) return false; // Too few. - - return true; + return hasNItemsOrMore(use_begin(), use_end(), N); } bool Value::isUsedInBasicBlock(const BasicBlock *BB) const { diff --git a/llvm/lib/Transforms/IPO/PartialInlining.cpp b/llvm/lib/Transforms/IPO/PartialInlining.cpp index a96342b..00ad0d8 100644 --- a/llvm/lib/Transforms/IPO/PartialInlining.cpp +++ b/llvm/lib/Transforms/IPO/PartialInlining.cpp @@ -403,7 +403,7 @@ PartialInlinerImpl::computeOutliningColdRegionsInfo(Function *F, auto IsSingleEntry = [](SmallVectorImpl &BlockList) { BasicBlock *Dom = BlockList.front(); - return BlockList.size() > 1 && pred_size(Dom) == 1; + return BlockList.size() > 1 && Dom->hasNPredecessors(1); }; auto IsSingleExit = diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp index 670168b..e2f5460 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -1526,7 +1526,7 @@ bool InstCombiner::mergeStoreIntoSuccessor(StoreInst &SI) { // Check if the successor block has exactly 2 incoming edges. BasicBlock *StoreBB = SI.getParent(); BasicBlock *DestBB = StoreBB->getTerminator()->getSuccessor(0); - if (pred_size(DestBB) != 2) + if (!DestBB->hasNPredecessors(2)) return false; // Capture the other block (the block that doesn't contain our store). diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 0dcd737..d9e0c15 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -682,10 +682,9 @@ void llvm::MergeBasicBlockIntoOnlyPred(BasicBlock *DestBB, // DTU updates: Collect all the edges that enter // PredBB. These dominator edges will be redirected to DestBB. - std::vector Updates; + SmallVector Updates; if (DTU) { - Updates.reserve(1 + (2 * pred_size(PredBB))); Updates.push_back({DominatorTree::Delete, PredBB, DestBB}); for (auto I = pred_begin(PredBB), E = pred_end(PredBB); I != E; ++I) { Updates.push_back({DominatorTree::Delete, *I, PredBB}); @@ -989,9 +988,8 @@ bool llvm::TryToSimplifyUncondBranchFromEmptyBlock(BasicBlock *BB, LLVM_DEBUG(dbgs() << "Killing Trivial BB: \n" << *BB); - std::vector Updates; + SmallVector Updates; if (DTU) { - Updates.reserve(1 + (2 * pred_size(BB))); Updates.push_back({DominatorTree::Delete, BB, Succ}); // All predecessors of BB will be moved to Succ. for (auto I = pred_begin(BB), E = pred_end(BB); I != E; ++I) { diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index af9d2ea..cbf9fc1 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -693,7 +693,7 @@ Value *SimplifyCFGOpt::isValueEqualityComparison(Instruction *TI) { if (SwitchInst *SI = dyn_cast(TI)) { // Do not permit merging of large switch instructions into their // predecessors unless there is only one predecessor. - if (SI->getNumSuccessors() * pred_size(SI->getParent()) <= 128) + if (!SI->getParent()->hasNPredecessorsOrMore(128 / SI->getNumSuccessors())) CV = SI->getCondition(); } else if (BranchInst *BI = dyn_cast(TI)) if (BI->isConditional() && BI->getCondition()->hasOneUse()) @@ -2890,7 +2890,7 @@ static Value *ensureValueAvailableInSuccessor(Value *V, BasicBlock *BB, if (!AlternativeV) break; - assert(pred_size(Succ) == 2); + assert(Succ->hasNPredecessors(2)); auto PredI = pred_begin(Succ); BasicBlock *OtherPredBB = *PredI == BB ? *++PredI : *PredI; if (PHI->getIncomingValueForBlock(OtherPredBB) == AlternativeV) @@ -5774,7 +5774,7 @@ bool SimplifyCFGOpt::SimplifyUncondBranch(BranchInst *BI, // backedge, so we can eliminate BB. bool NeedCanonicalLoop = Options.NeedCanonicalLoop && - (LoopHeaders && pred_size(BB) > 1 && + (LoopHeaders && BB->hasNPredecessorsOrMore(2) && (LoopHeaders->count(BB) || LoopHeaders->count(Succ))); BasicBlock::iterator I = BB->getFirstNonPHIOrDbg()->getIterator(); if (I->isTerminator() && BB != &BB->getParent()->getEntryBlock() && diff --git a/llvm/lib/Transforms/Vectorize/VPlan.cpp b/llvm/lib/Transforms/Vectorize/VPlan.cpp index dad733b..05a5400 100644 --- a/llvm/lib/Transforms/Vectorize/VPlan.cpp +++ b/llvm/lib/Transforms/Vectorize/VPlan.cpp @@ -468,7 +468,7 @@ void VPlan::updateDominatorTree(DominatorTree *DT, BasicBlock *LoopPreHeaderBB, "One successor of a basic block does not lead to the other."); assert(InterimSucc->getSinglePredecessor() && "Interim successor has more than one predecessor."); - assert(pred_size(PostDomSucc) == 2 && + assert(PostDomSucc->hasNPredecessors(2) && "PostDom successor has more than two predecessors."); DT->addNewBlock(InterimSucc, BB); DT->addNewBlock(PostDomSucc, BB);