[llvm] 20ae2d2 - [InstCombine] Generalize foldAndOrOfICmpEqZeroAndICmp

Dhruv Chawla via llvm-commits llvm-commits at lists.llvm.org
Tue Jul 11 22:44:37 PDT 2023


Author: Dhruv Chawla
Date: 2023-07-12T11:13:37+05:30
New Revision: 20ae2d200dc94b051757174ec0f3a03103b8e1e2

URL: https://github.com/llvm/llvm-project/commit/20ae2d200dc94b051757174ec0f3a03103b8e1e2
DIFF: https://github.com/llvm/llvm-project/commit/20ae2d200dc94b051757174ec0f3a03103b8e1e2.diff

LOG: [InstCombine] Generalize foldAndOrOfICmpEqZeroAndICmp

This patch generalizes the fold implemented by foldAndOrOfICmpEqZeroAndICmp,
which are:

(icmp eq X, 0) | (icmp ult Other, X) -> (icmp ule Other, X-1)
(icmp ne X, 0) & (icmp uge Other, X) -> (icmp ugt Other, X-1)

to the following:

(icmp eq X, C) | (icmp ult Other, (X - C)) -> (icmp ule Other, (X - (C + 1)))
(icmp ne X, C) & (icmp uge Other, (X - C)) -> (icmp ugt Other, (X - (C + 1)))

The function foldAndOrOfICmpEqZeroAndICmp is also renamed to
foldAndOrOfICmpEqConstantAndICmp to reflect the changes.

Proofs: https://alive2.llvm.org/ce/z/yXGv6q

Fixes #63749.

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

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
    llvm/test/Transforms/InstCombine/and-or-icmp-const-icmp.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index c06d5c75963447..3f8660dd93118a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2978,34 +2978,47 @@ Value *InstCombinerImpl::matchSelectFromAndOr(Value *A, Value *C, Value *B,
   return nullptr;
 }
 
-// (icmp eq X, 0) | (icmp ult Other, X) -> (icmp ule Other, X-1)
-// (icmp ne X, 0) & (icmp uge Other, X) -> (icmp ugt Other, X-1)
-static Value *foldAndOrOfICmpEqZeroAndICmp(ICmpInst *LHS, ICmpInst *RHS,
-                                           bool IsAnd, bool IsLogical,
-                                           IRBuilderBase &Builder) {
+// (icmp eq X, C) | (icmp ult Other, (X - C)) -> (icmp ule Other, (X - (C + 1)))
+// (icmp ne X, C) & (icmp uge Other, (X - C)) -> (icmp ugt Other, (X - (C + 1)))
+static Value *foldAndOrOfICmpEqConstantAndICmp(ICmpInst *LHS, ICmpInst *RHS,
+                                               bool IsAnd, bool IsLogical,
+                                               IRBuilderBase &Builder) {
+  Value *LHS0 = LHS->getOperand(0);
+  Value *RHS0 = RHS->getOperand(0);
+  Value *RHS1 = RHS->getOperand(1);
+
   ICmpInst::Predicate LPred =
       IsAnd ? LHS->getInversePredicate() : LHS->getPredicate();
   ICmpInst::Predicate RPred =
       IsAnd ? RHS->getInversePredicate() : RHS->getPredicate();
-  Value *LHS0 = LHS->getOperand(0);
-  if (LPred != ICmpInst::ICMP_EQ || !match(LHS->getOperand(1), m_Zero()) ||
+
+  const APInt *CInt;
+  if (LPred != ICmpInst::ICMP_EQ ||
+      !match(LHS->getOperand(1), m_APIntAllowUndef(CInt)) ||
       !LHS0->getType()->isIntOrIntVectorTy() ||
       !(LHS->hasOneUse() || RHS->hasOneUse()))
     return nullptr;
 
+  auto MatchRHSOp = [LHS0, CInt](const Value *RHSOp) {
+    return match(RHSOp,
+                 m_Add(m_Specific(LHS0), m_SpecificIntAllowUndef(-*CInt))) ||
+           (CInt->isZero() && RHSOp == LHS0);
+  };
+
   Value *Other;
-  if (RPred == ICmpInst::ICMP_ULT && RHS->getOperand(1) == LHS0)
-    Other = RHS->getOperand(0);
-  else if (RPred == ICmpInst::ICMP_UGT && RHS->getOperand(0) == LHS0)
-    Other = RHS->getOperand(1);
+  if (RPred == ICmpInst::ICMP_ULT && MatchRHSOp(RHS1))
+    Other = RHS0;
+  else if (RPred == ICmpInst::ICMP_UGT && MatchRHSOp(RHS0))
+    Other = RHS1;
   else
     return nullptr;
 
   if (IsLogical)
     Other = Builder.CreateFreeze(Other);
+
   return Builder.CreateICmp(
       IsAnd ? ICmpInst::ICMP_ULT : ICmpInst::ICMP_UGE,
-      Builder.CreateAdd(LHS0, Constant::getAllOnesValue(LHS0->getType())),
+      Builder.CreateSub(LHS0, ConstantInt::get(LHS0->getType(), *CInt + 1)),
       Other);
 }
 
@@ -3052,12 +3065,12 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
     return V;
 
   if (Value *V =
-          foldAndOrOfICmpEqZeroAndICmp(LHS, RHS, IsAnd, IsLogical, Builder))
+          foldAndOrOfICmpEqConstantAndICmp(LHS, RHS, IsAnd, IsLogical, Builder))
     return V;
   // We can treat logical like bitwise here, because both operands are used on
   // the LHS, and as such poison from both will propagate.
-  if (Value *V = foldAndOrOfICmpEqZeroAndICmp(RHS, LHS, IsAnd,
-                                              /*IsLogical*/ false, Builder))
+  if (Value *V = foldAndOrOfICmpEqConstantAndICmp(RHS, LHS, IsAnd,
+                                                  /*IsLogical*/ false, Builder))
     return V;
 
   if (Value *V =

diff  --git a/llvm/test/Transforms/InstCombine/and-or-icmp-const-icmp.ll b/llvm/test/Transforms/InstCombine/and-or-icmp-const-icmp.ll
index a410cacce8dd82..8531c7db1ee3fd 100644
--- a/llvm/test/Transforms/InstCombine/and-or-icmp-const-icmp.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-icmp-const-icmp.ll
@@ -28,10 +28,8 @@ define i1 @eq_basic(i8 %x, i8 %y) {
 define i1 @ne_basic_equal_5(i8 %x, i8 %y) {
 ; CHECK-LABEL: define i1 @ne_basic_equal_5
 ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
-; CHECK-NEXT:    [[SUB:%.*]] = add i8 [[X]], -5
-; CHECK-NEXT:    [[C1:%.*]] = icmp ne i8 [[X]], 5
-; CHECK-NEXT:    [[C2:%.*]] = icmp ule i8 [[SUB]], [[Y]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C1]], [[C2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[X]], -6
+; CHECK-NEXT:    [[AND:%.*]] = icmp ult i8 [[TMP1]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %sub = add i8 %x, -5
@@ -44,10 +42,7 @@ define i1 @ne_basic_equal_5(i8 %x, i8 %y) {
 define i1 @eq_basic_equal_minus_1(i8 %x, i8 %y) {
 ; CHECK-LABEL: define i1 @eq_basic_equal_minus_1
 ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[X]], 1
-; CHECK-NEXT:    [[C1:%.*]] = icmp eq i8 [[X]], -1
-; CHECK-NEXT:    [[C2:%.*]] = icmp ugt i8 [[ADD]], [[Y]]
-; CHECK-NEXT:    [[OR:%.*]] = or i1 [[C1]], [[C2]]
+; CHECK-NEXT:    [[OR:%.*]] = icmp uge i8 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[OR]]
 ;
   %add = add i8 %x, 1
@@ -60,10 +55,8 @@ define i1 @eq_basic_equal_minus_1(i8 %x, i8 %y) {
 define i1 @ne_basic_equal_minus_7(i8 %x, i8 %y) {
 ; CHECK-LABEL: define i1 @ne_basic_equal_minus_7
 ; CHECK-SAME: (i8 [[X:%.*]], i8 [[Y:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[X]], 7
-; CHECK-NEXT:    [[C1:%.*]] = icmp ne i8 [[X]], -7
-; CHECK-NEXT:    [[C2:%.*]] = icmp ule i8 [[ADD]], [[Y]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C1]], [[C2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add i8 [[X]], 6
+; CHECK-NEXT:    [[AND:%.*]] = icmp ult i8 [[TMP1]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %add = add i8 %x, 7
@@ -159,10 +152,8 @@ define <2 x i1> @eq_vector(<2 x i8> %x, <2 x i8> %y) {
 define <2 x i1> @ne_vector_equal_5(<2 x i8> %x, <2 x i8> %y) {
 ; CHECK-LABEL: define <2 x i1> @ne_vector_equal_5
 ; CHECK-SAME: (<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
-; CHECK-NEXT:    [[SUB:%.*]] = add <2 x i8> [[X]], <i8 -5, i8 -5>
-; CHECK-NEXT:    [[C1:%.*]] = icmp ne <2 x i8> [[X]], <i8 5, i8 5>
-; CHECK-NEXT:    [[C2:%.*]] = icmp ule <2 x i8> [[SUB]], [[Y]]
-; CHECK-NEXT:    [[AND:%.*]] = and <2 x i1> [[C1]], [[C2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i8> [[X]], <i8 -6, i8 -6>
+; CHECK-NEXT:    [[AND:%.*]] = icmp ult <2 x i8> [[TMP1]], [[Y]]
 ; CHECK-NEXT:    ret <2 x i1> [[AND]]
 ;
   %sub = add <2 x i8> %x, <i8 -5, i8 -5>
@@ -175,10 +166,7 @@ define <2 x i1> @ne_vector_equal_5(<2 x i8> %x, <2 x i8> %y) {
 define <2 x i1> @eq_vector_equal_minus_1(<2 x i8> %x, <2 x i8> %y) {
 ; CHECK-LABEL: define <2 x i1> @eq_vector_equal_minus_1
 ; CHECK-SAME: (<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i8> [[X]], <i8 1, i8 1>
-; CHECK-NEXT:    [[C1:%.*]] = icmp eq <2 x i8> [[X]], <i8 -1, i8 -1>
-; CHECK-NEXT:    [[C2:%.*]] = icmp ugt <2 x i8> [[ADD]], [[Y]]
-; CHECK-NEXT:    [[OR:%.*]] = or <2 x i1> [[C1]], [[C2]]
+; CHECK-NEXT:    [[OR:%.*]] = icmp uge <2 x i8> [[X]], [[Y]]
 ; CHECK-NEXT:    ret <2 x i1> [[OR]]
 ;
   %add = add <2 x i8> %x, <i8 1, i8 1>
@@ -191,10 +179,8 @@ define <2 x i1> @eq_vector_equal_minus_1(<2 x i8> %x, <2 x i8> %y) {
 define <2 x i1> @ne_vector_equal_minus_7(<2 x i8> %x, <2 x i8> %y) {
 ; CHECK-LABEL: define <2 x i1> @ne_vector_equal_minus_7
 ; CHECK-SAME: (<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
-; CHECK-NEXT:    [[ADD:%.*]] = add <2 x i8> [[X]], <i8 7, i8 7>
-; CHECK-NEXT:    [[C1:%.*]] = icmp ne <2 x i8> [[X]], <i8 -7, i8 -7>
-; CHECK-NEXT:    [[C2:%.*]] = icmp ule <2 x i8> [[ADD]], [[Y]]
-; CHECK-NEXT:    [[AND:%.*]] = and <2 x i1> [[C1]], [[C2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i8> [[X]], <i8 6, i8 6>
+; CHECK-NEXT:    [[AND:%.*]] = icmp ult <2 x i8> [[TMP1]], [[Y]]
 ; CHECK-NEXT:    ret <2 x i1> [[AND]]
 ;
   %add = add <2 x i8> %x, <i8 7, i8 7>
@@ -239,13 +225,11 @@ define <2 x i1> @ne_vector_unequal2(<2 x i8> %x, <2 x i8> %y) {
 ; ==============================================================================
 ; Tests with undef
 ; ==============================================================================
-define <2 x i1> @eq_vector_undef(<2 x i8> %x, <2 x i8> %y) {
-; CHECK-LABEL: define <2 x i1> @eq_vector_undef
+define <2 x i1> @eq_vector_undef_icmp(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: define <2 x i1> @eq_vector_undef_icmp
 ; CHECK-SAME: (<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
-; CHECK-NEXT:    [[SUB:%.*]] = add <2 x i8> [[X]], <i8 -5, i8 -5>
-; CHECK-NEXT:    [[C1:%.*]] = icmp eq <2 x i8> [[X]], <i8 5, i8 undef>
-; CHECK-NEXT:    [[C2:%.*]] = icmp ugt <2 x i8> [[SUB]], [[Y]]
-; CHECK-NEXT:    [[OR:%.*]] = or <2 x i1> [[C1]], [[C2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i8> [[X]], <i8 -6, i8 -6>
+; CHECK-NEXT:    [[OR:%.*]] = icmp uge <2 x i8> [[TMP1]], [[Y]]
 ; CHECK-NEXT:    ret <2 x i1> [[OR]]
 ;
   %sub = add <2 x i8> %x, <i8 -5, i8 -5>
@@ -255,6 +239,20 @@ define <2 x i1> @eq_vector_undef(<2 x i8> %x, <2 x i8> %y) {
   ret <2 x i1> %or
 }
 
+define <2 x i1> @eq_vector_undef_add(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: define <2 x i1> @eq_vector_undef_add
+; CHECK-SAME: (<2 x i8> [[X:%.*]], <2 x i8> [[Y:%.*]]) {
+; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i8> [[X]], <i8 -6, i8 -6>
+; CHECK-NEXT:    [[OR:%.*]] = icmp uge <2 x i8> [[TMP1]], [[Y]]
+; CHECK-NEXT:    ret <2 x i1> [[OR]]
+;
+  %sub = add <2 x i8> %x, <i8 -5, i8 undef>
+  %c1 = icmp eq <2 x i8> %x, <i8 5, i8 5>
+  %c2 = icmp ugt <2 x i8> %sub, %y
+  %or = or <2 x i1> %c1, %c2
+  ret <2 x i1> %or
+}
+
 ; ==============================================================================
 ; Tests with values commuted
 ; ==============================================================================
@@ -277,10 +275,7 @@ define i1 @ne_commuted_equal_minus_1(i8 %x, i8 %py) {
 ; CHECK-LABEL: define i1 @ne_commuted_equal_minus_1
 ; CHECK-SAME: (i8 [[X:%.*]], i8 [[PY:%.*]]) {
 ; CHECK-NEXT:    [[Y:%.*]] = sdiv i8 42, [[PY]]
-; CHECK-NEXT:    [[ADD:%.*]] = add i8 [[X]], 1
-; CHECK-NEXT:    [[C1:%.*]] = icmp ne i8 [[X]], -1
-; CHECK-NEXT:    [[C2:%.*]] = icmp uge i8 [[Y]], [[ADD]]
-; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C1]], [[C2]]
+; CHECK-NEXT:    [[AND:%.*]] = icmp ugt i8 [[Y]], [[X]]
 ; CHECK-NEXT:    ret i1 [[AND]]
 ;
   %y = sdiv i8 42, %py ; thwart complexity-based canonicalization


        


More information about the llvm-commits mailing list