diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2018-11-28 16:37:15 +0000 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2018-11-28 16:37:15 +0000 |
commit | 8d63aed45941eb40ee30cf80584d6fd024d56b53 (patch) | |
tree | 424b191c74900bc20d2beaf6c56db556641adc0c /llvm/lib | |
parent | 42f89989a1ccfa7df637a2ffb9c6aa0e249c70e6 (diff) | |
download | bcm5719-llvm-8d63aed45941eb40ee30cf80584d6fd024d56b53.tar.gz bcm5719-llvm-8d63aed45941eb40ee30cf80584d6fd024d56b53.zip |
[InstCombine] Combine saturating add/sub with constant operands
Combine
sat(sat(X + C1) + C2) -> sat(X + (C1+C2))
and
sat(sat(X - C1) - C2) -> sat(X - (C1+C2))
if the sign of C1 and C2 matches.
In the unsigned case we can compute C1+C2 with saturating arithmetic,
and InstSimplify will reduce this just to the saturation value. For
the signed case, we cannot perform the simplification if the result
of the addition overflows.
This change is part of https://reviews.llvm.org/D54534.
llvm-svn: 347773
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 34 |
1 files changed, 34 insertions, 0 deletions
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp index a6921d745e8..f0b09e1f0bd 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -2113,6 +2113,40 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) { *II, Builder.CreateBinaryIntrinsic( Intrinsic::sadd_sat, Arg0, NegVal)); } + + // sat(sat(X + Val2) + Val) -> sat(X + (Val+Val2)) + // sat(sat(X - Val2) - Val) -> sat(X - (Val+Val2)) + // if Val and Val2 have the same sign + if (auto *Other = dyn_cast<IntrinsicInst>(Arg0)) { + Value *X; + const APInt *Val, *Val2; + APInt NewVal; + bool IsUnsigned = + IID == Intrinsic::uadd_sat || IID == Intrinsic::usub_sat; + if (Other->getIntrinsicID() == II->getIntrinsicID() && + match(Arg1, m_APInt(Val)) && + match(Other->getArgOperand(0), m_Value(X)) && + match(Other->getArgOperand(1), m_APInt(Val2))) { + if (IsUnsigned) + NewVal = Val->uadd_sat(*Val2); + else if (Val->isNonNegative() == Val2->isNonNegative()) { + bool Overflow; + NewVal = Val->sadd_ov(*Val2, Overflow); + if (Overflow) { + // Both adds together may add more than SignedMaxValue + // without saturating the final result. + break; + } + } else { + // Cannot fold saturated addition with different signs. + break; + } + + return replaceInstUsesWith( + *II, Builder.CreateBinaryIntrinsic( + IID, X, ConstantInt::get(II->getType(), NewVal))); + } + } break; } |