mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #73478 from apple/elsh/pcmo-res
Support generating loadable types in serialized function when package-cmo is enabled.
This commit is contained in:
@@ -779,11 +779,7 @@ public:
|
||||
return getLoweredFunctionType()->getRepresentation();
|
||||
}
|
||||
|
||||
ResilienceExpansion getResilienceExpansion() const {
|
||||
return (isSerialized()
|
||||
? ResilienceExpansion::Minimal
|
||||
: ResilienceExpansion::Maximal);
|
||||
}
|
||||
ResilienceExpansion getResilienceExpansion() const;
|
||||
|
||||
// Returns the type expansion context to be used inside this function.
|
||||
TypeExpansionContext getTypeExpansionContext() const {
|
||||
|
||||
@@ -517,6 +517,23 @@ bool SILFunction::isNoReturnFunction(TypeExpansionContext context) const {
|
||||
.isNoReturnFunction(getModule(), context);
|
||||
}
|
||||
|
||||
ResilienceExpansion SILFunction::getResilienceExpansion() const {
|
||||
// If package serialization is enabled, we can safely
|
||||
// assume that the defining .swiftmodule is built from
|
||||
// source and is never used outside of its package;
|
||||
// Even if the module is built resiliently, return
|
||||
// maximal expansion here so aggregate types can be
|
||||
// loadable in the same resilient domain (from a client
|
||||
// module in the same package.
|
||||
if (getModule().getSwiftModule()->serializePackageEnabled() &&
|
||||
getModule().getSwiftModule()->isResilient())
|
||||
return ResilienceExpansion::Maximal;
|
||||
|
||||
return (isSerialized()
|
||||
? ResilienceExpansion::Minimal
|
||||
: ResilienceExpansion::Maximal);
|
||||
}
|
||||
|
||||
const TypeLowering &
|
||||
SILFunction::getTypeLowering(AbstractionPattern orig, Type subst) {
|
||||
return getModule().Types.getTypeLowering(orig, subst,
|
||||
|
||||
@@ -2324,17 +2324,25 @@ namespace {
|
||||
if (D->isResilient()) {
|
||||
// If the type is resilient and defined in our module, make a note of
|
||||
// that, since our lowering now depends on the resilience expansion.
|
||||
bool sameModule = (D->getModuleContext() == &TC.M);
|
||||
auto declModule = D->getModuleContext();
|
||||
bool sameModule = (declModule == &TC.M);
|
||||
if (sameModule)
|
||||
properties.addSubobject(RecursiveProperties::forResilient());
|
||||
|
||||
// If the type is in a different module, or if we're using a minimal
|
||||
// expansion, the type is address only and completely opaque to us.
|
||||
// However, this is not true if the different module is in the same
|
||||
// package and package serialization is enabled (resilience expansion
|
||||
// is maximal), e.g. in case of package-cmo.
|
||||
//
|
||||
// Note: if the type is in a different module, the lowering does
|
||||
// not depend on the resilience expansion, so we do not need to set
|
||||
// the isResilient() flag above.
|
||||
if (!sameModule || Expansion.getResilienceExpansion() ==
|
||||
bool serializedPackage = declModule->inSamePackage(&TC.M) &&
|
||||
declModule->isResilient() &&
|
||||
declModule->serializePackageEnabled();
|
||||
if ((!sameModule && !serializedPackage) ||
|
||||
Expansion.getResilienceExpansion() ==
|
||||
ResilienceExpansion::Minimal) {
|
||||
properties.addSubobject(RecursiveProperties::forOpaque());
|
||||
return true;
|
||||
|
||||
@@ -158,22 +158,9 @@ namespace {
|
||||
template <typename DeclType>
|
||||
bool checkResilience(DeclType *D, ModuleDecl *M,
|
||||
ResilienceExpansion expansion) {
|
||||
auto refDeclModule = D->getModuleContext();
|
||||
// Explicitly bypassed for debugging with `bypass-resilience-checks`
|
||||
if (refDeclModule->getBypassResilience())
|
||||
if (D->getModuleContext()->getBypassResilience())
|
||||
return false;
|
||||
|
||||
// If package serialization is enabled with `experimental-package-cmo`,
|
||||
// decls can be serialized in a resiliently built module. In such case,
|
||||
// a direct access should be allowed.
|
||||
auto packageSerialized = expansion == ResilienceExpansion::Minimal &&
|
||||
refDeclModule->isResilient() &&
|
||||
refDeclModule->allowNonResilientAccess() &&
|
||||
refDeclModule->serializePackageEnabled() &&
|
||||
refDeclModule->inSamePackage(M);
|
||||
if (packageSerialized)
|
||||
return false;
|
||||
|
||||
return D->isResilient(M, expansion);
|
||||
}
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@ private:
|
||||
|
||||
bool canSerializeGlobal(SILGlobalVariable *global);
|
||||
|
||||
bool canSerializeType(SILType type, TypeExpansionContext typeExpCtx);
|
||||
bool canSerializeType(SILType type);
|
||||
|
||||
bool canUseFromInline(DeclContext *declCtxt);
|
||||
|
||||
@@ -331,14 +331,12 @@ bool CrossModuleOptimization::canSerializeFunction(
|
||||
bool CrossModuleOptimization::canSerializeInstruction(
|
||||
SILInstruction *inst, FunctionFlags &canSerializeFlags, int maxDepth) {
|
||||
// First check if any result or operand types prevent serialization.
|
||||
auto typeExpCtx = inst->getFunction()->getTypeExpansionContext();
|
||||
|
||||
for (SILValue result : inst->getResults()) {
|
||||
if (!canSerializeType(result->getType(), typeExpCtx))
|
||||
if (!canSerializeType(result->getType()))
|
||||
return false;
|
||||
}
|
||||
for (Operand &op : inst->getAllOperands()) {
|
||||
if (!canSerializeType(op.get()->getType(), typeExpCtx))
|
||||
if (!canSerializeType(op.get()->getType()))
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -437,23 +435,11 @@ bool CrossModuleOptimization::canSerializeGlobal(SILGlobalVariable *global) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CrossModuleOptimization::canSerializeType(SILType type,
|
||||
TypeExpansionContext typeExpCtx) {
|
||||
bool CrossModuleOptimization::canSerializeType(SILType type) {
|
||||
auto iter = typesChecked.find(type);
|
||||
if (iter != typesChecked.end())
|
||||
return iter->getSecond();
|
||||
|
||||
if (M.getSwiftModule()->isResilient()) {
|
||||
auto minResilientCtx = TypeExpansionContext(ResilienceExpansion::Minimal,
|
||||
typeExpCtx.getContext(),
|
||||
typeExpCtx.isWholeModuleContext());
|
||||
auto loadableInMinResilientCtx = M.Types.getTypeLowering(type, minResilientCtx).isLoadable();
|
||||
if (!loadableInMinResilientCtx) {
|
||||
typesChecked[type] = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool success = !type.getASTType().findIf(
|
||||
[this](Type rawSubType) {
|
||||
CanType subType = rawSubType->getCanonicalType();
|
||||
|
||||
@@ -172,43 +172,73 @@ print(prevPkgData)
|
||||
|
||||
//--- Lib.swift
|
||||
|
||||
// FIXME: handle struct_element_addr %field in resilient mode; requires non-resilience in SIL verify.
|
||||
// CHECK-RES-NOT: s3Lib9PubStructV6fooVarSivg
|
||||
// CHECK-RES-NOT: s3Lib9PkgStructV6fooVarSivg
|
||||
|
||||
// FIXME: handle `struct $PubStruct` in resilient mode; PubStruct is by-address, so fails in IsLodableOrOpaque check.
|
||||
// CHECK-RES-NOT: s3Lib9PubStructV6fooVarSivs
|
||||
// CHECK-RES-NOT: s3Lib9PkgStructV6fooVarSivs
|
||||
|
||||
public struct PubStruct {
|
||||
// PubStruct.foovar.getter
|
||||
// CHECK-RES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructV6fooVarSivg : $@convention(method) (@in_guaranteed PubStruct) -> Int {
|
||||
// CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV6fooVarSivg : $@convention(method) (PubStruct) -> Int
|
||||
// CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV6fooVarSivM : $@yield_once @convention(method) (@inout PubStruct) -> @yields @inout Int {
|
||||
// CHECK-RES-DAG: [[FIELD:%.*]] = struct_element_addr %0 : $*PubStruct, #PubStruct.fooVar
|
||||
// CHECK-RES-DAG: load [[FIELD]] : $*Int
|
||||
// CHECK-NONRES-DAG = struct_extract %0 : $PubStruct, #PubStruct.fooVar
|
||||
|
||||
// PubStruct.foovar.setter
|
||||
// CHECK-RES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructV6fooVarSivs : $@convention(method) (Int, @inout PubStruct) -> () {
|
||||
// CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV6fooVarSivs : $@convention(method) (Int, @inout PubStruct) -> () {
|
||||
|
||||
/// NOTE: `struct $PubStruct` in [serialized] function is legal only if package serialization is enabled.
|
||||
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct $PubStruct
|
||||
// CHECK-RES-DAG: store [[FIELD]] to {{.*}} : $*PubStruct
|
||||
// CHECK-NONRES-DAG: store [[FIELD]] to [trivial] {{.*}} : $*PubStruct
|
||||
|
||||
// PubStruct.foovar.modify
|
||||
// CHECK-RES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructV6fooVarSivM : $@yield_once @convention(method) (@inout PubStruct) -> @yields @inout Int {
|
||||
// CHECK-NONRES-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib9PubStructV6fooVarSivM : $@yield_once @convention(method) (@inout PubStruct) -> @yields @inout Int {
|
||||
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct_element_addr %0 : $*PubStruct, #PubStruct.fooVar
|
||||
// CHECK-COMMON-DAG: yield [[FIELD]]
|
||||
public var fooVar: Int
|
||||
|
||||
public init(_ arg: Int) {
|
||||
// CHECK-RES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructVyACSicfC : $@convention(method) (Int, @thin PubStruct.Type) -> @out PubStruct {
|
||||
// CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructVyACSicfC : $@convention(method) (Int, @thin PubStruct.Type) -> PubStruct {
|
||||
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct $PubStruct
|
||||
// CHECK-RES-DAG: store [[FIELD]] to %0 : $*PubStruct
|
||||
// CHECK-NONRES-DAG: return [[FIELD]] : $PubStruct
|
||||
fooVar = arg
|
||||
}
|
||||
public func f() {
|
||||
// CHECK-RES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructV1fyyF : $@convention(method) (@in_guaranteed PubStruct) -> () {
|
||||
// CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib9PubStructV1fyyF : $@convention(method) (PubStruct) -> () {
|
||||
print(fooVar)
|
||||
}
|
||||
}
|
||||
|
||||
public func runPub(_ arg: PubStruct) {
|
||||
// CHECK-RES-DAG: sil [serialized] [canonical] @$s3Lib6runPubyyAA0C6StructVF : $@convention(thin) (@in_guaranteed PubStruct) -> () {
|
||||
// CHECK-NONRES-DAG: sil [serialized] [canonical] @$s3Lib6runPubyyAA0C6StructVF : $@convention(thin) (PubStruct) -> () {
|
||||
print(arg)
|
||||
}
|
||||
|
||||
@frozen
|
||||
public struct FrPubStruct {
|
||||
// CHECK-COMMON-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV6fooVarSivM : $@yield_once @convention(method) (@inout FrPubStruct) -> @yields @inout Int {
|
||||
// FrPubStruct.fooVar.getter
|
||||
// CHECK-COMMON-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV6fooVarSivg : $@convention(method) (FrPubStruct) -> Int {
|
||||
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct_extract %0 : $FrPubStruct, #FrPubStruct.fooVar
|
||||
// CHECK-COMMON-DAG: return [[FIELD]] : $Int
|
||||
|
||||
// FrPubStruct.fooVar.setter
|
||||
// CHECK-COMMON-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV6fooVarSivs : $@convention(method) (Int, @inout FrPubStruct) -> () {
|
||||
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct $FrPubStruct
|
||||
// CHECK-COMMON-DAG: store [[FIELD]] to [trivial] {{.*}} : $*FrPubStruct
|
||||
|
||||
// FrPubStruct.fooVar.modify
|
||||
// CHECK-COMMON-DAG: sil [transparent] [serialized] [canonical] [ossa] @$s3Lib11FrPubStructV6fooVarSivM : $@yield_once @convention(method) (@inout FrPubStruct) -> @yields @inout Int {
|
||||
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct_element_addr %0 : $*FrPubStruct, #FrPubStruct.fooVar
|
||||
// CHECK-COMMON-DAG: yield [[FIELD]]
|
||||
public var fooVar: Int
|
||||
|
||||
public init(_ arg: Int) {
|
||||
// CHECK-COMMON-DAG: sil [serialized] [canonical] @$s3Lib11FrPubStructVyACSicfC : $@convention(method) (Int, @thin FrPubStruct.Type) -> FrPubStruct {
|
||||
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct $FrPubStruct
|
||||
// CHECK-COMMON-DAG: return [[FIELD]] : $FrPubStruct
|
||||
fooVar = arg
|
||||
}
|
||||
public func f() {
|
||||
@@ -222,25 +252,44 @@ public func runFrPub(_ arg: FrPubStruct) {
|
||||
}
|
||||
|
||||
package struct PkgStruct {
|
||||
// fooVar.getter
|
||||
// PkgStruct.fooVar.getter
|
||||
// CHECK-RES-DAG: sil package [serialized] [canonical] @$s3Lib9PkgStructV6fooVarSivg : $@convention(method) (@in_guaranteed PkgStruct) -> Int {
|
||||
// CHECK-NONRES-DAG: sil package [transparent] [serialized] [canonical] [ossa] @$s3Lib9PkgStructV6fooVarSivg : $@convention(method) (PkgStruct) -> Int {
|
||||
// fooVar.modify
|
||||
// CHECK-NONRES-DAG: sil package [transparent] [serialized] [canonical] [ossa] @$s3Lib9PkgStructV6fooVarSivM : $@yield_once @convention(method) (@inout PkgStruct) -> @yields @inout Int {
|
||||
// fooVar.setter
|
||||
// CHECK-RES-DAG: [[FIELD:%.*]] = struct_element_addr %0 : $*PkgStruct, #PkgStruct.fooVar
|
||||
// CHECK-RES-DAG: load [[FIELD]] : $*Int
|
||||
// CHECK-NONRES-DAG = struct_extract %0 : $PkgStruct, #PkgStruct.fooVar
|
||||
|
||||
// PkgStruct.fooVar.setter
|
||||
// CHECK-RES-DAG: sil package [serialized] [canonical] @$s3Lib9PkgStructV6fooVarSivs : $@convention(method) (Int, @inout PkgStruct) -> () {
|
||||
// CHECK-NONRES-DAG: sil package [transparent] [serialized] [canonical] [ossa] @$s3Lib9PkgStructV6fooVarSivs : $@convention(method) (Int, @inout PkgStruct) -> () {
|
||||
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct $PkgStruct
|
||||
// CHECK-RES-DAG: store [[FIELD]] to {{.*}} : $*PkgStruct
|
||||
// CHECK-NONRES-DAG: store [[FIELD]] to [trivial] {{.*}} : $*PkgStruct
|
||||
|
||||
// PkgStruct.fooVar.modify
|
||||
// CHECK-RES-DAG: sil package [serialized] [canonical] @$s3Lib9PkgStructV6fooVarSivM : $@yield_once @convention(method) (@inout PkgStruct) -> @yields @inout Int {
|
||||
// CHECK-NONRES-DAG: sil package [transparent] [serialized] [canonical] [ossa] @$s3Lib9PkgStructV6fooVarSivM : $@yield_once @convention(method) (@inout PkgStruct) -> @yields @inout Int {
|
||||
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct_element_addr %0 : $*PkgStruct, #PkgStruct.fooVar
|
||||
// CHECK-COMMON-DAG: yield [[FIELD]]
|
||||
package var fooVar: Int
|
||||
|
||||
package init(_ arg: Int) {
|
||||
// CHECK-RES-DAG: sil package [serialized] [canonical] @$s3Lib9PkgStructVyACSicfC : $@convention(method) (Int, @thin PkgStruct.Type) -> @out PkgStruct {
|
||||
// CHECK-NONRES-DAG: sil package [serialized] [canonical] @$s3Lib9PkgStructVyACSicfC : $@convention(method) (Int, @thin PkgStruct.Type) -> PkgStruct {
|
||||
// CHECK-COMMON-DAG: [[FIELD:%.*]] = struct $PkgStruct
|
||||
// CHECK-RES-DAG: store [[FIELD]] to %0 : $*PkgStruct
|
||||
// CHECK-NONRES-DAG: return [[FIELD]] : $PkgStruct
|
||||
fooVar = arg
|
||||
}
|
||||
package func f() {
|
||||
// CHECK-RES-DAG: sil package [serialized] [canonical] @$s3Lib9PkgStructV1fyyF : $@convention(method) (@in_guaranteed PkgStruct) -> () {
|
||||
// CHECK-NONRES-DAG: sil package [serialized] [canonical] @$s3Lib9PkgStructV1fyyF : $@convention(method) (PkgStruct) -> () {
|
||||
print(fooVar)
|
||||
}
|
||||
}
|
||||
|
||||
package func runPkg(_ arg: PkgStruct) {
|
||||
// CHECK-RES-DAG: sil package [serialized] [canonical] @$s3Lib6runPkgyyAA0C6StructVF : $@convention(thin) (@in_guaranteed PkgStruct) -> () {
|
||||
// CHECK-NONRES-DAG: sil package [serialized] [canonical] @$s3Lib6runPkgyyAA0C6StructVF : $@convention(thin) (PkgStruct) -> () {
|
||||
print(arg)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user