[llvm] 51dfe3c - [IR] Add PHINode::removeIncomingValueIf() (NFC)
Nikita Popov via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 17 00:09:47 PDT 2023
Author: Nikita Popov
Date: 2023-08-17T09:09:14+02:00
New Revision: 51dfe3cb3bdf543186fb3fba5085f2376047bb33
URL: https://github.com/llvm/llvm-project/commit/51dfe3cb3bdf543186fb3fba5085f2376047bb33
DIFF: https://github.com/llvm/llvm-project/commit/51dfe3cb3bdf543186fb3fba5085f2376047bb33.diff
LOG: [IR] Add PHINode::removeIncomingValueIf() (NFC)
Add an API that allows removing multiple incoming phi values based
on a predicate callback, as suggested on D157621.
This makes sure that the removal is linear time rather than quadratic,
and avoids subtleties around iterator invalidation.
I have replaced some of the more straightforward users with the new
API, though there's a couple more places that should be able to use it.
Differential Revision: https://reviews.llvm.org/D158064
Added:
Modified:
llvm/include/llvm/IR/Instructions.h
llvm/lib/IR/Instructions.cpp
llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp
llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
llvm/lib/Transforms/Utils/LoopSimplify.cpp
llvm/lib/Transforms/Utils/LoopUtils.cpp
llvm/lib/Transforms/Utils/SimplifyCFG.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/IR/Instructions.h b/llvm/include/llvm/IR/Instructions.h
index 8d60384e1a32fc..61e9e099ed992c 100644
--- a/llvm/include/llvm/IR/Instructions.h
+++ b/llvm/include/llvm/IR/Instructions.h
@@ -2890,6 +2890,11 @@ class PHINode : public Instruction {
return removeIncomingValue(Idx, DeletePHIIfEmpty);
}
+ /// Remove all incoming values for which the predicate returns true.
+ /// The predicate accepts the incoming value index.
+ void removeIncomingValueIf(function_ref<bool(unsigned)> Predicate,
+ bool DeletePHIIfEmpty = true);
+
/// Return the first index of the specified basic
/// block in the value list for this PHI. Returns -1 if no instance.
///
diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp
index e60f8f981d636f..59f6f5e119e828 100644
--- a/llvm/lib/IR/Instructions.cpp
+++ b/llvm/lib/IR/Instructions.cpp
@@ -145,6 +145,39 @@ Value *PHINode::removeIncomingValue(unsigned Idx, bool DeletePHIIfEmpty) {
return Removed;
}
+void PHINode::removeIncomingValueIf(function_ref<bool(unsigned)> Predicate,
+ bool DeletePHIIfEmpty) {
+ SmallDenseSet<unsigned> RemoveIndices;
+ for (unsigned Idx = 0; Idx < getNumIncomingValues(); ++Idx)
+ if (Predicate(Idx))
+ RemoveIndices.insert(Idx);
+
+ if (RemoveIndices.empty())
+ return;
+
+ // Remove operands.
+ auto NewOpEnd = remove_if(operands(), [&](Use &U) {
+ return RemoveIndices.contains(U.getOperandNo());
+ });
+ for (Use &U : make_range(NewOpEnd, op_end()))
+ U.set(nullptr);
+
+ // Remove incoming blocks.
+ std::remove_if(const_cast<block_iterator>(block_begin()),
+ const_cast<block_iterator>(block_end()), [&](BasicBlock *&BB) {
+ return RemoveIndices.contains(&BB - block_begin());
+ });
+
+ setNumHungOffUseOperands(getNumOperands() - RemoveIndices.size());
+
+ // If the PHI node is dead, because it has zero entries, nuke it now.
+ if (getNumOperands() == 0 && DeletePHIIfEmpty) {
+ // If anyone is using this PHI, make them use a dummy value instead...
+ replaceAllUsesWith(PoisonValue::get(getType()));
+ eraseFromParent();
+ }
+}
+
/// growOperands - grow operands - This grows the operand list in response
/// to a push_back style of operation. This grows the number of ops by 1.5
/// times.
diff --git a/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp b/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp
index 597cec8e61c9e3..901c5fc0e509ab 100644
--- a/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp
+++ b/llvm/lib/Transforms/Instrumentation/ControlHeightReduction.cpp
@@ -1780,17 +1780,10 @@ void CHR::cloneScopeBlocks(CHRScope *Scope,
// Unreachable predecessors will not be cloned and will not have an edge
// to the cloned block. As such, also remove them from any phi nodes.
- // To avoid iterator invalidation, first collect the dead predecessors
- // from the first phi node, and then perform the actual removal.
- if (auto *FirstPN = dyn_cast<PHINode>(NewBB->begin())) {
- SmallVector<BasicBlock *> DeadPreds;
- for (BasicBlock *Pred : FirstPN->blocks())
- if (!DT.isReachableFromEntry(Pred))
- DeadPreds.push_back(Pred);
- for (PHINode &PN : make_early_inc_range(NewBB->phis()))
- for (BasicBlock *Pred : DeadPreds)
- PN.removeIncomingValue(Pred);
- }
+ for (PHINode &PN : make_early_inc_range(NewBB->phis()))
+ PN.removeIncomingValueIf([&](unsigned Idx) {
+ return !DT.isReachableFromEntry(PN.getIncomingBlock(Idx));
+ });
}
// Place the cloned blocks right after the original blocks (right before the
diff --git a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
index f06ea89cc61d4e..6b956a193e6418 100644
--- a/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
+++ b/llvm/lib/Transforms/Utils/BasicBlockUtils.cpp
@@ -1137,14 +1137,11 @@ static void UpdatePHINodes(BasicBlock *OrigBB, BasicBlock *NewBB,
// If all incoming values for the new PHI would be the same, just don't
// make a new PHI. Instead, just remove the incoming values from the old
// PHI.
-
- // NOTE! This loop walks backwards for a reason! First off, this minimizes
- // the cost of removal if we end up removing a large number of values, and
- // second off, this ensures that the indices for the incoming values
- // aren't invalidated when we remove one.
- for (int64_t i = PN->getNumIncomingValues() - 1; i >= 0; --i)
- if (PredSet.count(PN->getIncomingBlock(i)))
- PN->removeIncomingValue(i, false);
+ PN->removeIncomingValueIf(
+ [&](unsigned Idx) {
+ return PredSet.contains(PN->getIncomingBlock(Idx));
+ },
+ /* DeletePHIIfEmpty */ false);
// Add an incoming value to the PHI node in the loop for the preheader
// edge.
diff --git a/llvm/lib/Transforms/Utils/LoopSimplify.cpp b/llvm/lib/Transforms/Utils/LoopSimplify.cpp
index 3e604fdf2e11ac..07e622b1577fe1 100644
--- a/llvm/lib/Transforms/Utils/LoopSimplify.cpp
+++ b/llvm/lib/Transforms/Utils/LoopSimplify.cpp
@@ -429,8 +429,8 @@ static BasicBlock *insertUniqueBackedgeBlock(Loop *L, BasicBlock *Preheader,
PN->setIncomingBlock(0, PN->getIncomingBlock(PreheaderIdx));
}
// Nuke all entries except the zero'th.
- for (unsigned i = 0, e = PN->getNumIncomingValues()-1; i != e; ++i)
- PN->removeIncomingValue(e-i, false);
+ PN->removeIncomingValueIf([](unsigned Idx) { return Idx != 0; },
+ /* DeletePHIIfEmpty */ false);
// Finally, add the newly constructed PHI node as the entry for the BEBlock.
PN->addIncoming(NewPN, BEBlock);
diff --git a/llvm/lib/Transforms/Utils/LoopUtils.cpp b/llvm/lib/Transforms/Utils/LoopUtils.cpp
index f99cf3d4b3320a..6e0c195cc76571 100644
--- a/llvm/lib/Transforms/Utils/LoopUtils.cpp
+++ b/llvm/lib/Transforms/Utils/LoopUtils.cpp
@@ -556,12 +556,8 @@ void llvm::deleteDeadLoop(Loop *L, DominatorTree *DT, ScalarEvolution *SE,
// Removes all incoming values from all other exiting blocks (including
// duplicate values from an exiting block).
// Nuke all entries except the zero'th entry which is the preheader entry.
- // NOTE! We need to remove Incoming Values in the reverse order as done
- // below, to keep the indices valid for deletion (removeIncomingValues
- // updates getNumIncomingValues and shifts all values down into the
- // operand being deleted).
- for (unsigned i = 0, e = P.getNumIncomingValues() - 1; i != e; ++i)
- P.removeIncomingValue(e - i, false);
+ P.removeIncomingValueIf([](unsigned Idx) { return Idx != 0; },
+ /* DeletePHIIfEmpty */ false);
assert((P.getNumIncomingValues() == 1 &&
P.getIncomingBlock(PredIndex) == Preheader) &&
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 3a86ded03b61d0..64b5a915042c52 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -5890,8 +5890,8 @@ static void removeSwitchAfterSelectFold(SwitchInst *SI, PHINode *PHI,
// Remove the switch.
- while (PHI->getBasicBlockIndex(SelectBB) >= 0)
- PHI->removeIncomingValue(SelectBB);
+ PHI->removeIncomingValueIf(
+ [&](unsigned Idx) { return PHI->getIncomingBlock(Idx) == SelectBB; });
PHI->addIncoming(SelectValue, SelectBB);
SmallPtrSet<BasicBlock *, 4> RemovedSuccessors;
More information about the llvm-commits
mailing list