1 From 779a169144581438d9e24b8b46a86704f6335e35 Mon Sep 17 00:00:00 2001
2 From: Nikita Popov <nikita.ppv@gmail.com>
3 Date: Sat, 16 Nov 2019 16:22:18 +0100
4 Subject: [PATCH] [LVI] Restructure caching
6 Variant on D70103. The caching is switched to always use a BB to
7 cache entry map, which then contains per-value caches. A separate
8 set contains value handles with a deletion callback. This allows us
9 to properly invalidate overdefined values.
11 A possible alternative would be to always cache by value first and
12 have per-BB maps/sets in the each cache entry. In that case we could
13 use a ValueMap and would avoid the separate value handle set. I went
14 with the BB indexing at the top level to make it easier to integrate
15 D69914, but possibly that's not the right choice.
17 Differential Revision: https://reviews.llvm.org/D70376
19 diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
20 index bad2de9e5f5..33406a75d80 100644
21 --- a/llvm/lib/Analysis/LazyValueInfo.cpp
22 +++ b/llvm/lib/Analysis/LazyValueInfo.cpp
23 @@ -136,12 +136,10 @@ namespace {
24 /// A callback value handle updates the cache when values are erased.
25 class LazyValueInfoCache;
26 struct LVIValueHandle final : public CallbackVH {
27 - // Needs to access getValPtr(), which is protected.
28 - friend struct DenseMapInfo<LVIValueHandle>;
30 LazyValueInfoCache *Parent;
32 - LVIValueHandle(Value *V, LazyValueInfoCache *P)
33 + LVIValueHandle(Value *V, LazyValueInfoCache *P = nullptr)
34 : CallbackVH(V), Parent(P) { }
36 void deleted() override;
37 @@ -155,89 +153,63 @@ namespace {
38 /// This is the cache kept by LazyValueInfo which
39 /// maintains information about queries across the clients' queries.
40 class LazyValueInfoCache {
41 - /// This is all of the cached block information for exactly one Value*.
42 - /// The entries are sorted by the BasicBlock* of the
43 - /// entries, allowing us to do a lookup with a binary search.
44 - /// Over-defined lattice values are recorded in OverDefinedCache to reduce
45 - /// memory overhead.
46 - struct ValueCacheEntryTy {
47 - ValueCacheEntryTy(Value *V, LazyValueInfoCache *P) : Handle(V, P) {}
48 - LVIValueHandle Handle;
49 - SmallDenseMap<PoisoningVH<BasicBlock>, ValueLatticeElement, 4> BlockVals;
50 + /// This is all of the cached information for one basic block. It contains
51 + /// the per-value lattice elements, as well as a separate set for
52 + /// overdefined values to reduce memory usage.
53 + struct BlockCacheEntryTy {
54 + SmallDenseMap<AssertingVH<Value>, ValueLatticeElement, 4> LatticeElements;
55 + SmallDenseSet<AssertingVH<Value>, 4> OverDefined;
58 - /// This tracks, on a per-block basis, the set of values that are
59 - /// over-defined at the end of that block.
60 - typedef DenseMap<PoisoningVH<BasicBlock>, SmallPtrSet<Value *, 4>>
62 - /// Keep track of all blocks that we have ever seen, so we
63 - /// don't spend time removing unused blocks from our caches.
64 - DenseSet<PoisoningVH<BasicBlock> > SeenBlocks;
66 - /// This is all of the cached information for all values,
67 - /// mapped from Value* to key information.
68 - DenseMap<Value *, std::unique_ptr<ValueCacheEntryTy>> ValueCache;
69 - OverDefinedCacheTy OverDefinedCache;
71 + /// Cached information per basic block.
72 + DenseMap<PoisoningVH<BasicBlock>, BlockCacheEntryTy> BlockCache;
73 + /// Set of value handles used to erase values from the cache on deletion.
74 + DenseSet<LVIValueHandle, DenseMapInfo<Value *>> ValueHandles;
77 void insertResult(Value *Val, BasicBlock *BB,
78 const ValueLatticeElement &Result) {
79 - SeenBlocks.insert(BB);
81 + auto &CacheEntry = BlockCache.try_emplace(BB).first->second;
82 // Insert over-defined values into their own cache to reduce memory
84 if (Result.isOverdefined())
85 - OverDefinedCache[BB].insert(Val);
87 - auto It = ValueCache.find_as(Val);
88 - if (It == ValueCache.end()) {
89 - ValueCache[Val] = std::make_unique<ValueCacheEntryTy>(Val, this);
90 - It = ValueCache.find_as(Val);
91 - assert(It != ValueCache.end() && "Val was just added to the map!");
93 - It->second->BlockVals[BB] = Result;
97 - bool isOverdefined(Value *V, BasicBlock *BB) const {
98 - auto ODI = OverDefinedCache.find(BB);
100 - if (ODI == OverDefinedCache.end())
102 + CacheEntry.OverDefined.insert(Val);
104 + CacheEntry.LatticeElements.insert({ Val, Result });
106 - return ODI->second.count(V);
107 + auto HandleIt = ValueHandles.find_as(Val);
108 + if (HandleIt == ValueHandles.end())
109 + ValueHandles.insert({ Val, this });
112 bool hasCachedValueInfo(Value *V, BasicBlock *BB) const {
113 - if (isOverdefined(V, BB))
116 - auto I = ValueCache.find_as(V);
117 - if (I == ValueCache.end())
118 + auto It = BlockCache.find(BB);
119 + if (It == BlockCache.end())
122 - return I->second->BlockVals.count(BB);
123 + return It->second.OverDefined.count(V) ||
124 + It->second.LatticeElements.count(V);
127 ValueLatticeElement getCachedValueInfo(Value *V, BasicBlock *BB) const {
128 - if (isOverdefined(V, BB))
129 + auto It = BlockCache.find(BB);
130 + if (It == BlockCache.end())
131 + return ValueLatticeElement();
133 + if (It->second.OverDefined.count(V))
134 return ValueLatticeElement::getOverdefined();
136 - auto I = ValueCache.find_as(V);
137 - if (I == ValueCache.end())
138 - return ValueLatticeElement();
139 - auto BBI = I->second->BlockVals.find(BB);
140 - if (BBI == I->second->BlockVals.end())
141 + auto LatticeIt = It->second.LatticeElements.find(V);
142 + if (LatticeIt == It->second.LatticeElements.end())
143 return ValueLatticeElement();
144 - return BBI->second;
146 + return LatticeIt->second;
149 /// clear - Empty the cache.
151 - SeenBlocks.clear();
152 - ValueCache.clear();
153 - OverDefinedCache.clear();
154 + BlockCache.clear();
155 + ValueHandles.clear();
158 /// Inform the cache that a given value has been deleted.
159 @@ -251,23 +223,18 @@ namespace {
160 /// OldSucc might have (unless also overdefined in NewSucc). This just
161 /// flushes elements from the cache and does not add any.
162 void threadEdgeImpl(BasicBlock *OldSucc,BasicBlock *NewSucc);
164 - friend struct LVIValueHandle;
168 void LazyValueInfoCache::eraseValue(Value *V) {
169 - for (auto I = OverDefinedCache.begin(), E = OverDefinedCache.end(); I != E;) {
170 - // Copy and increment the iterator immediately so we can erase behind
173 - SmallPtrSetImpl<Value *> &ValueSet = Iter->second;
175 - if (ValueSet.empty())
176 - OverDefinedCache.erase(Iter);
177 + for (auto &Pair : BlockCache) {
178 + Pair.second.LatticeElements.erase(V);
179 + Pair.second.OverDefined.erase(V);
182 - ValueCache.erase(V);
183 + auto HandleIt = ValueHandles.find_as(V);
184 + if (HandleIt != ValueHandles.end())
185 + ValueHandles.erase(HandleIt);
188 void LVIValueHandle::deleted() {
189 @@ -277,18 +244,7 @@ void LVIValueHandle::deleted() {
192 void LazyValueInfoCache::eraseBlock(BasicBlock *BB) {
193 - // Shortcut if we have never seen this block.
194 - DenseSet<PoisoningVH<BasicBlock> >::iterator I = SeenBlocks.find(BB);
195 - if (I == SeenBlocks.end())
197 - SeenBlocks.erase(I);
199 - auto ODI = OverDefinedCache.find(BB);
200 - if (ODI != OverDefinedCache.end())
201 - OverDefinedCache.erase(ODI);
203 - for (auto &I : ValueCache)
204 - I.second->BlockVals.erase(BB);
205 + BlockCache.erase(BB);
208 void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
209 @@ -306,10 +262,11 @@ void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
210 std::vector<BasicBlock*> worklist;
211 worklist.push_back(OldSucc);
213 - auto I = OverDefinedCache.find(OldSucc);
214 - if (I == OverDefinedCache.end())
215 + auto I = BlockCache.find(OldSucc);
216 + if (I == BlockCache.end() || I->second.OverDefined.empty())
217 return; // Nothing to process here.
218 - SmallVector<Value *, 4> ValsToClear(I->second.begin(), I->second.end());
219 + SmallVector<Value *, 4> ValsToClear(I->second.OverDefined.begin(),
220 + I->second.OverDefined.end());
222 // Use a worklist to perform a depth-first search of OldSucc's successors.
223 // NOTE: We do not need a visited list since any blocks we have already
224 @@ -323,10 +280,10 @@ void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
225 if (ToUpdate == NewSucc) continue;
227 // If a value was marked overdefined in OldSucc, and is here too...
228 - auto OI = OverDefinedCache.find(ToUpdate);
229 - if (OI == OverDefinedCache.end())
230 + auto OI = BlockCache.find(ToUpdate);
231 + if (OI == BlockCache.end() || OI->second.OverDefined.empty())
233 - SmallPtrSetImpl<Value *> &ValueSet = OI->second;
234 + auto &ValueSet = OI->second.OverDefined;
236 bool changed = false;
237 for (Value *V : ValsToClear) {
238 @@ -336,11 +293,6 @@ void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
239 // If we removed anything, then we potentially need to update
240 // blocks successors too.
243 - if (ValueSet.empty()) {
244 - OverDefinedCache.erase(OI);
249 if (!changed) continue;