Skip to content

Commit d529e78

Browse files
authored
[GVN] Refactor the LeaderTable structure into a properly encapsulated data structure (llvm#88347)
Hide the details of the one-off linked list used to implement the leader lists by wrapping them in iterators, and then use that to reimplement a number of traversals using standard algorithms and range-based for-loops. No functional change intended.
1 parent c4b28bf commit d529e78

File tree

2 files changed

+149
-97
lines changed
  • llvm
    • include/llvm/Transforms/Scalar
    • lib/Transforms/Scalar

2 files changed

+149
-97
lines changed

llvm/include/llvm/Transforms/Scalar/GVN.h

Lines changed: 60 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -232,13 +232,67 @@ class GVNPass : public PassInfoMixin<GVNPass> {
232232

233233
/// A mapping from value numbers to lists of Value*'s that
234234
/// have that value number. Use findLeader to query it.
235-
struct LeaderTableEntry {
236-
Value *Val;
237-
const BasicBlock *BB;
238-
LeaderTableEntry *Next;
235+
class LeaderMap {
236+
public:
237+
struct LeaderTableEntry {
238+
Value *Val;
239+
const BasicBlock *BB;
240+
};
241+
242+
private:
243+
struct LeaderListNode {
244+
LeaderTableEntry Entry;
245+
LeaderListNode *Next;
246+
};
247+
DenseMap<uint32_t, LeaderListNode> NumToLeaders;
248+
BumpPtrAllocator TableAllocator;
249+
250+
public:
251+
class leader_iterator {
252+
const LeaderListNode *Current;
253+
254+
public:
255+
using iterator_category = std::forward_iterator_tag;
256+
using value_type = const LeaderTableEntry;
257+
using difference_type = std::ptrdiff_t;
258+
using pointer = value_type *;
259+
using reference = value_type &;
260+
261+
leader_iterator(const LeaderListNode *C) : Current(C) {}
262+
leader_iterator &operator++() {
263+
assert(Current && "Dereferenced end of leader list!");
264+
Current = Current->Next;
265+
return *this;
266+
}
267+
bool operator==(const leader_iterator &Other) const {
268+
return Current == Other.Current;
269+
}
270+
bool operator!=(const leader_iterator &Other) const {
271+
return Current != Other.Current;
272+
}
273+
reference operator*() const { return Current->Entry; }
274+
};
275+
276+
iterator_range<leader_iterator> getLeaders(uint32_t N) {
277+
auto I = NumToLeaders.find(N);
278+
if (I == NumToLeaders.end()) {
279+
return iterator_range(leader_iterator(nullptr),
280+
leader_iterator(nullptr));
281+
}
282+
283+
return iterator_range(leader_iterator(&I->second),
284+
leader_iterator(nullptr));
285+
}
286+
287+
void insert(uint32_t N, Value *V, const BasicBlock *BB);
288+
void erase(uint32_t N, Instruction *I, const BasicBlock *BB);
289+
void verifyRemoved(const Value *Inst) const;
290+
void clear() {
291+
NumToLeaders.clear();
292+
TableAllocator.Reset();
293+
}
239294
};
240-
DenseMap<uint32_t, LeaderTableEntry> LeaderTable;
241-
BumpPtrAllocator TableAllocator;
295+
LeaderMap LeaderTable;
242296

243297
// Block-local map of equivalent values to their leader, does not
244298
// propagate to any successors. Entries added mid-block are applied
@@ -264,51 +318,6 @@ class GVNPass : public PassInfoMixin<GVNPass> {
264318
MemoryDependenceResults *RunMD, LoopInfo &LI,
265319
OptimizationRemarkEmitter *ORE, MemorySSA *MSSA = nullptr);
266320

267-
/// Push a new Value to the LeaderTable onto the list for its value number.
268-
void addToLeaderTable(uint32_t N, Value *V, const BasicBlock *BB) {
269-
LeaderTableEntry &Curr = LeaderTable[N];
270-
if (!Curr.Val) {
271-
Curr.Val = V;
272-
Curr.BB = BB;
273-
return;
274-
}
275-
276-
LeaderTableEntry *Node = TableAllocator.Allocate<LeaderTableEntry>();
277-
Node->Val = V;
278-
Node->BB = BB;
279-
Node->Next = Curr.Next;
280-
Curr.Next = Node;
281-
}
282-
283-
/// Scan the list of values corresponding to a given
284-
/// value number, and remove the given instruction if encountered.
285-
void removeFromLeaderTable(uint32_t N, Instruction *I, BasicBlock *BB) {
286-
LeaderTableEntry *Prev = nullptr;
287-
LeaderTableEntry *Curr = &LeaderTable[N];
288-
289-
while (Curr && (Curr->Val != I || Curr->BB != BB)) {
290-
Prev = Curr;
291-
Curr = Curr->Next;
292-
}
293-
294-
if (!Curr)
295-
return;
296-
297-
if (Prev) {
298-
Prev->Next = Curr->Next;
299-
} else {
300-
if (!Curr->Next) {
301-
Curr->Val = nullptr;
302-
Curr->BB = nullptr;
303-
} else {
304-
LeaderTableEntry *Next = Curr->Next;
305-
Curr->Val = Next->Val;
306-
Curr->BB = Next->BB;
307-
Curr->Next = Next->Next;
308-
}
309-
}
310-
}
311-
312321
// List of critical edges to be split between iterations.
313322
SmallVector<std::pair<Instruction *, unsigned>, 4> toSplit;
314323

llvm/lib/Transforms/Scalar/GVN.cpp

Lines changed: 89 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -725,6 +725,69 @@ void GVNPass::ValueTable::verifyRemoved(const Value *V) const {
725725
"Inst still occurs in value numbering map!");
726726
}
727727

728+
//===----------------------------------------------------------------------===//
729+
// LeaderMap External Functions
730+
//===----------------------------------------------------------------------===//
731+
732+
/// Push a new Value to the LeaderTable onto the list for its value number.
733+
void GVNPass::LeaderMap::insert(uint32_t N, Value *V, const BasicBlock *BB) {
734+
LeaderListNode &Curr = NumToLeaders[N];
735+
if (!Curr.Entry.Val) {
736+
Curr.Entry.Val = V;
737+
Curr.Entry.BB = BB;
738+
return;
739+
}
740+
741+
LeaderListNode *Node = TableAllocator.Allocate<LeaderListNode>();
742+
Node->Entry.Val = V;
743+
Node->Entry.BB = BB;
744+
Node->Next = Curr.Next;
745+
Curr.Next = Node;
746+
}
747+
748+
/// Scan the list of values corresponding to a given
749+
/// value number, and remove the given instruction if encountered.
750+
void GVNPass::LeaderMap::erase(uint32_t N, Instruction *I,
751+
const BasicBlock *BB) {
752+
LeaderListNode *Prev = nullptr;
753+
LeaderListNode *Curr = &NumToLeaders[N];
754+
755+
while (Curr && (Curr->Entry.Val != I || Curr->Entry.BB != BB)) {
756+
Prev = Curr;
757+
Curr = Curr->Next;
758+
}
759+
760+
if (!Curr)
761+
return;
762+
763+
if (Prev) {
764+
Prev->Next = Curr->Next;
765+
} else {
766+
if (!Curr->Next) {
767+
Curr->Entry.Val = nullptr;
768+
Curr->Entry.BB = nullptr;
769+
} else {
770+
LeaderListNode *Next = Curr->Next;
771+
Curr->Entry.Val = Next->Entry.Val;
772+
Curr->Entry.BB = Next->Entry.BB;
773+
Curr->Next = Next->Next;
774+
}
775+
}
776+
}
777+
778+
void GVNPass::LeaderMap::verifyRemoved(const Value *V) const {
779+
// Walk through the value number scope to make sure the instruction isn't
780+
// ferreted away in it.
781+
for (const auto &I : NumToLeaders) {
782+
(void)I;
783+
assert(I.second.Entry.Val != V && "Inst still in value numbering scope!");
784+
assert(
785+
std::none_of(leader_iterator(&I.second), leader_iterator(nullptr),
786+
[=](const LeaderTableEntry &E) { return E.Val == V; }) &&
787+
"Inst still in value numbering scope!");
788+
}
789+
}
790+
728791
//===----------------------------------------------------------------------===//
729792
// GVN Pass
730793
//===----------------------------------------------------------------------===//
@@ -1467,7 +1530,7 @@ void GVNPass::eliminatePartiallyRedundantLoad(
14671530
OldLoad->replaceAllUsesWith(NewLoad);
14681531
replaceValuesPerBlockEntry(ValuesPerBlock, OldLoad, NewLoad);
14691532
if (uint32_t ValNo = VN.lookup(OldLoad, false))
1470-
removeFromLeaderTable(ValNo, OldLoad, OldLoad->getParent());
1533+
LeaderTable.erase(ValNo, OldLoad, OldLoad->getParent());
14711534
VN.erase(OldLoad);
14721535
removeInstruction(OldLoad);
14731536
}
@@ -2204,10 +2267,9 @@ GVNPass::ValueTable::assignExpNewValueNum(Expression &Exp) {
22042267
/// defined in \p BB.
22052268
bool GVNPass::ValueTable::areAllValsInBB(uint32_t Num, const BasicBlock *BB,
22062269
GVNPass &Gvn) {
2207-
LeaderTableEntry *Vals = &Gvn.LeaderTable[Num];
2208-
while (Vals && Vals->BB == BB)
2209-
Vals = Vals->Next;
2210-
return !Vals;
2270+
return all_of(
2271+
Gvn.LeaderTable.getLeaders(Num),
2272+
[=](const LeaderMap::LeaderTableEntry &L) { return L.BB == BB; });
22112273
}
22122274

22132275
/// Wrap phiTranslateImpl to provide caching functionality.
@@ -2229,12 +2291,11 @@ bool GVNPass::ValueTable::areCallValsEqual(uint32_t Num, uint32_t NewNum,
22292291
const BasicBlock *PhiBlock,
22302292
GVNPass &Gvn) {
22312293
CallInst *Call = nullptr;
2232-
LeaderTableEntry *Vals = &Gvn.LeaderTable[Num];
2233-
while (Vals) {
2234-
Call = dyn_cast<CallInst>(Vals->Val);
2294+
auto Leaders = Gvn.LeaderTable.getLeaders(Num);
2295+
for (const auto &Entry : Leaders) {
2296+
Call = dyn_cast<CallInst>(Entry.Val);
22352297
if (Call && Call->getParent() == PhiBlock)
22362298
break;
2237-
Vals = Vals->Next;
22382299
}
22392300

22402301
if (AA->doesNotAccessMemory(Call))
@@ -2327,23 +2388,17 @@ void GVNPass::ValueTable::eraseTranslateCacheEntry(
23272388
// question. This is fast because dominator tree queries consist of only
23282389
// a few comparisons of DFS numbers.
23292390
Value *GVNPass::findLeader(const BasicBlock *BB, uint32_t num) {
2330-
LeaderTableEntry Vals = LeaderTable[num];
2331-
if (!Vals.Val) return nullptr;
2391+
auto Leaders = LeaderTable.getLeaders(num);
2392+
if (Leaders.empty())
2393+
return nullptr;
23322394

23332395
Value *Val = nullptr;
2334-
if (DT->dominates(Vals.BB, BB)) {
2335-
Val = Vals.Val;
2336-
if (isa<Constant>(Val)) return Val;
2337-
}
2338-
2339-
LeaderTableEntry* Next = Vals.Next;
2340-
while (Next) {
2341-
if (DT->dominates(Next->BB, BB)) {
2342-
if (isa<Constant>(Next->Val)) return Next->Val;
2343-
if (!Val) Val = Next->Val;
2396+
for (const auto &Entry : Leaders) {
2397+
if (DT->dominates(Entry.BB, BB)) {
2398+
Val = Entry.Val;
2399+
if (isa<Constant>(Val))
2400+
return Val;
23442401
}
2345-
2346-
Next = Next->Next;
23472402
}
23482403

23492404
return Val;
@@ -2452,7 +2507,7 @@ bool GVNPass::propagateEquality(Value *LHS, Value *RHS,
24522507
// have the simple case where the edge dominates the end.
24532508
if (RootDominatesEnd && !isa<Instruction>(RHS) &&
24542509
canReplacePointersIfEqual(LHS, RHS, DL))
2455-
addToLeaderTable(LVN, RHS, Root.getEnd());
2510+
LeaderTable.insert(LVN, RHS, Root.getEnd());
24562511

24572512
// Replace all occurrences of 'LHS' with 'RHS' everywhere in the scope. As
24582513
// LHS always has at least one use that is not dominated by Root, this will
@@ -2546,7 +2601,7 @@ bool GVNPass::propagateEquality(Value *LHS, Value *RHS,
25462601
// The leader table only tracks basic blocks, not edges. Only add to if we
25472602
// have the simple case where the edge dominates the end.
25482603
if (RootDominatesEnd)
2549-
addToLeaderTable(Num, NotVal, Root.getEnd());
2604+
LeaderTable.insert(Num, NotVal, Root.getEnd());
25502605

25512606
continue;
25522607
}
@@ -2596,7 +2651,7 @@ bool GVNPass::processInstruction(Instruction *I) {
25962651
return true;
25972652

25982653
unsigned Num = VN.lookupOrAdd(Load);
2599-
addToLeaderTable(Num, Load, Load->getParent());
2654+
LeaderTable.insert(Num, Load, Load->getParent());
26002655
return false;
26012656
}
26022657

@@ -2664,15 +2719,15 @@ bool GVNPass::processInstruction(Instruction *I) {
26642719
// Allocations are always uniquely numbered, so we can save time and memory
26652720
// by fast failing them.
26662721
if (isa<AllocaInst>(I) || I->isTerminator() || isa<PHINode>(I)) {
2667-
addToLeaderTable(Num, I, I->getParent());
2722+
LeaderTable.insert(Num, I, I->getParent());
26682723
return false;
26692724
}
26702725

26712726
// If the number we were assigned was a brand new VN, then we don't
26722727
// need to do a lookup to see if the number already exists
26732728
// somewhere in the domtree: it can't!
26742729
if (Num >= NextNum) {
2675-
addToLeaderTable(Num, I, I->getParent());
2730+
LeaderTable.insert(Num, I, I->getParent());
26762731
return false;
26772732
}
26782733

@@ -2681,7 +2736,7 @@ bool GVNPass::processInstruction(Instruction *I) {
26812736
Value *Repl = findLeader(I->getParent(), Num);
26822737
if (!Repl) {
26832738
// Failure, just remember this instance for future use.
2684-
addToLeaderTable(Num, I, I->getParent());
2739+
LeaderTable.insert(Num, I, I->getParent());
26852740
return false;
26862741
}
26872742

@@ -2876,7 +2931,7 @@ bool GVNPass::performScalarPREInsertion(Instruction *Instr, BasicBlock *Pred,
28762931
VN.add(Instr, Num);
28772932

28782933
// Update the availability map to include the new instruction.
2879-
addToLeaderTable(Num, Instr, Pred);
2934+
LeaderTable.insert(Num, Instr, Pred);
28802935
return true;
28812936
}
28822937

@@ -3027,13 +3082,13 @@ bool GVNPass::performScalarPRE(Instruction *CurInst) {
30273082
// After creating a new PHI for ValNo, the phi translate result for ValNo will
30283083
// be changed, so erase the related stale entries in phi translate cache.
30293084
VN.eraseTranslateCacheEntry(ValNo, *CurrentBlock);
3030-
addToLeaderTable(ValNo, Phi, CurrentBlock);
3085+
LeaderTable.insert(ValNo, Phi, CurrentBlock);
30313086
Phi->setDebugLoc(CurInst->getDebugLoc());
30323087
CurInst->replaceAllUsesWith(Phi);
30333088
if (MD && Phi->getType()->isPtrOrPtrVectorTy())
30343089
MD->invalidateCachedPointerInfo(Phi);
30353090
VN.erase(CurInst);
3036-
removeFromLeaderTable(ValNo, CurInst, CurrentBlock);
3091+
LeaderTable.erase(ValNo, CurInst, CurrentBlock);
30373092

30383093
LLVM_DEBUG(dbgs() << "GVN PRE removed: " << *CurInst << '\n');
30393094
removeInstruction(CurInst);
@@ -3127,7 +3182,6 @@ void GVNPass::cleanupGlobalSets() {
31273182
VN.clear();
31283183
LeaderTable.clear();
31293184
BlockRPONumber.clear();
3130-
TableAllocator.Reset();
31313185
ICF->clear();
31323186
InvalidBlockRPONumbers = true;
31333187
}
@@ -3147,18 +3201,7 @@ void GVNPass::removeInstruction(Instruction *I) {
31473201
/// internal data structures.
31483202
void GVNPass::verifyRemoved(const Instruction *Inst) const {
31493203
VN.verifyRemoved(Inst);
3150-
3151-
// Walk through the value number scope to make sure the instruction isn't
3152-
// ferreted away in it.
3153-
for (const auto &I : LeaderTable) {
3154-
const LeaderTableEntry *Node = &I.second;
3155-
assert(Node->Val != Inst && "Inst still in value numbering scope!");
3156-
3157-
while (Node->Next) {
3158-
Node = Node->Next;
3159-
assert(Node->Val != Inst && "Inst still in value numbering scope!");
3160-
}
3161-
}
3204+
LeaderTable.verifyRemoved(Inst);
31623205
}
31633206

31643207
/// BB is declared dead, which implied other blocks become dead as well. This
@@ -3285,7 +3328,7 @@ void GVNPass::assignValNumForDeadCode() {
32853328
for (BasicBlock *BB : DeadBlocks) {
32863329
for (Instruction &Inst : *BB) {
32873330
unsigned ValNum = VN.lookupOrAdd(&Inst);
3288-
addToLeaderTable(ValNum, &Inst, BB);
3331+
LeaderTable.insert(ValNum, &Inst, BB);
32893332
}
32903333
}
32913334
}

0 commit comments

Comments
 (0)