Skip to content

Commit 15bc4dc

Browse files
committed
[LVI] Normalize pointer behavior
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 1471a7d commit 15bc4dc

File tree

2 files changed

+96
-90
lines changed

2 files changed

+96
-90
lines changed

llvm/lib/Analysis/LazyValueInfo.cpp

Lines changed: 94 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

@@ -279,9 +296,8 @@ void LazyValueInfoCache::eraseBlock(BasicBlock *BB) {
279296
return;
280297
SeenBlocks.erase(I);
281298

282-
auto ODI = OverDefinedCache.find(BB);
283-
if (ODI != OverDefinedCache.end())
284-
OverDefinedCache.erase(ODI);
299+
OverDefinedCache.erase(BB);
300+
DereferencedPointerCache.erase(BB);
285301

286302
for (auto &I : ValueCache)
287303
I.second->BlockVals.erase(BB);
@@ -438,6 +454,7 @@ namespace {
438454
BasicBlock *BB);
439455
bool solveBlockValueExtractValue(ValueLatticeElement &BBLV,
440456
ExtractValueInst *EVI, BasicBlock *BB);
457+
bool isNonNullDueToDereferenceInBlock(Value *Val, BasicBlock *BB);
441458
void intersectAssumeOrGuardBlockValueConstantRange(Value *Val,
442459
ValueLatticeElement &BBLV,
443460
Instruction *BBI);
@@ -619,17 +636,6 @@ bool LazyValueInfoImpl::solveBlockValue(Value *Val, BasicBlock *BB) {
619636

620637
bool LazyValueInfoImpl::solveBlockValueImpl(ValueLatticeElement &Res,
621638
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-
633639
// If this value is a nonnull pointer, record it's range and bailout. Note
634640
// that for all other pointer typed values, we terminate the search at the
635641
// definition. We could easily extend this to look through geps, bitcasts,
@@ -639,11 +645,22 @@ bool LazyValueInfoImpl::solveBlockValueImpl(ValueLatticeElement &Res,
639645
// This does mean that we have a sensitivity to where the defining
640646
// instruction is placed, even if it could legally be hoisted much higher.
641647
// That is unfortunate.
642-
PointerType *PT = dyn_cast<PointerType>(BBI->getType());
643-
if (PT && isKnownNonZero(BBI, DL)) {
648+
PointerType *PT = dyn_cast<PointerType>(Val->getType());
649+
if (PT && isKnownNonZero(Val, DL)) {
644650
Res = ValueLatticeElement::getNot(ConstantPointerNull::get(PT));
645651
return true;
646652
}
653+
654+
Instruction *BBI = dyn_cast<Instruction>(Val);
655+
if (!BBI || BBI->getParent() != BB)
656+
return solveBlockValueNonLocal(Res, Val, BB);
657+
658+
if (PHINode *PN = dyn_cast<PHINode>(BBI))
659+
return solveBlockValuePHINode(Res, PN, BB);
660+
661+
if (auto *SI = dyn_cast<SelectInst>(BBI))
662+
return solveBlockValueSelect(Res, SI, BB);
663+
647664
if (BBI->getType()->isIntegerTy()) {
648665
if (auto *CI = dyn_cast<CastInst>(BBI))
649666
return solveBlockValueCast(Res, CI, BB);
@@ -664,75 +681,63 @@ bool LazyValueInfoImpl::solveBlockValueImpl(ValueLatticeElement &Res,
664681
return true;
665682
}
666683

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;
684+
static void AddDereferencedPointer(
685+
Value *Ptr, SmallPtrSet<Value *, 4> &PtrSet, const DataLayout &DL) {
686+
// TODO: Use NullPointerIsDefined instead.
687+
if (Ptr->getType()->getPointerAddressSpace() == 0) {
688+
Ptr = GetUnderlyingObject(Ptr, DL);
689+
PtrSet.insert(Ptr);
672690
}
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;
691+
}
692+
693+
static void AddPointersDereferencedByInstruction(
694+
Instruction *I, SmallPtrSet<Value *, 4> &PtrSet, const DataLayout &DL) {
695+
if (LoadInst *L = dyn_cast<LoadInst>(I)) {
696+
AddDereferencedPointer(L->getPointerOperand(), PtrSet, DL);
697+
} else if (StoreInst *S = dyn_cast<StoreInst>(I)) {
698+
AddDereferencedPointer(S->getPointerOperand(), PtrSet, DL);
699+
} else if (MemIntrinsic *MI = dyn_cast<MemIntrinsic>(I)) {
700+
if (MI->isVolatile()) return;
680701

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

685-
if (MI->getDestAddressSpace() == 0)
686-
if (GetUnderlyingObject(MI->getRawDest(),
687-
MI->getModule()->getDataLayout()) == Ptr)
688-
return true;
706+
AddDereferencedPointer(MI->getRawDest(), PtrSet, DL);
689707
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;
708+
AddDereferencedPointer(MTI->getRawSource(), PtrSet, DL);
694709
}
695-
return false;
696710
}
697711

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());
712+
bool LazyValueInfoImpl::isNonNullDueToDereferenceInBlock(
713+
Value *Val, BasicBlock *BB) {
714+
if (NullPointerIsDefined(BB->getParent(),
715+
Val->getType()->getPointerAddressSpace()))
716+
return false;
704717

705718
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))
719+
Val = GetUnderlyingObject(Val, DL);
720+
721+
LazyValueInfoCache::PerBlockValueCacheTy::iterator It;
722+
bool NeedsInit;
723+
std::tie(It, NeedsInit) = TheCache.getOrInitDereferencedPointers(BB);
724+
725+
if (NeedsInit)
710726
for (Instruction &I : *BB)
711-
if (InstructionDereferencesPointer(&I, UnderlyingVal))
712-
return true;
713-
return false;
727+
AddPointersDereferencedByInstruction(&I, It->second, DL);
728+
729+
return It->second.count(Val);
714730
}
715731

716732
bool LazyValueInfoImpl::solveBlockValueNonLocal(ValueLatticeElement &BBLV,
717-
Value *Val, BasicBlock *BB) {
733+
Value *Val, BasicBlock *BB) {
718734
ValueLatticeElement Result; // Start Undefined.
719735

720736
// If this is the entry block, we must be asking about an argument. The
721737
// value is overdefined.
722738
if (BB == &BB->getParent()->getEntryBlock()) {
723739
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;
740+
BBLV = ValueLatticeElement::getOverdefined();
736741
return true;
737742
}
738743

@@ -758,14 +763,6 @@ bool LazyValueInfoImpl::solveBlockValueNonLocal(ValueLatticeElement &BBLV,
758763
if (Result.isOverdefined()) {
759764
LLVM_DEBUG(dbgs() << " compute BB '" << BB->getName()
760765
<< "' - 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-
769766
BBLV = Result;
770767
return true;
771768
}
@@ -838,16 +835,24 @@ void LazyValueInfoImpl::intersectAssumeOrGuardBlockValueConstantRange(
838835
// If guards are not used in the module, don't spend time looking for them
839836
auto *GuardDecl = BBI->getModule()->getFunction(
840837
Intrinsic::getName(Intrinsic::experimental_guard));
841-
if (!GuardDecl || GuardDecl->use_empty())
842-
return;
838+
if (GuardDecl && !GuardDecl->use_empty()) {
839+
if (BBI->getIterator() == BBI->getParent()->begin())
840+
return;
841+
for (Instruction &I : make_range(std::next(BBI->getIterator().getReverse()),
842+
BBI->getParent()->rend())) {
843+
Value *Cond = nullptr;
844+
if (match(&I, m_Intrinsic<Intrinsic::experimental_guard>(m_Value(Cond))))
845+
BBLV = intersect(BBLV, getValueFromCondition(Val, Cond));
846+
}
847+
}
843848

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));
849+
if (BBLV.isOverdefined()) {
850+
// Check whether we're checking at the terminator, and the pointer has
851+
// been dereferenced in this block.
852+
PointerType *PTy = dyn_cast<PointerType>(Val->getType());
853+
if (PTy && BBI->getParent()->getTerminator() == BBI &&
854+
isNonNullDueToDereferenceInBlock(Val, BBI->getParent()))
855+
BBLV = ValueLatticeElement::getNot(ConstantPointerNull::get(PTy));
851856
}
852857
}
853858

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)