Skip to content

Commit 4e21809

Browse files
committed
Use reverse-post order instead of DFS order
As noted by Eli and Nikita, there is no need to use depth first ordering because all we need is a deterministic order. This approach avoids calling expensive DFSNumbering operation and reuse an existing visitation order
1 parent 37992c4 commit 4e21809

File tree

1 file changed

+38
-40
lines changed

1 file changed

+38
-40
lines changed

llvm/lib/Transforms/Scalar/GVNSink.cpp

Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
#include "llvm/ADT/SmallPtrSet.h"
4343
#include "llvm/ADT/SmallVector.h"
4444
#include "llvm/ADT/Statistic.h"
45-
#include "llvm/Analysis/DomTreeUpdater.h"
4645
#include "llvm/Analysis/GlobalsModRef.h"
4746
#include "llvm/IR/BasicBlock.h"
4847
#include "llvm/IR/CFG.h"
@@ -228,20 +227,20 @@ class ModelledPHI {
228227
ModelledPHI() = default;
229228

230229
ModelledPHI(const PHINode *PN,
231-
const DenseMap<const BasicBlock *, unsigned> &DFS) {
230+
const DenseMap<const BasicBlock *, unsigned> &BlockOrder) {
232231
// BasicBlock comes first so we sort by basic block pointer order,
233232
// then by value pointer order. No need to call `verifyModelledPHI`
234-
// As the Values and Blocks are populated in DFSOrder already.
233+
// As the Values and Blocks are populated in a deterministic order.
235234
using OpsType = std::pair<BasicBlock *, Value *>;
236235
SmallVector<OpsType, 4> Ops;
237236
for (unsigned I = 0, E = PN->getNumIncomingValues(); I != E; ++I)
238237
Ops.push_back({PN->getIncomingBlock(I), PN->getIncomingValue(I)});
239238

240-
auto DFSOrder = [DFS](OpsType O1, OpsType O2) {
241-
return DFS.lookup(O1.first) < DFS.lookup(O2.first);
239+
auto ComesBefore = [BlockOrder](OpsType O1, OpsType O2) {
240+
return BlockOrder.lookup(O1.first) < BlockOrder.lookup(O2.first);
242241
};
243-
// Sort by DFSNumber to have a deterministic order.
244-
llvm::sort(Ops, DFSOrder);
242+
// Sort in a deterministic order.
243+
llvm::sort(Ops, ComesBefore);
245244

246245
for (auto &P : Ops) {
247246
Blocks.push_back(P.first);
@@ -258,13 +257,15 @@ class ModelledPHI {
258257
return M;
259258
}
260259

261-
void verifyModelledPHI(const DenseMap<const BasicBlock *, unsigned> &DFS) {
260+
void
261+
verifyModelledPHI(const DenseMap<const BasicBlock *, unsigned> &BlockOrder) {
262262
assert(Values.size() > 1 && Blocks.size() > 1 &&
263263
"Modelling PHI with less than 2 values");
264-
auto DFSOrder = [DFS](const BasicBlock *BB1, const BasicBlock *BB2) {
265-
return DFS.lookup(BB1) < DFS.lookup(BB2);
264+
auto ComesBefore = [BlockOrder](const BasicBlock *BB1,
265+
const BasicBlock *BB2) {
266+
return BlockOrder.lookup(BB1) < BlockOrder.lookup(BB2);
266267
};
267-
assert(llvm::is_sorted(Blocks, DFSOrder));
268+
assert(llvm::is_sorted(Blocks, ComesBefore));
268269
int C = 0;
269270
llvm::for_each(Values, [&C, this](const Value *V) {
270271
if (!isa<UndefValue>(V)) {
@@ -277,11 +278,11 @@ class ModelledPHI {
277278
/// Create a PHI from an array of incoming values and incoming blocks.
278279
ModelledPHI(SmallVectorImpl<Instruction *> &V,
279280
SmallSetVector<BasicBlock *, 4> &B,
280-
const DenseMap<const BasicBlock *, unsigned> &DFS) {
281-
// The order of Values and Blocks are already as per their DFSNumbers.
281+
const DenseMap<const BasicBlock *, unsigned> &BlockOrder) {
282+
// The order of Values and Blocks are already ordered by the caller.
282283
llvm::copy(V, std::back_inserter(Values));
283284
llvm::copy(B, std::back_inserter(Blocks));
284-
verifyModelledPHI(DFS);
285+
verifyModelledPHI(BlockOrder);
285286
}
286287

287288
/// Create a PHI from [I[OpNum] for I in Insts].
@@ -328,7 +329,7 @@ class ModelledPHI {
328329

329330
// Hash functor
330331
unsigned hash() const {
331-
// Is deterministic because Values are saved in DFSOrder.
332+
// Is deterministic because Values are saved in a specific order.
332333
return (unsigned)hash_combine_range(Values.begin(), Values.end());
333334
}
334335

@@ -598,7 +599,7 @@ class ValueTable {
598599

599600
class GVNSink {
600601
public:
601-
GVNSink(DominatorTree *DT) : DT(DT) {}
602+
GVNSink() {}
602603

603604
bool run(Function &F) {
604605
LLVM_DEBUG(dbgs() << "GVNSink: running on function @" << F.getName()
@@ -607,13 +608,16 @@ class GVNSink {
607608
unsigned NumSunk = 0;
608609
ReversePostOrderTraversal<Function*> RPOT(&F);
609610
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.
611+
// Populate reverse post-order to order basic blocks in deterministic
612+
// order. Any arbitrary ordering will work in this case as long as they are
613+
// deterministic. The node ordering of newly created basic blocks
614+
// are irrelevant because RPOT(for computing sinkable candidates) is also
615+
// obtained ahead of time and only their order are relevant for this pass.
616+
unsigned NodeOrdering = 0;
617+
RPOTOrder[*RPOT.begin()] = ++NodeOrdering;
614618
for (auto *BB : RPOT)
615-
if (DT->getNode(BB))
616-
DFSNumbers[BB] = DT->getNode(BB)->getDFSNumIn();
619+
if (!pred_empty(BB))
620+
RPOTOrder[BB] = ++NodeOrdering;
617621
for (auto *N : RPOT)
618622
NumSunk += sinkBB(N);
619623

@@ -622,8 +626,7 @@ class GVNSink {
622626

623627
private:
624628
ValueTable VN;
625-
DominatorTree *DT;
626-
DenseMap<const BasicBlock *, unsigned> DFSNumbers;
629+
DenseMap<const BasicBlock *, unsigned> RPOTOrder;
627630

628631
bool shouldAvoidSinkingInstruction(Instruction *I) {
629632
// These instructions may change or break semantics if moved.
@@ -644,7 +647,7 @@ class GVNSink {
644647
void analyzeInitialPHIs(BasicBlock *BB, ModelledPHISet &PHIs,
645648
SmallPtrSetImpl<Value *> &PHIContents) {
646649
for (PHINode &PN : BB->phis()) {
647-
auto MPHI = ModelledPHI(&PN, DFSNumbers);
650+
auto MPHI = ModelledPHI(&PN, RPOTOrder);
648651
PHIs.insert(MPHI);
649652
for (auto *V : MPHI.getValues())
650653
PHIContents.insert(V);
@@ -732,7 +735,7 @@ GVNSink::analyzeInstructionForSinking(LockstepReverseIterator &LRI,
732735
}
733736

734737
// The sunk instruction's results.
735-
ModelledPHI NewPHI(NewInsts, ActivePreds, DFSNumbers);
738+
ModelledPHI NewPHI(NewInsts, ActivePreds, RPOTOrder);
736739

737740
// Does sinking this instruction render previous PHIs redundant?
738741
if (NeededPHIs.erase(NewPHI))
@@ -807,8 +810,8 @@ unsigned GVNSink::sinkBB(BasicBlock *BBEnd) {
807810
BBEnd->printAsOperand(dbgs()); dbgs() << "\n");
808811
SmallVector<BasicBlock *, 4> Preds;
809812
for (auto *B : predecessors(BBEnd)) {
810-
// Bailout on malformed CFG where BasicBlock has no predecessor(PR42346).
811-
if (!DFSNumbers.count(B))
813+
// Bailout on basic blocks without predecessor(PR42346).
814+
if (!RPOTOrder.count(B))
812815
return 0;
813816
auto *T = B->getTerminator();
814817
if (isa<BranchInst>(T) || isa<SwitchInst>(T))
@@ -818,11 +821,11 @@ unsigned GVNSink::sinkBB(BasicBlock *BBEnd) {
818821
}
819822
if (Preds.size() < 2)
820823
return 0;
821-
auto DFSOrder = [this](const BasicBlock *BB1, const BasicBlock *BB2) {
822-
return DFSNumbers.lookup(BB1) < DFSNumbers.lookup(BB2);
824+
auto ComesBefore = [this](const BasicBlock *BB1, const BasicBlock *BB2) {
825+
return RPOTOrder.lookup(BB1) < RPOTOrder.lookup(BB2);
823826
};
824-
// Sort by DFSNumber to have a deterministic order.
825-
llvm::sort(Preds, DFSOrder);
827+
// Sort in a deterministic order.
828+
llvm::sort(Preds, ComesBefore);
826829

827830
unsigned NumOrigPreds = Preds.size();
828831
// We can only sink instructions through unconditional branches.
@@ -859,12 +862,11 @@ unsigned GVNSink::sinkBB(BasicBlock *BBEnd) {
859862
auto C = Candidates.front();
860863

861864
LLVM_DEBUG(dbgs() << " -- Sinking: " << C << "\n");
862-
DomTreeUpdater DTU(DT, DomTreeUpdater::UpdateStrategy::Eager);
863865
BasicBlock *InsertBB = BBEnd;
864866
if (C.Blocks.size() < NumOrigPreds) {
865867
LLVM_DEBUG(dbgs() << " -- Splitting edge to ";
866868
BBEnd->printAsOperand(dbgs()); dbgs() << "\n");
867-
InsertBB = SplitBlockPredecessors(BBEnd, C.Blocks, ".gvnsink.split", &DTU);
869+
InsertBB = SplitBlockPredecessors(BBEnd, C.Blocks, ".gvnsink.split");
868870
if (!InsertBB) {
869871
LLVM_DEBUG(dbgs() << " -- FAILED to split edge!\n");
870872
// Edge couldn't be split.
@@ -935,13 +937,9 @@ void GVNSink::sinkLastInstruction(ArrayRef<BasicBlock *> Blocks,
935937
} // end anonymous namespace
936938

937939
PreservedAnalyses GVNSinkPass::run(Function &F, FunctionAnalysisManager &AM) {
938-
auto &DT = AM.getResult<DominatorTreeAnalysis>(F);
939-
GVNSink G(&DT);
940-
DT.updateDFSNumbers();
940+
GVNSink G;
941941
if (!G.run(F))
942942
return PreservedAnalyses::all();
943943

944-
PreservedAnalyses PA;
945-
PA.preserve<DominatorTreeAnalysis>();
946-
return PA;
944+
return PreservedAnalyses::none();
947945
}

0 commit comments

Comments
 (0)