[llvm] [LV] Reject outer loops without integer induction. (PR #228137)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Thu Oct 1 09:57:21 PDT 2026
https://github.com/fhahn created https://github.com/llvm/llvm-project/pull/228137
Bail out if we did not find any induction and WidestIndTy is null. Otherwise we would crash.
>From b81b058a44400e544bd8801634b9b49105e93a61 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 30 Sep 2026 14:04:41 +0100
Subject: [PATCH] [LV] Reject outer loops without an integer induction in
VPlan-native path
setupOuterLoopInductions succeeds trivially if the outer loop header has
no phis, leaving WidestIndTy null. The null type is then passed to
buildVPlan0, which crashes in ScalarEvolution::getTripCountFromExitCount.
Reject such loops, matching the inner-loop path, which requires at
least one integer induction.
---
.../Vectorize/LoopVectorizationLegality.cpp | 10 ++++
...plan-outer-loop-uncomputable-trip-count.ll | 55 ++++++++++++-------
2 files changed, 46 insertions(+), 19 deletions(-)
diff --git a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
index f486cde69c459..0fd5c875281a0 100644
--- a/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
+++ b/llvm/lib/Transforms/Vectorize/LoopVectorizationLegality.cpp
@@ -637,6 +637,16 @@ bool LoopVectorizationLegality::canVectorizeOuterLoop() {
return false;
}
+ // Like for inner loops, the widest integer induction type is used for the
+ // canonical IV and trip count, so at least one integer induction is required.
+ if (!WidestIndTy) {
+ reportVectorizationFailure(
+ "Did not find one integer induction var",
+ "loop induction variable could not be identified",
+ "NoInductionVariable", ORE, TheLoop);
+ return false;
+ }
+
return Result;
}
diff --git a/llvm/test/Transforms/LoopVectorize/vplan-outer-loop-uncomputable-trip-count.ll b/llvm/test/Transforms/LoopVectorize/vplan-outer-loop-uncomputable-trip-count.ll
index 358082968efe4..39f20c3dfa193 100644
--- a/llvm/test/Transforms/LoopVectorize/vplan-outer-loop-uncomputable-trip-count.ll
+++ b/llvm/test/Transforms/LoopVectorize/vplan-outer-loop-uncomputable-trip-count.ll
@@ -1,5 +1,4 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals none --version 6
-; RUN: opt -passes=loop-vectorize -enable-vplan-native-path -S %s | FileCheck %s
+; RUN: opt -passes=loop-vectorize -enable-vplan-native-path -pass-remarks=loop-vectorize -pass-remarks-analysis=loop-vectorize -disable-output --check-implicit-not='vectorized outer loop' %s 2>&1 | FileCheck %s
declare i1 @cond()
@@ -7,26 +6,13 @@ declare i1 @cond()
; trip-counts.
define void @test() {
-; CHECK-LABEL: define void @test() {
-; CHECK-NEXT: [[ENTRY:.*:]]
-; CHECK-NEXT: br label %[[FOR1_HEADER:.*]]
-; CHECK: [[FOR1_HEADER]]:
-; CHECK-NEXT: br label %[[FOR2_HEADER:.*]]
-; CHECK: [[FOR2_HEADER]]:
-; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ 0, %[[FOR1_HEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], %[[FOR2_HEADER]] ]
-; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1
-; CHECK-NEXT: [[EXITCOND:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], 0
-; CHECK-NEXT: br i1 [[EXITCOND]], label %[[FOR1_LATCH:.*]], label %[[FOR2_HEADER]]
-; CHECK: [[FOR1_LATCH]]:
-; CHECK-NEXT: [[C:%.*]] = call i1 @cond()
-; CHECK-NEXT: br i1 [[C]], label %[[EXIT:.*]], label %[[FOR1_HEADER]], !llvm.loop [[LOOP0:![0-9]+]]
-; CHECK: [[EXIT]]:
-; CHECK-NEXT: ret void
+; CHECK: remark: <unknown>:0:0: loop not vectorized: loop induction variable could not be identified
;
entry:
br label %outer.header
outer.header:
+ %outer.iv = phi i64 [ 0, %entry ], [ %outer.iv.next, %outer.latch ]
br label %inner
inner:
@@ -36,6 +22,7 @@ inner:
br i1 %inner.ec, label %outer.latch, label %inner
outer.latch:
+ %outer.iv.next = add nuw nsw i64 %outer.iv, 1
%c = call i1 @cond()
br i1 %c, label %exit, label %outer.header, !llvm.loop !0
@@ -43,5 +30,35 @@ exit:
ret void
}
-!0 = distinct !{!0, !1}
-!1 = !{!"llvm.loop.vectorize.enable"}
+; The outer loop has no induction phi, but a computable backedge-taken count
+; (0). It must be rejected like an inner loop without an integer induction,
+; as the widest induction type is used for the canonical IV and trip count.
+define void @outer_loop_without_induction(ptr %p) {
+; CHECK: remark: <unknown>:0:0: loop not vectorized: Unsupported outer loop
+;
+entry:
+ br label %outer.header
+
+outer.header:
+ br label %inner
+
+inner:
+ %iv = phi i64 [ 0, %outer.header ], [ %iv.next, %inner ]
+ %gep = getelementptr inbounds i32, ptr %p, i64 %iv
+ store i32 0, ptr %gep, align 4
+ %iv.next = add nuw nsw i64 %iv, 1
+ %ec = icmp eq i64 %iv.next, 8
+ br i1 %ec, label %outer.latch, label %inner
+
+outer.latch:
+ %outer.ec = icmp eq i64 %iv.next, 8
+ br i1 %outer.ec, label %exit, label %outer.header, !llvm.loop !1
+
+exit:
+ ret void
+}
+
+!0 = distinct !{!0, !2}
+!1 = distinct !{!1, !2, !3}
+!2 = !{!"llvm.loop.vectorize.enable"}
+!3 = !{!"llvm.loop.vectorize.width", i32 4}
More information about the llvm-commits
mailing list