[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