@@ -49,6 +49,10 @@ llvm::cl::opt<unsigned> SILNumOptPassesToRun(
49
49
" sil-opt-pass-count" , llvm::cl::init(UINT_MAX),
50
50
llvm::cl::desc(" Stop optimizing after <N> optimization passes" ));
51
51
52
+ llvm::cl::opt<unsigned > SILFunctionPassPipelineLimit (" sil-pipeline-limit" ,
53
+ llvm::cl::init (10 ),
54
+ llvm::cl::desc(" " ));
55
+
52
56
llvm::cl::opt<std::string> SILBreakOnFun (
53
57
" sil-break-on-function" , llvm::cl::init(" " ),
54
58
llvm::cl::desc(
@@ -270,92 +274,110 @@ static bool breakBeforeRunning(StringRef fnName, StringRef passName) {
270
274
return fnName == SILBreakOnFun && passName == SILBreakOnPass;
271
275
}
272
276
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];
275
284
276
285
assert (analysesUnlocked () && " Expected all analyses to be unlocked!" );
277
286
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
+ }
280
304
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
+ }
283
312
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 ;
295
314
296
- if (isDisabled (SFT)) {
297
315
if (SILPrintPassName)
298
- llvm::dbgs () << " (Disabled) Stage: " << StageName
316
+ llvm::dbgs () << " # " << NumPassesRun << " Stage: " << StageName
299
317
<< " Pass: " << SFT->getName ()
300
318
<< " , Function: " << F->getName () << " \n " ;
301
- return ;
302
- }
303
319
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
+ }
305
326
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
+ }
310
345
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
+ }
317
353
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 ());
325
357
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
+ }
332
363
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 ;
340
368
341
- // Remember if this pass didn't change anything.
342
- if (!CurrentPassHasInvalidated)
343
- completedPasses.set ((size_t )SFT->getPassKind ());
369
+ if (runToCompletion)
370
+ continue ;
344
371
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 ;
349
377
}
350
-
351
- ++NumPassesRun;
352
378
}
353
379
354
380
void SILPassManager::runFunctionPasses (PassList FuncTransforms) {
355
-
356
- if (FuncTransforms.empty ())
357
- return ;
358
-
359
381
BasicCalleeAnalysis *BCA = getAnalysis<BasicCalleeAnalysis>();
360
382
BottomUpFunctionOrder BottomUpOrder (*Mod, BCA);
361
383
auto BottomUpFunctions = BottomUpOrder.getFunctions ();
@@ -373,41 +395,82 @@ void SILPassManager::runFunctionPasses(PassList FuncTransforms) {
373
395
FunctionWorklist.push_back (*I);
374
396
}
375
397
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
379
407
// happening.
380
- const unsigned MaxNumRestarts = 20 ;
408
+ unsigned IterationsWithoutProgress = 0 ;
381
409
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 ;
384
413
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.
386
416
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 ();
390
418
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.
393
424
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
+
394
433
continue ;
395
434
}
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 () &&
397
446
" Did not expect function pipeline set up to restart from beginning!" );
398
447
399
- runPassOnFunction (FuncTransforms[PipelineIdx], F);
448
+ assert (CountOptimized[F] <= SILFunctionPassPipelineLimit &&
449
+ " Function optimization count exceeds limit!" );
450
+ auto runToCompletion = CountOptimized[F] == SILFunctionPassPipelineLimit;
400
451
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 ;
410
461
}
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
+
411
474
clearRestartPipeline ();
412
475
}
413
476
}
0 commit comments