[llvm] [SCEV] Fold zext(C+A)<nsw> -> (sext(C) + zext(A))<nsw> if possible. (PR #142599)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Fri May 22 06:50:46 PDT 2026
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/142599
>From 0de583c986b6e859480d15eb94df242d5627f39a Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 3 Jun 2025 10:38:19 +0100
Subject: [PATCH 1/6] [SCEV] Fold zext(C+A)<nsw> -> (sext(C) + zext(A))<nsw> if
possible.
Simplify zext(C+A)<nsw> -> (sext(C) + zext(A))<nsw> if
* zext (C + A)<nsw> >=s 0 and
* A >=s V.
For now this is limited to cases where the first operand is a constant,
so the SExt can be folded to a new constant. This can be relaxed in the
future.
Alive2 proof of the general pattern and the test changes in zext-nuw.ll
(times out in the online instance but verifies locally)
https://alive2.llvm.org/ce/z/_BtyGy
---
llvm/lib/Analysis/ScalarEvolution.cpp | 12 +++++++++++
.../max-backedge-taken-count-guard-info.ll | 2 +-
.../Transforms/LoopVectorize/reduction.ll | 20 +++++++++----------
3 files changed, 23 insertions(+), 11 deletions(-)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 6dbcd82744f8b..cb101159954af 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -1910,6 +1910,18 @@ const SCEV *ScalarEvolution::getZeroExtendExprImpl(const SCEV *Op, Type *Ty,
return getAddExpr(Ops, SCEV::FlagNUW, Depth + 1);
}
+ const SCEVConstant *C;
+ const SCEV *A;
+ // zext (C + A)<nsw> -> (sext(C) + zext(A))<nsw> if zext (C + A)<nsw> >=s 0
+ // and A >=s V.
+ if (SA->hasNoSignedWrap() && isKnownNonNegative(SA) &&
+ match(SA, m_scev_Add(m_SCEVConstant(C), m_SCEV(A))) &&
+ isKnownPredicate(CmpInst::ICMP_SGE, A, C)) {
+ SmallVector<const SCEV *, 4> Ops = {getSignExtendExpr(C, Ty, Depth + 1),
+ getZeroExtendExpr(A, Ty, Depth + 1)};
+ return getAddExpr(Ops, SCEV::FlagNSW, Depth + 1);
+ }
+
// zext(C + x + y + ...) --> (zext(D) + zext((C - D) + x + y + ...))
// if D + (C - D + x + y + ...) could be proven to not unsigned wrap
// where D maximizes the number of trailing zeros of (C - D + x + y + ...)
diff --git a/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll b/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll
index 436f0e55840d9..449dbab51f325 100644
--- a/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll
+++ b/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll
@@ -1231,7 +1231,7 @@ define void @optimized_range_check_unsigned3(ptr %pred, i1 %c) {
; CHECK-NEXT: %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,3) S: [0,3) Exits: (-1 + %N)<nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %gep = getelementptr inbounds i16, ptr %pred, i32 %iv
-; CHECK-NEXT: --> {%pred,+,2}<nuw><%loop> U: full-set S: full-set Exits: ((zext i32 (-2 + (2 * %N)<nuw><nsw>)<nsw> to i64) + %pred) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {%pred,+,2}<nuw><%loop> U: full-set S: full-set Exits: (-2 + (2 * (zext i32 %N to i64))<nuw><nsw> + %pred) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.next = add nuw nsw i32 %iv, 1
; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,4) S: [1,4) Exits: %N LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @optimized_range_check_unsigned3
diff --git a/llvm/test/Transforms/LoopVectorize/reduction.ll b/llvm/test/Transforms/LoopVectorize/reduction.ll
index 5803585e7a787..c683ef897715a 100644
--- a/llvm/test/Transforms/LoopVectorize/reduction.ll
+++ b/llvm/test/Transforms/LoopVectorize/reduction.ll
@@ -1184,13 +1184,13 @@ define i64 @reduction_with_phi_with_one_incoming_on_backedge(i16 %n, ptr %A) {
; CHECK-SAME: i16 [[N:%.*]], ptr [[A:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SMAX:%.*]] = call i16 @llvm.smax.i16(i16 [[N]], i16 2)
-; CHECK-NEXT: [[TMP0:%.*]] = add nsw i16 [[SMAX]], -1
-; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i16 [[TMP0]] to i32
+; CHECK-NEXT: [[TMP0:%.*]] = zext nneg i16 [[SMAX]] to i32
+; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[TMP0]], -1
; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp slt i16 [[N]], 5
; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label [[SCALAR_PH:%.*]], label [[VECTOR_PH:%.*]]
; CHECK: vector.ph:
-; CHECK-NEXT: [[N_VEC:%.*]] = and i32 [[TMP1]], 32764
-; CHECK-NEXT: [[DOTCAST:%.*]] = trunc nuw nsw i32 [[N_VEC]] to i16
+; CHECK-NEXT: [[N_VEC:%.*]] = and i32 [[TMP1]], -4
+; CHECK-NEXT: [[DOTCAST:%.*]] = trunc nsw i32 [[N_VEC]] to i16
; CHECK-NEXT: [[IND_END:%.*]] = or disjoint i16 [[DOTCAST]], 1
; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
; CHECK: vector.body:
@@ -1207,7 +1207,7 @@ define i64 @reduction_with_phi_with_one_incoming_on_backedge(i16 %n, ptr %A) {
; CHECK-NEXT: br i1 [[TMP5]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP23:![0-9]+]]
; CHECK: middle.block:
; CHECK-NEXT: [[TMP6:%.*]] = call i64 @llvm.vector.reduce.add.v4i64(<4 x i64> [[TMP4]])
-; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i32 [[N_VEC]], [[TMP1]]
+; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i32 [[TMP1]], [[N_VEC]]
; CHECK-NEXT: br i1 [[CMP_N]], label [[EXIT:%.*]], label [[SCALAR_PH]]
; CHECK: scalar.ph:
; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i16 [ [[IND_END]], [[MIDDLE_BLOCK]] ], [ 1, [[ENTRY:%.*]] ]
@@ -1262,13 +1262,13 @@ define i64 @reduction_with_phi_with_two_incoming_on_backedge(i16 %n, ptr %A) {
; CHECK-SAME: i16 [[N:%.*]], ptr [[A:%.*]]) {
; CHECK-NEXT: entry:
; CHECK-NEXT: [[SMAX:%.*]] = call i16 @llvm.smax.i16(i16 [[N]], i16 2)
-; CHECK-NEXT: [[TMP0:%.*]] = add nsw i16 [[SMAX]], -1
-; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i16 [[TMP0]] to i32
+; CHECK-NEXT: [[TMP0:%.*]] = zext nneg i16 [[SMAX]] to i32
+; CHECK-NEXT: [[TMP1:%.*]] = add nsw i32 [[TMP0]], -1
; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp slt i16 [[N]], 5
; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label [[SCALAR_PH:%.*]], label [[VECTOR_PH:%.*]]
; CHECK: vector.ph:
-; CHECK-NEXT: [[N_VEC:%.*]] = and i32 [[TMP1]], 32764
-; CHECK-NEXT: [[DOTCAST:%.*]] = trunc nuw nsw i32 [[N_VEC]] to i16
+; CHECK-NEXT: [[N_VEC:%.*]] = and i32 [[TMP1]], -4
+; CHECK-NEXT: [[DOTCAST:%.*]] = trunc nsw i32 [[N_VEC]] to i16
; CHECK-NEXT: [[IND_END:%.*]] = or disjoint i16 [[DOTCAST]], 1
; CHECK-NEXT: br label [[VECTOR_BODY:%.*]]
; CHECK: vector.body:
@@ -1285,7 +1285,7 @@ define i64 @reduction_with_phi_with_two_incoming_on_backedge(i16 %n, ptr %A) {
; CHECK-NEXT: br i1 [[TMP5]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP25:![0-9]+]]
; CHECK: middle.block:
; CHECK-NEXT: [[TMP6:%.*]] = call i64 @llvm.vector.reduce.add.v4i64(<4 x i64> [[TMP4]])
-; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i32 [[N_VEC]], [[TMP1]]
+; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i32 [[TMP1]], [[N_VEC]]
; CHECK-NEXT: br i1 [[CMP_N]], label [[EXIT:%.*]], label [[SCALAR_PH]]
; CHECK: scalar.ph:
; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i16 [ [[IND_END]], [[MIDDLE_BLOCK]] ], [ 1, [[ENTRY:%.*]] ]
>From a13adb999e9cb2c42e21fd6af4b1bc6662f7e81f Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 3 Jun 2025 16:37:46 +0100
Subject: [PATCH 2/6] !fixup drop A >= C requierement
---
llvm/lib/Analysis/ScalarEvolution.cpp | 8 +++-----
1 file changed, 3 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index cb101159954af..d0f2d4e4cd882 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -1912,13 +1912,11 @@ const SCEV *ScalarEvolution::getZeroExtendExprImpl(const SCEV *Op, Type *Ty,
const SCEVConstant *C;
const SCEV *A;
- // zext (C + A)<nsw> -> (sext(C) + zext(A))<nsw> if zext (C + A)<nsw> >=s 0
- // and A >=s V.
+ // zext (C + A)<nsw> -> (sext(C) + sext(A))<nsw> if zext (C + A)<nsw> >=s 0.
if (SA->hasNoSignedWrap() && isKnownNonNegative(SA) &&
- match(SA, m_scev_Add(m_SCEVConstant(C), m_SCEV(A))) &&
- isKnownPredicate(CmpInst::ICMP_SGE, A, C)) {
+ match(SA, m_scev_Add(m_SCEVConstant(C), m_SCEV(A)))) {
SmallVector<const SCEV *, 4> Ops = {getSignExtendExpr(C, Ty, Depth + 1),
- getZeroExtendExpr(A, Ty, Depth + 1)};
+ getSignExtendExpr(A, Ty, Depth + 1)};
return getAddExpr(Ops, SCEV::FlagNSW, Depth + 1);
}
>From 70f6b8417d9e3d67597d6d08b818ef15cf6b8fa2 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Tue, 3 Jun 2025 19:58:47 +0100
Subject: [PATCH 3/6] !fixup add test showing regression.
---
.../Transforms/IndVarSimplify/add-nsw-zext-fold.ll | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/llvm/test/Transforms/IndVarSimplify/add-nsw-zext-fold.ll b/llvm/test/Transforms/IndVarSimplify/add-nsw-zext-fold.ll
index 1de41e47a8569..c263b3f2d060b 100644
--- a/llvm/test/Transforms/IndVarSimplify/add-nsw-zext-fold.ll
+++ b/llvm/test/Transforms/IndVarSimplify/add-nsw-zext-fold.ll
@@ -12,14 +12,15 @@ define void @add_nsw_zext_fold_results_in_sext(i64 %len) {
; CHECK-NEXT: [[LEN_TRUNC:%.*]] = trunc i64 [[LEN]] to i32
; CHECK-NEXT: [[LZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[LEN_TRUNC]], i1 false)
; CHECK-NEXT: [[SUB_I:%.*]] = lshr i32 [[LZ]], 3
-; CHECK-NEXT: [[ADD_I:%.*]] = sub i32 5, [[SUB_I]]
; CHECK-NEXT: [[PRECOND:%.*]] = icmp eq i32 [[SUB_I]], 5
; CHECK-NEXT: br i1 [[PRECOND]], label %[[EXIT:.*]], label %[[LOOP_PREHEADER:.*]]
; CHECK: [[LOOP_PREHEADER]]:
-; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[ADD_I]] to i64
+; CHECK-NEXT: [[TMP3:%.*]] = sub i32 0, [[SUB_I]]
+; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[TMP3]] to i64
+; CHECK-NEXT: [[TMP2:%.*]] = add nsw i64 [[TMP1]], 5
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
-; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[TMP1]], %[[LOOP_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[TMP2]], %[[LOOP_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IV:%.*]] = trunc nuw i64 [[INDVARS_IV]] to i32
; CHECK-NEXT: [[IV_NEXT:%.*]] = add i32 [[IV]], 1
; CHECK-NEXT: [[SH_PROM:%.*]] = zext nneg i32 [[IV_NEXT]] to i64
@@ -65,9 +66,9 @@ define void @add_nsw_zext_fold_results_in_sext_known_positive(i32 %mask, ptr %sr
; CHECK-NEXT: [[PRECOND:%.*]] = icmp slt i32 [[ADD]], 0
; CHECK-NEXT: br i1 [[PRECOND]], label %[[EXIT:.*]], label %[[PH:.*]]
; CHECK: [[PH]]:
-; CHECK-NEXT: [[TMP0:%.*]] = sub i32 78, [[SPEC_SELECT]]
-; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[TMP0]] to i64
-; CHECK-NEXT: [[TMP2:%.*]] = add nuw nsw i64 [[TMP1]], 1
+; CHECK-NEXT: [[TMP0:%.*]] = sub i32 0, [[SPEC_SELECT]]
+; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i64
+; CHECK-NEXT: [[TMP2:%.*]] = add nsw i64 [[TMP1]], 79
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[TMP2]]
>From d22a067dbbb4704a3b711aaec8efab46e647faf5 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Thu, 5 Jun 2025 20:09:55 +0100
Subject: [PATCH 4/6] !fixup use getAddExpr taking 2 SCEVs.
---
llvm/lib/Analysis/ScalarEvolution.cpp | 6 +--
.../LoopIdiom/X86/memset-size-compute.ll | 8 ++--
.../Transforms/LoopIdiom/add-nsw-zext-fold.ll | 7 +--
.../peel-last-iteration-with-guards.ll | 46 +++++++++++++++----
.../LoopVectorize/AArch64/predicated-costs.ll | 4 +-
.../Transforms/LoopVectorize/runtime-check.ll | 7 ---
6 files changed, 51 insertions(+), 27 deletions(-)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index d0f2d4e4cd882..9ff5859be69b5 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -1915,9 +1915,9 @@ const SCEV *ScalarEvolution::getZeroExtendExprImpl(const SCEV *Op, Type *Ty,
// zext (C + A)<nsw> -> (sext(C) + sext(A))<nsw> if zext (C + A)<nsw> >=s 0.
if (SA->hasNoSignedWrap() && isKnownNonNegative(SA) &&
match(SA, m_scev_Add(m_SCEVConstant(C), m_SCEV(A)))) {
- SmallVector<const SCEV *, 4> Ops = {getSignExtendExpr(C, Ty, Depth + 1),
- getSignExtendExpr(A, Ty, Depth + 1)};
- return getAddExpr(Ops, SCEV::FlagNSW, Depth + 1);
+ return getAddExpr(getSignExtendExpr(C, Ty, Depth + 1),
+ getSignExtendExpr(A, Ty, Depth + 1), SCEV::FlagNSW,
+ Depth + 1);
}
// zext(C + x + y + ...) --> (zext(D) + zext((C - D) + x + y + ...))
diff --git a/llvm/test/Transforms/LoopIdiom/X86/memset-size-compute.ll b/llvm/test/Transforms/LoopIdiom/X86/memset-size-compute.ll
index 0123f15334281..b58e3c7d275bb 100644
--- a/llvm/test/Transforms/LoopIdiom/X86/memset-size-compute.ll
+++ b/llvm/test/Transforms/LoopIdiom/X86/memset-size-compute.ll
@@ -15,10 +15,10 @@ define void @test(ptr %ptr) {
; CHECK: for.body.preheader:
; CHECK-NEXT: [[LIM_0:%.*]] = phi i32 [ 65, [[ENTRY:%.*]] ], [ 1, [[DEAD:%.*]] ]
; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[PTR:%.*]], i64 8
-; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[LIM_0]], i32 2)
-; CHECK-NEXT: [[TMP2:%.*]] = shl nuw nsw i32 [[UMAX]], 3
-; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[TMP2]], -8
-; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[TMP0]] to i64
+; CHECK-NEXT: [[TMP0:%.*]] = zext nneg i32 [[LIM_0]] to i64
+; CHECK-NEXT: [[UMAX:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP0]], i64 2)
+; CHECK-NEXT: [[TMP2:%.*]] = shl nuw nsw i64 [[UMAX]], 3
+; CHECK-NEXT: [[TMP1:%.*]] = add nsw i64 [[TMP2]], -8
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[SCEVGEP]], i8 0, i64 [[TMP1]], i1 false)
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
diff --git a/llvm/test/Transforms/LoopIdiom/add-nsw-zext-fold.ll b/llvm/test/Transforms/LoopIdiom/add-nsw-zext-fold.ll
index bc1543d8361a7..cf894eb916ab1 100644
--- a/llvm/test/Transforms/LoopIdiom/add-nsw-zext-fold.ll
+++ b/llvm/test/Transforms/LoopIdiom/add-nsw-zext-fold.ll
@@ -9,9 +9,10 @@ define void @fold_add_zext_to_sext(ptr %dst, i1 %start) {
; CHECK-NEXT: [[TMP0:%.*]] = zext i1 [[START]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw nsw i64 [[TMP0]], 2
; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[DST]], i64 [[TMP1]]
-; CHECK-NEXT: [[TMP4:%.*]] = shl nuw nsw i32 [[START_EXT]], 2
-; CHECK-NEXT: [[TMP2:%.*]] = sub i32 100, [[TMP4]]
-; CHECK-NEXT: [[TMP3:%.*]] = zext nneg i32 [[TMP2]] to i64
+; CHECK-NEXT: [[TMP2:%.*]] = sub i32 0, [[START_EXT]]
+; CHECK-NEXT: [[TMP5:%.*]] = sext i32 [[TMP2]] to i64
+; CHECK-NEXT: [[TMP4:%.*]] = shl nsw i64 [[TMP5]], 2
+; CHECK-NEXT: [[TMP3:%.*]] = add nsw i64 [[TMP4]], 100
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[SCEVGEP]], i8 0, i64 [[TMP3]], i1 false)
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
diff --git a/llvm/test/Transforms/LoopUnroll/peel-last-iteration-with-guards.ll b/llvm/test/Transforms/LoopUnroll/peel-last-iteration-with-guards.ll
index c1d8395965577..c763f14b73cb8 100644
--- a/llvm/test/Transforms/LoopUnroll/peel-last-iteration-with-guards.ll
+++ b/llvm/test/Transforms/LoopUnroll/peel-last-iteration-with-guards.ll
@@ -77,10 +77,14 @@ define i32 @peel_with_guard_known_nonnegative_2(ptr %x, i32 %w) {
; CHECK-NEXT: [[SUB:%.*]] = add nsw i32 [[W]], -1
; CHECK-NEXT: [[TMP0:%.*]] = zext nneg i32 [[SUB]] to i64
; CHECK-NEXT: [[WIDE_TRIP_COUNT:%.*]] = zext nneg i32 [[W]] to i64
+; CHECK-NEXT: [[TMP3:%.*]] = add nsw i64 [[WIDE_TRIP_COUNT]], -1
+; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i64 [[TMP3]], 0
+; CHECK-NEXT: br i1 [[TMP2]], label %[[PH_SPLIT:.*]], label %[[EXIT_LOOPEXIT_PEEL_BEGIN:.*]]
+; CHECK: [[PH_SPLIT]]:
; CHECK-NEXT: br label %[[LOOP_HEADER:.*]]
; CHECK: [[LOOP_HEADER]]:
-; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[PH]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
-; CHECK-NEXT: [[RED:%.*]] = phi i32 [ 0, %[[PH]] ], [ [[ADD:%.*]], %[[LOOP_LATCH]] ]
+; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[PH_SPLIT]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT: [[RED:%.*]] = phi i32 [ 0, %[[PH_SPLIT]] ], [ [[ADD:%.*]], %[[LOOP_LATCH]] ]
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i64 [[IV]], [[TMP0]]
; CHECK-NEXT: br i1 [[CMP1]], label %[[IF_THEN:.*]], label %[[LOOP_LATCH]]
; CHECK: [[IF_THEN]]:
@@ -91,13 +95,38 @@ define i32 @peel_with_guard_known_nonnegative_2(ptr %x, i32 %w) {
; CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
; CHECK-NEXT: [[ADD]] = add nsw i32 [[TMP1]], [[RED]]
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
-; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[WIDE_TRIP_COUNT]]
-; CHECK-NEXT: br i1 [[EC]], label %[[EXIT_LOOPEXIT:.*]], label %[[LOOP_HEADER]]
+; CHECK-NEXT: [[TMP4:%.*]] = sub i64 [[WIDE_TRIP_COUNT]], 1
+; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[TMP4]]
+; CHECK-NEXT: br i1 [[EC]], label %[[EXIT_LOOPEXIT_PEEL_BEGIN_LOOPEXIT:.*]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP2:![0-9]+]]
+; CHECK: [[EXIT_LOOPEXIT_PEEL_BEGIN_LOOPEXIT]]:
+; CHECK-NEXT: [[DOTPH:%.*]] = phi i64 [ [[IV_NEXT]], %[[LOOP_LATCH]] ]
+; CHECK-NEXT: [[DOTPH1:%.*]] = phi i32 [ [[ADD]], %[[LOOP_LATCH]] ]
+; CHECK-NEXT: br label %[[EXIT_LOOPEXIT_PEEL_BEGIN]]
+; CHECK: [[EXIT_LOOPEXIT_PEEL_BEGIN]]:
+; CHECK-NEXT: [[TMP5:%.*]] = phi i64 [ 0, %[[PH]] ], [ [[DOTPH]], %[[EXIT_LOOPEXIT_PEEL_BEGIN_LOOPEXIT]] ]
+; CHECK-NEXT: [[TMP6:%.*]] = phi i32 [ 0, %[[PH]] ], [ [[DOTPH1]], %[[EXIT_LOOPEXIT_PEEL_BEGIN_LOOPEXIT]] ]
+; CHECK-NEXT: br label %[[LOOP_HEADER_PEEL:.*]]
+; CHECK: [[LOOP_HEADER_PEEL]]:
+; CHECK-NEXT: [[CMP1_PEEL:%.*]] = icmp eq i64 [[TMP5]], [[TMP0]]
+; CHECK-NEXT: br i1 [[CMP1_PEEL]], label %[[EXIT_LOOPEXIT:.*]], label %[[LOOP_LATCH_PEEL:.*]]
; CHECK: [[EXIT_LOOPEXIT]]:
-; CHECK-NEXT: [[ADD_LCSSA:%.*]] = phi i32 [ [[ADD]], %[[LOOP_LATCH]] ]
+; CHECK-NEXT: tail call void @foo()
+; CHECK-NEXT: br label %[[LOOP_LATCH_PEEL]]
+; CHECK: [[LOOP_LATCH_PEEL]]:
+; CHECK-NEXT: [[ARRAYIDX_PEEL:%.*]] = getelementptr inbounds nuw i32, ptr [[X]], i64 [[TMP5]]
+; CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[ARRAYIDX_PEEL]], align 4
+; CHECK-NEXT: [[ADD_PEEL:%.*]] = add nsw i32 [[TMP7]], [[TMP6]]
+; CHECK-NEXT: [[IV_NEXT_PEEL:%.*]] = add nuw nsw i64 [[TMP5]], 1
+; CHECK-NEXT: [[EC_PEEL:%.*]] = icmp eq i64 [[IV_NEXT_PEEL]], [[WIDE_TRIP_COUNT]]
+; CHECK-NEXT: br i1 [[EC_PEEL]], label %[[EXIT_LOOPEXIT_PEEL_NEXT:.*]], label %[[EXIT_LOOPEXIT_PEEL_NEXT]]
+; CHECK: [[EXIT_LOOPEXIT_PEEL_NEXT]]:
+; CHECK-NEXT: br label %[[LOOP_HEADER_PEEL_NEXT:.*]]
+; CHECK: [[LOOP_HEADER_PEEL_NEXT]]:
+; CHECK-NEXT: br label %[[EXIT_LOOPEXIT1:.*]]
+; CHECK: [[EXIT_LOOPEXIT1]]:
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
-; CHECK-NEXT: [[RED_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[ADD_LCSSA]], %[[EXIT_LOOPEXIT]] ]
+; CHECK-NEXT: [[RED_LCSSA:%.*]] = phi i32 [ 0, %[[ENTRY]] ], [ [[ADD_PEEL]], %[[EXIT_LOOPEXIT1]] ]
; CHECK-NEXT: ret i32 [[RED_LCSSA]]
;
entry:
@@ -156,7 +185,7 @@ define void @peel_with_guard2(i32 %n) {
; CHECK-NEXT: [[IV_NEXT]] = add nuw i32 [[IV]], 1
; CHECK-NEXT: [[TMP2:%.*]] = sub i32 [[N]], 1
; CHECK-NEXT: [[EC:%.*]] = icmp eq i32 [[IV_NEXT]], [[TMP2]]
-; CHECK-NEXT: br i1 [[EC]], label %[[EXIT_LOOPEXIT_PEEL_BEGIN_LOOPEXIT:.*]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP2:![0-9]+]]
+; CHECK-NEXT: br i1 [[EC]], label %[[EXIT_LOOPEXIT_PEEL_BEGIN_LOOPEXIT:.*]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP3:![0-9]+]]
; CHECK: [[EXIT_LOOPEXIT_PEEL_BEGIN_LOOPEXIT]]:
; CHECK-NEXT: [[DOTPH:%.*]] = phi i32 [ [[IV_NEXT]], %[[LOOP_LATCH]] ]
; CHECK-NEXT: br label %[[EXIT_LOOPEXIT_PEEL_BEGIN]]
@@ -228,7 +257,7 @@ define void @test_peel_guard_sub_1_btc(i32 %n) {
; CHECK-NEXT: [[IV_NEXT]] = add nuw i32 [[IV]], 1
; CHECK-NEXT: [[TMP2:%.*]] = sub i32 [[N]], 1
; CHECK-NEXT: [[EC:%.*]] = icmp eq i32 [[IV_NEXT]], [[TMP2]]
-; CHECK-NEXT: br i1 [[EC]], label %[[EXIT_LOOPEXIT_PEEL_BEGIN_LOOPEXIT:.*]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP3:![0-9]+]]
+; CHECK-NEXT: br i1 [[EC]], label %[[EXIT_LOOPEXIT_PEEL_BEGIN_LOOPEXIT:.*]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP4:![0-9]+]]
; CHECK: [[EXIT_LOOPEXIT_PEEL_BEGIN_LOOPEXIT]]:
; CHECK-NEXT: [[DOTPH:%.*]] = phi i32 [ [[IV_NEXT]], %[[LOOP_LATCH]] ]
; CHECK-NEXT: br label %[[EXIT_LOOPEXIT_PEEL_BEGIN]]
@@ -281,4 +310,5 @@ exit:
; CHECK: [[META1]] = !{!"llvm.loop.peeled.count", i32 1}
; CHECK: [[LOOP2]] = distinct !{[[LOOP2]], [[META1]]}
; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[META1]]}
+; CHECK: [[LOOP4]] = distinct !{[[LOOP4]], [[META1]]}
;.
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/predicated-costs.ll b/llvm/test/Transforms/LoopVectorize/AArch64/predicated-costs.ll
index 8095e40000e9e..1938212173b6c 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/predicated-costs.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/predicated-costs.ll
@@ -46,8 +46,8 @@ define void @test_predicated_load_cast_hint(ptr %dst.1, ptr %dst.2, ptr %src, i8
; CHECK-NEXT: [[TMP18:%.*]] = shl i64 [[OFF]], 3
; CHECK-NEXT: [[SCEVGEP6:%.*]] = getelementptr i8, ptr [[DST_1]], i64 [[TMP18]]
; CHECK-NEXT: [[SMAX7:%.*]] = call i32 @llvm.smax.i32(i32 [[N_SUB]], i32 4)
-; CHECK-NEXT: [[TMP19:%.*]] = add nsw i32 [[SMAX7]], -1
-; CHECK-NEXT: [[TMP20:%.*]] = zext nneg i32 [[TMP19]] to i64
+; CHECK-NEXT: [[TMP19:%.*]] = zext nneg i32 [[SMAX7]] to i64
+; CHECK-NEXT: [[TMP20:%.*]] = add nsw i64 [[TMP19]], -1
; CHECK-NEXT: [[TMP21:%.*]] = lshr i64 [[TMP20]], 2
; CHECK-NEXT: [[TMP22:%.*]] = shl nuw nsw i64 [[TMP21]], 9
; CHECK-NEXT: [[TMP23:%.*]] = add i64 [[TMP22]], [[TMP18]]
diff --git a/llvm/test/Transforms/LoopVectorize/runtime-check.ll b/llvm/test/Transforms/LoopVectorize/runtime-check.ll
index e0f355375e46c..e5cb8e0894803 100644
--- a/llvm/test/Transforms/LoopVectorize/runtime-check.ll
+++ b/llvm/test/Transforms/LoopVectorize/runtime-check.ll
@@ -504,12 +504,6 @@ define void @test_scev_check_mul_add_expansion(ptr %out, ptr %in, i32 %len, i32
; CHECK-NEXT: [[INDEX:%.*]] = phi i32 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ]
; CHECK-NEXT: [[OFFSET_IDX:%.*]] = add i32 [[INDEX]], 6
; CHECK-NEXT: [[TMP6:%.*]] = sext i32 [[OFFSET_IDX]] to i64
-; CHECK-NEXT: [[TMP7:%.*]] = getelementptr [2 x i8], ptr [[OUT]], i64 [[TMP6]]
-; CHECK-NEXT: store <4 x i16> zeroinitializer, ptr [[TMP7]], align 2, !alias.scope [[META36:![0-9]+]], !noalias [[META39:![0-9]+]]
-; CHECK-NEXT: store i32 0, ptr [[IN]], align 4, !alias.scope [[META39]]
-; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i32 [[INDEX]], 4
-; CHECK-NEXT: [[TMP8:%.*]] = icmp eq i32 [[INDEX_NEXT]], [[N_VEC]]
-; CHECK-NEXT: br i1 [[TMP8]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP41:![0-9]+]]
; CHECK: middle.block:
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i32 [[TMP0]], [[N_VEC]]
; CHECK-NEXT: br i1 [[CMP_N]], label [[EXIT:%.*]], label [[SCALAR_PH]]
@@ -524,7 +518,6 @@ define void @test_scev_check_mul_add_expansion(ptr %out, ptr %in, i32 %len, i32
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
; CHECK-NEXT: store i32 0, ptr [[IN]], align 4
; CHECK-NEXT: [[CMP7_NOT:%.*]] = icmp sgt i32 [[LEN]], [[IV_NEXT]]
-; CHECK-NEXT: br i1 [[CMP7_NOT]], label [[LOOP]], label [[EXIT]], !llvm.loop [[LOOP42:![0-9]+]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
>From d4fd5c83c72ea49cfbaa6cc7565556074867c56f Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sun, 19 Apr 2026 12:06:16 +0100
Subject: [PATCH 5/6] !fxup limit to SMax
---
llvm/lib/Analysis/ScalarEvolution.cpp | 18 +++++++++++-------
.../max-backedge-taken-count-guard-info.ll | 2 +-
.../IndVarSimplify/add-nsw-zext-fold.ll | 13 ++++++-------
.../LoopIdiom/X86/memset-size-compute.ll | 8 ++++----
.../Transforms/LoopIdiom/add-nsw-zext-fold.ll | 7 +++----
.../Transforms/LoopVectorize/runtime-check.ll | 7 +++++++
6 files changed, 32 insertions(+), 23 deletions(-)
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 9ff5859be69b5..657984aa0c3a8 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -1910,14 +1910,18 @@ const SCEV *ScalarEvolution::getZeroExtendExprImpl(const SCEV *Op, Type *Ty,
return getAddExpr(Ops, SCEV::FlagNUW, Depth + 1);
}
- const SCEVConstant *C;
- const SCEV *A;
+ const APInt *C, *C2;
// zext (C + A)<nsw> -> (sext(C) + sext(A))<nsw> if zext (C + A)<nsw> >=s 0.
- if (SA->hasNoSignedWrap() && isKnownNonNegative(SA) &&
- match(SA, m_scev_Add(m_SCEVConstant(C), m_SCEV(A)))) {
- return getAddExpr(getSignExtendExpr(C, Ty, Depth + 1),
- getSignExtendExpr(A, Ty, Depth + 1), SCEV::FlagNSW,
- Depth + 1);
+ // Currently the non-negative check is done manually, as isKnownNonNegative
+ // is too expensive.
+ if (SA->hasNoSignedWrap() &&
+ match(SA, m_scev_Add(m_scev_APInt(C),
+ m_scev_SMax(m_scev_APInt(C2), m_SCEV()))) &&
+ C->isNegative() && !C->isMinSignedValue() && C2->sge(C->abs())) {
+ assert(isKnownNonNegative(SA) && "incorrectly determined non-negative");
+ return getAddExpr(getSignExtendExpr(SA->getOperand(0), Ty, Depth + 1),
+ getSignExtendExpr(SA->getOperand(1), Ty, Depth + 1),
+ SCEV::FlagNSW, Depth + 1);
}
// zext(C + x + y + ...) --> (zext(D) + zext((C - D) + x + y + ...))
diff --git a/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll b/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll
index 449dbab51f325..436f0e55840d9 100644
--- a/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll
+++ b/llvm/test/Analysis/ScalarEvolution/max-backedge-taken-count-guard-info.ll
@@ -1231,7 +1231,7 @@ define void @optimized_range_check_unsigned3(ptr %pred, i1 %c) {
; CHECK-NEXT: %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ]
; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,3) S: [0,3) Exits: (-1 + %N)<nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %gep = getelementptr inbounds i16, ptr %pred, i32 %iv
-; CHECK-NEXT: --> {%pred,+,2}<nuw><%loop> U: full-set S: full-set Exits: (-2 + (2 * (zext i32 %N to i64))<nuw><nsw> + %pred) LoopDispositions: { %loop: Computable }
+; CHECK-NEXT: --> {%pred,+,2}<nuw><%loop> U: full-set S: full-set Exits: ((zext i32 (-2 + (2 * %N)<nuw><nsw>)<nsw> to i64) + %pred) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %iv.next = add nuw nsw i32 %iv, 1
; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,4) S: [1,4) Exits: %N LoopDispositions: { %loop: Computable }
; CHECK-NEXT: Determining loop execution counts for: @optimized_range_check_unsigned3
diff --git a/llvm/test/Transforms/IndVarSimplify/add-nsw-zext-fold.ll b/llvm/test/Transforms/IndVarSimplify/add-nsw-zext-fold.ll
index c263b3f2d060b..1de41e47a8569 100644
--- a/llvm/test/Transforms/IndVarSimplify/add-nsw-zext-fold.ll
+++ b/llvm/test/Transforms/IndVarSimplify/add-nsw-zext-fold.ll
@@ -12,15 +12,14 @@ define void @add_nsw_zext_fold_results_in_sext(i64 %len) {
; CHECK-NEXT: [[LEN_TRUNC:%.*]] = trunc i64 [[LEN]] to i32
; CHECK-NEXT: [[LZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[LEN_TRUNC]], i1 false)
; CHECK-NEXT: [[SUB_I:%.*]] = lshr i32 [[LZ]], 3
+; CHECK-NEXT: [[ADD_I:%.*]] = sub i32 5, [[SUB_I]]
; CHECK-NEXT: [[PRECOND:%.*]] = icmp eq i32 [[SUB_I]], 5
; CHECK-NEXT: br i1 [[PRECOND]], label %[[EXIT:.*]], label %[[LOOP_PREHEADER:.*]]
; CHECK: [[LOOP_PREHEADER]]:
-; CHECK-NEXT: [[TMP3:%.*]] = sub i32 0, [[SUB_I]]
-; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[TMP3]] to i64
-; CHECK-NEXT: [[TMP2:%.*]] = add nsw i64 [[TMP1]], 5
+; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[ADD_I]] to i64
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
-; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[TMP2]], %[[LOOP_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[TMP1]], %[[LOOP_PREHEADER]] ], [ [[INDVARS_IV_NEXT:%.*]], %[[LOOP]] ]
; CHECK-NEXT: [[IV:%.*]] = trunc nuw i64 [[INDVARS_IV]] to i32
; CHECK-NEXT: [[IV_NEXT:%.*]] = add i32 [[IV]], 1
; CHECK-NEXT: [[SH_PROM:%.*]] = zext nneg i32 [[IV_NEXT]] to i64
@@ -66,9 +65,9 @@ define void @add_nsw_zext_fold_results_in_sext_known_positive(i32 %mask, ptr %sr
; CHECK-NEXT: [[PRECOND:%.*]] = icmp slt i32 [[ADD]], 0
; CHECK-NEXT: br i1 [[PRECOND]], label %[[EXIT:.*]], label %[[PH:.*]]
; CHECK: [[PH]]:
-; CHECK-NEXT: [[TMP0:%.*]] = sub i32 0, [[SPEC_SELECT]]
-; CHECK-NEXT: [[TMP1:%.*]] = sext i32 [[TMP0]] to i64
-; CHECK-NEXT: [[TMP2:%.*]] = add nsw i64 [[TMP1]], 79
+; CHECK-NEXT: [[TMP0:%.*]] = sub i32 78, [[SPEC_SELECT]]
+; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[TMP0]] to i64
+; CHECK-NEXT: [[TMP2:%.*]] = add nuw nsw i64 [[TMP1]], 1
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
; CHECK-NEXT: [[GEP:%.*]] = getelementptr i32, ptr [[SRC]], i64 [[TMP2]]
diff --git a/llvm/test/Transforms/LoopIdiom/X86/memset-size-compute.ll b/llvm/test/Transforms/LoopIdiom/X86/memset-size-compute.ll
index b58e3c7d275bb..0123f15334281 100644
--- a/llvm/test/Transforms/LoopIdiom/X86/memset-size-compute.ll
+++ b/llvm/test/Transforms/LoopIdiom/X86/memset-size-compute.ll
@@ -15,10 +15,10 @@ define void @test(ptr %ptr) {
; CHECK: for.body.preheader:
; CHECK-NEXT: [[LIM_0:%.*]] = phi i32 [ 65, [[ENTRY:%.*]] ], [ 1, [[DEAD:%.*]] ]
; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[PTR:%.*]], i64 8
-; CHECK-NEXT: [[TMP0:%.*]] = zext nneg i32 [[LIM_0]] to i64
-; CHECK-NEXT: [[UMAX:%.*]] = call i64 @llvm.umax.i64(i64 [[TMP0]], i64 2)
-; CHECK-NEXT: [[TMP2:%.*]] = shl nuw nsw i64 [[UMAX]], 3
-; CHECK-NEXT: [[TMP1:%.*]] = add nsw i64 [[TMP2]], -8
+; CHECK-NEXT: [[UMAX:%.*]] = call i32 @llvm.umax.i32(i32 [[LIM_0]], i32 2)
+; CHECK-NEXT: [[TMP2:%.*]] = shl nuw nsw i32 [[UMAX]], 3
+; CHECK-NEXT: [[TMP0:%.*]] = add nsw i32 [[TMP2]], -8
+; CHECK-NEXT: [[TMP1:%.*]] = zext nneg i32 [[TMP0]] to i64
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 8 [[SCEVGEP]], i8 0, i64 [[TMP1]], i1 false)
; CHECK-NEXT: br label [[FOR_BODY:%.*]]
; CHECK: for.body:
diff --git a/llvm/test/Transforms/LoopIdiom/add-nsw-zext-fold.ll b/llvm/test/Transforms/LoopIdiom/add-nsw-zext-fold.ll
index cf894eb916ab1..bc1543d8361a7 100644
--- a/llvm/test/Transforms/LoopIdiom/add-nsw-zext-fold.ll
+++ b/llvm/test/Transforms/LoopIdiom/add-nsw-zext-fold.ll
@@ -9,10 +9,9 @@ define void @fold_add_zext_to_sext(ptr %dst, i1 %start) {
; CHECK-NEXT: [[TMP0:%.*]] = zext i1 [[START]] to i64
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw nsw i64 [[TMP0]], 2
; CHECK-NEXT: [[SCEVGEP:%.*]] = getelementptr i8, ptr [[DST]], i64 [[TMP1]]
-; CHECK-NEXT: [[TMP2:%.*]] = sub i32 0, [[START_EXT]]
-; CHECK-NEXT: [[TMP5:%.*]] = sext i32 [[TMP2]] to i64
-; CHECK-NEXT: [[TMP4:%.*]] = shl nsw i64 [[TMP5]], 2
-; CHECK-NEXT: [[TMP3:%.*]] = add nsw i64 [[TMP4]], 100
+; CHECK-NEXT: [[TMP4:%.*]] = shl nuw nsw i32 [[START_EXT]], 2
+; CHECK-NEXT: [[TMP2:%.*]] = sub i32 100, [[TMP4]]
+; CHECK-NEXT: [[TMP3:%.*]] = zext nneg i32 [[TMP2]] to i64
; CHECK-NEXT: call void @llvm.memset.p0.i64(ptr align 4 [[SCEVGEP]], i8 0, i64 [[TMP3]], i1 false)
; CHECK-NEXT: br label %[[LOOP:.*]]
; CHECK: [[LOOP]]:
diff --git a/llvm/test/Transforms/LoopVectorize/runtime-check.ll b/llvm/test/Transforms/LoopVectorize/runtime-check.ll
index e5cb8e0894803..e0f355375e46c 100644
--- a/llvm/test/Transforms/LoopVectorize/runtime-check.ll
+++ b/llvm/test/Transforms/LoopVectorize/runtime-check.ll
@@ -504,6 +504,12 @@ define void @test_scev_check_mul_add_expansion(ptr %out, ptr %in, i32 %len, i32
; CHECK-NEXT: [[INDEX:%.*]] = phi i32 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ]
; CHECK-NEXT: [[OFFSET_IDX:%.*]] = add i32 [[INDEX]], 6
; CHECK-NEXT: [[TMP6:%.*]] = sext i32 [[OFFSET_IDX]] to i64
+; CHECK-NEXT: [[TMP7:%.*]] = getelementptr [2 x i8], ptr [[OUT]], i64 [[TMP6]]
+; CHECK-NEXT: store <4 x i16> zeroinitializer, ptr [[TMP7]], align 2, !alias.scope [[META36:![0-9]+]], !noalias [[META39:![0-9]+]]
+; CHECK-NEXT: store i32 0, ptr [[IN]], align 4, !alias.scope [[META39]]
+; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i32 [[INDEX]], 4
+; CHECK-NEXT: [[TMP8:%.*]] = icmp eq i32 [[INDEX_NEXT]], [[N_VEC]]
+; CHECK-NEXT: br i1 [[TMP8]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP41:![0-9]+]]
; CHECK: middle.block:
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i32 [[TMP0]], [[N_VEC]]
; CHECK-NEXT: br i1 [[CMP_N]], label [[EXIT:%.*]], label [[SCALAR_PH]]
@@ -518,6 +524,7 @@ define void @test_scev_check_mul_add_expansion(ptr %out, ptr %in, i32 %len, i32
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i32 [[IV]], 1
; CHECK-NEXT: store i32 0, ptr [[IN]], align 4
; CHECK-NEXT: [[CMP7_NOT:%.*]] = icmp sgt i32 [[LEN]], [[IV_NEXT]]
+; CHECK-NEXT: br i1 [[CMP7_NOT]], label [[LOOP]], label [[EXIT]], !llvm.loop [[LOOP42:![0-9]+]]
; CHECK: exit:
; CHECK-NEXT: ret void
;
>From 44601daf9e6dc7045ab267c9215752a4e3da9df8 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Mon, 20 Apr 2026 21:05:58 +0100
Subject: [PATCH 6/6] !fixup update test
---
.../test/Analysis/LoopAccessAnalysis/depend_diff_types.ll | 8 +-------
llvm/test/Analysis/ScalarEvolution/zext-add-nsw-fold.ll | 4 ++--
llvm/test/Analysis/ScalarEvolution/zext-add.ll | 2 +-
3 files changed, 4 insertions(+), 10 deletions(-)
diff --git a/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll b/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll
index 27a85c7a46084..5d59660a68e90 100644
--- a/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll
+++ b/llvm/test/Analysis/LoopAccessAnalysis/depend_diff_types.ll
@@ -561,17 +561,11 @@ exit:
ret void
}
-; TODO: Relax HasSameSize check in isSafeDependenceDistance.
define void @different_type_sizes_safe_dep_dist(i16 %n, ptr %p) {
; CHECK-LABEL: 'different_type_sizes_safe_dep_dist'
; CHECK-NEXT: loop:
-; CHECK-NEXT: Report: unsafe dependent memory operations in loop. Use #pragma clang loop distribute(enable) to allow loop distribution to attempt to isolate the offending operations into a separate loop
-; CHECK-NEXT: Unknown data dependence.
+; CHECK-NEXT: Memory dependences are safe
; CHECK-NEXT: Dependences:
-; CHECK-NEXT: Unknown:
-; CHECK-NEXT: store i32 0, ptr %gep.iv, align 1 ->
-; CHECK-NEXT: store i16 1, ptr %gep.off.iv, align 1
-; CHECK-EMPTY:
; CHECK-NEXT: Run-time memory checks:
; CHECK-NEXT: Grouped accesses:
; CHECK-EMPTY:
diff --git a/llvm/test/Analysis/ScalarEvolution/zext-add-nsw-fold.ll b/llvm/test/Analysis/ScalarEvolution/zext-add-nsw-fold.ll
index 19e4b5c06bc5a..06e1f48a5f2c4 100644
--- a/llvm/test/Analysis/ScalarEvolution/zext-add-nsw-fold.ll
+++ b/llvm/test/Analysis/ScalarEvolution/zext-add-nsw-fold.ll
@@ -12,7 +12,7 @@ define i64 @smax_fold_basic(i32 %x) {
; CHECK-NEXT: %add = add nsw i32 -5, %smax
; CHECK-NEXT: --> (-5 + (5 smax %x))<nsw> U: [0,2147483643) S: [0,2147483643)
; CHECK-NEXT: %ext = zext i32 %add to i64
-; CHECK-NEXT: --> (zext i32 (-5 + (5 smax %x))<nsw> to i64) U: [0,2147483643) S: [0,2147483643)
+; CHECK-NEXT: --> (-5 + (zext i32 (5 smax %x) to i64))<nsw> U: [0,2147483643) S: [0,2147483643)
; CHECK-NEXT: Determining loop execution counts for: @smax_fold_basic
;
%smax = call i32 @llvm.smax.i32(i32 %x, i32 5)
@@ -29,7 +29,7 @@ define i64 @smax_fold_larger_k(i32 %x) {
; CHECK-NEXT: %add = add nsw i32 -3, %smax
; CHECK-NEXT: --> (-3 + (10 smax %x))<nsw> U: [7,2147483645) S: [7,2147483645)
; CHECK-NEXT: %ext = zext i32 %add to i64
-; CHECK-NEXT: --> (zext i32 (-3 + (10 smax %x))<nsw> to i64) U: [7,2147483645) S: [7,2147483645)
+; CHECK-NEXT: --> (-3 + (zext i32 (10 smax %x) to i64))<nsw> U: [7,2147483645) S: [7,2147483645)
; CHECK-NEXT: Determining loop execution counts for: @smax_fold_larger_k
;
%smax = call i32 @llvm.smax.i32(i32 %x, i32 10)
diff --git a/llvm/test/Analysis/ScalarEvolution/zext-add.ll b/llvm/test/Analysis/ScalarEvolution/zext-add.ll
index 29f37a82a8b80..02cfac2abb059 100644
--- a/llvm/test/Analysis/ScalarEvolution/zext-add.ll
+++ b/llvm/test/Analysis/ScalarEvolution/zext-add.ll
@@ -13,7 +13,7 @@ define void @test_push_constant_into_zext(ptr %dst, ptr %src, i32 %n, i64 %offse
; CHECK-NEXT: %iv = phi i32 [ 0, %outer.loop ], [ %iv.next, %inner.loop ]
; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%inner.loop> U: [0,2147483647) S: [0,2147483647) Exits: (-1 + (1 smax %n))<nsw> LoopDispositions: { %inner.loop: Computable, %outer.loop: Uniform }
; CHECK-NEXT: %ptr.iv = phi ptr [ %src, %outer.loop ], [ %ptr.iv.next, %inner.loop ]
-; CHECK-NEXT: --> {%src,+,%offset}<%inner.loop> U: full-set S: full-set Exits: (((zext i32 (-1 + (1 smax %n))<nsw> to i64) * %offset) + %src) LoopDispositions: { %inner.loop: Computable, %outer.loop: Uniform }
+; CHECK-NEXT: --> {%src,+,%offset}<%inner.loop> U: full-set S: full-set Exits: (((-1 + (zext i32 (1 smax %n) to i64))<nsw> * %offset) + %src) LoopDispositions: { %inner.loop: Computable, %outer.loop: Uniform }
; CHECK-NEXT: %l = load i8, ptr %outer.ptr, align 1
; CHECK-NEXT: --> %l U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %inner.loop: Variant, %outer.loop: Variant }
; CHECK-NEXT: %ptr.iv.next = getelementptr i8, ptr %ptr.iv, i64 %offset
More information about the llvm-commits
mailing list