Skip to content

Commit 94ee0ec

Browse files
Merge pull request #58826 from aschwaighofer/pre_specialization_cherry_picks_5.7
[5.7] Pre-specialization fixes cherry-picks
2 parents 523fd5a + 564df84 commit 94ee0ec

File tree

15 files changed

+137
-56
lines changed

15 files changed

+137
-56
lines changed

lib/AST/ASTPrinter.cpp

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,17 @@ static bool isPublicOrUsableFromInline(Type ty) {
108108
});
109109
}
110110

111+
static bool isPrespecilizationDeclWithTarget(const ValueDecl *vd) {
112+
// Add exported prespecialized symbols.
113+
for (auto *attr : vd->getAttrs().getAttributes<SpecializeAttr>()) {
114+
if (!attr->isExported())
115+
continue;
116+
if (auto *targetFun = attr->getTargetFunctionDecl(vd))
117+
return true;
118+
}
119+
return false;
120+
}
121+
111122
static bool contributesToParentTypeStorage(const AbstractStorageDecl *ASD) {
112123
auto *DC = ASD->getDeclContext()->getAsDecl();
113124
if (!DC) return false;
@@ -180,9 +191,11 @@ PrintOptions PrintOptions::printSwiftInterfaceFile(ModuleDecl *ModuleToPrint,
180191
if (!options.PrintSPIs && D->isSPI())
181192
return false;
182193

183-
// Skip anything that isn't 'public' or '@usableFromInline'.
194+
// Skip anything that isn't 'public' or '@usableFromInline' or has a
195+
// _specialize attribute with a targetFunction parameter.
184196
if (auto *VD = dyn_cast<ValueDecl>(D)) {
185-
if (!isPublicOrUsableFromInline(VD)) {
197+
if (!isPublicOrUsableFromInline(VD) &&
198+
!isPrespecilizationDeclWithTarget(VD)) {
186199
// We do want to print private stored properties, without their
187200
// original names present.
188201
if (auto *ASD = dyn_cast<AbstractStorageDecl>(VD))

lib/SIL/IR/SILFunctionBuilder.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,11 @@ SILFunction *SILFunctionBuilder::getOrCreateFunction(
270270

271271
IsTransparent_t IsTrans =
272272
constant.isTransparent() ? IsTransparent : IsNotTransparent;
273+
273274
IsSerialized_t IsSer = constant.isSerialized();
275+
// Don't create a [serialized] function after serialization has happened.
276+
if (IsSer == IsSerialized && mod.isSerialized())
277+
IsSer = IsNotSerialized;
274278

275279
Inline_t inlineStrategy = InlineDefault;
276280
if (constant.isNoinline())

lib/SILOptimizer/IPO/CrossModuleOptimization.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,9 @@ bool CrossModuleOptimization::canSerializeFunction(
207207
// Do the same check for the specializations of such functions.
208208
if (function->isSpecialization()) {
209209
const SILFunction *parent = function->getSpecializationInfo()->getParent();
210-
if (!parent->getSpecializeAttrs().empty())
210+
// Don't serialize exported (public) specializations.
211+
if (!parent->getSpecializeAttrs().empty() &&
212+
function->getLinkage() == SILLinkage::Public)
211213
return false;
212214
}
213215

lib/SILOptimizer/PassManager/PassPipeline.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -927,6 +927,11 @@ SILPassPipelinePlan::getOnonePassPipeline(const SILOptions &Options) {
927927
// be no need to run another analysis of copies at -Onone.
928928
P.addMandatoryARCOpts();
929929

930+
// Create pre-specializations.
931+
// This needs to run pre-serialization because it needs to identify native
932+
// inlinable functions from imported ones.
933+
P.addOnonePrespecializations();
934+
930935
// First serialize the SIL if we are asked to.
931936
P.startPipeline("Serialization");
932937
P.addSerializeSILPass();
@@ -946,9 +951,6 @@ SILPassPipelinePlan::getOnonePassPipeline(const SILOptions &Options) {
946951
P.addAssumeSingleThreaded();
947952
}
948953

949-
// Create pre-specializations.
950-
P.addOnonePrespecializations();
951-
952954
// Has only an effect if the -sil-based-debuginfo option is specified.
953955
P.addSILDebugInfoGenerator();
954956

lib/SILOptimizer/Transforms/EagerSpecializer.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,14 @@ void EagerSpecializerTransform::run() {
853853
assert(success);
854854
}
855855
onlyCreatePrespecializations = true;
856+
} else if (targetFunc->getLinkage() == SILLinkage::Shared) {
857+
// We have `shared` linkage if we deserialize a public serialized
858+
// function.
859+
// That means we are loading it from another module. In this case, we
860+
// don't want to create a pre-specialization.
861+
SpecializedFuncs.push_back(nullptr);
862+
ReInfoVec.emplace_back(ReabstractionInfo());
863+
continue;
856864
}
857865
ReInfoVec.emplace_back(FuncBuilder.getModule().getSwiftModule(),
858866
FuncBuilder.getModule().isWholeModule(), targetFunc,

lib/SILOptimizer/Transforms/GenericSpecializer.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,44 @@
3333
using namespace swift;
3434

3535
namespace {
36+
static void transferSpecializeAttributeTargets(SILModule &M,
37+
SILOptFunctionBuilder &builder,
38+
Decl *d) {
39+
auto *vd = cast<AbstractFunctionDecl>(d);
40+
for (auto *A : vd->getAttrs().getAttributes<SpecializeAttr>()) {
41+
auto *SA = cast<SpecializeAttr>(A);
42+
// Filter _spi.
43+
auto spiGroups = SA->getSPIGroups();
44+
auto hasSPIGroup = !spiGroups.empty();
45+
if (hasSPIGroup) {
46+
if (vd->getModuleContext() != M.getSwiftModule() &&
47+
!M.getSwiftModule()->isImportedAsSPI(SA, vd)) {
48+
continue;
49+
}
50+
}
51+
if (auto *targetFunctionDecl = SA->getTargetFunctionDecl(vd)) {
52+
auto target = SILDeclRef(targetFunctionDecl);
53+
auto targetSILFunction = builder.getOrCreateFunction(
54+
SILLocation(vd), target, NotForDefinition,
55+
[&builder](SILLocation loc, SILDeclRef constant) -> SILFunction * {
56+
return builder.getOrCreateFunction(loc, constant, NotForDefinition);
57+
});
58+
auto kind = SA->getSpecializationKind() ==
59+
SpecializeAttr::SpecializationKind::Full
60+
? SILSpecializeAttr::SpecializationKind::Full
61+
: SILSpecializeAttr::SpecializationKind::Partial;
62+
Identifier spiGroupIdent;
63+
if (hasSPIGroup) {
64+
spiGroupIdent = spiGroups[0];
65+
}
66+
auto availability = AvailabilityInference::annotatedAvailableRangeForAttr(
67+
SA, M.getSwiftModule()->getASTContext());
68+
targetSILFunction->addSpecializeAttr(SILSpecializeAttr::create(
69+
M, SA->getSpecializedSignature(), SA->isExported(), kind, nullptr,
70+
spiGroupIdent, vd->getModuleContext(), availability));
71+
}
72+
}
73+
}
3674

3775
static bool specializeAppliesInFunction(SILFunction &F,
3876
SILTransform *transform,
@@ -60,6 +98,13 @@ static bool specializeAppliesInFunction(SILFunction &F,
6098
auto *Callee = Apply.getReferencedFunctionOrNull();
6199
if (!Callee)
62100
continue;
101+
102+
FunctionBuilder.getModule().performOnceForPrespecializedImportedExtensions(
103+
[&FunctionBuilder](AbstractFunctionDecl *pre) {
104+
transferSpecializeAttributeTargets(FunctionBuilder.getModule(), FunctionBuilder,
105+
pre);
106+
});
107+
63108
if (!Callee->isDefinition() && !Callee->hasPrespecialization()) {
64109
ORE.emit([&]() {
65110
using namespace OptRemark;

lib/SILOptimizer/Utils/Generics.cpp

Lines changed: 0 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -2552,45 +2552,6 @@ usePrespecialized(SILOptFunctionBuilder &funcBuilder, ApplySite apply,
25522552
return nullptr;
25532553
}
25542554

2555-
static void transferSpecializeAttributeTargets(SILModule &M,
2556-
SILOptFunctionBuilder &builder,
2557-
Decl *d) {
2558-
auto *vd = cast<AbstractFunctionDecl>(d);
2559-
for (auto *A : vd->getAttrs().getAttributes<SpecializeAttr>()) {
2560-
auto *SA = cast<SpecializeAttr>(A);
2561-
// Filter _spi.
2562-
auto spiGroups = SA->getSPIGroups();
2563-
auto hasSPIGroup = !spiGroups.empty();
2564-
if (hasSPIGroup) {
2565-
if (vd->getModuleContext() != M.getSwiftModule() &&
2566-
!M.getSwiftModule()->isImportedAsSPI(SA, vd)) {
2567-
continue;
2568-
}
2569-
}
2570-
if (auto *targetFunctionDecl = SA->getTargetFunctionDecl(vd)) {
2571-
auto target = SILDeclRef(targetFunctionDecl);
2572-
auto targetSILFunction = builder.getOrCreateFunction(
2573-
SILLocation(vd), target, NotForDefinition,
2574-
[&builder](SILLocation loc, SILDeclRef constant) -> SILFunction * {
2575-
return builder.getOrCreateFunction(loc, constant, NotForDefinition);
2576-
});
2577-
auto kind = SA->getSpecializationKind() ==
2578-
SpecializeAttr::SpecializationKind::Full
2579-
? SILSpecializeAttr::SpecializationKind::Full
2580-
: SILSpecializeAttr::SpecializationKind::Partial;
2581-
Identifier spiGroupIdent;
2582-
if (hasSPIGroup) {
2583-
spiGroupIdent = spiGroups[0];
2584-
}
2585-
auto availability = AvailabilityInference::annotatedAvailableRangeForAttr(
2586-
SA, M.getSwiftModule()->getASTContext());
2587-
targetSILFunction->addSpecializeAttr(SILSpecializeAttr::create(
2588-
M, SA->getSpecializedSignature(), SA->isExported(), kind, nullptr,
2589-
spiGroupIdent, vd->getModuleContext(), availability));
2590-
}
2591-
}
2592-
}
2593-
25942555
void swift::trySpecializeApplyOfGeneric(
25952556
SILOptFunctionBuilder &FuncBuilder,
25962557
ApplySite Apply, DeadInstructionSet &DeadApplies,
@@ -2646,12 +2607,6 @@ void swift::trySpecializeApplyOfGeneric(
26462607
SILFunction *prespecializedF = nullptr;
26472608
ReabstractionInfo prespecializedReInfo;
26482609

2649-
FuncBuilder.getModule().performOnceForPrespecializedImportedExtensions(
2650-
[&FuncBuilder](AbstractFunctionDecl *pre) {
2651-
transferSpecializeAttributeTargets(FuncBuilder.getModule(), FuncBuilder,
2652-
pre);
2653-
});
2654-
26552610
if ((prespecializedF = usePrespecialized(FuncBuilder, Apply, RefF, ReInfo,
26562611
prespecializedReInfo))) {
26572612
ReInfo = prespecializedReInfo;

test/ModuleInterface/attrs.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,12 @@
1717
// CHECK-NEXT: public var y: Swift.Int
1818
public var y: Int
1919
} // CHECK-NEXT: {{^}$}}
20+
21+
public func someGenericFunction<T>(_ t: T) -> Int { return 0 }
22+
23+
// CHECK: @_specialize(exported: true, kind: full, target: someGenericFunction(_:), where T == Swift.Int)
24+
// CHECK: internal func __specialize_someGenericFunction<T>(_ t: T)
25+
@_specialize(exported: true, target: someGenericFunction(_:), where T == Int)
26+
internal func __specialize_someGenericFunction<T>(_ t: T) -> Int {
27+
fatalError("don't call")
28+
}

test/SILOptimizer/Inputs/cross-module/cross-module.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public struct Container {
1717
var arr = Array<Base>()
1818
arr.append(Base())
1919
print(arr)
20+
dontBlockSerialization(arr)
2021
return t
2122
}
2223

test/SILOptimizer/Inputs/cross-module/cross-submodule.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,9 @@ public func genericSubmoduleFunc<T>(_ t: T) {
1010
printit(t)
1111
}
1212

13+
@_specialize(exported: true, where T == Int)
14+
@inlinable
15+
@inline(never)
16+
public func dontBlockSerialization<T>(_ t: T) {
17+
print(t)
18+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
public func someFunc<T>(_ t: T) {
2+
print(t)
3+
}
4+
5+
@_specialize(exported: true, target: someFunc(_:), where T == Int)
6+
@usableFromInline
7+
func __specialize_someFunc<T>(_: T) {}

test/SILOptimizer/eager_specialize.sil

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,24 @@ bb0(%0 : $*T):
848848
return %8 : $Builtin.Int64
849849
}
850850

851+
// Don't specialize `shared` definitions they are imported from another module.
852+
// CHECK-NOT: sil @$s24testDontSpecializeSharedSi_Ts5
853+
sil shared [_specialize exported: true, kind: full, where T == Int] @testDontSpecializeShared : $@convention(thin) <T>(@in T) -> () {
854+
bb(%0: $*T):
855+
destroy_addr %0 : $*T
856+
%t = tuple()
857+
return %t : $()
858+
}
859+
860+
// But do specialize `shared` definitions when they are target from another // function.
861+
// CHECK: sil @$s24testDontSpecializeSharedSd_Ts5
862+
sil shared [_specialize exported: true, kind: full, target: "testDontSpecializeShared" ,where T == Double] @butSpecializeWhenTargetIsPresent : $@convention(thin) <T>(@in T) -> () {
863+
bb(%0: $*T):
864+
destroy_addr %0 : $*T
865+
%t = tuple()
866+
return %t : $()
867+
}
868+
851869
sil_vtable ClassUsingThrowingP {
852870
#ClassUsingThrowingP.init!allocator: (ClassUsingThrowingP.Type) -> () -> ClassUsingThrowingP : @$s34eager_specialize_throwing_function19ClassUsingThrowingPCACycfC // ClassUsingThrowingP.__allocating_init()
853871
#ClassUsingThrowingP.init!initializer: (ClassUsingThrowingP.Type) -> () -> ClassUsingThrowingP : @$s34eager_specialize_throwing_function19ClassUsingThrowingPCACycfc // ClassUsingThrowingP.init()
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -module-name A -emit-module-path %t/A.swiftmodule %S/Inputs/prespecialize_import_module.swift
3+
// RUN: %target-swift-frontend -O -emit-sil -module-name B -I %t %s | %FileCheck %s
4+
import A
5+
6+
// CHECK-LABEL: sil{{.*}} @$s1B4testyyF
7+
public func test() {
8+
// CHECK: s1A8someFuncyyxlFSi_Ts5
9+
someFunc(5)
10+
}
11+
// CHECK: end sil function '$s1B4testyyF'

test/Serialization/serialize_attr.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,6 @@ public class CC<T : PP> {
7979
}
8080
}
8181

82-
// CHECK-DAG: sil [serialized] [_specialize exported: false, kind: full, where T == Int, U == Float] [canonical] [ossa] @$s14serialize_attr14specializeThis_1uyx_q_tr0_lF : $@convention(thin) <T, U> (@in_guaranteed T, @in_guaranteed U) -> () {
82+
// CHECK-DAG: sil [serialized] [canonical] [ossa] @$s14serialize_attr14specializeThis_1uyx_q_tr0_lF : $@convention(thin) <T, U> (@in_guaranteed T, @in_guaranteed U) -> () {
8383

84-
// CHECK-DAG: sil [serialized] [noinline] [_specialize exported: false, kind: full, where T == RR, U == SS] [canonical] [ossa] @$s14serialize_attr2CCC3foo_1gqd___AA2GGVyxGtqd___AHtAA2QQRd__lF : $@convention(method) <T where T : PP><U where U : QQ> (@in_guaranteed U, GG<T>, @guaranteed CC<T>) -> (@out U, GG<T>) {
84+
// CHECK-DAG: sil [serialized] [noinline] [canonical] [ossa] @$s14serialize_attr2CCC3foo_1gqd___AA2GGVyxGtqd___AHtAA2QQRd__lF : $@convention(method) <T where T : PP><U where U : QQ> (@in_guaranteed U, GG<T>, @guaranteed CC<T>) -> (@out U, GG<T>) {

test/sil-passpipeline-dump/basic.test-sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22

33
// CHECK: ---
44
// CHECK: name: Non-Diagnostic Mandatory Optimizations
5-
// CHECK: passes: [ "for-each-loop-unroll", "mandatory-combine",
6-
// CHECK: "mandatory-arc-opts" ]
5+
// CHECK: passes: [ "for-each-loop-unroll", "mandatory-combine", "mandatory-arc-opts",
6+
// CHECK: "onone-prespecializer" ]
77
// CHECK: ---
88
// CHECK: name: Serialization
99
// CHECK: passes: [ "serialize-sil", "sil-moved-async-var-dbginfo-propagator",
1010
// CHECK-NEXT: "ownership-model-eliminator" ]
1111
// CHECK: ---
1212
// CHECK: name: Rest of Onone
13-
// CHECK: passes: [ "use-prespecialized", "onone-prespecializer", "sil-debuginfo-gen" ]
13+
// CHECK: passes: [ "use-prespecialized", "sil-debuginfo-gen" ]
1414
// CHECK: ...

0 commit comments

Comments
 (0)