[llvm] ddd18d0 - [InstCombine] Transform `icmp eq/ne ({su}div exact X,Y),C` -> `icmp eq/ne X, Y*C`

Noah Goldstein via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 13 17:37:18 PDT 2023


Author: Noah Goldstein
Date: 2023-07-13T19:36:59-05:00
New Revision: ddd18d02c71be4b683a2f9440c7c0d9c4ca4abe8

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

LOG: [InstCombine] Transform `icmp eq/ne ({su}div exact X,Y),C` -> `icmp eq/ne X, Y*C`

We can do this if `Y*C` doesn't overflow. This is trivial if `C` is
0/1. Otherwise we actually generate a `mul` instruction iff the `div`
has one use.

Alive2 Links:
    udiv: https://alive2.llvm.org/ce/z/GWPW67
    sdiv: https://alive2.llvm.org/ce/z/bUoX9h

Reviewed By: nikic

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

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 4a282bee362e3b..a70877549ce7f9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3323,7 +3323,29 @@ Instruction *InstCombinerImpl::foldICmpBinOpEqualityWithConstant(
     break;
   }
   case Instruction::UDiv:
-    if (C.isZero()) {
+  case Instruction::SDiv:
+    if (BO->isExact()) {
+      // div exact X, Y eq/ne 0 -> X eq/ne 0
+      // div exact X, Y eq/ne 1 -> X eq/ne Y
+      // div exact X, Y eq/ne C ->
+      //    if Y * C never-overflow && OneUse:
+      //      -> Y * C eq/ne X
+      if (C.isZero())
+        return new ICmpInst(Pred, BOp0, Constant::getNullValue(BO->getType()));
+      else if (C.isOne())
+        return new ICmpInst(Pred, BOp0, BOp1);
+      else if (BO->hasOneUse()) {
+        OverflowResult OR = computeOverflow(
+            Instruction::Mul, BO->getOpcode() == Instruction::SDiv, BOp1,
+            Cmp.getOperand(1), BO);
+        if (OR == OverflowResult::NeverOverflows) {
+          Value *YC =
+              Builder.CreateMul(BOp1, ConstantInt::get(BO->getType(), C));
+          return new ICmpInst(Pred, YC, BOp0);
+        }
+      }
+    }
+    if (BO->getOpcode() == Instruction::UDiv && C.isZero()) {
       // (icmp eq/ne (udiv A, B), 0) -> (icmp ugt/ule i32 B, A)
       auto NewPred = isICMP_NE ? ICmpInst::ICMP_ULE : ICmpInst::ICMP_UGT;
       return new ICmpInst(NewPred, BOp1, BOp0);

diff  --git a/llvm/test/Transforms/InstCombine/sdiv-icmp.ll b/llvm/test/Transforms/InstCombine/sdiv-icmp.ll
index 39da0a27dad10f..0a6fecd810c879 100644
--- a/llvm/test/Transforms/InstCombine/sdiv-icmp.ll
+++ b/llvm/test/Transforms/InstCombine/sdiv-icmp.ll
@@ -4,8 +4,7 @@
 declare void @use.i8(i8)
 define i1 @sdiv_exact_eq_0(i8 %x, i8 %y) {
 ; CHECK-LABEL: @sdiv_exact_eq_0(
-; CHECK-NEXT:    [[D:%.*]] = sdiv exact i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[D]], 0
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %d = sdiv exact i8 %x, %y
@@ -15,7 +14,7 @@ define i1 @sdiv_exact_eq_0(i8 %x, i8 %y) {
 
 define i1 @udiv_exact_ne_0(i8 %x, i8 %y) {
 ; CHECK-LABEL: @udiv_exact_ne_0(
-; CHECK-NEXT:    [[R:%.*]] = icmp ule i8 [[Y:%.*]], [[X:%.*]]
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %d = udiv exact i8 %x, %y
@@ -25,8 +24,7 @@ define i1 @udiv_exact_ne_0(i8 %x, i8 %y) {
 
 define i1 @sdiv_exact_ne_1(i8 %x, i8 %y) {
 ; CHECK-LABEL: @sdiv_exact_ne_1(
-; CHECK-NEXT:    [[D:%.*]] = sdiv exact i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[D]], 0
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[X:%.*]], 0
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %d = sdiv exact i8 %x, %y
@@ -36,8 +34,7 @@ define i1 @sdiv_exact_ne_1(i8 %x, i8 %y) {
 
 define i1 @udiv_exact_eq_1(i8 %x, i8 %y) {
 ; CHECK-LABEL: @udiv_exact_eq_1(
-; CHECK-NEXT:    [[D:%.*]] = udiv exact i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[D]], 1
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %d = udiv exact i8 %x, %y
@@ -48,8 +45,8 @@ define i1 @udiv_exact_eq_1(i8 %x, i8 %y) {
 define i1 @sdiv_exact_eq_9_no_of(i8 %x, i8 %y) {
 ; CHECK-LABEL: @sdiv_exact_eq_9_no_of(
 ; CHECK-NEXT:    [[YY:%.*]] = and i8 [[Y:%.*]], 7
-; CHECK-NEXT:    [[D:%.*]] = sdiv exact i8 [[X:%.*]], [[YY]]
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[D]], 9
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nuw nsw i8 [[YY]], 9
+; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[TMP1]], [[X:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %yy = and i8 %y, 7
@@ -100,8 +97,8 @@ define i1 @sdiv_exact_eq_9_must_of_todo_is_false(i8 %x, i8 %y) {
 define i1 @udiv_exact_ne_30_no_of(i8 %x, i8 %y) {
 ; CHECK-LABEL: @udiv_exact_ne_30_no_of(
 ; CHECK-NEXT:    [[YY:%.*]] = and i8 [[Y:%.*]], 7
-; CHECK-NEXT:    [[D:%.*]] = udiv exact i8 [[X:%.*]], [[YY]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[D]], 30
+; CHECK-NEXT:    [[TMP1:%.*]] = mul nuw i8 [[YY]], 30
+; CHECK-NEXT:    [[R:%.*]] = icmp ne i8 [[TMP1]], [[X:%.*]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %yy = and i8 %y, 7


        


More information about the llvm-commits mailing list