diff options
Diffstat (limited to 'llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp')
-rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp | 125 |
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; } |