[llvm] [SCCP] Relax two-instruction range checks (PR #158495)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 14 09:14:50 PDT 2025


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

>From 19c19ca0d54a2458c8560489ceef2ba4d102f2e0 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 14 Sep 2025 23:11:30 +0800
Subject: [PATCH 1/4] [SCCP] Add pre-commit tests. NFC.

---
 .../Transforms/SCCP/relax-range-checks.ll     | 50 +++++++++++++++++++
 1 file changed, 50 insertions(+)
 create mode 100644 llvm/test/Transforms/SCCP/relax-range-checks.ll

diff --git a/llvm/test/Transforms/SCCP/relax-range-checks.ll b/llvm/test/Transforms/SCCP/relax-range-checks.ll
new file mode 100644
index 0000000000000..ad9c476722174
--- /dev/null
+++ b/llvm/test/Transforms/SCCP/relax-range-checks.ll
@@ -0,0 +1,50 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt < %s -passes=sccp -S | FileCheck %s
+
+define i1 @relax_range_check(i8 range(i8 0, 5) %x)  {
+; CHECK-LABEL: define i1 @relax_range_check(
+; CHECK-SAME: i8 range(i8 0, 5) [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], -3
+; CHECK-NEXT:    [[RET:%.*]] = icmp ult i8 [[ADD]], 2
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %add = add i8 %x, -3
+  %ret = icmp ult i8 %add, 2
+  ret i1 %ret
+}
+
+define i1 @relax_range_check_highbits_check(i8 range(i8 2, 0) %x)  {
+; CHECK-LABEL: define i1 @relax_range_check_highbits_check(
+; CHECK-SAME: i8 range(i8 2, 0) [[X:%.*]]) {
+; CHECK-NEXT:    [[AND:%.*]] = and i8 [[X]], -2
+; CHECK-NEXT:    [[RET:%.*]] = icmp eq i8 [[AND]], 2
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %and = and i8 %x, -2
+  %ret = icmp eq i8 %and, 2
+  ret i1 %ret
+}
+
+; Negative tests.
+
+define i1 @relax_range_check_one_instruction(i8 range(i8 0, 5) %x)  {
+; CHECK-LABEL: define i1 @relax_range_check_one_instruction(
+; CHECK-SAME: i8 range(i8 0, 5) [[X:%.*]]) {
+; CHECK-NEXT:    [[RET:%.*]] = icmp ult i8 [[X]], 2
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %ret = icmp ult i8 %x, 2
+  ret i1 %ret
+}
+
+define i1 @relax_range_check_not_profitable(i8 range(i8 0, 6) %x)  {
+; CHECK-LABEL: define i1 @relax_range_check_not_profitable(
+; CHECK-SAME: i8 range(i8 0, 6) [[X:%.*]]) {
+; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], -3
+; CHECK-NEXT:    [[RET:%.*]] = icmp ult i8 [[ADD]], 2
+; CHECK-NEXT:    ret i1 [[RET]]
+;
+  %add = add i8 %x, -3
+  %ret = icmp ult i8 %add, 2
+  ret i1 %ret
+}

>From 3a89d80c31011205af132a4090949ab2df09f3e1 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 14 Sep 2025 23:13:03 +0800
Subject: [PATCH 2/4] [SCCP] Relax two-instruction range checks.

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

diff --git a/llvm/lib/Transforms/Utils/SCCPSolver.cpp b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
index 84485176ad4ff..caaf069194b3b 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -19,8 +19,10 @@
 #include "llvm/Analysis/ValueLattice.h"
 #include "llvm/Analysis/ValueLatticeUtils.h"
 #include "llvm/Analysis/ValueTracking.h"
+#include "llvm/IR/ConstantRange.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/InstVisitor.h"
+#include "llvm/IR/Instructions.h"
 #include "llvm/IR/NoFolder.h"
 #include "llvm/IR/PatternMatch.h"
 #include "llvm/Support/Casting.h"
@@ -284,6 +286,52 @@ static Value *simplifyInstruction(SCCPSolver &Solver,
     return Sub;
   }
 
+  // Relax range checks.
+  if (auto *ICmp = dyn_cast<ICmpInst>(&Inst)) {
+    Value *X;
+    auto MatchTwoInstructionExactRangeCheck =
+        [&]() -> std::optional<ConstantRange> {
+      const APInt *RHSC;
+      if (!match(ICmp->getOperand(1), m_APInt(RHSC)))
+        return std::nullopt;
+
+      Value *LHS = ICmp->getOperand(0);
+      ICmpInst::Predicate Pred = ICmp->getPredicate();
+      unsigned BitWidth = RHSC->getBitWidth();
+      if (Pred == ICmpInst::ICMP_ULT) {
+        const APInt *Offset;
+        if (match(LHS, m_AddLike(m_Value(X), m_APInt(Offset))))
+          return ConstantRange(APInt::getZero(BitWidth), *RHSC).sub(*Offset);
+        return std::nullopt;
+      }
+      // Match icmp eq/ne X & NegPow2, C
+      if (ICmp->isEquality()) {
+        const APInt *Mask;
+        if (match(LHS, m_And(m_Value(X), m_NegatedPower2(Mask))) &&
+            RHSC->countr_zero() >= Mask->countr_zero()) {
+          ConstantRange CR(*RHSC, *RHSC - *Mask);
+          return Pred == ICmpInst::ICMP_EQ ? CR : CR.inverse();
+        }
+      }
+      return std::nullopt;
+    };
+
+    if (auto CR = MatchExactTwoInstructionRangeCheck()) {
+      ConstantRange LRange = GetRange(X);
+      if (auto NewCR = CR->exactUnionWith(LRange.inverse())) {
+        ICmpInst::Predicate Pred;
+        APInt RHS;
+        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;
+        }
+      }
+    }
+  }
+
   return nullptr;
 }
 
diff --git a/llvm/test/Transforms/SCCP/relax-range-checks.ll b/llvm/test/Transforms/SCCP/relax-range-checks.ll
index ad9c476722174..c5f90e419f710 100644
--- a/llvm/test/Transforms/SCCP/relax-range-checks.ll
+++ b/llvm/test/Transforms/SCCP/relax-range-checks.ll
@@ -5,7 +5,7 @@ define i1 @relax_range_check(i8 range(i8 0, 5) %x)  {
 ; CHECK-LABEL: define i1 @relax_range_check(
 ; CHECK-SAME: i8 range(i8 0, 5) [[X:%.*]]) {
 ; CHECK-NEXT:    [[ADD:%.*]] = add nsw i8 [[X]], -3
-; CHECK-NEXT:    [[RET:%.*]] = icmp ult i8 [[ADD]], 2
+; CHECK-NEXT:    [[RET:%.*]] = icmp uge i8 [[X]], 3
 ; CHECK-NEXT:    ret i1 [[RET]]
 ;
   %add = add i8 %x, -3
@@ -17,7 +17,7 @@ define i1 @relax_range_check_highbits_check(i8 range(i8 2, 0) %x)  {
 ; CHECK-LABEL: define i1 @relax_range_check_highbits_check(
 ; CHECK-SAME: i8 range(i8 2, 0) [[X:%.*]]) {
 ; CHECK-NEXT:    [[AND:%.*]] = and i8 [[X]], -2
-; CHECK-NEXT:    [[RET:%.*]] = icmp eq i8 [[AND]], 2
+; CHECK-NEXT:    [[RET:%.*]] = icmp ult i8 [[X]], 4
 ; CHECK-NEXT:    ret i1 [[RET]]
 ;
   %and = and i8 %x, -2

>From 99e2a89566dbb9fec1d76b84aa3a17e0044b0ca7 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Sun, 14 Sep 2025 23:33:15 +0800
Subject: [PATCH 3/4] [SCCP] Fix typo

---
 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 caaf069194b3b..3dd45498e92a9 100644
--- a/llvm/lib/Transforms/Utils/SCCPSolver.cpp
+++ b/llvm/lib/Transforms/Utils/SCCPSolver.cpp
@@ -316,7 +316,7 @@ static Value *simplifyInstruction(SCCPSolver &Solver,
       return std::nullopt;
     };
 
-    if (auto CR = MatchExactTwoInstructionRangeCheck()) {
+    if (auto CR = MatchTwoInstructionExactRangeCheck()) {
       ConstantRange LRange = GetRange(X);
       if (auto NewCR = CR->exactUnionWith(LRange.inverse())) {
         ICmpInst::Predicate Pred;

>From 6d1d9629aea42f6ab4bdb90c39d89ed8519aab3a Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Mon, 15 Sep 2025 00:14:34 +0800
Subject: [PATCH 4/4] [SCCP] Updates tests. NFC.

---
 llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll b/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll
index b49a40abaaeb1..ef56d213d5db2 100644
--- a/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll
+++ b/llvm/test/Transforms/SCCP/conditions-ranges-with-undef.ll
@@ -40,7 +40,7 @@ define void @val_undef_range() {
 ; CHECK-LABEL: @val_undef_range(
 ; CHECK-NEXT:  entry:
 ; CHECK-NEXT:    [[A:%.*]] = add nuw nsw i32 undef, 0
-; CHECK-NEXT:    [[BC_1:%.*]] = icmp ult i32 [[A]], 127
+; CHECK-NEXT:    [[BC_1:%.*]] = icmp ult i32 undef, 127
 ; CHECK-NEXT:    br i1 [[BC_1]], label [[TRUE:%.*]], label [[FALSE:%.*]]
 ; CHECK:       true:
 ; CHECK-NEXT:    call void @use(i1 false)



More information about the llvm-commits mailing list