[llvm] [LAA] Add tests for a set of miscompiles. (NFC) (PR #230773)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Sat Oct 10 03:25:43 PDT 2026
https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/230773
Add tests for the following issues:
* interleaved-accesses-retry-runtime-checks.ll: when LAA retries with runtime checks, the store of an interleave group is moved past a load from the same address.
* is-safe-dep-distance-narrow-btc.ll: accesses with a real backward dependence are reported as safe if the byte stride does not fit in a narrow backedge-taken count type or MaxBTC * MaxStride wraps in it.
* is-safe-dep-distance-partial-overlap.ll: accesses are reported as independent if |Dist| > MaxBTC * MaxStride, even if the distance is not a multiple of the access size and the accesses partially overlap.
* different-access-types-rt-checks.ll: the runtime check bounds of a pointer loaded as i32 and stored as i8 only account for the i8 store, so the tail of the loaded range is not checked.
* runtime-check-grouping-wrapping-bounds.ll: pointers whose bounds can wrap relative to each other are grouped, so the group's Low can be above its High and the runtime checks never detect a conflict.
>From 65c4dc4eb0c5c0905bded03f2552d0716aa7cb73 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Fri, 9 Oct 2026 14:46:06 +0000
Subject: [PATCH] [LAA] Add tests for miscompiles with runtime checks and
dependence analysis (NFC).
Add tests for the following issues:
* interleaved-accesses-retry-runtime-checks.ll: when LAA retries with
runtime checks, the store of an interleave group is moved past a load
from the same address.
* is-safe-dep-distance-narrow-btc.ll: accesses with a real backward
dependence are reported as safe if the byte stride does not fit in a
narrow backedge-taken count type or MaxBTC * MaxStride wraps in it.
* is-safe-dep-distance-partial-overlap.ll: accesses are reported as
independent if |Dist| > MaxBTC * MaxStride, even if the distance is not
a multiple of the access size and the accesses partially overlap.
* different-access-types-rt-checks.ll: the runtime check bounds of a
pointer loaded as i32 and stored as i8 only account for the i8 store, so
the tail of the loaded range is not checked.
* runtime-check-grouping-wrapping-bounds.ll: pointers whose bounds can wrap
relative to each other are grouped, so the group's Low can be above its
High and the runtime checks never detect a conflict.
---
.../different-access-types-rt-checks.ll | 248 ++++++++++++
.../is-safe-dep-distance-narrow-btc.ll | 232 +++++++++++
.../is-safe-dep-distance-partial-overlap.ll | 130 ++++++
.../runtime-check-grouping-wrapping-bounds.ll | 373 ++++++++++++++++++
...terleaved-accesses-retry-runtime-checks.ll | 67 ++++
5 files changed, 1050 insertions(+)
create mode 100644 llvm/test/Analysis/LoopAccessAnalysis/is-safe-dep-distance-narrow-btc.ll
create mode 100644 llvm/test/Analysis/LoopAccessAnalysis/is-safe-dep-distance-partial-overlap.ll
create mode 100644 llvm/test/Analysis/LoopAccessAnalysis/runtime-check-grouping-wrapping-bounds.ll
create mode 100644 llvm/test/Transforms/LoopVectorize/interleaved-accesses-retry-runtime-checks.ll
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/different-access-types-rt-checks.ll b/llvm/test/Analysis/LoopAccessAnalysis/different-access-types-rt-checks.ll
index cac1b857063d0..1e96714c95cf4 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/different-access-types-rt-checks.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/different-access-types-rt-checks.ll
@@ -163,3 +163,251 @@ loop:
exit:
ret void
}
+
+define void @load_store_same_pointer_with_different_sizes(ptr %a, ptr %b, i64 %n) {
+; CHECK-LABEL: 'load_store_same_pointer_with_different_sizes'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe with run-time checks
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: Forward:
+; CHECK-NEXT: %l.a = load i32, ptr %gep.a, align 1 ->
+; CHECK-NEXT: store i8 0, ptr %gep.a, align 1
+; CHECK-EMPTY:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Against group GRP1:
+; CHECK-NEXT: %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group GRP0:
+; CHECK-NEXT: (Low: %a High: (-3 + (4 * %n) + %a))
+; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop>
+; CHECK-NEXT: Group GRP1:
+; CHECK-NEXT: (Low: %b High: ((4 * %n) + %b))
+; CHECK-NEXT: Member: {%b,+,4}<nuw><%loop>
+; 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:
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ %l.a = load i32, ptr %gep.a, align 1
+ store i8 0, ptr %gep.a, align 1
+ %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+ store i32 %l.a, ptr %gep.b, align 1
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+define void @load_store_same_pointer_with_same_sizes(ptr %a, ptr %b, i64 %n) {
+; CHECK-LABEL: 'load_store_same_pointer_with_same_sizes'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe with run-time checks
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Against group GRP1:
+; CHECK-NEXT: %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group GRP0:
+; CHECK-NEXT: (Low: %a High: ((4 * %n) + %a))
+; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop>
+; CHECK-NEXT: Group GRP1:
+; CHECK-NEXT: (Low: %b High: ((4 * %n) + %b))
+; CHECK-NEXT: Member: {%b,+,4}<nuw><%loop>
+; 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:
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ %l.a = load i32, ptr %gep.a, align 1
+ store i32 0, ptr %gep.a, align 1
+ %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+ store i32 %l.a, ptr %gep.b, align 1
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+define void @load_store_same_pointer_with_different_sizes_read_only_group(ptr %a, ptr %b, i64 %n) {
+; CHECK-LABEL: 'load_store_same_pointer_with_different_sizes_read_only_group'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe with run-time checks
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: Forward:
+; CHECK-NEXT: %l.a = load i32, ptr %gep.a, align 1 ->
+; CHECK-NEXT: store i8 0, ptr %gep.a, align 1
+; CHECK-EMPTY:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Against group GRP1:
+; CHECK-NEXT: %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group GRP0:
+; CHECK-NEXT: (Low: %a High: (-3 + (4 * %n) + %a))
+; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop>
+; CHECK-NEXT: Group GRP1:
+; CHECK-NEXT: (Low: %b High: ((4 * %n) + %b))
+; CHECK-NEXT: Member: {%b,+,4}<nuw><%loop>
+; 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:
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ %l.a = load i32, ptr %gep.a, align 1
+ %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+ %l.b = load i32, ptr %gep.b, align 1
+ store i8 0, ptr %gep.a, align 1
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+define void @load_store_same_pointer_with_different_sizes_unknown_dep(ptr %a, ptr %b, i64 %k, i64 %n) {
+; CHECK-LABEL: 'load_store_same_pointer_with_different_sizes_unknown_dep'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe with run-time checks
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Against group GRP1:
+; CHECK-NEXT: %gep.a.k = getelementptr inbounds i32, ptr %a.k, i64 %iv
+; CHECK-NEXT: Check 1:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Against group GRP2:
+; CHECK-NEXT: %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+; CHECK-NEXT: Check 2:
+; CHECK-NEXT: Comparing group GRP1:
+; CHECK-NEXT: %gep.a.k = getelementptr inbounds i32, ptr %a.k, i64 %iv
+; CHECK-NEXT: Against group GRP2:
+; CHECK-NEXT: %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group GRP0:
+; CHECK-NEXT: (Low: %a High: (-3 + (4 * %n) + %a))
+; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop>
+; CHECK-NEXT: Group GRP1:
+; CHECK-NEXT: (Low: (%k + %a) High: (-3 + (4 * %n) + %k + %a))
+; CHECK-NEXT: Member: {(%k + %a),+,4}<nw><%loop>
+; CHECK-NEXT: Group GRP2:
+; CHECK-NEXT: (Low: %b High: ((4 * %n) + %b))
+; CHECK-NEXT: Member: {%b,+,4}<nuw><%loop>
+; 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.k = getelementptr inbounds i8, ptr %a, i64 %k
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ %l.a = load i32, ptr %gep.a, align 1
+ %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+ %l.b = load i32, ptr %gep.b, align 1
+ store i8 0, ptr %gep.a, align 1
+ %gep.a.k = getelementptr inbounds i32, ptr %a.k, i64 %iv
+ store i8 1, ptr %gep.a.k, align 1
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+define void @stores_same_pointer_with_different_sizes_unknown_dep(ptr %a, i64 %k, i64 %n) {
+; CHECK-LABEL: 'stores_same_pointer_with_different_sizes_unknown_dep'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe with run-time checks
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Against group GRP1:
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Check 1:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Against group GRP2:
+; CHECK-NEXT: %gep.a.k = getelementptr inbounds i32, ptr %a.k, i64 %iv
+; CHECK-NEXT: Check 2:
+; CHECK-NEXT: Comparing group GRP1:
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Against group GRP2:
+; CHECK-NEXT: %gep.a.k = getelementptr inbounds i32, ptr %a.k, i64 %iv
+; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group GRP0:
+; CHECK-NEXT: (Low: %a High: ((4 * %n) + %a))
+; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop>
+; CHECK-NEXT: Group GRP1:
+; CHECK-NEXT: (Low: %a High: (-3 + (4 * %n) + %a))
+; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop>
+; CHECK-NEXT: Group GRP2:
+; CHECK-NEXT: (Low: (%k + %a) High: (-3 + (4 * %n) + %k + %a))
+; CHECK-NEXT: Member: {(%k + %a),+,4}<nw><%loop>
+; 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.k = getelementptr inbounds i8, ptr %a, i64 %k
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ store i32 0, ptr %gep.a, align 1
+ store i8 1, ptr %gep.a, align 1
+ %gep.a.k = getelementptr inbounds i32, ptr %a.k, i64 %iv
+ store i8 2, ptr %gep.a.k, align 1
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/is-safe-dep-distance-narrow-btc.ll b/llvm/test/Analysis/LoopAccessAnalysis/is-safe-dep-distance-narrow-btc.ll
new file mode 100644
index 0000000000000..1b2b14df58f03
--- /dev/null
+++ b/llvm/test/Analysis/LoopAccessAnalysis/is-safe-dep-distance-narrow-btc.ll
@@ -0,0 +1,232 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes='print<access-info>' -disable-output %s 2>&1 | FileCheck %s
+
+; The 256-byte stride does not fit in the i8 backedge-taken count type.
+define void @backward_dep_i8_btc_stride_256(ptr %a) {
+; CHECK-LABEL: 'backward_dep_i8_btc_stride_256'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe
+; CHECK-NEXT: Dependences:
+; 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:
+ br label %loop
+
+loop:
+ %iv = phi i8 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a = getelementptr [256 x i8], ptr %a, i8 %iv
+ %l.a = load i8, ptr %gep.a, align 1
+ %iv.next = add i8 %iv, 1
+ %gep.a.next = getelementptr [256 x i8], ptr %a, i8 %iv.next
+ store i8 %l.a, ptr %gep.a.next, align 1
+ %ec = icmp ult i8 %iv.next, 100
+ br i1 %ec, label %loop, label %exit
+
+exit:
+ ret void
+}
+
+define void @backward_dep_i8_btc_stride_255(ptr %a) {
+; CHECK-LABEL: 'backward_dep_i8_btc_stride_255'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe
+; CHECK-NEXT: Dependences:
+; 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:
+ br label %loop
+
+loop:
+ %iv = phi i8 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a = getelementptr [255 x i8], ptr %a, i8 %iv
+ %l.a = load i8, ptr %gep.a, align 1
+ %iv.next = add i8 %iv, 1
+ %gep.a.next = getelementptr [255 x i8], ptr %a, i8 %iv.next
+ store i8 %l.a, ptr %gep.a.next, align 1
+ %ec = icmp ult i8 %iv.next, 100
+ br i1 %ec, label %loop, label %exit
+
+exit:
+ ret void
+}
+
+define void @backward_dep_i32_btc_stride_256(ptr %a) {
+; CHECK-LABEL: 'backward_dep_i32_btc_stride_256'
+; 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.
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: Backward:
+; CHECK-NEXT: %l.a = load i8, ptr %gep.a, align 1 ->
+; CHECK-NEXT: store i8 %l.a, ptr %gep.a.next, align 1
+; 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:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a = getelementptr [256 x i8], ptr %a, i32 %iv
+ %l.a = load i8, ptr %gep.a, align 1
+ %iv.next = add i32 %iv, 1
+ %gep.a.next = getelementptr [256 x i8], ptr %a, i32 %iv.next
+ store i8 %l.a, ptr %gep.a.next, align 1
+ %ec = icmp ult i32 %iv.next, 100
+ br i1 %ec, label %loop, label %exit
+
+exit:
+ ret void
+}
+
+; The distance is 4 iterations; MaxBTC * 64 wraps in i8.
+define void @backward_dep_i8_btc_product_wraps(ptr %a, i8 %n) {
+; CHECK-LABEL: 'backward_dep_i8_btc_product_wraps'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe
+; CHECK-NEXT: Dependences:
+; 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.256 = getelementptr i8, ptr %a, i64 256
+ br label %loop
+
+loop:
+ %iv = phi i8 [ 0, %entry ], [ %iv.next, %loop ]
+ %iv.ext = zext i8 %iv to i64
+ %gep.a = getelementptr inbounds [16 x i32], ptr %a, i64 %iv.ext
+ %l.a = load i32, ptr %gep.a, align 4
+ %gep.a.256 = getelementptr inbounds [16 x i32], ptr %a.256, i64 %iv.ext
+ store i32 %l.a, ptr %gep.a.256, align 4
+ %iv.next = add nuw i8 %iv, 1
+ %ec = icmp eq i8 %iv.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+; The distance of 16384 bytes is larger than 255 * 64.
+define void @no_dep_i8_btc_large_distance(ptr %a, i8 %n) {
+; CHECK-LABEL: 'no_dep_i8_btc_large_distance'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe
+; CHECK-NEXT: Dependences:
+; 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.16384 = getelementptr i8, ptr %a, i64 16384
+ br label %loop
+
+loop:
+ %iv = phi i8 [ 0, %entry ], [ %iv.next, %loop ]
+ %iv.ext = zext i8 %iv to i64
+ %gep.a = getelementptr inbounds [16 x i32], ptr %a, i64 %iv.ext
+ %l.a = load i32, ptr %gep.a, align 4
+ %gep.a.16384 = getelementptr inbounds [16 x i32], ptr %a.16384, i64 %iv.ext
+ store i32 %l.a, ptr %gep.a.16384, align 4
+ %iv.next = add nuw i8 %iv, 1
+ %ec = icmp eq i8 %iv.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+define void @no_dep_i32_btc_large_distance(ptr %a) {
+; CHECK-LABEL: 'no_dep_i32_btc_large_distance'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe
+; CHECK-NEXT: Dependences:
+; 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:
+ br label %loop
+
+loop:
+ %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a = getelementptr i32, ptr %a, i32 %iv
+ %l.a = load i32, ptr %gep.a, align 4
+ %iv.4096 = add i32 %iv, 4096
+ %gep.a.4096 = getelementptr i32, ptr %a, i32 %iv.4096
+ store i32 %l.a, ptr %gep.a.4096, align 4
+ %iv.next = add i32 %iv, 1
+ %ec = icmp ult i32 %iv.next, 100
+ br i1 %ec, label %loop, label %exit
+
+exit:
+ ret void
+}
+
+; FIXME: MaxBTC * 8 wraps in i64, so a[iv + n + 1] may alias a[iv + 1].
+define void @backward_dep_i64_btc_product_wraps(ptr %a, i64 %n) {
+; CHECK-LABEL: 'backward_dep_i64_btc_product_wraps'
+; CHECK-NEXT: loop.header:
+; CHECK-NEXT: Memory dependences are safe
+; CHECK-NEXT: Dependences:
+; 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:
+ %n.1 = add i64 %n, 1
+ br label %loop.header
+
+loop.header:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
+ %gep.a = getelementptr i64, ptr %a, i64 %iv
+ %l.a = load i64, ptr %gep.a, align 8
+ %iv.n.1 = add i64 %iv, %n.1
+ %gep.a.n.1 = getelementptr i64, ptr %a, i64 %iv.n.1
+ store i64 %l.a, ptr %gep.a.n.1, align 8
+ %c = icmp eq i64 %l.a, 0
+ br i1 %c, label %exit, label %loop.latch
+
+loop.latch:
+ %iv.next = add nuw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %loop.header
+
+exit:
+ ret void
+}
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/is-safe-dep-distance-partial-overlap.ll b/llvm/test/Analysis/LoopAccessAnalysis/is-safe-dep-distance-partial-overlap.ll
new file mode 100644
index 0000000000000..807bf39d1356b
--- /dev/null
+++ b/llvm/test/Analysis/LoopAccessAnalysis/is-safe-dep-distance-partial-overlap.ll
@@ -0,0 +1,130 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes='print<access-info>' -disable-output %s 2>&1 | FileCheck %s
+
+; MaxBTC * 4 = 60 and the distance is 61 bytes, so the i32 store in iteration 0
+; overlaps the load in iteration 15.
+; FIXME: The accesses are incorrectly reported as independent.
+define void @partial_overlap_pos_dist(ptr %a) {
+; CHECK-LABEL: 'partial_overlap_pos_dist'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe
+; CHECK-NEXT: Dependences:
+; 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.61 = getelementptr i8, ptr %a, i64 61
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ %l.a = load i32, ptr %gep.a, align 1
+ %gep.a.61 = getelementptr inbounds i32, ptr %a.61, i64 %iv
+ store i32 %l.a, ptr %gep.a.61, align 1
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, 16
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+define void @no_overlap_pos_dist(ptr %a) {
+; CHECK-LABEL: 'no_overlap_pos_dist'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe
+; CHECK-NEXT: Dependences:
+; 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.64 = getelementptr i8, ptr %a, i64 64
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ %l.a = load i32, ptr %gep.a, align 1
+ %gep.a.64 = getelementptr inbounds i32, ptr %a.64, i64 %iv
+ store i32 %l.a, ptr %gep.a.64, align 1
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, 16
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+; FIXME: The accesses are incorrectly reported as independent.
+define void @partial_overlap_neg_dist(ptr %a) {
+; CHECK-LABEL: 'partial_overlap_neg_dist'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe
+; CHECK-NEXT: Dependences:
+; 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.61 = getelementptr i8, ptr %a, i64 61
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a.61 = getelementptr inbounds i32, ptr %a.61, i64 %iv
+ %l.a = load i32, ptr %gep.a.61, align 1
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ store i32 %l.a, ptr %gep.a, align 1
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, 16
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+define void @no_overlap_neg_dist(ptr %a) {
+; CHECK-LABEL: 'no_overlap_neg_dist'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe
+; CHECK-NEXT: Dependences:
+; 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.64 = getelementptr i8, ptr %a, i64 64
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a.64 = getelementptr inbounds i32, ptr %a.64, i64 %iv
+ %l.a = load i32, ptr %gep.a.64, align 1
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ store i32 %l.a, ptr %gep.a, align 1
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, 16
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/runtime-check-grouping-wrapping-bounds.ll b/llvm/test/Analysis/LoopAccessAnalysis/runtime-check-grouping-wrapping-bounds.ll
new file mode 100644
index 0000000000000..87592ababebf4
--- /dev/null
+++ b/llvm/test/Analysis/LoopAccessAnalysis/runtime-check-grouping-wrapping-bounds.ll
@@ -0,0 +1,373 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes='print<access-info>' -disable-output %s 2>&1 | FileCheck %s
+
+; The conditional load of a[iv - 2^40] may wrap below %a, so it must not be
+; grouped with a[iv].
+define void @cond_access_large_negative_offset(ptr %a, ptr %b, i64 %n, i64 %k) {
+; CHECK-LABEL: 'cond_access_large_negative_offset'
+; CHECK-NEXT: loop.header:
+; CHECK-NEXT: Memory dependences are safe with run-time checks
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+; CHECK-NEXT: Against group GRP1:
+; CHECK-NEXT: %gep.a.off = getelementptr i32, ptr %a, i64 %iv.off
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group GRP0:
+; CHECK-NEXT: (Low: %b High: ((4 * %n) + %b))
+; CHECK-NEXT: Member: {%b,+,4}<%loop.header>
+; CHECK-NEXT: Group GRP1:
+; CHECK-NEXT: (Low: (-4398046511104 + %a) High: ((4 * %n) + %a))
+; CHECK-NEXT: Member: {(-4398046511104 + %a),+,4}<%loop.header>
+; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop.header>
+; 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:
+ br label %loop.header
+
+loop.header:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ %l.a = load i32, ptr %gep.a, align 4
+ %c = icmp ult i64 %iv, %k
+ br i1 %c, label %loop.then, label %loop.latch
+
+loop.then:
+ %iv.off = add i64 %iv, -1099511627776
+ %gep.a.off = getelementptr i32, ptr %a, i64 %iv.off
+ %l.a.off = load i32, ptr %gep.a.off, align 4
+ br label %loop.latch
+
+loop.latch:
+ %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+ store i32 %l.a, ptr %gep.b, align 4
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %loop.header
+
+exit:
+ ret void
+}
+
+define void @cond_access_small_negative_offset(ptr %a, ptr %b, i64 %n, i64 %k) {
+; CHECK-LABEL: 'cond_access_small_negative_offset'
+; CHECK-NEXT: loop.header:
+; CHECK-NEXT: Memory dependences are safe with run-time checks
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+; CHECK-NEXT: Against group GRP1:
+; CHECK-NEXT: %gep.a.off = getelementptr i32, ptr %a, i64 %iv.off
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group GRP0:
+; CHECK-NEXT: (Low: %b High: ((4 * %n) + %b))
+; CHECK-NEXT: Member: {%b,+,4}<%loop.header>
+; CHECK-NEXT: Group GRP1:
+; CHECK-NEXT: (Low: (-4 + %a) High: ((4 * %n) + %a))
+; CHECK-NEXT: Member: {(-4 + %a),+,4}<%loop.header>
+; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop.header>
+; 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:
+ br label %loop.header
+
+loop.header:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ %l.a = load i32, ptr %gep.a, align 4
+ %c = icmp ult i64 %iv, %k
+ br i1 %c, label %loop.then, label %loop.latch
+
+loop.then:
+ %iv.off = add i64 %iv, -1
+ %gep.a.off = getelementptr i32, ptr %a, i64 %iv.off
+ %l.a.off = load i32, ptr %gep.a.off, align 4
+ br label %loop.latch
+
+loop.latch:
+ %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+ store i32 %l.a, ptr %gep.b, align 4
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %loop.header
+
+exit:
+ ret void
+}
+
+define void @uncond_accesses_large_negative_offset(ptr %a, ptr %b, i64 %n) {
+; CHECK-LABEL: 'uncond_accesses_large_negative_offset'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe with run-time checks
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+; CHECK-NEXT: Against group GRP1:
+; CHECK-NEXT: %gep.a.off = getelementptr i32, ptr %a, i64 %iv.off
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group GRP0:
+; CHECK-NEXT: (Low: %b High: ((4 * %n) + %b))
+; CHECK-NEXT: Member: {%b,+,4}<nuw><%loop>
+; CHECK-NEXT: Group GRP1:
+; CHECK-NEXT: (Low: (-4398046511104 + %a) High: ((4 * %n) + %a))
+; CHECK-NEXT: Member: {(-4398046511104 + %a),+,4}<%loop>
+; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop>
+; 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:
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ %l.a = load i32, ptr %gep.a, align 4
+ %iv.off = add i64 %iv, -1099511627776
+ %gep.a.off = getelementptr i32, ptr %a, i64 %iv.off
+ %l.a.off = load i32, ptr %gep.a.off, align 4
+ %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+ store i32 %l.a, ptr %gep.b, align 4
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+define void @cond_accesses_same_block_large_negative_offset(ptr %a, ptr %b, i64 %n, i64 %k) {
+; CHECK-LABEL: 'cond_accesses_same_block_large_negative_offset'
+; CHECK-NEXT: loop.header:
+; CHECK-NEXT: Memory dependences are safe with run-time checks
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+; CHECK-NEXT: Against group GRP1:
+; CHECK-NEXT: %gep.a.off = getelementptr i32, ptr %a, i64 %iv.off
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group GRP0:
+; CHECK-NEXT: (Low: %b High: ((4 * %n) + %b))
+; CHECK-NEXT: Member: {%b,+,4}<%loop.header>
+; CHECK-NEXT: Group GRP1:
+; CHECK-NEXT: (Low: (-4398046511104 + %a) High: ((4 * %n) + %a))
+; CHECK-NEXT: Member: {(-4398046511104 + %a),+,4}<%loop.header>
+; CHECK-NEXT: Member: {%a,+,4}<%loop.header>
+; 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:
+ br label %loop.header
+
+loop.header:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
+ %c = icmp ult i64 %iv, %k
+ br i1 %c, label %loop.then, label %loop.latch
+
+loop.then:
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ %l.a = load i32, ptr %gep.a, align 4
+ %iv.off = add i64 %iv, -1099511627776
+ %gep.a.off = getelementptr i32, ptr %a, i64 %iv.off
+ %l.a.off = load i32, ptr %gep.a.off, align 4
+ br label %loop.latch
+
+loop.latch:
+ %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+ store i32 0, ptr %gep.b, align 4
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %loop.header
+
+exit:
+ ret void
+}
+
+; a[iv] is also loaded unconditionally, so it must not be grouped with the
+; conditional store to a[iv - 2^40].
+define void @cond_store_same_block_uncond_load_large_negative_offset(ptr %a, ptr %b, i64 %n, i64 %k) {
+; CHECK-LABEL: 'cond_store_same_block_uncond_load_large_negative_offset'
+; CHECK-NEXT: loop.header:
+; CHECK-NEXT: Memory dependences are safe with run-time checks
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: Forward:
+; CHECK-NEXT: %l.a = load i32, ptr %gep.a, align 4 ->
+; CHECK-NEXT: store i32 1, ptr %gep.a.off, align 4
+; CHECK-EMPTY:
+; CHECK-NEXT: Forward:
+; CHECK-NEXT: store i32 0, ptr %gep.a, align 4 ->
+; CHECK-NEXT: store i32 1, ptr %gep.a.off, align 4
+; CHECK-EMPTY:
+; CHECK-NEXT: Forward:
+; CHECK-NEXT: %l.a = load i32, ptr %gep.a, align 4 ->
+; CHECK-NEXT: store i32 0, ptr %gep.a, align 4
+; CHECK-EMPTY:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+; CHECK-NEXT: Against group GRP1:
+; CHECK-NEXT: %gep.a.off = getelementptr i32, ptr %a, i64 %iv.off
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group GRP0:
+; CHECK-NEXT: (Low: %b High: ((4 * %n) + %b))
+; CHECK-NEXT: Member: {%b,+,4}<nuw><%loop.header>
+; CHECK-NEXT: Group GRP1:
+; CHECK-NEXT: (Low: (-4398046511104 + %a) High: ((4 * %n) + %a))
+; CHECK-NEXT: Member: {(-4398046511104 + %a),+,4}<%loop.header>
+; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop.header>
+; 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:
+ br label %loop.header
+
+loop.header:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ %l.a = load i32, ptr %gep.a, align 4
+ %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+ store i32 %l.a, ptr %gep.b, align 4
+ %c = icmp ult i64 %iv, %k
+ br i1 %c, label %loop.then, label %loop.latch
+
+loop.then:
+ store i32 0, ptr %gep.a, align 4
+ %iv.off = add i64 %iv, -1099511627776
+ %gep.a.off = getelementptr i32, ptr %a, i64 %iv.off
+ store i32 1, ptr %gep.a.off, align 4
+ br label %loop.latch
+
+loop.latch:
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %loop.header
+
+exit:
+ ret void
+}
+
+define void @uncond_accesses_invariant_and_addrec(ptr %a, ptr %b) {
+; CHECK-LABEL: 'uncond_accesses_invariant_and_addrec'
+; CHECK-NEXT: loop:
+; CHECK-NEXT: Memory dependences are safe with run-time checks
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+; CHECK-NEXT: Against group GRP1:
+; CHECK-NEXT: %gep.a.100 = getelementptr inbounds i32, ptr %a, i64 100
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group GRP0:
+; CHECK-NEXT: (Low: %b High: (400 + %b))
+; CHECK-NEXT: Member: {%b,+,4}<nuw><%loop>
+; CHECK-NEXT: Group GRP1:
+; CHECK-NEXT: (Low: %a High: (404 + %a))
+; CHECK-NEXT: Member: (400 + %a)<nuw>
+; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop>
+; 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:
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ %l.a = load i32, ptr %gep.a, align 4
+ %gep.a.100 = getelementptr inbounds i32, ptr %a, i64 100
+ %l.a.100 = load i32, ptr %gep.a.100, align 4
+ %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+ store i32 %l.a, ptr %gep.b, align 4
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, 100
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
+
+; The loop may exit before the load of a[iv - 2^40] in the first iteration.
+define void @uncond_accesses_large_negative_offset_early_exit(ptr %a, ptr %b, i64 %n, i64 %k) {
+; CHECK-LABEL: 'uncond_accesses_large_negative_offset_early_exit'
+; CHECK-NEXT: loop.header:
+; CHECK-NEXT: Memory dependences are safe with run-time checks
+; CHECK-NEXT: Dependences:
+; CHECK-NEXT: Run-time memory checks:
+; CHECK-NEXT: Check 0:
+; CHECK-NEXT: Comparing group GRP0:
+; CHECK-NEXT: %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+; CHECK-NEXT: Against group GRP1:
+; CHECK-NEXT: %gep.a.off = getelementptr i32, ptr %a, i64 %iv.off
+; CHECK-NEXT: %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+; CHECK-NEXT: Grouped accesses:
+; CHECK-NEXT: Group GRP0:
+; CHECK-NEXT: (Low: %b High: (4 + (4 * (%k umin_seq (-1 + %n))) + %b))
+; CHECK-NEXT: Member: {%b,+,4}<%loop.header>
+; CHECK-NEXT: Group GRP1:
+; CHECK-NEXT: (Low: (-4398046511104 + %a) High: (4 + (4 * (%k umin_seq (-1 + %n))) + %a))
+; CHECK-NEXT: Member: {(-4398046511104 + %a),+,4}<%loop.header>
+; CHECK-NEXT: Member: {%a,+,4}<nuw><%loop.header>
+; 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:
+ br label %loop.header
+
+loop.header:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
+ %gep.a = getelementptr inbounds i32, ptr %a, i64 %iv
+ %l.a = load i32, ptr %gep.a, align 4
+ %ec.early = icmp eq i64 %iv, %k
+ br i1 %ec.early, label %exit, label %loop.latch
+
+loop.latch:
+ %iv.off = add i64 %iv, -1099511627776
+ %gep.a.off = getelementptr i32, ptr %a, i64 %iv.off
+ %l.a.off = load i32, ptr %gep.a.off, align 4
+ %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+ store i32 %l.a, ptr %gep.b, align 4
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, %n
+ br i1 %ec, label %exit, label %loop.header
+
+exit:
+ ret void
+}
diff --git a/llvm/test/Transforms/LoopVectorize/interleaved-accesses-retry-runtime-checks.ll b/llvm/test/Transforms/LoopVectorize/interleaved-accesses-retry-runtime-checks.ll
new file mode 100644
index 0000000000000..0ccc743ecfb3c
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/interleaved-accesses-retry-runtime-checks.ll
@@ -0,0 +1,67 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals none --filter-out-after "^scalar.ph:" --version 6
+; RUN: opt -p loop-vectorize -enable-interleaved-mem-accesses -force-vector-width=4 -S %s | FileCheck %s
+
+define void @dep_between_interleaved_store_and_load_with_runtime_checks(ptr %a, ptr %b, i64 %off) {
+; CHECK-LABEL: define void @dep_between_interleaved_store_and_load_with_runtime_checks(
+; CHECK-SAME: ptr [[A:%.*]], ptr [[B:%.*]], i64 [[OFF:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[B_OFF:%.*]] = getelementptr i8, ptr [[B]], i64 [[OFF]]
+; CHECK-NEXT: br label %[[VECTOR_MEMCHECK:.*]]
+; CHECK: [[VECTOR_MEMCHECK]]:
+; CHECK-NEXT: [[TMP0:%.*]] = getelementptr i8, ptr [[A]], i64 800
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[B]], i64 400
+; CHECK-NEXT: [[TMP2:%.*]] = add i64 [[OFF]], 400
+; CHECK-NEXT: [[TMP3:%.*]] = getelementptr i8, ptr [[B]], i64 [[TMP2]]
+; CHECK-NEXT: [[BOUND0:%.*]] = icmp ult ptr [[A]], [[TMP1]]
+; CHECK-NEXT: [[BOUND1:%.*]] = icmp ult ptr [[B]], [[TMP0]]
+; CHECK-NEXT: [[FOUND_CONFLICT:%.*]] = and i1 [[BOUND0]], [[BOUND1]]
+; CHECK-NEXT: [[BOUND010:%.*]] = icmp ult ptr [[A]], [[TMP3]]
+; CHECK-NEXT: [[BOUND111:%.*]] = icmp ult ptr [[B_OFF]], [[TMP0]]
+; CHECK-NEXT: [[FOUND_CONFLICT12:%.*]] = and i1 [[BOUND010]], [[BOUND111]]
+; CHECK-NEXT: [[CONFLICT_RDX:%.*]] = or i1 [[FOUND_CONFLICT]], [[FOUND_CONFLICT12]]
+; CHECK-NEXT: [[BOUND013:%.*]] = icmp ult ptr [[B]], [[TMP3]]
+; CHECK-NEXT: [[BOUND114:%.*]] = icmp ult ptr [[B_OFF]], [[TMP1]]
+; CHECK-NEXT: [[FOUND_CONFLICT15:%.*]] = and i1 [[BOUND013]], [[BOUND114]]
+; CHECK-NEXT: [[CONFLICT_RDX16:%.*]] = or i1 [[CONFLICT_RDX]], [[FOUND_CONFLICT15]]
+; CHECK-NEXT: br i1 [[CONFLICT_RDX16]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
+; CHECK: [[VECTOR_PH]]:
+; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
+; CHECK: [[VECTOR_BODY]]:
+; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
+; CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds [2 x i32], ptr [[A]], i64 [[INDEX]]
+; CHECK-NEXT: [[WIDE_VEC:%.*]] = load <8 x i32>, ptr [[TMP4]], align 4, !alias.scope [[META0:![0-9]+]], !noalias [[META3:![0-9]+]]
+; CHECK-NEXT: [[STRIDED_VEC:%.*]] = shufflevector <8 x i32> [[WIDE_VEC]], <8 x i32> poison, <4 x i32> <i32 0, i32 2, i32 4, i32 6>
+; CHECK-NEXT: store <8 x i32> <i32 1, i32 3, i32 1, i32 3, i32 1, i32 3, i32 1, i32 3>, ptr [[TMP4]], align 4, !alias.scope [[META0]], !noalias [[META3]]
+; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[INDEX]]
+; CHECK-NEXT: store <4 x i32> [[STRIDED_VEC]], ptr [[TMP5]], align 4, !alias.scope [[META6:![0-9]+]], !noalias [[META7:![0-9]+]]
+; CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds i32, ptr [[B_OFF]], i64 [[INDEX]]
+; CHECK-NEXT: store <4 x i32> zeroinitializer, ptr [[TMP6]], align 4, !alias.scope [[META7]]
+; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 4
+; CHECK-NEXT: [[TMP7:%.*]] = icmp eq i64 [[INDEX_NEXT]], 96
+; CHECK-NEXT: br i1 [[TMP7]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP8:![0-9]+]]
+; CHECK: [[MIDDLE_BLOCK]]:
+; CHECK-NEXT: br label %[[SCALAR_PH]]
+; CHECK: [[SCALAR_PH]]:
+;
+entry:
+ %b.off = getelementptr i8, ptr %b, i64 %off
+ br label %loop
+
+loop:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
+ %gep.a.0 = getelementptr inbounds [2 x i32], ptr %a, i64 %iv
+ store i32 1, ptr %gep.a.0, align 4
+ %l.a.0 = load i32, ptr %gep.a.0, align 4
+ %gep.a.1 = getelementptr inbounds [2 x i32], ptr %a, i64 %iv, i64 1
+ store i32 3, ptr %gep.a.1, align 4
+ %gep.b = getelementptr inbounds i32, ptr %b, i64 %iv
+ store i32 %l.a.0, ptr %gep.b, align 4
+ %gep.b.off = getelementptr inbounds i32, ptr %b.off, i64 %iv
+ store i32 0, ptr %gep.b.off, align 4
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, 100
+ br i1 %ec, label %exit, label %loop
+
+exit:
+ ret void
+}
More information about the llvm-commits
mailing list