Skip to content

Commit 76af58b

Browse files
committed
Update PassManager's function worklist for newly added SILFunctions
The PassManager should transform all functions in bottom up order. This is necessary because when optimizations like inlining looks at the callee function bodies to compute profitability, the callee functions should have already undergone optimizations to get better profitability estimates. The PassManager builds its function worklist based on bottom up order on initialization. However, newly created SILFunctions due to specialization etc, are simply appended to the function worklist. This can cause us to make bad inlining decisions due to inaccurate profitability estimates. This change now updates the function worklist such that, all the callees of the newly added SILFunction are proccessed before it by the PassManager. Fixes rdar://52202680
1 parent 4c7bc26 commit 76af58b

File tree

2 files changed

+57
-0
lines changed

2 files changed

+57
-0
lines changed

include/swift/SILOptimizer/PassManager/PassManager.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,13 @@ class SILPassManager {
274274
/// Add a pass with a given name.
275275
void addPassForName(StringRef Name);
276276

277+
/// The PassManager's function worklist is updated such that all the callees
278+
/// in function 'F' are present after function 'F'.
279+
void updateFunctionWorklist(SILFunction *F);
280+
281+
void recursivelyUpdateFunctionWorklist(
282+
SILFunction *F, llvm::SmallPtrSetImpl<SILFunction *> &visited);
283+
277284
/// Run the \p TransIdx'th SIL module transform over all the functions in
278285
/// the module.
279286
void runModulePass(unsigned TransIdx);

lib/SILOptimizer/PassManager/PassManager.cpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,56 @@ void SILPassManager::addFunctionToWorklist(SILFunction *F,
729729

730730
StoredLevel = NewLevel;
731731
FunctionWorklist.push_back(F);
732+
// Update FunctionWorklist such that all the callees in function 'F' are
733+
// present after it.
734+
updateFunctionWorklist(F);
735+
}
736+
737+
void SILPassManager::updateFunctionWorklist(SILFunction *F) {
738+
llvm::SmallPtrSet<SILFunction*, 16> Visited;
739+
recursivelyUpdateFunctionWorklist(F, Visited);
740+
}
741+
742+
// Recursively update PassManager's FunctionWorklist such that all the callees
743+
// in function 'F' are present after it.
744+
void SILPassManager::recursivelyUpdateFunctionWorklist(
745+
SILFunction *F, SmallPtrSetImpl<SILFunction *> &Visited) {
746+
BasicCalleeAnalysis *BCA = getAnalysis<BasicCalleeAnalysis>();
747+
auto findFunc = [this](SILFunction *Func) {
748+
return std::find_if(FunctionWorklist.begin(), FunctionWorklist.end(),
749+
[Func](WorklistEntry w) { return w.F == Func; });
750+
};
751+
auto FuncIt = findFunc(F);
752+
if (FuncIt == FunctionWorklist.end()) {
753+
return;
754+
}
755+
auto FuncIndex = std::distance(FunctionWorklist.begin(), FuncIt);
756+
if (Visited.find(F) != Visited.end()) {
757+
return;
758+
}
759+
Visited.insert(F);
760+
for (auto &B : *F) {
761+
for (auto &I : B) {
762+
auto FAS = FullApplySite::isa(&I);
763+
if (!FAS && !isa<StrongReleaseInst>(&I) && !isa<ReleaseValueInst>(&I))
764+
continue;
765+
auto Callees = FAS ? BCA->getCalleeList(FAS) : BCA->getCalleeList(&I);
766+
for (auto *CalleeFn : Callees) {
767+
if (CalleeFn != F) {
768+
auto CalleeIt = findFunc(CalleeFn);
769+
if (CalleeIt != FunctionWorklist.end()) {
770+
assert(CalleeIt->F == CalleeFn);
771+
auto CalleeIndex = std::distance(FunctionWorklist.begin(), CalleeIt);
772+
if (CalleeIndex < FuncIndex) {
773+
FunctionWorklist.erase(CalleeIt);
774+
FunctionWorklist.insert(std::next(findFunc(F)), CalleeFn);
775+
recursivelyUpdateFunctionWorklist(CalleeFn, Visited);
776+
}
777+
}
778+
}
779+
}
780+
}
781+
}
732782
}
733783

734784
void SILPassManager::restartWithCurrentFunction(SILTransform *T) {

0 commit comments

Comments
 (0)