[llvm] 97ad26d - [LoopFlatten] Invalidate SCEV on each widening (#211819)

via llvm-commits llvm-commits at lists.llvm.org
Tue Sep 8 02:43:04 PDT 2026


Author: Arda Serdar Pektezol
Date: 2026-09-08T09:42:59Z
New Revision: 97ad26d9bfdb0c83bc6edc3de016fb7bc7b3d5b3

URL: https://github.com/llvm/llvm-project/commit/97ad26d9bfdb0c83bc6edc3de016fb7bc7b3d5b3
DIFF: https://github.com/llvm/llvm-project/commit/97ad26d9bfdb0c83bc6edc3de016fb7bc7b3d5b3.diff

LOG: [LoopFlatten] Invalidate SCEV on each widening (#211819)

LoopFlatten can update a loop before deciding on not to flatten it due
to profitability. SCEV has cached loop information during the checks and
the widening, where it can lead to stale data if the pass bails at
flattening. Invalidate it after each successful widening.

Fixes #203176

Co-authored-by: Steve Gustaman <stevegustaman at kaist.ac.kr>

Added: 
    llvm/test/Transforms/LoopFlatten/invalidate-scev-pr203176.ll

Modified: 
    llvm/lib/Transforms/Scalar/LoopFlatten.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/LoopFlatten.cpp b/llvm/lib/Transforms/Scalar/LoopFlatten.cpp
index 6d81fa935b491..d5c3a974ee675 100644
--- a/llvm/lib/Transforms/Scalar/LoopFlatten.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopFlatten.cpp
@@ -873,6 +873,7 @@ static bool CanWidenIV(FlattenInfo &FI, DominatorTree *DT, LoopInfo *LI,
                      true /* HasGuards */, true /* UsePostIncrementRanges */);
     if (!WidePhi)
       return false;
+    SE->forgetLoop(FI.OuterLoop);
     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
new file mode 100644
index 0000000000000..e80a811d98335
--- /dev/null
+++ b/llvm/test/Transforms/LoopFlatten/invalidate-scev-pr203176.ll
@@ -0,0 +1,96 @@
+; 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"
+
+ at g = global i32 0, align 4
+
+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: (-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
+; 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 @g, i32 %3
+; CHECK-NEXT:    --> {@g,+,(4 * (sext i32 {0,+,1}<%outer.loop> to i64))<nsw>}<nw><%mid.loop> U: [4,-7) S: [-9223372036854775808,9223372036854775805) Exits: {@g,+,(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> + {@g,+,(4 * (sext i32 {0,+,1}<%outer.loop> to i64))<nsw>}<nuw><nsw><%mid.loop>) U: [0,-3) S: [-9223372036854775808,9223372036854775805) Exits: {((4 * (sext i32 {-1,+,1}<%outer.loop> to i64))<nsw> + @g),+,(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: (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
+; 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 + (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
+; 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 @g, 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
+}


        


More information about the llvm-commits mailing list