Skip to content

Commit 70578b8

Browse files
authored
Merge pull request #9794 from swiftix/inline-always-fixes
[sil-inliner] Respect the @inline(__always) and @_transparent even if inlining of generics is disabled
2 parents f4e2b53 + d940a35 commit 70578b8

File tree

5 files changed

+91
-19
lines changed

5 files changed

+91
-19
lines changed

lib/SILOptimizer/Transforms/PerformanceInliner.cpp

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -365,15 +365,6 @@ static Optional<bool> shouldInlineGeneric(FullApplySite AI) {
365365
assert(!AI.getSubstitutions().empty() &&
366366
"Expected a generic apply");
367367

368-
if (!EnableSILInliningOfGenerics)
369-
return false;
370-
371-
// If all substitutions are concrete, then there is no need to perform the
372-
// generic inlining. Let the generic specializer create a specialized
373-
// function and then decide if it is beneficial to inline it.
374-
if (!hasArchetypes(AI.getSubstitutions()))
375-
return false;
376-
377368
SILFunction *Callee = AI.getReferencedFunction();
378369

379370
// Do not inline @_semantics functions when compiling the stdlib,
@@ -393,6 +384,17 @@ static Optional<bool> shouldInlineGeneric(FullApplySite AI) {
393384
if (Callee->getInlineStrategy() == AlwaysInline || Callee->isTransparent())
394385
return true;
395386

387+
// All other generic functions should not be inlined if this kind of inlining
388+
// is disabled.
389+
if (!EnableSILInliningOfGenerics)
390+
return false;
391+
392+
// If all substitutions are concrete, then there is no need to perform the
393+
// generic inlining. Let the generic specializer create a specialized
394+
// function and then decide if it is beneficial to inline it.
395+
if (!hasArchetypes(AI.getSubstitutions()))
396+
return false;
397+
396398
// It is not clear yet if this function should be decided or not.
397399
return None;
398400
}
@@ -411,10 +413,10 @@ decideInWarmBlock(FullApplySite AI,
411413

412414
SILFunction *Callee = AI.getReferencedFunction();
413415

414-
if (Callee->getInlineStrategy() == AlwaysInline) {
416+
if (Callee->getInlineStrategy() == AlwaysInline || Callee->isTransparent()) {
415417
DEBUG(
416418
dumpCaller(AI.getFunction());
417-
llvm::dbgs() << " always-inline decision " <<Callee->getName() << '\n';
419+
llvm::dbgs() << " always-inline decision " << Callee->getName() << '\n';
418420
);
419421
return true;
420422
}
@@ -434,8 +436,13 @@ bool SILPerformanceInliner::decideInColdBlock(FullApplySite AI,
434436
return false;
435437
}
436438

437-
if (Callee->getInlineStrategy() == AlwaysInline)
439+
if (Callee->getInlineStrategy() == AlwaysInline || Callee->isTransparent()) {
440+
DEBUG(
441+
dumpCaller(AI.getFunction());
442+
llvm::dbgs() << " always-inline decision " << Callee->getName() << '\n';
443+
);
438444
return true;
445+
}
439446

440447
int CalleeCost = 0;
441448

lib/SILOptimizer/Utils/PerformanceInlinerUtils.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -678,8 +678,10 @@ SILFunction *swift::getEligibleFunction(FullApplySite AI,
678678
}
679679

680680
if (!EnableSILInliningOfGenerics && AI.hasSubstitutions()) {
681-
// Inlining of generics is not allowed.
682-
return nullptr;
681+
// Inlining of generics is not allowed unless it is an @inline(__always)
682+
// or transparent function.
683+
if (Callee->getInlineStrategy() != AlwaysInline && !Callee->isTransparent())
684+
return nullptr;
683685
}
684686

685687
// IRGen cannot handle partial_applies containing opened_existentials

test/SILGen/collection_cast_crash.swift

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,28 +10,28 @@ class KeyClass : Hashable {
1010
}
1111
func ==(lhs: KeyClass, rhs: KeyClass) -> Bool { return true }
1212

13-
// CHECK-LABEL: sil hidden @{{.*}}arrayUpCast{{.*}} <Ct where Ct : MyClass>
13+
// CHECK-LABEL: sil shared @{{.*}}arrayUpCast{{.*}} <Ct where Ct : MyClass>
1414
func arrayUpCast<Ct: MyClass>(_ arr: [Ct]) -> [MyClass] {
1515
// CHECK: apply %{{[0-9]*}}<Ct, MyClass>(%{{[0-9]*}})
1616
return arr
1717
// CHECK: return
1818
}
1919

20-
// CHECK-LABEL: sil hidden @{{.*}}arrayDownCast{{.*}} <Ct where Ct : MyClass>
20+
// CHECK-LABEL: sil shared @{{.*}}arrayDownCast{{.*}} <Ct where Ct : MyClass>
2121
func arrayDownCast<Ct: MyClass>(_ arr: [MyClass]) -> [Ct] {
2222
// CHECK: apply %{{[0-9]*}}<MyClass, Ct>(%{{[0-9]*}})
2323
return arr as! [Ct]
2424
// CHECK: return
2525
}
2626

27-
// CHECK-LABEL: sil hidden @{{.*}}dictUpCast{{.*}} <Ct where Ct : MyClass>
27+
// CHECK-LABEL: sil shared @{{.*}}dictUpCast{{.*}} <Ct where Ct : MyClass>
2828
func dictUpCast<Ct: MyClass>(_ dict: [KeyClass:Ct]) -> [KeyClass:MyClass] {
2929
// CHECK: apply %{{[0-9]*}}<KeyClass, Ct, KeyClass, MyClass>(%{{[0-9]*}})
3030
return dict as [KeyClass:MyClass]
3131
// CHECK: return
3232
}
3333

34-
// CHECK-LABEL: sil hidden @{{.*}}dictDownCast{{.*}} <Ct where Ct : MyClass>
34+
// CHECK-LABEL: sil shared @{{.*}}dictDownCast{{.*}} <Ct where Ct : MyClass>
3535
func dictDownCast<Ct: MyClass>(_ dict: [KeyClass:MyClass]) -> [KeyClass:Ct] {
3636
// CHECK: apply %{{[0-9]*}}<KeyClass, MyClass, KeyClass, Ct>(%{{[0-9]*}})
3737
return dict as! [KeyClass:Ct]

test/SILOptimizer/inline_generics.sil

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -inline -sil-inline-generics=true | %FileCheck %s
2+
// RUN: %target-sil-opt -assume-parsing-unqualified-ownership-sil -enable-sil-verify-all %s -inline -sil-inline-generics=false | %FileCheck --check-prefix=DISABLED-GENERIC-INLINING-CHECK %s
23

34
sil_stage canonical
45

@@ -112,6 +113,68 @@ bb0(%0 : $T, %1 : $@callee_owned (@owned P) -> Bool):
112113
return %3 : $Bool
113114
} // end sil function 'thunk2'
114115

116+
117+
sil [always_inline] @alwaysInlineGenericCallee : $@convention(thin) <T> (@in T) -> @out T {
118+
bb0(%0 : $*T, %1 : $*T):
119+
copy_addr [take] %1 to [initialization] %0 : $*T
120+
%4 = tuple ()
121+
return %4 : $()
122+
} // end sil function 'alwaysInlineGenericCallee'
123+
124+
sil [transparent] @transparentGenericCallee : $@convention(thin) <T> (@in T) -> @out T {
125+
bb0(%0 : $*T, %1 : $*T):
126+
copy_addr [take] %1 to [initialization] %0 : $*T
127+
%4 = tuple ()
128+
return %4 : $()
129+
} // end sil function 'transparentInlineGenericCallee'
130+
131+
132+
// Check that [always_inline] and [transparent] functions are inlined even if
133+
// inlining of generics is disabled. Regular generic functions should not be
134+
// inlined.
135+
// DISABLED-GENERIC-INLINING-CHECK-LABEL: sil @testComplexInliningOfGenerics
136+
// DISABLED-GENERIC-INLINING-CHECK-NOT: function_ref @{{.*}}
137+
// DISABLED-GENERIC-INLINING-CHECK-NOT: apply
138+
// DISABLED-GENERIC-INLINING-CHECK: [[FUNC:%[0-9]+]] = function_ref @genericFoo
139+
// DISABLED-GENERIC-INLINING-CHECK: apply [[FUNC]]
140+
// DISABLED-GENERIC-INLINING-CHECK-NOT: function_ref
141+
// DISABLED-GENERIC-INLINING-CHECK-NOT: apply
142+
// DISABLED-GENERIC-INLINING-CHECK: end sil function 'testComplexInliningOfGenerics'
143+
144+
// Check that all callees are inlined if inlining of generics is enabled.
145+
// CHECK-LABEL: sil @testComplexInliningOfGenerics
146+
// CHECK-NOT: apply
147+
// CHECK: end sil function 'testComplexInliningOfGenerics'
148+
sil @testComplexInliningOfGenerics : $@convention(thin) <T> (@in T) -> @out T {
149+
bb0(%0 : $*T, %1 : $*T):
150+
151+
// Call an [always_inline] function.
152+
%3 = function_ref @alwaysInlineGenericCallee : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0
153+
%4 = alloc_stack $T
154+
copy_addr %1 to [initialization] %4 : $*T
155+
%6 = apply %3<T>(%0, %4) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0
156+
dealloc_stack %4 : $*T
157+
158+
// Call a [transparent] function.
159+
%8 = function_ref @transparentGenericCallee : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0
160+
%9 = alloc_stack $T
161+
copy_addr %1 to [initialization] %9 : $*T
162+
%10 = apply %8<T>(%0, %9) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0
163+
dealloc_stack %9 : $*T
164+
165+
// Call a regular function.
166+
// function_ref genericFoo<A> (A) -> A
167+
%12 = function_ref @genericFoo : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0
168+
%13 = alloc_stack $T
169+
copy_addr %1 to [initialization] %13 : $*T
170+
%15 = apply %12<T>(%0, %13) : $@convention(thin) <τ_0_0> (@in τ_0_0) -> @out τ_0_0
171+
dealloc_stack %13 : $*T
172+
173+
destroy_addr %1 : $*T
174+
%18 = tuple ()
175+
return %18 : $()
176+
} // end sil function 'testComplexInliningOfGenerics'
177+
115178
sil_default_witness_table P {
116179
no_default
117180
}

test/SILOptimizer/performance_inliner.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -786,7 +786,7 @@ bb2: // Preds: bb0 bb1
786786
return %16 : $() // id: %17
787787
}
788788

789-
sil [transparent] @slowHelper : $@convention(thin) () -> () {
789+
sil @slowHelper : $@convention(thin) () -> () {
790790
bb0:
791791
// make it a non-trivial function
792792
%f = function_ref @unknown_function : $@convention(thin) () -> ()

0 commit comments

Comments
 (0)