[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
This commit is contained in:
parent
740122fb8c
commit
4de31bba51
|
@ -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 <typename IterTy>
|
||||
bool hasNItems(
|
||||
IterTy &&Begin, IterTy &&End, unsigned N,
|
||||
typename std::enable_if<
|
||||
!std::is_same<
|
||||
typename std::iterator_traits<typename std::remove_reference<
|
||||
decltype(Begin)>::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 <typename IterTy>
|
||||
bool hasNItemsOrMore(
|
||||
IterTy &&Begin, IterTy &&End, unsigned N,
|
||||
typename std::enable_if<
|
||||
!std::is_same<
|
||||
typename std::iterator_traits<typename std::remove_reference<
|
||||
decltype(Begin)>::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
|
||||
|
|
|
@ -237,6 +237,12 @@ public:
|
|||
static_cast<const BasicBlock *>(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.
|
||||
///
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -403,7 +403,7 @@ PartialInlinerImpl::computeOutliningColdRegionsInfo(Function *F,
|
|||
|
||||
auto IsSingleEntry = [](SmallVectorImpl<BasicBlock *> &BlockList) {
|
||||
BasicBlock *Dom = BlockList.front();
|
||||
return BlockList.size() > 1 && pred_size(Dom) == 1;
|
||||
return BlockList.size() > 1 && Dom->hasNPredecessors(1);
|
||||
};
|
||||
|
||||
auto IsSingleExit =
|
||||
|
|
|
@ -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).
|
||||
|
|
|
@ -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 <DominatorTree::UpdateType> Updates;
|
||||
SmallVector<DominatorTree::UpdateType, 32> 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<DominatorTree::UpdateType> Updates;
|
||||
SmallVector<DominatorTree::UpdateType, 32> 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) {
|
||||
|
|
|
@ -693,7 +693,7 @@ Value *SimplifyCFGOpt::isValueEqualityComparison(Instruction *TI) {
|
|||
if (SwitchInst *SI = dyn_cast<SwitchInst>(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<BranchInst>(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() &&
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue