Skip to content

Commit 87656b3

Browse files
fhahntru
authored andcommitted
[LAA] Refine stride checks for SCEVs during dependence analysis. (llvm#99577)
Update getDependenceDistanceStrideAndSize to reason about different combinations of strides directly and explicitly. Update getPtrStride to return 0 for invariant pointers. Then proceed by checking the strides. If either source or sink are not strided by a constant (i.e. not a non-wrapping AddRec) or invariant, the accesses may overlap with earlier or later iterations and we cannot generate runtime checks to disambiguate them. Otherwise they are either loop invariant or strided. In that case, we can generate a runtime check to disambiguate them. If both are strided by constants, we proceed as previously. This is an alternative to llvm#99239 and also replaces additional checks if the underlying object is loop-invariant. Fixes llvm#87189. PR: llvm#99577
1 parent 1545897 commit 87656b3

File tree

7 files changed

+87
-101
lines changed

7 files changed

+87
-101
lines changed

llvm/include/llvm/Analysis/LoopAccessAnalysis.h

+9-14
Original file line numberDiff line numberDiff line change
@@ -199,9 +199,8 @@ class MemoryDepChecker {
199199
/// Check whether the dependencies between the accesses are safe.
200200
///
201201
/// Only checks sets with elements in \p CheckDeps.
202-
bool areDepsSafe(DepCandidates &AccessSets, MemAccessInfoList &CheckDeps,
203-
const DenseMap<Value *, SmallVector<const Value *, 16>>
204-
&UnderlyingObjects);
202+
bool areDepsSafe(const DepCandidates &AccessSets,
203+
const MemAccessInfoList &CheckDeps);
205204

206205
/// No memory dependence was encountered that would inhibit
207206
/// vectorization.
@@ -351,11 +350,8 @@ class MemoryDepChecker {
351350
/// element access it records this distance in \p MinDepDistBytes (if this
352351
/// distance is smaller than any other distance encountered so far).
353352
/// Otherwise, this function returns true signaling a possible dependence.
354-
Dependence::DepType
355-
isDependent(const MemAccessInfo &A, unsigned AIdx, const MemAccessInfo &B,
356-
unsigned BIdx,
357-
const DenseMap<Value *, SmallVector<const Value *, 16>>
358-
&UnderlyingObjects);
353+
Dependence::DepType isDependent(const MemAccessInfo &A, unsigned AIdx,
354+
const MemAccessInfo &B, unsigned BIdx);
359355

360356
/// Check whether the data dependence could prevent store-load
361357
/// forwarding.
@@ -392,11 +388,9 @@ class MemoryDepChecker {
392388
/// determined, or a struct containing (Distance, Stride, TypeSize, AIsWrite,
393389
/// BIsWrite).
394390
std::variant<Dependence::DepType, DepDistanceStrideAndSizeInfo>
395-
getDependenceDistanceStrideAndSize(
396-
const MemAccessInfo &A, Instruction *AInst, const MemAccessInfo &B,
397-
Instruction *BInst,
398-
const DenseMap<Value *, SmallVector<const Value *, 16>>
399-
&UnderlyingObjects);
391+
getDependenceDistanceStrideAndSize(const MemAccessInfo &A, Instruction *AInst,
392+
const MemAccessInfo &B,
393+
Instruction *BInst);
400394
};
401395

402396
class RuntimePointerChecking;
@@ -797,7 +791,8 @@ replaceSymbolicStrideSCEV(PredicatedScalarEvolution &PSE,
797791
Value *Ptr);
798792

799793
/// If the pointer has a constant stride return it in units of the access type
800-
/// size. Otherwise return std::nullopt.
794+
/// size. If the pointer is loop-invariant, return 0. Otherwise return
795+
/// std::nullopt.
801796
///
802797
/// Ensure that it does not wrap in the address space, assuming the predicate
803798
/// associated with \p PSE is true.

llvm/lib/Analysis/LoopAccessAnalysis.cpp

+56-65
Original file line numberDiff line numberDiff line change
@@ -728,11 +728,6 @@ class AccessAnalysis {
728728

729729
MemAccessInfoList &getDependenciesToCheck() { return CheckDeps; }
730730

731-
const DenseMap<Value *, SmallVector<const Value *, 16>> &
732-
getUnderlyingObjects() {
733-
return UnderlyingObjects;
734-
}
735-
736731
private:
737732
typedef MapVector<MemAccessInfo, SmallSetVector<Type *, 1>> PtrAccessMap;
738733

@@ -1459,22 +1454,23 @@ static bool isNoWrapAddRec(Value *Ptr, const SCEVAddRecExpr *AR,
14591454
}
14601455

14611456
/// Check whether the access through \p Ptr has a constant stride.
1462-
std::optional<int64_t> llvm::getPtrStride(PredicatedScalarEvolution &PSE,
1463-
Type *AccessTy, Value *Ptr,
1464-
const Loop *Lp,
1465-
const DenseMap<Value *, const SCEV *> &StridesMap,
1466-
bool Assume, bool ShouldCheckWrap) {
1457+
std::optional<int64_t>
1458+
llvm::getPtrStride(PredicatedScalarEvolution &PSE, Type *AccessTy, Value *Ptr,
1459+
const Loop *Lp,
1460+
const DenseMap<Value *, const SCEV *> &StridesMap,
1461+
bool Assume, bool ShouldCheckWrap) {
1462+
const SCEV *PtrScev = replaceSymbolicStrideSCEV(PSE, StridesMap, Ptr);
1463+
if (PSE.getSE()->isLoopInvariant(PtrScev, Lp))
1464+
return {0};
1465+
14671466
Type *Ty = Ptr->getType();
14681467
assert(Ty->isPointerTy() && "Unexpected non-ptr");
1469-
14701468
if (isa<ScalableVectorType>(AccessTy)) {
14711469
LLVM_DEBUG(dbgs() << "LAA: Bad stride - Scalable object: " << *AccessTy
14721470
<< "\n");
14731471
return std::nullopt;
14741472
}
14751473

1476-
const SCEV *PtrScev = replaceSymbolicStrideSCEV(PSE, StridesMap, Ptr);
1477-
14781474
const SCEVAddRecExpr *AR = dyn_cast<SCEVAddRecExpr>(PtrScev);
14791475
if (Assume && !AR)
14801476
AR = PSE.getAsAddRec(Ptr);
@@ -1899,24 +1895,12 @@ static bool areStridedAccessesIndependent(uint64_t Distance, uint64_t Stride,
18991895
return ScaledDist % Stride;
19001896
}
19011897

1902-
/// Returns true if any of the underlying objects has a loop varying address,
1903-
/// i.e. may change in \p L.
1904-
static bool
1905-
isLoopVariantIndirectAddress(ArrayRef<const Value *> UnderlyingObjects,
1906-
ScalarEvolution &SE, const Loop *L) {
1907-
return any_of(UnderlyingObjects, [&SE, L](const Value *UO) {
1908-
return !SE.isLoopInvariant(SE.getSCEV(const_cast<Value *>(UO)), L);
1909-
});
1910-
}
1911-
19121898
std::variant<MemoryDepChecker::Dependence::DepType,
19131899
MemoryDepChecker::DepDistanceStrideAndSizeInfo>
19141900
MemoryDepChecker::getDependenceDistanceStrideAndSize(
19151901
const AccessAnalysis::MemAccessInfo &A, Instruction *AInst,
1916-
const AccessAnalysis::MemAccessInfo &B, Instruction *BInst,
1917-
const DenseMap<Value *, SmallVector<const Value *, 16>>
1918-
&UnderlyingObjects) {
1919-
auto &DL = InnermostLoop->getHeader()->getDataLayout();
1902+
const AccessAnalysis::MemAccessInfo &B, Instruction *BInst) {
1903+
const auto &DL = InnermostLoop->getHeader()->getDataLayout();
19201904
auto &SE = *PSE.getSE();
19211905
auto [APtr, AIsWrite] = A;
19221906
auto [BPtr, BIsWrite] = B;
@@ -1933,39 +1917,30 @@ MemoryDepChecker::getDependenceDistanceStrideAndSize(
19331917
BPtr->getType()->getPointerAddressSpace())
19341918
return MemoryDepChecker::Dependence::Unknown;
19351919

1936-
int64_t StrideAPtr =
1937-
getPtrStride(PSE, ATy, APtr, InnermostLoop, SymbolicStrides, true)
1938-
.value_or(0);
1939-
int64_t StrideBPtr =
1940-
getPtrStride(PSE, BTy, BPtr, InnermostLoop, SymbolicStrides, true)
1941-
.value_or(0);
1920+
std::optional<int64_t> StrideAPtr =
1921+
getPtrStride(PSE, ATy, APtr, InnermostLoop, SymbolicStrides, true, true);
1922+
std::optional<int64_t> StrideBPtr =
1923+
getPtrStride(PSE, BTy, BPtr, InnermostLoop, SymbolicStrides, true, true);
19421924

19431925
const SCEV *Src = PSE.getSCEV(APtr);
19441926
const SCEV *Sink = PSE.getSCEV(BPtr);
19451927

19461928
// If the induction step is negative we have to invert source and sink of the
19471929
// dependence when measuring the distance between them. We should not swap
19481930
// AIsWrite with BIsWrite, as their uses expect them in program order.
1949-
if (StrideAPtr < 0) {
1931+
if (StrideAPtr && *StrideAPtr < 0) {
19501932
std::swap(Src, Sink);
19511933
std::swap(AInst, BInst);
1934+
std::swap(StrideAPtr, StrideBPtr);
19521935
}
19531936

19541937
const SCEV *Dist = SE.getMinusSCEV(Sink, Src);
19551938

19561939
LLVM_DEBUG(dbgs() << "LAA: Src Scev: " << *Src << "Sink Scev: " << *Sink
1957-
<< "(Induction step: " << StrideAPtr << ")\n");
1940+
<< "\n");
19581941
LLVM_DEBUG(dbgs() << "LAA: Distance for " << *AInst << " to " << *BInst
19591942
<< ": " << *Dist << "\n");
19601943

1961-
// Needs accesses where the addresses of the accessed underlying objects do
1962-
// not change within the loop.
1963-
if (isLoopVariantIndirectAddress(UnderlyingObjects.find(APtr)->second, SE,
1964-
InnermostLoop) ||
1965-
isLoopVariantIndirectAddress(UnderlyingObjects.find(BPtr)->second, SE,
1966-
InnermostLoop))
1967-
return MemoryDepChecker::Dependence::IndirectUnsafe;
1968-
19691944
// Check if we can prove that Sink only accesses memory after Src's end or
19701945
// vice versa. At the moment this is limited to cases where either source or
19711946
// sink are loop invariant to avoid compile-time increases. This is not
@@ -1987,12 +1962,33 @@ MemoryDepChecker::getDependenceDistanceStrideAndSize(
19871962
}
19881963
}
19891964

1990-
// Need accesses with constant strides and the same direction. We don't want
1991-
// to vectorize "A[B[i]] += ..." and similar code or pointer arithmetic that
1992-
// could wrap in the address space.
1993-
if (!StrideAPtr || !StrideBPtr || (StrideAPtr > 0 && StrideBPtr < 0) ||
1994-
(StrideAPtr < 0 && StrideBPtr > 0)) {
1965+
// Need accesses with constant strides and the same direction for further
1966+
// dependence analysis. We don't want to vectorize "A[B[i]] += ..." and
1967+
// similar code or pointer arithmetic that could wrap in the address space.
1968+
1969+
// If either Src or Sink are not strided (i.e. not a non-wrapping AddRec) and
1970+
// not loop-invariant (stride will be 0 in that case), we cannot analyze the
1971+
// dependence further and also cannot generate runtime checks.
1972+
if (!StrideAPtr || !StrideBPtr) {
19951973
LLVM_DEBUG(dbgs() << "Pointer access with non-constant stride\n");
1974+
return MemoryDepChecker::Dependence::IndirectUnsafe;
1975+
}
1976+
1977+
int64_t StrideAPtrInt = *StrideAPtr;
1978+
int64_t StrideBPtrInt = *StrideBPtr;
1979+
LLVM_DEBUG(dbgs() << "LAA: Src induction step: " << StrideAPtrInt
1980+
<< " Sink induction step: " << StrideBPtrInt << "\n");
1981+
// At least Src or Sink are loop invariant and the other is strided or
1982+
// invariant. We can generate a runtime check to disambiguate the accesses.
1983+
if (StrideAPtrInt == 0 || StrideBPtrInt == 0)
1984+
return MemoryDepChecker::Dependence::Unknown;
1985+
1986+
// Both Src and Sink have a constant stride, check if they are in the same
1987+
// direction.
1988+
if ((StrideAPtrInt > 0 && StrideBPtrInt < 0) ||
1989+
(StrideAPtrInt < 0 && StrideBPtrInt > 0)) {
1990+
LLVM_DEBUG(
1991+
dbgs() << "Pointer access with strides in different directions\n");
19961992
return MemoryDepChecker::Dependence::Unknown;
19971993
}
19981994

@@ -2001,22 +1997,20 @@ MemoryDepChecker::getDependenceDistanceStrideAndSize(
20011997
DL.getTypeStoreSizeInBits(ATy) == DL.getTypeStoreSizeInBits(BTy);
20021998
if (!HasSameSize)
20031999
TypeByteSize = 0;
2004-
return DepDistanceStrideAndSizeInfo(Dist, std::abs(StrideAPtr),
2005-
std::abs(StrideBPtr), TypeByteSize,
2000+
return DepDistanceStrideAndSizeInfo(Dist, std::abs(StrideAPtrInt),
2001+
std::abs(StrideBPtrInt), TypeByteSize,
20062002
AIsWrite, BIsWrite);
20072003
}
20082004

2009-
MemoryDepChecker::Dependence::DepType MemoryDepChecker::isDependent(
2010-
const MemAccessInfo &A, unsigned AIdx, const MemAccessInfo &B,
2011-
unsigned BIdx,
2012-
const DenseMap<Value *, SmallVector<const Value *, 16>>
2013-
&UnderlyingObjects) {
2005+
MemoryDepChecker::Dependence::DepType
2006+
MemoryDepChecker::isDependent(const MemAccessInfo &A, unsigned AIdx,
2007+
const MemAccessInfo &B, unsigned BIdx) {
20142008
assert(AIdx < BIdx && "Must pass arguments in program order");
20152009

20162010
// Get the dependence distance, stride, type size and what access writes for
20172011
// the dependence between A and B.
2018-
auto Res = getDependenceDistanceStrideAndSize(
2019-
A, InstMap[AIdx], B, InstMap[BIdx], UnderlyingObjects);
2012+
auto Res =
2013+
getDependenceDistanceStrideAndSize(A, InstMap[AIdx], B, InstMap[BIdx]);
20202014
if (std::holds_alternative<Dependence::DepType>(Res))
20212015
return std::get<Dependence::DepType>(Res);
20222016

@@ -2250,10 +2244,8 @@ MemoryDepChecker::Dependence::DepType MemoryDepChecker::isDependent(
22502244
return Dependence::BackwardVectorizable;
22512245
}
22522246

2253-
bool MemoryDepChecker::areDepsSafe(
2254-
DepCandidates &AccessSets, MemAccessInfoList &CheckDeps,
2255-
const DenseMap<Value *, SmallVector<const Value *, 16>>
2256-
&UnderlyingObjects) {
2247+
bool MemoryDepChecker::areDepsSafe(const DepCandidates &AccessSets,
2248+
const MemAccessInfoList &CheckDeps) {
22572249

22582250
MinDepDistBytes = -1;
22592251
SmallPtrSet<MemAccessInfo, 8> Visited;
@@ -2296,8 +2288,8 @@ bool MemoryDepChecker::areDepsSafe(
22962288
if (*I1 > *I2)
22972289
std::swap(A, B);
22982290

2299-
Dependence::DepType Type = isDependent(*A.first, A.second, *B.first,
2300-
B.second, UnderlyingObjects);
2291+
Dependence::DepType Type =
2292+
isDependent(*A.first, A.second, *B.first, B.second);
23012293
mergeInStatus(Dependence::isSafeForVectorization(Type));
23022294

23032295
// Gather dependences unless we accumulated MaxDependences
@@ -2652,8 +2644,7 @@ bool LoopAccessInfo::analyzeLoop(AAResults *AA, LoopInfo *LI,
26522644
if (Accesses.isDependencyCheckNeeded()) {
26532645
LLVM_DEBUG(dbgs() << "LAA: Checking memory dependencies\n");
26542646
DepsAreSafe = DepChecker->areDepsSafe(DependentAccesses,
2655-
Accesses.getDependenciesToCheck(),
2656-
Accesses.getUnderlyingObjects());
2647+
Accesses.getDependenciesToCheck());
26572648

26582649
if (!DepsAreSafe && DepChecker->shouldRetryWithRuntimeCheck()) {
26592650
LLVM_DEBUG(dbgs() << "LAA: Retrying with memory checks\n");

llvm/test/Analysis/LoopAccessAnalysis/load-store-index-loaded-in-loop.ll

+12-14
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,19 @@
99
define void @B_indices_loaded_in_loop_A_stored(ptr %A, ptr noalias %B, i64 %N, i64 %off) {
1010
; CHECK-LABEL: 'B_indices_loaded_in_loop_A_stored'
1111
; CHECK-NEXT: loop:
12-
; CHECK-NEXT: Memory dependences are safe with run-time checks
12+
; 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
13+
; CHECK-NEXT: Unsafe indirect dependence.
1314
; CHECK-NEXT: Dependences:
15+
; CHECK-NEXT: IndirectUnsafe:
16+
; CHECK-NEXT: %l = load i32, ptr %gep.B, align 4 ->
17+
; CHECK-NEXT: store i32 %inc, ptr %gep.B, align 4
18+
; CHECK-EMPTY:
19+
; CHECK-NEXT: Unknown:
20+
; CHECK-NEXT: %indices = load i8, ptr %gep.A, align 1 ->
21+
; CHECK-NEXT: store i32 %l, ptr %gep.C, align 4
22+
; CHECK-EMPTY:
1423
; CHECK-NEXT: Run-time memory checks:
15-
; CHECK-NEXT: Check 0:
16-
; CHECK-NEXT: Comparing group ([[GRP1:0x[0-9a-f]+]]):
17-
; CHECK-NEXT: %gep.C = getelementptr inbounds i32, ptr %A, i64 %iv
18-
; CHECK-NEXT: Against group ([[GRP2:0x[0-9a-f]+]]):
19-
; CHECK-NEXT: %gep.A = getelementptr inbounds i8, ptr %A, i64 %iv.off
2024
; CHECK-NEXT: Grouped accesses:
21-
; CHECK-NEXT: Group [[GRP1]]:
22-
; CHECK-NEXT: (Low: %A High: ((4 * %N) + %A))
23-
; CHECK-NEXT: Member: {%A,+,4}<nuw><%loop>
24-
; CHECK-NEXT: Group [[GRP2]]:
25-
; CHECK-NEXT: (Low: (%off + %A) High: (%N + %off + %A))
26-
; CHECK-NEXT: Member: {(%off + %A),+,1}<nw><%loop>
2725
; CHECK-EMPTY:
2826
; CHECK-NEXT: Non vectorizable stores to invariant address were not found in loop.
2927
; CHECK-NEXT: SCEV assumptions:
@@ -59,9 +57,9 @@ define void @B_indices_loaded_in_loop_A_not_stored(ptr %A, ptr noalias %B, i64 %
5957
; CHECK-LABEL: 'B_indices_loaded_in_loop_A_not_stored'
6058
; CHECK-NEXT: loop:
6159
; 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
62-
; CHECK-NEXT: Unknown data dependence.
60+
; CHECK-NEXT: Unsafe indirect dependence.
6361
; CHECK-NEXT: Dependences:
64-
; CHECK-NEXT: Unknown:
62+
; CHECK-NEXT: IndirectUnsafe:
6563
; CHECK-NEXT: %l = load i32, ptr %gep.B, align 4 ->
6664
; CHECK-NEXT: store i32 %inc, ptr %gep.B, align 4
6765
; CHECK-EMPTY:

llvm/test/Analysis/LoopAccessAnalysis/pointer-with-unknown-bounds.ll

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
1313
; CHECK-NEXT: for.body:
1414
; CHECK-NEXT: Report: unsafe dependent memory operations in loop
1515
; CHECK-NOT: Report: cannot identify array bounds
16-
; CHECK-NEXT: Unknown data dependence.
16+
; CHECK-NEXT: Unsafe indirect dependence.
1717
; CHECK-NEXT: Dependences:
18-
; CHECK-NEXT: Unknown:
18+
; CHECK-NEXT: IndirectUnsafe:
1919
; CHECK-NEXT: %loadA = load i16, ptr %arrayidxA, align 2 ->
2020
; CHECK-NEXT: store i16 %mul, ptr %arrayidxA, align 2
2121

llvm/test/Analysis/LoopAccessAnalysis/print-order.ll

+4-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,9 @@
99
; CHECK-LABEL: 'negative_step'
1010
; CHECK: LAA: Found an analyzable loop: loop
1111
; CHECK: LAA: Checking memory dependencies
12-
; CHECK-NEXT: LAA: Src Scev: {(4092 + %A),+,-4}<nw><%loop>Sink Scev: {(4088 + %A)<nuw>,+,-4}<nw><%loop>(Induction step: -1)
12+
; CHECK-NEXT: LAA: Src Scev: {(4092 + %A),+,-4}<nw><%loop>Sink Scev: {(4088 + %A)<nuw>,+,-4}<nw><%loop>
1313
; CHECK-NEXT: LAA: Distance for store i32 %add, ptr %gep.A.plus.1, align 4 to %l = load i32, ptr %gep.A, align 4: -4
14+
; CHECK-NEXT: LAA: Src induction step: -1 Sink induction step: -1
1415
; CHECK-NEXT: LAA: Dependence is negative
1516

1617
define void @negative_step(ptr nocapture %A) {
@@ -41,8 +42,9 @@ exit:
4142
; CHECK-LABEL: 'positive_step'
4243
; CHECK: LAA: Found an analyzable loop: loop
4344
; CHECK: LAA: Checking memory dependencies
44-
; CHECK-NEXT: LAA: Src Scev: {(4 + %A)<nuw>,+,4}<nuw><%loop>Sink Scev: {%A,+,4}<nw><%loop>(Induction step: 1)
45+
; CHECK-NEXT: LAA: Src Scev: {(4 + %A)<nuw>,+,4}<nuw><%loop>Sink Scev: {%A,+,4}<nw><%loop>
4546
; CHECK-NEXT: LAA: Distance for %l = load i32, ptr %gep.A, align 4 to store i32 %add, ptr %gep.A.minus.1, align 4: -4
47+
; CHECK-NEXT: LAA: Src induction step: 1 Sink induction step: 1
4648
; CHECK-NEXT: LAA: Dependence is negative
4749

4850
define void @positive_step(ptr nocapture %A) {

llvm/test/Analysis/LoopAccessAnalysis/select-dependence.ll

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ define void @test(ptr noalias %x, ptr noalias %y, ptr noalias %z) {
55
; CHECK-LABEL: 'test'
66
; CHECK-NEXT: loop:
77
; 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
8-
; CHECK-NEXT: Unknown data dependence.
8+
; CHECK-NEXT: Unsafe indirect dependence.
99
; CHECK-NEXT: Dependences:
10-
; CHECK-NEXT: Unknown:
10+
; CHECK-NEXT: IndirectUnsafe:
1111
; CHECK-NEXT: %load = load double, ptr %gep.sel, align 8 ->
1212
; CHECK-NEXT: store double %load, ptr %gep.sel2, align 8
1313
; CHECK-EMPTY:

llvm/test/Analysis/LoopAccessAnalysis/symbolic-stride.ll

+2-2
Original file line numberDiff line numberDiff line change
@@ -276,9 +276,9 @@ define void @single_stride_used_for_trip_count(ptr noalias %A, ptr noalias %B, i
276276
; CHECK-LABEL: 'single_stride_used_for_trip_count'
277277
; CHECK-NEXT: loop:
278278
; 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
279-
; CHECK-NEXT: Unknown data dependence.
279+
; CHECK-NEXT: Unsafe indirect dependence.
280280
; CHECK-NEXT: Dependences:
281-
; CHECK-NEXT: Unknown:
281+
; CHECK-NEXT: IndirectUnsafe:
282282
; CHECK-NEXT: %load = load i32, ptr %gep.A, align 4 ->
283283
; CHECK-NEXT: store i32 %add, ptr %gep.A.next, align 4
284284
; CHECK-EMPTY:

0 commit comments

Comments
 (0)