diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2383,26 +2383,41 @@ Instruction *InstCombinerImpl::foldICmpUDivConstant(ICmpInst &Cmp, BinaryOperator *UDiv, const APInt &C) { + ICmpInst::Predicate Pred = Cmp.getPredicate(); + Value *X = UDiv->getOperand(0); + 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(UDiv->getOperand(0), m_APInt(C2))) + if (!match(X, m_APInt(C2))) return nullptr; assert(*C2 != 0 && "udiv 0, X should have been simplified already."); // (icmp ugt (udiv C2, Y), C) -> (icmp ule Y, C2/(C+1)) - Value *Y = UDiv->getOperand(1); - if (Cmp.getPredicate() == ICmpInst::ICMP_UGT) { + if (Pred == ICmpInst::ICMP_UGT) { assert(!C.isMaxValue() && "icmp ugt X, UINT_MAX should have been simplified already."); return new ICmpInst(ICmpInst::ICMP_ULE, Y, - ConstantInt::get(Y->getType(), C2->udiv(C + 1))); + ConstantInt::get(Ty, C2->udiv(C + 1))); } // (icmp ult (udiv C2, Y), C) -> (icmp ugt Y, C2/C) - if (Cmp.getPredicate() == ICmpInst::ICMP_ULT) { + if (Pred == ICmpInst::ICMP_ULT) { assert(C != 0 && "icmp ult X, 0 should have been simplified already."); return new ICmpInst(ICmpInst::ICMP_UGT, Y, - ConstantInt::get(Y->getType(), C2->udiv(C))); + ConstantInt::get(Ty, C2->udiv(C))); } return nullptr; diff --git a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll --- a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll +++ b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll @@ -198,8 +198,9 @@ define i1 @udiv_eq_umax(i8 %x, i8 %y) { ; CHECK-LABEL: @udiv_eq_umax( -; CHECK-NEXT: [[D:%.*]] = udiv i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[D]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = icmp eq i8 [[X:%.*]], -1 +; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i8 [[Y:%.*]], 1 +; CHECK-NEXT: [[R:%.*]] = and i1 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i1 [[R]] ; %d = udiv i8 %x, %y @@ -209,8 +210,9 @@ define <2 x i1> @udiv_ne_umax(<2 x i5> %x, <2 x i5> %y) { ; CHECK-LABEL: @udiv_ne_umax( -; CHECK-NEXT: [[D:%.*]] = udiv <2 x i5> [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i5> [[D]], +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne <2 x i5> [[X:%.*]], +; CHECK-NEXT: [[TMP2:%.*]] = icmp ne <2 x i5> [[Y:%.*]], +; CHECK-NEXT: [[R:%.*]] = or <2 x i1> [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret <2 x i1> [[R]] ; %d = udiv <2 x i5> %x, %y @@ -220,8 +222,9 @@ define i1 @udiv_eq_big(i8 %x, i8 %y) { ; CHECK-LABEL: @udiv_eq_big( -; CHECK-NEXT: [[D:%.*]] = udiv 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 = udiv i8 %x, %y @@ -231,8 +234,9 @@ define i1 @udiv_ne_big(i8 %x, i8 %y) { ; CHECK-LABEL: @udiv_ne_big( -; CHECK-NEXT: [[D:%.*]] = udiv i8 [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[D]], -128 +; CHECK-NEXT: [[TMP1:%.*]] = icmp ne i8 [[X:%.*]], -128 +; CHECK-NEXT: [[TMP2:%.*]] = icmp ne i8 [[Y:%.*]], 1 +; CHECK-NEXT: [[R:%.*]] = or i1 [[TMP1]], [[TMP2]] ; CHECK-NEXT: ret i1 [[R]] ; %d = udiv i8 %x, %y @@ -240,6 +244,8 @@ ret i1 %r } +; negative test - must have negative compare constant + define i1 @udiv_eq_not_big(i8 %x, i8 %y) { ; CHECK-LABEL: @udiv_eq_not_big( ; CHECK-NEXT: [[D:%.*]] = udiv i8 [[X:%.*]], [[Y:%.*]] @@ -251,6 +257,8 @@ ret i1 %r } +; negative test - must be equality predicate + define i1 @udiv_slt_umax(i8 %x, i8 %y) { ; CHECK-LABEL: @udiv_slt_umax( ; CHECK-NEXT: [[D:%.*]] = udiv i8 [[X:%.*]], [[Y:%.*]] @@ -262,6 +270,8 @@ ret i1 %r } +; negative test - extra use + define i1 @udiv_eq_umax_use(i32 %x, i32 %y) { ; CHECK-LABEL: @udiv_eq_umax_use( ; CHECK-NEXT: [[D:%.*]] = udiv i32 [[X:%.*]], [[Y:%.*]]