diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2022-07-03 14:10:23 +0000 |
| commit | 145449b1e420787bb99721a429341fa6be3adfb6 (patch) | |
| tree | 1d56ae694a6de602e348dd80165cf881a36600ed /llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp | |
| parent | ecbca9f5fb7d7613d2b94982c4825eb0d33d6842 (diff) | |
Diffstat (limited to 'llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp')
| -rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp | 115 |
1 files changed, 65 insertions, 50 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp index 0598f751febe..f4d8b79a5311 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -693,9 +693,6 @@ unsigned FAddCombine::calcInstrNumber(const AddendVect &Opnds) { unsigned OpndNum = Opnds.size(); unsigned InstrNeeded = OpndNum - 1; - // The number of addends in the form of "(-1)*x". - unsigned NegOpndNum = 0; - // Adjust the number of instructions needed to emit the N-ary add. for (const FAddend *Opnd : Opnds) { if (Opnd->isConstant()) @@ -707,9 +704,6 @@ unsigned FAddCombine::calcInstrNumber(const AddendVect &Opnds) { continue; const FAddendCoef &CE = Opnd->getCoef(); - if (CE.isMinusOne() || CE.isMinusTwo()) - NegOpndNum++; - // Let the addend be "c * x". If "c == +/-1", the value of the addend // is immediately available; otherwise, it needs exactly one instruction // to evaluate the value. @@ -1277,7 +1271,7 @@ static Instruction *factorizeMathWithShlOps(BinaryOperator &I, } Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) { - if (Value *V = SimplifyAddInst(I.getOperand(0), I.getOperand(1), + if (Value *V = simplifyAddInst(I.getOperand(0), I.getOperand(1), I.hasNoSignedWrap(), I.hasNoUnsignedWrap(), SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -1375,6 +1369,13 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) { } } + // (A & 2^C1) + A => A & (2^C1 - 1) iff bit C1 in A is a sign bit + if (match(&I, m_c_Add(m_And(m_Value(A), m_APInt(C1)), m_Deferred(A))) && + C1->isPowerOf2() && (ComputeNumSignBits(A) > C1->countLeadingZeros())) { + Constant *NewMask = ConstantInt::get(RHS->getType(), *C1 - 1); + return BinaryOperator::CreateAnd(A, NewMask); + } + // A+B --> A|B iff A and B have no bits set in common. if (haveNoCommonBitsSet(LHS, RHS, DL, &AC, &I, &DT)) return BinaryOperator::CreateOr(LHS, RHS); @@ -1528,7 +1529,7 @@ static Instruction *factorizeFAddFSub(BinaryOperator &I, } Instruction *InstCombinerImpl::visitFAdd(BinaryOperator &I) { - if (Value *V = SimplifyFAddInst(I.getOperand(0), I.getOperand(1), + if (Value *V = simplifyFAddInst(I.getOperand(0), I.getOperand(1), I.getFastMathFlags(), SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -1687,7 +1688,8 @@ Value *InstCombinerImpl::OptimizePointerDifference(Value *LHS, Value *RHS, // Require at least one GEP with a common base pointer on both sides. if (auto *LHSGEP = dyn_cast<GEPOperator>(LHS)) { // (gep X, ...) - X - if (LHSGEP->getOperand(0) == RHS) { + if (LHSGEP->getOperand(0)->stripPointerCasts() == + RHS->stripPointerCasts()) { GEP1 = LHSGEP; } else if (auto *RHSGEP = dyn_cast<GEPOperator>(RHS)) { // (gep X, ...) - (gep X, ...) @@ -1749,7 +1751,7 @@ Value *InstCombinerImpl::OptimizePointerDifference(Value *LHS, Value *RHS, } Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) { - if (Value *V = SimplifySubInst(I.getOperand(0), I.getOperand(1), + if (Value *V = simplifySubInst(I.getOperand(0), I.getOperand(1), I.hasNoSignedWrap(), I.hasNoUnsignedWrap(), SQ.getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -2014,6 +2016,37 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) { } } + if (auto *II = dyn_cast<MinMaxIntrinsic>(Op1)) { + { + // sub(add(X,Y), s/umin(X,Y)) --> s/umax(X,Y) + // sub(add(X,Y), s/umax(X,Y)) --> s/umin(X,Y) + Value *X = II->getLHS(); + Value *Y = II->getRHS(); + if (match(Op0, m_c_Add(m_Specific(X), m_Specific(Y))) && + (Op0->hasOneUse() || Op1->hasOneUse())) { + Intrinsic::ID InvID = getInverseMinMaxIntrinsic(II->getIntrinsicID()); + Value *InvMaxMin = Builder.CreateBinaryIntrinsic(InvID, X, Y); + return replaceInstUsesWith(I, InvMaxMin); + } + } + + { + // sub(add(X,Y),umin(Y,Z)) --> add(X,usub.sat(Y,Z)) + // sub(add(X,Z),umin(Y,Z)) --> add(X,usub.sat(Z,Y)) + Value *X, *Y, *Z; + if (match(Op1, m_OneUse(m_UMin(m_Value(Y), m_Value(Z))))) { + if (match(Op0, m_OneUse(m_c_Add(m_Specific(Y), m_Value(X))))) + return BinaryOperator::CreateAdd( + X, Builder.CreateIntrinsic(Intrinsic::usub_sat, I.getType(), + {Y, Z})); + if (match(Op0, m_OneUse(m_c_Add(m_Specific(Z), m_Value(X))))) + return BinaryOperator::CreateAdd( + X, Builder.CreateIntrinsic(Intrinsic::usub_sat, I.getType(), + {Z, Y})); + } + } + } + { // If we have a subtraction between some value and a select between // said value and something else, sink subtraction into select hands, i.e.: @@ -2089,36 +2122,6 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) { return BinaryOperator::CreateSub(X, Not); } - // TODO: This is the same logic as above but handles the cmp-select idioms - // for min/max, so the use checks are increased to account for the - // extra instructions. If we canonicalize to intrinsics, this block - // can likely be removed. - { - Value *LHS, *RHS, *A; - Value *NotA = Op0, *MinMax = Op1; - SelectPatternFlavor SPF = matchSelectPattern(MinMax, LHS, RHS).Flavor; - if (!SelectPatternResult::isMinOrMax(SPF)) { - NotA = Op1; - MinMax = Op0; - SPF = matchSelectPattern(MinMax, LHS, RHS).Flavor; - } - if (SelectPatternResult::isMinOrMax(SPF) && - match(NotA, m_Not(m_Value(A))) && (NotA == LHS || NotA == RHS)) { - if (NotA == LHS) - std::swap(LHS, RHS); - // LHS is now Y above and expected to have at least 2 uses (the min/max) - // NotA is expected to have 2 uses from the min/max and 1 from the sub. - if (isFreeToInvert(LHS, !LHS->hasNUsesOrMore(3)) && - !NotA->hasNUsesOrMore(4)) { - Value *Not = Builder.CreateNot(MinMax); - if (NotA == Op0) - return BinaryOperator::CreateSub(Not, A); - else - return BinaryOperator::CreateSub(A, Not); - } - } - } - // Optimize pointer differences into the same array into a size. Consider: // &A[10] - &A[0]: we should compile this to "10". Value *LHSOp, *RHSOp; @@ -2149,11 +2152,11 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) { // B = ashr i32 A, 31 ; smear the sign bit // sub (xor A, B), B ; flip bits if negative and subtract -1 (add 1) // --> (A < 0) ? -A : A - Value *Cmp = Builder.CreateICmpSLT(A, ConstantInt::getNullValue(Ty)); + Value *IsNeg = Builder.CreateIsNeg(A); // Copy the nuw/nsw flags from the sub to the negate. - Value *Neg = Builder.CreateNeg(A, "", I.hasNoUnsignedWrap(), - I.hasNoSignedWrap()); - return SelectInst::Create(Cmp, Neg, A); + Value *NegA = Builder.CreateNeg(A, "", I.hasNoUnsignedWrap(), + I.hasNoSignedWrap()); + return SelectInst::Create(IsNeg, NegA, A); } // If we are subtracting a low-bit masked subset of some value from an add @@ -2187,12 +2190,23 @@ Instruction *InstCombinerImpl::visitSub(BinaryOperator &I) { return replaceInstUsesWith( I, Builder.CreateIntrinsic(Intrinsic::usub_sat, {Ty}, {X, Op1})); + // Op0 - umin(X, Op0) --> usub.sat(Op0, X) + if (match(Op1, m_OneUse(m_c_UMin(m_Value(X), m_Specific(Op0))))) + return replaceInstUsesWith( + I, Builder.CreateIntrinsic(Intrinsic::usub_sat, {Ty}, {Op0, X})); + // Op0 - umax(X, Op0) --> 0 - usub.sat(X, Op0) if (match(Op1, m_OneUse(m_c_UMax(m_Value(X), m_Specific(Op0))))) { Value *USub = Builder.CreateIntrinsic(Intrinsic::usub_sat, {Ty}, {X, Op0}); return BinaryOperator::CreateNeg(USub); } + // umin(X, Op1) - Op1 --> 0 - usub.sat(Op1, X) + if (match(Op0, m_OneUse(m_c_UMin(m_Value(X), m_Specific(Op1))))) { + Value *USub = Builder.CreateIntrinsic(Intrinsic::usub_sat, {Ty}, {Op1, X}); + return BinaryOperator::CreateNeg(USub); + } + // 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))))) @@ -2264,7 +2278,7 @@ static Instruction *hoistFNegAboveFMulFDiv(Instruction &I, Instruction *InstCombinerImpl::visitFNeg(UnaryOperator &I) { Value *Op = I.getOperand(0); - if (Value *V = SimplifyFNegInst(Op, I.getFastMathFlags(), + if (Value *V = simplifyFNegInst(Op, I.getFastMathFlags(), getSimplifyQuery().getWithInstruction(&I))) return replaceInstUsesWith(I, V); @@ -2287,10 +2301,11 @@ Instruction *InstCombinerImpl::visitFNeg(UnaryOperator &I) { // 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) { + auto propagateSelectFMF = [&](SelectInst *S, bool CommonOperand) { S->copyFastMathFlags(&I); if (auto *OldSel = dyn_cast<SelectInst>(Op)) - if (!OldSel->hasNoSignedZeros()) + if (!OldSel->hasNoSignedZeros() && !CommonOperand && + !isGuaranteedNotToBeUndefOrPoison(OldSel->getCondition())) S->setHasNoSignedZeros(false); }; // -(Cond ? -P : Y) --> Cond ? P : -Y @@ -2298,14 +2313,14 @@ Instruction *InstCombinerImpl::visitFNeg(UnaryOperator &I) { 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); + propagateSelectFMF(NewSel, P == Y); 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); + propagateSelectFMF(NewSel, P == X); return NewSel; } } @@ -2314,7 +2329,7 @@ Instruction *InstCombinerImpl::visitFNeg(UnaryOperator &I) { } Instruction *InstCombinerImpl::visitFSub(BinaryOperator &I) { - if (Value *V = SimplifyFSubInst(I.getOperand(0), I.getOperand(1), + if (Value *V = simplifyFSubInst(I.getOperand(0), I.getOperand(1), I.getFastMathFlags(), getSimplifyQuery().getWithInstruction(&I))) return replaceInstUsesWith(I, V); |
