[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 Apr 15 01:16:58 PDT 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 01/10] 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 02/10] 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 03/10] 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 04/10] 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 05/10] 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 004eb60d39d5c46fd1b3663a7b01839241010917 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 06/10] 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:
>From 210546d6fc4cad7a1ad2afc1eaf692197c8d73c1 Mon Sep 17 00:00:00 2001
From: Adar Dagan <adar.dagan at mobileye.com>
Date: Mon, 9 Feb 2026 17:33:12 +0200
Subject: [PATCH 07/10] Fix comments
---
llvm/lib/IR/ConstantRange.cpp | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 79a75b9b45fd0..86343b0a83ca1 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -131,17 +131,16 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
if (W == 1)
return getEmpty(W);
- // deal with edge cases
- APInt AugmentedUpper = CR.getUpper();
+ APInt CRUpper = CR.getUpper();
if (CR.getUnsignedMax().isMinSignedValue())
- AugmentedUpper = APInt::getSignedMinValue(W);
+ CRUpper = APInt::getSignedMinValue(W);
else if (CR.getSignedMax().isMinValue())
- AugmentedUpper = APInt::getMinValue(W);
+ CRUpper = APInt::getMinValue(W);
- if (AugmentedUpper == CR.getLower() && !CR.isFullSet())
+ if (CRUpper == CR.getLower() && !CR.isFullSet())
return getEmpty(W);
- ConstantRange Augmented(CR.getLower(), AugmentedUpper);
+ ConstantRange Augmented(CR.getLower(), CRUpper);
if (Augmented.isAllNonNegative() ||
(!Augmented.isAllNegative() && Augmented.isSignWrappedSet()))
return getNonEmpty(APInt::getMinValue(W), Augmented.getUnsignedMax());
@@ -156,8 +155,6 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
case CmpInst::ICMP_ULE:
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);
@@ -174,16 +171,16 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
return getEmpty(W);
// deal with edge cases
- APInt AugmentedLower = CR.getLower();
+ APInt CRLower = CR.getLower();
if (CR.getLower().isMaxSignedValue())
- AugmentedLower = APInt::getSignedMinValue(W);
+ CRLower = APInt::getSignedMinValue(W);
else if (CR.getLower().isMaxValue())
- AugmentedLower = APInt::getMinValue(W);
+ CRLower = APInt::getMinValue(W);
- if (AugmentedLower == CR.getUpper())
+ if (CRLower == CR.getUpper())
return getEmpty(W);
- ConstantRange Augmented(AugmentedLower, CR.getUpper());
+ ConstantRange Augmented(CRLower, CR.getUpper());
if (Augmented.isAllNegative())
return getNonEmpty(Augmented.getSignedMin() + 1, APInt::getZero(W));
if (!Augmented.isAllNonNegative() && Augmented.isSignWrappedSet())
>From 3727dd17e497cab7107cb0bddb3a8b593c435a2d Mon Sep 17 00:00:00 2001
From: Adar Dagan <adar.dagan at mobileye.com>
Date: Thu, 26 Feb 2026 10:15:08 +0200
Subject: [PATCH 08/10] Use fallthrough to get signed range
---
llvm/lib/IR/ConstantRange.cpp | 84 +++++++++++++----------------------
1 file changed, 30 insertions(+), 54 deletions(-)
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 86343b0a83ca1..2a393cdc904f3 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -113,6 +113,7 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
return CR;
uint32_t W = CR.getBitWidth();
+ ConstantRange Result = getFull(W);
switch (Pred) {
default:
llvm_unreachable("Invalid ICmp predicate to makeAllowedICmpRegion()");
@@ -126,81 +127,56 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
APInt UMax(CR.getUnsignedMax());
if (UMax.isMinValue())
return getEmpty(W);
+ Result = ConstantRange(APInt::getMinValue(W), std::move(UMax));
if (!Pred.hasSameSign())
- return ConstantRange(APInt::getMinValue(W), std::move(UMax));
- if (W == 1)
- return getEmpty(W);
-
- APInt CRUpper = CR.getUpper();
- if (CR.getUnsignedMax().isMinSignedValue())
- CRUpper = APInt::getSignedMinValue(W);
- else if (CR.getSignedMax().isMinValue())
- CRUpper = APInt::getMinValue(W);
-
- if (CRUpper == CR.getLower() && !CR.isFullSet())
- return getEmpty(W);
-
- ConstantRange Augmented(CR.getLower(), CRUpper);
- if (Augmented.isAllNonNegative() ||
- (!Augmented.isAllNegative() && Augmented.isSignWrappedSet()))
- return getNonEmpty(APInt::getMinValue(W), Augmented.getUnsignedMax());
- return getNonEmpty(APInt::getSignedMinValue(W), Augmented.getSignedMax());
+ return Result;
}
+ // For samesign, intersect with signed range.
+ LLVM_FALLTHROUGH;
case CmpInst::ICMP_SLT: {
APInt SMax(CR.getSignedMax());
if (SMax.isMinSignedValue())
return getEmpty(W);
- return ConstantRange(APInt::getSignedMinValue(W), std::move(SMax));
+ return Result.intersectWith(
+ ConstantRange(APInt::getSignedMinValue(W), std::move(SMax)));
}
- case CmpInst::ICMP_ULE:
+ case CmpInst::ICMP_ULE: {
+ Result = getNonEmpty(APInt::getMinValue(W), CR.getUnsignedMax() + 1);
if (!Pred.hasSameSign())
- return getNonEmpty(APInt::getMinValue(W), CR.getUnsignedMax() + 1);
- if (CR.isAllNegative() ||
- (!CR.isAllNonNegative() && !CR.isSignWrappedSet()))
- return getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax() + 1);
- return getNonEmpty(APInt::getMinValue(W), CR.getUnsignedMax() + 1);
+ return Result;
+ }
+ // For samesign, intersect with signed range.
+ LLVM_FALLTHROUGH;
case CmpInst::ICMP_SLE:
- return getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax() + 1);
+ return Result.intersectWith(
+ getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax() + 1));
case CmpInst::ICMP_UGT: {
APInt UMin(CR.getUnsignedMin());
if (UMin.isMaxValue())
return getEmpty(W);
+ Result = 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 CRLower = CR.getLower();
- if (CR.getLower().isMaxSignedValue())
- CRLower = APInt::getSignedMinValue(W);
- else if (CR.getLower().isMaxValue())
- CRLower = APInt::getMinValue(W);
-
- if (CRLower == CR.getUpper())
- return getEmpty(W);
-
- ConstantRange Augmented(CRLower, 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));
+ return Result;
}
+ // For samesign, intersect with signed range.
+ LLVM_FALLTHROUGH;
case CmpInst::ICMP_SGT: {
APInt SMin(CR.getSignedMin());
if (SMin.isMaxSignedValue())
return getEmpty(W);
- return ConstantRange(std::move(SMin) + 1, APInt::getSignedMinValue(W));
+ return Result.intersectWith(
+ ConstantRange(std::move(SMin) + 1, APInt::getSignedMinValue(W)));
}
- case CmpInst::ICMP_UGE:
- 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_UGE: {
+ Result = getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W));
+ if (!Pred.hasSameSign())
+ return Result;
+ }
+ // For samesign, intersect with signed range.
+ LLVM_FALLTHROUGH;
case CmpInst::ICMP_SGE:
- return getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W));
+ return Result.intersectWith(
+ getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W)));
}
}
>From 1549c1716515512073447459a323b01f74188177 Mon Sep 17 00:00:00 2001
From: Adar Dagan <adar.dagan at mobileye.com>
Date: Wed, 25 Mar 2026 09:34:01 +0200
Subject: [PATCH 09/10] Get rid of fallthrough
---
llvm/lib/IR/ConstantRange.cpp | 70 +++++++++++++++++++----------------
1 file changed, 39 insertions(+), 31 deletions(-)
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index 2a393cdc904f3..5017db37b5449 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -107,13 +107,36 @@ std::pair<ConstantRange, ConstantRange> ConstantRange::splitPosNeg() const {
return {intersectWith(PosFilter), intersectWith(NegFilter)};
}
+static ConstantRange makeAllowedSignedLT(const ConstantRange &CR, uint32_t W) {
+ APInt SMax(CR.getSignedMax());
+ if (SMax.isMinSignedValue())
+ return ConstantRange::getEmpty(W);
+ return ConstantRange(APInt::getSignedMinValue(W), std::move(SMax));
+}
+
+static ConstantRange makeAllowedSignedLE(const ConstantRange &CR, uint32_t W) {
+ return ConstantRange::getNonEmpty(APInt::getSignedMinValue(W),
+ CR.getSignedMax() + 1);
+}
+
+static ConstantRange makeAllowedSignedGT(const ConstantRange &CR, uint32_t W) {
+ APInt SMin(CR.getSignedMin());
+ if (SMin.isMaxSignedValue())
+ return ConstantRange::getEmpty(W);
+ return ConstantRange(std::move(SMin) + 1, APInt::getSignedMinValue(W));
+}
+
+static ConstantRange makeAllowedSignedGE(const ConstantRange &CR, uint32_t W) {
+ return ConstantRange::getNonEmpty(CR.getSignedMin(),
+ APInt::getSignedMinValue(W));
+}
+
ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
const ConstantRange &CR) {
if (CR.isEmptySet())
return CR;
uint32_t W = CR.getBitWidth();
- ConstantRange Result = getFull(W);
switch (Pred) {
default:
llvm_unreachable("Invalid ICmp predicate to makeAllowedICmpRegion()");
@@ -127,56 +150,41 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
APInt UMax(CR.getUnsignedMax());
if (UMax.isMinValue())
return getEmpty(W);
- Result = ConstantRange(APInt::getMinValue(W), std::move(UMax));
+ ConstantRange Result(APInt::getMinValue(W), std::move(UMax));
if (!Pred.hasSameSign())
return Result;
+ return Result.intersectWith(makeAllowedSignedLT(CR, W));
}
- // For samesign, intersect with signed range.
- LLVM_FALLTHROUGH;
- case CmpInst::ICMP_SLT: {
- APInt SMax(CR.getSignedMax());
- if (SMax.isMinSignedValue())
- return getEmpty(W);
- return Result.intersectWith(
- ConstantRange(APInt::getSignedMinValue(W), std::move(SMax)));
- }
+ case CmpInst::ICMP_SLT:
+ return makeAllowedSignedLT(CR, W);
case CmpInst::ICMP_ULE: {
- Result = getNonEmpty(APInt::getMinValue(W), CR.getUnsignedMax() + 1);
+ ConstantRange Result =
+ getNonEmpty(APInt::getMinValue(W), CR.getUnsignedMax() + 1);
if (!Pred.hasSameSign())
return Result;
+ return Result.intersectWith(makeAllowedSignedLE(CR, W));
}
- // For samesign, intersect with signed range.
- LLVM_FALLTHROUGH;
case CmpInst::ICMP_SLE:
- return Result.intersectWith(
- getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax() + 1));
+ return makeAllowedSignedLE(CR, W);
case CmpInst::ICMP_UGT: {
APInt UMin(CR.getUnsignedMin());
if (UMin.isMaxValue())
return getEmpty(W);
- Result = ConstantRange(std::move(UMin) + 1, APInt::getZero(W));
+ ConstantRange Result(std::move(UMin) + 1, APInt::getZero(W));
if (!Pred.hasSameSign())
return Result;
+ return Result.intersectWith(makeAllowedSignedGT(CR, W));
}
- // For samesign, intersect with signed range.
- LLVM_FALLTHROUGH;
- case CmpInst::ICMP_SGT: {
- APInt SMin(CR.getSignedMin());
- if (SMin.isMaxSignedValue())
- return getEmpty(W);
- return Result.intersectWith(
- ConstantRange(std::move(SMin) + 1, APInt::getSignedMinValue(W)));
- }
+ case CmpInst::ICMP_SGT:
+ return makeAllowedSignedGT(CR, W);
case CmpInst::ICMP_UGE: {
- Result = getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W));
+ ConstantRange Result = getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W));
if (!Pred.hasSameSign())
return Result;
+ return Result.intersectWith(makeAllowedSignedGE(CR, W));
}
- // For samesign, intersect with signed range.
- LLVM_FALLTHROUGH;
case CmpInst::ICMP_SGE:
- return Result.intersectWith(
- getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W)));
+ return makeAllowedSignedGE(CR, W);
}
}
>From 415084b9af3e5506ad168c3e4e600d19c9380aa4 Mon Sep 17 00:00:00 2001
From: Adar Dagan <adar.dagan at mobileye.com>
Date: Wed, 15 Apr 2026 11:15:03 +0300
Subject: [PATCH 10/10] Overload implemenation
---
llvm/include/llvm/IR/ConstantRange.h | 7 +++
llvm/lib/IR/ConstantRange.cpp | 78 ++++++++++------------------
2 files changed, 35 insertions(+), 50 deletions(-)
diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h
index 47b9b60b64b2e..4abe53a06ef87 100644
--- a/llvm/include/llvm/IR/ConstantRange.h
+++ b/llvm/include/llvm/IR/ConstantRange.h
@@ -107,6 +107,13 @@ 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);
+
+ /// Produce the smallest range such that all values that may satisfy the given
+ /// predicate with any value contained within Other is contained in the
+ /// returned range. This overload takes a CmpPredicate, which may carry
+ /// samesign information for tighter ranges on unsigned predicates.
+ LLVM_ABI static ConstantRange
makeAllowedICmpRegion(CmpPredicate Pred, const ConstantRange &Other);
/// Produce the largest range such that all values in the returned range
diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp
index c557dc34ecce6..68554ed6ab1f5 100644
--- a/llvm/lib/IR/ConstantRange.cpp
+++ b/llvm/lib/IR/ConstantRange.cpp
@@ -107,31 +107,7 @@ std::pair<ConstantRange, ConstantRange> ConstantRange::splitPosNeg() const {
return {intersectWith(PosFilter), intersectWith(NegFilter)};
}
-static ConstantRange makeAllowedSignedLT(const ConstantRange &CR, uint32_t W) {
- APInt SMax(CR.getSignedMax());
- if (SMax.isMinSignedValue())
- return ConstantRange::getEmpty(W);
- return ConstantRange(APInt::getSignedMinValue(W), std::move(SMax));
-}
-
-static ConstantRange makeAllowedSignedLE(const ConstantRange &CR, uint32_t W) {
- return ConstantRange::getNonEmpty(APInt::getSignedMinValue(W),
- CR.getSignedMax() + 1);
-}
-
-static ConstantRange makeAllowedSignedGT(const ConstantRange &CR, uint32_t W) {
- APInt SMin(CR.getSignedMin());
- if (SMin.isMaxSignedValue())
- return ConstantRange::getEmpty(W);
- return ConstantRange(std::move(SMin) + 1, APInt::getSignedMinValue(W));
-}
-
-static ConstantRange makeAllowedSignedGE(const ConstantRange &CR, uint32_t W) {
- return ConstantRange::getNonEmpty(CR.getSignedMin(),
- APInt::getSignedMinValue(W));
-}
-
-ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
+ConstantRange ConstantRange::makeAllowedICmpRegion(CmpInst::Predicate Pred,
const ConstantRange &CR) {
if (CR.isEmptySet())
return CR;
@@ -150,44 +126,46 @@ ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
APInt UMax(CR.getUnsignedMax());
if (UMax.isMinValue())
return getEmpty(W);
- ConstantRange Result(APInt::getMinValue(W), std::move(UMax));
- if (!Pred.hasSameSign())
- return Result;
- return Result.intersectWith(makeAllowedSignedLT(CR, W));
+ return ConstantRange(APInt::getMinValue(W), std::move(UMax));
}
- case CmpInst::ICMP_SLT:
- return makeAllowedSignedLT(CR, W);
- case CmpInst::ICMP_ULE: {
- ConstantRange Result =
- getNonEmpty(APInt::getMinValue(W), CR.getUnsignedMax() + 1);
- if (!Pred.hasSameSign())
- return Result;
- return Result.intersectWith(makeAllowedSignedLE(CR, W));
+ case CmpInst::ICMP_SLT: {
+ APInt SMax(CR.getSignedMax());
+ if (SMax.isMinSignedValue())
+ return getEmpty(W);
+ return ConstantRange(APInt::getSignedMinValue(W), std::move(SMax));
}
+ case CmpInst::ICMP_ULE:
+ return getNonEmpty(APInt::getMinValue(W), CR.getUnsignedMax() + 1);
case CmpInst::ICMP_SLE:
- return makeAllowedSignedLE(CR, W);
+ return getNonEmpty(APInt::getSignedMinValue(W), CR.getSignedMax() + 1);
case CmpInst::ICMP_UGT: {
APInt UMin(CR.getUnsignedMin());
if (UMin.isMaxValue())
return getEmpty(W);
- ConstantRange Result(std::move(UMin) + 1, APInt::getZero(W));
- if (!Pred.hasSameSign())
- return Result;
- return Result.intersectWith(makeAllowedSignedGT(CR, W));
+ return ConstantRange(std::move(UMin) + 1, APInt::getZero(W));
}
- case CmpInst::ICMP_SGT:
- return makeAllowedSignedGT(CR, W);
- case CmpInst::ICMP_UGE: {
- ConstantRange Result = getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W));
- if (!Pred.hasSameSign())
- return Result;
- return Result.intersectWith(makeAllowedSignedGE(CR, W));
+ case CmpInst::ICMP_SGT: {
+ APInt SMin(CR.getSignedMin());
+ if (SMin.isMaxSignedValue())
+ return getEmpty(W);
+ return ConstantRange(std::move(SMin) + 1, APInt::getSignedMinValue(W));
}
+ case CmpInst::ICMP_UGE:
+ return getNonEmpty(CR.getUnsignedMin(), APInt::getZero(W));
case CmpInst::ICMP_SGE:
- return makeAllowedSignedGE(CR, W);
+ return getNonEmpty(CR.getSignedMin(), APInt::getSignedMinValue(W));
}
}
+ConstantRange ConstantRange::makeAllowedICmpRegion(CmpPredicate Pred,
+ const ConstantRange &CR) {
+ ConstantRange Result = makeAllowedICmpRegion(Pred.dropSameSign(), CR);
+ if (!Pred.hasSameSign() || !CmpInst::isUnsigned(Pred))
+ return Result;
+ return Result.intersectWith(
+ makeAllowedICmpRegion(ICmpInst::getSignedPredicate(Pred), CR));
+}
+
ConstantRange ConstantRange::makeSatisfyingICmpRegion(CmpInst::Predicate Pred,
const ConstantRange &CR) {
// Follows from De-Morgan's laws:
More information about the llvm-commits
mailing list