[llvm] [SCCP] Relax two-instruction range checks (PR #158495)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 14 08:17:37 PDT 2025
https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/158495
If we know x in R1, the range check `x in R2` can be relaxed into `x in Union(R2, Inverse(R1))`.
Fixes regressions introduced by https://github.com/llvm/llvm-project/pull/156497.
>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/2] [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/2] [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
More information about the llvm-commits
mailing list