Skip to content

Commit 5a0c73c

Browse files
committed
Add isPackageCMOEnabled check for MethodInst and KeyPathInst.
Update lambda in table serialization. Add more tests.
1 parent fd07578 commit 5a0c73c

File tree

4 files changed

+410
-317
lines changed

4 files changed

+410
-317
lines changed

lib/SIL/IR/Linker.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,6 @@ void SILLinkerVisitor::maybeAddFunctionToWorklist(
105105
F->hasValidLinkageForFragileRef(callerSerializedKind) ||
106106
hasSharedVisibility(linkage) || F->isExternForwardDeclaration()) &&
107107
"called function has wrong linkage for serialized function");
108-
109108
if (!F->isExternalDeclaration()) {
110109
// The function is already in the module, so no need to de-serialized it.
111110
// But check if we need to set the IsSerialized flag.

lib/SILOptimizer/IPO/CrossModuleOptimization.cpp

Lines changed: 72 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ static bool isPackageOrPublic(AccessLevel accessLevel, SILOptions options) {
189189
return accessLevel == AccessLevel::Public;
190190
}
191191

192+
static bool isPackageCMOEnabled(ModuleDecl *mod) {
193+
return mod->isResilient() && mod->serializePackageEnabled();
194+
}
195+
192196
/// Checks wither this function is [serialized_for_package] due to Package CMO
193197
/// or [serialized] with non-package CMO. The [serialized_for_package] attribute
194198
/// is used to indicate that a function is serialized because of Package CMO, which
@@ -201,20 +205,21 @@ static bool isPackageOrPublic(AccessLevel accessLevel, SILOptions options) {
201205
/// is the correct behavior.
202206
static bool isSerializedWithRightKind(const SILModule &mod,
203207
SILFunction *f) {
204-
return mod.getSwiftModule()->serializePackageEnabled() &&
205-
mod.getSwiftModule()->isResilient() ?
206-
f->isSerializedForPackage() : f->isSerialized();
208+
// If Package CMO is enabled in resilient mode, return
209+
// true if the function is [serialized] due to @inlinable
210+
// (or similar) or [serialized_for_pkg] due to this
211+
// optimization.
212+
return isPackageCMOEnabled(mod.getSwiftModule()) ? f->isAnySerialized()
213+
: f->isSerialized();
207214
}
208215
static bool isSerializedWithRightKind(const SILModule &mod,
209216
SILGlobalVariable *g) {
210-
return mod.getSwiftModule()->serializePackageEnabled() &&
211-
mod.getSwiftModule()->isResilient() ?
212-
g->isSerializedForPackage() : g->isSerialized();
217+
return isPackageCMOEnabled(mod.getSwiftModule()) ? g->isAnySerialized()
218+
: g->isSerialized();
213219
}
214220
static SerializedKind_t getRightSerializedKind(const SILModule &mod) {
215-
return mod.getSwiftModule()->serializePackageEnabled() &&
216-
mod.getSwiftModule()->isResilient() ?
217-
IsSerializedForPackage : IsSerialized;
221+
return isPackageCMOEnabled(mod.getSwiftModule()) ? IsSerializedForPackage
222+
: IsSerialized;
218223
}
219224

220225
static bool isSerializeCandidate(SILFunction *F, SILOptions options) {
@@ -286,24 +291,28 @@ void CrossModuleOptimization::serializeTablesInModule() {
286291
// This should not be necessary but is added to ensure all applicable
287292
// symbols are serialized. Whether serialized or not is cached so
288293
// this check shouldn't be expensive.
289-
auto unserializedClassMethodRange = llvm::make_filter_range(vt->getEntries(), [&](auto &entry) {
290-
return entry.getImplementation()->getSerializedKind() != getRightSerializedKind(M);
291-
});
294+
auto unserializedClassMethodRange = llvm::make_filter_range(
295+
vt->getEntries(), [&](const SILVTableEntry &entry) {
296+
return entry.getImplementation()->getSerializedKind() !=
297+
getRightSerializedKind(M);
298+
});
292299
std::vector<SILFunction *> classMethodsToSerialize;
293300
llvm::transform(unserializedClassMethodRange,
294301
std::back_inserter(classMethodsToSerialize),
295-
[&](auto entry) {
296-
return entry.getImplementation();
297-
});
302+
[&](const SILVTableEntry &entry) {
303+
return entry.getImplementation();
304+
});
298305
trySerializeFunctions(classMethodsToSerialize);
299306

300-
bool containsInternal = llvm::any_of(classMethodsToSerialize, [&](auto &method) {
301-
// If the entry is internal, vtable should not be serialized.
302-
// However, if the entry is not serialized but has the right
303-
// visibility, it can still be referenced, thus the vtable
304-
// should serialized.
305-
return !method->hasValidLinkageForFragileRef(getRightSerializedKind(M));
306-
});
307+
bool containsInternal =
308+
llvm::any_of(vt->getEntries(), [&](const SILVTableEntry &entry) {
309+
// If the entry is internal, vtable should not be serialized.
310+
// However, if the entry is not serialized but has the right
311+
// visibility, it can still be referenced, thus the vtable
312+
// should serialized.
313+
return !entry.getImplementation()->hasValidLinkageForFragileRef(
314+
getRightSerializedKind(M));
315+
});
307316
if (!containsInternal)
308317
vt->setSerializedKind(getRightSerializedKind(M));
309318
}
@@ -318,25 +327,31 @@ void CrossModuleOptimization::serializeTablesInModule() {
318327
// This should not be necessary but is added to ensure all applicable
319328
// symbols are serialized. Whether serialized or not is cached so
320329
// this check shouldn't be expensive.
321-
auto unserializedWTMethodRange = llvm::make_filter_range(wt.getEntries(), [&](auto &entry) {
322-
return entry.getKind() == SILWitnessTable::Method &&
323-
entry.getMethodWitness().Witness->getSerializedKind() != getRightSerializedKind(M);
324-
});
330+
auto unserializedWTMethodRange = llvm::make_filter_range(
331+
wt.getEntries(), [&](const SILWitnessTable::Entry &entry) {
332+
return entry.getKind() == SILWitnessTable::Method &&
333+
entry.getMethodWitness().Witness->getSerializedKind() !=
334+
getRightSerializedKind(M);
335+
});
325336
std::vector<SILFunction *> wtMethodsToSerialize;
326337
llvm::transform(unserializedWTMethodRange,
327338
std::back_inserter(wtMethodsToSerialize),
328-
[&](auto entry) {
329-
return entry.getMethodWitness().Witness;
330-
});
339+
[&](const SILWitnessTable::Entry &entry) {
340+
return entry.getMethodWitness().Witness;
341+
});
331342
trySerializeFunctions(wtMethodsToSerialize);
332343

333-
bool containsInternal = llvm::any_of(wtMethodsToSerialize, [&](auto &method) {
334-
// If the entry is internal, wtable should not be serialized.
335-
// However, if the entry is not serialized but has the right
336-
// visibility, it can still be referenced, thus the vtable
337-
// should serialized.
338-
return !method->hasValidLinkageForFragileRef(getRightSerializedKind(M));
339-
});
344+
bool containsInternal = llvm::any_of(
345+
wt.getEntries(), [&](const SILWitnessTable::Entry &entry) {
346+
// If the entry is internal, wtable should not be serialized.
347+
// However, if the entry is not serialized but has the right
348+
// visibility, it can still be referenced, thus the vtable
349+
// should serialized.
350+
return entry.getKind() == SILWitnessTable::Method &&
351+
!entry.getMethodWitness()
352+
.Witness->hasValidLinkageForFragileRef(
353+
getRightSerializedKind(M));
354+
});
340355
if (!containsInternal)
341356
wt.setSerializedKind(getRightSerializedKind(M));
342357
}
@@ -485,17 +500,29 @@ bool CrossModuleOptimization::canSerializeInstruction(
485500
[&](SILDeclRef method) {
486501
if (method.isForeign)
487502
canUse = false;
503+
else if (isPackageCMOEnabled(method.getModuleContext())) {
504+
// If the referenced keypath is internal, do not
505+
// serialize.
506+
auto methodScope = method.getDecl()->getFormalAccessScope(
507+
nullptr,
508+
/*treatUsableFromInlineAsPublic*/ true);
509+
canUse = methodScope.isPublicOrPackage();
510+
}
488511
});
489512
return canUse;
490513
}
491514
if (auto *MI = dyn_cast<MethodInst>(inst)) {
492-
// If a class_method or witness_method is internal, it can't
493-
// be serialized.
515+
// If a class_method or witness_method is internal,
516+
// it can't be serialized.
494517
auto member = MI->getMember();
495-
auto methodAccessScope = member.getDecl()->getFormalAccessScope(nullptr,
496-
/*treatUsableFromInlineAsPublic*/ true);
497-
return methodAccessScope.isPublicOrPackage() &&
498-
!member.isForeign;
518+
auto canUse = !member.isForeign;
519+
if (canUse && isPackageCMOEnabled(member.getModuleContext())) {
520+
auto methodScope = member.getDecl()->getFormalAccessScope(
521+
nullptr,
522+
/*treatUsableFromInlineAsPublic*/ true);
523+
canUse = methodScope.isPublicOrPackage();
524+
}
525+
return canUse;
499526
}
500527
if (auto *REAI = dyn_cast<RefElementAddrInst>(inst)) {
501528
// In conservative mode, we don't support class field accesses of non-public
@@ -737,7 +764,9 @@ void CrossModuleOptimization::serializeInstruction(SILInstruction *inst,
737764
if (canSerializeGlobal(global)) {
738765
serializeGlobal(global);
739766
}
740-
if (!hasPublicOrPackageVisibility(global->getLinkage(), M.getSwiftModule()->serializePackageEnabled())) {
767+
if (!hasPublicOrPackageVisibility(
768+
global->getLinkage(),
769+
M.getSwiftModule()->serializePackageEnabled())) {
741770
global->setLinkage(SILLinkage::Public);
742771
}
743772
return;

0 commit comments

Comments
 (0)