From 3952c905ef08580de1ddc5d776177497407a6093 Mon Sep 17 00:00:00 2001 From: Sanjay Patel Date: Thu, 26 May 2022 08:23:36 -0400 Subject: [PATCH] [InstCombine] fold icmp equality with udiv and large constant With large compare constant: (X u/ Y) == C --> (X == C) && (Y == 1) (X u/ Y) != C --> (X != C) || (Y != 1) https://alive2.llvm.org/ce/z/EhKwh6 There are various potential missing icmp (div) transforms shown here: https://github.com/llvm/llvm-project/issues/55695 This is a generalization for part of the udiv + equality. I didn't check in detail, but some of those may only make sense as codegen transforms. This results in one extra instruction in IR, but it is better for analysis, and looks much better in codegen on all targets that I tried. Differential Revision: https://reviews.llvm.org/D126410 --- .../InstCombine/InstCombineCompares.cpp | 27 ++++++++++++++----- .../InstCombine/icmp-div-constant.ll | 26 ++++++++++++------ 2 files changed, 39 insertions(+), 14 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index f88585929248..9f5f65cf3bb2 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -2383,26 +2383,41 @@ Instruction *InstCombinerImpl::foldICmpSRemConstant(ICmpInst &Cmp, 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 index ff587dc347a8..e9b26e6b4bca 100644 --- a/llvm/test/Transforms/InstCombine/icmp-div-constant.ll +++ b/llvm/test/Transforms/InstCombine/icmp-div-constant.ll @@ -198,8 +198,9 @@ exit: 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 i1 @udiv_eq_umax(i8 %x, i8 %y) { 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 <2 x i1> @udiv_ne_umax(<2 x i5> %x, <2 x i5> %y) { 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_eq_big(i8 %x, i8 %y) { 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 @@ define i1 @udiv_ne_big(i8 %x, i8 %y) { 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 @@ define i1 @udiv_eq_not_big(i8 %x, i8 %y) { 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 @@ define i1 @udiv_slt_umax(i8 %x, i8 %y) { 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:%.*]]