[llvm] [InstCombine] Missed fold: umax(x, C) > ~x -> x < 0 (PR #189396)

via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 30 07:41:30 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Madhur Kumar (MadhurKumar004)

<details>
<summary>Changes</summary>

fix : https://github.com/llvm/llvm-project/issues/187648

Fix the missed optimization for 
`icmp ugt (umax(x, C)), ~x` and `icmp ult (umax(x, C)), ~x`

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


2 Files Affected:

- (modified) llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp (+24-1) 
- (added) llvm/test/Transforms/InstCombine/icmp-umax-notx.ll (+45) 


``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index ff1868f3a5840..e029b845d595e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -7785,13 +7785,36 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
   if (Instruction *Res = foldICmpWithZero(I))
     return Res;
 
+  Value* X;
+  const APInt *C;
+  if (I.getPredicate() == ICmpInst::ICMP_UGT &&
+          match(Op0, m_UMax(m_Value(X), m_APInt(C))) &&
+          match(Op1, m_Not(m_Specific(X)))) {
+    if (C->isNonNegative()) {
+      return new ICmpInst(ICmpInst::ICMP_SLT, X,
+                        Constant::getNullValue(X->getType()));
+    }
+    return new ICmpInst(ICmpInst::ICMP_UGT, X,
+                    ConstantInt::get(X->getType(), ~*C));
+  }
+
+  if (I.getPredicate() == ICmpInst::ICMP_ULT &&
+          match(Op0, m_UMax(m_Value(X), m_APInt(C))) &&
+          match(Op1, m_Not(m_Specific(X)))) {
+    if (C->isNonNegative()) {
+      return new ICmpInst(ICmpInst::ICMP_SGT, X,
+                          Constant::getAllOnesValue(X->getType()));
+    }
+    return new ICmpInst(ICmpInst::ICMP_ULT, X,
+                        ConstantInt::get(X->getType(), ~*C));
+  }
+
   // FIXME: We only do this after checking for min/max to prevent infinite
   // looping caused by a reverse canonicalization of these patterns for min/max.
   // FIXME: The organization of folds is a mess. These would naturally go into
   // canonicalizeCmpWithConstant(), but we can't move all of the above folds
   // down here after the min/max restriction.
   ICmpInst::Predicate Pred = I.getPredicate();
-  const APInt *C;
   if (match(Op1, m_APInt(C))) {
     // For i32: x >u 2147483647 -> x <s 0  -> true if sign bit set
     if (Pred == ICmpInst::ICMP_UGT && C->isMaxSignedValue()) {
diff --git a/llvm/test/Transforms/InstCombine/icmp-umax-notx.ll b/llvm/test/Transforms/InstCombine/icmp-umax-notx.ll
new file mode 100644
index 0000000000000..5eae09375d27a
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/icmp-umax-notx.ll
@@ -0,0 +1,45 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+declare i64 @llvm.umax.i64(i64, i64)
+
+define i1 @test_ugt_small_c(i64 %x){
+; CHECK-LABEL: @test_ugt_small_c(
+; CHECK-NEXT:    %r = icmp slt i64 %x, 0
+; CHECK-NEXT:    ret i1 %r
+  %m = call i64 @llvm.umax.i64(i64 %x, i64 1)
+  %notx = xor i64 %x, -1
+  %r = icmp ugt i64 %m, %notx
+  ret i1 %r
+}
+
+define i1 @test_ugt_large_c(i64 %x){
+; CHECK-LABEL: @test_ugt_large_c(
+; CHECK-NEXT:    %r = icmp ugt i64 %x, 8446744073709551615
+; CHECK-NEXT:    ret i1 %r
+  %m = call i64 @llvm.umax.i64(i64 %x, i64 10000000000000000000)
+  %notx = xor i64 %x, -1
+  %r = icmp ugt i64 %m, %notx
+  ret i1 %r
+}
+
+define i1 @test_ult_small_c(i64 %x){
+; CHECK-LABEL: @test_ult_small_c(
+; CHECK-NEXT:    %r = icmp sgt i64 %x, -1
+; CHECK-NEXT:    ret i1 %r
+  %m = call i64 @llvm.umax.i64(i64 %x, i64 1)
+  %notx = xor i64 %x, -1
+  %r = icmp ult i64 %m, %notx
+  ret i1 %r
+}
+
+define i1 @test_ult_large_c(i64 %x){
+; CHECK-LABEL: @test_ult_large_c(
+; CHECK-NEXT:    %r = icmp ult i64 %x, 8446744073709551615
+; CHECK-NEXT:    ret i1 %r
+  %m = call i64 @llvm.umax.i64(i64 %x, i64 10000000000000000000)
+  %notx = xor i64 %x, -1
+  %r = icmp ult i64 %m, %notx
+  ret i1 %r
+}
+

``````````

</details>


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


More information about the llvm-commits mailing list