@@ -264,8 +264,12 @@ void addHighLevelLoopOptPasses(SILPassPipelinePlan &P) {
264
264
P.addSwiftArrayPropertyOpt ();
265
265
}
266
266
267
- // Perform classic SSA optimizations.
268
- void addSSAPasses (SILPassPipelinePlan &P, OptimizationLevelKind OpLevel) {
267
+ // Primary FunctionPass pipeline.
268
+ //
269
+ // Inserting a module passes within this pipeline would break the pipeline
270
+ // restart functionality.
271
+ void addFunctionPasses (SILPassPipelinePlan &P,
272
+ OptimizationLevelKind OpLevel) {
269
273
// Promote box allocations to stack allocations.
270
274
P.addAllocBoxToStack ();
271
275
@@ -289,12 +293,29 @@ void addSSAPasses(SILPassPipelinePlan &P, OptimizationLevelKind OpLevel) {
289
293
290
294
// Cleanup, which is important if the inliner has restarted the pass pipeline.
291
295
P.addPerformanceConstantPropagation ();
292
- P.addSimplifyCFG ();
293
- P.addSILCombine ();
294
296
295
- // Mainly for Array.append(contentsOf) optimization.
297
+ addSimplifyCFGSILCombinePasses (P);
298
+
296
299
P.addArrayElementPropagation ();
297
300
301
+ // Perform a round of loop/array optimization in the mid-level pipeline after
302
+ // potentially inlining semantic calls, e.g. Array append. The high level
303
+ // pipeline only optimizes semantic calls *after* inlining (see
304
+ // addHighLevelLoopOptPasses). For example, the high-level pipeline may
305
+ // perform ArrayElementPropagation and after inlining a level of semantic
306
+ // calls, the mid-level pipeline may handle uniqueness hoisting. Do this as
307
+ // late as possible before inlining because it must run between runs of the
308
+ // inliner when the pipeline restarts.
309
+ if (OpLevel == OptimizationLevelKind::MidLevel) {
310
+ P.addHighLevelLICM ();
311
+ P.addArrayCountPropagation ();
312
+ P.addABCOpt ();
313
+ P.addDCE ();
314
+ P.addCOWArrayOpts ();
315
+ P.addDCE ();
316
+ P.addSwiftArrayPropertyOpt ();
317
+ }
318
+
298
319
// Run the devirtualizer, specializer, and inliner. If any of these
299
320
// makes a change we'll end up restarting the function passes on the
300
321
// current function (after optimizing any new callees).
@@ -310,22 +331,6 @@ void addSSAPasses(SILPassPipelinePlan &P, OptimizationLevelKind OpLevel) {
310
331
P.addEarlyInliner ();
311
332
break ;
312
333
case OptimizationLevelKind::MidLevel:
313
- P.addGlobalOpt ();
314
- P.addLetPropertiesOpt ();
315
- // It is important to serialize before any of the @_semantics
316
- // functions are inlined, because otherwise the information about
317
- // uses of such functions inside the module is lost,
318
- // which reduces the ability of the compiler to optimize clients
319
- // importing this module.
320
- P.addSerializeSILPass ();
321
-
322
- // Now strip any transparent functions that still have ownership.
323
- if (P.getOptions ().StripOwnershipAfterSerialization )
324
- P.addOwnershipModelEliminator ();
325
-
326
- if (P.getOptions ().StopOptimizationAfterSerialization )
327
- return ;
328
-
329
334
// Does inline semantics-functions (except "availability"), but not
330
335
// global-init functions.
331
336
P.addPerfInliner ();
@@ -446,30 +451,58 @@ static void addPerfEarlyModulePassPipeline(SILPassPipelinePlan &P) {
446
451
P.addCMOSerializeSILPass ();
447
452
}
448
453
449
- static void addHighLevelEarlyLoopOptPipeline (SILPassPipelinePlan &P) {
450
- P.startPipeline (" HighLevel+EarlyLoopOpt" );
451
- // FIXME: update this to be a function pass.
454
+ // The "high-level" pipeline serves two purposes:
455
+ //
456
+ // 1. Optimize the standard library Swift module prior to serialization. This
457
+ // reduces the amount of work during compilation of all non-stdlib clients.
458
+ //
459
+ // 2. Optimize caller functions before inlining semantic calls inside
460
+ // callees. This provides more precise escape analysis and side effect analysis
461
+ // of callee arguments.
462
+ static void addHighLevelFunctionPipeline (SILPassPipelinePlan &P) {
463
+ P.startPipeline (" HighLevel,Function+EarlyLoopOpt" );
464
+ // FIXME: update EagerSpecializer to be a function pass!
452
465
P.addEagerSpecializer ();
453
- addSSAPasses (P, OptimizationLevelKind::HighLevel);
466
+ addFunctionPasses (P, OptimizationLevelKind::HighLevel);
467
+
454
468
addHighLevelLoopOptPasses (P);
455
469
}
456
470
457
- static void addMidModulePassesStackPromotePassPipeline (SILPassPipelinePlan &P) {
458
- P.startPipeline (" MidModulePasses+StackPromote" );
471
+ // After "high-level" function passes have processed the entire call tree, run
472
+ // one round of module passes.
473
+ static void addHighLevelModulePipeline (SILPassPipelinePlan &P) {
474
+ P.startPipeline (" HighLevel,Module+StackPromote" );
459
475
P.addDeadFunctionElimination ();
460
476
P.addPerformanceSILLinker ();
461
477
P.addDeadObjectElimination ();
462
478
P.addGlobalPropertyOpt ();
463
479
464
- // Do the first stack promotion on high-level SIL.
480
+ // Do the first stack promotion on high-level SIL before serialization.
481
+ //
482
+ // FIXME: why does StackPromotion need to run in the module pipeline?
465
483
P.addStackPromotion ();
484
+
485
+ P.addGlobalOpt ();
486
+ P.addLetPropertiesOpt ();
487
+ }
488
+
489
+ static void addSerializePipeline (SILPassPipelinePlan &P) {
490
+ P.startPipeline (" Serialize" );
491
+ // It is important to serialize before any of the @_semantics
492
+ // functions are inlined, because otherwise the information about
493
+ // uses of such functions inside the module is lost,
494
+ // which reduces the ability of the compiler to optimize clients
495
+ // importing this module.
496
+ P.addSerializeSILPass ();
497
+
498
+ // Strip any transparent functions that still have ownership.
499
+ if (P.getOptions ().StripOwnershipAfterSerialization )
500
+ P.addOwnershipModelEliminator ();
466
501
}
467
502
468
- static bool addMidLevelPassPipeline (SILPassPipelinePlan &P) {
469
- P.startPipeline (" MidLevel" );
470
- addSSAPasses (P, OptimizationLevelKind::MidLevel);
471
- if (P.getOptions ().StopOptimizationAfterSerialization )
472
- return true ;
503
+ static void addMidLevelFunctionPipeline (SILPassPipelinePlan &P) {
504
+ P.startPipeline (" MidLevel,Function" , true /* isFunctionPassPipeline*/ );
505
+ addFunctionPasses (P, OptimizationLevelKind::MidLevel);
473
506
474
507
// Specialize partially applied functions with dead arguments as a preparation
475
508
// for CapturePropagation.
@@ -481,7 +514,6 @@ static bool addMidLevelPassPipeline(SILPassPipelinePlan &P) {
481
514
// Run loop unrolling after inlining and constant propagation, because loop
482
515
// trip counts may have became constant.
483
516
P.addLoopUnroll ();
484
- return false ;
485
517
}
486
518
487
519
static void addClosureSpecializePassPipeline (SILPassPipelinePlan &P) {
@@ -532,12 +564,12 @@ static void addClosureSpecializePassPipeline(SILPassPipelinePlan &P) {
532
564
}
533
565
534
566
static void addLowLevelPassPipeline (SILPassPipelinePlan &P) {
535
- P.startPipeline (" LowLevel" );
567
+ P.startPipeline (" LowLevel,Function " , true /* isFunctionPassPipeline */ );
536
568
537
569
// Should be after FunctionSignatureOpts and before the last inliner.
538
570
P.addReleaseDevirtualizer ();
539
571
540
- addSSAPasses (P, OptimizationLevelKind::LowLevel);
572
+ addFunctionPasses (P, OptimizationLevelKind::LowLevel);
541
573
542
574
P.addDeadObjectElimination ();
543
575
P.addObjectOutliner ();
@@ -652,13 +684,21 @@ SILPassPipelinePlan::getPerformancePassPipeline(const SILOptions &Options) {
652
684
addPerfEarlyModulePassPipeline (P);
653
685
654
686
// Then run an iteration of the high-level SSA passes.
655
- addHighLevelEarlyLoopOptPipeline (P);
656
- addMidModulePassesStackPromotePassPipeline (P);
687
+ //
688
+ // FIXME: When *not* emitting a .swiftmodule, skip the high-level function
689
+ // pipeline to save compile time.
690
+ addHighLevelFunctionPipeline (P);
691
+
692
+ addHighLevelModulePipeline (P);
657
693
658
- // Run an iteration of the mid-level SSA passes.
659
- if (addMidLevelPassPipeline (P) )
694
+ addSerializePipeline (P);
695
+ if (Options. StopOptimizationAfterSerialization )
660
696
return P;
661
697
698
+ // After serialization run the function pass pipeline to iteratively lower
699
+ // high-level constructs like @_semantics calls.
700
+ addMidLevelFunctionPipeline (P);
701
+
662
702
// Perform optimizations that specialize.
663
703
addClosureSpecializePassPipeline (P);
664
704
@@ -698,7 +738,7 @@ SILPassPipelinePlan::getOnonePassPipeline(const SILOptions &Options) {
698
738
P.startPipeline (" Serialization" );
699
739
P.addSerializeSILPass ();
700
740
701
- // And then strip ownership.. .
741
+ // Now strip any transparent functions that still have ownership.
702
742
if (Options.StripOwnershipAfterSerialization )
703
743
P.addOwnershipModelEliminator ();
704
744
0 commit comments