[llvm] 3cf54c5 - [InstCombine] Add transforms for `(icmp upred (or X, Y), X)`

Noah Goldstein via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 15 23:59:37 PDT 2023


Author: Noah Goldstein
Date: 2023-08-16T02:00:15-05:00
New Revision: 3cf54c533d9fccfcf08c91c95b2891e353ff7128

URL: https://github.com/llvm/llvm-project/commit/3cf54c533d9fccfcf08c91c95b2891e353ff7128
DIFF: https://github.com/llvm/llvm-project/commit/3cf54c533d9fccfcf08c91c95b2891e353ff7128.diff

LOG: [InstCombine] Add transforms for `(icmp upred (or X, Y), X)`

We can simplify ule/ugt -> eq/ne and we can remove the `Or` in some
cases of eq/ne.

`icmp (X | Y) u<= X` --> `(X | Y) == X`
    - https://alive2.llvm.org/ce/z/qnbbPv
`icmp (X | Y) u> X` --> `(X | Y) != X`
    - https://alive2.llvm.org/ce/z/fvLqg3
`icmp (X | Y) eq/ne X`
     - --> `(~X & Y) eq/ne 0` iff X is freely invertible
     - --> `(X & ~Y) eq/ne -1` iff Y is freely invertible
          - https://alive2.llvm.org/ce/z/cpPV_W

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D144610

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
    llvm/test/Transforms/InstCombine/icmp-of-or-x.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 390b5a61450d14..6091dd31d45ba0 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4430,6 +4430,42 @@ static Instruction *foldICmpXNegX(ICmpInst &I,
   return nullptr;
 }
 
+static Instruction *foldICmpOrXX(ICmpInst &I, const SimplifyQuery &Q,
+                                 InstCombinerImpl &IC) {
+  Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1), *A;
+
+  // Normalize or operand as operand 0.
+  CmpInst::Predicate Pred = I.getPredicate();
+  if (match(Op1, m_c_Or(m_Specific(Op0), m_Value(A)))) {
+    std::swap(Op0, Op1);
+    Pred = ICmpInst::getSwappedPredicate(Pred);
+  } else if (!match(Op0, m_c_Or(m_Specific(Op1), m_Value(A)))) {
+    return nullptr;
+  }
+
+  // icmp (X | Y) u<= X --> (X | Y) == X
+  if (Pred == ICmpInst::ICMP_ULE)
+    return new ICmpInst(ICmpInst::ICMP_EQ, Op0, Op1);
+
+  // icmp (X | Y) u> X --> (X | Y) != X
+  if (Pred == ICmpInst::ICMP_UGT)
+    return new ICmpInst(ICmpInst::ICMP_NE, Op0, Op1);
+
+  if (ICmpInst::isEquality(Pred) && Op0->hasOneUse()) {
+    // icmp (X | Y) eq/ne Y --> (X & ~Y) eq/ne 0 if Y is freely invertible
+    if (IC.isFreeToInvert(Op1, Op1->hasOneUse()))
+      return new ICmpInst(Pred,
+                          IC.Builder.CreateAnd(A, IC.Builder.CreateNot(Op1)),
+                          Constant::getNullValue(Op1->getType()));
+    // icmp (X | Y) eq/ne Y --> (~X | Y) eq/ne -1 if X  is freely invertible.
+    if (IC.isFreeToInvert(A, A->hasOneUse()))
+      return new ICmpInst(Pred,
+                          IC.Builder.CreateOr(Op1, IC.Builder.CreateNot(A)),
+                          Constant::getAllOnesValue(Op1->getType()));
+  }
+  return nullptr;
+}
+
 static Instruction *foldICmpXorXX(ICmpInst &I, const SimplifyQuery &Q,
                                   InstCombinerImpl &IC) {
   Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1), *A;
@@ -4752,6 +4788,8 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
 
   if (Instruction * R = foldICmpXorXX(I, Q, *this))
     return R;
+  if (Instruction *R = foldICmpOrXX(I, Q, *this))
+    return R;
 
   {
     // Try to remove shared multiplier from comparison:

diff  --git a/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
index 834f66f6e9412c..839aa98a8b24e2 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
@@ -9,7 +9,7 @@ declare void @use.i8(i8)
 define i1 @or_ugt(i8 %x, i8 %y) {
 ; CHECK-LABEL: @or_ugt(
 ; CHECK-NEXT:    [[XN1:%.*]] = or i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[XN1]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[XN1]], [[X]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %xn1 = or i8 %x, %y
@@ -20,7 +20,7 @@ define i1 @or_ugt(i8 %x, i8 %y) {
 define <2 x i1> @or_ule(<2 x i8> %x, <2 x i8> %y) {
 ; CHECK-LABEL: @or_ule(
 ; CHECK-NEXT:    [[XN1:%.*]] = or <2 x i8> [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ule <2 x i8> [[XN1]], [[X]]
+; CHECK-NEXT:    [[R:%.*]] = icmp eq <2 x i8> [[XN1]], [[X]]
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %xn1 = or <2 x i8> %x, %y
@@ -82,9 +82,8 @@ define i1 @or_eq_noundef(i8 %x, i8 noundef %y) {
 
 define i1 @or_eq_notY_eq_0(i8 %x, i8 %y) {
 ; CHECK-LABEL: @or_eq_notY_eq_0(
-; CHECK-NEXT:    [[NY:%.*]] = xor i8 [[Y:%.*]], -1
-; CHECK-NEXT:    [[OR:%.*]] = or i8 [[NY]], [[X:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[OR]], [[NY]]
+; CHECK-NEXT:    [[TMP1:%.*]] = and i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[TMP1]], 0
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %ny = xor i8 %y, -1
@@ -110,9 +109,8 @@ define i1 @or_eq_notY_eq_0_fail_multiuse(i8 %x, i8 %y) {
 
 define i1 @or_ne_notY_eq_1s(i8 %x, i8 %y) {
 ; CHECK-LABEL: @or_ne_notY_eq_1s(
-; CHECK-NEXT:    [[NY:%.*]] = xor i8 [[Y:%.*]], -1
-; CHECK-NEXT:    [[OR:%.*]] = or i8 [[NY]], [[X:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[OR]], [[X]]
+; CHECK-NEXT:    [[TMP1:%.*]] = or i8 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i8 [[TMP1]], -1
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %ny = xor i8 %y, -1
@@ -136,8 +134,8 @@ define i1 @or_ne_notY_eq_1s_fail_bad_not(i8 %x, i8 %y) {
 
 define <2 x i1> @or_ne_vecC(<2 x i8> %x) {
 ; CHECK-LABEL: @or_ne_vecC(
-; CHECK-NEXT:    [[OR:%.*]] = or <2 x i8> [[X:%.*]], <i8 9, i8 42>
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i8> [[OR]], <i8 9, i8 42>
+; CHECK-NEXT:    [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 -10, i8 -43>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i8> [[TMP1]], zeroinitializer
 ; CHECK-NEXT:    ret <2 x i1> [[CMP]]
 ;
   %or = or <2 x i8> %x, <i8 9, i8 42>
@@ -359,7 +357,7 @@ define i1 @or_simplify_ugt_fail(i8 %y_in, i8 %rhs_in) {
 ; CHECK-LABEL: @or_simplify_ugt_fail(
 ; CHECK-NEXT:    [[RHS:%.*]] = or i8 [[RHS_IN:%.*]], 1
 ; CHECK-NEXT:    [[LBO:%.*]] = or i8 [[RHS]], [[Y_IN:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i8 [[LBO]], [[RHS]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[LBO]], [[RHS]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %y = and i8 %y_in, -2
@@ -371,11 +369,7 @@ define i1 @or_simplify_ugt_fail(i8 %y_in, i8 %rhs_in) {
 
 define i1 @pr64610(ptr %b) {
 ; CHECK-LABEL: @pr64610(
-; CHECK-NEXT:    [[V:%.*]] = load i1, ptr [[B:%.*]], align 2
-; CHECK-NEXT:    [[S:%.*]] = select i1 [[V]], i32 74, i32 0
-; CHECK-NEXT:    [[OR:%.*]] = or i32 [[S]], 1
-; CHECK-NEXT:    [[R:%.*]] = icmp ugt i32 [[OR]], [[S]]
-; CHECK-NEXT:    ret i1 [[R]]
+; CHECK-NEXT:    ret i1 true
 ;
   %v = load i1, ptr %b, align 2
   %s = select i1 %v, i32 74, i32 0


        


More information about the llvm-commits mailing list