[llvm] [InstCombine] Fold `icmp samesign u{gt/ge/lt/le} (X +nsw C2), C` -> `icmp s{gt/ge/lt/le} X, (C - C2)` (PR #169960)
Tirthankar Mazumder via llvm-commits
llvm-commits at lists.llvm.org
Sun Nov 30 10:14:21 PST 2025
https://github.com/wermos updated https://github.com/llvm/llvm-project/pull/169960
>From 29ab236799f4fab8b4e57822de874a3d42beeed1 Mon Sep 17 00:00:00 2001
From: wermos <63574588+wermos at users.noreply.github.com>
Date: Sat, 29 Nov 2025 01:55:58 +0530
Subject: [PATCH 1/2] Pre-commit tests
---
llvm/test/Transforms/InstCombine/icmp-add.ll | 64 ++++++++++++++++++++
1 file changed, 64 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/icmp-add.ll b/llvm/test/Transforms/InstCombine/icmp-add.ll
index 8449c7c5ea935..a9f7d36602dfb 100644
--- a/llvm/test/Transforms/InstCombine/icmp-add.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-add.ll
@@ -3440,3 +3440,67 @@ define i1 @val_is_aligend_pred_mismatch(i32 %num) {
%_0 = icmp sge i32 %num.masked, %num
ret i1 %_0
}
+
+define i1 @icmp_samesign_with_nsw_add(i32 %arg0) {
+; CHECK-LABEL: @icmp_samesign_with_nsw_add(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[ARG0:%.*]], -26
+; CHECK-NEXT: [[V1:%.*]] = icmp ult i32 [[TMP0]], -8
+; CHECK-NEXT: ret i1 [[V1]]
+;
+entry:
+ %v0 = add nsw i32 %arg0, -18
+ %v1 = icmp samesign ugt i32 %v0, 7
+ ret i1 %v1
+}
+
+; Shouldn't fire since -124 - 12 causes signed overflow
+define i1 @icmp_samesign_with_nsw_add_no_fire(i8 %arg0) {
+; CHECK-LABEL: @icmp_samesign_with_nsw_add_no_fire(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = add i8 [[ARG0:%.*]], -121
+; CHECK-NEXT: [[V1:%.*]] = icmp ult i8 [[TMP0]], 123
+; CHECK-NEXT: ret i1 [[V1]]
+;
+entry:
+ %v0 = add nsw i8 %arg0, 12
+ %v1 = icmp samesign ugt i8 %v0, -124
+ ret i1 %v1
+}
+
+define i1 @icmp_with_nuw_add(i32 %arg0) {
+; CHECK-LABEL: @icmp_with_nuw_add(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[V1:%.*]] = icmp ugt i32 [[ARG0:%.*]], 11
+; CHECK-NEXT: ret i1 [[V1]]
+;
+entry:
+ %v0 = add nuw i32 %arg0, 7
+ %v1 = icmp ugt i32 %v0, 18
+ ret i1 %v1
+}
+
+define i1 @icmp_partial_negative_samesign_ult_to_slt(i8 range(i8 -1, 5) %x) {
+; CHECK-LABEL: @icmp_partial_negative_samesign_ult_to_slt(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[X:%.*]], -5
+; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ult i8 [[ADD]], -3
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+entry:
+ %add = add nsw i8 %x, -5
+ %cmp = icmp samesign ult i8 %add, -3
+ ret i1 %cmp
+}
+
+define i1 @icmp_pos_samesign_slt_to_ult(i8 range(i8 1, 5) %x) {
+; CHECK-LABEL: @icmp_pos_samesign_slt_to_ult(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ult i8 [[X:%.*]], 2
+; CHECK-NEXT: ret i1 [[CMP]]
+;
+entry:
+ %add = add nsw i8 %x, 1
+ %cmp = icmp samesign slt i8 %add, 3
+ ret i1 %cmp
+}
>From 726d4a9c5df6e78ac3fb10dc0ab17477927b5632 Mon Sep 17 00:00:00 2001
From: wermos <63574588+wermos at users.noreply.github.com>
Date: Sat, 29 Nov 2025 02:02:43 +0530
Subject: [PATCH 2/2] Fold `icmp samesign u{gt/lt} (add nsw X, C2), C` -> `icmp
s{gt/lt} X, (C - C2)` whenever applicable.
---
.../InstCombine/InstCombineCompares.cpp | 19 ++++++++++---------
llvm/test/Transforms/InstCombine/icmp-add.ll | 16 +++++++---------
2 files changed, 17 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 33eee8e059486..2c3ab5147d265 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3132,7 +3132,7 @@ Instruction *InstCombinerImpl::foldICmpAddConstant(ICmpInst &Cmp,
Value *Op0, *Op1;
Instruction *Ext0, *Ext1;
- const CmpInst::Predicate Pred = Cmp.getPredicate();
+ const CmpPredicate Pred(Cmp.getPredicate(), Cmp.hasSameSign());
if (match(Add,
m_Add(m_CombineAnd(m_Instruction(Ext0), m_ZExtOrSExt(m_Value(Op0))),
m_CombineAnd(m_Instruction(Ext1),
@@ -3167,20 +3167,21 @@ Instruction *InstCombinerImpl::foldICmpAddConstant(ICmpInst &Cmp,
// If the add does not wrap, we can always adjust the compare by subtracting
// the constants. Equality comparisons are handled elsewhere. SGE/SLE/UGE/ULE
- // are canonicalized to SGT/SLT/UGT/ULT.
- if ((Add->hasNoSignedWrap() &&
- (Pred == ICmpInst::ICMP_SGT || Pred == ICmpInst::ICMP_SLT)) ||
- (Add->hasNoUnsignedWrap() &&
- (Pred == ICmpInst::ICMP_UGT || Pred == ICmpInst::ICMP_ULT))) {
+ // has been canonicalized to SGT/SLT/UGT/ULT.
+ CmpInst::Predicate ChosenPred = Pred.getPreferredSignedPredicate();
+ if ((Add->hasNoSignedWrap() && (ChosenPred == ICmpInst::ICMP_SGT ||
+ ChosenPred == ICmpInst::ICMP_SLT)) ||
+ (Add->hasNoUnsignedWrap() && (ChosenPred == ICmpInst::ICMP_UGT ||
+ ChosenPred == ICmpInst::ICMP_ULT))) {
bool Overflow;
- APInt NewC =
- Cmp.isSigned() ? C.ssub_ov(*C2, Overflow) : C.usub_ov(*C2, Overflow);
+ APInt NewC = ICmpInst::isSigned(ChosenPred) ? C.ssub_ov(*C2, Overflow)
+ : C.usub_ov(*C2, Overflow);
// If there is overflow, the result must be true or false.
// TODO: Can we assert there is no overflow because InstSimplify always
// handles those cases?
if (!Overflow)
// icmp Pred (add nsw X, C2), C --> icmp Pred X, (C - C2)
- return new ICmpInst(Pred, X, ConstantInt::get(Ty, NewC));
+ return new ICmpInst(ChosenPred, X, ConstantInt::get(Ty, NewC));
}
if (ICmpInst::isUnsigned(Pred) && Add->hasNoSignedWrap() &&
diff --git a/llvm/test/Transforms/InstCombine/icmp-add.ll b/llvm/test/Transforms/InstCombine/icmp-add.ll
index a9f7d36602dfb..e5b977fc60e6e 100644
--- a/llvm/test/Transforms/InstCombine/icmp-add.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-add.ll
@@ -3444,8 +3444,7 @@ define i1 @val_is_aligend_pred_mismatch(i32 %num) {
define i1 @icmp_samesign_with_nsw_add(i32 %arg0) {
; CHECK-LABEL: @icmp_samesign_with_nsw_add(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[TMP0:%.*]] = add i32 [[ARG0:%.*]], -26
-; CHECK-NEXT: [[V1:%.*]] = icmp ult i32 [[TMP0]], -8
+; CHECK-NEXT: [[V1:%.*]] = icmp sgt i32 [[ARG0:%.*]], 25
; CHECK-NEXT: ret i1 [[V1]]
;
entry:
@@ -3454,9 +3453,9 @@ entry:
ret i1 %v1
}
-; Shouldn't fire since -124 - 12 causes signed overflow
-define i1 @icmp_samesign_with_nsw_add_no_fire(i8 %arg0) {
-; CHECK-LABEL: @icmp_samesign_with_nsw_add_no_fire(
+; Negative test; Fold shouldn't fire since -124 - 12 causes signed overflow
+define i1 @icmp_samesign_with_nsw_add_neg(i8 %arg0) {
+; CHECK-LABEL: @icmp_samesign_with_nsw_add_neg(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[TMP0:%.*]] = add i8 [[ARG0:%.*]], -121
; CHECK-NEXT: [[V1:%.*]] = icmp ult i8 [[TMP0]], 123
@@ -3471,20 +3470,19 @@ entry:
define i1 @icmp_with_nuw_add(i32 %arg0) {
; CHECK-LABEL: @icmp_with_nuw_add(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[V1:%.*]] = icmp ugt i32 [[ARG0:%.*]], 11
+; CHECK-NEXT: [[V1:%.*]] = icmp ult i32 [[ARG0:%.*]], 11
; CHECK-NEXT: ret i1 [[V1]]
;
entry:
%v0 = add nuw i32 %arg0, 7
- %v1 = icmp ugt i32 %v0, 18
+ %v1 = icmp ult i32 %v0, 18
ret i1 %v1
}
define i1 @icmp_partial_negative_samesign_ult_to_slt(i8 range(i8 -1, 5) %x) {
; CHECK-LABEL: @icmp_partial_negative_samesign_ult_to_slt(
; CHECK-NEXT: entry:
-; CHECK-NEXT: [[ADD:%.*]] = add nsw i8 [[X:%.*]], -5
-; CHECK-NEXT: [[CMP:%.*]] = icmp samesign ult i8 [[ADD]], -3
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 2
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
More information about the llvm-commits
mailing list