[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