Support Package CMO

* Add a new flag -experimental-package-cmo that requires -experimental-allow-non-resilient-access.
* Support serializing package decls for CMO in package if enabled.
* Only applies to default mode CMO.
* Unlike the existing CMO, package CMO can be built with -enable-library-evolution as package
modules are required to be built together in the same project.
* Create hasPublicOrPackageVisibility to opt in for package decls; needed for CMO, SILVerifier,
and other call sites that verify or determine codegen.

Resolves rdar://121976014
This commit is contained in:
Ellie Shin
2024-03-06 20:46:22 -08:00
parent 8df1abe111
commit a3250e426d
14 changed files with 325 additions and 21 deletions

View File

@@ -161,6 +161,17 @@ public:
}
};
static bool isVisible(SILLinkage linkage, SILOptions options) {
if (options.EnableSerializePackage)
return linkage == SILLinkage::Public || linkage == SILLinkage::Package;
return linkage == SILLinkage::Public;
}
static bool isVisible(AccessLevel accessLevel, SILOptions options) {
if (options.EnableSerializePackage)
return accessLevel == AccessLevel::Package || accessLevel == AccessLevel::Public;
return accessLevel == AccessLevel::Public;
}
/// Select functions in the module which should be serialized.
void CrossModuleOptimization::serializeFunctionsInModule() {
@@ -168,7 +179,8 @@ void CrossModuleOptimization::serializeFunctionsInModule() {
// Start with public functions.
for (SILFunction &F : M) {
if (F.getLinkage() == SILLinkage::Public || everything) {
if (isVisible(F.getLinkage(), M.getOptions()) ||
everything) {
if (canSerializeFunction(&F, canSerializeFlags, /*maxDepth*/ 64)) {
serializeFunction(&F, canSerializeFlags);
}
@@ -185,7 +197,6 @@ bool CrossModuleOptimization::canSerializeFunction(
FunctionFlags &canSerializeFlags,
int maxDepth) {
auto iter = canSerializeFlags.find(function);
// Avoid infinite recursion in case it's a cycle in the call graph.
if (iter != canSerializeFlags.end())
return iter->second;
@@ -270,7 +281,7 @@ bool CrossModuleOptimization::canSerializeInstruction(SILInstruction *inst,
// function is completely inlined afterwards.
// Also, when emitting TBD files, we cannot introduce a new public symbol.
if ((conservative || M.getOptions().emitTBD) &&
!hasPublicVisibility(callee->getLinkage())) {
!hasPublicOrPackageVisibility(callee->getLinkage(), M.getOptions().EnableSerializePackage)) {
return false;
}
@@ -290,13 +301,12 @@ bool CrossModuleOptimization::canSerializeInstruction(SILInstruction *inst,
// inline.
if (!canUseFromInline(callee))
return false;
return true;
}
if (auto *GAI = dyn_cast<GlobalAddrInst>(inst)) {
SILGlobalVariable *global = GAI->getReferencedGlobal();
if ((conservative || M.getOptions().emitTBD) &&
!hasPublicVisibility(global->getLinkage())) {
!hasPublicOrPackageVisibility(global->getLinkage(), M.getOptions().EnableSerializePackage)) {
return false;
}
@@ -344,7 +354,7 @@ bool CrossModuleOptimization::canSerializeGlobal(SILGlobalVariable *global) {
// function is completely inlined afterwards.
// Also, when emitting TBD files, we cannot introduce a new public symbol.
if ((conservative || M.getOptions().emitTBD) &&
!hasPublicVisibility(referencedFunc->getLinkage())) {
!hasPublicOrPackageVisibility(referencedFunc->getLinkage(), M.getOptions().EnableSerializePackage)) {
return false;
}
@@ -368,7 +378,7 @@ bool CrossModuleOptimization::canSerializeType(SILType type) {
if (conservative && subNT->getEffectiveAccess() < AccessLevel::Package) {
return true;
}
// Exclude types which are defined in an @_implementationOnly imported
// module. Such modules are not transitively available.
if (!canUseFromInline(subNT)) {
@@ -542,7 +552,7 @@ void CrossModuleOptimization::serializeInstruction(SILInstruction *inst,
}
}
serializeFunction(callee, canSerializeFlags);
assert(callee->isSerialized() || callee->getLinkage() == SILLinkage::Public);
assert(callee->isSerialized() || isVisible(callee->getLinkage(), M.getOptions()));
return;
}
if (auto *GAI = dyn_cast<GlobalAddrInst>(inst)) {
@@ -550,7 +560,7 @@ void CrossModuleOptimization::serializeInstruction(SILInstruction *inst,
if (canSerializeGlobal(global)) {
serializeGlobal(global);
}
if (!hasPublicVisibility(global->getLinkage())) {
if (!hasPublicOrPackageVisibility(global->getLinkage(), M.getOptions().EnableSerializePackage)) {
global->setLinkage(SILLinkage::Public);
}
return;
@@ -606,7 +616,7 @@ void CrossModuleOptimization::makeDeclUsableFromInline(ValueDecl *decl) {
if (M.getSwiftModule() != decl->getDeclContext()->getParentModule())
return;
if (decl->getFormalAccess() < AccessLevel::Public &&
if (!isVisible(decl->getFormalAccess(), M.getOptions()) &&
!decl->isUsableFromInline()) {
// Mark the nominal type as "usableFromInline".
// TODO: find a way to do this without modifying the AST. The AST should be