Skip to content

Commit 1a445b9

Browse files
committed
Serialize SIL witness-tables and v-tables and their entries when applicable
if package cmo is enabled. If two modules are in the same package and package cmo is enabled, v-table or witness-table calls should not be generated at the use site in client module. Also allow serializing a definition with shared linkage in package cmo. rdar://124632670
1 parent 576a4ba commit 1a445b9

File tree

2 files changed

+468
-6
lines changed

2 files changed

+468
-6
lines changed

lib/SILOptimizer/IPO/CrossModuleOptimization.cpp

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ class CrossModuleOptimization {
7171
: M(M), conservative(conservative), everything(everything) { }
7272

7373
void serializeFunctionsInModule();
74+
void serializeTablesInModule();
7475

7576
private:
7677
bool canSerializeFunction(SILFunction *function,
@@ -188,6 +189,35 @@ void CrossModuleOptimization::serializeFunctionsInModule() {
188189
}
189190
}
190191

192+
void CrossModuleOptimization::serializeTablesInModule() {
193+
if (!M.getOptions().EnableSerializePackage)
194+
return;
195+
196+
for (const auto &vt : M.getVTables()) {
197+
if (!vt->isSerialized() &&
198+
vt->getClass()->getEffectiveAccess() >= AccessLevel::Package) {
199+
vt->setSerialized(IsSerialized);
200+
}
201+
}
202+
203+
for (auto &wt : M.getWitnessTables()) {
204+
if (!wt.isSerialized() && (wt.getLinkage() == SILLinkage::Package ||
205+
wt.getLinkage() == SILLinkage::Public)) {
206+
for (auto &entry : wt.getEntries()) {
207+
// Entries in witness table with package linkage are not serialized
208+
// (by default only entries in public witness table are; \see
209+
// SILWitnessTable::conformanceIsSerialized), so serialize them here
210+
// if package-cmo is enabled (otherwise nil).
211+
if (entry.getKind() == SILWitnessTable::Method &&
212+
!entry.getMethodWitness().Witness->isSerialized())
213+
entry.getMethodWitness().Witness->setSerialized(IsSerialized);
214+
}
215+
// Then serialize the witness table itself.
216+
wt.setSerialized(IsSerialized);
217+
}
218+
}
219+
}
220+
191221
/// Recursively walk the call graph and select functions to be serialized.
192222
///
193223
/// The results are stored in \p canSerializeFlags and the result for \p
@@ -280,9 +310,21 @@ bool CrossModuleOptimization::canSerializeInstruction(SILInstruction *inst,
280310
// public functions, because that can increase code size. E.g. if the
281311
// function is completely inlined afterwards.
282312
// Also, when emitting TBD files, we cannot introduce a new public symbol.
283-
if ((conservative || M.getOptions().emitTBD) &&
284-
!hasPublicOrPackageVisibility(callee->getLinkage(), M.getOptions().EnableSerializePackage)) {
285-
return false;
313+
if (conservative || M.getOptions().emitTBD) {
314+
// In package-cmo, serialize this inst if its referenced function has
315+
// package+ linkage, or is a definition with shared linkage.
316+
// For example, `public func foo() { print("") }` is a function with
317+
// public linkage which contains `print`, which is a definition with
318+
// shared linkage, thus should be serialized.
319+
if (M.getOptions().EnableSerializePackage) {
320+
if (!(hasPublicOrPackageVisibility(callee->getLinkage(),
321+
/*includePackage*/ true) ||
322+
(hasSharedVisibility(callee->getLinkage()) &&
323+
callee->isDefinition())))
324+
return false;
325+
} else if (!hasPublicVisibility(callee->getLinkage())) {
326+
return false;
327+
}
286328
}
287329

288330
// In some project configurations imported C functions are not necessarily
@@ -374,7 +416,7 @@ bool CrossModuleOptimization::canSerializeType(SILType type) {
374416
[this](Type rawSubType) {
375417
CanType subType = rawSubType->getCanonicalType();
376418
if (NominalTypeDecl *subNT = subType->getNominalOrBoundGenericNominal()) {
377-
419+
378420
if (conservative && subNT->getEffectiveAccess() < AccessLevel::Package) {
379421
return true;
380422
}
@@ -482,6 +524,12 @@ bool CrossModuleOptimization::shouldSerialize(SILFunction *function) {
482524

483525
if (function->getLinkage() == SILLinkage::Shared)
484526
return true;
527+
} else if (function->getModule().getOptions().EnableSerializePackage &&
528+
(function->getLinkage() == SILLinkage::Package ||
529+
function->getLinkage() == SILLinkage::Public)) {
530+
// If package-cmo is enabled, we should not limit the amount of inlining
531+
// as checked with CMOFunctionSizeLimit below.
532+
return true;
485533
}
486534

487535
// Also serialize "small" non-generic functions.
@@ -503,7 +551,7 @@ void CrossModuleOptimization::serializeFunction(SILFunction *function,
503551
const FunctionFlags &canSerializeFlags) {
504552
if (function->isSerialized())
505553
return;
506-
554+
507555
if (!canSerializeFlags.lookup(function))
508556
return;
509557

@@ -699,7 +747,10 @@ class CrossModuleOptimizationPass: public SILModuleTransform {
699747
void run() override {
700748

701749
auto &M = *getModule();
702-
if (M.getSwiftModule()->isResilient())
750+
if (M.getSwiftModule()->isResilient() &&
751+
// FIXME: need to properly lower type when this is enabled
752+
// else leads to assert fail.
753+
!M.getOptions().EnableSerializePackage)
703754
return;
704755
if (!M.isWholeModule())
705756
return;
@@ -727,6 +778,7 @@ class CrossModuleOptimizationPass: public SILModuleTransform {
727778

728779
CrossModuleOptimization CMO(M, conservative, everything);
729780
CMO.serializeFunctionsInModule();
781+
CMO.serializeTablesInModule();
730782
}
731783
};
732784

0 commit comments

Comments
 (0)