diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2021-07-29 20:15:26 +0000 |
| commit | 344a3780b2e33f6ca763666c380202b18aab72a3 (patch) | |
| tree | f0b203ee6eb71d7fdd792373e3c81eb18d6934dd /llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | |
| parent | b60736ec1405bb0a8dd40989f67ef4c93da068ab (diff) | |
vendor/llvm-project/llvmorg-13-init-16847-g88e66fa60ae5vendor/llvm-project/llvmorg-12.0.1-rc2-0-ge7dac564cd0evendor/llvm-project/llvmorg-12.0.1-0-gfed41342a82f
Diffstat (limited to 'llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp')
| -rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp | 102 |
1 files changed, 78 insertions, 24 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp index 4b485a0ad85e..6f2a8ebf839a 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -328,7 +328,7 @@ Instruction *InstCombinerImpl::visitMul(BinaryOperator &I) { if (((match(Op0, m_ZExt(m_Value(X))) && match(Op1, m_ZExt(m_Value(Y)))) || (match(Op0, m_SExt(m_Value(X))) && match(Op1, m_SExt(m_Value(Y))))) && X->getType()->isIntOrIntVectorTy(1) && X->getType() == Y->getType() && - (Op0->hasOneUse() || Op1->hasOneUse())) { + (Op0->hasOneUse() || Op1->hasOneUse() || X == Y)) { Value *And = Builder.CreateAnd(X, Y, "mulbool"); return CastInst::Create(Instruction::ZExt, And, I.getType()); } @@ -555,24 +555,30 @@ Instruction *InstCombinerImpl::visitFMul(BinaryOperator &I) { } } - // exp(X) * exp(Y) -> exp(X + Y) - // Match as long as at least one of exp has only one use. - if (match(Op0, m_Intrinsic<Intrinsic::exp>(m_Value(X))) && - match(Op1, m_Intrinsic<Intrinsic::exp>(m_Value(Y))) && - (Op0->hasOneUse() || Op1->hasOneUse())) { - Value *XY = Builder.CreateFAddFMF(X, Y, &I); - Value *Exp = Builder.CreateUnaryIntrinsic(Intrinsic::exp, XY, &I); - return replaceInstUsesWith(I, Exp); - } + 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); + } + + // 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) - // Match as long as at least one of exp2 has only one use. - if (match(Op0, m_Intrinsic<Intrinsic::exp2>(m_Value(X))) && - match(Op1, m_Intrinsic<Intrinsic::exp2>(m_Value(Y))) && - (Op0->hasOneUse() || Op1->hasOneUse())) { - Value *XY = Builder.CreateFAddFMF(X, Y, &I); - Value *Exp2 = Builder.CreateUnaryIntrinsic(Intrinsic::exp2, XY, &I); - return replaceInstUsesWith(I, Exp2); + // 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 @@ -661,13 +667,12 @@ bool InstCombinerImpl::simplifyDivRemOfSelectWithZeroOp(BinaryOperator &I) { break; // Replace uses of the select or its condition with the known values. - for (Instruction::op_iterator I = BBI->op_begin(), E = BBI->op_end(); - I != E; ++I) { - if (*I == SI) { - replaceUse(*I, SI->getOperand(NonNullOperand)); + for (Use &Op : BBI->operands()) { + if (Op == SI) { + replaceUse(Op, SI->getOperand(NonNullOperand)); Worklist.push(&*BBI); - } else if (*I == SelectCond) { - replaceUse(*I, NonNullOperand == 1 ? ConstantInt::getTrue(CondTy) + } else if (Op == SelectCond) { + replaceUse(Op, NonNullOperand == 1 ? ConstantInt::getTrue(CondTy) : ConstantInt::getFalse(CondTy)); Worklist.push(&*BBI); } @@ -1275,6 +1280,51 @@ static Instruction *foldFDivConstantDividend(BinaryOperator &I) { return BinaryOperator::CreateFDivFMF(NewC, X, &I); } +/// Negate the exponent of pow/exp to fold division-by-pow() into multiply. +static Instruction *foldFDivPowDivisor(BinaryOperator &I, + InstCombiner::BuilderTy &Builder) { + Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1); + auto *II = dyn_cast<IntrinsicInst>(Op1); + if (!II || !II->hasOneUse() || !I.hasAllowReassoc() || + !I.hasAllowReciprocal()) + return nullptr; + + // Z / pow(X, Y) --> Z * pow(X, -Y) + // Z / exp{2}(Y) --> Z * exp{2}(-Y) + // In the general case, this creates an extra instruction, but fmul allows + // for better canonicalization and optimization than fdiv. + Intrinsic::ID IID = II->getIntrinsicID(); + SmallVector<Value *> Args; + switch (IID) { + case Intrinsic::pow: + Args.push_back(II->getArgOperand(0)); + Args.push_back(Builder.CreateFNegFMF(II->getArgOperand(1), &I)); + break; + case Intrinsic::powi: { + // Require 'ninf' assuming that makes powi(X, -INT_MIN) acceptable. + // That is, X ** (huge negative number) is 0.0, ~1.0, or INF and so + // dividing by that is INF, ~1.0, or 0.0. Code that uses powi allows + // non-standard results, so this corner case should be acceptable if the + // code rules out INF values. + if (!I.hasNoInfs()) + return nullptr; + Args.push_back(II->getArgOperand(0)); + Args.push_back(Builder.CreateNeg(II->getArgOperand(1))); + Type *Tys[] = {I.getType(), II->getArgOperand(1)->getType()}; + Value *Pow = Builder.CreateIntrinsic(IID, Tys, Args, &I); + return BinaryOperator::CreateFMulFMF(Op0, Pow, &I); + } + case Intrinsic::exp: + case Intrinsic::exp2: + Args.push_back(Builder.CreateFNegFMF(II->getArgOperand(0), &I)); + break; + default: + return nullptr; + } + Value *Pow = Builder.CreateIntrinsic(IID, I.getType(), Args, &I); + return BinaryOperator::CreateFMulFMF(Op0, Pow, &I); +} + Instruction *InstCombinerImpl::visitFDiv(BinaryOperator &I) { if (Value *V = SimplifyFDivInst(I.getOperand(0), I.getOperand(1), I.getFastMathFlags(), @@ -1373,6 +1423,10 @@ Instruction *InstCombinerImpl::visitFDiv(BinaryOperator &I) { Intrinsic::copysign, ConstantFP::get(I.getType(), 1.0), X, &I); return replaceInstUsesWith(I, V); } + + if (Instruction *Mul = foldFDivPowDivisor(I, Builder)) + return Mul; + return nullptr; } |
