Skip to content

Commit b7e5ec8

Browse files
committed
MandatoryPerformanceOptimizations: force inlining of transparent functions and de-virtualization
Do this even if the function then contains references to other functions with wrong linkage. Instead fix the linkage later. Fixes a false error in embedded swift. rdar://134352676
1 parent c96b196 commit b7e5ec8

File tree

4 files changed

+80
-5
lines changed

4 files changed

+80
-5
lines changed

SwiftCompilerSources/Sources/Optimizer/ModulePasses/MandatoryPerformanceOptimizations.swift

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,16 @@ private func optimize(function: Function, _ context: FunctionPassContext, _ modu
118118
context.erase(instructionIncludingDebugUses: iem)
119119
}
120120

121+
case let fri as FunctionRefInst:
122+
// Mandatory de-virtualization and mandatory inlining might leave referenced functions in "serialized"
123+
// functions with wrong linkage. Fix this by making the referenced function public.
124+
// It's not great, because it can prevent dead code elimination. But it's only a rare case.
125+
if function.serializedKind != .notSerialized,
126+
!fri.referencedFunction.hasValidLinkageForFragileRef(function.serializedKind)
127+
{
128+
fri.referencedFunction.set(linkage: .public, moduleContext)
129+
}
130+
121131
default:
122132
break
123133
}
@@ -153,6 +163,8 @@ private func specializeVTableAndAddEntriesToWorklist(for type: Type, in function
153163

154164
private func inlineAndDevirtualize(apply: FullApplySite, alreadyInlinedFunctions: inout Set<PathFunctionTuple>,
155165
_ context: FunctionPassContext, _ simplifyCtxt: SimplifyContext) {
166+
// De-virtualization and inlining in/into a "serialized" function might create function references to functions
167+
// with wrong linkage. We need to fix this later (see handling of FunctionRefInst in `optimize`).
156168
if simplifyCtxt.tryDevirtualize(apply: apply, isMandatory: true) != nil {
157169
return
158170
}
@@ -166,9 +178,7 @@ private func inlineAndDevirtualize(apply: FullApplySite, alreadyInlinedFunctions
166178
return
167179
}
168180

169-
if apply.canInline &&
170-
shouldInline(apply: apply, callee: callee, alreadyInlinedFunctions: &alreadyInlinedFunctions)
171-
{
181+
if shouldInline(apply: apply, callee: callee, alreadyInlinedFunctions: &alreadyInlinedFunctions) {
172182
if apply.inliningCanInvalidateStackNesting {
173183
simplifyCtxt.notifyInvalidatedStackNesting()
174184
}
@@ -196,9 +206,14 @@ private func removeUnusedMetatypeInstructions(in function: Function, _ context:
196206

197207
private func shouldInline(apply: FullApplySite, callee: Function, alreadyInlinedFunctions: inout Set<PathFunctionTuple>) -> Bool {
198208
if callee.isTransparent {
209+
precondition(callee.hasOwnership, "transparent functions should have ownership at this stage of the pipeline")
199210
return true
200211
}
201212

213+
if !apply.canInline {
214+
return false
215+
}
216+
202217
if apply is BeginApplyInst {
203218
// Avoid co-routines because they might allocate (their context).
204219
return true

lib/SILOptimizer/Utils/Devirtualize.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1182,7 +1182,8 @@ static bool canDevirtualizeWitnessMethod(ApplySite applySite, bool isMandatory)
11821182

11831183
// function_ref inside fragile function cannot reference a private or
11841184
// hidden symbol.
1185-
if (applySite.getFunction()->isAnySerialized() &&
1185+
if (!isMandatory &&
1186+
applySite.getFunction()->isAnySerialized() &&
11861187
!f->hasValidLinkageForFragileRef(applySite.getFunction()->getSerializedKind()))
11871188
return false;
11881189

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// RUN: %target-sil-opt -module-name=test -enable-sil-verify-all %s -mandatory-performance-optimizations -performance-diagnostics | %FileCheck %s
2+
3+
sil_stage canonical
4+
5+
import Swift
6+
import SwiftShims
7+
import Builtin
8+
9+
public protocol P {
10+
func foo()
11+
}
12+
13+
private struct S : P {
14+
@_hasStorage var x: Int
15+
func foo()
16+
}
17+
18+
// Linkage should be set to public
19+
// CHECK-LABEL: sil [perf_constraint] [ossa] @S_foo : $@convention(method) (S) -> () {
20+
sil private [ossa] @S_foo : $@convention(method) (S) -> () {
21+
bb0(%0 : $S):
22+
%2 = tuple ()
23+
return %2 : $()
24+
}
25+
26+
sil private [transparent] [thunk] [ossa] @S_foo_thunk : $@convention(witness_method: P) (@in_guaranteed S) -> () {
27+
bb0(%0 : $*S):
28+
%1 = load [trivial] %0 : $*S
29+
%2 = function_ref @S_foo : $@convention(method) (S) -> ()
30+
%3 = apply %2(%1) : $@convention(method) (S) -> ()
31+
%4 = tuple ()
32+
return %4 : $()
33+
}
34+
35+
// CHECK-LABEL: sil shared [serialized] [perf_constraint] [ossa] @$s8call_foo4test1S{{.*}}_Tgq5 : $@convention(thin) (S) -> () {
36+
// CHECK: [[F:%.*]] = function_ref @S_foo : $@convention(method) (S) -> ()
37+
// CHECK: = apply [[F]](%0) : $@convention(method) (S) -> ()
38+
// CHECK: // end sil function '$s8call_foo4test1S{{.*}}_Tgq5'
39+
sil [ossa] [serialized] @call_foo : $@convention(thin) <T where T : P> (@in_guaranteed T) -> () {
40+
bb0(%0 : $*T):
41+
%2 = witness_method $T, #P.foo : <Self where Self : P> (Self) -> () -> () : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
42+
%3 = apply %2<T>(%0) : $@convention(witness_method: P) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
43+
%4 = tuple ()
44+
return %4 : $()
45+
}
46+
47+
sil [no_locks] [ossa] [serialized] @main : $@convention(thin) (@in_guaranteed S) -> () {
48+
bb0(%0 : $*S):
49+
%5 = function_ref @call_foo : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
50+
%6 = apply %5<S>(%0) : $@convention(thin) <τ_0_0 where τ_0_0 : P> (@in_guaranteed τ_0_0) -> ()
51+
%8 = tuple ()
52+
return %8 : $()
53+
}
54+
55+
sil_witness_table private S: P module test {
56+
method #P.foo: <Self where Self : P> (Self) -> () -> () : @S_foo_thunk
57+
}
58+
59+

test/SILOptimizer/mandatory_performance_optimizations.sil

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ bb0:
120120
%2 = tuple ()
121121
return %2 : $()
122122
}
123-
sil shared [transparent] [serialized] [thunk] [canonical] @$sSiSLsSL1loiySbx_xtFZTW : $@convention(witness_method: Comparable) (@in_guaranteed Int, @in_guaranteed Int, @thick Int.Type) -> Bool {
123+
sil shared [ossa] [transparent] [serialized] [thunk] [canonical] @$sSiSLsSL1loiySbx_xtFZTW : $@convention(witness_method: Comparable) (@in_guaranteed Int, @in_guaranteed Int, @thick Int.Type) -> Bool {
124124
bb0(%0 : $*Int, %1 : $*Int, %2 : $@thick Int.Type):
125125
%3 = integer_literal $Builtin.Int1, 0
126126
%4 = struct $Bool (%3 : $Builtin.Int1)

0 commit comments

Comments
 (0)