diff options
author | Florian Hahn <flo@fhahn.com> | 2025-07-14 09:17:33 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2025-07-14 08:17:33 +0100 |
commit | cad62df49a79df5e5136cfad280c5abc9f62c60b (patch) | |
tree | 8a91ae0d8643eea20e3f6c2a9db6273414766d89 /llvm/lib/Analysis/Loads.cpp | |
parent | 040e7ad8281dcb52507070fbeec59421af78c5ca (diff) | |
download | llvm-cad62df49a79df5e5136cfad280c5abc9f62c60b.zip llvm-cad62df49a79df5e5136cfad280c5abc9f62c60b.tar.gz llvm-cad62df49a79df5e5136cfad280c5abc9f62c60b.tar.bz2 |
[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: https://github.com/llvm/llvm-project/pull/128436
Diffstat (limited to 'llvm/lib/Analysis/Loads.cpp')
-rw-r--r-- | llvm/lib/Analysis/Loads.cpp | 88 |
1 files changed, 53 insertions, 35 deletions
diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp index 8802495..89e42ff 100644 --- a/llvm/lib/Analysis/Loads.cpp +++ b/llvm/lib/Analysis/Loads.cpp @@ -31,6 +31,40 @@ static bool isAligned(const Value *Base, Align Alignment, return Base->getPointerAlignment(DL) >= Alignment; } +static bool isDereferenceableAndAlignedPointerViaAssumption( + const Value *Ptr, Align Alignment, + function_ref<bool(const RetainedKnowledge &RK)> CheckSize, + const DataLayout &DL, const Instruction *CtxI, AssumptionCache *AC, + const DominatorTree *DT) { + // Dereferenceable information from assumptions is only valid if the value + // cannot be freed between the assumption and use. For now just use the + // information for values that cannot be freed in the function. + // TODO: More precisely check if the pointer can be freed between assumption + // and use. + if (!CtxI || Ptr->canBeFreed()) + return false; + /// Look through assumes to see if both dereferencability and alignment can + /// be proven by an assume if needed. + RetainedKnowledge AlignRK; + RetainedKnowledge DerefRK; + bool IsAligned = Ptr->getPointerAlignment(DL) >= Alignment; + return getKnowledgeForValue( + Ptr, {Attribute::Dereferenceable, Attribute::Alignment}, *AC, + [&](RetainedKnowledge RK, Instruction *Assume, auto) { + if (!isValidAssumeForContext(Assume, CtxI, DT)) + return false; + if (RK.AttrKind == Attribute::Alignment) + AlignRK = std::max(AlignRK, RK); + if (RK.AttrKind == Attribute::Dereferenceable) + DerefRK = std::max(DerefRK, RK); + IsAligned |= AlignRK && AlignRK.ArgValue >= Alignment.value(); + if (IsAligned && DerefRK && CheckSize(DerefRK)) + return true; // We have found what we needed so we stop looking + return false; // Other assumes may have better information. so + // keep looking + }); +} + /// Test if V is always a pointer to allocated and suitably aligned memory for /// a simple load or store. static bool isDereferenceableAndAlignedPointer( @@ -169,38 +203,12 @@ static bool isDereferenceableAndAlignedPointer( Size, DL, CtxI, AC, DT, TLI, Visited, MaxDepth); - // Dereferenceable information from assumptions is only valid if the value - // cannot be freed between the assumption and use. For now just use the - // information for values that cannot be freed in the function. - // TODO: More precisely check if the pointer can be freed between assumption - // and use. - if (CtxI && AC && !V->canBeFreed()) { - /// Look through assumes to see if both dereferencability and alignment can - /// be proven by an assume if needed. - RetainedKnowledge AlignRK; - RetainedKnowledge DerefRK; - bool IsAligned = V->getPointerAlignment(DL) >= Alignment; - if (getKnowledgeForValue( - V, {Attribute::Dereferenceable, Attribute::Alignment}, *AC, - [&](RetainedKnowledge RK, Instruction *Assume, auto) { - if (!isValidAssumeForContext(Assume, CtxI, DT)) - return false; - if (RK.AttrKind == Attribute::Alignment) - AlignRK = std::max(AlignRK, RK); - if (RK.AttrKind == Attribute::Dereferenceable) - DerefRK = std::max(DerefRK, RK); - IsAligned |= AlignRK && AlignRK.ArgValue >= Alignment.value(); - if (IsAligned && DerefRK && - DerefRK.ArgValue >= Size.getZExtValue()) - return true; // We have found what we needed so we stop looking - return false; // Other assumes may have better information. so - // keep looking - })) - return true; - } - - // If we don't know, assume the worst. - return false; + return AC && isDereferenceableAndAlignedPointerViaAssumption( + V, Alignment, + [Size](const RetainedKnowledge &RK) { + return RK.ArgValue >= Size.getZExtValue(); + }, + DL, CtxI, AC, DT); } bool llvm::isDereferenceableAndAlignedPointer( @@ -317,8 +325,8 @@ bool llvm::isDereferenceableAndAlignedInLoop( return false; const SCEV *MaxBECount = - Predicates ? SE.getPredicatedConstantMaxBackedgeTakenCount(L, *Predicates) - : SE.getConstantMaxBackedgeTakenCount(L); + Predicates ? SE.getPredicatedSymbolicMaxBackedgeTakenCount(L, *Predicates) + : SE.getSymbolicMaxBackedgeTakenCount(L); const SCEV *BECount = Predicates ? SE.getPredicatedBackedgeTakenCount(L, *Predicates) : SE.getBackedgeTakenCount(L); @@ -339,9 +347,11 @@ bool llvm::isDereferenceableAndAlignedInLoop( Value *Base = nullptr; APInt AccessSize; + const SCEV *AccessSizeSCEV = nullptr; if (const SCEVUnknown *NewBase = dyn_cast<SCEVUnknown>(AccessStart)) { Base = NewBase->getValue(); AccessSize = MaxPtrDiff; + AccessSizeSCEV = PtrDiff; } else if (auto *MinAdd = dyn_cast<SCEVAddExpr>(AccessStart)) { if (MinAdd->getNumOperands() != 2) return false; @@ -365,12 +375,20 @@ bool llvm::isDereferenceableAndAlignedInLoop( return false; AccessSize = MaxPtrDiff + Offset->getAPInt(); + AccessSizeSCEV = SE.getAddExpr(PtrDiff, Offset); Base = NewBase->getValue(); } else return false; Instruction *HeaderFirstNonPHI = &*L->getHeader()->getFirstNonPHIIt(); - return isDereferenceableAndAlignedPointer(Base, Alignment, AccessSize, DL, + return isDereferenceableAndAlignedPointerViaAssumption( + Base, Alignment, + [&SE, AccessSizeSCEV](const RetainedKnowledge &RK) { + return SE.isKnownPredicate(CmpInst::ICMP_ULE, AccessSizeSCEV, + SE.getSCEV(RK.IRArgValue)); + }, + DL, HeaderFirstNonPHI, AC, &DT) || + isDereferenceableAndAlignedPointer(Base, Alignment, AccessSize, DL, HeaderFirstNonPHI, AC, &DT); } |