14
14
#include " swift/SILOptimizer/PassManager/Passes.h"
15
15
#include " swift/SILOptimizer/PassManager/Transforms.h"
16
16
#include " swift/SILOptimizer/Utils/PerformanceInlinerUtils.h"
17
+ #include " swift/Strings.h"
17
18
#include " llvm/ADT/Statistic.h"
18
19
#include " llvm/Support/Debug.h"
19
20
#include " llvm/Support/CommandLine.h"
@@ -26,6 +27,10 @@ llvm::cl::opt<bool> PrintShortestPathInfo(
26
27
" print-shortest-path-info" , llvm::cl::init(false ),
27
28
llvm::cl::desc(" Print shortest-path information for inlining" ));
28
29
30
+ llvm::cl::opt<bool > EnableSILInliningOfGenerics (
31
+ " sil-inline-generics" , llvm::cl::init(false ),
32
+ llvm::cl::desc(" Enable inlining of generics" ));
33
+
29
34
// ===----------------------------------------------------------------------===//
30
35
// Performance Inliner
31
36
// ===----------------------------------------------------------------------===//
@@ -117,12 +122,18 @@ class SILPerformanceInliner {
117
122
118
123
SILFunction *getEligibleFunction (FullApplySite AI);
119
124
120
- bool isProfitableToInlineNonGeneric (FullApplySite AI,
125
+ bool isProfitableToInline (FullApplySite AI,
121
126
Weight CallerWeight,
122
- ConstantTracker &constTracker,
123
- int &NumCallerBlocks);
127
+ ConstantTracker &callerTracker,
128
+ int &NumCallerBlocks,
129
+ bool IsGeneric);
130
+
131
+ bool decideInWarmBlock (FullApplySite AI,
132
+ Weight CallerWeight,
133
+ ConstantTracker &callerTracker,
134
+ int &NumCallerBlocks);
124
135
125
- bool isProfitableInColdBlock (FullApplySite AI, SILFunction *Callee);
136
+ bool decideInColdBlock (FullApplySite AI, SILFunction *Callee);
126
137
127
138
void visitColdBlocks (SmallVectorImpl<FullApplySite> &AppliesToInline,
128
139
SILBasicBlock *root, DominanceInfo *DT);
@@ -239,19 +250,12 @@ SILFunction *SILPerformanceInliner::getEligibleFunction(FullApplySite AI) {
239
250
return Callee;
240
251
}
241
252
242
- // / Return true if inlining this call site is profitable.
243
- bool SILPerformanceInliner::isProfitableToInlineNonGeneric (FullApplySite AI,
244
- Weight CallerWeight,
245
- ConstantTracker &callerTracker,
246
- int &NumCallerBlocks) {
247
- assert (AI.getSubstitutions ().empty () &&
248
- " Expected a non-generic apply" );
249
-
253
+ bool SILPerformanceInliner::isProfitableToInline (FullApplySite AI,
254
+ Weight CallerWeight,
255
+ ConstantTracker &callerTracker,
256
+ int &NumCallerBlocks,
257
+ bool IsGeneric) {
250
258
SILFunction *Callee = AI.getReferencedFunction ();
251
-
252
- if (Callee->getInlineStrategy () == AlwaysInline)
253
- return true ;
254
-
255
259
SILLoopInfo *LI = LA->get (Callee);
256
260
ShortestPathAnalysis *SPA = getSPA (Callee, LI);
257
261
assert (SPA->isValid ());
@@ -369,9 +373,80 @@ bool SILPerformanceInliner::isProfitableToInlineNonGeneric(FullApplySite AI,
369
373
return true ;
370
374
}
371
375
376
+ // / Checks if a given generic apply should be inlined unconditionally, i.e.
377
+ // / without any complex analysis using e.g. a cost model.
378
+ // / It returns true if a function should be inlined.
379
+ // / It returns false if a function should not be inlined.
380
+ // / It returns None if the decision cannot be made without a more complex
381
+ // / analysis.
382
+ static Optional<bool > shouldInlineGeneric (FullApplySite AI) {
383
+ assert (!AI.getSubstitutions ().empty () &&
384
+ " Expected a generic apply" );
385
+
386
+ if (!EnableSILInliningOfGenerics)
387
+ return false ;
388
+
389
+ // If all substitutions are concrete, then there is no need to perform the
390
+ // generic inlining. Let the generic specializer create a specialized
391
+ // function and then decide if it is beneficial to inline it.
392
+ if (!hasUnboundGenericTypes (AI.getSubstitutions ()))
393
+ return false ;
394
+
395
+ SILFunction *Callee = AI.getReferencedFunction ();
396
+
397
+ // Do not inline @_semantics functions when compiling the stdlib,
398
+ // because they need to be preserved, so that the optimizer
399
+ // can properly optimize a user code later.
400
+ auto ModuleName = Callee->getModule ().getSwiftModule ()->getName ().str ();
401
+ if (Callee->hasSemanticsAttrThatStartsWith (" array." ) &&
402
+ (ModuleName == STDLIB_NAME || ModuleName == SWIFT_ONONE_SUPPORT))
403
+ return false ;
404
+
405
+ // Always inline generic functions which are marked as
406
+ // AlwaysInline or transparent.
407
+ if (Callee->getInlineStrategy () == AlwaysInline || Callee->isTransparent ())
408
+ return true ;
409
+
410
+ // Only inline if we decided to inline or we are asked to inline all
411
+ // generic functions.
412
+ return None;
413
+ }
414
+
415
+ bool SILPerformanceInliner::
416
+ decideInWarmBlock (FullApplySite AI,
417
+ Weight CallerWeight,
418
+ ConstantTracker &callerTracker,
419
+ int &NumCallerBlocks) {
420
+ if (!AI.getSubstitutions ().empty ()) {
421
+ // Only inline generics if definitively clear that it should be done.
422
+ auto ShouldInlineGeneric = shouldInlineGeneric (AI);
423
+ if (ShouldInlineGeneric.hasValue ())
424
+ return ShouldInlineGeneric.getValue ();
425
+
426
+ return false ;
427
+ }
428
+
429
+ SILFunction *Callee = AI.getReferencedFunction ();
430
+
431
+ if (Callee->getInlineStrategy () == AlwaysInline)
432
+ return true ;
433
+
434
+ return isProfitableToInline (AI, CallerWeight, callerTracker, NumCallerBlocks,
435
+ /* IsGeneric */ false );
436
+ }
437
+
372
438
// / Return true if inlining this call site into a cold block is profitable.
373
- bool SILPerformanceInliner::isProfitableInColdBlock (FullApplySite AI,
374
- SILFunction *Callee) {
439
+ bool SILPerformanceInliner::decideInColdBlock (FullApplySite AI,
440
+ SILFunction *Callee) {
441
+ if (!AI.getSubstitutions ().empty ()) {
442
+ // Only inline generics if definitively clear that it should be done.
443
+ auto ShouldInlineGeneric = shouldInlineGeneric (AI);
444
+ if (ShouldInlineGeneric.hasValue ())
445
+ return ShouldInlineGeneric.getValue ();
446
+
447
+ return false ;
448
+ }
449
+
375
450
if (Callee->getInlineStrategy () == AlwaysInline)
376
451
return true ;
377
452
@@ -482,9 +557,7 @@ void SILPerformanceInliner::collectAppliesToInline(
482
557
// The actual weight including a possible weight correction.
483
558
Weight W (BlockWeight, WeightCorrections.lookup (AI));
484
559
485
- bool IsProfitableToInline = isProfitableToInlineNonGeneric (
486
- AI, W, constTracker, NumCallerBlocks);
487
- if (IsProfitableToInline)
560
+ if (decideInWarmBlock (AI, W, constTracker, NumCallerBlocks))
488
561
InitialCandidates.push_back (AI);
489
562
}
490
563
}
@@ -591,7 +664,7 @@ void SILPerformanceInliner::visitColdBlocks(
591
664
continue ;
592
665
593
666
auto *Callee = getEligibleFunction (AI);
594
- if (Callee && isProfitableInColdBlock (AI, Callee)) {
667
+ if (Callee && decideInColdBlock (AI, Callee)) {
595
668
AppliesToInline.push_back (AI);
596
669
}
597
670
}
0 commit comments