[llvm] [ConstantRange] Expand makeAllowedICmpRegion to use samesign to give tighter range (PR #174355)
Adar Dagan via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 4 23:43:40 PST 2026
https://github.com/Adar-Dagan updated https://github.com/llvm/llvm-project/pull/174355
>From dca9fb2b76c3057720e316cb08ba9b8f3c29b163 Mon Sep 17 00:00:00 2001
From: Adar Dagan <adar.dagan at mobileye.com>
Date: Mon, 5 Jan 2026 06:48:16 +0200
Subject: [PATCH 1/6] init
---
llvm/include/llvm/IR/ConstantRange.h | 3 ++-
llvm/lib/Analysis/ValueTracking.cpp | 2 +-
llvm/lib/IR/ConstantRange.cpp | 7 ++++++-
3 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h
index f4d4f1f555fa4..47b9b60b64b2e 100644
--- a/llvm/include/llvm/IR/ConstantRange.h
+++ b/llvm/include/llvm/IR/ConstantRange.h
@@ -41,6 +41,7 @@ namespace llvm {
class MDNode;
class raw_ostream;
+class CmpPredicate;
struct KnownBits;
/// This class represents a range of values.
@@ -106,7 +107,7 @@ class [[nodiscard]] ConstantRange {
///
/// Example: Pred = ult and Other = i8 [2, 5) returns Result = [0, 4)
LLVM_ABI static ConstantRange
- makeAllowedICmpRegion(CmpInst::Predicate Pred, const ConstantRange &Other);
+ makeAllowedICmpRegion(CmpPredicate Pred, const ConstantRange &Other);
/// Produce the largest range such that all values in the returned range
/// satisfy the given predicate with all values contained within Other.
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 171952120fc40..dc73bcf1b657b 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -10325,7 +10325,7 @@ ConstantRange llvm::computeConstantRange(const Value *V, bool ForSigned,
computeConstantRange(Cmp->getOperand(1), /* ForSigned */ false,
UseInstrInfo, AC, I, DT, Depth + 1);
CR = CR.intersectWith(
- ConstantRange::makeAllowedICmpRegion(Cmp->getPredicate(), RHS));
+ ConstantRange::makeAllowedICmpRegion(Cmp->getCmpPredicate(), RHS));
}
}
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 9beaee60d0bc1..87d180f19470e 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -23,6 +23,7 @@
#include "llvm/IR/ConstantRange.h"
#include "llvm/ADT/APInt.h"
#include "llvm/Config/llvm-config.h"
+#include "llvm/IR/CmpPredicate.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/IR/Instruction.h"
@@ -106,7 +107,7 @@ std::pair<ConstantRange, ConstantRange> ConstantRange::splitPosNeg() const {
return {intersectWith(PosFilter), intersectWith(NegFilter)};
}
-ConstantRange ConstantRange::makeAllowedICmpRegion(CmpInst::Predicate Pred,
+ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
const ConstantRange &CR) {
if (CR.isEmptySet())
return CR;
@@ -141,6 +142,8 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpInst::Predicate Pred,
APInt UMin(CR.getUnsignedMin());
if (UMin.isMaxValue())
return getEmpty(W);
+ if (Pred.hasSameSign() && CR.isAllNonNegative())
+ return ConstantRange(std::move(UMin) + 1, APInt::getSignedMinValue(W));
return ConstantRange(std::move(UMin) + 1, APInt::getZero(W));
}
case CmpInst::ICMP_SGT: {
@@ -150,6 +153,8 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpInst::Predicate Pred,
return ConstantRange(std::move(SMin) + 1, APInt::getSignedMinValue(W));
}
case CmpInst::ICMP_UGE:
+ if (Pred.hasSameSign() && CR.isAllNonNegative())
+ return getNonEmpty(CR.getUnsignedMin(), APInt::getSignedMinValue(W));
return getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W));
case CmpInst::ICMP_SGE:
return getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W));
>From 94734c35f264ec5a1cf8e0ea1efab11a4f51ee40 Mon Sep 17 00:00:00 2001
From: Adar Dagan <adar.dagan at mobileye.com>
Date: Thu, 15 Jan 2026 07:48:32 +0200
Subject: [PATCH 2/6] Add tests
---
llvm/test/Transforms/InstCombine/assume.ll | 13 +++++
llvm/unittests/Analysis/ValueTrackingTest.cpp | 49 +++++++++++++++++++
2 files changed, 62 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/assume.ll b/llvm/test/Transforms/InstCombine/assume.ll
index cc87d6542fa12..85b4892093f85 100644
--- a/llvm/test/Transforms/InstCombine/assume.ll
+++ b/llvm/test/Transforms/InstCombine/assume.ll
@@ -1056,6 +1056,19 @@ define i1 @neg_assume_trunc_eq_one(i8 %x) {
ret i1 %q
}
+define i8 @remove_for_samesign(i8 %x) {
+; CHECK-LABEL: @remove_for_samesign(
+; CHECK-NEXT: [[LT:%.*]] = icmp samesign ugt i8 [[X:%.*]], 10
+; CHECK-NEXT: call void @llvm.assume(i1 [[LT]])
+; CHECK-NEXT: ret i8 [[X]]
+;
+ %gt = icmp sgt i8 %x, 10
+ call void @llvm.assume(i1 %gt)
+ %gt.zero = icmp sge i8 %x, 0
+ call void @llvm.assume(i1 %gt.zero)
+ ret i8 %x
+}
+
declare void @use(i1)
declare void @llvm.dbg.value(metadata, metadata, metadata)
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 1707ed2c39264..5356d4cfb5d12 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -3234,6 +3234,55 @@ TEST_F(ValueTrackingTest, ComputeConstantRange) {
EXPECT_EQ(10, CR2.getUpper());
}
+ {
+ // Assumptions:
+ // * stride >= 5 (unsigned)
+ //
+ // stride = [5, 0)
+ auto M = parseModule(R"(
+ declare void @llvm.assume(i1)
+
+ define i32 @test(i32 %stride) {
+ %gt = icmp uge i32 %stride, 5
+ call void @llvm.assume(i1 %gt)
+ %stride.plus.one = add nsw nuw i32 %stride, 1
+ ret i32 %stride.plus.one
+ })");
+ Function *F = M->getFunction("test");
+
+ AssumptionCache AC(*F);
+ Value *Stride = &*F->arg_begin();
+
+ Instruction *I = &findInstructionByName(F, "stride.plus.one");
+ ConstantRange CR2 = computeConstantRange(Stride, false, true, &AC, I);
+ EXPECT_EQ(5, CR2.getLower());
+ EXPECT_EQ(0, CR2.getUpper());
+ }
+ {
+ // Assumptions:
+ // * stride >= 5 (samesign unsigned)
+ //
+ // stride = [5, MIN_SIGNED)
+ auto M = parseModule(R"(
+ declare void @llvm.assume(i1)
+
+ define i32 @test(i32 %stride) {
+ %gt = icmp samesign uge i32 %stride, 5
+ call void @llvm.assume(i1 %gt)
+ %stride.plus.one = add nsw nuw i32 %stride, 1
+ ret i32 %stride.plus.one
+ })");
+ Function *F = M->getFunction("test");
+
+ AssumptionCache AC(*F);
+ Value *Stride = &*F->arg_begin();
+
+ Instruction *I = &findInstructionByName(F, "stride.plus.one");
+ ConstantRange CR2 = computeConstantRange(Stride, false, true, &AC, I);
+ EXPECT_EQ(5, CR2.getLower());
+ EXPECT_EQ(APInt::getSignedMinValue(32), CR2.getUpper());
+ }
+
{
// Assumptions:
// * stride >= 5
>From a36100962c0f6851df18a28d2c4c362e5b12d867 Mon Sep 17 00:00:00 2001
From: Adar Dagan <adar.dagan at mobileye.com>
Date: Sun, 18 Jan 2026 10:31:45 +0200
Subject: [PATCH 3/6] Fix comments and add tests
---
llvm/lib/IR/ConstantRange.cpp | 5 ++-
llvm/test/Transforms/InstCombine/assume.ll | 13 -------
llvm/unittests/IR/ConstantRangeTest.cpp | 40 ++++++++++++++++++++++
3 files changed, 44 insertions(+), 14 deletions(-)
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 87d180f19470e..d68a1db53a86f 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -142,8 +142,11 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
APInt UMin(CR.getUnsignedMin());
if (UMin.isMaxValue())
return getEmpty(W);
- if (Pred.hasSameSign() && CR.isAllNonNegative())
+ if (Pred.hasSameSign() && CR.isAllNonNegative()) {
+ if (W == 1)
+ return ConstantRange::getEmpty(W);
return ConstantRange(std::move(UMin) + 1, APInt::getSignedMinValue(W));
+ }
return ConstantRange(std::move(UMin) + 1, APInt::getZero(W));
}
case CmpInst::ICMP_SGT: {
diff --git a/llvm/test/Transforms/InstCombine/assume.ll b/llvm/test/Transforms/InstCombine/assume.ll
index 85b4892093f85..cc87d6542fa12 100644
--- a/llvm/test/Transforms/InstCombine/assume.ll
+++ b/llvm/test/Transforms/InstCombine/assume.ll
@@ -1056,19 +1056,6 @@ define i1 @neg_assume_trunc_eq_one(i8 %x) {
ret i1 %q
}
-define i8 @remove_for_samesign(i8 %x) {
-; CHECK-LABEL: @remove_for_samesign(
-; CHECK-NEXT: [[LT:%.*]] = icmp samesign ugt i8 [[X:%.*]], 10
-; CHECK-NEXT: call void @llvm.assume(i1 [[LT]])
-; CHECK-NEXT: ret i8 [[X]]
-;
- %gt = icmp sgt i8 %x, 10
- call void @llvm.assume(i1 %gt)
- %gt.zero = icmp sge i8 %x, 0
- call void @llvm.assume(i1 %gt.zero)
- ret i8 %x
-}
-
declare void @use(i1)
declare void @llvm.dbg.value(metadata, metadata, metadata)
diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp
index 13712a76d3edf..ede04f7279a1c 100644
--- a/llvm/unittests/IR/ConstantRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeTest.cpp
@@ -1728,6 +1728,46 @@ TEST(ConstantRange, MakeAllowedICmpRegionEdgeCases) {
.isSingleElement());
EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(ICmpInst::ICMP_UGE, UMin)
.isFullSet());
+
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_UGE, /*HasSameSign=*/true), UMin),
+ ConstantRange::getNonEmpty(APInt::getMinValue(8),
+ APInt::getSignedMinValue(8)));
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_UGT, /*HasSameSign=*/true), UMin),
+ ConstantRange::getNonEmpty(APInt::getMinValue(8) + 1,
+ APInt::getSignedMinValue(8)));
+}
+
+TEST(ConstantRange, MakeAllowedICmpRegionBoolean) {
+ ConstantRange One(APInt(1, 1));
+ ConstantRange Zero(APInt(1, 0));
+
+ EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_UGE, /*HasSameSign=*/false), Zero)
+ .isFullSet());
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_UGE, /*HasSameSign=*/false), One),
+ One);
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_UGE, /*HasSameSign=*/true), Zero),
+ Zero);
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_UGE, /*HasSameSign=*/true), One),
+ One);
+
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_UGT, /*HasSameSign=*/false), Zero),
+ One);
+ EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_UGT, /*HasSameSign=*/false), One)
+ .isEmptySet());
+ EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_UGT, /*HasSameSign=*/true), Zero)
+ .isEmptySet());
+ EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_UGT, /*HasSameSign=*/true), One)
+ .isEmptySet());
}
TEST(ConstantRange, MakeExactICmpRegion) {
>From 8f3757d4ee22ce69235482ba778e5cf6b5ce3ce7 Mon Sep 17 00:00:00 2001
From: Adar Dagan <adar.dagan at mobileye.com>
Date: Wed, 28 Jan 2026 16:52:44 +0200
Subject: [PATCH 4/6] Fix more comments
---
llvm/lib/IR/ConstantRange.cpp | 29 +++++--
llvm/unittests/Analysis/ValueTrackingTest.cpp | 51 ++++++++++++
llvm/unittests/IR/ConstantRangeTest.cpp | 83 +++++++++++++++++--
3 files changed, 150 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index d68a1db53a86f..84fdf87d22f97 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -126,6 +126,12 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
APInt UMax(CR.getUnsignedMax());
if (UMax.isMinValue())
return getEmpty(W);
+ if (Pred.hasSameSign()) {
+ if (W == 1)
+ return getEmpty(W);
+ if (CR.isAllNegative() || (!CR.isAllPositive() && !CR.isSignWrappedSet()))
+ return getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax());
+ }
return ConstantRange(APInt::getMinValue(W), std::move(UMax));
}
case CmpInst::ICMP_SLT: {
@@ -135,6 +141,12 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
return ConstantRange(APInt::getSignedMinValue(W), std::move(SMax));
}
case CmpInst::ICMP_ULE:
+ if (Pred.hasSameSign()) {
+ if (W == 1)
+ return CR;
+ if (CR.isAllNegative() || (!CR.isAllPositive() && !CR.isSignWrappedSet()))
+ return getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax() + 1);
+ }
return getNonEmpty(APInt::getMinValue(W), CR.getUnsignedMax() + 1);
case CmpInst::ICMP_SLE:
return getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax() + 1);
@@ -142,10 +154,13 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
APInt UMin(CR.getUnsignedMin());
if (UMin.isMaxValue())
return getEmpty(W);
- if (Pred.hasSameSign() && CR.isAllNonNegative()) {
+ if (Pred.hasSameSign()) {
if (W == 1)
- return ConstantRange::getEmpty(W);
- return ConstantRange(std::move(UMin) + 1, APInt::getSignedMinValue(W));
+ return getEmpty(W);
+ if (CR.isAllNonNegative())
+ return ConstantRange(std::move(UMin) + 1, APInt::getSignedMinValue(W));
+ if (!(CR.isAllNegative() || CR.isSignWrappedSet()))
+ return getNonEmpty(CR.getSignedMin() + 1, APInt::getSignedMinValue(W));
}
return ConstantRange(std::move(UMin) + 1, APInt::getZero(W));
}
@@ -156,8 +171,12 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
return ConstantRange(std::move(SMin) + 1, APInt::getSignedMinValue(W));
}
case CmpInst::ICMP_UGE:
- if (Pred.hasSameSign() && CR.isAllNonNegative())
- return getNonEmpty(CR.getUnsignedMin(), APInt::getSignedMinValue(W));
+ if (Pred.hasSameSign()) {
+ if (CR.isAllNonNegative())
+ return getNonEmpty(CR.getUnsignedMin(), APInt::getSignedMinValue(W));
+ if (!(CR.isAllNegative() || CR.isSignWrappedSet()))
+ return getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W));
+ }
return getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W));
case CmpInst::ICMP_SGE:
return getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W));
diff --git a/llvm/unittests/Analysis/ValueTrackingTest.cpp b/llvm/unittests/Analysis/ValueTrackingTest.cpp
index 5356d4cfb5d12..ef839d07b174c 100644
--- a/llvm/unittests/Analysis/ValueTrackingTest.cpp
+++ b/llvm/unittests/Analysis/ValueTrackingTest.cpp
@@ -3258,6 +3258,32 @@ TEST_F(ValueTrackingTest, ComputeConstantRange) {
EXPECT_EQ(5, CR2.getLower());
EXPECT_EQ(0, CR2.getUpper());
}
+
+ {
+ // Assumptions:
+ // * stride > 5 (unsigned)
+ //
+ // stride = [5, 0)
+ auto M = parseModule(R"(
+ declare void @llvm.assume(i1)
+
+ define i32 @test(i32 %stride) {
+ %gt = icmp ugt i32 %stride, 5
+ call void @llvm.assume(i1 %gt)
+ %stride.plus.one = add nsw nuw i32 %stride, 1
+ ret i32 %stride.plus.one
+ })");
+ Function *F = M->getFunction("test");
+
+ AssumptionCache AC(*F);
+ Value *Stride = &*F->arg_begin();
+
+ Instruction *I = &findInstructionByName(F, "stride.plus.one");
+ ConstantRange CR2 = computeConstantRange(Stride, false, true, &AC, I);
+ EXPECT_EQ(6, CR2.getLower());
+ EXPECT_EQ(0, CR2.getUpper());
+ }
+
{
// Assumptions:
// * stride >= 5 (samesign unsigned)
@@ -3283,6 +3309,31 @@ TEST_F(ValueTrackingTest, ComputeConstantRange) {
EXPECT_EQ(APInt::getSignedMinValue(32), CR2.getUpper());
}
+ {
+ // Assumptions:
+ // * stride > 5 (samesign unsigned)
+ //
+ // stride = [5, MIN_SIGNED)
+ auto M = parseModule(R"(
+ declare void @llvm.assume(i1)
+
+ define i32 @test(i32 %stride) {
+ %gt = icmp samesign ugt i32 %stride, 5
+ call void @llvm.assume(i1 %gt)
+ %stride.plus.one = add nsw nuw i32 %stride, 1
+ ret i32 %stride.plus.one
+ })");
+ Function *F = M->getFunction("test");
+
+ AssumptionCache AC(*F);
+ Value *Stride = &*F->arg_begin();
+
+ Instruction *I = &findInstructionByName(F, "stride.plus.one");
+ ConstantRange CR2 = computeConstantRange(Stride, false, true, &AC, I);
+ EXPECT_EQ(6, CR2.getLower());
+ EXPECT_EQ(APInt::getSignedMinValue(32), CR2.getUpper());
+ }
+
{
// Assumptions:
// * stride >= 5
diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp
index ede04f7279a1c..568e3a984d2fc 100644
--- a/llvm/unittests/IR/ConstantRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeTest.cpp
@@ -10,6 +10,7 @@
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/Sequence.h"
#include "llvm/ADT/SmallBitVector.h"
+#include "llvm/IR/CmpPredicate.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Operator.h"
#include "llvm/Support/KnownBits.h"
@@ -1728,15 +1729,55 @@ TEST(ConstantRange, MakeAllowedICmpRegionEdgeCases) {
.isSingleElement());
EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(ICmpInst::ICMP_UGE, UMin)
.isFullSet());
+}
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_UGE, /*HasSameSign=*/true), UMin),
- ConstantRange::getNonEmpty(APInt::getMinValue(8),
- APInt::getSignedMinValue(8)));
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_UGT, /*HasSameSign=*/true), UMin),
- ConstantRange::getNonEmpty(APInt::getMinValue(8) + 1,
- APInt::getSignedMinValue(8)));
+TEST(ConstantRange, MakeAllowedICmpRegionSameSign) {
+ APInt Positive(8, 10);
+ APInt Negative(8, -10, true);
+ ConstantRange AllPositive(Positive);
+ ConstantRange AllNegative(Negative);
+ ConstantRange BothPosAndNeg(Negative, Positive + 1);
+ ConstantRange Wrapped(Positive, Negative + 1);
+
+ CmpPredicate UGE(ICmpInst::ICMP_UGE, true);
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGE, AllPositive),
+ ConstantRange(Positive, APInt::getSignedMinValue(8)));
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGE, AllNegative),
+ ConstantRange(Negative, APInt::getZero(8)));
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGE, BothPosAndNeg),
+ ConstantRange(Negative, APInt::getSignedMinValue(8)));
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGE, Wrapped),
+ ConstantRange(Positive, APInt::getMinValue(8)));
+
+ CmpPredicate UGT(ICmpInst::ICMP_UGT, true);
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGT, AllPositive),
+ ConstantRange(Positive + 1, APInt::getSignedMinValue(8)));
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGT, AllNegative),
+ ConstantRange(Negative + 1, APInt::getZero(8)));
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGT, BothPosAndNeg),
+ ConstantRange(Negative + 1, APInt::getSignedMinValue(8)));
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGT, Wrapped),
+ ConstantRange(Positive + 1, APInt::getMinValue(8)));
+
+ CmpPredicate ULE(ICmpInst::ICMP_ULE, true);
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULE, AllPositive),
+ ConstantRange(APInt::getZero(8), Positive + 1));
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULE, AllNegative),
+ ConstantRange(APInt::getSignedMinValue(8), Negative + 1));
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULE, BothPosAndNeg),
+ ConstantRange(APInt::getSignedMinValue(8), Positive + 1));
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULE, Wrapped),
+ ConstantRange(APInt::getZero(8), Negative + 1));
+
+ CmpPredicate ULT(ICmpInst::ICMP_ULT, true);
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULT, AllPositive),
+ ConstantRange(APInt::getZero(8), Positive));
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULT, AllNegative),
+ ConstantRange(APInt::getSignedMinValue(8), Negative));
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULT, BothPosAndNeg),
+ ConstantRange(APInt::getSignedMinValue(8), Positive));
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULT, Wrapped),
+ ConstantRange(APInt::getZero(8), Negative));
}
TEST(ConstantRange, MakeAllowedICmpRegionBoolean) {
@@ -1768,6 +1809,32 @@ TEST(ConstantRange, MakeAllowedICmpRegionBoolean) {
EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
CmpPredicate(ICmpInst::ICMP_UGT, /*HasSameSign=*/true), One)
.isEmptySet());
+
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_ULE, /*HasSameSign=*/false), Zero),
+ Zero);
+ EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_ULE, /*HasSameSign=*/false), One)
+ .isFullSet());
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_ULE, /*HasSameSign=*/true), Zero),
+ Zero);
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_ULE, /*HasSameSign=*/true), One),
+ One);
+
+ EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_ULT, /*HasSameSign=*/false), Zero)
+ .isEmptySet());
+ EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_ULT, /*HasSameSign=*/false), One),
+ Zero);
+ EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_ULT, /*HasSameSign=*/true), Zero)
+ .isEmptySet());
+ EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
+ CmpPredicate(ICmpInst::ICMP_ULT, /*HasSameSign=*/true), One)
+ .isEmptySet());
}
TEST(ConstantRange, MakeExactICmpRegion) {
>From 1c98459d2ab64fd3a5b34b9e0cc639ab897ca926 Mon Sep 17 00:00:00 2001
From: Adar Dagan <adar.dagan at mobileye.com>
Date: Sun, 1 Feb 2026 08:07:21 +0200
Subject: [PATCH 5/6] Use exhaustive test function and improve robustness
---
llvm/lib/IR/ConstantRange.cpp | 83 ++++++++-----
llvm/unittests/IR/ConstantRangeTest.cpp | 158 +++++++++---------------
2 files changed, 110 insertions(+), 131 deletions(-)
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 84fdf87d22f97..ff640b00d6093 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -126,13 +126,26 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
APInt UMax(CR.getUnsignedMax());
if (UMax.isMinValue())
return getEmpty(W);
- if (Pred.hasSameSign()) {
- if (W == 1)
- return getEmpty(W);
- if (CR.isAllNegative() || (!CR.isAllPositive() && !CR.isSignWrappedSet()))
- return getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax());
- }
- return ConstantRange(APInt::getMinValue(W), std::move(UMax));
+ if (!Pred.hasSameSign())
+ return ConstantRange(APInt::getMinValue(W), std::move(UMax));
+ if (W == 1)
+ return getEmpty(W);
+
+ // deal with edge cases
+ APInt AugmentedUpper = CR.getUpper();
+ if (CR.getUnsignedMax().isMinSignedValue())
+ AugmentedUpper = APInt::getSignedMinValue(W);
+ else if (CR.getSignedMax().isMinValue())
+ AugmentedUpper = APInt::getMinValue(W);
+
+ if (AugmentedUpper == CR.getLower() && !CR.isFullSet())
+ return getEmpty(W);
+
+ ConstantRange Augmented(CR.getLower(), AugmentedUpper);
+ if (Augmented.isAllNonNegative() ||
+ (!Augmented.isAllNegative() && Augmented.isSignWrappedSet()))
+ return getNonEmpty(APInt::getMinValue(W), Augmented.getUnsignedMax());
+ return getNonEmpty(APInt::getSignedMinValue(W), Augmented.getSignedMax());
}
case CmpInst::ICMP_SLT: {
APInt SMax(CR.getSignedMax());
@@ -141,12 +154,13 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
return ConstantRange(APInt::getSignedMinValue(W), std::move(SMax));
}
case CmpInst::ICMP_ULE:
- if (Pred.hasSameSign()) {
- if (W == 1)
- return CR;
- if (CR.isAllNegative() || (!CR.isAllPositive() && !CR.isSignWrappedSet()))
- return getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax() + 1);
- }
+ if (!Pred.hasSameSign())
+ return getNonEmpty(APInt::getMinValue(W), CR.getUnsignedMax() + 1);
+ if (W == 1)
+ return CR;
+ if (CR.isAllNegative() ||
+ (!CR.isAllNonNegative() && !CR.isSignWrappedSet()))
+ return getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax() + 1);
return getNonEmpty(APInt::getMinValue(W), CR.getUnsignedMax() + 1);
case CmpInst::ICMP_SLE:
return getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax() + 1);
@@ -154,15 +168,28 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
APInt UMin(CR.getUnsignedMin());
if (UMin.isMaxValue())
return getEmpty(W);
- if (Pred.hasSameSign()) {
- if (W == 1)
- return getEmpty(W);
- if (CR.isAllNonNegative())
- return ConstantRange(std::move(UMin) + 1, APInt::getSignedMinValue(W));
- if (!(CR.isAllNegative() || CR.isSignWrappedSet()))
- return getNonEmpty(CR.getSignedMin() + 1, APInt::getSignedMinValue(W));
- }
- return ConstantRange(std::move(UMin) + 1, APInt::getZero(W));
+ if (!Pred.hasSameSign())
+ return ConstantRange(std::move(UMin) + 1, APInt::getZero(W));
+ if (W == 1)
+ return getEmpty(W);
+
+ // deal with edge cases
+ APInt AugmentedLower = CR.getLower();
+ if (CR.getLower().isMaxSignedValue())
+ AugmentedLower = APInt::getSignedMinValue(W);
+ else if (CR.getLower().isMaxValue())
+ AugmentedLower = APInt::getMinValue(W);
+
+ if (AugmentedLower == CR.getUpper())
+ return getEmpty(W);
+
+ ConstantRange Augmented(AugmentedLower, CR.getUpper());
+ if (Augmented.isAllNegative())
+ return getNonEmpty(Augmented.getSignedMin() + 1, APInt::getZero(W));
+ if (!Augmented.isAllNonNegative() && Augmented.isSignWrappedSet())
+ return getNonEmpty(Augmented.getUnsignedMin() + 1, APInt::getZero(W));
+ return getNonEmpty(Augmented.getSignedMin() + 1,
+ APInt::getSignedMinValue(W));
}
case CmpInst::ICMP_SGT: {
APInt SMin(CR.getSignedMin());
@@ -171,12 +198,12 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
return ConstantRange(std::move(SMin) + 1, APInt::getSignedMinValue(W));
}
case CmpInst::ICMP_UGE:
- if (Pred.hasSameSign()) {
- if (CR.isAllNonNegative())
- return getNonEmpty(CR.getUnsignedMin(), APInt::getSignedMinValue(W));
- if (!(CR.isAllNegative() || CR.isSignWrappedSet()))
- return getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W));
- }
+ if (!Pred.hasSameSign())
+ return getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W));
+
+ if (CR.isAllNonNegative() ||
+ (!CR.isAllNegative() && !CR.isSignWrappedSet()))
+ return getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W));
return getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W));
case CmpInst::ICMP_SGE:
return getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W));
diff --git a/llvm/unittests/IR/ConstantRangeTest.cpp b/llvm/unittests/IR/ConstantRangeTest.cpp
index 568e3a984d2fc..bb6b2a1cb7249 100644
--- a/llvm/unittests/IR/ConstantRangeTest.cpp
+++ b/llvm/unittests/IR/ConstantRangeTest.cpp
@@ -1731,110 +1731,62 @@ TEST(ConstantRange, MakeAllowedICmpRegionEdgeCases) {
.isFullSet());
}
-TEST(ConstantRange, MakeAllowedICmpRegionSameSign) {
- APInt Positive(8, 10);
- APInt Negative(8, -10, true);
- ConstantRange AllPositive(Positive);
- ConstantRange AllNegative(Negative);
- ConstantRange BothPosAndNeg(Negative, Positive + 1);
- ConstantRange Wrapped(Positive, Negative + 1);
-
- CmpPredicate UGE(ICmpInst::ICMP_UGE, true);
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGE, AllPositive),
- ConstantRange(Positive, APInt::getSignedMinValue(8)));
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGE, AllNegative),
- ConstantRange(Negative, APInt::getZero(8)));
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGE, BothPosAndNeg),
- ConstantRange(Negative, APInt::getSignedMinValue(8)));
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGE, Wrapped),
- ConstantRange(Positive, APInt::getMinValue(8)));
-
- CmpPredicate UGT(ICmpInst::ICMP_UGT, true);
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGT, AllPositive),
- ConstantRange(Positive + 1, APInt::getSignedMinValue(8)));
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGT, AllNegative),
- ConstantRange(Negative + 1, APInt::getZero(8)));
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGT, BothPosAndNeg),
- ConstantRange(Negative + 1, APInt::getSignedMinValue(8)));
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(UGT, Wrapped),
- ConstantRange(Positive + 1, APInt::getMinValue(8)));
-
- CmpPredicate ULE(ICmpInst::ICMP_ULE, true);
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULE, AllPositive),
- ConstantRange(APInt::getZero(8), Positive + 1));
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULE, AllNegative),
- ConstantRange(APInt::getSignedMinValue(8), Negative + 1));
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULE, BothPosAndNeg),
- ConstantRange(APInt::getSignedMinValue(8), Positive + 1));
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULE, Wrapped),
- ConstantRange(APInt::getZero(8), Negative + 1));
-
- CmpPredicate ULT(ICmpInst::ICMP_ULT, true);
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULT, AllPositive),
- ConstantRange(APInt::getZero(8), Positive));
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULT, AllNegative),
- ConstantRange(APInt::getSignedMinValue(8), Negative));
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULT, BothPosAndNeg),
- ConstantRange(APInt::getSignedMinValue(8), Positive));
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(ULT, Wrapped),
- ConstantRange(APInt::getZero(8), Negative));
-}
-
-TEST(ConstantRange, MakeAllowedICmpRegionBoolean) {
- ConstantRange One(APInt(1, 1));
- ConstantRange Zero(APInt(1, 0));
-
- EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_UGE, /*HasSameSign=*/false), Zero)
- .isFullSet());
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_UGE, /*HasSameSign=*/false), One),
- One);
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_UGE, /*HasSameSign=*/true), Zero),
- Zero);
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_UGE, /*HasSameSign=*/true), One),
- One);
-
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_UGT, /*HasSameSign=*/false), Zero),
- One);
- EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_UGT, /*HasSameSign=*/false), One)
- .isEmptySet());
- EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_UGT, /*HasSameSign=*/true), Zero)
- .isEmptySet());
- EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_UGT, /*HasSameSign=*/true), One)
- .isEmptySet());
+template <typename SIV>
+auto getSameSignTester(SIV ShouldIncludeValue, CmpInst::Predicate Cmp) {
+ return [Cmp, ShouldIncludeValue](const ConstantRange &CR) {
+ uint32_t BitWidth = CR.getBitWidth();
+ unsigned Max = 1 << BitWidth;
+ SmallBitVector Elems(Max);
+ if (!CR.isEmptySet()) {
+ for (unsigned I : llvm::seq(Max)) {
+ APInt Current(BitWidth, I);
+ if (ShouldIncludeValue(Current, CR))
+ Elems.set(I);
+ }
+ }
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_ULE, /*HasSameSign=*/false), Zero),
- Zero);
- EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_ULE, /*HasSameSign=*/false), One)
- .isFullSet());
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_ULE, /*HasSameSign=*/true), Zero),
- Zero);
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_ULE, /*HasSameSign=*/true), One),
- One);
-
- EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_ULT, /*HasSameSign=*/false), Zero)
- .isEmptySet());
- EXPECT_EQ(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_ULT, /*HasSameSign=*/false), One),
- Zero);
- EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_ULT, /*HasSameSign=*/true), Zero)
- .isEmptySet());
- EXPECT_TRUE(ConstantRange::makeAllowedICmpRegion(
- CmpPredicate(ICmpInst::ICMP_ULT, /*HasSameSign=*/true), One)
- .isEmptySet());
+ CmpPredicate CmpPred(Cmp, true);
+ TestRange(ConstantRange::makeAllowedICmpRegion(CmpPred, CR), Elems,
+ PreferSmallest, {});
+ };
+}
+
+TEST(ConstantRange, MakeAllowedICmpRegionExaustive) {
+ EnumerateInterestingConstantRanges(getSameSignTester(
+ [](const APInt &A, const ConstantRange &B) {
+ if (A.isNegative())
+ return A.sge(B.getSignedMin());
+ return A.uge(B.getUnsignedMin());
+ },
+ ICmpInst::ICMP_UGE));
+
+ EnumerateInterestingConstantRanges(getSameSignTester(
+ [](const APInt &A, const ConstantRange &B) {
+ if (A.isNegative())
+ return A.sgt(B.getSignedMin());
+ return A.ugt(B.getUnsignedMin());
+ },
+ ICmpInst::ICMP_UGT));
+
+ EnumerateInterestingConstantRanges(getSameSignTester(
+ [](const APInt &A, const ConstantRange &B) {
+ if (A.isNegative() && B.getUnsignedMax().isNegative())
+ return A.sle(B.getUnsignedMax());
+ if (A.isNonNegative() && B.getSignedMax().isNonNegative())
+ return A.ule(B.getSignedMax());
+ return false;
+ },
+ ICmpInst::ICMP_ULE));
+
+ EnumerateInterestingConstantRanges(getSameSignTester(
+ [](const APInt &A, const ConstantRange &B) {
+ if (A.isNegative() && B.getUnsignedMax().isNegative())
+ return A.slt(B.getUnsignedMax());
+ if (A.isNonNegative() && B.getSignedMax().isNonNegative())
+ return A.ult(B.getSignedMax());
+ return false;
+ },
+ ICmpInst::ICMP_ULT));
}
TEST(ConstantRange, MakeExactICmpRegion) {
>From e94c036b5ac90dcb42b33b74aad3fae09e2fa187 Mon Sep 17 00:00:00 2001
From: Adar Dagan <adar.dagan at mobileye.com>
Date: Thu, 5 Feb 2026 09:42:11 +0200
Subject: [PATCH 6/6] Add suggestion
---
llvm/lib/IR/ConstantRange.cpp | 7 ++-----
1 file changed, 2 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index ff640b00d6093..79a75b9b45fd0 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -198,11 +198,8 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
return ConstantRange(std::move(SMin) + 1, APInt::getSignedMinValue(W));
}
case CmpInst::ICMP_UGE:
- if (!Pred.hasSameSign())
- return getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W));
-
- if (CR.isAllNonNegative() ||
- (!CR.isAllNegative() && !CR.isSignWrappedSet()))
+ if (Pred.hasSameSign() && (CR.isAllNonNegative() ||
+ (!CR.isAllNegative() && !CR.isSignWrappedSet())))
return getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W));
return getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W));
case CmpInst::ICMP_SGE:
More information about the llvm-commits
mailing list