[llvm] 49f8b05 - [InstCombine] fold icmp equality with sdiv and SMIN

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Thu May 26 13:19:34 PDT 2022


Author: Sanjay Patel
Date: 2022-05-26T16:19:15-04:00
New Revision: 49f8b0513763c2621d8d872ec19a33cc7a00d4c8

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

LOG: [InstCombine] fold icmp equality with sdiv and SMIN

This extends the fold from D126410 / 3952c905ef08
to allow for the only case where it works with signed
division:
https://alive2.llvm.org/ce/z/k7_ypu

(X s/ Y) == SMIN --> (X == SMIN) && (Y == 1)
(X s/ Y) != SMIN --> (X != SMIN) || (Y != 1)

This is another improvement based on #55695.

Added: 
    

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

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index c64463da9a16..1df61f0624bc 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -2388,17 +2388,6 @@ Instruction *InstCombinerImpl::foldICmpUDivConstant(ICmpInst &Cmp,
   Value *Y = UDiv->getOperand(1);
   Type *Ty = UDiv->getType();
 
-  // If the compare constant is bigger than UMAX/2 (negative), there's only one
-  // pair of values that satisfies an equality check, so eliminate the division:
-  // (X u/ Y) == C --> (X == C) && (Y == 1)
-  // (X u/ Y) != C --> (X != C) || (Y != 1)
-  if (Cmp.isEquality() && UDiv->hasOneUse() && C.isSignBitSet()) {
-    Value *XBig = Builder.CreateICmp(Pred, X, ConstantInt::get(Ty, C));
-    Value *YOne = Builder.CreateICmp(Pred, Y, ConstantInt::get(Ty, 1));
-    auto Logic = Pred == ICmpInst::ICMP_EQ ? Instruction::And : Instruction::Or;
-    return BinaryOperator::Create(Logic, XBig, YOne);
-  }
-
   const APInt *C2;
   if (!match(X, m_APInt(C2)))
     return nullptr;
@@ -2431,6 +2420,23 @@ Instruction *InstCombinerImpl::foldICmpDivConstant(ICmpInst &Cmp,
   Value *X = Div->getOperand(0);
   Value *Y = Div->getOperand(1);
   Type *Ty = Div->getType();
+  bool DivIsSigned = Div->getOpcode() == Instruction::SDiv;
+
+  // If unsigned division and the compare constant is bigger than
+  // UMAX/2 (negative), there's only one pair of values that satisfies an
+  // equality check, so eliminate the division:
+  // (X u/ Y) == C --> (X == C) && (Y == 1)
+  // (X u/ Y) != C --> (X != C) || (Y != 1)
+  // Similarly, if signed division and the compare constant is exactly SMIN:
+  // (X s/ Y) == SMIN --> (X == SMIN) && (Y == 1)
+  // (X s/ Y) != SMIN --> (X != SMIN) || (Y != 1)
+  if (Cmp.isEquality() && Div->hasOneUse() && C.isSignBitSet() &&
+      (!DivIsSigned || C.isMinSignedValue()))   {
+    Value *XBig = Builder.CreateICmp(Pred, X, ConstantInt::get(Ty, C));
+    Value *YOne = Builder.CreateICmp(Pred, Y, ConstantInt::get(Ty, 1));
+    auto Logic = Pred == ICmpInst::ICMP_EQ ? Instruction::And : Instruction::Or;
+    return BinaryOperator::Create(Logic, XBig, YOne);
+  }
 
   // Fold: icmp pred ([us]div X, C2), C -> range test
   // Fold this div into the comparison, producing a range check.
@@ -2450,7 +2456,6 @@ Instruction *InstCombinerImpl::foldICmpDivConstant(ICmpInst &Cmp,
   // (x /u C2) <u C.  Simply casting the operands and result won't
   // work. :(  The if statement below tests that condition and bails
   // if it finds it.
-  bool DivIsSigned = Div->getOpcode() == Instruction::SDiv;
   if (!Cmp.isEquality() && DivIsSigned != Cmp.isSigned())
     return nullptr;
 

diff  --git a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
index 9d7f25fecfd2..9348af51f4ae 100644
--- a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll
@@ -287,8 +287,9 @@ define i1 @udiv_eq_umax_use(i32 %x, i32 %y) {
 
 define i1 @sdiv_eq_smin(i8 %x, i8 %y) {
 ; CHECK-LABEL: @sdiv_eq_smin(
-; CHECK-NEXT:    [[D:%.*]] = sdiv i8 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp eq i8 [[D]], -128
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], -128
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp eq i8 [[Y:%.*]], 1
+; CHECK-NEXT:    [[R:%.*]] = and i1 [[TMP1]], [[TMP2]]
 ; CHECK-NEXT:    ret i1 [[R]]
 ;
   %d = sdiv i8 %x, %y
@@ -298,8 +299,9 @@ define i1 @sdiv_eq_smin(i8 %x, i8 %y) {
 
 define <2 x i1> @sdiv_ne_smin(<2 x i5> %x, <2 x i5> %y) {
 ; CHECK-LABEL: @sdiv_ne_smin(
-; CHECK-NEXT:    [[D:%.*]] = sdiv <2 x i5> [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT:    [[R:%.*]] = icmp ne <2 x i5> [[D]], <i5 -16, i5 -16>
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne <2 x i5> [[X:%.*]], <i5 -16, i5 -16>
+; CHECK-NEXT:    [[TMP2:%.*]] = icmp ne <2 x i5> [[Y:%.*]], <i5 1, i5 1>
+; CHECK-NEXT:    [[R:%.*]] = or <2 x i1> [[TMP1]], [[TMP2]]
 ; CHECK-NEXT:    ret <2 x i1> [[R]]
 ;
   %d = sdiv <2 x i5> %x, %y
@@ -307,6 +309,8 @@ define <2 x i1> @sdiv_ne_smin(<2 x i5> %x, <2 x i5> %y) {
   ret <2 x i1> %r
 }
 
+; negative test - must be SMIN
+
 define i1 @sdiv_eq_small(i8 %x, i8 %y) {
 ; CHECK-LABEL: @sdiv_eq_small(
 ; CHECK-NEXT:    [[D:%.*]] = sdiv i8 [[X:%.*]], [[Y:%.*]]
@@ -318,6 +322,8 @@ define i1 @sdiv_eq_small(i8 %x, i8 %y) {
   ret i1 %r
 }
 
+; negative test - must be SMIN
+
 define i1 @sdiv_ne_big(i8 %x, i8 %y) {
 ; CHECK-LABEL: @sdiv_ne_big(
 ; CHECK-NEXT:    [[D:%.*]] = sdiv i8 [[X:%.*]], [[Y:%.*]]
@@ -329,6 +335,8 @@ define i1 @sdiv_ne_big(i8 %x, i8 %y) {
   ret i1 %r
 }
 
+; negative test - must be SMIN
+
 define i1 @sdiv_eq_not_big(i8 %x, i8 %y) {
 ; CHECK-LABEL: @sdiv_eq_not_big(
 ; CHECK-NEXT:    [[D:%.*]] = sdiv i8 [[X:%.*]], [[Y:%.*]]
@@ -340,6 +348,8 @@ define i1 @sdiv_eq_not_big(i8 %x, i8 %y) {
   ret i1 %r
 }
 
+; negative test - must be equality predicate
+
 define i1 @sdiv_ult_smin(i8 %x, i8 %y) {
 ; CHECK-LABEL: @sdiv_ult_smin(
 ; CHECK-NEXT:    [[D:%.*]] = sdiv i8 [[X:%.*]], [[Y:%.*]]
@@ -351,6 +361,8 @@ define i1 @sdiv_ult_smin(i8 %x, i8 %y) {
   ret i1 %r
 }
 
+; negative test - extra use
+
 define i1 @sdiv_eq_smin_use(i32 %x, i32 %y) {
 ; CHECK-LABEL: @sdiv_eq_smin_use(
 ; CHECK-NEXT:    [[D:%.*]] = sdiv i32 [[X:%.*]], [[Y:%.*]]


        


More information about the llvm-commits mailing list