[llvm] [InstSimplify] Extend icmp-of-add simplification to sle/sgt/sge (PR #168900)
Pedro Lobo via llvm-commits
llvm-commits at lists.llvm.org
Thu Nov 20 10:05:48 PST 2025
https://github.com/pedroclobo updated https://github.com/llvm/llvm-project/pull/168900
>From c9a2887052acf4d16f273db397ae5576565dc917 Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedrocerqueiralobo at gmail.com>
Date: Thu, 20 Nov 2025 16:01:03 +0000
Subject: [PATCH 1/3] Pre-commit tests
---
llvm/test/Transforms/InstSimplify/compare.ll | 114 +++++++++++++++++++
1 file changed, 114 insertions(+)
diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll
index 97ac8f2ea47ea..dc05ceaab385a 100644
--- a/llvm/test/Transforms/InstSimplify/compare.ll
+++ b/llvm/test/Transforms/InstSimplify/compare.ll
@@ -2724,6 +2724,45 @@ define i1 @icmp_nsw_false_5(i8 %V) {
ret i1 %cmp
}
+define i1 @icmp_nsw_false_6(i8 %V) {
+; CHECK-LABEL: @icmp_nsw_false_6(
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[V:%.*]], 6
+; CHECK-NEXT: [[ADDNSW:%.*]] = add nsw i8 [[V]], -1
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[ADD]], [[ADDNSW]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %add = add i8 %V, 6
+ %addnsw = add nsw i8 %V, -1
+ %cmp = icmp sgt i8 %add, %addnsw
+ ret i1 %cmp
+}
+
+define i1 @icmp_nsw_false_7(i8 %V) {
+; CHECK-LABEL: @icmp_nsw_false_7(
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[V:%.*]], -1
+; CHECK-NEXT: [[ADDNSW:%.*]] = add nsw i8 [[V]], 3
+; CHECK-NEXT: [[CMP:%.*]] = icmp sle i8 [[ADD]], [[ADDNSW]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %add = add i8 %V, -1
+ %addnsw = add nsw i8 %V, 3
+ %cmp = icmp sle i8 %add, %addnsw
+ ret i1 %cmp
+}
+
+define i1 @icmp_nsw_false_8(i8 %V) {
+; CHECK-LABEL: @icmp_nsw_false_8(
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[V:%.*]], -15
+; CHECK-NEXT: [[ADDNSW:%.*]] = add nsw i8 [[V]], 42
+; CHECK-NEXT: [[CMP:%.*]] = icmp sge i8 [[ADD]], [[ADDNSW]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %add = add i8 %V, -15
+ %addnsw = add nsw i8 %V, 42
+ %cmp = icmp sge i8 %add, %addnsw
+ ret i1 %cmp
+}
+
define i1 @icmp_nsw_i8(i8 %V) {
; CHECK-LABEL: @icmp_nsw_i8(
; CHECK-NEXT: ret i1 true
@@ -2868,6 +2907,42 @@ define i1 @icmp_nsw_11(i32 %V) {
ret i1 %cmp
}
+define i1 @icmp_nsw_12(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_12(
+; CHECK-NEXT: ret i1 true
+;
+ %add5 = add i32 %V, 2
+ %add6 = add nsw i32 %V, 3
+ %cmp = icmp slt i32 %add5, %add6
+ ret i1 %cmp
+}
+
+define i1 @icmp_nsw_13(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_13(
+; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], 7
+; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], 10
+; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[ADD5]], [[ADD6]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %add5 = add i32 %V, 7
+ %add6 = add nsw i32 %V, 10
+ %cmp = icmp sle i32 %add5, %add6
+ ret i1 %cmp
+}
+
+define i1 @icmp_nsw_14(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_14(
+; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], 7
+; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], 10
+; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[ADD5]], [[ADD6]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %add5 = add i32 %V, 7
+ %add6 = add nsw i32 %V, 10
+ %cmp = icmp sge i32 %add5, %add6
+ ret i1 %cmp
+}
+
define i1 @icmp_nsw_nonpos(i32 %V) {
; CHECK-LABEL: @icmp_nsw_nonpos(
; CHECK-NEXT: ret i1 false
@@ -2890,6 +2965,45 @@ define i1 @icmp_nsw_nonpos2(i32 %V) {
ret i1 %cmp
}
+define i1 @icmp_nsw_nonpos3(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_nonpos3(
+; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], -2
+; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], -5
+; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[ADD5]], [[ADD6]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %add5 = add i32 %V, -2
+ %add6 = add nsw i32 %V, -5
+ %cmp = icmp sle i32 %add5, %add6
+ ret i1 %cmp
+}
+
+define i1 @icmp_nsw_nonpos4(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_nonpos4(
+; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], -10
+; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], -30
+; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[ADD5]], [[ADD6]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %add5 = add i32 %V, -10
+ %add6 = add nsw i32 %V, -30
+ %cmp = icmp sgt i32 %add5, %add6
+ ret i1 %cmp
+}
+
+define i1 @icmp_nsw_nonpos5(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_nonpos5(
+; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], -15
+; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], -100
+; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[ADD5]], [[ADD6]]
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+ %add5 = add i32 %V, -15
+ %add6 = add nsw i32 %V, -100
+ %cmp = icmp sge i32 %add5, %add6
+ ret i1 %cmp
+}
+
declare i11 @llvm.ctpop.i11(i11)
declare i73 @llvm.ctpop.i73(i73)
declare <2 x i13> @llvm.ctpop.v2i13(<2 x i13>)
>From 9fee32d25261bae3cbb7f2f87449faf8c044cae9 Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedrocerqueiralobo at gmail.com>
Date: Thu, 20 Nov 2025 16:10:03 +0000
Subject: [PATCH 2/3] [InstSimplify] Extend icmp-of-add simplification to
sle/sgt/sge
When comparing additions with the same base where one has `nsw`, the
following simplification can be performed:
```llvm
icmp slt/sgt/sle/sge (x + C1), (x +nsw C2)
=>
icmp slt/sgt/sle/sge C1, C2
```
Previously this was only done for `slt`. This patch extends it to the
`sgt`, `sle`, and `sge` predicates when either of the conditions hold:
- `C1 <= C2 && C1 >= 0`, or
- `C2 <= C1 && C1 <= 0`
This patch also handles the `C1 == C2` case, which was previously excluded.
Proof: https://alive2.llvm.org/ce/z/LtmY4f
---
llvm/lib/Analysis/InstructionSimplify.cpp | 18 +++++----
llvm/test/Transforms/InstSimplify/compare.ll | 40 ++++----------------
2 files changed, 18 insertions(+), 40 deletions(-)
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 8968f6b934d77..452cba23e3309 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3261,20 +3261,22 @@ static Value *simplifyICmpWithBinOpOnLHS(CmpPredicate Pred, BinaryOperator *LBO,
// If only one of the icmp's operands has NSW flags, try to prove that:
//
-// icmp slt (x + C1), (x +nsw C2)
+// icmp slt/sgt/sle/sge (x + C1), (x +nsw C2)
//
// is equivalent to:
//
-// icmp slt C1, C2
+// icmp slt/sgt/sle/sge C1, C2
//
// which is true if x + C2 has the NSW flags set and:
-// *) C1 < C2 && C1 >= 0, or
-// *) C2 < C1 && C1 <= 0.
+// *) C1 <= C2 && C1 >= 0, or
+// *) C2 <= C1 && C1 <= 0.
//
static bool trySimplifyICmpWithAdds(CmpPredicate Pred, Value *LHS, Value *RHS,
const InstrInfoQuery &IIQ) {
- // TODO: only support icmp slt for now.
- if (Pred != CmpInst::ICMP_SLT || !IIQ.UseInstrInfo)
+ // TODO: support other predicates.
+ if ((Pred != CmpInst::ICMP_SLT && Pred != CmpInst::ICMP_SGT &&
+ Pred != CmpInst::ICMP_SLE && Pred != CmpInst::ICMP_SGE) ||
+ !IIQ.UseInstrInfo)
return false;
// Canonicalize nsw add as RHS.
@@ -3289,8 +3291,8 @@ static bool trySimplifyICmpWithAdds(CmpPredicate Pred, Value *LHS, Value *RHS,
!match(RHS, m_Add(m_Specific(X), m_APInt(C2))))
return false;
- return (C1->slt(*C2) && C1->isNonNegative()) ||
- (C2->slt(*C1) && C1->isNonPositive());
+ return (C1->sle(*C2) && C1->isNonNegative()) ||
+ (C2->sle(*C1) && C1->isNonPositive());
}
/// TODO: A large part of this logic is duplicated in InstCombine's
diff --git a/llvm/test/Transforms/InstSimplify/compare.ll b/llvm/test/Transforms/InstSimplify/compare.ll
index dc05ceaab385a..ba10ea532a34a 100644
--- a/llvm/test/Transforms/InstSimplify/compare.ll
+++ b/llvm/test/Transforms/InstSimplify/compare.ll
@@ -2687,10 +2687,7 @@ define i1 @icmp_nsw_false_2(i32 %V) {
define i1 @icmp_nsw_false_3(i32 %V) {
; CHECK-LABEL: @icmp_nsw_false_3(
-; CHECK-NEXT: [[ADD5:%.*]] = add nsw i32 [[V:%.*]], 5
-; CHECK-NEXT: [[ADD6:%.*]] = add i32 [[V]], 5
-; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD6]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%add5 = add nsw i32 %V, 5
%add6 = add i32 %V, 5
@@ -2805,10 +2802,7 @@ define <4 x i1> @icmp_nsw_vec(<4 x i32> %V) {
define i1 @icmp_nsw_3(i32 %V) {
; CHECK-LABEL: @icmp_nsw_3(
-; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], 5
-; CHECK-NEXT: [[ADD5_2:%.*]] = add nsw i32 [[V]], 5
-; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[ADD5]], [[ADD5_2]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%add5 = add i32 %V, 5
%add5_2 = add nsw i32 %V, 5
@@ -2883,10 +2877,7 @@ define i1 @icmp_nsw_9(i32 %V1, i32 %V2) {
define i1 @icmp_nsw_10(i32 %V) {
; CHECK-LABEL: @icmp_nsw_10(
-; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], 5
-; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], 6
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[ADD6]], [[ADD5]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%add5 = add i32 %V, 5
%add6 = add nsw i32 %V, 6
@@ -2919,10 +2910,7 @@ define i1 @icmp_nsw_12(i32 %V) {
define i1 @icmp_nsw_13(i32 %V) {
; CHECK-LABEL: @icmp_nsw_13(
-; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], 7
-; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], 10
-; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[ADD5]], [[ADD6]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%add5 = add i32 %V, 7
%add6 = add nsw i32 %V, 10
@@ -2932,10 +2920,7 @@ define i1 @icmp_nsw_13(i32 %V) {
define i1 @icmp_nsw_14(i32 %V) {
; CHECK-LABEL: @icmp_nsw_14(
-; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], 7
-; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], 10
-; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[ADD5]], [[ADD6]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%add5 = add i32 %V, 7
%add6 = add nsw i32 %V, 10
@@ -2967,10 +2952,7 @@ define i1 @icmp_nsw_nonpos2(i32 %V) {
define i1 @icmp_nsw_nonpos3(i32 %V) {
; CHECK-LABEL: @icmp_nsw_nonpos3(
-; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], -2
-; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], -5
-; CHECK-NEXT: [[CMP:%.*]] = icmp sle i32 [[ADD5]], [[ADD6]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 false
;
%add5 = add i32 %V, -2
%add6 = add nsw i32 %V, -5
@@ -2980,10 +2962,7 @@ define i1 @icmp_nsw_nonpos3(i32 %V) {
define i1 @icmp_nsw_nonpos4(i32 %V) {
; CHECK-LABEL: @icmp_nsw_nonpos4(
-; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], -10
-; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], -30
-; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[ADD5]], [[ADD6]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%add5 = add i32 %V, -10
%add6 = add nsw i32 %V, -30
@@ -2993,10 +2972,7 @@ define i1 @icmp_nsw_nonpos4(i32 %V) {
define i1 @icmp_nsw_nonpos5(i32 %V) {
; CHECK-LABEL: @icmp_nsw_nonpos5(
-; CHECK-NEXT: [[ADD5:%.*]] = add i32 [[V:%.*]], -15
-; CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[V]], -100
-; CHECK-NEXT: [[CMP:%.*]] = icmp sge i32 [[ADD5]], [[ADD6]]
-; CHECK-NEXT: ret i1 [[CMP]]
+; CHECK-NEXT: ret i1 true
;
%add5 = add i32 %V, -15
%add6 = add nsw i32 %V, -100
>From 4bf9e8abc92910b13991a0e3a204ba843770cebd Mon Sep 17 00:00:00 2001
From: Pedro Lobo <pedrocerqueiralobo at gmail.com>
Date: Thu, 20 Nov 2025 18:05:13 +0000
Subject: [PATCH 3/3] Use `!ICmpInst::isSigned`
---
llvm/lib/Analysis/InstructionSimplify.cpp | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 452cba23e3309..59a213b47825a 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -3274,9 +3274,7 @@ static Value *simplifyICmpWithBinOpOnLHS(CmpPredicate Pred, BinaryOperator *LBO,
static bool trySimplifyICmpWithAdds(CmpPredicate Pred, Value *LHS, Value *RHS,
const InstrInfoQuery &IIQ) {
// TODO: support other predicates.
- if ((Pred != CmpInst::ICMP_SLT && Pred != CmpInst::ICMP_SGT &&
- Pred != CmpInst::ICMP_SLE && Pred != CmpInst::ICMP_SGE) ||
- !IIQ.UseInstrInfo)
+ if (!ICmpInst::isSigned(Pred) || !IIQ.UseInstrInfo)
return false;
// Canonicalize nsw add as RHS.
More information about the llvm-commits
mailing list