[llvm] [LoopAccessAnalysis] Analyze forked pointer dependences per alternative (PR #214216)
Ramkumar Ramachandra via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 25 05:25:57 PDT 2026
================
@@ -2234,6 +2243,113 @@ MemoryDepChecker::getDependenceDistanceStrideAndSize(
TypeByteSize, AIsWrite, BIsWrite);
}
+std::optional<int64_t>
+MemoryDepChecker::getStrideFromSCEV(
+ const SCEV *S, Type *AccessTy,
+ SmallVectorImpl<const SCEVPredicate *> *Predicates) {
+ ScalarEvolution &SE = *PSE.getSE();
+ if (SE.isLoopInvariant(S, InnermostLoop))
+ return 0;
+ const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(S);
+ if (!AR)
+ return std::nullopt;
+ std::optional<int64_t> Stride =
+ getStrideFromAddRec(AR, InnermostLoop, AccessTy, /*Ptr=*/nullptr, PSE);
+ if (!Stride)
+ return std::nullopt;
+ if (isNoWrap(PSE, AR, /*Ptr=*/nullptr, AccessTy, InnermostLoop, *DT, Stride,
+ Predicates))
+ return Stride;
+ return std::nullopt;
+}
+
+std::optional<MemoryDepChecker::Dependence::DepType>
+MemoryDepChecker::getForkedDepType(const MemAccessInfo &A, Instruction *AInst,
+ const MemAccessInfo &B, Instruction *BInst) {
+ // Two reads are independent.
+ const auto &[APtr, AIsWrite] = A;
+ const auto &[BPtr, BIsWrite] = B;
+ if (!AIsWrite && !BIsWrite)
+ return Dependence::NoDep;
+
+ ScalarEvolution &SE = *PSE.getSE();
+
+ // A pointer may be a fork of multiple strided pointers, e.g. produced by a
+ // select of two pointers. SCEV cannot form a single AddRec for such a
+ // pointer, so the regular analysis in getDependenceDistanceStrideAndSize
+ // would report an IndirectUnsafe dependence. The runtime pointer checking
+ // handles such pointers by analyzing each fork alternative separately
+ // (findForkedSCEVs); do the same here by checking each pair of alternatives
+ // and aggregating the results.
+ SmallVector<PointerIntPair<const SCEV *, 1, bool>> Srcs;
+ SmallVector<PointerIntPair<const SCEV *, 1, bool>> Sinks;
+ findForkedSCEVs(&SE, InnermostLoop, APtr, Srcs, MaxForkedSCEVDepth);
+ findForkedSCEVs(&SE, InnermostLoop, BPtr, Sinks, MaxForkedSCEVDepth);
+
+ // If neither access pointer is a fork, fall back to the regular single-SCEV
+ // analysis in getDependenceDistanceStrideAndSize.
+ if (Srcs.size() == 1 && Sinks.size() == 1)
+ return std::nullopt;
+
+ // We can only analyze a fork if each alternative is loop-invariant or an
+ // affine AddRec; this is the same requirement as for generating runtime
+ // checks for forked pointers (see AccessAnalysis::createCheckForAccess).
+ auto IsLoopInvariantOrAR =
+ [&](const PointerIntPair<const SCEV *, 1, bool> &P) {
+ return SE.isLoopInvariant(P.getPointer(), InnermostLoop) ||
+ isa<SCEVAddRecExpr>(P.getPointer());
+ };
+ if (!all_of(Srcs, IsLoopInvariantOrAR) ||
+ !all_of(Sinks, IsLoopInvariantOrAR))
+ return Dependence::IndirectUnsafe;
----------------
artagnon wrote:
Redundant? I don't think findForkedSCEVs returns non-loop-invariant-or-ARs?
```cpp
if (isa<SCEVAddRecExpr>(Scev) || L->isLoopInvariant(Ptr) ||
!isa<Instruction>(Ptr) || Depth == 0) {
ScevList.emplace_back(Scev, !isGuaranteedNotToBeUndefOrPoison(Ptr));
return;
}
```
https://github.com/llvm/llvm-project/pull/214216
More information about the llvm-commits
mailing list