[llvm] [LoopVectorize] Add tests for reverse early-exit loops in deref regions (PR #228062)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 1 05:52:44 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Aleksandr Popov (aleks-tmb)
<details>
<summary>Changes</summary>
Related to #<!-- -->211962
---
Full diff: https://github.com/llvm/llvm-project/pull/228062.diff
1 Files Affected:
- (added) llvm/test/Transforms/LoopVectorize/reverse-loop-length.ll (+96)
``````````diff
diff --git a/llvm/test/Transforms/LoopVectorize/reverse-loop-length.ll b/llvm/test/Transforms/LoopVectorize/reverse-loop-length.ll
new file mode 100644
index 0000000000000..fba1918ab65c9
--- /dev/null
+++ b/llvm/test/Transforms/LoopVectorize/reverse-loop-length.ll
@@ -0,0 +1,96 @@
+; 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 -force-vector-width=4 -S %s | FileCheck %s
+
+; TODO: LAA should recognise that the AR fits within the deref region
+; and produce tight bounds, allowing the early-exit loop to be vectorized
+; without runtime memory checks.
+define ptr @reverse_reaches_base_dynamic_length(i64 %length, ptr %ptr) {
+; CHECK-LABEL: define ptr @reverse_reaches_base_dynamic_length(
+; CHECK-SAME: i64 [[LENGTH:%.*]], ptr [[PTR:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*:]]
+; CHECK-NEXT: [[NULL_CHECK:%.*]] = icmp eq i64 [[LENGTH]], 0
+; CHECK-NEXT: br i1 [[NULL_CHECK]], label %[[EXIT:.*]], label %[[PREHEADER:.*]]
+; CHECK: [[PREHEADER]]:
+; CHECK-NEXT: call void @llvm.assume(i1 true) [ "dereferenceable"(ptr [[PTR]], i64 [[LENGTH]]) ]
+; CHECK-NEXT: [[START:%.*]] = sub i64 [[LENGTH]], 1
+; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
+; CHECK: [[VECTOR_BODY]]:
+; CHECK-NEXT: [[TMP1:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[VECTOR_BODY_INTERIM:.*]] ], [ [[START]], %[[PREHEADER]] ]
+; CHECK-NEXT: [[TMP2:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[TMP1]]
+; CHECK-NEXT: [[ELEMENT:%.*]] = load i8, ptr [[TMP2]], align 1
+; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i8 [[ELEMENT]], 0
+; CHECK-NEXT: br i1 [[TMP6]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM]]
+; CHECK: [[VECTOR_BODY_INTERIM]]:
+; CHECK-NEXT: [[IV_NEXT]] = add i64 [[TMP1]], -1
+; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ne i64 [[TMP1]], 0
+; CHECK-NEXT: br i1 [[RANGE_CHECK]], label %[[VECTOR_BODY]], label %[[VECTOR_EARLY_EXIT]]
+; CHECK: [[VECTOR_EARLY_EXIT]]:
+; CHECK-NEXT: br label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret ptr null
+;
+entry:
+ %null_check = icmp eq i64 %length, 0
+ br i1 %null_check, label %exit, label %preheader
+
+preheader:
+ call void @llvm.assume(i1 true) [ "dereferenceable"(ptr %ptr, i64 %length) ]
+ %start = sub i64 %length, 1
+ br label %loop
+
+loop:
+ %iv = phi i64 [ %iv.next, %latch ], [ %start, %preheader ]
+ %element_gep = getelementptr i8, ptr %ptr, i64 %iv
+ %element = load i8, ptr %element_gep, align 1
+ %found_check = icmp eq i8 %element, 0
+ br i1 %found_check, label %exit, label %latch
+
+latch:
+ %iv.next = add i64 %iv, -1
+ %range_check = icmp ne i64 %iv, 0
+ br i1 %range_check, label %loop, label %exit
+
+exit:
+ ret ptr null
+}
+
+; TODO: The last iteration of the reverse loop lands exactly on %ptr, so the
+; accessed range [0, 16) exactly fills the dereferenceable region. LAA should
+; produce tight bounds, allowing the early-exit loop to be vectorized without
+; runtime memory checks.
+define ptr @reverse_reaches_base_static_length(ptr dereferenceable(16) %ptr) {
+; CHECK-LABEL: define ptr @reverse_reaches_base_static_length(
+; CHECK-SAME: ptr dereferenceable(16) [[PTR:%.*]]) {
+; CHECK-NEXT: [[VECTOR_PH:.*]]:
+; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
+; CHECK: [[VECTOR_BODY]]:
+; CHECK-NEXT: [[TMP0:%.*]] = phi i64 [ [[IV_NEXT:%.*]], %[[VECTOR_BODY_INTERIM:.*]] ], [ 15, %[[VECTOR_PH]] ]
+; CHECK-NEXT: [[TMP1:%.*]] = getelementptr i8, ptr [[PTR]], i64 [[TMP0]]
+; CHECK-NEXT: [[ELEMENT:%.*]] = load i8, ptr [[TMP1]], align 1
+; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i8 [[ELEMENT]], 0
+; CHECK-NEXT: br i1 [[TMP5]], label %[[VECTOR_EARLY_EXIT:.*]], label %[[VECTOR_BODY_INTERIM]]
+; CHECK: [[VECTOR_BODY_INTERIM]]:
+; CHECK-NEXT: [[IV_NEXT]] = add i64 [[TMP0]], -1
+; CHECK-NEXT: [[RANGE_CHECK:%.*]] = icmp ne i64 [[TMP0]], 0
+; CHECK-NEXT: br i1 [[RANGE_CHECK]], label %[[VECTOR_BODY]], label %[[VECTOR_EARLY_EXIT]]
+; CHECK: [[VECTOR_EARLY_EXIT]]:
+; CHECK-NEXT: ret ptr null
+;
+entry:
+ br label %loop
+
+loop:
+ %iv = phi i64 [ %iv.next, %latch ], [ 15, %entry ]
+ %element_gep = getelementptr i8, ptr %ptr, i64 %iv
+ %element = load i8, ptr %element_gep, align 1
+ %found_check = icmp eq i8 %element, 0
+ br i1 %found_check, label %exit, label %latch
+
+latch:
+ %iv.next = add i64 %iv, -1
+ %range_check = icmp ne i64 %iv, 0
+ br i1 %range_check, label %loop, label %exit
+
+exit:
+ ret ptr null
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/228062
More information about the llvm-commits
mailing list