Skip to content

Commit 649b691

Browse files
resistormemfrob
authored andcommitted
Replace the custom linked list in LeaderTableEntry with TinyPtrVector.
The purpose of the custom linked list was to optimize for the case of a single-element list. It turns out that TinyPtrVector handles the same basic scenario even better, reducing the size of LeaderTableEntry by 33%, and requiring only log2(N) allocations as the size of the list grows. The only downside is that we have to store the Value's and BasicBlock's in separate vectors, which is slightly awkward in a few cases. Fortunately that ends up being entirely encapsulated inside helper functions. Reviewed By: asbirlea Differential Revision: https://reviews.llvm.org/D125205
1 parent a01710e commit 649b691

File tree

2 files changed

+40
-64
lines changed
  • llvm
    • include/llvm/Transforms/Scalar
    • lib/Transforms/Scalar

2 files changed

+40
-64
lines changed

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

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include "llvm/ADT/MapVector.h"
2020
#include "llvm/ADT/SetVector.h"
2121
#include "llvm/ADT/SmallVector.h"
22+
#include "llvm/ADT/TinyPtrVector.h"
2223
#include "llvm/IR/Dominators.h"
2324
#include "llvm/IR/InstrTypes.h"
2425
#include "llvm/IR/PassManager.h"
@@ -232,12 +233,10 @@ class GVNPass : public PassInfoMixin<GVNPass> {
232233
/// A mapping from value numbers to lists of Value*'s that
233234
/// have that value number. Use findLeader to query it.
234235
struct LeaderTableEntry {
235-
Value *Val;
236-
const BasicBlock *BB;
237-
LeaderTableEntry *Next;
236+
TinyPtrVector<Value *> Val;
237+
TinyPtrVector<const BasicBlock *> BB;
238238
};
239239
DenseMap<uint32_t, LeaderTableEntry> LeaderTable;
240-
BumpPtrAllocator TableAllocator;
241240

242241
// Block-local map of equivalent values to their leader, does not
243242
// propagate to any successors. Entries added mid-block are applied
@@ -266,44 +265,31 @@ class GVNPass : public PassInfoMixin<GVNPass> {
266265
/// Push a new Value to the LeaderTable onto the list for its value number.
267266
void addToLeaderTable(uint32_t N, Value *V, const BasicBlock *BB) {
268267
LeaderTableEntry &Curr = LeaderTable[N];
269-
if (!Curr.Val) {
270-
Curr.Val = V;
271-
Curr.BB = BB;
272-
return;
268+
if (Curr.Val.size() == 0) {
269+
Curr.Val.push_back(V);
270+
Curr.BB.push_back(BB);
271+
} else {
272+
Curr.Val.insert(Curr.Val.begin()+1, V);
273+
Curr.BB.insert(Curr.BB.begin()+1, BB);
273274
}
274-
275-
LeaderTableEntry *Node = TableAllocator.Allocate<LeaderTableEntry>();
276-
Node->Val = V;
277-
Node->BB = BB;
278-
Node->Next = Curr.Next;
279-
Curr.Next = Node;
280275
}
281276

282277
/// Scan the list of values corresponding to a given
283278
/// value number, and remove the given instruction if encountered.
284279
void removeFromLeaderTable(uint32_t N, Instruction *I, BasicBlock *BB) {
285-
LeaderTableEntry *Prev = nullptr;
286-
LeaderTableEntry *Curr = &LeaderTable[N];
287-
288-
while (Curr && (Curr->Val != I || Curr->BB != BB)) {
289-
Prev = Curr;
290-
Curr = Curr->Next;
291-
}
292-
293-
if (!Curr)
294-
return;
295-
296-
if (Prev) {
297-
Prev->Next = Curr->Next;
298-
} else {
299-
if (!Curr->Next) {
300-
Curr->Val = nullptr;
301-
Curr->BB = nullptr;
280+
LeaderTableEntry &entry = LeaderTable[N];
281+
assert(entry.BB.size() == entry.Val.size());
282+
auto VI = entry.Val.begin();
283+
auto VE = entry.Val.end();
284+
auto BI = entry.BB.begin();
285+
while (VI != VE) {
286+
if (*VI == I && *BI == BB) {
287+
VI = entry.Val.erase(VI);
288+
BI = entry.BB.erase(BI);
289+
VE = entry.Val.end();
302290
} else {
303-
LeaderTableEntry *Next = Curr->Next;
304-
Curr->Val = Next->Val;
305-
Curr->BB = Next->BB;
306-
Curr->Next = Next->Next;
291+
++VI;
292+
++BI;
307293
}
308294
}
309295
}

llvm/lib/Transforms/Scalar/GVN.cpp

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -2105,10 +2105,9 @@ GVNPass::ValueTable::assignExpNewValueNum(Expression &Exp) {
21052105
/// defined in \p BB.
21062106
bool GVNPass::ValueTable::areAllValsInBB(uint32_t Num, const BasicBlock *BB,
21072107
GVNPass &Gvn) {
2108-
LeaderTableEntry *Vals = &Gvn.LeaderTable[Num];
2109-
while (Vals && Vals->BB == BB)
2110-
Vals = Vals->Next;
2111-
return !Vals;
2108+
const LeaderTableEntry &Entry = Gvn.LeaderTable[Num];
2109+
return all_of(Entry.BB,
2110+
[BB](const BasicBlock *EntryBB) { return EntryBB == BB; });
21122111
}
21132112

21142113
/// Wrap phiTranslateImpl to provide caching functionality.
@@ -2130,12 +2129,11 @@ bool GVNPass::ValueTable::areCallValsEqual(uint32_t Num, uint32_t NewNum,
21302129
const BasicBlock *PhiBlock,
21312130
GVNPass &Gvn) {
21322131
CallInst *Call = nullptr;
2133-
LeaderTableEntry *Vals = &Gvn.LeaderTable[Num];
2134-
while (Vals) {
2135-
Call = dyn_cast<CallInst>(Vals->Val);
2132+
const LeaderTableEntry &Entry = Gvn.LeaderTable[Num];
2133+
for (Value *Val : Entry.Val) {
2134+
Call = dyn_cast<CallInst>(Val);
21362135
if (Call && Call->getParent() == PhiBlock)
21372136
break;
2138-
Vals = Vals->Next;
21392137
}
21402138

21412139
if (AA->doesNotAccessMemory(Call))
@@ -2228,23 +2226,18 @@ void GVNPass::ValueTable::eraseTranslateCacheEntry(
22282226
// question. This is fast because dominator tree queries consist of only
22292227
// a few comparisons of DFS numbers.
22302228
Value *GVNPass::findLeader(const BasicBlock *BB, uint32_t num) {
2231-
LeaderTableEntry Vals = LeaderTable[num];
2232-
if (!Vals.Val) return nullptr;
2229+
const LeaderTableEntry &Entry = LeaderTable[num];
2230+
if (Entry.Val.empty())
2231+
return nullptr;
22332232

22342233
Value *Val = nullptr;
2235-
if (DT->dominates(Vals.BB, BB)) {
2236-
Val = Vals.Val;
2237-
if (isa<Constant>(Val)) return Val;
2238-
}
2239-
2240-
LeaderTableEntry* Next = Vals.Next;
2241-
while (Next) {
2242-
if (DT->dominates(Next->BB, BB)) {
2243-
if (isa<Constant>(Next->Val)) return Next->Val;
2244-
if (!Val) Val = Next->Val;
2234+
for (size_t i = 0, e = Entry.Val.size(); i != e; ++i) {
2235+
if (DT->dominates(Entry.BB[i], BB)) {
2236+
if (isa<Constant>(Entry.Val[i]))
2237+
return Entry.Val[i];
2238+
if (!Val)
2239+
Val = Entry.Val[i];
22452240
}
2246-
2247-
Next = Next->Next;
22482241
}
22492242

22502243
return Val;
@@ -3033,7 +3026,6 @@ void GVNPass::cleanupGlobalSets() {
30333026
VN.clear();
30343027
LeaderTable.clear();
30353028
BlockRPONumber.clear();
3036-
TableAllocator.Reset();
30373029
ICF->clear();
30383030
InvalidBlockRPONumbers = true;
30393031
}
@@ -3046,12 +3038,10 @@ void GVNPass::verifyRemoved(const Instruction *Inst) const {
30463038
// Walk through the value number scope to make sure the instruction isn't
30473039
// ferreted away in it.
30483040
for (const auto &I : LeaderTable) {
3049-
const LeaderTableEntry *Node = &I.second;
3050-
assert(Node->Val != Inst && "Inst still in value numbering scope!");
3051-
3052-
while (Node->Next) {
3053-
Node = Node->Next;
3054-
assert(Node->Val != Inst && "Inst still in value numbering scope!");
3041+
const LeaderTableEntry &Entry = I.second;
3042+
for (Value *Val : Entry.Val) {
3043+
(void)Val;
3044+
assert(Val != Inst && "Inst still in value numbering scope!");
30553045
}
30563046
}
30573047
}

0 commit comments

Comments
 (0)