Skip to content

Commit ad71aea

Browse files
committed
[IR] Improve PredIteratorCache to use block numbers
Avoid using DenseMap of BasicBlocks when a vector is sufficient. This only has a few users, so gains are low, but so is the effort. There's no longer a separate map which only holds sizes. All users that used size() also use get() afterwards, so it's always beneficial to compute both.
1 parent e7f9d8e commit ad71aea

File tree

1 file changed

+25
-35
lines changed

1 file changed

+25
-35
lines changed

llvm/include/llvm/IR/PredIteratorCache.h

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -25,52 +25,42 @@ namespace llvm {
2525
/// predecessor iterator queries. This is useful for code that repeatedly
2626
/// wants the predecessor list for the same blocks.
2727
class PredIteratorCache {
28-
/// BlockToPredsMap - Pointer to null-terminated list.
29-
mutable DenseMap<BasicBlock *, BasicBlock **> BlockToPredsMap;
30-
mutable DenseMap<BasicBlock *, unsigned> BlockToPredCountMap;
28+
/// Storage, indexed by block number.
29+
SmallVector<ArrayRef<BasicBlock *>> Storage;
30+
/// Block number epoch to guard against renumberings.
31+
unsigned BlockNumberEpoch;
3132

3233
/// Memory - This is the space that holds cached preds.
3334
BumpPtrAllocator Memory;
3435

35-
private:
36-
/// GetPreds - Get a cached list for the null-terminated predecessor list of
37-
/// the specified block. This can be used in a loop like this:
38-
/// for (BasicBlock **PI = PredCache->GetPreds(BB); *PI; ++PI)
39-
/// use(*PI);
40-
/// instead of:
41-
/// for (pred_iterator PI = pred_begin(BB), E = pred_end(BB); PI != E; ++PI)
42-
BasicBlock **GetPreds(BasicBlock *BB) {
43-
BasicBlock **&Entry = BlockToPredsMap[BB];
44-
if (Entry)
45-
return Entry;
46-
47-
SmallVector<BasicBlock *, 32> PredCache(predecessors(BB));
48-
PredCache.push_back(nullptr); // null terminator.
36+
public:
37+
size_t size(BasicBlock *BB) { return get(BB).size(); }
38+
ArrayRef<BasicBlock *> get(BasicBlock *BB) {
39+
#ifndef NDEBUG
40+
// In debug builds, verify that no renumbering has occured.
41+
if (Storage.empty())
42+
BlockNumberEpoch = BB->getParent()->getBlockNumberEpoch();
43+
else
44+
assert(BlockNumberEpoch == BB->getParent()->getBlockNumberEpoch() &&
45+
"Blocks renumbered during lifetime of PredIteratorCache");
46+
#endif
4947

50-
BlockToPredCountMap[BB] = PredCache.size() - 1;
48+
if (LLVM_LIKELY(BB->getNumber() < Storage.size()))
49+
if (auto Res = Storage[BB->getNumber()]; Res.data())
50+
return Res;
5151

52-
Entry = Memory.Allocate<BasicBlock *>(PredCache.size());
53-
std::copy(PredCache.begin(), PredCache.end(), Entry);
54-
return Entry;
55-
}
52+
if (BB->getNumber() >= Storage.size())
53+
Storage.resize(BB->getParent()->getMaxBlockNumber());
5654

57-
unsigned GetNumPreds(BasicBlock *BB) const {
58-
auto Result = BlockToPredCountMap.find(BB);
59-
if (Result != BlockToPredCountMap.end())
60-
return Result->second;
61-
return BlockToPredCountMap[BB] = pred_size(BB);
62-
}
63-
64-
public:
65-
size_t size(BasicBlock *BB) const { return GetNumPreds(BB); }
66-
ArrayRef<BasicBlock *> get(BasicBlock *BB) {
67-
return ArrayRef(GetPreds(BB), GetNumPreds(BB));
55+
SmallVector<BasicBlock *, 32> PredCache(predecessors(BB));
56+
BasicBlock **Data = Memory.Allocate<BasicBlock *>(PredCache.size());
57+
std::copy(PredCache.begin(), PredCache.end(), Data);
58+
return Storage[BB->getNumber()] = ArrayRef(Data, PredCache.size());
6859
}
6960

7061
/// clear - Remove all information.
7162
void clear() {
72-
BlockToPredsMap.clear();
73-
BlockToPredCountMap.clear();
63+
Storage.clear();
7464
Memory.Reset();
7565
}
7666
};

0 commit comments

Comments
 (0)