[llvm] abbd256 - Improve transforms for (icmp uPred X * Z, Y * Z) -> (icmp uPred X, Y)

Noah Goldstein via llvm-commits llvm-commits at lists.llvm.org
Mon Feb 6 12:16:51 PST 2023


Author: Noah Goldstein
Date: 2023-02-06T14:09:18-06:00
New Revision: abbd256a810a0b0c92dda88a3050fc85cb604a9c

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

LOG: Improve transforms for (icmp uPred X * Z, Y * Z) -> (icmp uPred X, Y)

Several cases where missing.

1. `(icmp eq/ne X*Z, Y*Z) [if Z % 2 != 0] -> (icmp eq/ne X, Y)`
    EQ: https://alive2.llvm.org/ce/z/6_HPZ5
    NE: https://alive2.llvm.org/ce/z/c34qSU

    There was previously an implementation of this that work of `Y`
    was non-constant, but it was missing if `Y*Z` evaluated to a
    constant and/or `nsw`/`nuw` where both false. As well it only
    worked if `Z` was a constant but we can check 1s bit of
    `KnownBits` to cover more cases.

2. `(icmp eq/ne X*Z, Y*Z) [if Z != 0 and nsw(X*Y) and nsw(Y*Z)] -> (icmp eq/ne X, Y)`
    EQ: https://alive2.llvm.org/ce/z/6SdAG6
    NE: https://alive2.llvm.org/ce/z/fjsq_b

    This was previously implemented only to work if `Z` was constant,
    but we can use `isKnownNonZero` to cover more cases.

3. `(icmp uPred X*Y, Y*Z) [if Z != 0 and nuw(X*Y) and nuw(X*Y)] -> (icmp uPred X, Y)`
    EQ:  https://alive2.llvm.org/ce/z/FqWQLX
    NE:  https://alive2.llvm.org/ce/z/2gHrd2
    ULT: https://alive2.llvm.org/ce/z/MUAWgZ
    ULE: https://alive2.llvm.org/ce/z/szQQ2L
    UGT: https://alive2.llvm.org/ce/z/McVUdu
    UGE: https://alive2.llvm.org/ce/z/95uyC8

    This was previously implemented only for `eq/ne` cases. As well
    only if `Z` was constant, but again we can use `isKnownNonZero` to
    cover more cases.

Reviewed By: spatel

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

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
    llvm/test/Transforms/InstCombine/icmp-mul.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index bfe586c0d1c9..6bd3c826c9e4 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -4404,16 +4404,37 @@ Instruction *InstCombinerImpl::foldICmpBinOp(ICmpInst &I,
   }
 
   {
-    // Try to remove shared constant multiplier from equality comparison:
-    // X * C == Y * C (with no overflowing/aliasing) --> X == Y
-    Value *X, *Y;
-    const APInt *C;
-    if (match(Op0, m_Mul(m_Value(X), m_APInt(C))) && *C != 0 &&
-        match(Op1, m_Mul(m_Value(Y), m_SpecificInt(*C))) && I.isEquality())
-      if (!C->countTrailingZeros() ||
-          (BO0 && BO1 && BO0->hasNoSignedWrap() && BO1->hasNoSignedWrap()) ||
-          (BO0 && BO1 && BO0->hasNoUnsignedWrap() && BO1->hasNoUnsignedWrap()))
-      return new ICmpInst(Pred, X, Y);
+    // Try to remove shared multiplier from comparison:
+    // X * Z u{lt/le/gt/ge}/eq/ne Y * Z
+    Value *X, *Y, *Z;
+    if (Pred == ICmpInst::getUnsignedPredicate(Pred) &&
+        ((match(Op0, m_Mul(m_Value(X), m_Value(Z))) &&
+          match(Op1, m_c_Mul(m_Specific(Z), m_Value(Y)))) ||
+         (match(Op0, m_Mul(m_Value(Z), m_Value(X))) &&
+          match(Op1, m_c_Mul(m_Specific(Z), m_Value(Y)))))) {
+      bool NonZero;
+      if (ICmpInst::isEquality(Pred)) {
+        KnownBits ZKnown = computeKnownBits(Z, 0, &I);
+        // if Z % 2 != 0
+        //    X * Z eq/ne Y * Z -> X eq/ne Y
+        if (ZKnown.countMaxTrailingZeros() == 0)
+          return new ICmpInst(Pred, X, Y);
+        NonZero = !ZKnown.One.isZero() ||
+                  isKnownNonZero(Z, Q.DL, /*Depth=*/0, Q.AC, Q.CxtI, Q.DT);
+        // if Z != 0 and nsw(X * Z) and nsw(Y * Z)
+        //    X * Z eq/ne Y * Z -> X eq/ne Y
+        if (NonZero && BO0 && BO1 && BO0->hasNoSignedWrap() &&
+            BO1->hasNoSignedWrap())
+          return new ICmpInst(Pred, X, Y);
+      } else
+        NonZero = isKnownNonZero(Z, Q.DL, /*Depth=*/0, Q.AC, Q.CxtI, Q.DT);
+
+      // If Z != 0 and nuw(X * Z) and nuw(Y * Z)
+      //    X * Z u{lt/le/gt/ge}/eq/ne Y * Z -> X u{lt/le/gt/ge}/eq/ne Y
+      if (NonZero && BO0 && BO1 && BO0->hasNoUnsignedWrap() &&
+          BO1->hasNoUnsignedWrap())
+        return new ICmpInst(Pred, X, Y);
+    }
   }
 
   BinaryOperator *SRem = nullptr;

diff  --git a/llvm/test/Transforms/InstCombine/icmp-mul.ll b/llvm/test/Transforms/InstCombine/icmp-mul.ll
index e26ea68e8304..7adcaf390f53 100644
--- a/llvm/test/Transforms/InstCombine/icmp-mul.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-mul.ll
@@ -1047,9 +1047,7 @@ define i1 @mul_xy_z_assumeodd_eq(i8 %x, i8 %y, i8 %z) {
 ; CHECK-NEXT:    [[LB:%.*]] = and i8 [[Z:%.*]], 1
 ; CHECK-NEXT:    [[NZ:%.*]] = icmp ne i8 [[LB]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[NZ]])
-; CHECK-NEXT:    [[MULX:%.*]] = mul i8 [[X:%.*]], [[Z]]
-; CHECK-NEXT:    [[MULY:%.*]] = mul i8 [[Z]], [[Y:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[MULX]], [[MULY]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
   %lb = and i8 %z, 1
@@ -1064,9 +1062,8 @@ define i1 @mul_xy_z_assumeodd_eq(i8 %x, i8 %y, i8 %z) {
 define <2 x i1> @reused_mul_nsw_xy_z_setnonzero_vec_ne(<2 x i8> %x, <2 x i8> %y, <2 x i8> %zi) {
 ; CHECK-LABEL: @reused_mul_nsw_xy_z_setnonzero_vec_ne(
 ; CHECK-NEXT:    [[Z:%.*]] = or <2 x i8> [[ZI:%.*]], <i8 4, i8 4>
-; CHECK-NEXT:    [[MULX:%.*]] = mul nsw <2 x i8> [[Z]], [[X:%.*]]
 ; CHECK-NEXT:    [[MULY:%.*]] = mul nsw <2 x i8> [[Z]], [[Y:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i8> [[MULY]], [[MULX]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ne <2 x i8> [[Y]], [[X:%.*]]
 ; CHECK-NEXT:    call void @usev2xi8(<2 x i8> [[MULY]])
 ; CHECK-NEXT:    ret <2 x i1> [[CMP]]
 ;
@@ -1098,8 +1095,7 @@ define i1 @mul_nuw_xy_z_assumenonzero_uge(i8 %x, i8 %y, i8 %z) {
 ; CHECK-NEXT:    [[NZ:%.*]] = icmp ne i8 [[Z:%.*]], 0
 ; CHECK-NEXT:    call void @llvm.assume(i1 [[NZ]])
 ; CHECK-NEXT:    [[MULX:%.*]] = mul nuw i8 [[X:%.*]], [[Z]]
-; CHECK-NEXT:    [[MULY:%.*]] = mul nuw i8 [[Y:%.*]], [[Z]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i8 [[MULY]], [[MULX]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp uge i8 [[Y:%.*]], [[X]]
 ; CHECK-NEXT:    call void @use(i8 [[MULX]])
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ;
@@ -1114,10 +1110,7 @@ define i1 @mul_nuw_xy_z_assumenonzero_uge(i8 %x, i8 %y, i8 %z) {
 
 define <2 x i1> @mul_nuw_xy_z_setnonzero_vec_eq(<2 x i8> %x, <2 x i8> %y, <2 x i8> %zi) {
 ; CHECK-LABEL: @mul_nuw_xy_z_setnonzero_vec_eq(
-; CHECK-NEXT:    [[Z:%.*]] = or <2 x i8> [[ZI:%.*]], <i8 41, i8 12>
-; CHECK-NEXT:    [[MULX:%.*]] = mul nuw <2 x i8> [[Z]], [[X:%.*]]
-; CHECK-NEXT:    [[MULY:%.*]] = mul nuw <2 x i8> [[Z]], [[Y:%.*]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i8> [[MULX]], [[MULY]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x i8> [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    ret <2 x i1> [[CMP]]
 ;
   %z = or <2 x i8> %zi, <i8 41, i8 12>
@@ -1132,9 +1125,7 @@ define i1 @mul_nuw_xy_z_brnonzero_ult(i8 %x, i8 %y, i8 %z) {
 ; CHECK-NEXT:    [[NZ_NOT:%.*]] = icmp eq i8 [[Z:%.*]], 0
 ; CHECK-NEXT:    br i1 [[NZ_NOT]], label [[FALSE:%.*]], label [[TRUE:%.*]]
 ; CHECK:       true:
-; CHECK-NEXT:    [[MULX:%.*]] = mul nuw i8 [[X:%.*]], [[Z]]
-; CHECK-NEXT:    [[MULY:%.*]] = mul nuw i8 [[Y:%.*]], [[Z]]
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[MULY]], [[MULX]]
+; CHECK-NEXT:    [[CMP:%.*]] = icmp ult i8 [[Y:%.*]], [[X:%.*]]
 ; CHECK-NEXT:    ret i1 [[CMP]]
 ; CHECK:       false:
 ; CHECK-NEXT:    call void @use(i8 [[Z]])


        


More information about the llvm-commits mailing list