diff options
Diffstat (limited to 'llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp')
-rw-r--r-- | llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp | 62 |
1 files changed, 48 insertions, 14 deletions
diff --git a/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp b/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp index 2a1a040bf83ee..f1d2e3c1ecfad 100644 --- a/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp +++ b/llvm/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp @@ -431,8 +431,10 @@ private: bool reuniteExts(Instruction *I); /// Find the closest dominator of <Dominatee> that is equivalent to <Key>. - Instruction *findClosestMatchingDominator(const SCEV *Key, - Instruction *Dominatee); + Instruction *findClosestMatchingDominator( + const SCEV *Key, Instruction *Dominatee, + DenseMap<const SCEV *, SmallVector<Instruction *, 2>> &DominatingExprs); + /// Verify F is free of dead code. void verifyNoDeadCode(Function &F); @@ -456,7 +458,8 @@ private: /// multiple GEPs with a single index. bool LowerGEP; - DenseMap<const SCEV *, SmallVector<Instruction *, 2>> DominatingExprs; + DenseMap<const SCEV *, SmallVector<Instruction *, 2>> DominatingAdds; + DenseMap<const SCEV *, SmallVector<Instruction *, 2>> DominatingSubs; }; } // end anonymous namespace @@ -519,7 +522,7 @@ bool ConstantOffsetExtractor::CanTraceInto(bool SignExtended, // sext(a + b) = sext(a) + sext(b) // even if the addition is not marked nsw. // - // Leveraging this invarient, we can trace into an sext'ed inbound GEP + // Leveraging this invariant, we can trace into an sext'ed inbound GEP // index if the constant offset is non-negative. // // Verified in @sext_add in split-gep.ll. @@ -549,6 +552,9 @@ bool ConstantOffsetExtractor::CanTraceInto(bool SignExtended, APInt ConstantOffsetExtractor::findInEitherOperand(BinaryOperator *BO, bool SignExtended, bool ZeroExtended) { + // Save off the current height of the chain, in case we need to restore it. + size_t ChainLength = UserChain.size(); + // BO being non-negative does not shed light on whether its operands are // non-negative. Clear the NonNegative flag here. APInt ConstantOffset = find(BO->getOperand(0), SignExtended, ZeroExtended, @@ -559,12 +565,22 @@ APInt ConstantOffsetExtractor::findInEitherOperand(BinaryOperator *BO, // However, such cases are probably already handled by -instcombine, // given this pass runs after the standard optimizations. if (ConstantOffset != 0) return ConstantOffset; + + // Reset the chain back to where it was when we started exploring this node, + // since visiting the LHS didn't pan out. + UserChain.resize(ChainLength); + ConstantOffset = find(BO->getOperand(1), SignExtended, ZeroExtended, /* NonNegative */ false); // If U is a sub operator, negate the constant offset found in the right // operand. if (BO->getOpcode() == Instruction::Sub) ConstantOffset = -ConstantOffset; + + // If RHS wasn't a suitable candidate either, reset the chain again. + if (ConstantOffset == 0) + UserChain.resize(ChainLength); + return ConstantOffset; } @@ -688,7 +704,7 @@ Value *ConstantOffsetExtractor::removeConstOffset(unsigned ChainIndex) { } BinaryOperator *BO = cast<BinaryOperator>(UserChain[ChainIndex]); - assert(BO->getNumUses() <= 1 && + assert((BO->use_empty() || BO->hasOneUse()) && "distributeExtsAndCloneChain clones each BinaryOperator in " "UserChain, so no one should be used more than " "once"); @@ -1141,7 +1157,8 @@ bool SeparateConstOffsetFromGEP::runOnFunction(Function &F) { } Instruction *SeparateConstOffsetFromGEP::findClosestMatchingDominator( - const SCEV *Key, Instruction *Dominatee) { + const SCEV *Key, Instruction *Dominatee, + DenseMap<const SCEV *, SmallVector<Instruction *, 2>> &DominatingExprs) { auto Pos = DominatingExprs.find(Key); if (Pos == DominatingExprs.end()) return nullptr; @@ -1169,12 +1186,23 @@ bool SeparateConstOffsetFromGEP::reuniteExts(Instruction *I) { // If Dom can't sign overflow and Dom dominates I, optimize I to sext(Dom). // TODO: handle zext Value *LHS = nullptr, *RHS = nullptr; - if (match(I, m_Add(m_SExt(m_Value(LHS)), m_SExt(m_Value(RHS)))) || - match(I, m_Sub(m_SExt(m_Value(LHS)), m_SExt(m_Value(RHS))))) { + if (match(I, m_Add(m_SExt(m_Value(LHS)), m_SExt(m_Value(RHS))))) { if (LHS->getType() == RHS->getType()) { const SCEV *Key = SE->getAddExpr(SE->getUnknown(LHS), SE->getUnknown(RHS)); - if (auto *Dom = findClosestMatchingDominator(Key, I)) { + if (auto *Dom = findClosestMatchingDominator(Key, I, DominatingAdds)) { + Instruction *NewSExt = new SExtInst(Dom, I->getType(), "", I); + NewSExt->takeName(I); + I->replaceAllUsesWith(NewSExt); + RecursivelyDeleteTriviallyDeadInstructions(I); + return true; + } + } + } else if (match(I, m_Sub(m_SExt(m_Value(LHS)), m_SExt(m_Value(RHS))))) { + if (LHS->getType() == RHS->getType()) { + const SCEV *Key = + SE->getAddExpr(SE->getUnknown(LHS), SE->getUnknown(RHS)); + if (auto *Dom = findClosestMatchingDominator(Key, I, DominatingSubs)) { Instruction *NewSExt = new SExtInst(Dom, I->getType(), "", I); NewSExt->takeName(I); I->replaceAllUsesWith(NewSExt); @@ -1185,12 +1213,17 @@ bool SeparateConstOffsetFromGEP::reuniteExts(Instruction *I) { } // Add I to DominatingExprs if it's an add/sub that can't sign overflow. - if (match(I, m_NSWAdd(m_Value(LHS), m_Value(RHS))) || - match(I, m_NSWSub(m_Value(LHS), m_Value(RHS)))) { - if (programUndefinedIfFullPoison(I)) { + if (match(I, m_NSWAdd(m_Value(LHS), m_Value(RHS)))) { + if (programUndefinedIfPoison(I)) { + const SCEV *Key = + SE->getAddExpr(SE->getUnknown(LHS), SE->getUnknown(RHS)); + DominatingAdds[Key].push_back(I); + } + } else if (match(I, m_NSWSub(m_Value(LHS), m_Value(RHS)))) { + if (programUndefinedIfPoison(I)) { const SCEV *Key = SE->getAddExpr(SE->getUnknown(LHS), SE->getUnknown(RHS)); - DominatingExprs[Key].push_back(I); + DominatingSubs[Key].push_back(I); } } return false; @@ -1198,7 +1231,8 @@ bool SeparateConstOffsetFromGEP::reuniteExts(Instruction *I) { bool SeparateConstOffsetFromGEP::reuniteExts(Function &F) { bool Changed = false; - DominatingExprs.clear(); + DominatingAdds.clear(); + DominatingSubs.clear(); for (const auto Node : depth_first(DT)) { BasicBlock *BB = Node->getBlock(); for (auto I = BB->begin(); I != BB->end(); ) { |