aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp')
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp125
1 files changed, 111 insertions, 14 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index bacb8689892a..d01a021bf3f4 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -864,7 +864,7 @@ static Instruction *foldNoWrapAdd(BinaryOperator &Add,
Instruction *InstCombinerImpl::foldAddWithConstant(BinaryOperator &Add) {
Value *Op0 = Add.getOperand(0), *Op1 = Add.getOperand(1);
Constant *Op1C;
- if (!match(Op1, m_Constant(Op1C)))
+ if (!match(Op1, m_ImmConstant(Op1C)))
return nullptr;
if (Instruction *NV = foldBinOpIntoSelectOrPhi(Add))
@@ -901,6 +901,12 @@ Instruction *InstCombinerImpl::foldAddWithConstant(BinaryOperator &Add) {
if (!match(Op1, m_APInt(C)))
return nullptr;
+ // (X | Op01C) + Op1C --> X + (Op01C + Op1C) iff the `or` is actually an `add`
+ Constant *Op01C;
+ if (match(Op0, m_Or(m_Value(X), m_ImmConstant(Op01C))) &&
+ haveNoCommonBitsSet(X, Op01C, DL, &AC, &Add, &DT))
+ return BinaryOperator::CreateAdd(X, ConstantExpr::getAdd(Op01C, Op1C));
+
// (X | C2) + C --> (X | C2) ^ C2 iff (C2 == -C)
const APInt *C2;
if (match(Op0, m_Or(m_Value(), m_APInt(C2))) && *C2 == -*C)
@@ -1442,6 +1448,14 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
Builder.CreateIntrinsic(Intrinsic::umax, {I.getType()}, {A, B}));
}
+ // ctpop(A) + ctpop(B) => ctpop(A | B) if A and B have no bits set in common.
+ if (match(LHS, m_OneUse(m_Intrinsic<Intrinsic::ctpop>(m_Value(A)))) &&
+ match(RHS, m_OneUse(m_Intrinsic<Intrinsic::ctpop>(m_Value(B)))) &&
+ haveNoCommonBitsSet(A, B, DL, &AC, &I, &DT))
+ return replaceInstUsesWith(
+ I, Builder.CreateIntrinsic(Intrinsic::ctpop, {I.getType()},
+ {Builder.CreateOr(A, B)}));
+
return Changed ? &I : nullptr;
}
@@ -1608,6 +1622,27 @@ Instruction *InstCombinerImpl::visitFAdd(BinaryOperator &I) {
if (I.hasAllowReassoc() && I.hasNoSignedZeros()) {
if (Instruction *F = factorizeFAddFSub(I, Builder))
return F;
+
+ // Try to fold fadd into start value of reduction intrinsic.
+ if (match(&I, m_c_FAdd(m_OneUse(m_Intrinsic<Intrinsic::vector_reduce_fadd>(
+ m_AnyZeroFP(), m_Value(X))),
+ m_Value(Y)))) {
+ // fadd (rdx 0.0, X), Y --> rdx Y, X
+ return replaceInstUsesWith(
+ I, Builder.CreateIntrinsic(Intrinsic::vector_reduce_fadd,
+ {X->getType()}, {Y, X}, &I));
+ }
+ const APFloat *StartC, *C;
+ if (match(LHS, m_OneUse(m_Intrinsic<Intrinsic::vector_reduce_fadd>(
+ m_APFloat(StartC), m_Value(X)))) &&
+ match(RHS, m_APFloat(C))) {
+ // fadd (rdx StartC, X), C --> rdx (C + StartC), X
+ Constant *NewStartC = ConstantFP::get(I.getType(), *C + *StartC);
+ return replaceInstUsesWith(
+ I, Builder.CreateIntrinsic(Intrinsic::vector_reduce_fadd,
+ {X->getType()}, {NewStartC, X}, &I));
+ }
+
if (Value *V = FAddCombine(Builder).simplify(&I))
return replaceInstUsesWith(I, V);
}
@@ -1726,12 +1761,13 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
if (Instruction *R = factorizeMathWithShlOps(I, Builder))
return R;
- if (Constant *C = dyn_cast<Constant>(Op0)) {
+ Constant *C;
+ if (match(Op0, m_ImmConstant(C))) {
Value *X;
Constant *C2;
// C-(X+C2) --> (C-C2)-X
- if (match(Op1, m_Add(m_Value(X), m_Constant(C2))))
+ if (match(Op1, m_Add(m_Value(X), m_ImmConstant(C2))))
return BinaryOperator::CreateSub(ConstantExpr::getSub(C, C2), X);
}
@@ -1801,6 +1837,12 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
return BinaryOperator::CreateSub(XZ, YW);
}
+ // ((X - Y) - Op1) --> X - (Y + Op1)
+ if (match(Op0, m_OneUse(m_Sub(m_Value(X), m_Value(Y))))) {
+ Value *Add = Builder.CreateAdd(Y, Op1);
+ return BinaryOperator::CreateSub(X, Add);
+ }
+
auto m_AddRdx = [](Value *&Vec) {
return m_OneUse(m_Intrinsic<Intrinsic::vector_reduce_add>(m_Value(Vec)));
};
@@ -2085,33 +2127,59 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) {
canonicalizeCondSignextOfHighBitExtractToSignextHighBitExtract(I))
return V;
+ // X - usub.sat(X, Y) => umin(X, Y)
+ if (match(Op1, m_OneUse(m_Intrinsic<Intrinsic::usub_sat>(m_Specific(Op0),
+ m_Value(Y)))))
+ return replaceInstUsesWith(
+ I, Builder.CreateIntrinsic(Intrinsic::umin, {I.getType()}, {Op0, Y}));
+
+ // C - ctpop(X) => ctpop(~X) if C is bitwidth
+ if (match(Op0, m_SpecificInt(Ty->getScalarSizeInBits())) &&
+ match(Op1, m_OneUse(m_Intrinsic<Intrinsic::ctpop>(m_Value(X)))))
+ return replaceInstUsesWith(
+ I, Builder.CreateIntrinsic(Intrinsic::ctpop, {I.getType()},
+ {Builder.CreateNot(X)}));
+
return TryToNarrowDeduceFlags();
}
/// This eliminates floating-point negation in either 'fneg(X)' or
/// 'fsub(-0.0, X)' form by combining into a constant operand.
static Instruction *foldFNegIntoConstant(Instruction &I) {
+ // This is limited with one-use because fneg is assumed better for
+ // reassociation and cheaper in codegen than fmul/fdiv.
+ // TODO: Should the m_OneUse restriction be removed?
+ Instruction *FNegOp;
+ if (!match(&I, m_FNeg(m_OneUse(m_Instruction(FNegOp)))))
+ return nullptr;
+
Value *X;
Constant *C;
- // Fold negation into constant operand. This is limited with one-use because
- // fneg is assumed better for analysis and cheaper in codegen than fmul/fdiv.
+ // Fold negation into constant operand.
// -(X * C) --> X * (-C)
- // FIXME: It's arguable whether these should be m_OneUse or not. The current
- // belief is that the FNeg allows for better reassociation opportunities.
- if (match(&I, m_FNeg(m_OneUse(m_FMul(m_Value(X), m_Constant(C))))))
+ if (match(FNegOp, m_FMul(m_Value(X), m_Constant(C))))
return BinaryOperator::CreateFMulFMF(X, ConstantExpr::getFNeg(C), &I);
// -(X / C) --> X / (-C)
- if (match(&I, m_FNeg(m_OneUse(m_FDiv(m_Value(X), m_Constant(C))))))
+ if (match(FNegOp, m_FDiv(m_Value(X), m_Constant(C))))
return BinaryOperator::CreateFDivFMF(X, ConstantExpr::getFNeg(C), &I);
// -(C / X) --> (-C) / X
- if (match(&I, m_FNeg(m_OneUse(m_FDiv(m_Constant(C), m_Value(X))))))
- return BinaryOperator::CreateFDivFMF(ConstantExpr::getFNeg(C), X, &I);
-
+ if (match(FNegOp, m_FDiv(m_Constant(C), m_Value(X)))) {
+ Instruction *FDiv =
+ BinaryOperator::CreateFDivFMF(ConstantExpr::getFNeg(C), X, &I);
+
+ // Intersect 'nsz' and 'ninf' because those special value exceptions may not
+ // apply to the fdiv. Everything else propagates from the fneg.
+ // TODO: We could propagate nsz/ninf from fdiv alone?
+ FastMathFlags FMF = I.getFastMathFlags();
+ FastMathFlags OpFMF = FNegOp->getFastMathFlags();
+ FDiv->setHasNoSignedZeros(FMF.noSignedZeros() & OpFMF.noSignedZeros());
+ FDiv->setHasNoInfs(FMF.noInfs() & OpFMF.noInfs());
+ return FDiv;
+ }
// With NSZ [ counter-example with -0.0: -(-0.0 + 0.0) != 0.0 + -0.0 ]:
// -(X + C) --> -X + -C --> -C - X
- if (I.hasNoSignedZeros() &&
- match(&I, m_FNeg(m_OneUse(m_FAdd(m_Value(X), m_Constant(C))))))
+ if (I.hasNoSignedZeros() && match(FNegOp, m_FAdd(m_Value(X), m_Constant(C))))
return BinaryOperator::CreateFSubFMF(ConstantExpr::getFNeg(C), X, &I);
return nullptr;
@@ -2153,6 +2221,35 @@ Instruction *InstCombinerImpl::visitFNeg(UnaryOperator &I) {
if (Instruction *R = hoistFNegAboveFMulFDiv(I, Builder))
return R;
+ // Try to eliminate fneg if at least 1 arm of the select is negated.
+ Value *Cond;
+ if (match(Op, m_OneUse(m_Select(m_Value(Cond), m_Value(X), m_Value(Y))))) {
+ // Unlike most transforms, this one is not safe to propagate nsz unless
+ // it is present on the original select. (We are conservatively intersecting
+ // the nsz flags from the select and root fneg instruction.)
+ auto propagateSelectFMF = [&](SelectInst *S) {
+ S->copyFastMathFlags(&I);
+ if (auto *OldSel = dyn_cast<SelectInst>(Op))
+ if (!OldSel->hasNoSignedZeros())
+ S->setHasNoSignedZeros(false);
+ };
+ // -(Cond ? -P : Y) --> Cond ? P : -Y
+ Value *P;
+ if (match(X, m_FNeg(m_Value(P)))) {
+ Value *NegY = Builder.CreateFNegFMF(Y, &I, Y->getName() + ".neg");
+ SelectInst *NewSel = SelectInst::Create(Cond, P, NegY);
+ propagateSelectFMF(NewSel);
+ return NewSel;
+ }
+ // -(Cond ? X : -P) --> Cond ? -X : P
+ if (match(Y, m_FNeg(m_Value(P)))) {
+ Value *NegX = Builder.CreateFNegFMF(X, &I, X->getName() + ".neg");
+ SelectInst *NewSel = SelectInst::Create(Cond, NegX, P);
+ propagateSelectFMF(NewSel);
+ return NewSel;
+ }
+ }
+
return nullptr;
}