Skip to content

Commit 4d9e77e

Browse files
committed
[LAA] hoist setting condition for rt-checks (NFC)
Strip ShouldRetyWithRuntimeCheck from the DepedenceDistanceStrideAndSizeInfo struct, and free isDependent from the responsibility of setting the condition for when runtime-checks are needed, transferring this responsibility to getDependenceDistanceStrideAndSize. The change is simple enough, but proving that this was the original intent of the code, making the change non-functional is non-trivial. The proof is as follows. The condition for runtime-checks is only respected when we return a Dependence::DepType of Dependence::Unknown, and the only possible place that could introduce a functional change with this patch is when Dist is possibly zero, but HasSameSize is false. Previously, we weren't checking that the Dist is not a SCEVConstant, and setting the runtime-check condition. Now, with the runtime-check condition hoisted, we do. We note that for a functional change to occur, the distance must be both non-constant, not provably non-positive and non-negative, and this is an impossibility.
1 parent 29db305 commit 4d9e77e

File tree

3 files changed

+29
-51
lines changed

3 files changed

+29
-51
lines changed

llvm/include/llvm/Analysis/LoopAccessAnalysis.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,6 @@ class MemoryDepChecker {
393393
uint64_t MaxStride;
394394
std::optional<uint64_t> CommonStride;
395395

396-
bool ShouldRetryWithRuntimeCheck;
397-
398396
/// TypeByteSize is either the common store size of both accesses, or 0 when
399397
/// store sizes mismatch.
400398
uint64_t TypeByteSize;
@@ -404,11 +402,9 @@ class MemoryDepChecker {
404402

405403
DepDistanceStrideAndSizeInfo(const SCEV *Dist, uint64_t MaxStride,
406404
std::optional<uint64_t> CommonStride,
407-
bool ShouldRetryWithRuntimeCheck,
408405
uint64_t TypeByteSize, bool AIsWrite,
409406
bool BIsWrite)
410407
: Dist(Dist), MaxStride(MaxStride), CommonStride(CommonStride),
411-
ShouldRetryWithRuntimeCheck(ShouldRetryWithRuntimeCheck),
412408
TypeByteSize(TypeByteSize), AIsWrite(AIsWrite), BIsWrite(BIsWrite) {}
413409
};
414410

llvm/lib/Analysis/LoopAccessAnalysis.cpp

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1979,14 +1979,14 @@ MemoryDepChecker::getDependenceDistanceStrideAndSize(
19791979
if (StrideAScaled == StrideBScaled)
19801980
CommonStride = StrideAScaled;
19811981

1982-
// TODO: Historically, we don't retry with runtime checks unless the
1983-
// (unscaled) strides are the same. Fix this once the condition for runtime
1984-
// checks in isDependent is fixed.
1985-
bool ShouldRetryWithRuntimeCheck = StrideAPtrInt == StrideBPtrInt;
1982+
// TODO: FoundNonConstantDistanceDependence is used as a necessary condition
1983+
// to consider retrying with runtime checks. Historically, we did not set it
1984+
// when (unscaled) strides were different but there is no inherent reason to.
1985+
if (!isa<SCEVConstant>(Dist))
1986+
FoundNonConstantDistanceDependence |= StrideAPtrInt == StrideBPtrInt;
19861987

19871988
return DepDistanceStrideAndSizeInfo(Dist, MaxStride, CommonStride,
1988-
ShouldRetryWithRuntimeCheck, TypeByteSize,
1989-
AIsWrite, BIsWrite);
1989+
TypeByteSize, AIsWrite, BIsWrite);
19901990
}
19911991

19921992
MemoryDepChecker::Dependence::DepType
@@ -2001,15 +2001,11 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
20012001
if (std::holds_alternative<Dependence::DepType>(Res))
20022002
return std::get<Dependence::DepType>(Res);
20032003

2004-
auto &[Dist, MaxStride, CommonStride, ShouldRetryWithRuntimeCheck,
2005-
TypeByteSize, AIsWrite, BIsWrite] =
2004+
auto &[Dist, MaxStride, CommonStride, TypeByteSize, AIsWrite, BIsWrite] =
20062005
std::get<DepDistanceStrideAndSizeInfo>(Res);
20072006
bool HasSameSize = TypeByteSize > 0;
20082007

20092008
if (isa<SCEVCouldNotCompute>(Dist)) {
2010-
// TODO: Relax requirement that there is a common unscaled stride to retry
2011-
// with non-constant distance dependencies.
2012-
FoundNonConstantDistanceDependence |= ShouldRetryWithRuntimeCheck;
20132009
LLVM_DEBUG(dbgs() << "LAA: Dependence because of uncomputable distance.\n");
20142010
return Dependence::Unknown;
20152011
}
@@ -2068,14 +2064,8 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
20682064
// forward dependency will allow vectorization using any width.
20692065

20702066
if (IsTrueDataDependence && EnableForwardingConflictDetection) {
2071-
if (!ConstDist) {
2072-
// TODO: FoundNonConstantDistanceDependence is used as a necessary
2073-
// condition to consider retrying with runtime checks. Historically, we
2074-
// did not set it when strides were different but there is no inherent
2075-
// reason to.
2076-
FoundNonConstantDistanceDependence |= ShouldRetryWithRuntimeCheck;
2067+
if (!ConstDist)
20772068
return Dependence::Unknown;
2078-
}
20792069
if (!HasSameSize || couldPreventStoreLoadForward(
20802070
ConstDist->abs().getZExtValue(), TypeByteSize)) {
20812071
LLVM_DEBUG(
@@ -2090,22 +2080,8 @@ MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
20902080

20912081
int64_t MinDistance = SE.getSignedRangeMin(Dist).getSExtValue();
20922082
// Below we only handle strictly positive distances.
2093-
if (MinDistance <= 0) {
2094-
FoundNonConstantDistanceDependence |= ShouldRetryWithRuntimeCheck;
2083+
if (MinDistance <= 0)
20952084
return Dependence::Unknown;
2096-
}
2097-
2098-
if (!ConstDist) {
2099-
// Previously this case would be treated as Unknown, possibly setting
2100-
// FoundNonConstantDistanceDependence to force re-trying with runtime
2101-
// checks. Until the TODO below is addressed, set it here to preserve
2102-
// original behavior w.r.t. re-trying with runtime checks.
2103-
// TODO: FoundNonConstantDistanceDependence is used as a necessary
2104-
// condition to consider retrying with runtime checks. Historically, we
2105-
// did not set it when strides were different but there is no inherent
2106-
// reason to.
2107-
FoundNonConstantDistanceDependence |= ShouldRetryWithRuntimeCheck;
2108-
}
21092085

21102086
if (!HasSameSize) {
21112087
LLVM_DEBUG(dbgs() << "LAA: ReadWrite-Write positive dependency with "

llvm/test/Analysis/LoopAccessAnalysis/retry-runtime-checks-after-dependence-analysis.ll

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -320,28 +320,34 @@ exit:
320320
define void @retry_after_dep_check_with_unknown_offset(ptr %A, i32 %offset) {
321321
; CHECK-LABEL: 'retry_after_dep_check_with_unknown_offset'
322322
; CHECK-NEXT: loop:
323-
; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
324-
; CHECK-NEXT: Unknown data dependence.
323+
; CHECK-NEXT: Memory dependences are safe with run-time checks
325324
; CHECK-NEXT: Dependences:
326-
; CHECK-NEXT: Unknown:
327-
; CHECK-NEXT: %l.A = load float, ptr %A, align 4 ->
328-
; CHECK-NEXT: store float 0.000000e+00, ptr %A.100.iv.offset.3, align 4
329-
; CHECK-EMPTY:
330-
; CHECK-NEXT: Unknown:
331-
; CHECK-NEXT: %l.A = load float, ptr %A, align 4 ->
332-
; CHECK-NEXT: store float %l.A, ptr %A.100.iv, align 8
333-
; CHECK-EMPTY:
334325
; CHECK-NEXT: Run-time memory checks:
326+
; CHECK-NEXT: Check 0:
327+
; CHECK-NEXT: Comparing group GRP0:
328+
; CHECK-NEXT: %A.100.iv = getelementptr { float, float }, ptr %A.100, i64 %iv
329+
; CHECK-NEXT: Against group GRP1:
330+
; CHECK-NEXT: %A.100.iv.offset.3 = getelementptr i8, ptr %A.100, i64 %iv.offset.3
331+
; CHECK-NEXT: Check 1:
332+
; CHECK-NEXT: Comparing group GRP0:
333+
; CHECK-NEXT: %A.100.iv = getelementptr { float, float }, ptr %A.100, i64 %iv
334+
; CHECK-NEXT: Against group GRP2:
335+
; CHECK-NEXT: ptr %A
336+
; CHECK-NEXT: Check 2:
337+
; CHECK-NEXT: Comparing group GRP1:
338+
; CHECK-NEXT: %A.100.iv.offset.3 = getelementptr i8, ptr %A.100, i64 %iv.offset.3
339+
; CHECK-NEXT: Against group GRP2:
340+
; CHECK-NEXT: ptr %A
335341
; CHECK-NEXT: Grouped accesses:
336342
; CHECK-NEXT: Group GRP0:
337-
; CHECK-NEXT: (Low: %A High: (4 + %A))
338-
; CHECK-NEXT: Member: %A
343+
; CHECK-NEXT: (Low: (100 + %A) High: (96 + (8 * (zext i32 %offset to i64))<nuw><nsw> + %A))
344+
; CHECK-NEXT: Member: {(100 + %A),+,8}<%loop>
339345
; CHECK-NEXT: Group GRP1:
340346
; CHECK-NEXT: (Low: (100 + (8 * (zext i32 %offset to i64))<nuw><nsw> + %A) High: (96 + (16 * (zext i32 %offset to i64))<nuw><nsw> + %A))
341347
; CHECK-NEXT: Member: {(100 + (8 * (zext i32 %offset to i64))<nuw><nsw> + %A),+,8}<%loop>
342348
; CHECK-NEXT: Group GRP2:
343-
; CHECK-NEXT: (Low: (100 + %A) High: (96 + (8 * (zext i32 %offset to i64))<nuw><nsw> + %A))
344-
; CHECK-NEXT: Member: {(100 + %A),+,8}<%loop>
349+
; CHECK-NEXT: (Low: %A High: (4 + %A))
350+
; CHECK-NEXT: Member: %A
345351
; CHECK-EMPTY:
346352
; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop.
347353
; CHECK-NEXT: SCEV assumptions:

0 commit comments

Comments
 (0)