diff options
Diffstat (limited to 'lib/Transforms/Scalar/CallSiteSplitting.cpp')
| -rw-r--r-- | lib/Transforms/Scalar/CallSiteSplitting.cpp | 102 |
1 files changed, 66 insertions, 36 deletions
diff --git a/lib/Transforms/Scalar/CallSiteSplitting.cpp b/lib/Transforms/Scalar/CallSiteSplitting.cpp index 5ebfbf8a879b..a806d6faed60 100644 --- a/lib/Transforms/Scalar/CallSiteSplitting.cpp +++ b/lib/Transforms/Scalar/CallSiteSplitting.cpp @@ -149,14 +149,14 @@ static void recordCondition(CallSite CS, BasicBlock *From, BasicBlock *To, /// Record ICmp conditions relevant to any argument in CS following Pred's /// single predecessors. If there are conflicting conditions along a path, like -/// x == 1 and x == 0, the first condition will be used. +/// x == 1 and x == 0, the first condition will be used. We stop once we reach +/// an edge to StopAt. static void recordConditions(CallSite CS, BasicBlock *Pred, - ConditionsTy &Conditions) { - recordCondition(CS, Pred, CS.getInstruction()->getParent(), Conditions); + ConditionsTy &Conditions, BasicBlock *StopAt) { BasicBlock *From = Pred; BasicBlock *To = Pred; SmallPtrSet<BasicBlock *, 4> Visited; - while (!Visited.count(From->getSinglePredecessor()) && + while (To != StopAt && !Visited.count(From->getSinglePredecessor()) && (From = From->getSinglePredecessor())) { recordCondition(CS, From, To, Conditions); Visited.insert(From); @@ -197,7 +197,7 @@ static bool canSplitCallSite(CallSite CS, TargetTransformInfo &TTI) { isa<IndirectBrInst>(Preds[1]->getTerminator())) return false; - // BasicBlock::canSplitPredecessors is more agressive, so checking for + // BasicBlock::canSplitPredecessors is more aggressive, so checking for // BasicBlock::isEHPad as well. if (!CallSiteBB->canSplitPredecessors() || CallSiteBB->isEHPad()) return false; @@ -248,7 +248,7 @@ static void copyMustTailReturn(BasicBlock *SplitBB, Instruction *CI, ReturnInst* RI = dyn_cast<ReturnInst>(&*II); assert(RI && "`musttail` call must be followed by `ret` instruction"); - TerminatorInst *TI = SplitBB->getTerminator(); + Instruction *TI = SplitBB->getTerminator(); Value *V = NewCI; if (BCI) V = cloneInstForMustTail(BCI, TI, V); @@ -302,7 +302,7 @@ static void copyMustTailReturn(BasicBlock *SplitBB, Instruction *CI, static void splitCallSite( CallSite CS, const SmallVectorImpl<std::pair<BasicBlock *, ConditionsTy>> &Preds, - DominatorTree *DT) { + DomTreeUpdater &DTU) { Instruction *Instr = CS.getInstruction(); BasicBlock *TailBB = Instr->getParent(); bool IsMustTailCall = CS.isMustTailCall(); @@ -312,8 +312,10 @@ static void splitCallSite( // `musttail` calls must be followed by optional `bitcast`, and `ret`. The // split blocks will be terminated right after that so there're no users for // this phi in a `TailBB`. - if (!IsMustTailCall && !Instr->use_empty()) + if (!IsMustTailCall && !Instr->use_empty()) { CallPN = PHINode::Create(Instr->getType(), Preds.size(), "phi.call"); + CallPN->setDebugLoc(Instr->getDebugLoc()); + } LLVM_DEBUG(dbgs() << "split call-site : " << *Instr << " into \n"); @@ -325,7 +327,7 @@ static void splitCallSite( BasicBlock *PredBB = Preds[i].first; BasicBlock *SplitBlock = DuplicateInstructionsInSplitBetween( TailBB, PredBB, &*std::next(Instr->getIterator()), ValueToValueMaps[i], - DT); + DTU); assert(SplitBlock && "Unexpected new basic block split."); Instruction *NewCI = @@ -363,11 +365,13 @@ static void splitCallSite( // attempting removal. SmallVector<BasicBlock *, 2> Splits(predecessors((TailBB))); assert(Splits.size() == 2 && "Expected exactly 2 splits!"); - for (unsigned i = 0; i < Splits.size(); i++) + for (unsigned i = 0; i < Splits.size(); i++) { Splits[i]->getTerminator()->eraseFromParent(); + DTU.deleteEdge(Splits[i], TailBB); + } // Erase the tail block once done with musttail patching - TailBB->eraseFromParent(); + DTU.deleteBB(TailBB); return; } @@ -394,6 +398,7 @@ static void splitCallSite( if (isa<PHINode>(CurrentI)) continue; PHINode *NewPN = PHINode::Create(CurrentI->getType(), Preds.size()); + NewPN->setDebugLoc(CurrentI->getDebugLoc()); for (auto &Mapping : ValueToValueMaps) NewPN->addIncoming(Mapping[CurrentI], cast<Instruction>(Mapping[CurrentI])->getParent()); @@ -435,49 +440,73 @@ static bool isPredicatedOnPHI(CallSite CS) { return false; } -static bool tryToSplitOnPHIPredicatedArgument(CallSite CS, DominatorTree *DT) { +using PredsWithCondsTy = SmallVector<std::pair<BasicBlock *, ConditionsTy>, 2>; + +// Check if any of the arguments in CS are predicated on a PHI node and return +// the set of predecessors we should use for splitting. +static PredsWithCondsTy shouldSplitOnPHIPredicatedArgument(CallSite CS) { if (!isPredicatedOnPHI(CS)) - return false; + return {}; auto Preds = getTwoPredecessors(CS.getInstruction()->getParent()); - SmallVector<std::pair<BasicBlock *, ConditionsTy>, 2> PredsCS = { - {Preds[0], {}}, {Preds[1], {}}}; - splitCallSite(CS, PredsCS, DT); - return true; + return {{Preds[0], {}}, {Preds[1], {}}}; } -static bool tryToSplitOnPredicatedArgument(CallSite CS, DominatorTree *DT) { +// Checks if any of the arguments in CS are predicated in a predecessor and +// returns a list of predecessors with the conditions that hold on their edges +// to CS. +static PredsWithCondsTy shouldSplitOnPredicatedArgument(CallSite CS, + DomTreeUpdater &DTU) { auto Preds = getTwoPredecessors(CS.getInstruction()->getParent()); if (Preds[0] == Preds[1]) - return false; + return {}; + + // We can stop recording conditions once we reached the immediate dominator + // for the block containing the call site. Conditions in predecessors of the + // that node will be the same for all paths to the call site and splitting + // is not beneficial. + assert(DTU.hasDomTree() && "We need a DTU with a valid DT!"); + auto *CSDTNode = DTU.getDomTree().getNode(CS.getInstruction()->getParent()); + BasicBlock *StopAt = CSDTNode ? CSDTNode->getIDom()->getBlock() : nullptr; SmallVector<std::pair<BasicBlock *, ConditionsTy>, 2> PredsCS; for (auto *Pred : make_range(Preds.rbegin(), Preds.rend())) { ConditionsTy Conditions; - recordConditions(CS, Pred, Conditions); + // Record condition on edge BB(CS) <- Pred + recordCondition(CS, Pred, CS.getInstruction()->getParent(), Conditions); + // Record conditions following Pred's single predecessors. + recordConditions(CS, Pred, Conditions, StopAt); PredsCS.push_back({Pred, Conditions}); } - if (std::all_of(PredsCS.begin(), PredsCS.end(), - [](const std::pair<BasicBlock *, ConditionsTy> &P) { - return P.second.empty(); - })) - return false; + if (all_of(PredsCS, [](const std::pair<BasicBlock *, ConditionsTy> &P) { + return P.second.empty(); + })) + return {}; - splitCallSite(CS, PredsCS, DT); - return true; + return PredsCS; } static bool tryToSplitCallSite(CallSite CS, TargetTransformInfo &TTI, - DominatorTree *DT) { + DomTreeUpdater &DTU) { + // Check if we can split the call site. if (!CS.arg_size() || !canSplitCallSite(CS, TTI)) return false; - return tryToSplitOnPredicatedArgument(CS, DT) || - tryToSplitOnPHIPredicatedArgument(CS, DT); + + auto PredsWithConds = shouldSplitOnPredicatedArgument(CS, DTU); + if (PredsWithConds.empty()) + PredsWithConds = shouldSplitOnPHIPredicatedArgument(CS); + if (PredsWithConds.empty()) + return false; + + splitCallSite(CS, PredsWithConds, DTU); + return true; } static bool doCallSiteSplitting(Function &F, TargetLibraryInfo &TLI, - TargetTransformInfo &TTI, DominatorTree *DT) { + TargetTransformInfo &TTI, DominatorTree &DT) { + + DomTreeUpdater DTU(&DT, DomTreeUpdater::UpdateStrategy::Lazy); bool Changed = false; for (Function::iterator BI = F.begin(), BE = F.end(); BI != BE;) { BasicBlock &BB = *BI++; @@ -501,7 +530,7 @@ static bool doCallSiteSplitting(Function &F, TargetLibraryInfo &TLI, // Check if such path is possible before attempting the splitting. bool IsMustTail = CS.isMustTailCall(); - Changed |= tryToSplitCallSite(CS, TTI, DT); + Changed |= tryToSplitCallSite(CS, TTI, DTU); // There're no interesting instructions after this. The call site // itself might have been erased on splitting. @@ -522,6 +551,7 @@ struct CallSiteSplittingLegacyPass : public FunctionPass { void getAnalysisUsage(AnalysisUsage &AU) const override { AU.addRequired<TargetLibraryInfoWrapperPass>(); AU.addRequired<TargetTransformInfoWrapperPass>(); + AU.addRequired<DominatorTreeWrapperPass>(); AU.addPreserved<DominatorTreeWrapperPass>(); FunctionPass::getAnalysisUsage(AU); } @@ -532,9 +562,8 @@ struct CallSiteSplittingLegacyPass : public FunctionPass { auto &TLI = getAnalysis<TargetLibraryInfoWrapperPass>().getTLI(); auto &TTI = getAnalysis<TargetTransformInfoWrapperPass>().getTTI(F); - auto *DTWP = getAnalysisIfAvailable<DominatorTreeWrapperPass>(); - return doCallSiteSplitting(F, TLI, TTI, - DTWP ? &DTWP->getDomTree() : nullptr); + auto &DT = getAnalysis<DominatorTreeWrapperPass>().getDomTree(); + return doCallSiteSplitting(F, TLI, TTI, DT); } }; } // namespace @@ -544,6 +573,7 @@ INITIALIZE_PASS_BEGIN(CallSiteSplittingLegacyPass, "callsite-splitting", "Call-site splitting", false, false) INITIALIZE_PASS_DEPENDENCY(TargetLibraryInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(TargetTransformInfoWrapperPass) +INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass) INITIALIZE_PASS_END(CallSiteSplittingLegacyPass, "callsite-splitting", "Call-site splitting", false, false) FunctionPass *llvm::createCallSiteSplittingPass() { @@ -554,7 +584,7 @@ PreservedAnalyses CallSiteSplittingPass::run(Function &F, FunctionAnalysisManager &AM) { auto &TLI = AM.getResult<TargetLibraryAnalysis>(F); auto &TTI = AM.getResult<TargetIRAnalysis>(F); - auto *DT = AM.getCachedResult<DominatorTreeAnalysis>(F); + auto &DT = AM.getResult<DominatorTreeAnalysis>(F); if (!doCallSiteSplitting(F, TLI, TTI, DT)) return PreservedAnalyses::all(); |
