Skip to content

Commit fd07578

Browse files
committed
Package CMO fixes.
* Do not use [serialized_for_package] for witness method before Package CMO. * Update v-table and witness-table and their entry serialization. -- Allow non-serialized but visible entries in a serialized table so they can be optimized by other SIL opt passes. * Only serialize MethodInst if it has the right visibility. Resolves rdar://129089105&129088935
1 parent ed85087 commit fd07578

File tree

5 files changed

+380
-138
lines changed

5 files changed

+380
-138
lines changed

lib/SIL/IR/SILWitnessTable.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -184,9 +184,7 @@ SerializedKind_t SILWitnessTable::conformanceSerializedKind(
184184

185185
auto *nominal = conformance->getDeclContext()->getSelfNominalTypeDecl();
186186
if (nominal->getEffectiveAccess() >= accessLevelToCheck)
187-
return optInPackage &&
188-
conformance->getDeclContext()->getParentModule()->isResilient() ?
189-
IsSerializedForPackage : IsSerialized;
187+
return IsSerialized;
190188

191189
return IsNotSerialized;
192190
}

lib/SILOptimizer/IPO/CrossModuleOptimization.cpp

Lines changed: 76 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,14 @@ class CrossModuleOptimization {
6767
bool everything;
6868

6969
typedef llvm::DenseMap<SILFunction *, bool> FunctionFlags;
70+
FunctionFlags canSerializeFlags;
7071

7172
public:
7273
CrossModuleOptimization(SILModule &M, bool conservative, bool everything)
7374
: M(M), conservative(conservative), everything(everything) { }
7475

75-
void serializeFunctionsInModule(ArrayRef<SILFunction *> functions);
76+
void trySerializeFunctions(ArrayRef<SILFunction *> functions);
77+
void serializeFunctionsInModule(SILPassManager *manager);
7678
void serializeTablesInModule();
7779

7880
private:
@@ -251,12 +253,8 @@ static bool isReferenceSerializeCandidate(SILGlobalVariable *G,
251253
}
252254

253255
/// Select functions in the module which should be serialized.
254-
void CrossModuleOptimization::serializeFunctionsInModule(
256+
void CrossModuleOptimization::trySerializeFunctions(
255257
ArrayRef<SILFunction *> functions) {
256-
FunctionFlags canSerializeFlags;
257-
258-
// The passed functions are already ordered bottom-up so the most
259-
// nested referenced function is checked first.
260258
for (SILFunction *F : functions) {
261259
if (isSerializeCandidate(F, M.getOptions()) || everything) {
262260
if (canSerializeFunction(F, canSerializeFlags, /*maxDepth*/ 64)) {
@@ -266,31 +264,81 @@ void CrossModuleOptimization::serializeFunctionsInModule(
266264
}
267265
}
268266

267+
void CrossModuleOptimization::serializeFunctionsInModule(SILPassManager *manager) {
268+
// Reorder SIL funtions in the module bottom up so we can serialize
269+
// the most nested referenced functions first and avoid unnecessary
270+
// recursive checks.
271+
BasicCalleeAnalysis *BCA = manager->getAnalysis<BasicCalleeAnalysis>();
272+
BottomUpFunctionOrder BottomUpOrder(M, BCA);
273+
auto bottomUpFunctions = BottomUpOrder.getFunctions();
274+
trySerializeFunctions(bottomUpFunctions);
275+
}
276+
269277
void CrossModuleOptimization::serializeTablesInModule() {
270278
if (!M.getSwiftModule()->serializePackageEnabled())
271279
return;
272280

273281
for (const auto &vt : M.getVTables()) {
274-
if (vt->isNotSerialized() &&
282+
if (vt->getSerializedKind() != getRightSerializedKind(M) &&
275283
vt->getClass()->getEffectiveAccess() >= AccessLevel::Package) {
276-
vt->setSerializedKind(getRightSerializedKind(M));
284+
// This checks if a vtable entry is not serialized and attempts to
285+
// serialize (and its references) if they have the right visibility.
286+
// This should not be necessary but is added to ensure all applicable
287+
// symbols are serialized. Whether serialized or not is cached so
288+
// 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+
});
292+
std::vector<SILFunction *> classMethodsToSerialize;
293+
llvm::transform(unserializedClassMethodRange,
294+
std::back_inserter(classMethodsToSerialize),
295+
[&](auto entry) {
296+
return entry.getImplementation();
297+
});
298+
trySerializeFunctions(classMethodsToSerialize);
299+
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+
if (!containsInternal)
308+
vt->setSerializedKind(getRightSerializedKind(M));
277309
}
278310
}
279311

312+
// Witness thunks are not serialized, so serialize them here.
280313
for (auto &wt : M.getWitnessTables()) {
281-
if (wt.isNotSerialized() &&
314+
if (wt.getSerializedKind() != getRightSerializedKind(M) &&
282315
hasPublicOrPackageVisibility(wt.getLinkage(), /*includePackage*/ true)) {
283-
for (auto &entry : wt.getEntries()) {
284-
// Witness thunks are not serialized, so serialize them here.
285-
if (entry.getKind() == SILWitnessTable::Method &&
286-
entry.getMethodWitness().Witness->isNotSerialized() &&
287-
isSerializeCandidate(entry.getMethodWitness().Witness,
288-
M.getOptions())) {
289-
entry.getMethodWitness().Witness->setSerializedKind(getRightSerializedKind(M));
290-
}
291-
}
292-
// Then serialize the witness table itself.
293-
wt.setSerializedKind(getRightSerializedKind(M));
316+
// This checks if a wtable entry is not serialized and attempts to
317+
// serialize (and its references) if they have the right visibility.
318+
// This should not be necessary but is added to ensure all applicable
319+
// symbols are serialized. Whether serialized or not is cached so
320+
// 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+
});
325+
std::vector<SILFunction *> wtMethodsToSerialize;
326+
llvm::transform(unserializedWTMethodRange,
327+
std::back_inserter(wtMethodsToSerialize),
328+
[&](auto entry) {
329+
return entry.getMethodWitness().Witness;
330+
});
331+
trySerializeFunctions(wtMethodsToSerialize);
332+
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+
});
340+
if (!containsInternal)
341+
wt.setSerializedKind(getRightSerializedKind(M));
294342
}
295343
}
296344
}
@@ -441,7 +489,13 @@ bool CrossModuleOptimization::canSerializeInstruction(
441489
return canUse;
442490
}
443491
if (auto *MI = dyn_cast<MethodInst>(inst)) {
444-
return !MI->getMember().isForeign;
492+
// If a class_method or witness_method is internal, it can't
493+
// be serialized.
494+
auto member = MI->getMember();
495+
auto methodAccessScope = member.getDecl()->getFormalAccessScope(nullptr,
496+
/*treatUsableFromInlineAsPublic*/ true);
497+
return methodAccessScope.isPublicOrPackage() &&
498+
!member.isForeign;
445499
}
446500
if (auto *REAI = dyn_cast<RefElementAddrInst>(inst)) {
447501
// In conservative mode, we don't support class field accesses of non-public
@@ -855,14 +909,7 @@ class CrossModuleOptimizationPass: public SILModuleTransform {
855909
}
856910

857911
CrossModuleOptimization CMO(M, conservative, everything);
858-
859-
// Reorder SIL funtions in the module bottom up so we can serialize
860-
// the most nested referenced functions first and avoid unnecessary
861-
// recursive checks.
862-
BasicCalleeAnalysis *BCA = PM->getAnalysis<BasicCalleeAnalysis>();
863-
BottomUpFunctionOrder BottomUpOrder(M, BCA);
864-
auto BottomUpFunctions = BottomUpOrder.getFunctions();
865-
CMO.serializeFunctionsInModule(BottomUpFunctions);
912+
CMO.serializeFunctionsInModule(PM);
866913

867914
// Serialize SIL v-tables and witness-tables if package-cmo is enabled.
868915
CMO.serializeTablesInModule();

0 commit comments

Comments
 (0)