Skip to content

Commit 885a05f

Browse files
committed
Reapply [LVI] Normalize pointer behavior
Fix cache invalidation by not guarding the dereferenced pointer cache erasure by SeenBlocks. SeenBlocks is only populated when actually caching a value in the block, which doesn't necessarily have to happen just because dereferenced pointers were calculated. ----- Related to D69686. As noted there, LVI currently behaves differently for integer and pointer values: For integers, the block value is always valid inside the basic block, while for pointers it is only valid at the end of the basic block. I believe the integer behavior is the correct one, and CVP relies on it via its getConstantRange() uses. The reason for the special pointer behavior is that LVI checks whether a pointer is dereferenced in a given basic block and marks it as non-null in that case. Of course, this information is valid only after the dereferencing instruction, or in conservative approximation, at the end of the block. This patch changes the treatment of dereferencability: Instead of including it inside the block value, we instead treat it as something similar to an assume (it essentially is a non-nullness assume) and incorporate this information in intersectAssumeOrGuardBlockValueConstantRange() if the context instruction is the terminator of the basic block. This happens either when determining an edge-value internally in LVI, or when a terminator was explicitly passed to getValueAt(). The latter case makes this change not fully NFC, because we can now fold terminator icmps based on the dereferencability information in the same block. This is the reason why I changed one JumpThreading test (it would optimize the condition away without the change). Of course, we do not want to recompute dereferencability on each intersectAssume call, so we need a new cache for this. The dereferencability analysis requires walking the entire basic block and computing underlying objects of all memory operands. This was previously done separately for each queried pointer value. In the new implementation (both because this makes the caching simpler, and because it is faster), I instead only walk the full BB once and cache all the dereferenced pointers. So the traversal is now performed only once per BB, instead of once per queried pointer value. I think the overall model now makes more sense than before, and there will be no more pitfalls due to differing integer/pointer behavior. Differential Revision: https://reviews.llvm.org/D69914
1 parent 590f279 commit 885a05f

File tree

2 files changed

+99
-90
lines changed

2 files changed

+99
-90
lines changed

llvm/lib/Analysis/LazyValueInfo.cpp

Lines changed: 97 additions & 89 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,11 @@ namespace {
151151
/// This is the cache kept by LazyValueInfo which
152152
/// maintains information about queries across the clients' queries.
153153
class LazyValueInfoCache {
154+
public:
155+
typedef DenseMap<PoisoningVH<BasicBlock>, SmallPtrSet<Value *, 4>>
156+
PerBlockValueCacheTy;
157+
158+
private:
154159
/// This is all of the cached block information for exactly one Value*.
155160
/// The entries are sorted by the BasicBlock* of the
156161
/// entries, allowing us to do a lookup with a binary search.
@@ -162,18 +167,19 @@ namespace {
162167
SmallDenseMap<PoisoningVH<BasicBlock>, ValueLatticeElement, 4> BlockVals;
163168
};
164169

165-
/// This tracks, on a per-block basis, the set of values that are
166-
/// over-defined at the end of that block.
167-
typedef DenseMap<PoisoningVH<BasicBlock>, SmallPtrSet<Value *, 4>>
168-
OverDefinedCacheTy;
169170
/// Keep track of all blocks that we have ever seen, so we
170171
/// don't spend time removing unused blocks from our caches.
171172
DenseSet<PoisoningVH<BasicBlock> > SeenBlocks;
172173

173174
/// This is all of the cached information for all values,
174175
/// mapped from Value* to key information.
175176
DenseMap<Value *, std::unique_ptr<ValueCacheEntryTy>> ValueCache;
176-
OverDefinedCacheTy OverDefinedCache;
177+
/// This tracks, on a per-block basis, the set of values that are
178+
/// over-defined at the end of that block.
179+
PerBlockValueCacheTy OverDefinedCache;
180+
/// This tracks, on a per-block basis, the set of pointers that are
181+
/// dereferenced in the block (and thus non-null at the end of the block).
182+
PerBlockValueCacheTy DereferencedPointerCache;
177183

178184

179185
public:
@@ -229,11 +235,17 @@ namespace {
229235
return BBI->second;
230236
}
231237

238+
std::pair<PerBlockValueCacheTy::iterator, bool>
239+
getOrInitDereferencedPointers(BasicBlock *BB) {
240+
return DereferencedPointerCache.try_emplace(BB);
241+
}
242+
232243
/// clear - Empty the cache.
233244
void clear() {
234245
SeenBlocks.clear();
235246
ValueCache.clear();
236247
OverDefinedCache.clear();
248+
DereferencedPointerCache.clear();
237249
}
238250

239251
/// Inform the cache that a given value has been deleted.
@@ -252,17 +264,22 @@ namespace {
252264
};
253265
}
254266

255-
void LazyValueInfoCache::eraseValue(Value *V) {
256-
for (auto I = OverDefinedCache.begin(), E = OverDefinedCache.end(); I != E;) {
267+
static void eraseValueFromPerBlockValueCache(
268+
Value *V, LazyValueInfoCache::PerBlockValueCacheTy &Cache) {
269+
for (auto I = Cache.begin(), E = Cache.end(); I != E;) {
257270
// Copy and increment the iterator immediately so we can erase behind
258271
// ourselves.
259272
auto Iter = I++;
260273
SmallPtrSetImpl<Value *> &ValueSet = Iter->second;
261274
ValueSet.erase(V);
262275
if (ValueSet.empty())
263-
OverDefinedCache.erase(Iter);
276+
Cache.erase(Iter);
264277
}
278+
}
265279

280+
void LazyValueInfoCache::eraseValue(Value *V) {
281+
eraseValueFromPerBlockValueCache(V, OverDefinedCache);
282+
eraseValueFromPerBlockValueCache(V, DereferencedPointerCache);
266283
ValueCache.erase(V);
267284
}
268285

@@ -273,15 +290,17 @@ void LVIValueHandle::deleted() {
273290
}
274291

275292
void LazyValueInfoCache::eraseBlock(BasicBlock *BB) {
293+
// The SeenBlocks shortcut applies only to the value caches,
294+
// always clear the dereferenced pointer cache.
295+
DereferencedPointerCache.erase(BB);
296+
276297
// Shortcut if we have never seen this block.
277298
DenseSet<PoisoningVH<BasicBlock> >::iterator I = SeenBlocks.find(BB);
278299
if (I == SeenBlocks.end())
279300
return;
280301
SeenBlocks.erase(I);
281302

282-
auto ODI = OverDefinedCache.find(BB);
283-
if (ODI != OverDefinedCache.end())
284-
OverDefinedCache.erase(ODI);
303+
OverDefinedCache.erase(BB);
285304

286305
for (auto &I : ValueCache)
287306
I.second->BlockVals.erase(BB);
@@ -438,6 +457,7 @@ namespace {
438457
BasicBlock *BB);
439458
bool solveBlockValueExtractValue(ValueLatticeElement &BBLV,
440459
ExtractValueInst *EVI, BasicBlock *BB);
460+
bool isNonNullDueToDereferenceInBlock(Value *Val, BasicBlock *BB);
441461
void intersectAssumeOrGuardBlockValueConstantRange(Value *Val,
442462
ValueLatticeElement &BBLV,
443463
Instruction *BBI);
@@ -619,17 +639,6 @@ bool LazyValueInfoImpl::solveBlockValue(Value *Val, BasicBlock *BB) {
619639

620640
bool LazyValueInfoImpl::solveBlockValueImpl(ValueLatticeElement &Res,
621641
Value *Val, BasicBlock *BB) {
622-
623-
Instruction *BBI = dyn_cast<Instruction>(Val);
624-
if (!BBI || BBI->getParent() != BB)
625-
return solveBlockValueNonLocal(Res, Val, BB);
626-
627-
if (PHINode *PN = dyn_cast<PHINode>(BBI))
628-
return solveBlockValuePHINode(Res, PN, BB);
629-
630-
if (auto *SI = dyn_cast<SelectInst>(BBI))
631-
return solveBlockValueSelect(Res, SI, BB);
632-
633642
// If this value is a nonnull pointer, record it's range and bailout. Note
634643
// that for all other pointer typed values, we terminate the search at the
635644
// definition. We could easily extend this to look through geps, bitcasts,
@@ -639,11 +648,22 @@ bool LazyValueInfoImpl::solveBlockValueImpl(ValueLatticeElement &Res,
639648
// This does mean that we have a sensitivity to where the defining
640649
// instruction is placed, even if it could legally be hoisted much higher.
641650
// That is unfortunate.
642-
PointerType *PT = dyn_cast<PointerType>(BBI->getType());
643-
if (PT && isKnownNonZero(BBI, DL)) {
651+
PointerType *PT = dyn_cast<PointerType>(Val->getType());
652+
if (PT && isKnownNonZero(Val, DL)) {
644653
Res = ValueLatticeElement::getNot(ConstantPointerNull::get(PT));
645654
return true;
646655
}
656+
657+
Instruction *BBI = dyn_cast<Instruction>(Val);
658+
if (!BBI || BBI->getParent() != BB)
659+
return solveBlockValueNonLocal(Res, Val, BB);
660+
661+
if (PHINode *PN = dyn_cast<PHINode>(BBI))
662+
return solveBlockValuePHINode(Res, PN, BB);
663+
664+
if (auto *SI = dyn_cast<SelectInst>(BBI))
665+
return solveBlockValueSelect(Res, SI, BB);
666+
647667
if (BBI->getType()->isIntegerTy()) {
648668
if (auto *CI = dyn_cast<CastInst>(BBI))
649669
return solveBlockValueCast(Res, CI, BB);
@@ -664,75 +684,63 @@ bool LazyValueInfoImpl::solveBlockValueImpl(ValueLatticeElement &Res,
664684
return true;
665685
}
666686

667-
static bool InstructionDereferencesPointer(Instruction *I, Value *Ptr) {
668-
if (LoadInst *L = dyn_cast<LoadInst>(I)) {
669-
return L->getPointerAddressSpace() == 0 &&
670-
GetUnderlyingObject(L->getPointerOperand(),
671-
L->getModule()->getDataLayout()) == Ptr;
687+
static void AddDereferencedPointer(
688+
Value *Ptr, SmallPtrSet<Value *, 4> &PtrSet, const DataLayout &DL) {
689+
// TODO: Use NullPointerIsDefined instead.
690+
if (Ptr->getType()->getPointerAddressSpace() == 0) {
691+
Ptr = GetUnderlyingObject(Ptr, DL);
692+
PtrSet.insert(Ptr);
672693
}
673-
if (StoreInst *S = dyn_cast<StoreInst>(I)) {
674-
return S->getPointerAddressSpace() == 0 &&
675-
GetUnderlyingObject(S->getPointerOperand(),
676-
S->getModule()->getDataLayout()) == Ptr;
677-
}
678-
if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(I)) {
679-
if (MI->isVolatile()) return false;
694+
}
695+
696+
static void AddPointersDereferencedByInstruction(
697+
Instruction *I, SmallPtrSet<Value *, 4> &PtrSet, const DataLayout &DL) {
698+
if (LoadInst *L = dyn_cast<LoadInst>(I)) {
699+
AddDereferencedPointer(L->getPointerOperand(), PtrSet, DL);
700+
} else if (StoreInst *S = dyn_cast<StoreInst>(I)) {
701+
AddDereferencedPointer(S->getPointerOperand(), PtrSet, DL);
702+
} else if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(I)) {
703+
if (MI->isVolatile()) return;
680704

681705
// FIXME: check whether it has a valuerange that excludes zero?
682706
ConstantInt *Len = dyn_cast<ConstantInt>(MI->getLength());
683-
if (!Len || Len->isZero()) return false;
707+
if (!Len || Len->isZero()) return;
684708

685-
if (MI->getDestAddressSpace() == 0)
686-
if (GetUnderlyingObject(MI->getRawDest(),
687-
MI->getModule()->getDataLayout()) == Ptr)
688-
return true;
709+
AddDereferencedPointer(MI->getRawDest(), PtrSet, DL);
689710
if (MemTransferInst *MTI = dyn_cast<MemTransferInst>(MI))
690-
if (MTI->getSourceAddressSpace() == 0)
691-
if (GetUnderlyingObject(MTI->getRawSource(),
692-
MTI->getModule()->getDataLayout()) == Ptr)
693-
return true;
711+
AddDereferencedPointer(MTI->getRawSource(), PtrSet, DL);
694712
}
695-
return false;
696713
}
697714

698-
/// Return true if the allocation associated with Val is ever dereferenced
699-
/// within the given basic block. This establishes the fact Val is not null,
700-
/// but does not imply that the memory at Val is dereferenceable. (Val may
701-
/// point off the end of the dereferenceable part of the object.)
702-
static bool isObjectDereferencedInBlock(Value *Val, BasicBlock *BB) {
703-
assert(Val->getType()->isPointerTy());
715+
bool LazyValueInfoImpl::isNonNullDueToDereferenceInBlock(
716+
Value *Val, BasicBlock *BB) {
717+
if (NullPointerIsDefined(BB->getParent(),
718+
Val->getType()->getPointerAddressSpace()))
719+
return false;
704720

705721
const DataLayout &DL = BB->getModule()->getDataLayout();
706-
Value *UnderlyingVal = GetUnderlyingObject(Val, DL);
707-
// If 'GetUnderlyingObject' didn't converge, skip it. It won't converge
708-
// inside InstructionDereferencesPointer either.
709-
if (UnderlyingVal == GetUnderlyingObject(UnderlyingVal, DL, 1))
722+
Val = GetUnderlyingObject(Val, DL);
723+
724+
LazyValueInfoCache::PerBlockValueCacheTy::iterator It;
725+
bool NeedsInit;
726+
std::tie(It, NeedsInit) = TheCache.getOrInitDereferencedPointers(BB);
727+
728+
if (NeedsInit)
710729
for (Instruction &I : *BB)
711-
if (InstructionDereferencesPointer(&I, UnderlyingVal))
712-
return true;
713-
return false;
730+
AddPointersDereferencedByInstruction(&I, It->second, DL);
731+
732+
return It->second.count(Val);
714733
}
715734

716735
bool LazyValueInfoImpl::solveBlockValueNonLocal(ValueLatticeElement &BBLV,
717-
Value *Val, BasicBlock *BB) {
736+
Value *Val, BasicBlock *BB) {
718737
ValueLatticeElement Result; // Start Undefined.
719738

720739
// If this is the entry block, we must be asking about an argument. The
721740
// value is overdefined.
722741
if (BB == &BB->getParent()->getEntryBlock()) {
723742
assert(isa<Argument>(Val) && "Unknown live-in to the entry block");
724-
// Before giving up, see if we can prove the pointer non-null local to
725-
// this particular block.
726-
PointerType *PTy = dyn_cast<PointerType>(Val->getType());
727-
if (PTy &&
728-
(isKnownNonZero(Val, DL) ||
729-
(isObjectDereferencedInBlock(Val, BB) &&
730-
!NullPointerIsDefined(BB->getParent(), PTy->getAddressSpace())))) {
731-
Result = ValueLatticeElement::getNot(ConstantPointerNull::get(PTy));
732-
} else {
733-
Result = ValueLatticeElement::getOverdefined();
734-
}
735-
BBLV = Result;
743+
BBLV = ValueLatticeElement::getOverdefined();
736744
return true;
737745
}
738746

@@ -758,14 +766,6 @@ bool LazyValueInfoImpl::solveBlockValueNonLocal(ValueLatticeElement &BBLV,
758766
if (Result.isOverdefined()) {
759767
LLVM_DEBUG(dbgs() << " compute BB '" << BB->getName()
760768
<< "' - overdefined because of pred (non local).\n");
761-
// Before giving up, see if we can prove the pointer non-null local to
762-
// this particular block.
763-
PointerType *PTy = dyn_cast<PointerType>(Val->getType());
764-
if (PTy && isObjectDereferencedInBlock(Val, BB) &&
765-
!NullPointerIsDefined(BB->getParent(), PTy->getAddressSpace())) {
766-
Result = ValueLatticeElement::getNot(ConstantPointerNull::get(PTy));
767-
}
768-
769769
BBLV = Result;
770770
return true;
771771
}
@@ -838,16 +838,24 @@ void LazyValueInfoImpl::intersectAssumeOrGuardBlockValueConstantRange(
838838
// If guards are not used in the module, don't spend time looking for them
839839
auto *GuardDecl = BBI->getModule()->getFunction(
840840
Intrinsic::getName(Intrinsic::experimental_guard));
841-
if (!GuardDecl || GuardDecl->use_empty())
842-
return;
841+
if (GuardDecl && !GuardDecl->use_empty()) {
842+
if (BBI->getIterator() == BBI->getParent()->begin())
843+
return;
844+
for (Instruction &I : make_range(std::next(BBI->getIterator().getReverse()),
845+
BBI->getParent()->rend())) {
846+
Value *Cond = nullptr;
847+
if (match(&I, m_Intrinsic<Intrinsic::experimental_guard>(m_Value(Cond))))
848+
BBLV = intersect(BBLV, getValueFromCondition(Val, Cond));
849+
}
850+
}
843851

844-
if (BBI->getIterator() == BBI->getParent()->begin())
845-
return;
846-
for (Instruction &I : make_range(std::next(BBI->getIterator().getReverse()),
847-
BBI->getParent()->rend())) {
848-
Value *Cond = nullptr;
849-
if (match(&I, m_Intrinsic<Intrinsic::experimental_guard>(m_Value(Cond))))
850-
BBLV = intersect(BBLV, getValueFromCondition(Val, Cond));
852+
if (BBLV.isOverdefined()) {
853+
// Check whether we're checking at the terminator, and the pointer has
854+
// been dereferenced in this block.
855+
PointerType *PTy = dyn_cast<PointerType>(Val->getType());
856+
if (PTy && BBI->getParent()->getTerminator() == BBI &&
857+
isNonNullDueToDereferenceInBlock(Val, BBI->getParent()))
858+
BBLV = ValueLatticeElement::getNot(ConstantPointerNull::get(PTy));
851859
}
852860
}
853861

llvm/test/Transforms/JumpThreading/combine-metadata.ll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ d2:
108108
d3:
109109
%y = load i32*, i32** %ptr
110110
store i32 1, i32* %y
111-
%c2 = icmp eq i32* %y, null
111+
%c2 = icmp eq i32* %y, @p
112112
br i1 %c2, label %ret1, label %ret2
113113

114114
ret1:
@@ -118,5 +118,6 @@ ret2:
118118
ret void
119119
}
120120

121+
@p = external global i32
121122

122123
!0 = !{}

0 commit comments

Comments
 (0)