[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