Skip to content

Commit 9db7948

Browse files
committed
[LVI] Complete the abstract of the cache layer [NFCI]
Convert the previous introduced is-a relationship between the LVICache and LVIImple clases into a has-a relationship and hide all the implementation details of the cache from the lazy query layer. The only slightly concerning change here is removing the addition of a queried block into the SeenBlock set in LVIImpl::getBlockValue. As far as I can tell, this was effectively dead code. I think it *used* to be the case that getCachedValueInfo wasn't const and might end up inserting elements in the cache during lookup. That's no longer true and hasn't been for a while. I did fixup the const usage to make that more obvious. llvm-svn: 281272
1 parent 5a805df commit 9db7948

File tree

1 file changed

+94
-72
lines changed

1 file changed

+94
-72
lines changed

llvm/lib/Analysis/LazyValueInfo.cpp

Lines changed: 94 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -386,7 +386,6 @@ namespace {
386386
/// This is the cache kept by LazyValueInfo which
387387
/// maintains information about queries across the clients' queries.
388388
class LazyValueInfoCache {
389-
protected:
390389
/// This is all of the cached block information for exactly one Value*.
391390
/// The entries are sorted by the BasicBlock* of the
392391
/// entries, allowing us to do a lookup with a binary search.
@@ -412,6 +411,7 @@ namespace {
412411
/// don't spend time removing unused blocks from our caches.
413412
DenseSet<AssertingVH<BasicBlock> > SeenBlocks;
414413

414+
public:
415415
void insertResult(Value *Val, BasicBlock *BB, const LVILatticeVal &Result) {
416416
SeenBlocks.insert(BB);
417417

@@ -439,7 +439,7 @@ namespace {
439439
return ODI->second.count(V);
440440
}
441441

442-
bool hasCachedValueInfo(Value *V, BasicBlock *BB) {
442+
bool hasCachedValueInfo(Value *V, BasicBlock *BB) const {
443443
if (isOverdefined(V, BB))
444444
return true;
445445

@@ -450,7 +450,7 @@ namespace {
450450
return I->second->BlockVals.count(BB);
451451
}
452452

453-
LVILatticeVal getCachedValueInfo(Value *V, BasicBlock *BB) {
453+
LVILatticeVal getCachedValueInfo(Value *V, BasicBlock *BB) const {
454454
if (isOverdefined(V, BB))
455455
return LVILatticeVal::getOverdefined();
456456

@@ -463,7 +463,6 @@ namespace {
463463
return BBI->second;
464464
}
465465

466-
public:
467466
/// clear - Empty the cache.
468467
void clear() {
469468
SeenBlocks.clear();
@@ -478,6 +477,11 @@ namespace {
478477
/// that a block has been deleted.
479478
void eraseBlock(BasicBlock *BB);
480479

480+
/// Updates the cache to remove any influence an overdefined value in
481+
/// OldSucc might have (unless also overdefined in NewSucc). This just
482+
/// flushes elements from the cache and does not add any.
483+
void threadEdgeImpl(BasicBlock *OldSucc,BasicBlock *NewSucc);
484+
481485
friend struct LVIValueHandle;
482486
};
483487
}
@@ -518,11 +522,70 @@ void LazyValueInfoCache::eraseBlock(BasicBlock *BB) {
518522
I.second->BlockVals.erase(BB);
519523
}
520524

525+
void LazyValueInfoCache::threadEdgeImpl(BasicBlock *OldSucc,
526+
BasicBlock *NewSucc) {
527+
// When an edge in the graph has been threaded, values that we could not
528+
// determine a value for before (i.e. were marked overdefined) may be
529+
// possible to solve now. We do NOT try to proactively update these values.
530+
// Instead, we clear their entries from the cache, and allow lazy updating to
531+
// recompute them when needed.
532+
533+
// The updating process is fairly simple: we need to drop cached info
534+
// for all values that were marked overdefined in OldSucc, and for those same
535+
// values in any successor of OldSucc (except NewSucc) in which they were
536+
// also marked overdefined.
537+
std::vector<BasicBlock*> worklist;
538+
worklist.push_back(OldSucc);
539+
540+
auto I = OverDefinedCache.find(OldSucc);
541+
if (I == OverDefinedCache.end())
542+
return; // Nothing to process here.
543+
SmallVector<Value *, 4> ValsToClear(I->second.begin(), I->second.end());
544+
545+
// Use a worklist to perform a depth-first search of OldSucc's successors.
546+
// NOTE: We do not need a visited list since any blocks we have already
547+
// visited will have had their overdefined markers cleared already, and we
548+
// thus won't loop to their successors.
549+
while (!worklist.empty()) {
550+
BasicBlock *ToUpdate = worklist.back();
551+
worklist.pop_back();
552+
553+
// Skip blocks only accessible through NewSucc.
554+
if (ToUpdate == NewSucc) continue;
555+
556+
bool changed = false;
557+
for (Value *V : ValsToClear) {
558+
// If a value was marked overdefined in OldSucc, and is here too...
559+
auto OI = OverDefinedCache.find(ToUpdate);
560+
if (OI == OverDefinedCache.end())
561+
continue;
562+
SmallPtrSetImpl<Value *> &ValueSet = OI->second;
563+
if (!ValueSet.count(V))
564+
continue;
565+
566+
ValueSet.erase(V);
567+
if (ValueSet.empty())
568+
OverDefinedCache.erase(OI);
569+
570+
// If we removed anything, then we potentially need to update
571+
// blocks successors too.
572+
changed = true;
573+
}
574+
575+
if (!changed) continue;
576+
577+
worklist.insert(worklist.end(), succ_begin(ToUpdate), succ_end(ToUpdate));
578+
}
579+
}
580+
521581
namespace {
522582
// The actual implementation of the lazy analysis and update. Note that the
523583
// inheritance from LazyValueInfoCache is intended to be temporary while
524584
// splitting the code and then transitioning to a has-a relationship.
525-
class LazyValueInfoImpl : public LazyValueInfoCache {
585+
class LazyValueInfoImpl {
586+
587+
/// Cached results from previous queries
588+
LazyValueInfoCache TheCache;
526589

527590
/// This stack holds the state of the value solver during a query.
528591
/// It basically emulates the callstack of the naive
@@ -587,6 +650,17 @@ namespace {
587650
LVILatticeVal getValueOnEdge(Value *V, BasicBlock *FromBB,BasicBlock *ToBB,
588651
Instruction *CxtI = nullptr);
589652

653+
/// Complete flush all previously computed values
654+
void clear() {
655+
TheCache.clear();
656+
}
657+
658+
/// This is part of the update interface to inform the cache
659+
/// that a block has been deleted.
660+
void eraseBlock(BasicBlock *BB) {
661+
TheCache.eraseBlock(BB);
662+
}
663+
590664
/// This is the update interface to inform the cache that an edge from
591665
/// PredBB to OldSucc has been threaded to be from PredBB to NewSucc.
592666
void threadEdge(BasicBlock *PredBB,BasicBlock *OldSucc,BasicBlock *NewSucc);
@@ -605,11 +679,11 @@ void LazyValueInfoImpl::solve() {
605679
if (solveBlockValue(e.second, e.first)) {
606680
// The work item was completely processed.
607681
assert(BlockValueStack.top() == e && "Nothing should have been pushed!");
608-
assert(hasCachedValueInfo(e.second, e.first) &&
682+
assert(TheCache.hasCachedValueInfo(e.second, e.first) &&
609683
"Result should be in cache!");
610684

611685
DEBUG(dbgs() << "POP " << *e.second << " in " << e.first->getName()
612-
<< " = " << getCachedValueInfo(e.second, e.first) << "\n");
686+
<< " = " << TheCache.getCachedValueInfo(e.second, e.first) << "\n");
613687

614688
BlockValueStack.pop();
615689
BlockValueSet.erase(e);
@@ -625,16 +699,15 @@ bool LazyValueInfoImpl::hasBlockValue(Value *Val, BasicBlock *BB) {
625699
if (isa<Constant>(Val))
626700
return true;
627701

628-
return hasCachedValueInfo(Val, BB);
702+
return TheCache.hasCachedValueInfo(Val, BB);
629703
}
630704

631705
LVILatticeVal LazyValueInfoImpl::getBlockValue(Value *Val, BasicBlock *BB) {
632706
// If already a constant, there is nothing to compute.
633707
if (Constant *VC = dyn_cast<Constant>(Val))
634708
return LVILatticeVal::get(VC);
635709

636-
SeenBlocks.insert(BB);
637-
return getCachedValueInfo(Val, BB);
710+
return TheCache.getCachedValueInfo(Val, BB);
638711
}
639712

640713
static LVILatticeVal getFromRangeMetadata(Instruction *BBI) {
@@ -657,10 +730,10 @@ bool LazyValueInfoImpl::solveBlockValue(Value *Val, BasicBlock *BB) {
657730
if (isa<Constant>(Val))
658731
return true;
659732

660-
if (hasCachedValueInfo(Val, BB)) {
733+
if (TheCache.hasCachedValueInfo(Val, BB)) {
661734
// If we have a cached value, use that.
662735
DEBUG(dbgs() << " reuse BB '" << BB->getName()
663-
<< "' val=" << getCachedValueInfo(Val, BB) << '\n');
736+
<< "' val=" << TheCache.getCachedValueInfo(Val, BB) << '\n');
664737

665738
// Since we're reusing a cached value, we don't need to update the
666739
// OverDefinedCache. The cache will have been properly updated whenever the
@@ -676,21 +749,21 @@ bool LazyValueInfoImpl::solveBlockValue(Value *Val, BasicBlock *BB) {
676749
if (!BBI || BBI->getParent() != BB) {
677750
if (!solveBlockValueNonLocal(Res, Val, BB))
678751
return false;
679-
insertResult(Val, BB, Res);
752+
TheCache.insertResult(Val, BB, Res);
680753
return true;
681754
}
682755

683756
if (PHINode *PN = dyn_cast<PHINode>(BBI)) {
684757
if (!solveBlockValuePHINode(Res, PN, BB))
685758
return false;
686-
insertResult(Val, BB, Res);
759+
TheCache.insertResult(Val, BB, Res);
687760
return true;
688761
}
689762

690763
if (auto *SI = dyn_cast<SelectInst>(BBI)) {
691764
if (!solveBlockValueSelect(Res, SI, BB))
692765
return false;
693-
insertResult(Val, BB, Res);
766+
TheCache.insertResult(Val, BB, Res);
694767
return true;
695768
}
696769

@@ -706,29 +779,29 @@ bool LazyValueInfoImpl::solveBlockValue(Value *Val, BasicBlock *BB) {
706779
PointerType *PT = dyn_cast<PointerType>(BBI->getType());
707780
if (PT && isKnownNonNull(BBI)) {
708781
Res = LVILatticeVal::getNot(ConstantPointerNull::get(PT));
709-
insertResult(Val, BB, Res);
782+
TheCache.insertResult(Val, BB, Res);
710783
return true;
711784
}
712785
if (BBI->getType()->isIntegerTy()) {
713786
if (isa<CastInst>(BBI)) {
714787
if (!solveBlockValueCast(Res, BBI, BB))
715788
return false;
716-
insertResult(Val, BB, Res);
789+
TheCache.insertResult(Val, BB, Res);
717790
return true;
718791
}
719792
BinaryOperator *BO = dyn_cast<BinaryOperator>(BBI);
720793
if (BO && isa<ConstantInt>(BO->getOperand(1))) {
721794
if (!solveBlockValueBinaryOp(Res, BBI, BB))
722795
return false;
723-
insertResult(Val, BB, Res);
796+
TheCache.insertResult(Val, BB, Res);
724797
return true;
725798
}
726799
}
727800

728801
DEBUG(dbgs() << " compute BB '" << BB->getName()
729802
<< "' - unknown inst def found.\n");
730803
Res = getFromRangeMetadata(BBI);
731-
insertResult(Val, BB, Res);
804+
TheCache.insertResult(Val, BB, Res);
732805
return true;
733806
}
734807

@@ -1465,59 +1538,8 @@ getValueOnEdge(Value *V, BasicBlock *FromBB, BasicBlock *ToBB,
14651538
}
14661539

14671540
void LazyValueInfoImpl::threadEdge(BasicBlock *PredBB, BasicBlock *OldSucc,
1468-
BasicBlock *NewSucc) {
1469-
// When an edge in the graph has been threaded, values that we could not
1470-
// determine a value for before (i.e. were marked overdefined) may be
1471-
// possible to solve now. We do NOT try to proactively update these values.
1472-
// Instead, we clear their entries from the cache, and allow lazy updating to
1473-
// recompute them when needed.
1474-
1475-
// The updating process is fairly simple: we need to drop cached info
1476-
// for all values that were marked overdefined in OldSucc, and for those same
1477-
// values in any successor of OldSucc (except NewSucc) in which they were
1478-
// also marked overdefined.
1479-
std::vector<BasicBlock*> worklist;
1480-
worklist.push_back(OldSucc);
1481-
1482-
auto I = OverDefinedCache.find(OldSucc);
1483-
if (I == OverDefinedCache.end())
1484-
return; // Nothing to process here.
1485-
SmallVector<Value *, 4> ValsToClear(I->second.begin(), I->second.end());
1486-
1487-
// Use a worklist to perform a depth-first search of OldSucc's successors.
1488-
// NOTE: We do not need a visited list since any blocks we have already
1489-
// visited will have had their overdefined markers cleared already, and we
1490-
// thus won't loop to their successors.
1491-
while (!worklist.empty()) {
1492-
BasicBlock *ToUpdate = worklist.back();
1493-
worklist.pop_back();
1494-
1495-
// Skip blocks only accessible through NewSucc.
1496-
if (ToUpdate == NewSucc) continue;
1497-
1498-
bool changed = false;
1499-
for (Value *V : ValsToClear) {
1500-
// If a value was marked overdefined in OldSucc, and is here too...
1501-
auto OI = OverDefinedCache.find(ToUpdate);
1502-
if (OI == OverDefinedCache.end())
1503-
continue;
1504-
SmallPtrSetImpl<Value *> &ValueSet = OI->second;
1505-
if (!ValueSet.count(V))
1506-
continue;
1507-
1508-
ValueSet.erase(V);
1509-
if (ValueSet.empty())
1510-
OverDefinedCache.erase(OI);
1511-
1512-
// If we removed anything, then we potentially need to update
1513-
// blocks successors too.
1514-
changed = true;
1515-
}
1516-
1517-
if (!changed) continue;
1518-
1519-
worklist.insert(worklist.end(), succ_begin(ToUpdate), succ_end(ToUpdate));
1520-
}
1541+
BasicBlock *NewSucc) {
1542+
TheCache.threadEdgeImpl(OldSucc, NewSucc);
15211543
}
15221544

15231545
//===----------------------------------------------------------------------===//

0 commit comments

Comments
 (0)