43909.patch 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. From c95310f2d4fd3c88241c3b5d6dbf6251d34a3256 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] Restructure caching
  5. Variant on D70103. The caching is switched to always use a BB to
  6. cache entry map, which then contains per-value caches. A separate
  7. set contains value handles with a deletion callback. This allows us
  8. to properly invalidate overdefined values.
  9. A possible alternative would be to always cache by value first and
  10. have per-BB maps/sets in the each cache entry. In that case we could
  11. use a ValueMap and would avoid the separate value handle set. I went
  12. with the BB indexing at the top level to make it easier to integrate
  13. D69914, but possibly that's not the right choice.
  14. Differential Revision: https://reviews.llvm.org/D70376
  15. diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
  16. index 110c085d3f3..aa6862cb588 100644
  17. --- a/llvm/lib/Analysis/LazyValueInfo.cpp
  18. +++ b/llvm/lib/Analysis/LazyValueInfo.cpp
  19. @@ -133,12 +133,9 @@ namespace {
  20. /// A callback value handle updates the cache when values are erased.
  21. class LazyValueInfoCache;
  22. struct LVIValueHandle final : public CallbackVH {
  23. - // Needs to access getValPtr(), which is protected.
  24. - friend struct DenseMapInfo<LVIValueHandle>;
  25. -
  26. LazyValueInfoCache *Parent;
  27. - LVIValueHandle(Value *V, LazyValueInfoCache *P)
  28. + LVIValueHandle(Value *V, LazyValueInfoCache *P = nullptr)
  29. : CallbackVH(V), Parent(P) { }
  30. void deleted() override;
  31. @@ -152,89 +149,63 @@ namespace {
  32. /// This is the cache kept by LazyValueInfo which
  33. /// maintains information about queries across the clients' queries.
  34. class LazyValueInfoCache {
  35. - /// This is all of the cached block information for exactly one Value*.
  36. - /// The entries are sorted by the BasicBlock* of the
  37. - /// entries, allowing us to do a lookup with a binary search.
  38. - /// Over-defined lattice values are recorded in OverDefinedCache to reduce
  39. - /// memory overhead.
  40. - struct ValueCacheEntryTy {
  41. - ValueCacheEntryTy(Value *V, LazyValueInfoCache *P) : Handle(V, P) {}
  42. - LVIValueHandle Handle;
  43. - SmallDenseMap<PoisoningVH<BasicBlock>, ValueLatticeElement, 4> BlockVals;
  44. + /// This is all of the cached information for one basic block. It contains
  45. + /// the per-value lattice elements, as well as a separate set for
  46. + /// overdefined values to reduce memory usage.
  47. + struct BlockCacheEntryTy {
  48. + SmallDenseMap<AssertingVH<Value>, ValueLatticeElement, 4> LatticeElements;
  49. + SmallDenseSet<AssertingVH<Value>, 4> OverDefined;
  50. };
  51. - /// This tracks, on a per-block basis, the set of values that are
  52. - /// over-defined at the end of that block.
  53. - typedef DenseMap<PoisoningVH<BasicBlock>, SmallPtrSet<Value *, 4>>
  54. - OverDefinedCacheTy;
  55. - /// Keep track of all blocks that we have ever seen, so we
  56. - /// don't spend time removing unused blocks from our caches.
  57. - DenseSet<PoisoningVH<BasicBlock> > SeenBlocks;
  58. -
  59. - /// This is all of the cached information for all values,
  60. - /// mapped from Value* to key information.
  61. - DenseMap<Value *, std::unique_ptr<ValueCacheEntryTy>> ValueCache;
  62. - OverDefinedCacheTy OverDefinedCache;
  63. -
  64. + /// Cached information per basic block.
  65. + DenseMap<PoisoningVH<BasicBlock>, BlockCacheEntryTy> BlockCache;
  66. + /// Set of value handles used to erase values from the cache on deletion.
  67. + DenseSet<LVIValueHandle, DenseMapInfo<Value *>> ValueHandles;
  68. public:
  69. void insertResult(Value *Val, BasicBlock *BB,
  70. const ValueLatticeElement &Result) {
  71. - SeenBlocks.insert(BB);
  72. -
  73. + auto &CacheEntry = BlockCache.try_emplace(BB).first->second;
  74. // Insert over-defined values into their own cache to reduce memory
  75. // overhead.
  76. if (Result.isOverdefined())
  77. - OverDefinedCache[BB].insert(Val);
  78. - else {
  79. - auto It = ValueCache.find_as(Val);
  80. - if (It == ValueCache.end()) {
  81. - ValueCache[Val] = make_unique<ValueCacheEntryTy>(Val, this);
  82. - It = ValueCache.find_as(Val);
  83. - assert(It != ValueCache.end() && "Val was just added to the map!");
  84. - }
  85. - It->second->BlockVals[BB] = Result;
  86. - }
  87. - }
  88. -
  89. - bool isOverdefined(Value *V, BasicBlock *BB) const {
  90. - auto ODI = OverDefinedCache.find(BB);
  91. -
  92. - if (ODI == OverDefinedCache.end())
  93. - return false;
  94. + CacheEntry.OverDefined.insert(Val);
  95. + else
  96. + CacheEntry.LatticeElements.insert({ Val, Result });
  97. - return ODI->second.count(V);
  98. + auto HandleIt = ValueHandles.find_as(Val);
  99. + if (HandleIt == ValueHandles.end())
  100. + ValueHandles.insert({ Val, this });
  101. }
  102. bool hasCachedValueInfo(Value *V, BasicBlock *BB) const {
  103. - if (isOverdefined(V, BB))
  104. - return true;
  105. -
  106. - auto I = ValueCache.find_as(V);
  107. - if (I == ValueCache.end())
  108. + auto It = BlockCache.find(BB);
  109. + if (It == BlockCache.end())
  110. return false;
  111. - return I->second->BlockVals.count(BB);
  112. + return It->second.OverDefined.count(V) ||
  113. + It->second.LatticeElements.count(V);
  114. }
  115. ValueLatticeElement getCachedValueInfo(Value *V, BasicBlock *BB) const {
  116. - if (isOverdefined(V, BB))
  117. + auto It = BlockCache.find(BB);
  118. + if (It == BlockCache.end())
  119. + return ValueLatticeElement();
  120. +
  121. + if (It->second.OverDefined.count(V))
  122. return ValueLatticeElement::getOverdefined();
  123. - auto I = ValueCache.find_as(V);
  124. - if (I == ValueCache.end())
  125. + auto LatticeIt = It->second.LatticeElements.find(V);
  126. + if (LatticeIt == It->second.LatticeElements.end())
  127. return ValueLatticeElement();
  128. - auto BBI = I->second->BlockVals.find(BB);
  129. - if (BBI == I->second->BlockVals.end())
  130. - return ValueLatticeElement();
  131. - return BBI->second;
  132. +
  133. + return LatticeIt->second;
  134. }
  135. /// clear - Empty the cache.
  136. void clear() {
  137. - SeenBlocks.clear();
  138. - ValueCache.clear();
  139. - OverDefinedCache.clear();
  140. + BlockCache.clear();
  141. + ValueHandles.clear();
  142. }
  143. /// Inform the cache that a given value has been deleted.
  144. @@ -248,23 +219,18 @@ namespace {
  145. /// OldSucc might have (unless also overdefined in NewSucc). This just
  146. /// flushes elements from the cache and does not add any.
  147. void threadEdgeImpl(BasicBlock *OldSucc,BasicBlock *NewSucc);
  148. -
  149. - friend struct LVIValueHandle;
  150. };
  151. }
  152. void LazyValueInfoCache::eraseValue(Value *V) {
  153. - for (auto I = OverDefinedCache.begin(), E = OverDefinedCache.end(); I != E;) {
  154. - // Copy and increment the iterator immediately so we can erase behind
  155. - // ourselves.
  156. - auto Iter = I++;
  157. - SmallPtrSetImpl<Value *> &ValueSet = Iter->second;
  158. - ValueSet.erase(V);
  159. - if (ValueSet.empty())
  160. - OverDefinedCache.erase(Iter);
  161. + for (auto &Pair : BlockCache) {
  162. + Pair.second.LatticeElements.erase(V);
  163. + Pair.second.OverDefined.erase(V);
  164. }
  165. - ValueCache.erase(V);
  166. + auto HandleIt = ValueHandles.find_as(V);
  167. + if (HandleIt != ValueHandles.end())
  168. + ValueHandles.erase(HandleIt);
  169. }
  170. void LVIValueHandle::deleted() {
  171. @@ -274,18 +240,7 @@ void LVIValueHandle::deleted() {
  172. }
  173. void LazyValueInfoCache::eraseBlock(BasicBlock *BB) {
  174. - // Shortcut if we have never seen this block.
  175. - DenseSet<PoisoningVH<BasicBlock> >::iterator I = SeenBlocks.find(BB);
  176. - if (I == SeenBlocks.end())
  177. - return;
  178. - SeenBlocks.erase(I);
  179. -
  180. - auto ODI = OverDefinedCache.find(BB);
  181. - if (ODI != OverDefinedCache.end())
  182. - OverDefinedCache.erase(ODI);
  183. -
  184. - for (auto &I : ValueCache)
  185. - I.second->BlockVals.erase(BB);
  186. + BlockCache.erase(BB);
  187. }
  188. void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
  189. @@ -303,10 +258,11 @@ void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
  190. std::vector<BasicBlock*> worklist;
  191. worklist.push_back(OldSucc);
  192. - auto I = OverDefinedCache.find(OldSucc);
  193. - if (I == OverDefinedCache.end())
  194. + auto I = BlockCache.find(OldSucc);
  195. + if (I == BlockCache.end() || I->second.OverDefined.empty())
  196. return; // Nothing to process here.
  197. - SmallVector<Value *, 4> ValsToClear(I->second.begin(), I->second.end());
  198. + SmallVector<Value *, 4> ValsToClear(I->second.OverDefined.begin(),
  199. + I->second.OverDefined.end());
  200. // Use a worklist to perform a depth-first search of OldSucc's successors.
  201. // NOTE: We do not need a visited list since any blocks we have already
  202. @@ -320,10 +276,10 @@ void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
  203. if (ToUpdate == NewSucc) continue;
  204. // If a value was marked overdefined in OldSucc, and is here too...
  205. - auto OI = OverDefinedCache.find(ToUpdate);
  206. - if (OI == OverDefinedCache.end())
  207. + auto OI = BlockCache.find(ToUpdate);
  208. + if (OI == BlockCache.end() || OI->second.OverDefined.empty())
  209. continue;
  210. - SmallPtrSetImpl<Value *> &ValueSet = OI->second;
  211. + auto &ValueSet = OI->second.OverDefined;
  212. bool changed = false;
  213. for (Value *V : ValsToClear) {
  214. @@ -333,11 +289,6 @@ void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
  215. // If we removed anything, then we potentially need to update
  216. // blocks successors too.
  217. changed = true;
  218. -
  219. - if (ValueSet.empty()) {
  220. - OverDefinedCache.erase(OI);
  221. - break;
  222. - }
  223. }
  224. if (!changed) continue;
  225. --
  226. 2.24.0