Skip to content

Commit 37992c4

Browse files
committed
Populate DFS numbers ahead of time
This prevents quadratic behavior of calling DominatorTree::updateDFSNumbers everytime BasicBlocks are split to sink instructions
1 parent 879999b commit 37992c4

File tree

1 file changed

+24
-18
lines changed

1 file changed

+24
-18
lines changed

llvm/lib/Transforms/Scalar/GVNSink.cpp

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -223,12 +223,12 @@ raw_ostream &operator<<(raw_ostream &OS, const SinkingInstructionCandidate &C) {
223223
class ModelledPHI {
224224
SmallVector<Value *, 4> Values;
225225
SmallVector<BasicBlock *, 4> Blocks;
226-
DominatorTree *DT;
227226

228227
public:
229228
ModelledPHI() = default;
230229

231-
ModelledPHI(const PHINode *PN, DominatorTree *DT) : DT(DT) {
230+
ModelledPHI(const PHINode *PN,
231+
const DenseMap<const BasicBlock *, unsigned> &DFS) {
232232
// BasicBlock comes first so we sort by basic block pointer order,
233233
// then by value pointer order. No need to call `verifyModelledPHI`
234234
// As the Values and Blocks are populated in DFSOrder already.
@@ -237,9 +237,8 @@ class ModelledPHI {
237237
for (unsigned I = 0, E = PN->getNumIncomingValues(); I != E; ++I)
238238
Ops.push_back({PN->getIncomingBlock(I), PN->getIncomingValue(I)});
239239

240-
auto DFSOrder = [DT](OpsType O1, OpsType O2) {
241-
return DT->getNode(O1.first)->getDFSNumIn() <
242-
DT->getNode(O2.first)->getDFSNumIn();
240+
auto DFSOrder = [DFS](OpsType O1, OpsType O2) {
241+
return DFS.lookup(O1.first) < DFS.lookup(O2.first);
243242
};
244243
// Sort by DFSNumber to have a deterministic order.
245244
llvm::sort(Ops, DFSOrder);
@@ -259,11 +258,11 @@ class ModelledPHI {
259258
return M;
260259
}
261260

262-
void verifyModelledPHI() {
261+
void verifyModelledPHI(const DenseMap<const BasicBlock *, unsigned> &DFS) {
263262
assert(Values.size() > 1 && Blocks.size() > 1 &&
264263
"Modelling PHI with less than 2 values");
265-
auto DFSOrder = [this](const BasicBlock *BB1, const BasicBlock *BB2) {
266-
return DT->getNode(BB1)->getDFSNumIn() < DT->getNode(BB2)->getDFSNumIn();
264+
auto DFSOrder = [DFS](const BasicBlock *BB1, const BasicBlock *BB2) {
265+
return DFS.lookup(BB1) < DFS.lookup(BB2);
267266
};
268267
assert(llvm::is_sorted(Blocks, DFSOrder));
269268
int C = 0;
@@ -277,19 +276,18 @@ class ModelledPHI {
277276
}
278277
/// Create a PHI from an array of incoming values and incoming blocks.
279278
ModelledPHI(SmallVectorImpl<Instruction *> &V,
280-
SmallSetVector<BasicBlock *, 4> &B, DominatorTree *DT)
281-
: DT(DT) {
279+
SmallSetVector<BasicBlock *, 4> &B,
280+
const DenseMap<const BasicBlock *, unsigned> &DFS) {
282281
// The order of Values and Blocks are already as per their DFSNumbers.
283282
llvm::copy(V, std::back_inserter(Values));
284283
llvm::copy(B, std::back_inserter(Blocks));
285-
verifyModelledPHI();
284+
verifyModelledPHI(DFS);
286285
}
287286

288287
/// Create a PHI from [I[OpNum] for I in Insts].
289288
/// TODO: Figure out a way to verifyModelledPHI in this constructor.
290289
ModelledPHI(ArrayRef<Instruction *> Insts, unsigned OpNum,
291-
SmallSetVector<BasicBlock *, 4> &B, DominatorTree *DT)
292-
: DT(DT) {
290+
SmallSetVector<BasicBlock *, 4> &B) {
293291
llvm::copy(B, std::back_inserter(Blocks));
294292
for (auto *I : Insts)
295293
Values.push_back(I->getOperand(OpNum));
@@ -609,6 +607,13 @@ class GVNSink {
609607
unsigned NumSunk = 0;
610608
ReversePostOrderTraversal<Function*> RPOT(&F);
611609
VN.setReachableBBs(BasicBlocksSet(RPOT.begin(), RPOT.end()));
610+
// Populated DFSNumbers ahead of time to avoid updating dominator tree
611+
// when CFG is modified. The DFSNumbers of newly created basic blocks
612+
// are irrelevant because RPOT is also obtained ahead of time and only
613+
// DFSNumbers of original CFG are relevant for sinkable candidates.
614+
for (auto *BB : RPOT)
615+
if (DT->getNode(BB))
616+
DFSNumbers[BB] = DT->getNode(BB)->getDFSNumIn();
612617
for (auto *N : RPOT)
613618
NumSunk += sinkBB(N);
614619

@@ -618,6 +623,7 @@ class GVNSink {
618623
private:
619624
ValueTable VN;
620625
DominatorTree *DT;
626+
DenseMap<const BasicBlock *, unsigned> DFSNumbers;
621627

622628
bool shouldAvoidSinkingInstruction(Instruction *I) {
623629
// These instructions may change or break semantics if moved.
@@ -638,7 +644,7 @@ class GVNSink {
638644
void analyzeInitialPHIs(BasicBlock *BB, ModelledPHISet &PHIs,
639645
SmallPtrSetImpl<Value *> &PHIContents) {
640646
for (PHINode &PN : BB->phis()) {
641-
auto MPHI = ModelledPHI(&PN, DT);
647+
auto MPHI = ModelledPHI(&PN, DFSNumbers);
642648
PHIs.insert(MPHI);
643649
for (auto *V : MPHI.getValues())
644650
PHIContents.insert(V);
@@ -726,7 +732,7 @@ GVNSink::analyzeInstructionForSinking(LockstepReverseIterator &LRI,
726732
}
727733

728734
// The sunk instruction's results.
729-
ModelledPHI NewPHI(NewInsts, ActivePreds, DT);
735+
ModelledPHI NewPHI(NewInsts, ActivePreds, DFSNumbers);
730736

731737
// Does sinking this instruction render previous PHIs redundant?
732738
if (NeededPHIs.erase(NewPHI))
@@ -763,7 +769,7 @@ GVNSink::analyzeInstructionForSinking(LockstepReverseIterator &LRI,
763769
return std::nullopt;
764770

765771
for (unsigned OpNum = 0, E = I0->getNumOperands(); OpNum != E; ++OpNum) {
766-
ModelledPHI PHI(NewInsts, OpNum, ActivePreds, DT);
772+
ModelledPHI PHI(NewInsts, OpNum, ActivePreds);
767773
if (PHI.areAllIncomingValuesSame())
768774
continue;
769775
if (!canReplaceOperandWithVariable(I0, OpNum))
@@ -802,7 +808,7 @@ unsigned GVNSink::sinkBB(BasicBlock *BBEnd) {
802808
SmallVector<BasicBlock *, 4> Preds;
803809
for (auto *B : predecessors(BBEnd)) {
804810
// Bailout on malformed CFG where BasicBlock has no predecessor(PR42346).
805-
if (!DT->getNode(B))
811+
if (!DFSNumbers.count(B))
806812
return 0;
807813
auto *T = B->getTerminator();
808814
if (isa<BranchInst>(T) || isa<SwitchInst>(T))
@@ -813,7 +819,7 @@ unsigned GVNSink::sinkBB(BasicBlock *BBEnd) {
813819
if (Preds.size() < 2)
814820
return 0;
815821
auto DFSOrder = [this](const BasicBlock *BB1, const BasicBlock *BB2) {
816-
return DT->getNode(BB1)->getDFSNumIn() < DT->getNode(BB2)->getDFSNumIn();
822+
return DFSNumbers.lookup(BB1) < DFSNumbers.lookup(BB2);
817823
};
818824
// Sort by DFSNumber to have a deterministic order.
819825
llvm::sort(Preds, DFSOrder);

0 commit comments

Comments
 (0)