diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2023-12-09 13:28:42 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2023-12-09 13:28:42 +0000 |
| commit | b1c73532ee8997fe5dfbeb7d223027bdf99758a0 (patch) | |
| tree | 7d6e51c294ab6719475d660217aa0c0ad0526292 /llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | |
| parent | 7fa27ce4a07f19b07799a767fc29416f3b625afb (diff) | |
Diffstat (limited to 'llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp')
| -rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | 454 |
1 files changed, 251 insertions, 203 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index 50458e2773e6..8d5866e98a8e 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -258,9 +258,14 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) { if (Op0->hasOneUse() && match(Op1, m_NegatedPower2())) { // Interpret X * (-1<<C) as (-X) * (1<<C) and try to sink the negation. // The "* (1<<C)" thus becomes a potential shifting opportunity. - if (Value *NegOp0 = Negator::Negate(/*IsNegation*/ true, Op0, *this)) - return BinaryOperator::CreateMul( - NegOp0, ConstantExpr::getNeg(cast<Constant>(Op1)), I.getName()); + if (Value *NegOp0 = + Negator::Negate(/*IsNegation*/ true, HasNSW, Op0, *this)) { + auto *Op1C = cast<Constant>(Op1); + return replaceInstUsesWith( + I, Builder.CreateMul(NegOp0, ConstantExpr::getNeg(Op1C), "", + /* HasNUW */ false, + HasNSW && Op1C->isNotMinSignedValue())); + } // Try to convert multiply of extended operand to narrow negate and shift // for better analysis. @@ -295,9 +300,7 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) { // Canonicalize (X|C1)*MulC -> X*MulC+C1*MulC. Value *X; Constant *C1; - if ((match(Op0, m_OneUse(m_Add(m_Value(X), m_ImmConstant(C1))))) || - (match(Op0, m_OneUse(m_Or(m_Value(X), m_ImmConstant(C1)))) && - haveNoCommonBitsSet(X, C1, DL, &AC, &I, &DT))) { + if (match(Op0, m_OneUse(m_AddLike(m_Value(X), m_ImmConstant(C1))))) { // C1*MulC simplifies to a tidier constant. Value *NewC = Builder.CreateMul(C1, MulC); auto *BOp0 = cast<BinaryOperator>(Op0); @@ -555,6 +558,180 @@ Instruction *InstCombinerImpl::foldFPSignBitOps(BinaryOperator &I) { return nullptr; } +Instruction *InstCombinerImpl::foldFMulReassoc(BinaryOperator &I) { + Value *Op0 = I.getOperand(0); + Value *Op1 = I.getOperand(1); + Value *X, *Y; + Constant *C; + + // Reassociate constant RHS with another constant to form constant + // expression. + if (match(Op1, m_Constant(C)) && C->isFiniteNonZeroFP()) { + Constant *C1; + if (match(Op0, m_OneUse(m_FDiv(m_Constant(C1), m_Value(X))))) { + // (C1 / X) * C --> (C * C1) / X + Constant *CC1 = + ConstantFoldBinaryOpOperands(Instruction::FMul, C, C1, DL); + if (CC1 && CC1->isNormalFP()) + return BinaryOperator::CreateFDivFMF(CC1, X, &I); + } + if (match(Op0, m_FDiv(m_Value(X), m_Constant(C1)))) { + // (X / C1) * C --> X * (C / C1) + Constant *CDivC1 = + ConstantFoldBinaryOpOperands(Instruction::FDiv, C, C1, DL); + if (CDivC1 && CDivC1->isNormalFP()) + return BinaryOperator::CreateFMulFMF(X, CDivC1, &I); + + // If the constant was a denormal, try reassociating differently. + // (X / C1) * C --> X / (C1 / C) + Constant *C1DivC = + ConstantFoldBinaryOpOperands(Instruction::FDiv, C1, C, DL); + if (C1DivC && Op0->hasOneUse() && C1DivC->isNormalFP()) + return BinaryOperator::CreateFDivFMF(X, C1DivC, &I); + } + + // We do not need to match 'fadd C, X' and 'fsub X, C' because they are + // canonicalized to 'fadd X, C'. Distributing the multiply may allow + // further folds and (X * C) + C2 is 'fma'. + if (match(Op0, m_OneUse(m_FAdd(m_Value(X), m_Constant(C1))))) { + // (X + C1) * C --> (X * C) + (C * C1) + if (Constant *CC1 = + ConstantFoldBinaryOpOperands(Instruction::FMul, C, C1, DL)) { + Value *XC = Builder.CreateFMulFMF(X, C, &I); + return BinaryOperator::CreateFAddFMF(XC, CC1, &I); + } + } + if (match(Op0, m_OneUse(m_FSub(m_Constant(C1), m_Value(X))))) { + // (C1 - X) * C --> (C * C1) - (X * C) + if (Constant *CC1 = + ConstantFoldBinaryOpOperands(Instruction::FMul, C, C1, DL)) { + Value *XC = Builder.CreateFMulFMF(X, C, &I); + return BinaryOperator::CreateFSubFMF(CC1, XC, &I); + } + } + } + + Value *Z; + if (match(&I, + m_c_FMul(m_OneUse(m_FDiv(m_Value(X), m_Value(Y))), m_Value(Z)))) { + // Sink division: (X / Y) * Z --> (X * Z) / Y + Value *NewFMul = Builder.CreateFMulFMF(X, Z, &I); + return BinaryOperator::CreateFDivFMF(NewFMul, Y, &I); + } + + // sqrt(X) * sqrt(Y) -> sqrt(X * Y) + // nnan disallows the possibility of returning a number if both operands are + // negative (in that case, we should return NaN). + if (I.hasNoNaNs() && match(Op0, m_OneUse(m_Sqrt(m_Value(X)))) && + match(Op1, m_OneUse(m_Sqrt(m_Value(Y))))) { + Value *XY = Builder.CreateFMulFMF(X, Y, &I); + Value *Sqrt = Builder.CreateUnaryIntrinsic(Intrinsic::sqrt, XY, &I); + return replaceInstUsesWith(I, Sqrt); + } + + // The following transforms are done irrespective of the number of uses + // for the expression "1.0/sqrt(X)". + // 1) 1.0/sqrt(X) * X -> X/sqrt(X) + // 2) X * 1.0/sqrt(X) -> X/sqrt(X) + // We always expect the backend to reduce X/sqrt(X) to sqrt(X), if it + // has the necessary (reassoc) fast-math-flags. + if (I.hasNoSignedZeros() && + match(Op0, (m_FDiv(m_SpecificFP(1.0), m_Value(Y)))) && + match(Y, m_Sqrt(m_Value(X))) && Op1 == X) + return BinaryOperator::CreateFDivFMF(X, Y, &I); + if (I.hasNoSignedZeros() && + match(Op1, (m_FDiv(m_SpecificFP(1.0), m_Value(Y)))) && + match(Y, m_Sqrt(m_Value(X))) && Op0 == X) + return BinaryOperator::CreateFDivFMF(X, Y, &I); + + // Like the similar transform in instsimplify, this requires 'nsz' because + // sqrt(-0.0) = -0.0, and -0.0 * -0.0 does not simplify to -0.0. + if (I.hasNoNaNs() && I.hasNoSignedZeros() && Op0 == Op1 && Op0->hasNUses(2)) { + // Peek through fdiv to find squaring of square root: + // (X / sqrt(Y)) * (X / sqrt(Y)) --> (X * X) / Y + if (match(Op0, m_FDiv(m_Value(X), m_Sqrt(m_Value(Y))))) { + Value *XX = Builder.CreateFMulFMF(X, X, &I); + return BinaryOperator::CreateFDivFMF(XX, Y, &I); + } + // (sqrt(Y) / X) * (sqrt(Y) / X) --> Y / (X * X) + if (match(Op0, m_FDiv(m_Sqrt(m_Value(Y)), m_Value(X)))) { + Value *XX = Builder.CreateFMulFMF(X, X, &I); + return BinaryOperator::CreateFDivFMF(Y, XX, &I); + } + } + + // pow(X, Y) * X --> pow(X, Y+1) + // X * pow(X, Y) --> pow(X, Y+1) + if (match(&I, m_c_FMul(m_OneUse(m_Intrinsic<Intrinsic::pow>(m_Value(X), + m_Value(Y))), + m_Deferred(X)))) { + Value *Y1 = Builder.CreateFAddFMF(Y, ConstantFP::get(I.getType(), 1.0), &I); + Value *Pow = Builder.CreateBinaryIntrinsic(Intrinsic::pow, X, Y1, &I); + return replaceInstUsesWith(I, Pow); + } + + if (I.isOnlyUserOfAnyOperand()) { + // pow(X, Y) * pow(X, Z) -> pow(X, Y + Z) + if (match(Op0, m_Intrinsic<Intrinsic::pow>(m_Value(X), m_Value(Y))) && + match(Op1, m_Intrinsic<Intrinsic::pow>(m_Specific(X), m_Value(Z)))) { + auto *YZ = Builder.CreateFAddFMF(Y, Z, &I); + auto *NewPow = Builder.CreateBinaryIntrinsic(Intrinsic::pow, X, YZ, &I); + return replaceInstUsesWith(I, NewPow); + } + // pow(X, Y) * pow(Z, Y) -> pow(X * Z, Y) + if (match(Op0, m_Intrinsic<Intrinsic::pow>(m_Value(X), m_Value(Y))) && + match(Op1, m_Intrinsic<Intrinsic::pow>(m_Value(Z), m_Specific(Y)))) { + auto *XZ = Builder.CreateFMulFMF(X, Z, &I); + auto *NewPow = Builder.CreateBinaryIntrinsic(Intrinsic::pow, XZ, Y, &I); + return replaceInstUsesWith(I, NewPow); + } + + // powi(x, y) * powi(x, z) -> powi(x, y + z) + if (match(Op0, m_Intrinsic<Intrinsic::powi>(m_Value(X), m_Value(Y))) && + match(Op1, m_Intrinsic<Intrinsic::powi>(m_Specific(X), m_Value(Z))) && + Y->getType() == Z->getType()) { + auto *YZ = Builder.CreateAdd(Y, Z); + auto *NewPow = Builder.CreateIntrinsic( + Intrinsic::powi, {X->getType(), YZ->getType()}, {X, YZ}, &I); + return replaceInstUsesWith(I, NewPow); + } + + // exp(X) * exp(Y) -> exp(X + Y) + if (match(Op0, m_Intrinsic<Intrinsic::exp>(m_Value(X))) && + match(Op1, m_Intrinsic<Intrinsic::exp>(m_Value(Y)))) { + Value *XY = Builder.CreateFAddFMF(X, Y, &I); + Value *Exp = Builder.CreateUnaryIntrinsic(Intrinsic::exp, XY, &I); + return replaceInstUsesWith(I, Exp); + } + + // exp2(X) * exp2(Y) -> exp2(X + Y) + if (match(Op0, m_Intrinsic<Intrinsic::exp2>(m_Value(X))) && + match(Op1, m_Intrinsic<Intrinsic::exp2>(m_Value(Y)))) { + Value *XY = Builder.CreateFAddFMF(X, Y, &I); + Value *Exp2 = Builder.CreateUnaryIntrinsic(Intrinsic::exp2, XY, &I); + return replaceInstUsesWith(I, Exp2); + } + } + + // (X*Y) * X => (X*X) * Y where Y != X + // The purpose is two-fold: + // 1) to form a power expression (of X). + // 2) potentially shorten the critical path: After transformation, the + // latency of the instruction Y is amortized by the expression of X*X, + // and therefore Y is in a "less critical" position compared to what it + // was before the transformation. + if (match(Op0, m_OneUse(m_c_FMul(m_Specific(Op1), m_Value(Y)))) && Op1 != Y) { + Value *XX = Builder.CreateFMulFMF(Op1, Op1, &I); + return BinaryOperator::CreateFMulFMF(XX, Y, &I); + } + if (match(Op1, m_OneUse(m_c_FMul(m_Specific(Op0), m_Value(Y)))) && Op0 != Y) { + Value *XX = Builder.CreateFMulFMF(Op0, Op0, &I); + return BinaryOperator::CreateFMulFMF(XX, Y, &I); + } + + return nullptr; +} + Instruction *InstCombinerImpl::visitFMul(BinaryOperator &I) { if (Value *V = simplifyFMulInst(I.getOperand(0), I.getOperand(1), I.getFastMathFlags(), @@ -602,176 +779,9 @@ Instruction *InstCombinerImpl::visitFMul(BinaryOperator &I) { if (Value *V = SimplifySelectsFeedingBinaryOp(I, Op0, Op1)) return replaceInstUsesWith(I, V); - if (I.hasAllowReassoc()) { - // Reassociate constant RHS with another constant to form constant - // expression. - if (match(Op1, m_Constant(C)) && C->isFiniteNonZeroFP()) { - Constant *C1; - if (match(Op0, m_OneUse(m_FDiv(m_Constant(C1), m_Value(X))))) { - // (C1 / X) * C --> (C * C1) / X - Constant *CC1 = - ConstantFoldBinaryOpOperands(Instruction::FMul, C, C1, DL); - if (CC1 && CC1->isNormalFP()) - return BinaryOperator::CreateFDivFMF(CC1, X, &I); - } - if (match(Op0, m_FDiv(m_Value(X), m_Constant(C1)))) { - // (X / C1) * C --> X * (C / C1) - Constant *CDivC1 = - ConstantFoldBinaryOpOperands(Instruction::FDiv, C, C1, DL); - if (CDivC1 && CDivC1->isNormalFP()) - return BinaryOperator::CreateFMulFMF(X, CDivC1, &I); - - // If the constant was a denormal, try reassociating differently. - // (X / C1) * C --> X / (C1 / C) - Constant *C1DivC = - ConstantFoldBinaryOpOperands(Instruction::FDiv, C1, C, DL); - if (C1DivC && Op0->hasOneUse() && C1DivC->isNormalFP()) - return BinaryOperator::CreateFDivFMF(X, C1DivC, &I); - } - - // We do not need to match 'fadd C, X' and 'fsub X, C' because they are - // canonicalized to 'fadd X, C'. Distributing the multiply may allow - // further folds and (X * C) + C2 is 'fma'. - if (match(Op0, m_OneUse(m_FAdd(m_Value(X), m_Constant(C1))))) { - // (X + C1) * C --> (X * C) + (C * C1) - if (Constant *CC1 = ConstantFoldBinaryOpOperands( - Instruction::FMul, C, C1, DL)) { - Value *XC = Builder.CreateFMulFMF(X, C, &I); - return BinaryOperator::CreateFAddFMF(XC, CC1, &I); - } - } - if (match(Op0, m_OneUse(m_FSub(m_Constant(C1), m_Value(X))))) { - // (C1 - X) * C --> (C * C1) - (X * C) - if (Constant *CC1 = ConstantFoldBinaryOpOperands( - Instruction::FMul, C, C1, DL)) { - Value *XC = Builder.CreateFMulFMF(X, C, &I); - return BinaryOperator::CreateFSubFMF(CC1, XC, &I); - } - } - } - - Value *Z; - if (match(&I, m_c_FMul(m_OneUse(m_FDiv(m_Value(X), m_Value(Y))), - m_Value(Z)))) { - // Sink division: (X / Y) * Z --> (X * Z) / Y - Value *NewFMul = Builder.CreateFMulFMF(X, Z, &I); - return BinaryOperator::CreateFDivFMF(NewFMul, Y, &I); - } - - // sqrt(X) * sqrt(Y) -> sqrt(X * Y) - // nnan disallows the possibility of returning a number if both operands are - // negative (in that case, we should return NaN). - if (I.hasNoNaNs() && match(Op0, m_OneUse(m_Sqrt(m_Value(X)))) && - match(Op1, m_OneUse(m_Sqrt(m_Value(Y))))) { - Value *XY = Builder.CreateFMulFMF(X, Y, &I); - Value *Sqrt = Builder.CreateUnaryIntrinsic(Intrinsic::sqrt, XY, &I); - return replaceInstUsesWith(I, Sqrt); - } - - // The following transforms are done irrespective of the number of uses - // for the expression "1.0/sqrt(X)". - // 1) 1.0/sqrt(X) * X -> X/sqrt(X) - // 2) X * 1.0/sqrt(X) -> X/sqrt(X) - // We always expect the backend to reduce X/sqrt(X) to sqrt(X), if it - // has the necessary (reassoc) fast-math-flags. - if (I.hasNoSignedZeros() && - match(Op0, (m_FDiv(m_SpecificFP(1.0), m_Value(Y)))) && - match(Y, m_Sqrt(m_Value(X))) && Op1 == X) - return BinaryOperator::CreateFDivFMF(X, Y, &I); - if (I.hasNoSignedZeros() && - match(Op1, (m_FDiv(m_SpecificFP(1.0), m_Value(Y)))) && - match(Y, m_Sqrt(m_Value(X))) && Op0 == X) - return BinaryOperator::CreateFDivFMF(X, Y, &I); - - // Like the similar transform in instsimplify, this requires 'nsz' because - // sqrt(-0.0) = -0.0, and -0.0 * -0.0 does not simplify to -0.0. - if (I.hasNoNaNs() && I.hasNoSignedZeros() && Op0 == Op1 && - Op0->hasNUses(2)) { - // Peek through fdiv to find squaring of square root: - // (X / sqrt(Y)) * (X / sqrt(Y)) --> (X * X) / Y - if (match(Op0, m_FDiv(m_Value(X), m_Sqrt(m_Value(Y))))) { - Value *XX = Builder.CreateFMulFMF(X, X, &I); - return BinaryOperator::CreateFDivFMF(XX, Y, &I); - } - // (sqrt(Y) / X) * (sqrt(Y) / X) --> Y / (X * X) - if (match(Op0, m_FDiv(m_Sqrt(m_Value(Y)), m_Value(X)))) { - Value *XX = Builder.CreateFMulFMF(X, X, &I); - return BinaryOperator::CreateFDivFMF(Y, XX, &I); - } - } - - // pow(X, Y) * X --> pow(X, Y+1) - // X * pow(X, Y) --> pow(X, Y+1) - if (match(&I, m_c_FMul(m_OneUse(m_Intrinsic<Intrinsic::pow>(m_Value(X), - m_Value(Y))), - m_Deferred(X)))) { - Value *Y1 = - Builder.CreateFAddFMF(Y, ConstantFP::get(I.getType(), 1.0), &I); - Value *Pow = Builder.CreateBinaryIntrinsic(Intrinsic::pow, X, Y1, &I); - return replaceInstUsesWith(I, Pow); - } - - if (I.isOnlyUserOfAnyOperand()) { - // pow(X, Y) * pow(X, Z) -> pow(X, Y + Z) - if (match(Op0, m_Intrinsic<Intrinsic::pow>(m_Value(X), m_Value(Y))) && - match(Op1, m_Intrinsic<Intrinsic::pow>(m_Specific(X), m_Value(Z)))) { - auto *YZ = Builder.CreateFAddFMF(Y, Z, &I); - auto *NewPow = Builder.CreateBinaryIntrinsic(Intrinsic::pow, X, YZ, &I); - return replaceInstUsesWith(I, NewPow); - } - // pow(X, Y) * pow(Z, Y) -> pow(X * Z, Y) - if (match(Op0, m_Intrinsic<Intrinsic::pow>(m_Value(X), m_Value(Y))) && - match(Op1, m_Intrinsic<Intrinsic::pow>(m_Value(Z), m_Specific(Y)))) { - auto *XZ = Builder.CreateFMulFMF(X, Z, &I); - auto *NewPow = Builder.CreateBinaryIntrinsic(Intrinsic::pow, XZ, Y, &I); - return replaceInstUsesWith(I, NewPow); - } - - // powi(x, y) * powi(x, z) -> powi(x, y + z) - if (match(Op0, m_Intrinsic<Intrinsic::powi>(m_Value(X), m_Value(Y))) && - match(Op1, m_Intrinsic<Intrinsic::powi>(m_Specific(X), m_Value(Z))) && - Y->getType() == Z->getType()) { - auto *YZ = Builder.CreateAdd(Y, Z); - auto *NewPow = Builder.CreateIntrinsic( - Intrinsic::powi, {X->getType(), YZ->getType()}, {X, YZ}, &I); - return replaceInstUsesWith(I, NewPow); - } - - // exp(X) * exp(Y) -> exp(X + Y) - if (match(Op0, m_Intrinsic<Intrinsic::exp>(m_Value(X))) && - match(Op1, m_Intrinsic<Intrinsic::exp>(m_Value(Y)))) { - Value *XY = Builder.CreateFAddFMF(X, Y, &I); - Value *Exp = Builder.CreateUnaryIntrinsic(Intrinsic::exp, XY, &I); - return replaceInstUsesWith(I, Exp); - } - - // exp2(X) * exp2(Y) -> exp2(X + Y) - if (match(Op0, m_Intrinsic<Intrinsic::exp2>(m_Value(X))) && - match(Op1, m_Intrinsic<Intrinsic::exp2>(m_Value(Y)))) { - Value *XY = Builder.CreateFAddFMF(X, Y, &I); - Value *Exp2 = Builder.CreateUnaryIntrinsic(Intrinsic::exp2, XY, &I); - return replaceInstUsesWith(I, Exp2); - } - } - - // (X*Y) * X => (X*X) * Y where Y != X - // The purpose is two-fold: - // 1) to form a power expression (of X). - // 2) potentially shorten the critical path: After transformation, the - // latency of the instruction Y is amortized by the expression of X*X, - // and therefore Y is in a "less critical" position compared to what it - // was before the transformation. - if (match(Op0, m_OneUse(m_c_FMul(m_Specific(Op1), m_Value(Y)))) && - Op1 != Y) { - Value *XX = Builder.CreateFMulFMF(Op1, Op1, &I); - return BinaryOperator::CreateFMulFMF(XX, Y, &I); - } - if (match(Op1, m_OneUse(m_c_FMul(m_Specific(Op0), m_Value(Y)))) && - Op0 != Y) { - Value *XX = Builder.CreateFMulFMF(Op0, Op0, &I); - return BinaryOperator::CreateFMulFMF(XX, Y, &I); - } - } + if (I.hasAllowReassoc()) + if (Instruction *FoldedMul = foldFMulReassoc(I)) + return FoldedMul; // log2(X * 0.5) * Y = log2(X) * Y - Y if (I.isFast()) { @@ -802,7 +812,7 @@ Instruction *InstCombinerImpl::visitFMul(BinaryOperator &I) { I.hasNoSignedZeros() && match(Start, m_Zero())) return replaceInstUsesWith(I, Start); - // minimun(X, Y) * maximum(X, Y) => X * Y. + // minimum(X, Y) * maximum(X, Y) => X * Y. if (match(&I, m_c_FMul(m_Intrinsic<Intrinsic::maximum>(m_Value(X), m_Value(Y)), m_c_Intrinsic<Intrinsic::minimum>(m_Deferred(X), @@ -918,8 +928,7 @@ static bool isMultiple(const APInt &C1, const APInt &C2, APInt &Quotient, return Remainder.isMinValue(); } -static Instruction *foldIDivShl(BinaryOperator &I, - InstCombiner::BuilderTy &Builder) { +static Value *foldIDivShl(BinaryOperator &I, InstCombiner::BuilderTy &Builder) { assert((I.getOpcode() == Instruction::SDiv || I.getOpcode() == Instruction::UDiv) && "Expected integer divide"); @@ -928,7 +937,6 @@ static Instruction *foldIDivShl(BinaryOperator &I, Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); Type *Ty = I.getType(); - Instruction *Ret = nullptr; Value *X, *Y, *Z; // With appropriate no-wrap constraints, remove a common factor in the @@ -943,12 +951,12 @@ static Instruction *foldIDivShl(BinaryOperator &I, // (X * Y) u/ (X << Z) --> Y u>> Z if (!IsSigned && HasNUW) - Ret = BinaryOperator::CreateLShr(Y, Z); + return Builder.CreateLShr(Y, Z, "", I.isExact()); // (X * Y) s/ (X << Z) --> Y s/ (1 << Z) if (IsSigned && HasNSW && (Op0->hasOneUse() || Op1->hasOneUse())) { Value *Shl = Builder.CreateShl(ConstantInt::get(Ty, 1), Z); - Ret = BinaryOperator::CreateSDiv(Y, Shl); + return Builder.CreateSDiv(Y, Shl, "", I.isExact()); } } @@ -966,20 +974,38 @@ static Instruction *foldIDivShl(BinaryOperator &I, ((Shl0->hasNoUnsignedWrap() && Shl1->hasNoUnsignedWrap()) || (Shl0->hasNoUnsignedWrap() && Shl0->hasNoSignedWrap() && Shl1->hasNoSignedWrap()))) - Ret = BinaryOperator::CreateUDiv(X, Y); + return Builder.CreateUDiv(X, Y, "", I.isExact()); // For signed div, we need 'nsw' on both shifts + 'nuw' on the divisor. // (X << Z) / (Y << Z) --> X / Y if (IsSigned && Shl0->hasNoSignedWrap() && Shl1->hasNoSignedWrap() && Shl1->hasNoUnsignedWrap()) - Ret = BinaryOperator::CreateSDiv(X, Y); + return Builder.CreateSDiv(X, Y, "", I.isExact()); } - if (!Ret) - return nullptr; + // If X << Y and X << Z does not overflow, then: + // (X << Y) / (X << Z) -> (1 << Y) / (1 << Z) -> 1 << Y >> Z + if (match(Op0, m_Shl(m_Value(X), m_Value(Y))) && + match(Op1, m_Shl(m_Specific(X), m_Value(Z)))) { + auto *Shl0 = cast<OverflowingBinaryOperator>(Op0); + auto *Shl1 = cast<OverflowingBinaryOperator>(Op1); - Ret->setIsExact(I.isExact()); - return Ret; + if (IsSigned ? (Shl0->hasNoSignedWrap() && Shl1->hasNoSignedWrap()) + : (Shl0->hasNoUnsignedWrap() && Shl1->hasNoUnsignedWrap())) { + Constant *One = ConstantInt::get(X->getType(), 1); + // Only preserve the nsw flag if dividend has nsw + // or divisor has nsw and operator is sdiv. + Value *Dividend = Builder.CreateShl( + One, Y, "shl.dividend", + /*HasNUW*/ true, + /*HasNSW*/ + IsSigned ? (Shl0->hasNoUnsignedWrap() || Shl1->hasNoUnsignedWrap()) + : Shl0->hasNoSignedWrap()); + return Builder.CreateLShr(Dividend, Z, "", I.isExact()); + } + } + + return nullptr; } /// This function implements the transforms common to both integer division @@ -1156,8 +1182,8 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) { return NewDiv; } - if (Instruction *R = foldIDivShl(I, Builder)) - return R; + if (Value *R = foldIDivShl(I, Builder)) + return replaceInstUsesWith(I, R); // With the appropriate no-wrap constraint, remove a multiply by the divisor // after peeking through another divide: @@ -1263,7 +1289,7 @@ static Value *takeLog2(IRBuilderBase &Builder, Value *Op, unsigned Depth, /// If we have zero-extended operands of an unsigned div or rem, we may be able /// to narrow the operation (sink the zext below the math). static Instruction *narrowUDivURem(BinaryOperator &I, - InstCombiner::BuilderTy &Builder) { + InstCombinerImpl &IC) { Instruction::BinaryOps Opcode = I.getOpcode(); Value *N = I.getOperand(0); Value *D = I.getOperand(1); @@ -1273,7 +1299,7 @@ static Instruction *narrowUDivURem(BinaryOperator &I, X->getType() == Y->getType() && (N->hasOneUse() || D->hasOneUse())) { // udiv (zext X), (zext Y) --> zext (udiv X, Y) // urem (zext X), (zext Y) --> zext (urem X, Y) - Value *NarrowOp = Builder.CreateBinOp(Opcode, X, Y); + Value *NarrowOp = IC.Builder.CreateBinOp(Opcode, X, Y); return new ZExtInst(NarrowOp, Ty); } @@ -1281,24 +1307,24 @@ static Instruction *narrowUDivURem(BinaryOperator &I, if (isa<Instruction>(N) && match(N, m_OneUse(m_ZExt(m_Value(X)))) && match(D, m_Constant(C))) { // If the constant is the same in the smaller type, use the narrow version. - Constant *TruncC = ConstantExpr::getTrunc(C, X->getType()); - if (ConstantExpr::getZExt(TruncC, Ty) != C) + Constant *TruncC = IC.getLosslessUnsignedTrunc(C, X->getType()); + if (!TruncC) return nullptr; // udiv (zext X), C --> zext (udiv X, C') // urem (zext X), C --> zext (urem X, C') - return new ZExtInst(Builder.CreateBinOp(Opcode, X, TruncC), Ty); + return new ZExtInst(IC.Builder.CreateBinOp(Opcode, X, TruncC), Ty); } if (isa<Instruction>(D) && match(D, m_OneUse(m_ZExt(m_Value(X)))) && match(N, m_Constant(C))) { // If the constant is the same in the smaller type, use the narrow version. - Constant *TruncC = ConstantExpr::getTrunc(C, X->getType()); - if (ConstantExpr::getZExt(TruncC, Ty) != C) + Constant *TruncC = IC.getLosslessUnsignedTrunc(C, X->getType()); + if (!TruncC) return nullptr; // udiv C, (zext X) --> zext (udiv C', X) // urem C, (zext X) --> zext (urem C', X) - return new ZExtInst(Builder.CreateBinOp(Opcode, TruncC, X), Ty); + return new ZExtInst(IC.Builder.CreateBinOp(Opcode, TruncC, X), Ty); } return nullptr; @@ -1346,7 +1372,7 @@ Instruction *InstCombinerImpl::visitUDiv(BinaryOperator &I) { return CastInst::CreateZExtOrBitCast(Cmp, Ty); } - if (Instruction *NarrowDiv = narrowUDivURem(I, Builder)) + if (Instruction *NarrowDiv = narrowUDivURem(I, *this)) return NarrowDiv; // If the udiv operands are non-overflowing multiplies with a common operand, @@ -1405,7 +1431,7 @@ Instruction *InstCombinerImpl::visitSDiv(BinaryOperator &I) { // sdiv Op0, (sext i1 X) --> -Op0 (because if X is 0, the op is undefined) if (match(Op1, m_AllOnes()) || (match(Op1, m_SExt(m_Value(X))) && X->getType()->isIntOrIntVectorTy(1))) - return BinaryOperator::CreateNeg(Op0); + return BinaryOperator::CreateNSWNeg(Op0); // X / INT_MIN --> X == INT_MIN if (match(Op1, m_SignMask())) @@ -1428,7 +1454,7 @@ Instruction *InstCombinerImpl::visitSDiv(BinaryOperator &I) { Constant *NegPow2C = ConstantExpr::getNeg(cast<Constant>(Op1)); Constant *C = ConstantExpr::getExactLogBase2(NegPow2C); Value *Ashr = Builder.CreateAShr(Op0, C, I.getName() + ".neg", true); - return BinaryOperator::CreateNeg(Ashr); + return BinaryOperator::CreateNSWNeg(Ashr); } } @@ -1490,7 +1516,7 @@ Instruction *InstCombinerImpl::visitSDiv(BinaryOperator &I) { if (KnownDividend.isNonNegative()) { // If both operands are unsigned, turn this into a udiv. - if (isKnownNonNegative(Op1, DL, 0, &AC, &I, &DT)) { + if (isKnownNonNegative(Op1, SQ.getWithInstruction(&I))) { auto *BO = BinaryOperator::CreateUDiv(Op0, Op1, I.getName()); BO->setIsExact(I.isExact()); return BO; @@ -1516,6 +1542,13 @@ Instruction *InstCombinerImpl::visitSDiv(BinaryOperator &I) { } } + // -X / X --> X == INT_MIN ? 1 : -1 + if (isKnownNegation(Op0, Op1)) { + APInt MinVal = APInt::getSignedMinValue(Ty->getScalarSizeInBits()); + Value *Cond = Builder.CreateICmpEQ(Op0, ConstantInt::get(Ty, MinVal)); + return SelectInst::Create(Cond, ConstantInt::get(Ty, 1), + ConstantInt::getAllOnesValue(Ty)); + } return nullptr; } @@ -1759,6 +1792,21 @@ Instruction *InstCombinerImpl::visitFDiv(BinaryOperator &I) { return replaceInstUsesWith(I, Pow); } + // powi(X, Y) / X --> powi(X, Y-1) + // This is legal when (Y - 1) can't wraparound, in which case reassoc and nnan + // are required. + // TODO: Multi-use may be also better off creating Powi(x,y-1) + if (I.hasAllowReassoc() && I.hasNoNaNs() && + match(Op0, m_OneUse(m_Intrinsic<Intrinsic::powi>(m_Specific(Op1), + m_Value(Y)))) && + willNotOverflowSignedSub(Y, ConstantInt::get(Y->getType(), 1), I)) { + Constant *NegOne = ConstantInt::getAllOnesValue(Y->getType()); + Value *Y1 = Builder.CreateAdd(Y, NegOne); + Type *Types[] = {Op1->getType(), Y1->getType()}; + Value *Pow = Builder.CreateIntrinsic(Intrinsic::powi, Types, {Op1, Y1}, &I); + return replaceInstUsesWith(I, Pow); + } + return nullptr; } @@ -1936,7 +1984,7 @@ Instruction *InstCombinerImpl::visitURem(BinaryOperator &I) { if (Instruction *common = commonIRemTransforms(I)) return common; - if (Instruction *NarrowRem = narrowUDivURem(I, Builder)) + if (Instruction *NarrowRem = narrowUDivURem(I, *this)) return NarrowRem; // X urem Y -> X and Y-1, where Y is a power of 2, |
