[llvm] [LoopFlatten] Invalidate SCEV on each widening (PR #211819)
Arda Serdar Pektezol via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 24 23:53:54 PDT 2026
https://github.com/pektezol updated https://github.com/llvm/llvm-project/pull/211819
>From cfc89366017a30619836a940ed804d4dfea0c49f Mon Sep 17 00:00:00 2001
From: Arda Serdar Pektezol <arda at pektezol.dev>
Date: Tue, 25 Aug 2026 00:35:38 +0300
Subject: [PATCH 1/2] baseline test
---
.../LoopFlatten/invalidate-scev-pr203176.ll | 94 +++++++++++++++++++
1 file changed, 94 insertions(+)
create mode 100644 llvm/test/Transforms/LoopFlatten/invalidate-scev-pr203176.ll
diff --git a/llvm/test/Transforms/LoopFlatten/invalidate-scev-pr203176.ll b/llvm/test/Transforms/LoopFlatten/invalidate-scev-pr203176.ll
new file mode 100644
index 0000000000000..83bce7418438b
--- /dev/null
+++ b/llvm/test/Transforms/LoopFlatten/invalidate-scev-pr203176.ll
@@ -0,0 +1,94 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes='loop(loop-flatten),print<scalar-evolution>' -disable-output 2>&1 | FileCheck %s
+
+target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
+
+define i64 @f(i64 %n) {
+; CHECK-LABEL: 'f'
+; CHECK-NEXT: Classifying expressions for: @f
+; CHECK-NEXT: %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
+; CHECK-NEXT: --> {0,+,1}<nuw><%outer.loop> U: full-set S: full-set Exits: %n LoopDispositions: { %outer.loop: Computable, %mid.loop: Invariant, %inner.loop: Invariant }
+; CHECK-NEXT: %tc = trunc i64 %i to i32
+; CHECK-NEXT: --> {0,+,1}<%outer.loop> U: full-set S: full-set Exits: (trunc i64 %n to i32) LoopDispositions: { %outer.loop: Computable, %mid.loop: Invariant, %inner.loop: Invariant }
+; CHECK-NEXT: %0 = zext i32 %tc to i64
+; CHECK-NEXT: --> (zext i32 {0,+,1}<%outer.loop> to i64) U: [0,4294967296) S: [0,4294967296) Exits: (zext i32 (trunc i64 %n to i32) to i64) LoopDispositions: { %outer.loop: Computable, %mid.loop: Invariant, %inner.loop: Invariant }
+; CHECK-NEXT: %1 = sext i32 %tc to i64
+; CHECK-NEXT: --> (sext i32 {0,+,1}<%outer.loop> to i64) U: [-2147483648,2147483648) S: [-2147483648,2147483648) Exits: (sext i32 (trunc i64 %n to i32) to i64) LoopDispositions: { %outer.loop: Computable, %mid.loop: Invariant, %inner.loop: Invariant }
+; CHECK-NEXT: %indvar1 = phi i64 [ 0, %mid.loop.preheader ], [ %indvar.next2, %mid.latch ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%mid.loop> U: [0,1) S: [0,1) Exits: 0 LoopDispositions: { %mid.loop: Computable, %outer.loop: Uniform, %inner.loop: Invariant }
+; CHECK-NEXT: %k = phi i32 [ %k.next, %mid.latch ], [ 0, %mid.loop.preheader ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%mid.loop> U: [0,1) S: [0,1) Exits: 0 LoopDispositions: { %mid.loop: Computable, %outer.loop: Uniform, %inner.loop: Invariant }
+; CHECK-NEXT: %indvar = phi i64 [ %indvar.next, %inner.loop ], [ 0, %mid.loop ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%inner.loop> U: [0,4294967295) S: [0,4294967295) Exits: (zext i32 {-1,+,1}<%outer.loop> to i64) LoopDispositions: { %inner.loop: Computable, %mid.loop: Uniform, %outer.loop: Uniform }
+; CHECK-NEXT: %2 = mul i64 %indvar1, %1
+; CHECK-NEXT: --> {0,+,(sext i32 {0,+,1}<%outer.loop> to i64)}<nsw><%mid.loop> U: [0,1) S: [0,1) Exits: {0,+,(sext i32 {0,+,1}<%outer.loop> to i64)}<nuw><nsw><%mid.loop> LoopDispositions: { %inner.loop: Invariant, %mid.loop: Computable, %outer.loop: Variant }
+; CHECK-NEXT: %mul = mul i32 %k, %tc
+; CHECK-NEXT: --> {0,+,{0,+,1}<%outer.loop>}<nsw><%mid.loop> U: [0,1) S: [0,1) Exits: {0,+,{0,+,1}<%outer.loop>}<nuw><nsw><%mid.loop> LoopDispositions: { %inner.loop: Invariant, %mid.loop: Computable, %outer.loop: Variant }
+; CHECK-NEXT: %3 = trunc nuw nsw i64 %2 to i32
+; CHECK-NEXT: --> {0,+,{0,+,1}<%outer.loop>}<nuw><nsw><%mid.loop> U: [0,1) S: [0,1) Exits: {0,+,{0,+,1}<%outer.loop>}<nuw><nsw><%mid.loop> LoopDispositions: { %inner.loop: Invariant, %mid.loop: Computable, %outer.loop: Variant }
+; CHECK-NEXT: %gep = getelementptr i32, ptr null, i32 %3
+; CHECK-NEXT: --> {null,+,(4 * (sext i32 {0,+,1}<%outer.loop> to i64))<nsw>}<nw><%mid.loop> U: [0,1) S: [0,1) Exits: {null,+,(4 * (sext i32 {0,+,1}<%outer.loop> to i64))<nsw>}<nuw><nsw><%mid.loop> LoopDispositions: { %inner.loop: Invariant, %mid.loop: Computable, %outer.loop: Variant }
+; CHECK-NEXT: %4 = trunc nuw i64 %indvar to i32
+; CHECK-NEXT: --> {0,+,1}<nuw><%inner.loop> U: [0,-1) S: [0,-1) Exits: {-1,+,1}<%outer.loop> LoopDispositions: { %inner.loop: Computable, %mid.loop: Uniform, %outer.loop: Uniform }
+; CHECK-NEXT: %arrayidx = getelementptr i32, ptr %gep, i32 %4
+; CHECK-NEXT: --> ((4 * (sext i32 {0,+,1}<nuw><%inner.loop> to i64))<nsw> + {null,+,(4 * (sext i32 {0,+,1}<%outer.loop> to i64))<nsw>}<nuw><nsw><%mid.loop>) U: [0,-3) S: [-8589934592,8589934589) Exits: {((4 * (sext i32 {-1,+,1}<%outer.loop> to i64))<nsw> + null),+,(4 * (sext i32 {0,+,1}<%outer.loop> to i64))<nsw>}<nw><%mid.loop> LoopDispositions: { %inner.loop: Computable, %mid.loop: Variant, %outer.loop: Variant }
+; CHECK-NEXT: %indvar.next = add i64 %indvar, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%inner.loop> U: [1,4294967296) S: [1,4294967296) Exits: (1 + (zext i32 {-1,+,1}<%outer.loop> to i64))<nuw><nsw> LoopDispositions: { %inner.loop: Computable, %mid.loop: Uniform, %outer.loop: Uniform }
+; CHECK-NEXT: %indvar.next2 = add i64 %indvar1, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%mid.loop> U: [1,2) S: [1,2) Exits: 1 LoopDispositions: { %mid.loop: Computable, %outer.loop: Uniform, %inner.loop: Invariant }
+; CHECK-NEXT: %k.next = add i32 %k, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%mid.loop> U: [1,2) S: [1,2) Exits: 1 LoopDispositions: { %mid.loop: Computable, %outer.loop: Uniform, %inner.loop: Invariant }
+; CHECK-NEXT: %i.next = add i64 %i, 1
+; CHECK-NEXT: --> {1,+,1}<nw><%outer.loop> U: full-set S: full-set Exits: (1 + %n) LoopDispositions: { %outer.loop: Computable, %mid.loop: Invariant, %inner.loop: Invariant }
+; CHECK-NEXT: Determining loop execution counts for: @f
+; CHECK-NEXT: Loop %inner.loop: backedge-taken count is {-1,+,1}<%outer.loop>
+; CHECK-NEXT: Loop %inner.loop: constant max backedge-taken count is i32 -2
+; CHECK-NEXT: Loop %inner.loop: symbolic max backedge-taken count is {-1,+,1}<%outer.loop>
+; CHECK-NEXT: Loop %inner.loop: Trip multiple is 1
+; CHECK-NEXT: Loop %mid.loop: backedge-taken count is i1 false
+; CHECK-NEXT: Loop %mid.loop: constant max backedge-taken count is i1 false
+; CHECK-NEXT: Loop %mid.loop: symbolic max backedge-taken count is i1 false
+; CHECK-NEXT: Loop %mid.loop: Trip multiple is 1
+; CHECK-NEXT: Loop %outer.loop: backedge-taken count is %n
+; CHECK-NEXT: Loop %outer.loop: constant max backedge-taken count is i64 -1
+; CHECK-NEXT: Loop %outer.loop: symbolic max backedge-taken count is %n
+; CHECK-NEXT: Loop %outer.loop: Trip multiple is 1
+;
+entry:
+ br label %outer.loop
+
+outer.loop: ; preds = %outer.latch, %entry
+ %i = phi i64 [ 0, %entry ], [ %i.next, %outer.latch ]
+ %outer.cond = icmp ult i64 %i, %n
+ br i1 %outer.cond, label %outer.body, label %exit
+
+outer.body: ; preds = %outer.loop
+ %tc = trunc i64 %i to i32
+ br i1 false, label %mid.loop, label %outer.latch
+
+mid.loop: ; preds = %mid.latch, %outer.body
+ %k = phi i32 [ %k.next, %mid.latch ], [ 0, %outer.body ]
+ br label %inner.loop
+
+inner.loop: ; preds = %inner.loop, %mid.loop
+ %j = phi i32 [ 0, %mid.loop ], [ %j.next, %inner.loop ]
+ %mul = mul i32 %k, %tc
+ %gep = getelementptr i32, ptr null, i32 %mul
+ %arrayidx = getelementptr i32, ptr %gep, i32 %j
+ store i32 0, ptr %gep, align 4
+ %j.next = add i32 %j, 1
+ %inner.cond = icmp ult i32 %j.next, %tc
+ br i1 %inner.cond, label %inner.loop, label %mid.latch
+
+mid.latch: ; preds = %inner.loop
+ %k.next = add i32 %k, 1
+ %mid.cond = icmp ult i32 %k.next, 0
+ br i1 %mid.cond, label %mid.loop, label %outer.latch
+
+outer.latch: ; preds = %mid.latch, %outer.body
+ %i.next = add i64 %i, 1
+ br label %outer.loop
+
+exit: ; preds = %outer.loop
+ ret i64 0
+}
>From 6bf1e613cb622f3735fb5fb18f463cac632b2b57 Mon Sep 17 00:00:00 2001
From: Arda Serdar Pektezol <arda at pektezol.dev>
Date: Tue, 25 Aug 2026 00:37:53 +0300
Subject: [PATCH 2/2] invalidate scev
---
llvm/lib/Transforms/Scalar/LoopFlatten.cpp | 2 ++
.../Transforms/LoopFlatten/invalidate-scev-pr203176.ll | 10 +++++-----
2 files changed, 7 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/LoopFlatten.cpp b/llvm/lib/Transforms/Scalar/LoopFlatten.cpp
index e48c47f1b4b89..7a6a8ce48cebd 100644
--- a/llvm/lib/Transforms/Scalar/LoopFlatten.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopFlatten.cpp
@@ -873,6 +873,8 @@ static bool CanWidenIV(FlattenInfo &FI, DominatorTree *DT, LoopInfo *LI,
true /* HasGuards */, true /* UsePostIncrementRanges */);
if (!WidePhi)
return false;
+ SE->forgetLoop(FI.OuterLoop);
+ SE->forgetBlockAndLoopDispositions();
LLVM_DEBUG(dbgs() << "Created wide phi: "; WidePhi->dump());
LLVM_DEBUG(dbgs() << "Deleting old phi: "; WideIV.NarrowIV->dump());
Deleted = RecursivelyDeleteDeadPHINode(WideIV.NarrowIV);
diff --git a/llvm/test/Transforms/LoopFlatten/invalidate-scev-pr203176.ll b/llvm/test/Transforms/LoopFlatten/invalidate-scev-pr203176.ll
index 83bce7418438b..293bd491a5a8d 100644
--- a/llvm/test/Transforms/LoopFlatten/invalidate-scev-pr203176.ll
+++ b/llvm/test/Transforms/LoopFlatten/invalidate-scev-pr203176.ll
@@ -19,7 +19,7 @@ define i64 @f(i64 %n) {
; CHECK-NEXT: %k = phi i32 [ %k.next, %mid.latch ], [ 0, %mid.loop.preheader ]
; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%mid.loop> U: [0,1) S: [0,1) Exits: 0 LoopDispositions: { %mid.loop: Computable, %outer.loop: Uniform, %inner.loop: Invariant }
; CHECK-NEXT: %indvar = phi i64 [ %indvar.next, %inner.loop ], [ 0, %mid.loop ]
-; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%inner.loop> U: [0,4294967295) S: [0,4294967295) Exits: (zext i32 {-1,+,1}<%outer.loop> to i64) LoopDispositions: { %inner.loop: Computable, %mid.loop: Uniform, %outer.loop: Uniform }
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%inner.loop> U: [0,4294967295) S: [0,4294967295) Exits: (-1 + (zext i32 {0,+,1}<%outer.loop> to i64))<nsw> LoopDispositions: { %inner.loop: Computable, %mid.loop: Uniform, %outer.loop: Uniform }
; CHECK-NEXT: %2 = mul i64 %indvar1, %1
; CHECK-NEXT: --> {0,+,(sext i32 {0,+,1}<%outer.loop> to i64)}<nsw><%mid.loop> U: [0,1) S: [0,1) Exits: {0,+,(sext i32 {0,+,1}<%outer.loop> to i64)}<nuw><nsw><%mid.loop> LoopDispositions: { %inner.loop: Invariant, %mid.loop: Computable, %outer.loop: Variant }
; CHECK-NEXT: %mul = mul i32 %k, %tc
@@ -33,7 +33,7 @@ define i64 @f(i64 %n) {
; CHECK-NEXT: %arrayidx = getelementptr i32, ptr %gep, i32 %4
; CHECK-NEXT: --> ((4 * (sext i32 {0,+,1}<nuw><%inner.loop> to i64))<nsw> + {null,+,(4 * (sext i32 {0,+,1}<%outer.loop> to i64))<nsw>}<nuw><nsw><%mid.loop>) U: [0,-3) S: [-8589934592,8589934589) Exits: {((4 * (sext i32 {-1,+,1}<%outer.loop> to i64))<nsw> + null),+,(4 * (sext i32 {0,+,1}<%outer.loop> to i64))<nsw>}<nw><%mid.loop> LoopDispositions: { %inner.loop: Computable, %mid.loop: Variant, %outer.loop: Variant }
; CHECK-NEXT: %indvar.next = add i64 %indvar, 1
-; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%inner.loop> U: [1,4294967296) S: [1,4294967296) Exits: (1 + (zext i32 {-1,+,1}<%outer.loop> to i64))<nuw><nsw> LoopDispositions: { %inner.loop: Computable, %mid.loop: Uniform, %outer.loop: Uniform }
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%inner.loop> U: [1,4294967296) S: [1,4294967296) Exits: (zext i32 {0,+,1}<%outer.loop> to i64) LoopDispositions: { %inner.loop: Computable, %mid.loop: Uniform, %outer.loop: Uniform }
; CHECK-NEXT: %indvar.next2 = add i64 %indvar1, 1
; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%mid.loop> U: [1,2) S: [1,2) Exits: 1 LoopDispositions: { %mid.loop: Computable, %outer.loop: Uniform, %inner.loop: Invariant }
; CHECK-NEXT: %k.next = add i32 %k, 1
@@ -41,9 +41,9 @@ define i64 @f(i64 %n) {
; CHECK-NEXT: %i.next = add i64 %i, 1
; CHECK-NEXT: --> {1,+,1}<nw><%outer.loop> U: full-set S: full-set Exits: (1 + %n) LoopDispositions: { %outer.loop: Computable, %mid.loop: Invariant, %inner.loop: Invariant }
; CHECK-NEXT: Determining loop execution counts for: @f
-; CHECK-NEXT: Loop %inner.loop: backedge-taken count is {-1,+,1}<%outer.loop>
-; CHECK-NEXT: Loop %inner.loop: constant max backedge-taken count is i32 -2
-; CHECK-NEXT: Loop %inner.loop: symbolic max backedge-taken count is {-1,+,1}<%outer.loop>
+; CHECK-NEXT: Loop %inner.loop: backedge-taken count is (-1 + (zext i32 {0,+,1}<%outer.loop> to i64))<nsw>
+; CHECK-NEXT: Loop %inner.loop: constant max backedge-taken count is i64 4294967294
+; CHECK-NEXT: Loop %inner.loop: symbolic max backedge-taken count is (-1 + (zext i32 {0,+,1}<%outer.loop> to i64))<nsw>
; CHECK-NEXT: Loop %inner.loop: Trip multiple is 1
; CHECK-NEXT: Loop %mid.loop: backedge-taken count is i1 false
; CHECK-NEXT: Loop %mid.loop: constant max backedge-taken count is i1 false
More information about the llvm-commits
mailing list