Skip to content

Commit cad62df

Browse files
authored
[Loads] Support dereferenceable assumption with variable size. (#128436)
Update isDereferenceableAndAlignedPointer to make use of dereferenceable assumptions with variable sizes via SCEV. To do so, factor out the logic to check via an assumption to a helper, and use SE to check if the access size is less than the dereferenceable size. PR: #128436
1 parent 040e7ad commit cad62df

File tree

8 files changed

+708
-41
lines changed

8 files changed

+708
-41
lines changed

llvm/include/llvm/Analysis/AssumeBundleQueries.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,10 +102,14 @@ LLVM_ABI void fillMapFromAssume(AssumeInst &Assume,
102102
struct RetainedKnowledge {
103103
Attribute::AttrKind AttrKind = Attribute::None;
104104
uint64_t ArgValue = 0;
105+
Value *IRArgValue = nullptr;
105106
Value *WasOn = nullptr;
107+
RetainedKnowledge(Attribute::AttrKind AttrKind = Attribute::None,
108+
uint64_t ArgValue = 0, Value *WasOn = nullptr)
109+
: AttrKind(AttrKind), ArgValue(ArgValue), WasOn(WasOn) {}
106110
bool operator==(RetainedKnowledge Other) const {
107111
return AttrKind == Other.AttrKind && WasOn == Other.WasOn &&
108-
ArgValue == Other.ArgValue;
112+
ArgValue == Other.ArgValue && IRArgValue == Other.IRArgValue;
109113
}
110114
bool operator!=(RetainedKnowledge Other) const { return !(*this == Other); }
111115
/// This is only intended for use in std::min/std::max between attribute that

llvm/lib/Analysis/AssumeBundleQueries.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,9 @@ llvm::getKnowledgeFromBundle(AssumeInst &Assume,
114114
};
115115
if (BOI.End - BOI.Begin > ABA_Argument)
116116
Result.ArgValue = GetArgOr1(0);
117+
Result.IRArgValue = bundleHasArgument(BOI, ABA_Argument)
118+
? getValueFromBundleOpInfo(Assume, BOI, ABA_Argument)
119+
: nullptr;
117120
if (Result.AttrKind == Attribute::Alignment)
118121
if (BOI.End - BOI.Begin > ABA_Argument + 1)
119122
Result.ArgValue = MinAlign(Result.ArgValue, GetArgOr1(1));

llvm/lib/Analysis/Loads.cpp

Lines changed: 53 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,40 @@ static bool isAligned(const Value *Base, Align Alignment,
3131
return Base->getPointerAlignment(DL) >= Alignment;
3232
}
3333

34+
static bool isDereferenceableAndAlignedPointerViaAssumption(
35+
const Value *Ptr, Align Alignment,
36+
function_ref<bool(const RetainedKnowledge &RK)> CheckSize,
37+
const DataLayout &DL, const Instruction *CtxI, AssumptionCache *AC,
38+
const DominatorTree *DT) {
39+
// Dereferenceable information from assumptions is only valid if the value
40+
// cannot be freed between the assumption and use. For now just use the
41+
// information for values that cannot be freed in the function.
42+
// TODO: More precisely check if the pointer can be freed between assumption
43+
// and use.
44+
if (!CtxI || Ptr->canBeFreed())
45+
return false;
46+
/// Look through assumes to see if both dereferencability and alignment can
47+
/// be proven by an assume if needed.
48+
RetainedKnowledge AlignRK;
49+
RetainedKnowledge DerefRK;
50+
bool IsAligned = Ptr->getPointerAlignment(DL) >= Alignment;
51+
return getKnowledgeForValue(
52+
Ptr, {Attribute::Dereferenceable, Attribute::Alignment}, *AC,
53+
[&](RetainedKnowledge RK, Instruction *Assume, auto) {
54+
if (!isValidAssumeForContext(Assume, CtxI, DT))
55+
return false;
56+
if (RK.AttrKind == Attribute::Alignment)
57+
AlignRK = std::max(AlignRK, RK);
58+
if (RK.AttrKind == Attribute::Dereferenceable)
59+
DerefRK = std::max(DerefRK, RK);
60+
IsAligned |= AlignRK && AlignRK.ArgValue >= Alignment.value();
61+
if (IsAligned && DerefRK && CheckSize(DerefRK))
62+
return true; // We have found what we needed so we stop looking
63+
return false; // Other assumes may have better information. so
64+
// keep looking
65+
});
66+
}
67+
3468
/// Test if V is always a pointer to allocated and suitably aligned memory for
3569
/// a simple load or store.
3670
static bool isDereferenceableAndAlignedPointer(
@@ -169,38 +203,12 @@ static bool isDereferenceableAndAlignedPointer(
169203
Size, DL, CtxI, AC, DT, TLI,
170204
Visited, MaxDepth);
171205

172-
// Dereferenceable information from assumptions is only valid if the value
173-
// cannot be freed between the assumption and use. For now just use the
174-
// information for values that cannot be freed in the function.
175-
// TODO: More precisely check if the pointer can be freed between assumption
176-
// and use.
177-
if (CtxI && AC && !V->canBeFreed()) {
178-
/// Look through assumes to see if both dereferencability and alignment can
179-
/// be proven by an assume if needed.
180-
RetainedKnowledge AlignRK;
181-
RetainedKnowledge DerefRK;
182-
bool IsAligned = V->getPointerAlignment(DL) >= Alignment;
183-
if (getKnowledgeForValue(
184-
V, {Attribute::Dereferenceable, Attribute::Alignment}, *AC,
185-
[&](RetainedKnowledge RK, Instruction *Assume, auto) {
186-
if (!isValidAssumeForContext(Assume, CtxI, DT))
187-
return false;
188-
if (RK.AttrKind == Attribute::Alignment)
189-
AlignRK = std::max(AlignRK, RK);
190-
if (RK.AttrKind == Attribute::Dereferenceable)
191-
DerefRK = std::max(DerefRK, RK);
192-
IsAligned |= AlignRK && AlignRK.ArgValue >= Alignment.value();
193-
if (IsAligned && DerefRK &&
194-
DerefRK.ArgValue >= Size.getZExtValue())
195-
return true; // We have found what we needed so we stop looking
196-
return false; // Other assumes may have better information. so
197-
// keep looking
198-
}))
199-
return true;
200-
}
201-
202-
// If we don't know, assume the worst.
203-
return false;
206+
return AC && isDereferenceableAndAlignedPointerViaAssumption(
207+
V, Alignment,
208+
[Size](const RetainedKnowledge &RK) {
209+
return RK.ArgValue >= Size.getZExtValue();
210+
},
211+
DL, CtxI, AC, DT);
204212
}
205213

206214
bool llvm::isDereferenceableAndAlignedPointer(
@@ -317,8 +325,8 @@ bool llvm::isDereferenceableAndAlignedInLoop(
317325
return false;
318326

319327
const SCEV *MaxBECount =
320-
Predicates ? SE.getPredicatedConstantMaxBackedgeTakenCount(L, *Predicates)
321-
: SE.getConstantMaxBackedgeTakenCount(L);
328+
Predicates ? SE.getPredicatedSymbolicMaxBackedgeTakenCount(L, *Predicates)
329+
: SE.getSymbolicMaxBackedgeTakenCount(L);
322330
const SCEV *BECount = Predicates
323331
? SE.getPredicatedBackedgeTakenCount(L, *Predicates)
324332
: SE.getBackedgeTakenCount(L);
@@ -339,9 +347,11 @@ bool llvm::isDereferenceableAndAlignedInLoop(
339347

340348
Value *Base = nullptr;
341349
APInt AccessSize;
350+
const SCEV *AccessSizeSCEV = nullptr;
342351
if (const SCEVUnknown *NewBase = dyn_cast<SCEVUnknown>(AccessStart)) {
343352
Base = NewBase->getValue();
344353
AccessSize = MaxPtrDiff;
354+
AccessSizeSCEV = PtrDiff;
345355
} else if (auto *MinAdd = dyn_cast<SCEVAddExpr>(AccessStart)) {
346356
if (MinAdd->getNumOperands() != 2)
347357
return false;
@@ -365,12 +375,20 @@ bool llvm::isDereferenceableAndAlignedInLoop(
365375
return false;
366376

367377
AccessSize = MaxPtrDiff + Offset->getAPInt();
378+
AccessSizeSCEV = SE.getAddExpr(PtrDiff, Offset);
368379
Base = NewBase->getValue();
369380
} else
370381
return false;
371382

372383
Instruction *HeaderFirstNonPHI = &*L->getHeader()->getFirstNonPHIIt();
373-
return isDereferenceableAndAlignedPointer(Base, Alignment, AccessSize, DL,
384+
return isDereferenceableAndAlignedPointerViaAssumption(
385+
Base, Alignment,
386+
[&SE, AccessSizeSCEV](const RetainedKnowledge &RK) {
387+
return SE.isKnownPredicate(CmpInst::ICMP_ULE, AccessSizeSCEV,
388+
SE.getSCEV(RK.IRArgValue));
389+
},
390+
DL, HeaderFirstNonPHI, AC, &DT) ||
391+
isDereferenceableAndAlignedPointer(Base, Alignment, AccessSize, DL,
374392
HeaderFirstNonPHI, AC, &DT);
375393
}
376394

llvm/lib/IR/Verifier.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5604,6 +5604,15 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
56045604
"third argument should be an integer if present", Call);
56055605
continue;
56065606
}
5607+
if (Kind == Attribute::Dereferenceable) {
5608+
Check(ArgCount == 2,
5609+
"dereferenceable assumptions should have 2 arguments", Call);
5610+
Check(Call.getOperand(Elem.Begin)->getType()->isPointerTy(),
5611+
"first argument should be a pointer", Call);
5612+
Check(Call.getOperand(Elem.Begin + 1)->getType()->isIntegerTy(),
5613+
"second argument should be an integer", Call);
5614+
continue;
5615+
}
56075616
Check(ArgCount <= 2, "too many arguments", Call);
56085617
if (Kind == Attribute::None)
56095618
break;

0 commit comments

Comments
 (0)