Skip to content

Commit 8a18fc0

Browse files
authored
Merge pull request swiftlang#63229 from tshortli/avoid-unnecessary-back-deploy-thunk
SILGen: Avoid using back deployment thunks for high enough deployment targets
2 parents fde0542 + 80295fd commit 8a18fc0

14 files changed

+152
-47
lines changed

lib/SILGen/SILGen.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
423423
/// Is the self method of the given nonmutating method passed indirectly?
424424
bool isNonMutatingSelfIndirect(SILDeclRef method);
425425

426-
SILDeclRef getAccessorDeclRef(AccessorDecl *accessor);
426+
SILDeclRef getAccessorDeclRef(AccessorDecl *accessor,
427+
ResilienceExpansion expansion);
427428

428429
bool canStorageUseStoredKeyPathComponent(AbstractStorageDecl *decl,
429430
ResilienceExpansion expansion);

lib/SILGen/SILGenApply.cpp

Lines changed: 52 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,31 @@ static void convertOwnershipConventionsGivenParamInfos(
259259
});
260260
}
261261

262+
static bool shouldApplyBackDeploymentThunk(ValueDecl *decl, ASTContext &ctx,
263+
ResilienceExpansion expansion) {
264+
auto backDeployBeforeVersion = decl->getBackDeployBeforeOSVersion(ctx);
265+
if (!backDeployBeforeVersion)
266+
return false;
267+
268+
// If the context of the application is inlinable then we must always call the
269+
// back deployment thunk since we can't predict the deployment targets of
270+
// other modules.
271+
if (expansion != ResilienceExpansion::Maximal)
272+
return true;
273+
274+
// In resilient function bodies skip calling the back deployment thunk when
275+
// the deployment target is high enough that the ABI implementation of the
276+
// back deployed function is guaranteed to be available.
277+
auto deploymentAvailability = AvailabilityContext::forDeploymentTarget(ctx);
278+
auto declAvailability =
279+
AvailabilityContext(VersionRange::allGTE(*backDeployBeforeVersion));
280+
281+
if (deploymentAvailability.isContainedIn(declAvailability))
282+
return false;
283+
284+
return true;
285+
}
286+
262287
//===----------------------------------------------------------------------===//
263288
// Callee
264289
//===----------------------------------------------------------------------===//
@@ -1104,6 +1129,28 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
11041129
}
11051130
}
11061131

1132+
SILDeclRef getDeclRefForStaticDispatchApply(DeclRefExpr *e) {
1133+
auto *afd = cast<AbstractFunctionDecl>(e->getDecl());
1134+
auto &ctx = SGF.getASTContext();
1135+
1136+
// A call to a `distributed` function may need to go through a thunk.
1137+
if (callSite && callSite->shouldApplyDistributedThunk()) {
1138+
if (auto distributedThunk = afd->getDistributedThunk())
1139+
return SILDeclRef(distributedThunk).asDistributed();
1140+
}
1141+
1142+
// A call to `@_backDeploy` function may need to go through a thunk.
1143+
if (shouldApplyBackDeploymentThunk(afd, ctx,
1144+
SGF.F.getResilienceExpansion())) {
1145+
return SILDeclRef(afd).asBackDeploymentKind(
1146+
SILDeclRef::BackDeploymentKind::Thunk);
1147+
}
1148+
1149+
return SILDeclRef(afd).asForeign(
1150+
!isConstructorWithGeneratedAllocatorThunk(afd) &&
1151+
requiresForeignEntryPoint(afd));
1152+
}
1153+
11071154
//
11081155
// Known callees.
11091156
//
@@ -1144,25 +1191,7 @@ class SILGenApply : public Lowering::ExprVisitor<SILGenApply> {
11441191
}
11451192

11461193
// Otherwise, we have a statically-dispatched call.
1147-
SILDeclRef constant = SILDeclRef(e->getDecl());
1148-
1149-
/// Some special handling may be necessary for thunks:
1150-
if (callSite && callSite->shouldApplyDistributedThunk()) {
1151-
if (auto distributedThunk = cast<AbstractFunctionDecl>(e->getDecl())->getDistributedThunk()) {
1152-
constant = SILDeclRef(distributedThunk).asDistributed();
1153-
}
1154-
} else if (afd->isBackDeployed()) {
1155-
// If we're calling a back deployed function then we need to call a
1156-
// thunk instead that will handle the fallback when the original
1157-
// function is unavailable at runtime.
1158-
constant =
1159-
constant.asBackDeploymentKind(SILDeclRef::BackDeploymentKind::Thunk);
1160-
} else {
1161-
constant = constant.asForeign(
1162-
!isConstructorWithGeneratedAllocatorThunk(e->getDecl())
1163-
&& requiresForeignEntryPoint(e->getDecl()));
1164-
}
1165-
1194+
SILDeclRef constant = getDeclRefForStaticDispatchApply(e);
11661195
auto captureInfo = SGF.SGM.Types.getLoweredLocalCaptures(constant);
11671196
SGF.SGM.Types.setCaptureTypeExpansionContext(constant, SGF.SGM.M);
11681197

@@ -5943,9 +5972,11 @@ SILGenFunction::prepareSubscriptIndices(SubscriptDecl *subscript,
59435972
return result;
59445973
}
59455974

5946-
SILDeclRef SILGenModule::getAccessorDeclRef(AccessorDecl *accessor) {
5975+
SILDeclRef SILGenModule::getAccessorDeclRef(AccessorDecl *accessor,
5976+
ResilienceExpansion expansion) {
59475977
auto declRef = SILDeclRef(accessor, SILDeclRef::Kind::Func);
5948-
if (accessor->isBackDeployed())
5978+
5979+
if (shouldApplyBackDeploymentThunk(accessor, getASTContext(), expansion))
59495980
return declRef.asBackDeploymentKind(SILDeclRef::BackDeploymentKind::Thunk);
59505981

59515982
return declRef.asForeign(requiresForeignEntryPoint(accessor));

lib/SILGen/SILGenExpr.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3552,6 +3552,7 @@ getOrCreateKeyPathEqualsAndHash(SILGenModule &SGM,
35523552
static KeyPathPatternComponent::ComputedPropertyId
35533553
getIdForKeyPathComponentComputedProperty(SILGenModule &SGM,
35543554
AbstractStorageDecl *storage,
3555+
ResilienceExpansion expansion,
35553556
AccessStrategy strategy) {
35563557
switch (strategy.getKind()) {
35573558
case AccessStrategy::Storage:
@@ -3563,7 +3564,8 @@ getIdForKeyPathComponentComputedProperty(SILGenModule &SGM,
35633564
strategy = strategy.getReadStrategy();
35643565
if (strategy.getKind() != AccessStrategy::Storage ||
35653566
!getRepresentativeAccessorForKeyPath(storage)) {
3566-
return getIdForKeyPathComponentComputedProperty(SGM, storage, strategy);
3567+
return getIdForKeyPathComponentComputedProperty(SGM, storage, expansion,
3568+
strategy);
35673569
}
35683570
LLVM_FALLTHROUGH;
35693571
case AccessStrategy::DirectToAccessor: {
@@ -3583,7 +3585,8 @@ getIdForKeyPathComponentComputedProperty(SILGenModule &SGM,
35833585
}
35843586
case AccessStrategy::DispatchToAccessor: {
35853587
// Identify the property by its vtable or wtable slot.
3586-
return SGM.getAccessorDeclRef(getRepresentativeAccessorForKeyPath(storage));
3588+
return SGM.getAccessorDeclRef(getRepresentativeAccessorForKeyPath(storage),
3589+
expansion);
35873590
}
35883591

35893592
case AccessStrategy::DispatchToDistributedThunk: {
@@ -3706,7 +3709,7 @@ SILGenModule::emitKeyPathComponentForDecl(SILLocation loc,
37063709
// either.
37073710
if (baseDecl->requiresOpaqueAccessors()) {
37083711
auto representative = getAccessorDeclRef(
3709-
getRepresentativeAccessorForKeyPath(baseDecl));
3712+
getRepresentativeAccessorForKeyPath(baseDecl), expansion);
37103713
if (representative.isForeign)
37113714
return false;
37123715
if (representative.getLinkage(ForDefinition) > SILLinkage::PublicNonABI)
@@ -3785,7 +3788,7 @@ SILGenModule::emitKeyPathComponentForDecl(SILLocation loc,
37853788

37863789
// We need thunks to bring the getter and setter to the right signature
37873790
// expected by the key path runtime.
3788-
auto id = getIdForKeyPathComponentComputedProperty(*this, var,
3791+
auto id = getIdForKeyPathComponentComputedProperty(*this, var, expansion,
37893792
strategy);
37903793
auto getter = getOrCreateKeyPathGetter(*this,
37913794
var, subs,
@@ -3842,8 +3845,9 @@ SILGenModule::emitKeyPathComponentForDecl(SILLocation loc,
38423845
indexPatterns,
38433846
indexEquals, indexHash);
38443847
}
3845-
3846-
auto id = getIdForKeyPathComponentComputedProperty(*this, decl, strategy);
3848+
3849+
auto id = getIdForKeyPathComponentComputedProperty(*this, decl, expansion,
3850+
strategy);
38473851
auto getter = getOrCreateKeyPathGetter(*this,
38483852
decl, subs,
38493853
needsGenericContext ? genericEnv : nullptr,

lib/SILGen/SILGenFunction.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2358,6 +2358,11 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
23582358

23592359
/// Get the _Pointer protocol used for pointer argument operations.
23602360
ProtocolDecl *getPointerProtocol();
2361+
2362+
/// Returns the SILDeclRef to use for references to the given accessor.
2363+
SILDeclRef getAccessorDeclRef(AccessorDecl *accessor) {
2364+
return SGM.getAccessorDeclRef(accessor, F.getResilienceExpansion());
2365+
}
23612366
};
23622367

23632368

lib/SILGen/SILGenLValue.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2896,7 +2896,7 @@ namespace {
28962896
void emitUsingAccessor(AccessorKind accessorKind,
28972897
bool isDirect) {
28982898
auto accessor =
2899-
SGF.SGM.getAccessorDeclRef(Storage->getOpaqueAccessor(accessorKind));
2899+
SGF.getAccessorDeclRef(Storage->getOpaqueAccessor(accessorKind));
29002900

29012901
switch (accessorKind) {
29022902
case AccessorKind::Set: {
@@ -3327,16 +3327,18 @@ LValue SILGenLValue::visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *e,
33273327
static SGFAccessKind getBaseAccessKindForAccessor(SILGenModule &SGM,
33283328
AccessorDecl *accessor,
33293329
CanType baseFormalType) {
3330-
if (accessor->isMutating()) {
3330+
if (accessor->isMutating())
33313331
return SGFAccessKind::ReadWrite;
3332-
} else if (SGM.shouldEmitSelfAsRValue(accessor, baseFormalType)) {
3333-
return SGM.isNonMutatingSelfIndirect(SGM.getAccessorDeclRef(accessor))
3334-
? SGFAccessKind::OwnedAddressRead
3335-
: SGFAccessKind::OwnedObjectRead;
3332+
3333+
auto declRef = SGM.getAccessorDeclRef(accessor, ResilienceExpansion::Minimal);
3334+
if (SGM.shouldEmitSelfAsRValue(accessor, baseFormalType)) {
3335+
return SGM.isNonMutatingSelfIndirect(declRef)
3336+
? SGFAccessKind::OwnedAddressRead
3337+
: SGFAccessKind::OwnedObjectRead;
33363338
} else {
3337-
return SGM.isNonMutatingSelfIndirect(SGM.getAccessorDeclRef(accessor))
3338-
? SGFAccessKind::BorrowedAddressRead
3339-
: SGFAccessKind::BorrowedObjectRead;
3339+
return SGM.isNonMutatingSelfIndirect(declRef)
3340+
? SGFAccessKind::BorrowedAddressRead
3341+
: SGFAccessKind::BorrowedObjectRead;
33403342
}
33413343
}
33423344

@@ -3444,7 +3446,7 @@ LValue SILGenLValue::visitMemberRefExpr(MemberRefExpr *e,
34443446
var->getOpaqueAccessor(AccessorKind::Read)) {
34453447
bool isObjC = false;
34463448
auto readAccessor =
3447-
SGF.SGM.getAccessorDeclRef(var->getOpaqueAccessor(AccessorKind::Read));
3449+
SGF.getAccessorDeclRef(var->getOpaqueAccessor(AccessorKind::Read));
34483450
if (isCallToReplacedInDynamicReplacement(
34493451
SGF, readAccessor.getAbstractFunctionDecl(), isObjC)) {
34503452
accessSemantics = AccessSemantics::DirectToImplementation;
@@ -3645,7 +3647,7 @@ LValue SILGenLValue::visitSubscriptExpr(SubscriptExpr *e,
36453647
decl->getOpaqueAccessor(AccessorKind::Read)) {
36463648
bool isObjC = false;
36473649
auto readAccessor =
3648-
SGF.SGM.getAccessorDeclRef(decl->getOpaqueAccessor(AccessorKind::Read));
3650+
SGF.getAccessorDeclRef(decl->getOpaqueAccessor(AccessorKind::Read));
36493651
if (isCallToReplacedInDynamicReplacement(
36503652
SGF, readAccessor.getAbstractFunctionDecl(), isObjC)) {
36513653
accessSemantics = AccessSemantics::DirectToImplementation;
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// RUN: %target-swift-emit-sil -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.50 -verify
2+
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s | %FileCheck %s
3+
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.50 | %FileCheck %s --check-prefixes=CHECK,CHECK-BACK-DEPLOY
4+
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.52 | %FileCheck %s --check-prefixes=CHECK,CHECK-NATIVE
5+
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.60 | %FileCheck %s --check-prefixes=CHECK,CHECK-NATIVE
6+
7+
// REQUIRES: OS=macosx
8+
9+
@_backDeploy(before: macOS 10.52)
10+
public func someFunc() {}
11+
12+
public struct S<T> {
13+
@usableFromInline var _x: T
14+
15+
@_backDeploy(before: macOS 10.52)
16+
public var x: T {
17+
get { _x }
18+
set { _x = newValue }
19+
}
20+
}
21+
22+
public struct Z {
23+
public init() {}
24+
}
25+
26+
// CHECK-LABEL: sil hidden [ossa] @$s11back_deploy15resilientCalleryyAA1SVyAA1ZVGzF
27+
func resilientCaller(_ s: inout S<Z>) {
28+
// CHECK-BACK-DEPLOY: function_ref @$s11back_deploy8someFuncyyFTwb : $@convention(thin) () -> ()
29+
// CHECK-NATIVE: function_ref @$s11back_deploy8someFuncyyF : $@convention(thin) () -> ()
30+
someFunc()
31+
// CHECK-BACK-DEPLOY: function_ref @$s11back_deploy1SV1xxvgTwb : $@convention(method) <τ_0_0> (@in_guaranteed S<τ_0_0>) -> @out τ_0_0
32+
// CHECK-NATIVE: function_ref @$s11back_deploy1SV1xxvg : $@convention(method) <τ_0_0> (@in_guaranteed S<τ_0_0>) -> @out τ_0_0
33+
_ = s.x
34+
// CHECK-BACK-DEPLOY: function_ref @$s11back_deploy1SV1xxvsTwb : $@convention(method) <τ_0_0> (@in τ_0_0, @inout S<τ_0_0>) -> ()
35+
// CHECK-NATIVE: function_ref @$s11back_deploy1SV1xxvs : $@convention(method) <τ_0_0> (@in τ_0_0, @inout S<τ_0_0>) -> ()
36+
s.x = Z()
37+
}
38+
39+
// CHECK-LABEL: sil [serialized] [ossa] @$s11back_deploy15inlinableCalleryyAA1SVyAA1ZVGzF
40+
@inlinable
41+
func inlinableCaller(_ s: inout S<Z>) {
42+
// CHECK: function_ref @$s11back_deploy8someFuncyyFTwb : $@convention(thin) () -> ()
43+
someFunc()
44+
// CHECK: function_ref @$s11back_deploy1SV1xxvgTwb : $@convention(method) <τ_0_0> (@in_guaranteed S<τ_0_0>) -> @out τ_0_0
45+
_ = s.x
46+
// CHECK: function_ref @$s11back_deploy1SV1xxvsTwb : $@convention(method) <τ_0_0> (@in τ_0_0, @inout S<τ_0_0>) -> ()
47+
s.x = Z()
48+
}
49+
50+
// CHECK-LABEL: sil non_abi [serialized] [ossa] @$s11back_deploy10aeicCalleryyAA1SVyAA1ZVGzF
51+
@_alwaysEmitIntoClient
52+
func aeicCaller(_ s: inout S<Z>) {
53+
// CHECK: function_ref @$s11back_deploy8someFuncyyFTwb : $@convention(thin) () -> ()
54+
someFunc()
55+
// CHECK: function_ref @$s11back_deploy1SV1xxvgTwb : $@convention(method) <τ_0_0> (@in_guaranteed S<τ_0_0>) -> @out τ_0_0
56+
_ = s.x
57+
// CHECK: function_ref @$s11back_deploy1SV1xxvsTwb : $@convention(method) <τ_0_0> (@in τ_0_0, @inout S<τ_0_0>) -> ()
58+
s.x = Z()
59+
}
60+
61+
// CHECK-LABEL: sil non_abi [serialized] [ossa] @$s11back_deploy0A14DeployedCalleryyAA1SVyAA1ZVGzFTwB
62+
@_backDeploy(before: macOS 10.52)
63+
public func backDeployedCaller(_ s: inout S<Z>) {
64+
// CHECK: function_ref @$s11back_deploy8someFuncyyFTwb : $@convention(thin) () -> ()
65+
someFunc()
66+
// CHECK: function_ref @$s11back_deploy1SV1xxvgTwb : $@convention(method) <τ_0_0> (@in_guaranteed S<τ_0_0>) -> @out τ_0_0
67+
_ = s.x
68+
// CHECK: function_ref @$s11back_deploy1SV1xxvsTwb : $@convention(method) <τ_0_0> (@in τ_0_0, @inout S<τ_0_0>) -> ()
69+
s.x = Z()
70+
}

test/SILGen/back_deploy_attribute_accessor.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// RUN: %target-swift-emit-sil -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.50 -verify
22
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s | %FileCheck %s
33
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.50 | %FileCheck %s
4-
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.60 | %FileCheck %s
54

65
// REQUIRES: OS=macosx
76

test/SILGen/back_deploy_attribute_accessor_coroutine.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// RUN: %target-swift-emit-sil -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.50 -verify
22
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s | %FileCheck %s
33
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.50 | %FileCheck %s
4-
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.60 | %FileCheck %s
54

65
// REQUIRES: OS=macosx
76

test/SILGen/back_deploy_attribute_async_func.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// RUN: %target-swift-emit-sil -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.50 -verify
22
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s | %FileCheck %s
33
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.50 | %FileCheck %s
4-
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.60 | %FileCheck %s
54

65
// REQUIRES: OS=macosx
76
// REQUIRES: concurrency

test/SILGen/back_deploy_attribute_func.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
// RUN: %target-swift-emit-sil -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.50 -verify
22
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s | %FileCheck %s
33
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.50 | %FileCheck %s
4-
// RUN: %target-swift-emit-silgen -parse-as-library -module-name back_deploy %s -target %target-cpu-apple-macosx10.60 | %FileCheck %s
54

65
// REQUIRES: OS=macosx
76

0 commit comments

Comments
 (0)