[llvm] [ConstraintElim] Derive an unsigned IV bound from a signed relational latch. (PR #222762)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 13 09:42:16 PDT 2026
https://github.com/fhahn updated https://github.com/llvm/llvm-project/pull/222762
>From 51b3565f6e8724483f2238b2462d59c8c4b2a9cb Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 9 Sep 2026 12:40:17 +0100
Subject: [PATCH 1/5] [ConstraintElim] Add tests for unsigned IV bounds from a
signed latch (NFC).
Pre-commit tests for deriving an unsigned bound on the induction from a signed
relational latch condition, plus the negative case where the step may wrap.
---
.../induction-relational-predicate-latch.ll | 164 ++++++++++++++++++
1 file changed, 164 insertions(+)
diff --git a/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll b/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll
index 803679831b988..8779f341d9546 100644
--- a/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll
+++ b/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll
@@ -712,3 +712,167 @@ loop.exit:
call void @use(i1 %c)
ret void
}
+
+; %iv is known non-negative, so the signed condition in the latch can also be
+; translated to an unsigned bound.
+define void @signed_latch_unsigned_fact(i64 %n, i1 %header.ec) {
+; CHECK-LABEL: define void @signed_latch_unsigned_fact(
+; CHECK-SAME: i64 [[N:%.*]], i1 [[HEADER_EC:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[PRE:%.*]] = icmp ne i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT: br label %[[LOOP_HEADER:.*]]
+; CHECK: [[LOOP_HEADER]]:
+; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[IV]], [[N]]
+; CHECK-NEXT: call void @use(i1 [[C]])
+; CHECK-NEXT: br i1 [[HEADER_EC]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK: [[LOOP_LATCH]]:
+; CHECK-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], 2
+; CHECK-NEXT: [[EC:%.*]] = icmp slt i64 [[IV_NEXT]], [[N]]
+; CHECK-NEXT: br i1 [[EC]], label %[[LOOP_HEADER]], label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ %pre = icmp ne i64 %n, 0
+ call void @llvm.assume(i1 %pre)
+ br label %loop.header
+
+loop.header:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
+ %c = icmp ult i64 %iv, %n
+ call void @use(i1 %c)
+ br i1 %header.ec, label %exit, label %loop.latch
+
+loop.latch:
+ %iv.next = add nsw i64 %iv, 2
+ %ec = icmp slt i64 %iv.next, %n
+ br i1 %ec, label %loop.header, label %exit
+
+exit:
+ ret void
+}
+
+; Same, but the step may wrap.
+define void @neg_wrapping_step_no_unsigned_fact(i64 %n, i1 %header.ec) {
+; CHECK-LABEL: define void @neg_wrapping_step_no_unsigned_fact(
+; CHECK-SAME: i64 [[N:%.*]], i1 [[HEADER_EC:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[PRE:%.*]] = icmp ne i64 [[N]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT: br label %[[LOOP_HEADER:.*]]
+; CHECK: [[LOOP_HEADER]]:
+; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[IV]], [[N]]
+; CHECK-NEXT: call void @use(i1 [[C]])
+; CHECK-NEXT: br i1 [[HEADER_EC]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK: [[LOOP_LATCH]]:
+; CHECK-NEXT: [[IV_NEXT]] = add i64 [[IV]], 2
+; CHECK-NEXT: [[EC:%.*]] = icmp slt i64 [[IV_NEXT]], [[N]]
+; CHECK-NEXT: br i1 [[EC]], label %[[LOOP_HEADER]], label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ %pre = icmp ne i64 %n, 0
+ call void @llvm.assume(i1 %pre)
+ br label %loop.header
+
+loop.header:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
+ %c = icmp ult i64 %iv, %n
+ call void @use(i1 %c)
+ br i1 %header.ec, label %exit, label %loop.latch
+
+loop.latch:
+ %iv.next = add i64 %iv, 2
+ %ec = icmp slt i64 %iv.next, %n
+ br i1 %ec, label %loop.header, label %exit
+
+exit:
+ ret void
+}
+
+define void @signed_latch_unsigned_fact_variable_start(i64 %start, i64 %n, i1 %header.ec) {
+; CHECK-LABEL: define void @signed_latch_unsigned_fact_variable_start(
+; CHECK-SAME: i64 [[START:%.*]], i64 [[N:%.*]], i1 [[HEADER_EC:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[PRE:%.*]] = icmp ult i64 [[START]], [[N]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT: [[PRE_POS:%.*]] = icmp sge i64 [[START]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[PRE_POS]])
+; CHECK-NEXT: br label %[[LOOP_HEADER:.*]]
+; CHECK: [[LOOP_HEADER]]:
+; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[IV]], [[N]]
+; CHECK-NEXT: call void @use(i1 [[C]])
+; CHECK-NEXT: br i1 [[HEADER_EC]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK: [[LOOP_LATCH]]:
+; CHECK-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], 2
+; CHECK-NEXT: [[EC:%.*]] = icmp slt i64 [[IV_NEXT]], [[N]]
+; CHECK-NEXT: br i1 [[EC]], label %[[LOOP_HEADER]], label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ %pre.1 = icmp ult i64 %start, %n
+ call void @llvm.assume(i1 %pre.1)
+ %start.pos = icmp sge i64 %start, 0
+ call void @llvm.assume(i1 %start.pos)
+ br label %loop.header
+
+loop.header:
+ %iv = phi i64 [ %start, %entry ], [ %iv.next, %loop.latch ]
+ %c = icmp ult i64 %iv, %n
+ call void @use(i1 %c)
+ br i1 %header.ec, label %exit, label %loop.latch
+
+loop.latch:
+ %iv.next = add nsw i64 %iv, 2
+ %ec = icmp slt i64 %iv.next, %n
+ br i1 %ec, label %loop.header, label %exit
+
+exit:
+ ret void
+}
+
+; Same as above, but with missing %start < %n precondition.
+define void @signed_latch_unsigned_fact_variable_start_missing_ult(i64 %start, i64 %n, i1 %header.ec) {
+; CHECK-LABEL: define void @signed_latch_unsigned_fact_variable_start_missing_ult(
+; CHECK-SAME: i64 [[START:%.*]], i64 [[N:%.*]], i1 [[HEADER_EC:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[PRE_POS:%.*]] = icmp sge i64 [[START]], 0
+; CHECK-NEXT: call void @llvm.assume(i1 [[PRE_POS]])
+; CHECK-NEXT: br label %[[LOOP_HEADER:.*]]
+; CHECK: [[LOOP_HEADER]]:
+; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[IV]], [[N]]
+; CHECK-NEXT: call void @use(i1 [[C]])
+; CHECK-NEXT: br i1 [[HEADER_EC]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK: [[LOOP_LATCH]]:
+; CHECK-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], 2
+; CHECK-NEXT: [[EC:%.*]] = icmp slt i64 [[IV_NEXT]], [[N]]
+; CHECK-NEXT: br i1 [[EC]], label %[[LOOP_HEADER]], label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ %start.pos = icmp sge i64 %start, 0
+ call void @llvm.assume(i1 %start.pos)
+ br label %loop.header
+
+loop.header:
+ %iv = phi i64 [ %start, %entry ], [ %iv.next, %loop.latch ]
+ %c = icmp ult i64 %iv, %n
+ call void @use(i1 %c)
+ br i1 %header.ec, label %exit, label %loop.latch
+
+loop.latch:
+ %iv.next = add nsw i64 %iv, 2
+ %ec = icmp slt i64 %iv.next, %n
+ br i1 %ec, label %loop.header, label %exit
+
+exit:
+ ret void
+}
>From 6d0b780464dd929d60a8bc3311739ac0fdf7b9a7 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Wed, 9 Sep 2026 12:43:13 +0100
Subject: [PATCH 2/5] [ConstraintElim] Derive an unsigned IV bound from a
signed relational latch.
For a known non-negative backedge (either via isKnownNonNegative or
because the increment is increasing), 0 <=s PN <= B holds and implies
that B is non-negative as well.
Use that to translate a signed condition to the equivalent unsigned one.
Note that the general signed->unsigned rewrite cannot catch this,
because the precondition also needs rewriting to unsigned.
No llvm-opt-benchmark-nightly impact, but it can help remove runtime
checks generated by sanitizers or Swift code. An end-to-end C example is
https://clang.godbolt.org/z/vbd91MjaM.
---
llvm/lib/Transforms/Scalar/ConstraintElimination.cpp | 12 ++++++++++++
.../induction-relational-predicate-latch.ll | 6 ++----
2 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index da2d61e1c6e27..4bf1ae29b27f4 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1188,6 +1188,18 @@ void State::addInfoForInductions(BasicBlock &BB) {
WorkList.push_back(FactOrCheck::getConditionFact(
DTN, ContinuePred, PN, B, ConditionTy(ContinuePred, StartValue, B)));
+ // For a non-negative backedge value, 0 s<= PN s< B implies B is
+ // non-negative as well, so the same bound holds in the unsigned system.
+ if (ICmpInst::isSigned(ContinuePred)) {
+ MonotonicInfo Info = getMonotonicityInfo(*PN, Backedge);
+ if ((Info.Signed && !Info.Decreasing) ||
+ isKnownNonNegative(Backedge, BB.getDataLayout())) {
+ CmpInst::Predicate UPred = ICmpInst::getUnsignedPredicate(ContinuePred);
+ WorkList.push_back(FactOrCheck::getConditionFact(
+ DTN, UPred, PN, B, ConditionTy(UPred, StartValue, B)));
+ }
+ }
+
// A relational latch steps past B rather than landing on it, so none of the
// reasoning below applies.
return;
diff --git a/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll b/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll
index 8779f341d9546..29101d54567e9 100644
--- a/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll
+++ b/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll
@@ -724,8 +724,7 @@ define void @signed_latch_unsigned_fact(i64 %n, i1 %header.ec) {
; CHECK-NEXT: br label %[[LOOP_HEADER:.*]]
; CHECK: [[LOOP_HEADER]]:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
-; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[IV]], [[N]]
-; CHECK-NEXT: call void @use(i1 [[C]])
+; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: br i1 [[HEADER_EC]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
; CHECK: [[LOOP_LATCH]]:
; CHECK-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], 2
@@ -805,8 +804,7 @@ define void @signed_latch_unsigned_fact_variable_start(i64 %start, i64 %n, i1 %h
; CHECK-NEXT: br label %[[LOOP_HEADER:.*]]
; CHECK: [[LOOP_HEADER]]:
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[START]], %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
-; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[IV]], [[N]]
-; CHECK-NEXT: call void @use(i1 [[C]])
+; CHECK-NEXT: call void @use(i1 true)
; CHECK-NEXT: br i1 [[HEADER_EC]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
; CHECK: [[LOOP_LATCH]]:
; CHECK-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], 2
>From d1acc15870659c603e69c3d3fa6c25e877b469d2 Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sat, 12 Sep 2026 16:19:11 +0100
Subject: [PATCH 3/5] !fixup add SLT/SLE assert + SGT tests
---
.../Scalar/ConstraintElimination.cpp | 3 +
.../induction-relational-predicate-latch.ll | 81 +++++++++++++++++++
2 files changed, 84 insertions(+)
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 4bf1ae29b27f4..7d721f7b1293d 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1191,6 +1191,9 @@ void State::addInfoForInductions(BasicBlock &BB) {
// For a non-negative backedge value, 0 s<= PN s< B implies B is
// non-negative as well, so the same bound holds in the unsigned system.
if (ICmpInst::isSigned(ContinuePred)) {
+ assert((ContinuePred == CmpInst::ICMP_SLT ||
+ ContinuePred == CmpInst::ICMP_SLE) &&
+ "Expected a signed less-than continuation predicate");
MonotonicInfo Info = getMonotonicityInfo(*PN, Backedge);
if ((Info.Signed && !Info.Decreasing) ||
isKnownNonNegative(Backedge, BB.getDataLayout())) {
diff --git a/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll b/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll
index 29101d54567e9..bdc1f406fce90 100644
--- a/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll
+++ b/llvm/test/Transforms/ConstraintElimination/induction-relational-predicate-latch.ll
@@ -874,3 +874,84 @@ loop.latch:
exit:
ret void
}
+
+; Continuing on sgt does not imply an unsigned lower bound. For n = -2,
+; incrementing iv from -1 to 0 makes the unsigned comparison false.
+define void @signed_gt_latch_no_unsigned_fact(i64 %n) {
+; CHECK-LABEL: define void @signed_gt_latch_no_unsigned_fact(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: [[PRE:%.*]] = icmp ugt i64 -1, [[N]]
+; CHECK-NEXT: call void @llvm.assume(i1 [[PRE]])
+; CHECK-NEXT: br label %[[LOOP_HEADER:.*]]
+; CHECK: [[LOOP_HEADER]]:
+; CHECK-NEXT: [[IV:%.*]] = phi i64 [ -1, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT: [[C:%.*]] = icmp ugt i64 [[IV]], [[N]]
+; CHECK-NEXT: call void @use(i1 [[C]])
+; CHECK-NEXT: [[STOP:%.*]] = icmp eq i64 [[IV]], 1
+; CHECK-NEXT: br i1 [[STOP]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK: [[LOOP_LATCH]]:
+; CHECK-NEXT: [[IV_NEXT]] = add nsw i64 [[IV]], 1
+; CHECK-NEXT: [[EC:%.*]] = icmp sgt i64 [[IV_NEXT]], [[N]]
+; CHECK-NEXT: br i1 [[EC]], label %[[LOOP_HEADER]], label %[[EXIT]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ %pre = icmp ugt i64 -1, %n
+ call void @llvm.assume(i1 %pre)
+ br label %loop.header
+
+loop.header:
+ %iv = phi i64 [ -1, %entry ], [ %iv.next, %loop.latch ]
+ %c = icmp ugt i64 %iv, %n
+ call void @use(i1 %c)
+ %stop = icmp eq i64 %iv, 1
+ br i1 %stop, label %exit, label %loop.latch
+
+loop.latch:
+ %iv.next = add nsw i64 %iv, 1
+ %ec = icmp sgt i64 %iv.next, %n
+ br i1 %ec, label %loop.header, label %exit
+
+exit:
+ ret void
+}
+
+; Exiting on sgt instead gives a signed <= continuation, which does imply an
+; unsigned upper bound for this non-negative induction.
+define void @signed_gt_exit_unsigned_fact(i64 %n) {
+; CHECK-LABEL: define void @signed_gt_exit_unsigned_fact(
+; CHECK-SAME: i64 [[N:%.*]]) {
+; CHECK-NEXT: [[ENTRY:.*]]:
+; CHECK-NEXT: br label %[[LOOP_HEADER:.*]]
+; CHECK: [[LOOP_HEADER]]:
+; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, %[[ENTRY]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
+; CHECK-NEXT: call void @use(i1 true)
+; CHECK-NEXT: [[STOP:%.*]] = icmp eq i64 [[IV]], 4
+; CHECK-NEXT: br i1 [[STOP]], label %[[EXIT:.*]], label %[[LOOP_LATCH]]
+; CHECK: [[LOOP_LATCH]]:
+; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
+; CHECK-NEXT: [[EC:%.*]] = icmp sgt i64 [[IV_NEXT]], [[N]]
+; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]]
+; CHECK: [[EXIT]]:
+; CHECK-NEXT: ret void
+;
+entry:
+ br label %loop.header
+
+loop.header:
+ %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
+ %c = icmp ule i64 %iv, %n
+ call void @use(i1 %c)
+ %stop = icmp eq i64 %iv, 4
+ br i1 %stop, label %exit, label %loop.latch
+
+loop.latch:
+ %iv.next = add nsw i64 %iv, 1
+ %ec = icmp sgt i64 %iv.next, %n
+ br i1 %ec, label %exit, label %loop.header
+
+exit:
+ ret void
+}
>From aa290fbb658a4f3674bc468323f0005aeb17471b Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sat, 12 Sep 2026 20:43:30 +0100
Subject: [PATCH 4/5] !fixu remove is knownnonnegative
---
llvm/lib/Transforms/Scalar/ConstraintElimination.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index 7d721f7b1293d..ff73ff1f27811 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1195,8 +1195,7 @@ void State::addInfoForInductions(BasicBlock &BB) {
ContinuePred == CmpInst::ICMP_SLE) &&
"Expected a signed less-than continuation predicate");
MonotonicInfo Info = getMonotonicityInfo(*PN, Backedge);
- if ((Info.Signed && !Info.Decreasing) ||
- isKnownNonNegative(Backedge, BB.getDataLayout())) {
+ if ((Info.Signed && !Info.Decreasing)) {
CmpInst::Predicate UPred = ICmpInst::getUnsignedPredicate(ContinuePred);
WorkList.push_back(FactOrCheck::getConditionFact(
DTN, UPred, PN, B, ConditionTy(UPred, StartValue, B)));
>From d2aabfd9bd1a5d1289856dffdf641926c6199e6c Mon Sep 17 00:00:00 2001
From: Florian Hahn <flo at fhahn.com>
Date: Sun, 13 Sep 2026 17:09:40 +0100
Subject: [PATCH 5/5] !fixup adjust comment
---
llvm/lib/Transforms/Scalar/ConstraintElimination.cpp | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
index ff73ff1f27811..f73f8c9180a44 100644
--- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
+++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp
@@ -1188,14 +1188,15 @@ void State::addInfoForInductions(BasicBlock &BB) {
WorkList.push_back(FactOrCheck::getConditionFact(
DTN, ContinuePred, PN, B, ConditionTy(ContinuePred, StartValue, B)));
- // For a non-negative backedge value, 0 s<= PN s< B implies B is
- // non-negative as well, so the same bound holds in the unsigned system.
+ // A signed bound can be translated to the unsigned system if PN is signed
+ // non-decreasing (StartValue s<= PN s< B) and StartValue u< B holds.
+ // Then StartValue, PN and B must all have the same sign.
if (ICmpInst::isSigned(ContinuePred)) {
assert((ContinuePred == CmpInst::ICMP_SLT ||
ContinuePred == CmpInst::ICMP_SLE) &&
"Expected a signed less-than continuation predicate");
MonotonicInfo Info = getMonotonicityInfo(*PN, Backedge);
- if ((Info.Signed && !Info.Decreasing)) {
+ if (Info.Signed && !Info.Decreasing) {
CmpInst::Predicate UPred = ICmpInst::getUnsignedPredicate(ContinuePred);
WorkList.push_back(FactOrCheck::getConditionFact(
DTN, UPred, PN, B, ConditionTy(UPred, StartValue, B)));
More information about the llvm-commits
mailing list