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 @@ -2040,6 +2040,29 @@ return nullptr; } +// Reassociate (C * X) * Y to (X * Y) * C to enable further +// optimizations. +static Value *tryReassociateMulConstant(ICmpInst::Predicate Pred, + BinaryOperator *Mul, + InstCombiner::BuilderTy &Builder) { + BinaryOperator *Inner; + Value *X, *Y; + const APInt *C; + + // TODO: mul can be fold to shl and we should make it work. + if (match(Mul, m_OneUse(m_c_Mul(m_BinOp(Inner), m_Value(Y))))) { + if (match(Inner, m_Mul(m_Value(X), m_APInt(C)))) { + if (Mul->hasNoSignedWrap() && Inner->hasNoSignedWrap() && + C->isStrictlyPositive()) { + Value *NewInner = Builder.CreateNSWMul(X, Y); + return Builder.CreateNSWMul(NewInner, + ConstantInt::get(Mul->getType(), *C)); + } + } + } + return nullptr; +} + /// Fold icmp (mul X, Y), C. Instruction *InstCombinerImpl::foldICmpMulConstant(ICmpInst &Cmp, BinaryOperator *Mul, @@ -2055,6 +2078,9 @@ (Mul->hasNoUnsignedWrap() || Mul->hasNoSignedWrap())) return new ICmpInst(Pred, X, ConstantInt::getNullValue(MulTy)); + if (Value *NewMul = tryReassociateMulConstant(Pred, Mul, Builder)) + replaceInstUsesWith(*Mul, NewMul); + const APInt *MulC; if (!match(Mul->getOperand(1), m_APInt(MulC))) return nullptr; diff --git a/llvm/test/Transforms/InstCombine/icmp.ll b/llvm/test/Transforms/InstCombine/icmp.ll --- a/llvm/test/Transforms/InstCombine/icmp.ll +++ b/llvm/test/Transforms/InstCombine/icmp.ll @@ -4968,9 +4968,8 @@ define i1 @mul_mul_sge_zero(i8 %a, i8 %b) { ; CHECK-LABEL: @mul_mul_sge_zero( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw i8 [[A:%.*]], 42 -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw i8 [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[MUL2]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i8 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[TMP1]], -1 ; CHECK-NEXT: ret i1 [[CMP]] ; %mul = mul nsw i8 %a, 42 @@ -4981,9 +4980,8 @@ define <2 x i1> @mul_mul_sge_zero_vec(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @mul_mul_sge_zero_vec( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw <2 x i8> [[A:%.*]], -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw <2 x i8> [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[MUL2]], +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw <2 x i8> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[TMP1]], ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %mul = mul nsw <2 x i8> %a, @@ -4994,9 +4992,8 @@ define i1 @mul_mul_sge_one(i8 %a, i8 %b) { ; CHECK-LABEL: @mul_mul_sge_one( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw i8 [[A:%.*]], 42 -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw i8 [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[MUL2]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i8 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %mul = mul nsw i8 %a, 42 @@ -5007,9 +5004,8 @@ define <2 x i1> @mul_mul_sge_one_vec(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @mul_mul_sge_one_vec( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw <2 x i8> [[A:%.*]], -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw <2 x i8> [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[MUL2]], zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw <2 x i8> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %mul = mul nsw <2 x i8> %a, @@ -5020,9 +5016,8 @@ define i1 @mul_mul_slt_zero(i8 %a, i8 %b) { ; CHECK-LABEL: @mul_mul_slt_zero( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw i8 [[A:%.*]], 42 -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw i8 [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[MUL2]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i8 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %mul = mul nsw i8 %a, 42 @@ -5033,9 +5028,8 @@ define <2 x i1> @mul_mul_slt_zero_vec(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @mul_mul_slt_zero_vec( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw <2 x i8> [[A:%.*]], -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw <2 x i8> [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[MUL2]], zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw <2 x i8> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %mul = mul nsw <2 x i8> %a, @@ -5046,9 +5040,8 @@ define i1 @mul_mul_slt_one(i8 %a, i8 %b) { ; CHECK-LABEL: @mul_mul_slt_one( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw i8 [[A:%.*]], 42 -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw i8 [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[MUL2]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i8 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[TMP1]], 1 ; CHECK-NEXT: ret i1 [[CMP]] ; %mul = mul nsw i8 %a, 42 @@ -5059,9 +5052,8 @@ define <2 x i1> @mul_mul_slt_one_vec(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @mul_mul_slt_one_vec( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw <2 x i8> [[A:%.*]], -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw <2 x i8> [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[MUL2]], +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw <2 x i8> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[TMP1]], ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %mul = mul nsw <2 x i8> %a, @@ -5072,9 +5064,8 @@ define i1 @mul_mul_sle_zero(i8 %a, i8 %b) { ; CHECK-LABEL: @mul_mul_sle_zero( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw i8 [[A:%.*]], 42 -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw i8 [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[MUL2]], 1 +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i8 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[TMP1]], 1 ; CHECK-NEXT: ret i1 [[CMP]] ; %mul = mul nsw i8 %a, 42 @@ -5085,9 +5076,8 @@ define <2 x i1> @mul_mul_sle_zero_vec(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @mul_mul_sle_zero_vec( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw <2 x i8> [[A:%.*]], -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw <2 x i8> [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[MUL2]], +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw <2 x i8> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[TMP1]], ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %mul = mul nsw <2 x i8> %a, @@ -5098,9 +5088,8 @@ define i1 @mul_mul_sle_negone(i8 %a, i8 %b) { ; CHECK-LABEL: @mul_mul_sle_negone( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw i8 [[A:%.*]], 42 -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw i8 [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[MUL2]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i8 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %mul = mul nsw i8 %a, 42 @@ -5111,9 +5100,8 @@ define <2 x i1> @mul_mul_sle_negone_vec(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @mul_mul_sle_negone_vec( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw <2 x i8> [[A:%.*]], -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw <2 x i8> [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[MUL2]], zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw <2 x i8> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i8> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %mul = mul nsw <2 x i8> %a, @@ -5124,9 +5112,8 @@ define i1 @mul_mul_sgt_zero(i8 %a, i8 %b) { ; CHECK-LABEL: @mul_mul_sgt_zero( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw i8 [[A:%.*]], 42 -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw i8 [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[MUL2]], 0 +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i8 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %mul = mul nsw i8 %a, 42 @@ -5137,9 +5124,8 @@ define <2 x i1> @mul_mul_sgt_zero_vec(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @mul_mul_sgt_zero_vec( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw <2 x i8> [[A:%.*]], -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw <2 x i8> [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[MUL2]], zeroinitializer +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw <2 x i8> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[TMP1]], zeroinitializer ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %mul = mul nsw <2 x i8> %a, @@ -5150,9 +5136,8 @@ define i1 @mul_mul_sgt_negone(i8 %a, i8 %b) { ; CHECK-LABEL: @mul_mul_sgt_negone( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw i8 [[A:%.*]], 42 -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw i8 [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[MUL2]], -1 +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw i8 [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i8 [[TMP1]], -1 ; CHECK-NEXT: ret i1 [[CMP]] ; %mul = mul nsw i8 %a, 42 @@ -5163,9 +5148,8 @@ define <2 x i1> @mul_mul_sgt_negone_vec(<2 x i8> %a, <2 x i8> %b) { ; CHECK-LABEL: @mul_mul_sgt_negone_vec( -; CHECK-NEXT: [[MUL:%.*]] = mul nsw <2 x i8> [[A:%.*]], -; CHECK-NEXT: [[MUL2:%.*]] = mul nsw <2 x i8> [[MUL]], [[B:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[MUL2]], +; CHECK-NEXT: [[TMP1:%.*]] = mul nsw <2 x i8> [[A:%.*]], [[B:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt <2 x i8> [[TMP1]], ; CHECK-NEXT: ret <2 x i1> [[CMP]] ; %mul = mul nsw <2 x i8> %a,