Skip to content

Commit d566d77

Browse files
authored
Merge pull request #4384 from apple/revert-4358-pass-manager
Revert "SILPassManager: After a new function is pushed on the stack don't res…"
2 parents 7d015df + 19e0eb8 commit d566d77

File tree

4 files changed

+156
-112
lines changed

4 files changed

+156
-112
lines changed

include/swift/SILOptimizer/PassManager/PassManager.h

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -42,21 +42,8 @@ class SILPassManager {
4242
/// A list of registered analysis.
4343
llvm::SmallVector<SILAnalysis *, 16> Analysis;
4444

45-
/// An entry in the FunctionWorkList.
46-
struct WorklistEntry {
47-
WorklistEntry(SILFunction *F) : F(F) { }
48-
49-
SILFunction *F;
50-
51-
/// The current position in the transform-list.
52-
unsigned PipelineIdx = 0;
53-
54-
/// How many times the pipeline was restarted for the function.
55-
unsigned NumRestarts = 0;
56-
};
57-
5845
/// The worklist of functions to be processed by function passes.
59-
std::vector<WorklistEntry> FunctionWorklist;
46+
std::vector<SILFunction *> FunctionWorklist;
6047

6148
// Name of the current optimization stage for diagnostics.
6249
std::string StageName;
@@ -224,8 +211,9 @@ class SILPassManager {
224211
/// the module.
225212
void runModulePass(SILModuleTransform *SMT);
226213

227-
/// Run the pass \p SFT on the function \p F.
228-
void runPassOnFunction(SILFunctionTransform *SFT, SILFunction *F);
214+
/// Run the passes in \p FuncTransforms on the function \p F.
215+
void runPassesOnFunction(PassList FuncTransforms, SILFunction *F,
216+
bool runToCompletion);
229217

230218
/// Run the passes in \p FuncTransforms. Return true
231219
/// if the pass manager requested to stop the execution

lib/SILOptimizer/PassManager/PassManager.cpp

Lines changed: 151 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ llvm::cl::opt<unsigned> SILNumOptPassesToRun(
4949
"sil-opt-pass-count", llvm::cl::init(UINT_MAX),
5050
llvm::cl::desc("Stop optimizing after <N> optimization passes"));
5151

52+
llvm::cl::opt<unsigned> SILFunctionPassPipelineLimit("sil-pipeline-limit",
53+
llvm::cl::init(10),
54+
llvm::cl::desc(""));
55+
5256
llvm::cl::opt<std::string> SILBreakOnFun(
5357
"sil-break-on-function", llvm::cl::init(""),
5458
llvm::cl::desc(
@@ -270,92 +274,110 @@ static bool breakBeforeRunning(StringRef fnName, StringRef passName) {
270274
return fnName == SILBreakOnFun && passName == SILBreakOnPass;
271275
}
272276

273-
void SILPassManager::runPassOnFunction(SILFunctionTransform *SFT,
274-
SILFunction *F) {
277+
void SILPassManager::runPassesOnFunction(PassList FuncTransforms,
278+
SILFunction *F,
279+
bool runToCompletion) {
280+
281+
const SILOptions &Options = getOptions();
282+
283+
CompletedPasses &completedPasses = CompletedPassesMap[F];
275284

276285
assert(analysesUnlocked() && "Expected all analyses to be unlocked!");
277286

278-
PrettyStackTraceSILFunctionTransform X(SFT, NumPassesRun);
279-
DebugPrintEnabler DebugPrint(NumPassesRun);
287+
for (auto SFT : FuncTransforms) {
288+
PrettyStackTraceSILFunctionTransform X(SFT, NumPassesRun);
289+
DebugPrintEnabler DebugPrint(NumPassesRun);
290+
291+
SFT->injectPassManager(this);
292+
SFT->injectFunction(F);
293+
294+
// If nothing changed since the last run of this pass, we can skip this
295+
// pass.
296+
if (completedPasses.test((size_t)SFT->getPassKind()) &&
297+
!SILDisableSkippingPasses) {
298+
if (SILPrintPassName)
299+
llvm::dbgs() << "(Skip) Stage: " << StageName
300+
<< " Pass: " << SFT->getName()
301+
<< ", Function: " << F->getName() << "\n";
302+
continue;
303+
}
280304

281-
SFT->injectPassManager(this);
282-
SFT->injectFunction(F);
305+
if (isDisabled(SFT)) {
306+
if (SILPrintPassName)
307+
llvm::dbgs() << "(Disabled) Stage: " << StageName
308+
<< " Pass: " << SFT->getName()
309+
<< ", Function: " << F->getName() << "\n";
310+
continue;
311+
}
283312

284-
// If nothing changed since the last run of this pass, we can skip this
285-
// pass.
286-
CompletedPasses &completedPasses = CompletedPassesMap[F];
287-
if (completedPasses.test((size_t)SFT->getPassKind()) &&
288-
!SILDisableSkippingPasses) {
289-
if (SILPrintPassName)
290-
llvm::dbgs() << " (Skip) Stage: " << StageName
291-
<< " Pass: " << SFT->getName()
292-
<< ", Function: " << F->getName() << "\n";
293-
return;
294-
}
313+
CurrentPassHasInvalidated = false;
295314

296-
if (isDisabled(SFT)) {
297315
if (SILPrintPassName)
298-
llvm::dbgs() << " (Disabled) Stage: " << StageName
316+
llvm::dbgs() << "#" << NumPassesRun << " Stage: " << StageName
299317
<< " Pass: " << SFT->getName()
300318
<< ", Function: " << F->getName() << "\n";
301-
return;
302-
}
303319

304-
CurrentPassHasInvalidated = false;
320+
if (doPrintBefore(SFT, F)) {
321+
llvm::dbgs() << "*** SIL function before " << StageName << " "
322+
<< SFT->getName() << " (" << NumOptimizationIterations
323+
<< ") ***\n";
324+
F->dump(Options.EmitVerboseSIL);
325+
}
305326

306-
if (SILPrintPassName)
307-
llvm::dbgs() << " #" << NumPassesRun << " Stage: " << StageName
308-
<< " Pass: " << SFT->getName()
309-
<< ", Function: " << F->getName() << "\n";
327+
llvm::sys::TimeValue StartTime = llvm::sys::TimeValue::now();
328+
Mod->registerDeleteNotificationHandler(SFT);
329+
if (breakBeforeRunning(F->getName(), SFT->getName()))
330+
LLVM_BUILTIN_DEBUGTRAP;
331+
SFT->run();
332+
assert(analysesUnlocked() && "Expected all analyses to be unlocked!");
333+
Mod->removeDeleteNotificationHandler(SFT);
334+
335+
// Did running the transform result in new functions being added
336+
// to the top of our worklist?
337+
bool newFunctionsAdded = (F != FunctionWorklist.back());
338+
339+
if (SILPrintPassTime) {
340+
auto Delta =
341+
llvm::sys::TimeValue::now().nanoseconds() - StartTime.nanoseconds();
342+
llvm::dbgs() << Delta << " (" << SFT->getName() << "," << F->getName()
343+
<< ")\n";
344+
}
310345

311-
if (doPrintBefore(SFT, F)) {
312-
llvm::dbgs() << "*** SIL function before " << StageName << " "
313-
<< SFT->getName() << " (" << NumOptimizationIterations
314-
<< ") ***\n";
315-
F->dump(getOptions().EmitVerboseSIL);
316-
}
346+
// If this pass invalidated anything, print and verify.
347+
if (doPrintAfter(SFT, F, CurrentPassHasInvalidated && SILPrintAll)) {
348+
llvm::dbgs() << "*** SIL function after " << StageName << " "
349+
<< SFT->getName() << " (" << NumOptimizationIterations
350+
<< ") ***\n";
351+
F->dump(Options.EmitVerboseSIL);
352+
}
317353

318-
llvm::sys::TimeValue StartTime = llvm::sys::TimeValue::now();
319-
Mod->registerDeleteNotificationHandler(SFT);
320-
if (breakBeforeRunning(F->getName(), SFT->getName()))
321-
LLVM_BUILTIN_DEBUGTRAP;
322-
SFT->run();
323-
assert(analysesUnlocked() && "Expected all analyses to be unlocked!");
324-
Mod->removeDeleteNotificationHandler(SFT);
354+
// Remember if this pass didn't change anything.
355+
if (!CurrentPassHasInvalidated)
356+
completedPasses.set((size_t)SFT->getPassKind());
325357

326-
if (SILPrintPassTime) {
327-
auto Delta =
328-
llvm::sys::TimeValue::now().nanoseconds() - StartTime.nanoseconds();
329-
llvm::dbgs() << Delta << " (" << SFT->getName() << "," << F->getName()
330-
<< ")\n";
331-
}
358+
if (Options.VerifyAll &&
359+
(CurrentPassHasInvalidated || SILVerifyWithoutInvalidation)) {
360+
F->verify();
361+
verifyAnalyses(F);
362+
}
332363

333-
// If this pass invalidated anything, print and verify.
334-
if (doPrintAfter(SFT, F, CurrentPassHasInvalidated && SILPrintAll)) {
335-
llvm::dbgs() << "*** SIL function after " << StageName << " "
336-
<< SFT->getName() << " (" << NumOptimizationIterations
337-
<< ") ***\n";
338-
F->dump(getOptions().EmitVerboseSIL);
339-
}
364+
++NumPassesRun;
365+
366+
if (!continueTransforming())
367+
return;
340368

341-
// Remember if this pass didn't change anything.
342-
if (!CurrentPassHasInvalidated)
343-
completedPasses.set((size_t)SFT->getPassKind());
369+
if (runToCompletion)
370+
continue;
344371

345-
if (getOptions().VerifyAll &&
346-
(CurrentPassHasInvalidated || SILVerifyWithoutInvalidation)) {
347-
F->verify();
348-
verifyAnalyses(F);
372+
// If running the transform resulted in new functions on the top
373+
// of the worklist, we'll return so that we can begin processing
374+
// those new functions.
375+
if (shouldRestartPipeline() || newFunctionsAdded)
376+
return;
349377
}
350-
351-
++NumPassesRun;
352378
}
353379

354380
void SILPassManager::runFunctionPasses(PassList FuncTransforms) {
355-
356-
if (FuncTransforms.empty())
357-
return;
358-
359381
BasicCalleeAnalysis *BCA = getAnalysis<BasicCalleeAnalysis>();
360382
BottomUpFunctionOrder BottomUpOrder(*Mod, BCA);
361383
auto BottomUpFunctions = BottomUpOrder.getFunctions();
@@ -373,41 +395,82 @@ void SILPassManager::runFunctionPasses(PassList FuncTransforms) {
373395
FunctionWorklist.push_back(*I);
374396
}
375397

376-
// The maximum number of times the pass pipeline can be restarted for a
377-
// function. This is used to ensure we are not going into an infinite loop in
378-
// cases where (for example) we have recursive type-based specialization
398+
// Used to track how many times a given function has been
399+
// (partially) optimized by the function pass pipeline in this
400+
// invocation.
401+
llvm::DenseMap<SILFunction *, unsigned> CountOptimized;
402+
403+
// Count of how many iterations we've had since any function was
404+
// popped off the function worklist. This is used to ensure progress
405+
// and eliminate the chance of going into an infinite loop in cases
406+
// where (for example) we have recursive type-based specialization
379407
// happening.
380-
const unsigned MaxNumRestarts = 20;
408+
unsigned IterationsWithoutProgress = 0;
381409

382-
if (SILPrintPassName)
383-
llvm::dbgs() << "Start function passes at stage: " << StageName << "\n";
410+
// The maximum number of functions we'll optimize without popping
411+
// any off the worklist. This is expected to non-zero.
412+
const unsigned MaxIterationsWithoutProgress = 20;
384413

385-
// Run all transforms for all functions, starting at the tail of the worklist.
414+
// Pop functions off the worklist, and run all function transforms
415+
// on each of them.
386416
while (!FunctionWorklist.empty() && continueTransforming()) {
387-
unsigned TailIdx = FunctionWorklist.size() - 1;
388-
unsigned PipelineIdx = FunctionWorklist[TailIdx].PipelineIdx;
389-
SILFunction *F = FunctionWorklist[TailIdx].F;
417+
auto *F = FunctionWorklist.back();
390418

391-
if (PipelineIdx >= FuncTransforms.size()) {
392-
// All passes did already run for the function. Pop it off the worklist.
419+
// If we've done many iterations without progress, pop the current
420+
// function and any other function we've run any optimizations on
421+
// on from the stack and then continue.
422+
if (IterationsWithoutProgress == (MaxIterationsWithoutProgress - 1)) {
423+
// Pop the current (potentially not-yet-optimized) function off.
393424
FunctionWorklist.pop_back();
425+
IterationsWithoutProgress = 0;
426+
427+
// Pop any remaining functions that have been optimized (at
428+
// least through some portion of the pipeline).
429+
while (!FunctionWorklist.empty() &&
430+
CountOptimized[FunctionWorklist.back()] > 0)
431+
FunctionWorklist.pop_back();
432+
394433
continue;
395434
}
396-
assert(!shouldRestartPipeline() &&
435+
436+
if (CountOptimized[F] > SILFunctionPassPipelineLimit) {
437+
DEBUG(llvm::dbgs() << "*** Hit limit optimizing: " << F->getName()
438+
<< '\n');
439+
FunctionWorklist.pop_back();
440+
IterationsWithoutProgress = 0;
441+
continue;
442+
}
443+
444+
assert(
445+
!shouldRestartPipeline() &&
397446
"Did not expect function pipeline set up to restart from beginning!");
398447

399-
runPassOnFunction(FuncTransforms[PipelineIdx], F);
448+
assert(CountOptimized[F] <= SILFunctionPassPipelineLimit &&
449+
"Function optimization count exceeds limit!");
450+
auto runToCompletion = CountOptimized[F] == SILFunctionPassPipelineLimit;
400451

401-
// Note: Don't get entry reference prior to runPassOnFunction().
402-
// A pass can push a new function to the worklist which may cause a
403-
// reallocation of the buffer and that would invalidate the reference.
404-
WorklistEntry &Entry = FunctionWorklist[TailIdx];
405-
if (shouldRestartPipeline() && Entry.NumRestarts < MaxNumRestarts) {
406-
++Entry.NumRestarts;
407-
Entry.PipelineIdx = 0;
408-
} else {
409-
++Entry.PipelineIdx;
452+
runPassesOnFunction(FuncTransforms, F, runToCompletion);
453+
++CountOptimized[F];
454+
++IterationsWithoutProgress;
455+
456+
if (runToCompletion) {
457+
FunctionWorklist.pop_back();
458+
IterationsWithoutProgress = 0;
459+
clearRestartPipeline();
460+
continue;
410461
}
462+
463+
464+
// If running the function transforms did not result in new
465+
// functions being added to the top of the worklist, then we're
466+
// done with this function and can pop it off and continue.
467+
// Otherwise, we'll return to this function and reoptimize after
468+
// processing the new functions that were added.
469+
if (F == FunctionWorklist.back() && !shouldRestartPipeline()) {
470+
FunctionWorklist.pop_back();
471+
IterationsWithoutProgress = 0;
472+
}
473+
411474
clearRestartPipeline();
412475
}
413476
}

lib/SILOptimizer/Transforms/FunctionSignatureOpts.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -869,13 +869,6 @@ class FunctionSignatureOpts : public SILFunctionTransform {
869869
// Make sure the PM knows about this function. This will also help us
870870
// with self-recursion.
871871
notifyPassManagerOfFunction(FST.getOptimizedFunction());
872-
873-
// We have to restart the pipeline for this thunk in order to run the
874-
// inliner (and other opts) again. This is important if the new
875-
// specialized function (which is called from this thunk) is
876-
// function-signature-optimized again and also becomes an
877-
// always-inline-thunk.
878-
restartPassPipeline();
879872
}
880873
}
881874

test/SILOptimizer/inline_devirtualize_specialize.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-sil-opt -enable-sil-verify-all %s -devirtualizer -generic-specializer -inline -dce | %FileCheck %s
1+
// RUN: %target-sil-opt -enable-sil-verify-all %s -inline -devirtualizer -generic-specializer -dce | %FileCheck %s
22

33
sil_stage canonical
44

0 commit comments

Comments
 (0)