diff options
author | Max Kazantsev <mkazantsev@azul.com> | 2020-11-12 10:49:01 +0700 |
---|---|---|
committer | Max Kazantsev <mkazantsev@azul.com> | 2020-11-12 10:51:29 +0700 |
commit | 2e01ceafaa1ceef2428182128c3654bab56a0a4f (patch) | |
tree | da5a0becd3039066cba0bcf2be85e49674d2a4a8 /llvm/lib/Transforms/Utils/SimplifyIndVar.cpp | |
parent | 813781a923007a6070521ebfcb939796b0a47df8 (diff) | |
download | llvm-2e01ceafaa1ceef2428182128c3654bab56a0a4f.zip llvm-2e01ceafaa1ceef2428182128c3654bab56a0a4f.tar.gz llvm-2e01ceafaa1ceef2428182128c3654bab56a0a4f.tar.bz2 |
[IndVars] Recognize 'sub nuw' expressed as 'add' for widening
InstCombine canonicalizes 'sub nuw' instructions to 'add' without the
`nuw` flag. The typical case where we see it is decrementing induction
variables. For them, IndVars fails to prove that it's legal to widen them,
and inserts unprofitable `zext`'s.
This patch adds recognition of such pattern using SCEV.
Differential Revision: https://reviews.llvm.org/D89550
Reviewed By: fhahn, skatkov
Diffstat (limited to 'llvm/lib/Transforms/Utils/SimplifyIndVar.cpp')
-rw-r--r-- | llvm/lib/Transforms/Utils/SimplifyIndVar.cpp | 26 |
1 files changed, 22 insertions, 4 deletions
diff --git a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp index 079ec7f..c7c0815 100644 --- a/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyIndVar.cpp @@ -1539,8 +1539,26 @@ bool WidenIV::widenWithVariantUse(WidenIV::NarrowIVDefUse DU) { ExtendKind ExtKind = getExtendKind(NarrowDef); bool CanSignExtend = ExtKind == SignExtended && OBO->hasNoSignedWrap(); bool CanZeroExtend = ExtKind == ZeroExtended && OBO->hasNoUnsignedWrap(); - if (!CanSignExtend && !CanZeroExtend) - return false; + auto AnotherOpExtKind = ExtKind; + if (!CanSignExtend && !CanZeroExtend) { + // Because InstCombine turns 'sub nuw' to 'add' losing the no-wrap flag, we + // will most likely not see it. Let's try to prove it. + if (OpCode != Instruction::Add) + return false; + if (ExtKind != ZeroExtended) + return false; + const SCEV *LHS = SE->getSCEV(OBO->getOperand(0)); + const SCEV *RHS = SE->getSCEV(OBO->getOperand(1)); + if (!SE->isKnownNegative(RHS)) + return false; + bool ProvedSubNUW = SE->isKnownPredicateAt( + ICmpInst::ICMP_UGE, LHS, SE->getNegativeSCEV(RHS), NarrowUse); + if (!ProvedSubNUW) + return false; + // In fact, our 'add' is 'sub nuw'. We will need to widen the 2nd operand as + // neg(zext(neg(op))), which is basically sext(op). + AnotherOpExtKind = SignExtended; + } // Verifying that Defining operand is an AddRec const SCEV *Op1 = SE->getSCEV(WideDef); @@ -1564,11 +1582,11 @@ bool WidenIV::widenWithVariantUse(WidenIV::NarrowIVDefUse DU) { Value *LHS = (NarrowUse->getOperand(0) == NarrowDef) ? WideDef : createExtendInst(NarrowUse->getOperand(0), WideType, - ExtKind, NarrowUse); + AnotherOpExtKind, NarrowUse); Value *RHS = (NarrowUse->getOperand(1) == NarrowDef) ? WideDef : createExtendInst(NarrowUse->getOperand(1), WideType, - ExtKind, NarrowUse); + AnotherOpExtKind, NarrowUse); auto *NarrowBO = cast<BinaryOperator>(NarrowUse); auto *WideBO = BinaryOperator::Create(NarrowBO->getOpcode(), LHS, RHS, |