[llvm] e701968 - [LAA] Properly report strided access preventing store-to-load forwarding (#208791)

via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 3 08:52:14 PDT 2026


Author: Andrei Elovikov
Date: 2026-08-03T15:52:09Z
New Revision: e70196862584c5b8952919b0e8b994c4e3649326

URL: https://github.com/llvm/llvm-project/commit/e70196862584c5b8952919b0e8b994c4e3649326
DIFF: https://github.com/llvm/llvm-project/commit/e70196862584c5b8952919b0e8b994c4e3649326.diff

LOG: [LAA] Properly report strided access preventing store-to-load forwarding (#208791)

Original test by @fhahn in https://github.com/llvm/llvm-project/pull/191867, further reduced here.
Before this change LAA results in

> maximum safe store-load forward width of 32|0 bits

for `i32` accesses, effectively meaning that only `VF == 1` is safe, yet
not explicitly returning `false` from `couldPreventStoreLoadForward`.
This PR fixes that.

Added: 
    

Modified: 
    llvm/lib/Analysis/LoopAccessAnalysis.cpp
    llvm/test/Analysis/LoopAccessAnalysis/num-iters-for-store-load-conflict.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index c99d43dd1ccc2..e248b22de7d43 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -1970,6 +1970,13 @@ bool MemoryDepChecker::couldPreventStoreLoadForward(uint64_t Distance,
     uint64_t MaxVFInBits = MaxVF * TypeByteSize * 8;
     MaxStoreLoadForwardSafeDistanceInBits =
         std::min(MaxStoreLoadForwardSafeDistanceInBits, MaxVFInBits);
+
+    if (MaxVF < 2) {
+      LLVM_DEBUG(
+          dbgs() << "LAA: strided access with Distance " << Distance
+                 << " that could cause a store-load forwarding conflict\n");
+      return true;
+    }
   }
   return false;
 }

diff  --git a/llvm/test/Analysis/LoopAccessAnalysis/num-iters-for-store-load-conflict.ll b/llvm/test/Analysis/LoopAccessAnalysis/num-iters-for-store-load-conflict.ll
index d3eda21dee27e..71eaa0ed2341e 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/num-iters-for-store-load-conflict.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/num-iters-for-store-load-conflict.ll
@@ -308,3 +308,91 @@ outer.latch:
 exit:
   ret void
 }
+
+define void @stride2_store_load_preventing_forwarding(ptr %A) {
+; CHECK-LABEL: 'stride2_store_load_preventing_forwarding'
+; CHECK-NEXT:    loop:
+; 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
+; CHECK-NEXT:  Backward loop carried data dependence that prevents store-to-load forwarding.
+; CHECK-NEXT:      Dependences:
+; CHECK-NEXT:        BackwardVectorizableButPreventsForwarding:
+; CHECK-NEXT:            %ld = load i32, ptr %gep.ld, align 4 ->
+; CHECK-NEXT:            store i32 %ld, ptr %gep.st, align 4
+; CHECK-EMPTY:
+; CHECK-NEXT:      Run-time memory checks:
+; CHECK-NEXT:      Grouped accesses:
+; CHECK-EMPTY:
+; CHECK-NEXT:      Non vectorizable stores to invariant address were not found in loop.
+; CHECK-NEXT:      SCEV assumptions:
+; CHECK-EMPTY:
+; CHECK-NEXT:      Expressions re-written:
+;
+entry:
+  %A.offset = getelementptr i32, ptr %A, i64 6
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+
+  %iv.x2 = mul i64 %iv, 2
+  %gep.ld = getelementptr i32, ptr %A, i64 %iv.x2
+  %ld = load i32, ptr %gep.ld, align 4
+  %gep.st = getelementptr i32, ptr %A.offset, i64 %iv.x2
+  store i32 %ld, ptr %gep.st, align 4
+
+  %iv.next = add i64 %iv, 1
+  %cmp = icmp ne i64 %iv, 1024
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret void
+}
+
+; FIXME: VF 2 is safe for store-load forwarding:
+;                 idx |  0 |  1 |  2 |  3 |  4 |  5 |  6 |  7 |  8 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 |
+; v/iter 0 load  lane |  0 |    |    |  1 |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |
+; v/iter 0 store lane |    |    |    |    |    |    |  0 |    |    |  1 |    |    |    |    |    |    |    |    |    |
+; -------------------------------------------------------------------------------------------------------------------|
+; v/iter 1 load  lane |    |    |    |    |    |    |  0 |    |    |  1 |    |    |    |    |    |    |    |    |    |
+; v/iter 1 store lane |    |    |    |    |    |    |    |    |    |    |    |    |  0 |    |    |  1 |    |    |    |
+; -------------------------------------------------------------------------------------------------------------------|
+; v/iter 2 load  lane |    |    |    |    |    |    |    |    |    |    |    |    |  0 |    |    |  1 |    |    |    |
+; v/iter 2 store lane |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |    |  0 |
+define void @stride3_store_load_forwarding_safe_dist(ptr %A) {
+; CHECK-LABEL: 'stride3_store_load_forwarding_safe_dist'
+; CHECK-NEXT:    loop:
+; 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
+; CHECK-NEXT:  Backward loop carried data dependence that prevents store-to-load forwarding.
+; CHECK-NEXT:      Dependences:
+; CHECK-NEXT:        BackwardVectorizableButPreventsForwarding:
+; CHECK-NEXT:            %ld = load i32, ptr %gep.ld, align 4 ->
+; CHECK-NEXT:            store i32 %ld, ptr %gep.st, align 4
+; CHECK-EMPTY:
+; CHECK-NEXT:      Run-time memory checks:
+; CHECK-NEXT:      Grouped accesses:
+; CHECK-EMPTY:
+; CHECK-NEXT:      Non vectorizable stores to invariant address were not found in loop.
+; CHECK-NEXT:      SCEV assumptions:
+; CHECK-EMPTY:
+; CHECK-NEXT:      Expressions re-written:
+;
+entry:
+  %A.offset = getelementptr i32, ptr %A, i64 6
+  br label %loop
+
+loop:
+  %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+
+  %iv.x2 = mul i64 %iv, 3
+  %gep.ld = getelementptr i32, ptr %A, i64 %iv.x2
+  %ld = load i32, ptr %gep.ld, align 4
+  %gep.st = getelementptr i32, ptr %A.offset, i64 %iv.x2
+  store i32 %ld, ptr %gep.st, align 4
+
+  %iv.next = add i64 %iv, 1
+  %cmp = icmp ne i64 %iv, 1024
+  br i1 %cmp, label %loop, label %exit
+
+exit:
+  ret void
+}


        


More information about the llvm-commits mailing list