[llvm] [InstSimplify] Extend icmp-of-add simplification to sle/sgt/sge (PR #168900)

via llvm-commits llvm-commits at lists.llvm.org
Thu Nov 20 08:34:58 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Pedro Lobo (pedroclobo)

<details>
<summary>Changes</summary>

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

---
Full diff: https://github.com/llvm/llvm-project/pull/168900.diff


2 Files Affected:

- (modified) llvm/lib/Analysis/InstructionSimplify.cpp (+10-8) 
- (modified) llvm/test/Transforms/InstSimplify/compare.ll (+102-12) 


``````````diff
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 97ac8f2ea47ea..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
@@ -2724,6 +2721,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
@@ -2766,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
@@ -2844,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
@@ -2868,6 +2898,36 @@ 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:    ret i1 true
+;
+  %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:    ret i1 false
+;
+  %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 +2950,36 @@ define i1 @icmp_nsw_nonpos2(i32 %V) {
   ret i1 %cmp
 }
 
+define i1 @icmp_nsw_nonpos3(i32 %V) {
+; CHECK-LABEL: @icmp_nsw_nonpos3(
+; CHECK-NEXT:    ret i1 false
+;
+  %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:    ret i1 true
+;
+  %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:    ret i1 true
+;
+  %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>)

``````````

</details>


https://github.com/llvm/llvm-project/pull/168900


More information about the llvm-commits mailing list