summaryrefslogtreecommitdiff
path: root/lib/Transforms/Scalar/CallSiteSplitting.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Transforms/Scalar/CallSiteSplitting.cpp')
-rw-r--r--lib/Transforms/Scalar/CallSiteSplitting.cpp102
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();