123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- From c95310f2d4fd3c88241c3b5d6dbf6251d34a3256 Mon Sep 17 00:00:00 2001
- From: Nikita Popov <nikita.ppv@gmail.com>
- Date: Sat, 16 Nov 2019 16:22:18 +0100
- Subject: [PATCH] Restructure caching
- Variant on D70103. The caching is switched to always use a BB to
- cache entry map, which then contains per-value caches. A separate
- set contains value handles with a deletion callback. This allows us
- to properly invalidate overdefined values.
- A possible alternative would be to always cache by value first and
- have per-BB maps/sets in the each cache entry. In that case we could
- use a ValueMap and would avoid the separate value handle set. I went
- with the BB indexing at the top level to make it easier to integrate
- D69914, but possibly that's not the right choice.
- Differential Revision: https://reviews.llvm.org/D70376
- diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp
- index 110c085d3f3..aa6862cb588 100644
- --- a/llvm/lib/Analysis/LazyValueInfo.cpp
- +++ b/llvm/lib/Analysis/LazyValueInfo.cpp
- @@ -133,12 +133,9 @@ namespace {
- /// A callback value handle updates the cache when values are erased.
- class LazyValueInfoCache;
- struct LVIValueHandle final : public CallbackVH {
- - // Needs to access getValPtr(), which is protected.
- - friend struct DenseMapInfo<LVIValueHandle>;
- -
- LazyValueInfoCache *Parent;
-
- - LVIValueHandle(Value *V, LazyValueInfoCache *P)
- + LVIValueHandle(Value *V, LazyValueInfoCache *P = nullptr)
- : CallbackVH(V), Parent(P) { }
-
- void deleted() override;
- @@ -152,89 +149,63 @@ namespace {
- /// This is the cache kept by LazyValueInfo which
- /// maintains information about queries across the clients' queries.
- class LazyValueInfoCache {
- - /// This is all of the cached block information for exactly one Value*.
- - /// The entries are sorted by the BasicBlock* of the
- - /// entries, allowing us to do a lookup with a binary search.
- - /// Over-defined lattice values are recorded in OverDefinedCache to reduce
- - /// memory overhead.
- - struct ValueCacheEntryTy {
- - ValueCacheEntryTy(Value *V, LazyValueInfoCache *P) : Handle(V, P) {}
- - LVIValueHandle Handle;
- - SmallDenseMap<PoisoningVH<BasicBlock>, ValueLatticeElement, 4> BlockVals;
- + /// This is all of the cached information for one basic block. It contains
- + /// the per-value lattice elements, as well as a separate set for
- + /// overdefined values to reduce memory usage.
- + struct BlockCacheEntryTy {
- + SmallDenseMap<AssertingVH<Value>, ValueLatticeElement, 4> LatticeElements;
- + SmallDenseSet<AssertingVH<Value>, 4> OverDefined;
- };
-
- - /// This tracks, on a per-block basis, the set of values that are
- - /// over-defined at the end of that block.
- - typedef DenseMap<PoisoningVH<BasicBlock>, SmallPtrSet<Value *, 4>>
- - OverDefinedCacheTy;
- - /// Keep track of all blocks that we have ever seen, so we
- - /// don't spend time removing unused blocks from our caches.
- - DenseSet<PoisoningVH<BasicBlock> > SeenBlocks;
- -
- - /// This is all of the cached information for all values,
- - /// mapped from Value* to key information.
- - DenseMap<Value *, std::unique_ptr<ValueCacheEntryTy>> ValueCache;
- - OverDefinedCacheTy OverDefinedCache;
- -
- + /// Cached information per basic block.
- + DenseMap<PoisoningVH<BasicBlock>, BlockCacheEntryTy> BlockCache;
- + /// Set of value handles used to erase values from the cache on deletion.
- + DenseSet<LVIValueHandle, DenseMapInfo<Value *>> ValueHandles;
-
- public:
- void insertResult(Value *Val, BasicBlock *BB,
- const ValueLatticeElement &Result) {
- - SeenBlocks.insert(BB);
- -
- + auto &CacheEntry = BlockCache.try_emplace(BB).first->second;
- // Insert over-defined values into their own cache to reduce memory
- // overhead.
- if (Result.isOverdefined())
- - OverDefinedCache[BB].insert(Val);
- - else {
- - auto It = ValueCache.find_as(Val);
- - if (It == ValueCache.end()) {
- - ValueCache[Val] = make_unique<ValueCacheEntryTy>(Val, this);
- - It = ValueCache.find_as(Val);
- - assert(It != ValueCache.end() && "Val was just added to the map!");
- - }
- - It->second->BlockVals[BB] = Result;
- - }
- - }
- -
- - bool isOverdefined(Value *V, BasicBlock *BB) const {
- - auto ODI = OverDefinedCache.find(BB);
- -
- - if (ODI == OverDefinedCache.end())
- - return false;
- + CacheEntry.OverDefined.insert(Val);
- + else
- + CacheEntry.LatticeElements.insert({ Val, Result });
-
- - return ODI->second.count(V);
- + auto HandleIt = ValueHandles.find_as(Val);
- + if (HandleIt == ValueHandles.end())
- + ValueHandles.insert({ Val, this });
- }
-
- bool hasCachedValueInfo(Value *V, BasicBlock *BB) const {
- - if (isOverdefined(V, BB))
- - return true;
- -
- - auto I = ValueCache.find_as(V);
- - if (I == ValueCache.end())
- + auto It = BlockCache.find(BB);
- + if (It == BlockCache.end())
- return false;
-
- - return I->second->BlockVals.count(BB);
- + return It->second.OverDefined.count(V) ||
- + It->second.LatticeElements.count(V);
- }
-
- ValueLatticeElement getCachedValueInfo(Value *V, BasicBlock *BB) const {
- - if (isOverdefined(V, BB))
- + auto It = BlockCache.find(BB);
- + if (It == BlockCache.end())
- + return ValueLatticeElement();
- +
- + if (It->second.OverDefined.count(V))
- return ValueLatticeElement::getOverdefined();
-
- - auto I = ValueCache.find_as(V);
- - if (I == ValueCache.end())
- + auto LatticeIt = It->second.LatticeElements.find(V);
- + if (LatticeIt == It->second.LatticeElements.end())
- return ValueLatticeElement();
- - auto BBI = I->second->BlockVals.find(BB);
- - if (BBI == I->second->BlockVals.end())
- - return ValueLatticeElement();
- - return BBI->second;
- +
- + return LatticeIt->second;
- }
-
- /// clear - Empty the cache.
- void clear() {
- - SeenBlocks.clear();
- - ValueCache.clear();
- - OverDefinedCache.clear();
- + BlockCache.clear();
- + ValueHandles.clear();
- }
-
- /// Inform the cache that a given value has been deleted.
- @@ -248,23 +219,18 @@ namespace {
- /// OldSucc might have (unless also overdefined in NewSucc). This just
- /// flushes elements from the cache and does not add any.
- void threadEdgeImpl(BasicBlock *OldSucc,BasicBlock *NewSucc);
- -
- - friend struct LVIValueHandle;
- };
- }
-
- void LazyValueInfoCache::eraseValue(Value *V) {
- - for (auto I = OverDefinedCache.begin(), E = OverDefinedCache.end(); I != E;) {
- - // Copy and increment the iterator immediately so we can erase behind
- - // ourselves.
- - auto Iter = I++;
- - SmallPtrSetImpl<Value *> &ValueSet = Iter->second;
- - ValueSet.erase(V);
- - if (ValueSet.empty())
- - OverDefinedCache.erase(Iter);
- + for (auto &Pair : BlockCache) {
- + Pair.second.LatticeElements.erase(V);
- + Pair.second.OverDefined.erase(V);
- }
-
- - ValueCache.erase(V);
- + auto HandleIt = ValueHandles.find_as(V);
- + if (HandleIt != ValueHandles.end())
- + ValueHandles.erase(HandleIt);
- }
-
- void LVIValueHandle::deleted() {
- @@ -274,18 +240,7 @@ void LVIValueHandle::deleted() {
- }
-
- void LazyValueInfoCache::eraseBlock(BasicBlock *BB) {
- - // Shortcut if we have never seen this block.
- - DenseSet<PoisoningVH<BasicBlock> >::iterator I = SeenBlocks.find(BB);
- - if (I == SeenBlocks.end())
- - return;
- - SeenBlocks.erase(I);
- -
- - auto ODI = OverDefinedCache.find(BB);
- - if (ODI != OverDefinedCache.end())
- - OverDefinedCache.erase(ODI);
- -
- - for (auto &I : ValueCache)
- - I.second->BlockVals.erase(BB);
- + BlockCache.erase(BB);
- }
-
- void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
- @@ -303,10 +258,11 @@ void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
- std::vector<BasicBlock*> worklist;
- worklist.push_back(OldSucc);
-
- - auto I = OverDefinedCache.find(OldSucc);
- - if (I == OverDefinedCache.end())
- + auto I = BlockCache.find(OldSucc);
- + if (I == BlockCache.end() || I->second.OverDefined.empty())
- return; // Nothing to process here.
- - SmallVector<Value *, 4> ValsToClear(I->second.begin(), I->second.end());
- + SmallVector<Value *, 4> ValsToClear(I->second.OverDefined.begin(),
- + I->second.OverDefined.end());
-
- // Use a worklist to perform a depth-first search of OldSucc's successors.
- // NOTE: We do not need a visited list since any blocks we have already
- @@ -320,10 +276,10 @@ void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
- if (ToUpdate == NewSucc) continue;
-
- // If a value was marked overdefined in OldSucc, and is here too...
- - auto OI = OverDefinedCache.find(ToUpdate);
- - if (OI == OverDefinedCache.end())
- + auto OI = BlockCache.find(ToUpdate);
- + if (OI == BlockCache.end() || OI->second.OverDefined.empty())
- continue;
- - SmallPtrSetImpl<Value *> &ValueSet = OI->second;
- + auto &ValueSet = OI->second.OverDefined;
-
- bool changed = false;
- for (Value *V : ValsToClear) {
- @@ -333,11 +289,6 @@ void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
- // If we removed anything, then we potentially need to update
- // blocks successors too.
- changed = true;
- -
- - if (ValueSet.empty()) {
- - OverDefinedCache.erase(OI);
- - break;
- - }
- }
-
- if (!changed) continue;
- --
- 2.24.0
|