[llvm] c661691 - [InstCombine] fold icmp with 'mul nsw/nuw' and constant operands

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 5 14:30:40 PDT 2020


Author: Sanjay Patel
Date: 2020-08-05T17:29:32-04:00
New Revision: c66169136fe667d653ff40ba4bd9f6047702e93c

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

LOG: [InstCombine] fold icmp with 'mul nsw/nuw' and constant operands

This also removes a more specific fold that only handled icmp with 0.

https://rise4fun.com/Alive/sdM9

  Name: mul nsw with icmp eq
  Pre: (C1 != 0) && (C2 % C1) == 0
  %a = mul nsw i8 %x, C1
  %r = icmp eq i8 %a, C2
    =>
  %r = icmp eq i8 %x, C2 / C1

  Name: mul nuw with icmp eq
  Pre: (C1 != 0) && (C2 %u C1) == 0
  %a = mul nuw i8 %x, C1
  %r = icmp eq i8 %a, C2
    =>
  %r = icmp eq i8 %x, C2 /u C1

  Name: mul nsw with icmp ne
  Pre: (C1 != 0) && (C2 % C1) == 0
  %a = mul nsw i8 %x, C1
  %r = icmp ne i8 %a, C2
    =>
  %r = icmp ne i8 %x, C2 / C1

  Name: mul nuw with icmp ne
  Pre: (C1 != 0) && (C2 %u C1) == 0
  %a = mul nuw i8 %x, C1
  %r = icmp ne i8 %a, C2
    =>
  %r = icmp ne i8 %x, C2 /u C1

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 ca2bcb9bc415..7aa3126e1754 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -1981,6 +1981,21 @@ Instruction *InstCombinerImpl::foldICmpMulConstant(ICmpInst &Cmp,
                         Constant::getNullValue(Mul->getType()));
   }
 
+  // If the multiply does not wrap, try to divide the compare constant by the
+  // multiplication factor.
+  if (Cmp.isEquality() && !MulC->isNullValue()) {
+    // (mul nsw X, MulC) == C --> X == C /s MulC
+    if (Mul->hasNoSignedWrap() && C.srem(*MulC).isNullValue()) {
+      Constant *NewC = ConstantInt::get(Mul->getType(), C.sdiv(*MulC));
+      return new ICmpInst(Pred, Mul->getOperand(0), NewC);
+    }
+    // (mul nuw X, MulC) == C --> X == C /u MulC
+    if (Mul->hasNoUnsignedWrap() && C.urem(*MulC).isNullValue()) {
+      Constant *NewC = ConstantInt::get(Mul->getType(), C.udiv(*MulC));
+      return new ICmpInst(Pred, Mul->getOperand(0), NewC);
+    }
+  }
+
   return nullptr;
 }
 
@@ -3051,17 +3066,6 @@ Instruction *InstCombinerImpl::foldICmpBinOpEqualityWithConstant(
     }
     break;
   }
-  case Instruction::Mul:
-    if (C.isNullValue() && BO->hasNoSignedWrap()) {
-      const APInt *BOC;
-      if (match(BOp1, m_APInt(BOC)) && !BOC->isNullValue()) {
-        // The trivial case (mul X, 0) is handled by InstSimplify.
-        // General case : (mul X, C) != 0 iff X != 0
-        //                (mul X, C) == 0 iff X == 0
-        return new ICmpInst(Pred, BOp0, Constant::getNullValue(RHS->getType()));
-      }
-    }
-    break;
   case Instruction::UDiv:
     if (C.isNullValue()) {
       // (icmp eq/ne (udiv A, B), 0) -> (icmp ugt/ule i32 B, A)

diff  --git a/llvm/test/Transforms/InstCombine/icmp-mul.ll b/llvm/test/Transforms/InstCombine/icmp-mul.ll
index 45c50c325b96..8e7d9056726e 100644
--- a/llvm/test/Transforms/InstCombine/icmp-mul.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-mul.ll
@@ -121,8 +121,7 @@ define i1 @ugt_rem_nz(i8 %x) {
 
 define i1 @eq_nsw_rem_zero(i8 %x) {
 ; CHECK-LABEL: @eq_nsw_rem_zero(
-; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], -5
-; CHECK-NEXT:    [[B:%.*]] = icmp eq i8 [[A]], 20
+; CHECK-NEXT:    [[B:%.*]] = icmp eq i8 [[X:%.*]], -4
 ; CHECK-NEXT:    ret i1 [[B]]
 ;
   %a = mul nsw i8 %x, -5
@@ -132,8 +131,7 @@ define i1 @eq_nsw_rem_zero(i8 %x) {
 
 define <2 x i1> @ne_nsw_rem_zero(<2 x i8> %x) {
 ; CHECK-LABEL: @ne_nsw_rem_zero(
-; CHECK-NEXT:    [[A:%.*]] = mul nsw <2 x i8> [[X:%.*]], <i8 5, i8 5>
-; CHECK-NEXT:    [[B:%.*]] = icmp ne <2 x i8> [[A]], <i8 -30, i8 -30>
+; CHECK-NEXT:    [[B:%.*]] = icmp ne <2 x i8> [[X:%.*]], <i8 -6, i8 -6>
 ; CHECK-NEXT:    ret <2 x i1> [[B]]
 ;
   %a = mul nsw <2 x i8> %x, <i8 5, i8 5>
@@ -141,6 +139,8 @@ define <2 x i1> @ne_nsw_rem_zero(<2 x i8> %x) {
   ret <2 x i1> %b
 }
 
+; TODO: Missed fold with undef.
+
 define <2 x i1> @ne_nsw_rem_zero_undef1(<2 x i8> %x) {
 ; CHECK-LABEL: @ne_nsw_rem_zero_undef1(
 ; CHECK-NEXT:    [[A:%.*]] = mul nsw <2 x i8> [[X:%.*]], <i8 5, i8 undef>
@@ -152,6 +152,8 @@ define <2 x i1> @ne_nsw_rem_zero_undef1(<2 x i8> %x) {
   ret <2 x i1> %b
 }
 
+; TODO: Missed fold with undef.
+
 define <2 x i1> @ne_nsw_rem_zero_undef2(<2 x i8> %x) {
 ; CHECK-LABEL: @ne_nsw_rem_zero_undef2(
 ; CHECK-NEXT:    [[A:%.*]] = mul nsw <2 x i8> [[X:%.*]], <i8 5, i8 5>
@@ -167,7 +169,7 @@ define i1 @eq_nsw_rem_zero_uses(i8 %x) {
 ; CHECK-LABEL: @eq_nsw_rem_zero_uses(
 ; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[X:%.*]], -5
 ; CHECK-NEXT:    call void @use(i8 [[A]])
-; CHECK-NEXT:    [[B:%.*]] = icmp eq i8 [[A]], 20
+; CHECK-NEXT:    [[B:%.*]] = icmp eq i8 [[X]], -4
 ; CHECK-NEXT:    ret i1 [[B]]
 ;
   %a = mul nsw i8 %x, -5
@@ -200,8 +202,7 @@ define i1 @ne_nsw_rem_nz(i8 %x) {
 
 define <2 x i1> @eq_nuw_rem_zero(<2 x i8> %x) {
 ; CHECK-LABEL: @eq_nuw_rem_zero(
-; CHECK-NEXT:    [[A:%.*]] = mul nuw <2 x i8> [[X:%.*]], <i8 5, i8 5>
-; CHECK-NEXT:    [[B:%.*]] = icmp eq <2 x i8> [[A]], <i8 20, i8 20>
+; CHECK-NEXT:    [[B:%.*]] = icmp eq <2 x i8> [[X:%.*]], <i8 4, i8 4>
 ; CHECK-NEXT:    ret <2 x i1> [[B]]
 ;
   %a = mul nuw <2 x i8> %x, <i8 5, i8 5>
@@ -209,6 +210,8 @@ define <2 x i1> @eq_nuw_rem_zero(<2 x i8> %x) {
   ret <2 x i1> %b
 }
 
+; TODO: Missed fold with undef.
+
 define <2 x i1> @eq_nuw_rem_zero_undef1(<2 x i8> %x) {
 ; CHECK-LABEL: @eq_nuw_rem_zero_undef1(
 ; CHECK-NEXT:    [[A:%.*]] = mul nuw <2 x i8> [[X:%.*]], <i8 undef, i8 5>
@@ -220,6 +223,8 @@ define <2 x i1> @eq_nuw_rem_zero_undef1(<2 x i8> %x) {
   ret <2 x i1> %b
 }
 
+; TODO: Missed fold with undef.
+
 define <2 x i1> @eq_nuw_rem_zero_undef2(<2 x i8> %x) {
 ; CHECK-LABEL: @eq_nuw_rem_zero_undef2(
 ; CHECK-NEXT:    [[A:%.*]] = mul nuw <2 x i8> [[X:%.*]], <i8 5, i8 5>
@@ -233,8 +238,7 @@ define <2 x i1> @eq_nuw_rem_zero_undef2(<2 x i8> %x) {
 
 define i1 @ne_nuw_rem_zero(i8 %x) {
 ; CHECK-LABEL: @ne_nuw_rem_zero(
-; CHECK-NEXT:    [[A:%.*]] = mul nuw i8 [[X:%.*]], 5
-; CHECK-NEXT:    [[B:%.*]] = icmp ne i8 [[A]], -126
+; CHECK-NEXT:    [[B:%.*]] = icmp ne i8 [[X:%.*]], 26
 ; CHECK-NEXT:    ret i1 [[B]]
 ;
   %a = mul nuw i8 %x, 5
@@ -246,7 +250,7 @@ define i1 @ne_nuw_rem_zero_uses(i8 %x) {
 ; CHECK-LABEL: @ne_nuw_rem_zero_uses(
 ; CHECK-NEXT:    [[A:%.*]] = mul nuw i8 [[X:%.*]], 5
 ; CHECK-NEXT:    call void @use(i8 [[A]])
-; CHECK-NEXT:    [[B:%.*]] = icmp ne i8 [[A]], -126
+; CHECK-NEXT:    [[B:%.*]] = icmp ne i8 [[X]], 26
 ; CHECK-NEXT:    ret i1 [[B]]
 ;
   %a = mul nuw i8 %x, 5


        


More information about the llvm-commits mailing list