[llvm] [SCCP] Strengthen two-instruction range checks (PR #162008)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Sun Oct 5 23:42:20 PDT 2025


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/162008

>From 6ef74bba5c5f79ddfdb770b90c5fa00f35443cfe Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 5 Oct 2025 19:10:45 +0800
Subject: [PATCH 1/3] [SCCP] Add pre-commit tests. NFC.

---
 .../Transforms/SCCP/relax-range-checks.ll     | 24 +++++++++++++++++++
 1 file changed, 24 insertions(+)

diff --git a/llvm/test/Transforms/SCCP/relax-range-checks.ll b/llvm/test/Transforms/SCCP/relax-range-checks.ll
index 90722f350aa9e..420b11e00ba79 100644
--- a/llvm/test/Transforms/SCCP/relax-range-checks.ll
+++ b/llvm/test/Transforms/SCCP/relax-range-checks.ll
@@ -89,4 +89,28 @@ define i1 @relax_range_check_multiuse(i8 range(i8 0, 5) %x)  {
   ret i1 %ret
 }
 
+define i1 @range_check_to_icmp_eq1(i32 range(i32 0, 4) %x) {
+; CHECK-LABEL: define i1 @range_check_to_icmp_eq1(
+; CHECK-SAME: i32 range(i32 0, 4) [[X:%.*]]) {
+; CHECK-NEXT:    [[OFF:%.*]] = add nsw i32 [[X]], -3
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp uge i32 [[X]], 3
+; CHECK-NEXT:    ret i1 [[TMP1]]
+;
+  %off = add nsw i32 %x, -3
+  %cmp = icmp ult i32 %off, 2
+  ret i1 %cmp
+}
+
+define i1 @range_check_to_icmp_eq2(i32 range(i32 -1, 2) %x) {
+; CHECK-LABEL: define i1 @range_check_to_icmp_eq2(
+; CHECK-SAME: i32 range(i32 -1, 2) [[X:%.*]]) {
+; CHECK-NEXT:    [[OFF:%.*]] = add nsw i32 [[X]], -1
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[OFF]], -2
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %off = add nsw i32 %x, -1
+  %cmp = icmp ult i32 %off, -2
+  ret i1 %cmp
+}
+
 declare void @use(i8)

>From 75dcb6acf9acec248fb1b4c814aa8d9745edde22 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 5 Oct 2025 19:24:38 +0800
Subject: [PATCH 2/3] [SCCP] Strengthen two-instruction range checks

---
 llvm/lib/Transforms/Utils/SCCPSolver.cpp      | 39 +++++++++++--------
 .../Transforms/SCCP/relax-range-checks.ll     |  4 +-
 2 files changed, 24 insertions(+), 19 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index af216cd9214bf..2e8e5ba18d933 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -317,24 +317,29 @@ static Value *simplifyInstruction(SCCPSolver &Solver,
       // Early exit if we know nothing about X.
       if (LRange.isFullSet())
         return nullptr;
-      // We are allowed to refine the comparison to either true or false for out
-      // of range inputs. Here we refine the comparison to true, i.e. we relax
-      // the range check.
-      auto NewCR = CR->exactUnionWith(LRange.inverse());
-      // TODO: Check if we can narrow the range check to an equality test.
-      // E.g, for X in [0, 4), X - 3 u< 2 -> X == 3
-      if (!NewCR)
+      auto ConvertCRToICmp =
+          [&](const std::optional<ConstantRange> &NewCR) -> Value * {
+        ICmpInst::Predicate Pred;
+        APInt RHS;
+        // Check if we can represent NewCR as an icmp predicate.
+        if (NewCR && NewCR->getEquivalentICmp(Pred, RHS)) {
+          IRBuilder<NoFolder> Builder(&Inst);
+          Value *NewICmp =
+              Builder.CreateICmp(Pred, X, ConstantInt::get(X->getType(), RHS));
+          InsertedValues.insert(NewICmp);
+          return NewICmp;
+        }
         return nullptr;
-      ICmpInst::Predicate Pred;
-      APInt RHS;
-      // Check if we can represent NewCR as an icmp predicate.
-      if (NewCR->getEquivalentICmp(Pred, RHS)) {
-        IRBuilder<NoFolder> Builder(&Inst);
-        Value *NewICmp =
-            Builder.CreateICmp(Pred, X, ConstantInt::get(X->getType(), RHS));
-        InsertedValues.insert(NewICmp);
-        return NewICmp;
-      }
+      };
+      // We are allowed to refine the comparison to either true or false for out
+      // of range inputs.
+      // Here we refine the comparison to false, and check if we can narrow the
+      // range check to an equality test.
+      if (auto *V = ConvertCRToICmp(CR->exactIntersectWith(LRange)))
+        return V;
+      // Here we refine the comparison to true, i.e. we relax the range check.
+      if (auto *V = ConvertCRToICmp(CR->exactUnionWith(LRange.inverse())))
+        return V;
     }
   }
 
diff --git a/llvm/test/Transforms/SCCP/relax-range-checks.ll b/llvm/test/Transforms/SCCP/relax-range-checks.ll
index 420b11e00ba79..34e48136df37a 100644
--- a/llvm/test/Transforms/SCCP/relax-range-checks.ll
+++ b/llvm/test/Transforms/SCCP/relax-range-checks.ll
@@ -93,7 +93,7 @@ define i1 @range_check_to_icmp_eq1(i32 range(i32 0, 4) %x) {
 ; CHECK-LABEL: define i1 @range_check_to_icmp_eq1(
 ; CHECK-SAME: i32 range(i32 0, 4) [[X:%.*]]) {
 ; CHECK-NEXT:    [[OFF:%.*]] = add nsw i32 [[X]], -3
-; CHECK-NEXT:    [[TMP1:%.*]] = icmp uge i32 [[X]], 3
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i32 [[X]], 3
 ; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %off = add nsw i32 %x, -3
@@ -105,7 +105,7 @@ define i1 @range_check_to_icmp_eq2(i32 range(i32 -1, 2) %x) {
 ; CHECK-LABEL: define i1 @range_check_to_icmp_eq2(
 ; CHECK-SAME: i32 range(i32 -1, 2) [[X:%.*]]) {
 ; CHECK-NEXT:    [[OFF:%.*]] = add nsw i32 [[X]], -1
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i32 [[OFF]], -2
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X]], 1
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %off = add nsw i32 %x, -1

>From 4b3b116cabe9f608524fd072209ff49828b29b24 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 6 Oct 2025 14:41:50 +0800
Subject: [PATCH 3/3] [SCCP] Adjust comments. NFC.

---
 llvm/lib/Transforms/Utils/SCCPSolver.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index 2e8e5ba18d933..9693ae6b8ceb5 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -334,7 +334,7 @@ static Value *simplifyInstruction(SCCPSolver &Solver,
       // We are allowed to refine the comparison to either true or false for out
       // of range inputs.
       // Here we refine the comparison to false, and check if we can narrow the
-      // range check to an equality test.
+      // range check to a simpler test.
       if (auto *V = ConvertCRToICmp(CR->exactIntersectWith(LRange)))
         return V;
       // Here we refine the comparison to true, i.e. we relax the range check.



More information about the llvm-commits mailing list