summaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-07-29 20:15:26 +0000
commit344a3780b2e33f6ca763666c380202b18aab72a3 (patch)
treef0b203ee6eb71d7fdd792373e3c81eb18d6934dd /llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
parentb60736ec1405bb0a8dd40989f67ef4c93da068ab (diff)
Diffstat (limited to 'llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp')
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp102
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;
}