[llvm] [LAA] Prepare to handle diff type sizes (NFC) (PR #122318)
Ramkumar Ramachandra via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 4 03:23:29 PDT 2025
https://github.com/artagnon updated https://github.com/llvm/llvm-project/pull/122318
>From e415c8bbcf7df25d861c2360666ab0b0b2c806e0 Mon Sep 17 00:00:00 2001
From: Ramkumar Ramachandra <ramkumar.ramachandra at codasip.com>
Date: Mon, 11 Aug 2025 12:27:33 +0100
Subject: [PATCH] [LAA] Prepare to handle diff type sizes (NFC)
As depend_diff_types shows, there are several places where the
HasSameSize check can be relaxed for higher analysis precision. As a
first step, return both the source size and the sink size from
getDependenceDistanceStrideAndSize, along with a HasSameSize boolean for
the moment.
---
.../llvm/Analysis/LoopAccessAnalysis.h | 27 ++++----
llvm/lib/Analysis/LoopAccessAnalysis.cpp | 67 +++++++++++--------
2 files changed, 54 insertions(+), 40 deletions(-)
diff --git a/llvm/include/llvm/Analysis/LoopAccessAnalysis.h b/llvm/include/llvm/Analysis/LoopAccessAnalysis.h
index 52ab38583d5de..49a795b5fd6a7 100644
--- a/llvm/include/llvm/Analysis/LoopAccessAnalysis.h
+++ b/llvm/include/llvm/Analysis/LoopAccessAnalysis.h
@@ -413,29 +413,30 @@ class MemoryDepChecker {
uint64_t MaxStride;
std::optional<uint64_t> CommonStride;
- /// TypeByteSize is either the common store size of both accesses, or 0 when
- /// store sizes mismatch.
- uint64_t TypeByteSize;
+ /// TypeByteSize is a pair of alloc sizes of the source and sink.
+ std::pair<uint64_t, uint64_t> TypeByteSize;
+
+ // HasSameSize is a boolean indicating whether the store sizes of the source
+ // and sink are equal.
+ // TODO: Remove this.
+ bool HasSameSize;
bool AIsWrite;
bool BIsWrite;
DepDistanceStrideAndSizeInfo(const SCEV *Dist, uint64_t MaxStride,
std::optional<uint64_t> CommonStride,
- uint64_t TypeByteSize, bool AIsWrite,
- bool BIsWrite)
+ std::pair<uint64_t, uint64_t> TypeByteSize,
+ bool HasSameSize, bool AIsWrite, bool BIsWrite)
: Dist(Dist), MaxStride(MaxStride), CommonStride(CommonStride),
- TypeByteSize(TypeByteSize), AIsWrite(AIsWrite), BIsWrite(BIsWrite) {}
+ TypeByteSize(TypeByteSize), HasSameSize(HasSameSize),
+ AIsWrite(AIsWrite), BIsWrite(BIsWrite) {}
};
/// Get the dependence distance, strides, type size and whether it is a write
- /// for the dependence between A and B. Returns a DepType, if we can prove
- /// there's no dependence or the analysis fails. Outlined to lambda to limit
- /// he scope of various temporary variables, like A/BPtr, StrideA/BPtr and
- /// others. Returns either the dependence result, if it could already be
- /// determined, or a DepDistanceStrideAndSizeInfo struct, noting that
- /// TypeByteSize could be 0 when store sizes mismatch, and this should be
- /// checked in the caller.
+ /// for the dependence between A and B. Returns either a DepType, the
+ /// dependence result, if it could already be determined, or a
+ /// DepDistanceStrideAndSizeInfo struct.
std::variant<Dependence::DepType, DepDistanceStrideAndSizeInfo>
getDependenceDistanceStrideAndSize(const MemAccessInfo &A, Instruction *AInst,
const MemAccessInfo &B,
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index e18cc6b4007e8..9d1baa9ff1c28 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -1960,17 +1960,21 @@ static bool isSafeDependenceDistance(const DataLayout &DL, ScalarEvolution &SE,
/// Check the dependence for two accesses with the same stride \p Stride.
/// \p Distance is the positive distance in bytes, and \p TypeByteSize is type
-/// size in bytes.
+/// size of source and sink in bytes.
+/// TODO: Relax HasSameSize check in caller.
///
/// \returns true if they are independent.
-static bool areStridedAccessesIndependent(uint64_t Distance, uint64_t Stride,
- uint64_t TypeByteSize) {
+static bool
+areStridedAccessesIndependent(uint64_t Distance, uint64_t Stride,
+ std::pair<uint64_t, uint64_t> TypeByteSize) {
assert(Stride > 1 && "The stride must be greater than 1");
- assert(TypeByteSize > 0 && "The type size in byte must be non-zero");
+ assert(TypeByteSize.first > 0 && TypeByteSize.second > 0 &&
+ "The type size in byte must be non-zero");
assert(Distance > 0 && "The distance must be non-zero");
- // Skip if the distance is not multiple of type byte size.
- if (Distance % TypeByteSize)
+ // Skip if the distance is not multiple of type byte size of either source or
+ // sink.
+ if (Distance % TypeByteSize.first || Distance % TypeByteSize.second)
return false;
// No dependence if the distance is not multiple of the stride.
@@ -2101,14 +2105,12 @@ MemoryDepChecker::getDependenceDistanceStrideAndSize(
return MemoryDepChecker::Dependence::Unknown;
}
- TypeSize AStoreSz = DL.getTypeStoreSize(ATy);
- TypeSize BStoreSz = DL.getTypeStoreSize(BTy);
-
- // If store sizes are not the same, set TypeByteSize to zero, so we can check
- // it in the caller isDependent.
uint64_t ASz = DL.getTypeAllocSize(ATy);
uint64_t BSz = DL.getTypeAllocSize(BTy);
- uint64_t TypeByteSize = (AStoreSz == BStoreSz) ? BSz : 0;
+
+ // Both the source and sink sizes are neeeded in dependence checks, depending
+ // on the use.
+ std::pair<uint64_t, uint64_t> TypeByteSize(ASz, BSz);
uint64_t StrideAScaled = std::abs(StrideAPtrInt) * ASz;
uint64_t StrideBScaled = std::abs(StrideBPtrInt) * BSz;
@@ -2130,8 +2132,23 @@ MemoryDepChecker::getDependenceDistanceStrideAndSize(
return Dependence::Unknown;
}
+ // When the distance is possibly zero, we're reading/writing the same memory
+ // location: if the store sizes are not equal, fail with an unknown
+ // dependence.
+ TypeSize AStoreSz = DL.getTypeStoreSize(ATy);
+ TypeSize BStoreSz = DL.getTypeStoreSize(BTy);
+ if (AStoreSz != BStoreSz && !SE.isKnownNonZero(Dist)) {
+ LLVM_DEBUG(dbgs() << "LAA: possibly zero dependence distance with "
+ "different type sizes\n");
+ return Dependence::Unknown;
+ }
+
+ // TODO: Remove this.
+ bool HasSameSize = AStoreSz == BStoreSz;
+
return DepDistanceStrideAndSizeInfo(Dist, MaxStride, CommonStride,
- TypeByteSize, AIsWrite, BIsWrite);
+ TypeByteSize, HasSameSize, AIsWrite,
+ BIsWrite);
}
MemoryDepChecker::Dependence::DepType
@@ -2163,9 +2180,8 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
return std::get<Dependence::DepType>(Res);
}
- auto &[Dist, MaxStride, CommonStride, TypeByteSize, AIsWrite, BIsWrite] =
- std::get<DepDistanceStrideAndSizeInfo>(Res);
- bool HasSameSize = TypeByteSize > 0;
+ auto &[Dist, MaxStride, CommonStride, TypeByteSize, HasSameSize, AIsWrite,
+ BIsWrite] = std::get<DepDistanceStrideAndSizeInfo>(Res);
ScalarEvolution &SE = *PSE.getSE();
auto &DL = InnermostLoop->getHeader()->getDataLayout();
@@ -2205,13 +2221,8 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
// Negative distances are not plausible dependencies.
if (SE.isKnownNonPositive(Dist)) {
if (SE.isKnownNonNegative(Dist)) {
- if (HasSameSize) {
- // Write to the same location with the same size.
- return Dependence::Forward;
- }
- LLVM_DEBUG(dbgs() << "LAA: possibly zero dependence difference but "
- "different type sizes\n");
- return Dependence::Unknown;
+ // Write to the same location with the same size.
+ return Dependence::Forward;
}
bool IsTrueDataDependence = (AIsWrite && !BIsWrite);
@@ -2229,7 +2240,7 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
: Dependence::Unknown;
}
if (!HasSameSize ||
- couldPreventStoreLoadForward(ConstDist, TypeByteSize)) {
+ couldPreventStoreLoadForward(ConstDist, TypeByteSize.first)) {
LLVM_DEBUG(
dbgs() << "LAA: Forward but may prevent st->ld forwarding\n");
return Dependence::ForwardButPreventsForwarding;
@@ -2295,7 +2306,8 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
// We know that Dist is positive, but it may not be constant. Use the signed
// minimum for computations below, as this ensures we compute the closest
// possible dependence distance.
- uint64_t MinDistanceNeeded = MaxStride * (MinNumIter - 1) + TypeByteSize;
+ uint64_t MinDistanceNeeded =
+ MaxStride * (MinNumIter - 1) + TypeByteSize.first;
if (MinDistanceNeeded > static_cast<uint64_t>(MinDistance)) {
if (!ConstDist) {
// For non-constant distances, we checked the lower bound of the
@@ -2323,14 +2335,15 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
bool IsTrueDataDependence = (!AIsWrite && BIsWrite);
if (IsTrueDataDependence && EnableForwardingConflictDetection && ConstDist &&
- couldPreventStoreLoadForward(MinDistance, TypeByteSize, *CommonStride))
+ couldPreventStoreLoadForward(MinDistance, TypeByteSize.first,
+ *CommonStride))
return Dependence::BackwardVectorizableButPreventsForwarding;
uint64_t MaxVF = MinDepDistBytes / MaxStride;
LLVM_DEBUG(dbgs() << "LAA: Positive min distance " << MinDistance
<< " with max VF = " << MaxVF << '\n');
- uint64_t MaxVFInBits = MaxVF * TypeByteSize * 8;
+ uint64_t MaxVFInBits = MaxVF * TypeByteSize.first * 8;
if (!ConstDist && MaxVFInBits < MaxTargetVectorWidthInBits) {
// For non-constant distances, we checked the lower bound of the dependence
// distance and the distance may be larger at runtime (and safe for
More information about the llvm-commits
mailing list