Skip to content

Commit 402e228

Browse files
committed
SIL: add a table in SILModule to mark method declarations as externally visible.
This is needed for cross-module-optimization: CMO marks functions as inlinable. If a private or internal method is referenced from such an inlinable function, it must not be eliminated by dead function elimination after serialization (a method is basically an AbstractFunctionDecl). For SILFunctions we can do this by simply setting the linkage, but for methods we need another mechanism.
1 parent db81552 commit 402e228

File tree

5 files changed

+71
-33
lines changed

5 files changed

+71
-33
lines changed

include/swift/SIL/SILModule.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,15 @@ class SILModule {
194194
/// The list of SILDefaultWitnessTables in the module.
195195
DefaultWitnessTableListType defaultWitnessTables;
196196

197+
/// Declarations which are externally visible.
198+
///
199+
/// These are method declarations which are referenced from inlinable
200+
/// functions due to cross-module-optimzation. Those declarations don't have
201+
/// any attributes or linkage which mark them as externally visible by
202+
/// default.
203+
/// Currently this table is not serialized.
204+
llvm::SetVector<ValueDecl *> externallyVisible;
205+
197206
/// Lookup table for SIL Global Variables.
198207
llvm::StringMap<SILGlobalVariable *> GlobalVariableMap;
199208

@@ -446,6 +455,13 @@ class SILModule {
446455
return {defaultWitnessTables.begin(), defaultWitnessTables.end()};
447456
}
448457

458+
void addExternallyVisibleDecl(ValueDecl *decl) {
459+
externallyVisible.insert(decl);
460+
}
461+
bool isExternallyVisibleDecl(ValueDecl *decl) {
462+
return externallyVisible.count(decl) != 0;
463+
}
464+
449465
using sil_global_iterator = GlobalListType::iterator;
450466
using sil_global_const_iterator = GlobalListType::const_iterator;
451467
GlobalListType &getSILGlobalList() { return silGlobals; }

include/swift/SILOptimizer/Utils/InstOptUtils.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,9 @@ struct LLVM_LIBRARY_VISIBILITY FindLocalApplySitesResult {
388388
Optional<FindLocalApplySitesResult>
389389
findLocalApplySites(FunctionRefBaseInst *fri);
390390

391+
/// Gets the base implementation of a method.
392+
AbstractFunctionDecl *getBaseMethod(AbstractFunctionDecl *FD);
393+
391394
} // end namespace swift
392395

393396
#endif

lib/SIL/SILPrinter.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2695,6 +2695,18 @@ static void printSILProperties(SILPrintContext &Ctx,
26952695
}
26962696
}
26972697

2698+
static void printExternallyVisibleDecls(SILPrintContext &Ctx,
2699+
ArrayRef<ValueDecl *> decls) {
2700+
if (decls.empty())
2701+
return;
2702+
Ctx.OS() << "/* externally visible decls: \n";
2703+
for (ValueDecl *decl : decls) {
2704+
printValueDecl(decl, Ctx.OS());
2705+
Ctx.OS() << '\n';
2706+
}
2707+
Ctx.OS() << "*/\n";
2708+
}
2709+
26982710
/// Pretty-print the SILModule to the designated stream.
26992711
void SILModule::print(SILPrintContext &PrintCtx, ModuleDecl *M,
27002712
bool PrintASTDecls) const {
@@ -2761,7 +2773,8 @@ void SILModule::print(SILPrintContext &PrintCtx, ModuleDecl *M,
27612773
printSILDefaultWitnessTables(PrintCtx, getDefaultWitnessTableList());
27622774
printSILCoverageMaps(PrintCtx, getCoverageMaps());
27632775
printSILProperties(PrintCtx, getPropertyList());
2764-
2776+
printExternallyVisibleDecls(PrintCtx, externallyVisible.getArrayRef());
2777+
27652778
OS << "\n\n";
27662779
}
27672780

lib/SILOptimizer/IPO/DeadFunctionElimination.cpp

Lines changed: 31 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,8 @@ class FunctionLivenessComputation {
159159
auto methodWitness = entry.getMethodWitness();
160160
auto *fd = cast<AbstractFunctionDecl>(methodWitness.Requirement.
161161
getDecl());
162-
assert(fd == getBase(fd) && "key in witness table is overridden");
162+
assert(fd == getBaseMethod(fd) &&
163+
"key in witness table is overridden");
163164
SILFunction *F = methodWitness.Witness;
164165
if (F) {
165166
MethodInfo *MI = getMethodInfo(fd, /*isWitnessMethod*/ true);
@@ -324,15 +325,6 @@ class FunctionLivenessComputation {
324325
}
325326
}
326327

327-
/// Gets the base implementation of a method.
328-
/// We always use the most overridden function to describe a method.
329-
AbstractFunctionDecl *getBase(AbstractFunctionDecl *FD) {
330-
while (FD->getOverriddenDecl()) {
331-
FD = FD->getOverriddenDecl();
332-
}
333-
return FD;
334-
}
335-
336328
/// Scans all references inside a function.
337329
void scanFunction(SILFunction *F) {
338330

@@ -342,12 +334,12 @@ class FunctionLivenessComputation {
342334
for (SILBasicBlock &BB : *F) {
343335
for (SILInstruction &I : BB) {
344336
if (auto *WMI = dyn_cast<WitnessMethodInst>(&I)) {
345-
auto *funcDecl = getBase(
337+
auto *funcDecl = getBaseMethod(
346338
cast<AbstractFunctionDecl>(WMI->getMember().getDecl()));
347339
MethodInfo *mi = getMethodInfo(funcDecl, /*isWitnessTable*/ true);
348340
ensureAliveProtocolMethod(mi);
349341
} else if (auto *MI = dyn_cast<MethodInst>(&I)) {
350-
auto *funcDecl = getBase(
342+
auto *funcDecl = getBaseMethod(
351343
cast<AbstractFunctionDecl>(MI->getMember().getDecl()));
352344
assert(MI->getNumOperands() - MI->getNumTypeDependentOperands() == 1
353345
&& "method insts except witness_method must have 1 operand");
@@ -474,7 +466,8 @@ class DeadFunctionElimination : FunctionLivenessComputation {
474466
continue;
475467
}
476468
SILFunction *F = entry.Implementation;
477-
auto *fd = getBase(cast<AbstractFunctionDecl>(entry.Method.getDecl()));
469+
auto *fd = getBaseMethod(cast<AbstractFunctionDecl>(
470+
entry.Method.getDecl()));
478471
MethodInfo *mi = getMethodInfo(fd, /*isWitnessTable*/ false);
479472
mi->addClassMethodImpl(F, vTable.getClass());
480473
}
@@ -490,7 +483,8 @@ class DeadFunctionElimination : FunctionLivenessComputation {
490483
auto methodWitness = entry.getMethodWitness();
491484
auto *fd = cast<AbstractFunctionDecl>(methodWitness.Requirement.
492485
getDecl());
493-
assert(fd == getBase(fd) && "key in witness table is overridden");
486+
assert(fd == getBaseMethod(fd) &&
487+
"key in witness table is overridden");
494488
SILFunction *F = methodWitness.Witness;
495489
if (!F)
496490
continue;
@@ -533,12 +527,14 @@ class DeadFunctionElimination : FunctionLivenessComputation {
533527
}
534528

535529
SILFunction *F = entry.Implementation;
536-
auto *fd = getBase(cast<AbstractFunctionDecl>(entry.Method.getDecl()));
530+
auto *fd = getBaseMethod(cast<AbstractFunctionDecl>(
531+
entry.Method.getDecl()));
537532

538533
if (// We also have to check the method declaration's access level.
539534
// Needed if it's a public base method declared in another
540535
// compilation unit (for this we have no SILFunction).
541536
isVisibleExternally(fd)
537+
|| Module->isExternallyVisibleDecl(fd)
542538
// Declarations are always accessible externally, so they are alive.
543539
|| !F->isDefinition()) {
544540
MethodInfo *mi = getMethodInfo(fd, /*isWitnessTable*/ false);
@@ -550,24 +546,27 @@ class DeadFunctionElimination : FunctionLivenessComputation {
550546
// Check witness table methods.
551547
for (SILWitnessTable &WT : Module->getWitnessTableList()) {
552548
ProtocolConformance *Conf = WT.getConformance();
553-
if (isVisibleExternally(Conf->getProtocol())) {
554-
// The witness table is visible from "outside". Therefore all methods
555-
// might be called and we mark all methods as alive.
556-
for (const SILWitnessTable::Entry &entry : WT.getEntries()) {
557-
if (entry.getKind() != SILWitnessTable::Method)
558-
continue;
549+
bool tableExternallyVisible = isVisibleExternally(Conf->getProtocol());
550+
// The witness table is visible from "outside". Therefore all methods
551+
// might be called and we mark all methods as alive.
552+
for (const SILWitnessTable::Entry &entry : WT.getEntries()) {
553+
if (entry.getKind() != SILWitnessTable::Method)
554+
continue;
559555

560-
auto methodWitness = entry.getMethodWitness();
561-
auto *fd = cast<AbstractFunctionDecl>(methodWitness.Requirement.
562-
getDecl());
563-
assert(fd == getBase(fd) && "key in witness table is overridden");
564-
SILFunction *F = methodWitness.Witness;
565-
if (!F)
566-
continue;
556+
auto methodWitness = entry.getMethodWitness();
557+
auto *fd = cast<AbstractFunctionDecl>(methodWitness.Requirement.
558+
getDecl());
559+
assert(fd == getBaseMethod(fd) &&
560+
"key in witness table is overridden");
561+
SILFunction *F = methodWitness.Witness;
562+
if (!F)
563+
continue;
567564

568-
MethodInfo *mi = getMethodInfo(fd, /*isWitnessTable*/ true);
569-
ensureAliveProtocolMethod(mi);
570-
}
565+
if (!tableExternallyVisible && !Module->isExternallyVisibleDecl(fd))
566+
continue;
567+
568+
MethodInfo *mi = getMethodInfo(fd, /*isWitnessTable*/ true);
569+
ensureAliveProtocolMethod(mi);
571570
}
572571

573572
// We don't do dead witness table elimination right now. So we assume
@@ -588,7 +587,7 @@ class DeadFunctionElimination : FunctionLivenessComputation {
588587
auto *fd =
589588
cast<AbstractFunctionDecl>(
590589
entry.getMethodWitness().Requirement.getDecl());
591-
assert(fd == getBase(fd) &&
590+
assert(fd == getBaseMethod(fd) &&
592591
"key in default witness table is overridden");
593592
SILFunction *F = entry.getMethodWitness().Witness;
594593
if (!F)

lib/SILOptimizer/Utils/InstOptUtils.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1582,3 +1582,10 @@ void swift::insertDestroyOfCapturedArguments(
15821582
releasePartialApplyCapturedArg(builder, loc, arg.get(), paramInfo);
15831583
}
15841584
}
1585+
1586+
AbstractFunctionDecl *swift::getBaseMethod(AbstractFunctionDecl *FD) {
1587+
while (FD->getOverriddenDecl()) {
1588+
FD = FD->getOverriddenDecl();
1589+
}
1590+
return FD;
1591+
}

0 commit comments

Comments
 (0)