[llvm] [LoopUnroll] Invalidate SCEV after full unrolling (PR #208874)
via llvm-commits
llvm-commits at lists.llvm.org
Fri Jul 10 20:47:11 PDT 2026
https://github.com/Michael-Chen-NJU created https://github.com/llvm/llvm-project/pull/208874
Full unrolling may leave stale ScalarEvolution loop and disposition caches around the loop pass boundary. A later IndVars pass can then use stale exit count information and incorrectly fold reachable exits.
Invalidate SCEV loop and disposition caches after successful full unrolling before preserving `ScalarEvolutionAnalysis.`
Fixes #207744.
>From 4856df7f683e26bbc0a37edf3d0f87d5f0c024ca Mon Sep 17 00:00:00 2001
From: Michael-Chen-NJU <2802328816 at qq.com>
Date: Sat, 11 Jul 2026 11:39:44 +0800
Subject: [PATCH] [LoopUnroll] Invalidate SCEV after full unrolling
---
llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp | 4 +
.../full-unroll-scev-invalidation.ll | 92 +++++++++++++++++++
2 files changed, 96 insertions(+)
create mode 100644 llvm/test/Transforms/LoopUnroll/full-unroll-scev-invalidation.ll
diff --git a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
index 7034e595a4435..85f28193f3399 100644
--- a/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
+++ b/llvm/lib/Transforms/Scalar/LoopUnrollPass.cpp
@@ -1700,6 +1700,10 @@ PreservedAnalyses LoopFullUnrollPass::run(Loop &L, LoopAnalysisManager &AM,
if (!Changed)
return PreservedAnalyses::all();
+ // Full unrolling may leave stale SCEV loop and disposition caches.
+ AR.SE.forgetAllLoops();
+ AR.SE.forgetBlockAndLoopDispositions();
+
// The parent must not be damaged by unrolling!
#ifndef NDEBUG
if (ParentL)
diff --git a/llvm/test/Transforms/LoopUnroll/full-unroll-scev-invalidation.ll b/llvm/test/Transforms/LoopUnroll/full-unroll-scev-invalidation.ll
new file mode 100644
index 0000000000000..19da4bbe2482c
--- /dev/null
+++ b/llvm/test/Transforms/LoopUnroll/full-unroll-scev-invalidation.ll
@@ -0,0 +1,92 @@
+; RUN: opt -S -passes='loop(loop-idiom,indvars,loop-deletion,loop-unroll-full,loop-idiom,indvars),simplifycfg,instcombine' %s | FileCheck %s
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
+
+ at g0 = global i64 0, align 8
+ at g15 = global i64 0, align 8
+ at g14 = global i64 0, align 8
+ at g5 = global i64 0, align 8
+ at f4_c7 = global i8 0, align 1
+ at g8 = global i64 0, align 8
+ at f4_c15 = global i8 0, align 1
+ at f4_c8 = global i8 0, align 1
+ at __chk = global i64 0, align 8
+
+define void @f4() {
+; CHECK-LABEL: define void @f4(
+; CHECK: store i64 5, ptr @__chk
+entry:
+ %0 = load i64, ptr @g0, align 8
+ %cmp.not = icmp eq i64 %0, 908375363948206739
+ br i1 %cmp.not, label %if.end, label %if.then
+
+if.then:
+ store i64 1, ptr @g15, align 8
+ br label %if.end
+
+if.end:
+ %1 = load i64, ptr @g15, align 8
+ store i64 %1, ptr @g14, align 8
+ store i64 %1, ptr @g0, align 8
+ br label %lbl_b5
+
+lbl_b5:
+ %bb13.0 = phi i32 [ 0, %if.end ], [ %bb13.1.lcssa, %if.then8 ]
+ %ov6.0 = phi i1 [ false, %if.end ], [ true, %if.then8 ]
+ br label %lbl_b10
+
+lbl_b10:
+ %2 = phi i8 [ 0, %lbl_b5 ], [ 1, %lbl_b10 ]
+ %3 = phi i64 [ %1, %lbl_b5 ], [ 0, %lbl_b10 ]
+ %bb13.1 = phi i32 [ %bb13.0, %lbl_b5 ], [ %5, %lbl_b10 ]
+ %conv1 = trunc i64 %3 to i32
+ %4 = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 %conv1)
+ %5 = and i32 %4, 1
+ %loadedv = trunc nuw i8 %2 to i1
+ br i1 %loadedv, label %if.then3, label %lbl_b10
+
+if.then3:
+ %.lcssa38 = phi i8 [ %2, %lbl_b10 ]
+ %.lcssa36 = phi i64 [ %3, %lbl_b10 ]
+ %bb13.1.lcssa = phi i32 [ %bb13.1, %lbl_b10 ]
+ %.lcssa = phi i32 [ %5, %lbl_b10 ]
+ %tobool4.not = icmp eq i32 %bb13.1.lcssa, 0
+ br i1 %tobool4.not, label %cleanup.loopexit, label %if.then8
+
+if.then8:
+ br i1 %ov6.0, label %if.then10, label %lbl_b5
+
+if.then10:
+ %.lcssa38.lcssa39 = phi i8 [ %.lcssa38, %if.then8 ]
+ %.lcssa36.lcssa37 = phi i64 [ %.lcssa36, %if.then8 ]
+ %bb13.1.lcssa.lcssa35 = phi i32 [ %bb13.1.lcssa, %if.then8 ]
+ %.lcssa.lcssa34 = phi i32 [ %.lcssa, %if.then8 ]
+ %conv2.le.le = zext nneg i32 %.lcssa.lcssa34 to i64
+ %storedv5.le = trunc nuw i32 %bb13.1.lcssa.lcssa35 to i8
+ store i64 %.lcssa36.lcssa37, ptr @g5, align 8
+ store i8 %.lcssa38.lcssa39, ptr @f4_c7, align 1
+ store i64 %conv2.le.le, ptr @g8, align 8
+ store i8 1, ptr @f4_c15, align 1
+ store i8 %storedv5.le, ptr @f4_c8, align 1
+ store i64 5, ptr @__chk, align 8
+ br label %cleanup
+
+cleanup.loopexit:
+ %ov6.0.lcssa = phi i1 [ %ov6.0, %if.then3 ]
+ %.lcssa38.lcssa = phi i8 [ %.lcssa38, %if.then3 ]
+ %.lcssa36.lcssa = phi i64 [ %.lcssa36, %if.then3 ]
+ %.lcssa.lcssa = phi i32 [ %.lcssa, %if.then3 ]
+ %conv2.le.le32 = zext nneg i32 %.lcssa.lcssa to i64
+ %storedv.le30 = zext i1 %ov6.0.lcssa to i8
+ store i64 %.lcssa36.lcssa, ptr @g5, align 8
+ store i8 %.lcssa38.lcssa, ptr @f4_c7, align 1
+ store i64 %conv2.le.le32, ptr @g8, align 8
+ store i8 %storedv.le30, ptr @f4_c15, align 1
+ store i8 0, ptr @f4_c8, align 1
+ br label %cleanup
+
+cleanup:
+ ret void
+}
+
+declare i32 @llvm.ctpop.i32(i32)
More information about the llvm-commits
mailing list