Skip to content

Commit f5dbcfc

Browse files
committed
[sil-perf-inliner] Allow for inlining of functions using dynamic Self if it is the same Self as used by the caller
It is safe to inline in such cases, because both dynamic Self types refer to the same type.
1 parent 49b3654 commit f5dbcfc

File tree

2 files changed

+43
-7
lines changed

2 files changed

+43
-7
lines changed

lib/SILOptimizer/Transforms/PerformanceInliner.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,14 +1124,23 @@ SILFunction *SILPerformanceInliner::getEligibleFunction(FullApplySite AI) {
11241124
return nullptr;
11251125
}
11261126

1127+
SILFunction *Caller = AI.getFunction();
1128+
11271129
// We don't support inlining a function that binds dynamic self because we
11281130
// have no mechanism to preserve the original function's local self metadata.
11291131
if (computeMayBindDynamicSelf(Callee)) {
1130-
return nullptr;
1132+
// Check if passed Self is the same as the Self of the caller.
1133+
// In this case, it is safe to inline because both functions
1134+
// use the same Self.
1135+
if (AI.hasSelfArgument() && Caller->hasSelfParam()) {
1136+
auto CalleeSelf = stripCasts(AI.getSelfArgument());
1137+
auto CallerSelf = Caller->getSelfArgument();
1138+
if (CalleeSelf != SILValue(CallerSelf))
1139+
return nullptr;
1140+
} else
1141+
return nullptr;
11311142
}
11321143

1133-
SILFunction *Caller = AI.getFunction();
1134-
11351144
// Detect self-recursive calls.
11361145
if (Caller == Callee) {
11371146
return nullptr;

test/SILOptimizer/inline_self.swift

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,31 @@ func callIt(fn: () -> ()) {
3333
fn()
3434
}
3535

36+
class BaseZ {
37+
final func baseCapturesSelf() -> Self {
38+
let fn = { [weak self] in _ = self }
39+
callIt(fn: fn)
40+
return self
41+
}
42+
}
43+
3644
// Do not inline C.capturesSelf() into main either.
37-
class Z {
38-
func capturesSelf() -> Self {
45+
class Z : BaseZ {
46+
final func capturesSelf() -> Self {
3947
let fn = { [weak self] in _ = self }
4048
callIt(fn: fn)
4149
return self
4250
}
51+
52+
// Inline captureSelf into callCaptureSelf,
53+
// because their respective Self types refer to the same type.
54+
final func callCapturesSelf() -> Self {
55+
return capturesSelf()
56+
}
57+
58+
final func callBaseCapturesSelf() -> Self {
59+
return baseCapturesSelf()
60+
}
4361
}
4462

4563
_ = Z().capturesSelf()
@@ -49,7 +67,16 @@ _ = Z().capturesSelf()
4967
// CHECK: [[F:%[0-9]+]] = function_ref @_TZFC11inline_self1C7factory{{.*}} : $@convention(method) (Int, @thick C.Type) -> @owned C
5068
// CHECK: apply [[F]](%{{.+}}, %{{.+}}) : $@convention(method) (Int, @thick C.Type) -> @owned C
5169

52-
// CHECK: [[Z:%.*]] = alloc_ref $Z
5370
// CHECK: function_ref inline_self.Z.capturesSelf () -> Self
5471
// CHECK: [[F:%[0-9]+]] = function_ref @_TFC11inline_self1Z12capturesSelffT_DS0_ : $@convention(method) (@guaranteed Z) -> @owned Z
55-
// CHECK: apply [[F]]([[Z]]) : $@convention(method) (@guaranteed Z) -> @owned Z
72+
// CHECK: [[Z:%.*]] = alloc_ref $Z
73+
// CHECK: apply [[F]]([[Z]]) : $@convention(method) (@guaranteed Z) -> @owned
74+
// CHECK: return
75+
76+
// CHECK-LABEL: sil hidden @_TFC11inline_self1Z16callCapturesSelffT_DS0_ : $@convention(method)
77+
// CHECK-NOT: function_ref @_TFC11inline_self1Z12capturesSelffT_DS0_
78+
// CHECK: }
79+
80+
// CHECK-LABEL: sil hidden @_TFC11inline_self1Z20callBaseCapturesSelffT_DS0_
81+
// CHECK-NOT: function_ref @_TFC11inline_self5BaseZ16baseCapturesSelffT_DS0_
82+
// CHECK: }

0 commit comments

Comments
 (0)