[llvm] [InstCombine] Fold signed icmp X, (X | C) when C is negative (PR #217805)

via llvm-commits llvm-commits at lists.llvm.org
Thu Sep 10 01:31:55 PDT 2026


https://github.com/milkHongYe updated https://github.com/llvm/llvm-project/pull/217805

>From 1c1f0e62c1bdcff2de462b78389a24b782d87b70 Mon Sep 17 00:00:00 2001
From: milkHongYe <1483685464 at qq.com>
Date: Fri, 21 Aug 2026 10:52:32 +0800
Subject: [PATCH] [InstCombine] Fold signed icmp X, (X | C) when C is negative

---
 .../InstCombine/InstCombineCompares.cpp       | 28 +++++++++++++
 .../Transforms/InstCombine/icmp-of-or-x.ll    | 39 ++++++++++++-------
 2 files changed, 52 insertions(+), 15 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 5f0b3fb888ecf..915df7e233af6 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -5310,6 +5310,34 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
     return NewICmp;
 
   const CmpInst::Predicate Pred = I.getPredicate();
+
+  // icmp sgt X, (X | C) --> icmp sge X, 0, when C is negative
+  // icmp sle X, (X | C) --> icmp slt X, 0
+  // icmp slt X, (X | C) --> false, icmp sge X, (X | C) --> true
+  if (ICmpInst::isSigned(Pred)) {
+    const APInt *C;
+    Value *X = Op0;
+    CmpInst::Predicate P = Pred;
+    if (!match(Op1, m_Or(m_Specific(Op0), m_APInt(C)))) {
+      X = Op1;
+      P = ICmpInst::getSwappedPredicate(Pred);
+      if (!match(Op0, m_Or(m_Specific(Op1), m_APInt(C))))
+        X = nullptr;
+    }
+    if (X && C->isNegative()) {
+      if (P == ICmpInst::ICMP_SGT)
+        return new ICmpInst(ICmpInst::ICMP_SGE, X,
+                            Constant::getNullValue(X->getType()));
+      if (P == ICmpInst::ICMP_SLE)
+        return new ICmpInst(ICmpInst::ICMP_SLT, X,
+                            Constant::getNullValue(X->getType()));
+      if (P == ICmpInst::ICMP_SLT)
+        return replaceInstUsesWith(I, ConstantInt::getFalse(I.getType()));
+      if (P == ICmpInst::ICMP_SGE)
+        return replaceInstUsesWith(I, ConstantInt::getTrue(I.getType()));
+    }
+  }
+
   Value *X;
 
   // Convert add-with-unsigned-overflow comparisons into a 'not' with compare.
diff --git a/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
index 993325f6ff0b0..e5f31c46ce630 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
@@ -180,8 +180,7 @@ define <2 x i1> @or_ne_noundef_fail_reuse(<2 x i8> %x, <2 x i8> noundef %y) {
 
 define i1 @or_slt_intmin(i8 %x) {
 ; CHECK-LABEL: @or_slt_intmin(
-; CHECK-NEXT:    [[XN1:%.*]] = or i8 [[X:%.*]], -128
-; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[XN1]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[X:%.*]], -1
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %xn1 = or i8 %x, 128
@@ -191,10 +190,7 @@ define i1 @or_slt_intmin(i8 %x) {
 
 define <2 x i1> @or_slt_intmin_2(<2 x i8> %xx, <2 x i8> %z) {
 ; CHECK-LABEL: @or_slt_intmin_2(
-; CHECK-NEXT:    [[X:%.*]] = add <2 x i8> [[XX:%.*]], [[Z:%.*]]
-; CHECK-NEXT:    [[XN1:%.*]] = or <2 x i8> [[X]], splat (i8 -128)
-; CHECK-NEXT:    [[R:%.*]] = icmp slt <2 x i8> [[X]], [[XN1]]
-; CHECK-NEXT:    ret <2 x i1> [[R]]
+; CHECK-NEXT:    ret <2 x i1> zeroinitializer
 ;
   %x = add <2 x i8> %xx, %z
   %xn1 = or <2 x i8> %x, <i8 128, i8 128>
@@ -208,8 +204,7 @@ define i1 @or_sle_intmin_indirect_2(i8 %xx, i8 %C, i8 %z) {
 ; CHECK-NEXT:    br i1 [[CMP]], label [[NEG:%.*]], label [[POS:%.*]]
 ; CHECK:       neg:
 ; CHECK-NEXT:    [[X:%.*]] = add i8 [[XX:%.*]], [[Z:%.*]]
-; CHECK-NEXT:    [[XN1:%.*]] = or i8 [[X]], -128
-; CHECK-NEXT:    [[R:%.*]] = icmp sle i8 [[X]], [[XN1]]
+; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[X]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ; CHECK:       pos:
 ; CHECK-NEXT:    call void @barrier()
@@ -231,8 +226,7 @@ pos:
 
 define i1 @or_sge_intmin(i8 %x) {
 ; CHECK-LABEL: @or_sge_intmin(
-; CHECK-NEXT:    [[XN1:%.*]] = or i8 [[X:%.*]], -128
-; CHECK-NEXT:    [[R:%.*]] = icmp sge i8 [[XN1]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = icmp slt i8 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %xn1 = or i8 %x, 128
@@ -245,9 +239,7 @@ define i1 @or_sgt_intmin_indirect(i8 %x, i8 %C) {
 ; CHECK-NEXT:    [[C_NOT:%.*]] = icmp eq i8 [[C:%.*]], -128
 ; CHECK-NEXT:    br i1 [[C_NOT]], label [[NEG:%.*]], label [[POS:%.*]]
 ; CHECK:       neg:
-; CHECK-NEXT:    [[XN1:%.*]] = or i8 [[X:%.*]], -128
-; CHECK-NEXT:    [[R:%.*]] = icmp sgt i8 [[XN1]], [[X]]
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 false
 ; CHECK:       pos:
 ; CHECK-NEXT:    call void @barrier()
 ; CHECK-NEXT:    ret i1 false
@@ -268,8 +260,7 @@ pos:
 define <2 x i1> @or_sgt_intmin_2(<2 x i8> %xx, <2 x i8> %z) {
 ; CHECK-LABEL: @or_sgt_intmin_2(
 ; CHECK-NEXT:    [[X:%.*]] = add <2 x i8> [[XX:%.*]], [[Z:%.*]]
-; CHECK-NEXT:    [[XN1:%.*]] = or <2 x i8> [[X]], splat (i8 -128)
-; CHECK-NEXT:    [[R:%.*]] = icmp sgt <2 x i8> [[X]], [[XN1]]
+; CHECK-NEXT:    [[R:%.*]] = icmp sgt <2 x i8> [[X]], splat (i8 -1)
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %x = add <2 x i8> %xx, %z
@@ -278,6 +269,24 @@ define <2 x i1> @or_sgt_intmin_2(<2 x i8> %xx, <2 x i8> %z) {
   ret <2 x i1> %r
 }
 
+define i1 @or_sge_intmin_rhs(i8 %x) {
+; CHECK-LABEL: @or_sge_intmin_rhs(
+; CHECK-NEXT:    ret i1 true
+;
+  %xn1 = or i8 %x, -128
+  %r = icmp sge i8 %x, %xn1
+  ret i1 %r
+}
+
+define i1 @or_sle_intmin_lhs(i8 %x) {
+; CHECK-LABEL: @or_sle_intmin_lhs(
+; CHECK-NEXT:    ret i1 true
+;
+  %xn1 = or i8 %x, -128
+  %r = icmp sle i8 %xn1, %x
+  ret i1 %r
+}
+
 define i1 @or_simplify_ule(i8 %y_in, i8 %rhs_in, i1 %c) {
 ; CHECK-LABEL: @or_simplify_ule(
 ; CHECK-NEXT:    [[RHS:%.*]] = and i8 [[RHS_IN:%.*]], -2



More information about the llvm-commits mailing list