Skip to content

Commit 0f606e7

Browse files
authored
Merge pull request #73478 from apple/elsh/pcmo-res
Support generating loadable types in serialized function when package-cmo is enabled.
2 parents 9a2e245 + 9b28969 commit 0f606e7

File tree

6 files changed

+96
-53
lines changed

6 files changed

+96
-53
lines changed

include/swift/SIL/SILFunction.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -779,11 +779,7 @@ class SILFunction
779779
return getLoweredFunctionType()->getRepresentation();
780780
}
781781

782-
ResilienceExpansion getResilienceExpansion() const {
783-
return (isSerialized()
784-
? ResilienceExpansion::Minimal
785-
: ResilienceExpansion::Maximal);
786-
}
782+
ResilienceExpansion getResilienceExpansion() const;
787783

788784
// Returns the type expansion context to be used inside this function.
789785
TypeExpansionContext getTypeExpansionContext() const {

lib/SIL/IR/SILFunction.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,23 @@ bool SILFunction::isNoReturnFunction(TypeExpansionContext context) const {
517517
.isNoReturnFunction(getModule(), context);
518518
}
519519

520+
ResilienceExpansion SILFunction::getResilienceExpansion() const {
521+
// If package serialization is enabled, we can safely
522+
// assume that the defining .swiftmodule is built from
523+
// source and is never used outside of its package;
524+
// Even if the module is built resiliently, return
525+
// maximal expansion here so aggregate types can be
526+
// loadable in the same resilient domain (from a client
527+
// module in the same package.
528+
if (getModule().getSwiftModule()->serializePackageEnabled() &&
529+
getModule().getSwiftModule()->isResilient())
530+
return ResilienceExpansion::Maximal;
531+
532+
return (isSerialized()
533+
? ResilienceExpansion::Minimal
534+
: ResilienceExpansion::Maximal);
535+
}
536+
520537
const TypeLowering &
521538
SILFunction::getTypeLowering(AbstractionPattern orig, Type subst) {
522539
return getModule().Types.getTypeLowering(orig, subst,

lib/SIL/IR/TypeLowering.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2324,17 +2324,25 @@ namespace {
23242324
if (D->isResilient()) {
23252325
// If the type is resilient and defined in our module, make a note of
23262326
// that, since our lowering now depends on the resilience expansion.
2327-
bool sameModule = (D->getModuleContext() == &TC.M);
2327+
auto declModule = D->getModuleContext();
2328+
bool sameModule = (declModule == &TC.M);
23282329
if (sameModule)
23292330
properties.addSubobject(RecursiveProperties::forResilient());
23302331

23312332
// If the type is in a different module, or if we're using a minimal
23322333
// expansion, the type is address only and completely opaque to us.
2334+
// However, this is not true if the different module is in the same
2335+
// package and package serialization is enabled (resilience expansion
2336+
// is maximal), e.g. in case of package-cmo.
23332337
//
23342338
// Note: if the type is in a different module, the lowering does
23352339
// not depend on the resilience expansion, so we do not need to set
23362340
// the isResilient() flag above.
2337-
if (!sameModule || Expansion.getResilienceExpansion() ==
2341+
bool serializedPackage = declModule->inSamePackage(&TC.M) &&
2342+
declModule->isResilient() &&
2343+
declModule->serializePackageEnabled();
2344+
if ((!sameModule && !serializedPackage) ||
2345+
Expansion.getResilienceExpansion() ==
23382346
ResilienceExpansion::Minimal) {
23392347
properties.addSubobject(RecursiveProperties::forOpaque());
23402348
return true;

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -158,22 +158,9 @@ namespace {
158158
template <typename DeclType>
159159
bool checkResilience(DeclType *D, ModuleDecl *M,
160160
ResilienceExpansion expansion) {
161-
auto refDeclModule = D->getModuleContext();
162161
// Explicitly bypassed for debugging with `bypass-resilience-checks`
163-
if (refDeclModule->getBypassResilience())
162+
if (D->getModuleContext()->getBypassResilience())
164163
return false;
165-
166-
// If package serialization is enabled with `experimental-package-cmo`,
167-
// decls can be serialized in a resiliently built module. In such case,
168-
// a direct access should be allowed.
169-
auto packageSerialized = expansion == ResilienceExpansion::Minimal &&
170-
refDeclModule->isResilient() &&
171-
refDeclModule->allowNonResilientAccess() &&
172-
refDeclModule->serializePackageEnabled() &&
173-
refDeclModule->inSamePackage(M);
174-
if (packageSerialized)
175-
return false;
176-
177164
return D->isResilient(M, expansion);
178165
}
179166

lib/SILOptimizer/IPO/CrossModuleOptimization.cpp

Lines changed: 4 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class CrossModuleOptimization {
8484

8585
bool canSerializeGlobal(SILGlobalVariable *global);
8686

87-
bool canSerializeType(SILType type, TypeExpansionContext typeExpCtx);
87+
bool canSerializeType(SILType type);
8888

8989
bool canUseFromInline(DeclContext *declCtxt);
9090

@@ -331,14 +331,12 @@ bool CrossModuleOptimization::canSerializeFunction(
331331
bool CrossModuleOptimization::canSerializeInstruction(
332332
SILInstruction *inst, FunctionFlags &canSerializeFlags, int maxDepth) {
333333
// First check if any result or operand types prevent serialization.
334-
auto typeExpCtx = inst->getFunction()->getTypeExpansionContext();
335-
336334
for (SILValue result : inst->getResults()) {
337-
if (!canSerializeType(result->getType(), typeExpCtx))
335+
if (!canSerializeType(result->getType()))
338336
return false;
339337
}
340338
for (Operand &op : inst->getAllOperands()) {
341-
if (!canSerializeType(op.get()->getType(), typeExpCtx))
339+
if (!canSerializeType(op.get()->getType()))
342340
return false;
343341
}
344342

@@ -437,23 +435,11 @@ bool CrossModuleOptimization::canSerializeGlobal(SILGlobalVariable *global) {
437435
return true;
438436
}
439437

440-
bool CrossModuleOptimization::canSerializeType(SILType type,
441-
TypeExpansionContext typeExpCtx) {
438+
bool CrossModuleOptimization::canSerializeType(SILType type) {
442439
auto iter = typesChecked.find(type);
443440
if (iter != typesChecked.end())
444441
return iter->getSecond();
445442

446-
if (M.getSwiftModule()->isResilient()) {
447-
auto minResilientCtx = TypeExpansionContext(ResilienceExpansion::Minimal,
448-
typeExpCtx.getContext(),
449-
typeExpCtx.isWholeModuleContext());
450-
auto loadableInMinResilientCtx = M.Types.getTypeLowering(type, minResilientCtx).isLoadable();
451-
if (!loadableInMinResilientCtx) {
452-
typesChecked[type] = false;
453-
return false;
454-
}
455-
}
456-
457443
bool success = !type.getASTType().findIf(
458444
[this](Type rawSubType) {
459445
CanType subType = rawSubType->getCanonicalType();

test/SILOptimizer/package-cmo-resilient-mode.swift

Lines changed: 63 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -172,43 +172,73 @@ print(prevPkgData)
172172

173173
//--- Lib.swift
174174

175-
// FIXME: handle struct_element_addr %field in resilient mode; requires non-resilience in SIL verify.
176-
// CHECK-RES-NOT: s3Lib9PubStructV6fooVarSivg
177-
// CHECK-RES-NOT: s3Lib9PkgStructV6fooVarSivg
178-
179-
// FIXME: handle `struct $PubStruct` in resilient mode; PubStruct is by-address, so fails in IsLodableOrOpaque check.
180-
// CHECK-RES-NOT: s3Lib9PubStructV6fooVarSivs
181-
// CHECK-RES-NOT: s3Lib9PkgStructV6fooVarSivs
182-
183175
public struct PubStruct {
176+
// PubStruct.foovar.getter
177+
// CHECK-RES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructV6fooVarSivg : $@convention(method) (@in_guaranteed PubStruct) -> Int {
184178
// CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV6fooVarSivg : $@convention(method) (PubStruct) -> Int
185-
// CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV6fooVarSivM : $@yield_once @convention(method) (@inout PubStruct) -> @yields @inout Int {
179+
// CHECK-RES-DAG: [[FIELD:%.*]] = struct_element_addr %0 : $*PubStruct, #PubStruct.fooVar
180+
// CHECK-RES-DAG: load [[FIELD]] : $*Int
181+
// CHECK-NONRES-DAG = struct_extract %0 : $PubStruct, #PubStruct.fooVar
182+
183+
// PubStruct.foovar.setter
184+
// CHECK-RES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructV6fooVarSivs : $@convention(method) (Int, @inout PubStruct) -> () {
186185
// CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV6fooVarSivs : $@convention(method) (Int, @inout PubStruct) -> () {
186+
187+
/// NOTE: `struct $PubStruct` in [serialized] function is legal only if package serialization is enabled.
188+
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct $PubStruct
189+
// CHECK-RES-DAG: store [[FIELD]] to {{.*}} : $*PubStruct
190+
// CHECK-NONRES-DAG: store [[FIELD]] to [trivial] {{.*}} : $*PubStruct
191+
192+
// PubStruct.foovar.modify
193+
// CHECK-RES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructV6fooVarSivM : $@yield_once @convention(method) (@inout PubStruct) -> @yields @inout Int {
194+
// CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV6fooVarSivM : $@yield_once @convention(method) (@inout PubStruct) -> @yields @inout Int {
195+
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct_element_addr %0 : $*PubStruct, #PubStruct.fooVar
196+
// CHECK-COMMON-DAG: yield [[FIELD]]
187197
public var fooVar: Int
188198

189199
public init(_ arg: Int) {
200+
// CHECK-RES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructVyACSicfC : $@convention(method) (Int, @thin PubStruct.Type) -> @out PubStruct {
190201
// CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructVyACSicfC : $@convention(method) (Int, @thin PubStruct.Type) -> PubStruct {
202+
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct $PubStruct
203+
// CHECK-RES-DAG: store [[FIELD]] to %0 : $*PubStruct
204+
// CHECK-NONRES-DAG: return [[FIELD]] : $PubStruct
191205
fooVar = arg
192206
}
193207
public func f() {
208+
// CHECK-RES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructV1fyyF : $@convention(method) (@in_guaranteed PubStruct) -> () {
194209
// CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructV1fyyF : $@convention(method) (PubStruct) -> () {
195210
print(fooVar)
196211
}
197212
}
198213

199214
public func runPub(_ arg: PubStruct) {
215+
// CHECK-RES-DAG: sil [serialized] [canonical] @$s3Lib6runPubyyAA0C6StructVF : $@convention(thin) (@in_guaranteed PubStruct) -> () {
200216
// CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib6runPubyyAA0C6StructVF : $@convention(thin) (PubStruct) -> () {
201217
print(arg)
202218
}
203219

204220
@frozen
205221
public struct FrPubStruct {
206-
// CHECK-COMMON-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV6fooVarSivM : $@yield_once @convention(method) (@inout FrPubStruct) -> @yields @inout Int {
222+
// FrPubStruct.fooVar.getter
207223
// CHECK-COMMON-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV6fooVarSivg : $@convention(method) (FrPubStruct) -> Int {
224+
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct_extract %0 : $FrPubStruct, #FrPubStruct.fooVar
225+
// CHECK-COMMON-DAG: return [[FIELD]] : $Int
226+
227+
// FrPubStruct.fooVar.setter
208228
// CHECK-COMMON-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV6fooVarSivs : $@convention(method) (Int, @inout FrPubStruct) -> () {
229+
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct $FrPubStruct
230+
// CHECK-COMMON-DAG: store [[FIELD]] to [trivial] {{.*}} : $*FrPubStruct
231+
232+
// FrPubStruct.fooVar.modify
233+
// CHECK-COMMON-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV6fooVarSivM : $@yield_once @convention(method) (@inout FrPubStruct) -> @yields @inout Int {
234+
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct_element_addr %0 : $*FrPubStruct, #FrPubStruct.fooVar
235+
// CHECK-COMMON-DAG: yield [[FIELD]]
209236
public var fooVar: Int
237+
210238
public init(_ arg: Int) {
211239
// CHECK-COMMON-DAG: sil [serialized] [canonical] @$s3Lib11FrPubStructVyACSicfC : $@convention(method) (Int, @thin FrPubStruct.Type) -> FrPubStruct {
240+
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct $FrPubStruct
241+
// CHECK-COMMON-DAG: return [[FIELD]] : $FrPubStruct
212242
fooVar = arg
213243
}
214244
public func f() {
@@ -222,25 +252,44 @@ public func runFrPub(_ arg: FrPubStruct) {
222252
}
223253

224254
package struct PkgStruct {
225-
// fooVar.getter
255+
// PkgStruct.fooVar.getter
256+
// CHECK-RES-DAG: sil package [serialized] [canonical] @$s3Lib9PkgStructV6fooVarSivg : $@convention(method) (@in_guaranteed PkgStruct) -> Int {
226257
// CHECK-NONRES-DAG: sil package [transparent] [serialized] [canonical] [ossa] @$s3Lib9PkgStructV6fooVarSivg : $@convention(method) (PkgStruct) -> Int {
227-
// fooVar.modify
228-
// CHECK-NONRES-DAG: sil package [transparent] [serialized] [canonical] [ossa] @$s3Lib9PkgStructV6fooVarSivM : $@yield_once @convention(method) (@inout PkgStruct) -> @yields @inout Int {
229-
// fooVar.setter
258+
// CHECK-RES-DAG: [[FIELD:%.*]] = struct_element_addr %0 : $*PkgStruct, #PkgStruct.fooVar
259+
// CHECK-RES-DAG: load [[FIELD]] : $*Int
260+
// CHECK-NONRES-DAG = struct_extract %0 : $PkgStruct, #PkgStruct.fooVar
261+
262+
// PkgStruct.fooVar.setter
263+
// CHECK-RES-DAG: sil package [serialized] [canonical] @$s3Lib9PkgStructV6fooVarSivs : $@convention(method) (Int, @inout PkgStruct) -> () {
230264
// CHECK-NONRES-DAG: sil package [transparent] [serialized] [canonical] [ossa] @$s3Lib9PkgStructV6fooVarSivs : $@convention(method) (Int, @inout PkgStruct) -> () {
265+
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct $PkgStruct
266+
// CHECK-RES-DAG: store [[FIELD]] to {{.*}} : $*PkgStruct
267+
// CHECK-NONRES-DAG: store [[FIELD]] to [trivial] {{.*}} : $*PkgStruct
268+
269+
// PkgStruct.fooVar.modify
270+
// CHECK-RES-DAG: sil package [serialized] [canonical] @$s3Lib9PkgStructV6fooVarSivM : $@yield_once @convention(method) (@inout PkgStruct) -> @yields @inout Int {
271+
// CHECK-NONRES-DAG: sil package [transparent] [serialized] [canonical] [ossa] @$s3Lib9PkgStructV6fooVarSivM : $@yield_once @convention(method) (@inout PkgStruct) -> @yields @inout Int {
272+
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct_element_addr %0 : $*PkgStruct, #PkgStruct.fooVar
273+
// CHECK-COMMON-DAG: yield [[FIELD]]
231274
package var fooVar: Int
232275

233276
package init(_ arg: Int) {
277+
// CHECK-RES-DAG: sil package [serialized] [canonical] @$s3Lib9PkgStructVyACSicfC : $@convention(method) (Int, @thin PkgStruct.Type) -> @out PkgStruct {
234278
// CHECK-NONRES-DAG: sil package [serialized] [canonical] @$s3Lib9PkgStructVyACSicfC : $@convention(method) (Int, @thin PkgStruct.Type) -> PkgStruct {
279+
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct $PkgStruct
280+
// CHECK-RES-DAG: store [[FIELD]] to %0 : $*PkgStruct
281+
// CHECK-NONRES-DAG: return [[FIELD]] : $PkgStruct
235282
fooVar = arg
236283
}
237284
package func f() {
285+
// CHECK-RES-DAG: sil package [serialized] [canonical] @$s3Lib9PkgStructV1fyyF : $@convention(method) (@in_guaranteed PkgStruct) -> () {
238286
// CHECK-NONRES-DAG: sil package [serialized] [canonical] @$s3Lib9PkgStructV1fyyF : $@convention(method) (PkgStruct) -> () {
239287
print(fooVar)
240288
}
241289
}
242290

243291
package func runPkg(_ arg: PkgStruct) {
292+
// CHECK-RES-DAG: sil package [serialized] [canonical] @$s3Lib6runPkgyyAA0C6StructVF : $@convention(thin) (@in_guaranteed PkgStruct) -> () {
244293
// CHECK-NONRES-DAG: sil package [serialized] [canonical] @$s3Lib6runPkgyyAA0C6StructVF : $@convention(thin) (PkgStruct) -> () {
245294
print(arg)
246295
}

0 commit comments

Comments
 (0)