Skip to content

Commit c949261

Browse files
authored
Merge pull request #27088 from eeckstein/inline-generic-coroutines
PerformanceInliner: enable generic inlining of co-routines
2 parents bb1ae9c + d07593b commit c949261

File tree

3 files changed

+53
-16
lines changed

3 files changed

+53
-16
lines changed

lib/SILOptimizer/Transforms/PerformanceInliner.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,6 @@ bool SILPerformanceInliner::isProfitableToInline(
262262
assert(Callee);
263263
bool IsGeneric = AI.hasSubstitutions();
264264

265-
assert(EnableSILInliningOfGenerics || !IsGeneric);
266-
267265
// Start with a base benefit.
268266
int BaseBenefit = RemovedCallBenefit;
269267

@@ -555,17 +553,26 @@ static Optional<bool> shouldInlineGeneric(FullApplySite AI) {
555553
if (Callee->getInlineStrategy() == AlwaysInline || Callee->isTransparent())
556554
return true;
557555

558-
// All other generic functions should not be inlined if this kind of inlining
559-
// is disabled.
560-
if (!EnableSILInliningOfGenerics)
561-
return false;
562-
563556
// If all substitutions are concrete, then there is no need to perform the
564557
// generic inlining. Let the generic specializer create a specialized
565558
// function and then decide if it is beneficial to inline it.
566559
if (!AI.getSubstitutionMap().hasArchetypes())
567560
return false;
568561

562+
if (Callee->getLoweredFunctionType()->getCoroutineKind() !=
563+
SILCoroutineKind::None) {
564+
// Co-routines are so expensive (e.g. Array.subscript.read) that we always
565+
// enable inlining them in a generic context. Though the final inlining
566+
// decision is done by the usual heuristics. Therefore we return None and
567+
// not true.
568+
return None;
569+
}
570+
571+
// All other generic functions should not be inlined if this kind of inlining
572+
// is disabled.
573+
if (!EnableSILInliningOfGenerics)
574+
return false;
575+
569576
// It is not clear yet if this function should be decided or not.
570577
return None;
571578
}

lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -767,20 +767,16 @@ SILFunction *swift::getEligibleFunction(FullApplySite AI,
767767
return nullptr;
768768
}
769769

770-
if (!EnableSILInliningOfGenerics && AI.hasSubstitutions()) {
771-
// Inlining of generics is not allowed unless it is an @inline(__always)
772-
// or transparent function.
773-
if (Callee->getInlineStrategy() != AlwaysInline && !Callee->isTransparent())
774-
return nullptr;
775-
}
776-
777770
// We cannot inline function with layout constraints on its generic types
778771
// if the corresponding substitution type does not have the same constraints.
779772
// The reason for this restriction is that we'd need to be able to express
780773
// in SIL something like casting a value of generic type T into a value of
781774
// generic type T: _LayoutConstraint, which is impossible currently.
782-
if (EnableSILInliningOfGenerics && AI.hasSubstitutions()) {
783-
if (!isCallerAndCalleeLayoutConstraintsCompatible(AI))
775+
if (AI.hasSubstitutions()) {
776+
if (!isCallerAndCalleeLayoutConstraintsCompatible(AI) &&
777+
// TODO: revisit why we can make an exception for inline-always
778+
// functions. Some tests depend on it.
779+
Callee->getInlineStrategy() != AlwaysInline && !Callee->isTransparent())
784780
return nullptr;
785781
}
786782

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: %target-swift-frontend -parse-as-library -O -emit-sil %s | %FileCheck %s
2+
// REQUIRES: swift_stdlib_no_asserts,optimized_stdlib
3+
4+
@inline(never)
5+
func useit<T>(_ t: T) {
6+
print(t)
7+
}
8+
9+
// Check that we inline the Array.subscript.read coroutine
10+
11+
// CHECK-LABEL: sil @{{.*}}testit
12+
// CHECK-NOT: begin_apply
13+
// CHECK-NOT: end_apply
14+
// CHECK: } // end sil function {{.*}}testit
15+
public func testit<T>(_ a: [T]) {
16+
for t in a {
17+
useit(t)
18+
}
19+
}
20+
21+
// Check that we inline the ManagedBufferPointer.header.read coroutine
22+
23+
public final class MyBuffer<Element> {
24+
typealias Manager = ManagedBufferPointer<Int, Element>
25+
26+
// CHECK-LABEL: sil @{{.*}}MyBuffer{{.*}}countSivg
27+
// CHECK-NOT: begin_apply
28+
// CHECK-NOT: end_apply
29+
// CHECK: } // end sil function {{.*}}MyBuffer{{.*}}countSivg
30+
public var count: Int {
31+
return Manager(unsafeBufferObject: self).header
32+
}
33+
}
34+

0 commit comments

Comments
 (0)