Skip to content

Commit c8be802

Browse files
authored
Merge pull request #28559 from eeckstein/fix-cmo
Cross-module-optimization: no need to add AST-attributes to make functions always-emit-into-client.
2 parents 7388b6c + 356a388 commit c8be802

File tree

12 files changed

+64
-56
lines changed

12 files changed

+64
-56
lines changed

include/swift/SIL/SILModule.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -526,6 +526,13 @@ class SILModule {
526526
/// succeeded, false otherwise.
527527
bool loadFunction(SILFunction *F);
528528

529+
/// Update the linkage of the SILFunction with the linkage of the serialized
530+
/// function.
531+
///
532+
/// The serialized SILLinkage can differ from the linkage derived from the
533+
/// AST, e.g. cross-module-optimization can change the SIL linkages.
534+
void updateFunctionLinkage(SILFunction *F);
535+
529536
/// Attempt to link the SILFunction. Returns true if linking succeeded, false
530537
/// otherwise.
531538
///

include/swift/Serialization/SerializedSILLoader.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ class SerializedSILLoader {
5656
}
5757
~SerializedSILLoader();
5858

59-
SILFunction *lookupSILFunction(SILFunction *Callee);
59+
SILFunction *lookupSILFunction(SILFunction *Callee, bool onlyUpdateLinkage);
6060
SILFunction *
6161
lookupSILFunction(StringRef Name, bool declarationOnly = false,
6262
Optional<SILLinkage> linkage = None);

lib/SIL/Linker.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,11 @@ void SILLinkerVisitor::maybeAddFunctionToWorklist(SILFunction *F) {
114114
// So try deserializing HiddenExternal functions too.
115115
if (F->getLinkage() == SILLinkage::HiddenExternal)
116116
return addFunctionToWorklist(F);
117+
118+
// Update the linkage of the function in case it's different in the serialized
119+
// SIL than derived from the AST. This can be the case with cross-module-
120+
// optimizations.
121+
Mod.updateFunctionLinkage(F);
117122
}
118123

119124
/// Process F, recursively deserializing any thing F may reference.

lib/SIL/SILModule.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,14 +321,19 @@ SILFunction *SILModule::lookUpFunction(SILDeclRef fnRef) {
321321
}
322322

323323
bool SILModule::loadFunction(SILFunction *F) {
324-
SILFunction *NewF = getSILLoader()->lookupSILFunction(F);
324+
SILFunction *NewF =
325+
getSILLoader()->lookupSILFunction(F, /*onlyUpdateLinkage*/ false);
325326
if (!NewF)
326327
return false;
327328

328329
assert(F == NewF);
329330
return true;
330331
}
331332

333+
void SILModule::updateFunctionLinkage(SILFunction *F) {
334+
getSILLoader()->lookupSILFunction(F, /*onlyUpdateLinkage*/ true);
335+
}
336+
332337
bool SILModule::linkFunction(SILFunction *F, SILModule::LinkingMode Mode) {
333338
return SILLinkerVisitor(*this, Mode).processFunction(F);
334339
}

lib/SIL/SILPrinter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,10 @@ static void printFullContext(const DeclContext *Context, raw_ostream &Buffer) {
222222

223223
static void printValueDecl(ValueDecl *Decl, raw_ostream &OS) {
224224
printFullContext(Decl->getDeclContext(), OS);
225-
assert(Decl->hasName());
226225

227-
if (Decl->isOperator()) {
226+
if (!Decl->hasName()) {
227+
OS << "anonname=" << (const void*)Decl;
228+
} else if (Decl->isOperator()) {
228229
OS << '"' << Decl->getBaseName() << '"';
229230
} else {
230231
bool shouldEscape = !Decl->getBaseName().isSpecial() &&

lib/SILOptimizer/IPO/CrossModuleSerializationSetup.cpp

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ class CrossModuleSerializationSetup {
6161

6262
void makeSubstUsableFromInline(const SubstitutionMap &substs);
6363

64-
bool markAsEmitIntoClient(SILFunction *F);
65-
6664
public:
6765
CrossModuleSerializationSetup(SILModule &M) : M(M) { }
6866

@@ -313,12 +311,7 @@ void CrossModuleSerializationSetup::scanModule() {
313311

314312
// As a code size optimization, make serialized functions
315313
// @alwaysEmitIntoClient.
316-
if (!markAsEmitIntoClient(F)) {
317-
// We don't have a declaration to put the attribute on (e.g. in case
318-
// the function is a closure). Just make the function public instead
319-
// of @alwaysEmitIntoClient.
320-
F->setLinkage(SILLinkage::Public);
321-
}
314+
F->setLinkage(SILLinkage::PublicNonABI);
322315
} else {
323316
// If for some reason the function cannot be serialized, we mark it as
324317
// usable-from-inline.
@@ -328,36 +321,6 @@ void CrossModuleSerializationSetup::scanModule() {
328321
}
329322
}
330323

331-
/// Marks a function as @alwaysEmitIntoClient and returns true if this is
332-
/// successful.
333-
bool CrossModuleSerializationSetup::markAsEmitIntoClient(SILFunction *F) {
334-
auto *DC = F->getDeclContext();
335-
if (!DC)
336-
return false;
337-
338-
Decl *decl = DC->getAsDecl();
339-
if (!decl)
340-
return false;
341-
342-
if (!isa<AbstractFunctionDecl>(decl))
343-
return false;
344-
345-
F->setLinkage(SILLinkage::PublicNonABI);
346-
347-
// Adding the attribute is only needed to be able to compile the
348-
// client module with -Onone. For optimized builds, setting the
349-
// SILLinkage is enough, because with optimization, the client module
350-
// eagerly de-serializes all functions and therefore gets the
351-
// linkage right. But with -Onone, the linkage is derived purly from
352-
// the AST.
353-
// TODO: also here, we should find a way to not modify the AST.
354-
auto &ctx = M.getASTContext();
355-
auto *attr = new (ctx) AlwaysEmitIntoClientAttr(/*implicit=*/true);
356-
decl->getAttrs().add(attr);
357-
358-
return true;
359-
}
360-
361324
class CrossModuleSerializationSetupPass: public SILModuleTransform {
362325
void run() override {
363326

lib/SILOptimizer/Transforms/SpeculativeDevirtualizer.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -618,6 +618,8 @@ namespace {
618618
Changed |= tryToSpeculateTarget(AI, CHA, ORE);
619619

620620
if (Changed) {
621+
CurFn.getModule().linkFunction(&CurFn, SILModule::LinkingMode::LinkAll);
622+
621623
invalidateAnalysis(SILAnalysis::InvalidationKind::FunctionBody);
622624
}
623625
}

lib/Serialization/DeserializeSIL.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -527,12 +527,13 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
527527
replacedObjectiveCFunc = MF->getIdentifier(replacedFunctionID);
528528
}
529529

530-
auto linkage = fromStableSILLinkage(rawLinkage);
531-
if (!linkage) {
530+
auto linkageOpt = fromStableSILLinkage(rawLinkage);
531+
if (!linkageOpt) {
532532
LLVM_DEBUG(llvm::dbgs() << "invalid linkage code " << rawLinkage
533533
<< " for SILFunction\n");
534534
MF->fatal();
535535
}
536+
SILLinkage linkage = linkageOpt.getValue();
536537

537538
ValueDecl *clangNodeOwner = nullptr;
538539
if (clangNodeOwnerID != 0) {
@@ -569,16 +570,22 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
569570
fn->setSerialized(IsSerialized_t(isSerialized));
570571

571572
if (SILMod.getOptions().MergePartialModules)
572-
fn->setLinkage(*linkage);
573+
fn->setLinkage(linkage);
573574

574575
// Don't override the transparency or linkage of a function with
575576
// an existing declaration, except if we deserialized a
576577
// PublicNonABI function, which has HiddenExternal when
577578
// referenced as a declaration, and SharedExternal when it has
578579
// a deserialized body.
579-
if (isAvailableExternally(fn->getLinkage()) &&
580-
linkage == SILLinkage::PublicNonABI) {
581-
fn->setLinkage(SILLinkage::SharedExternal);
580+
if (isAvailableExternally(fn->getLinkage())) {
581+
if (linkage == SILLinkage::PublicNonABI) {
582+
fn->setLinkage(SILLinkage::SharedExternal);
583+
} else if (hasPublicVisibility(linkage)) {
584+
// Cross-module-optimization can change the linkage to public. In this
585+
// case we need to update the linkage of the function (which is
586+
// originally just derived from the AST).
587+
fn->setLinkage(SILLinkage::PublicExternal);
588+
}
582589
}
583590

584591
if (fn->isDynamicallyReplaceable() != isDynamic) {
@@ -589,7 +596,7 @@ SILDeserializer::readSILFunctionChecked(DeclID FID, SILFunction *existingFn,
589596
} else {
590597
// Otherwise, create a new function.
591598
fn = builder.createDeclaration(name, ty, loc);
592-
fn->setLinkage(linkage.getValue());
599+
fn->setLinkage(linkage);
593600
fn->setTransparent(IsTransparent_t(isTransparent == 1));
594601
fn->setSerialized(IsSerialized_t(isSerialized));
595602
fn->setThunk(IsThunk_t(isThunk));
@@ -2545,16 +2552,18 @@ bool SILDeserializer::readSILInstruction(SILFunction *Fn, SILBasicBlock *BB,
25452552
return false;
25462553
}
25472554

2548-
SILFunction *SILDeserializer::lookupSILFunction(SILFunction *InFunc) {
2555+
SILFunction *SILDeserializer::lookupSILFunction(SILFunction *InFunc,
2556+
bool onlyUpdateLinkage) {
25492557
StringRef name = InFunc->getName();
25502558
if (!FuncTable)
25512559
return nullptr;
25522560
auto iter = FuncTable->find(name);
25532561
if (iter == FuncTable->end())
25542562
return nullptr;
25552563

2564+
// Re-reading the function as declaration will update the linkage.
25562565
auto maybeFunc = readSILFunctionChecked(*iter, InFunc, name,
2557-
/*declarationOnly*/ false);
2566+
/*declarationOnly*/ onlyUpdateLinkage);
25582567
if (!maybeFunc) {
25592568
// Ignore the error; treat it as if we didn't have a definition.
25602569
consumeError(maybeFunc.takeError());

lib/Serialization/DeserializeSIL.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ namespace swift {
140140
FileUnit *getFile() const {
141141
return MF->getFile();
142142
}
143-
SILFunction *lookupSILFunction(SILFunction *InFunc);
143+
SILFunction *lookupSILFunction(SILFunction *InFunc, bool onlyUpdateLinkage);
144144
SILFunction *lookupSILFunction(StringRef Name,
145145
bool declarationOnly = false);
146146
bool hasSILFunction(StringRef Name, Optional<SILLinkage> Linkage = None);

lib/Serialization/SerializedSILLoader.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,13 @@ SerializedSILLoader::SerializedSILLoader(
4242

4343
SerializedSILLoader::~SerializedSILLoader() {}
4444

45-
SILFunction *SerializedSILLoader::lookupSILFunction(SILFunction *Callee) {
45+
SILFunction *SerializedSILLoader::lookupSILFunction(SILFunction *Callee,
46+
bool onlyUpdateLinkage) {
4647
// It is possible that one module has a declaration of a SILFunction, while
4748
// another has the full definition.
4849
SILFunction *retVal = nullptr;
4950
for (auto &Des : LoadedSILSections) {
50-
if (auto Func = Des->lookupSILFunction(Callee)) {
51+
if (auto Func = Des->lookupSILFunction(Callee, onlyUpdateLinkage)) {
5152
LLVM_DEBUG(llvm::dbgs() << "Deserialized " << Func->getName() << " from "
5253
<< Des->getModuleIdentifier().str() << "\n");
5354
if (!Func->empty())

test/SILOptimizer/Inputs/cross-module.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,11 @@ private protocol PrivateProtocol {
9292

9393
open class OpenClass<T> {
9494
public init() { }
95+
96+
@inline(never)
97+
fileprivate func bar(_ t: T) {
98+
print(t)
99+
}
95100
}
96101

97102
extension OpenClass {
@@ -114,6 +119,12 @@ public func checkIfClassConforms_gen<T>(_ t: T) {
114119
print(x.testit())
115120
}
116121

122+
@inline(never)
123+
public func callClassMethod<T>(_ t: T) {
124+
let k = OpenClass<T>()
125+
k.bar(t)
126+
}
127+
117128
extension Int : PrivateProtocol {
118129
func foo() -> Int { return self }
119130
}

test/SILOptimizer/cross-module-optimization.swift

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@ func testError() {
6464
print(returnInternalError(27))
6565
}
6666

67-
func testProtocol() {
67+
class DerivedFromOpen<T> : OpenClass<T> { }
68+
69+
func testProtocolsAndClasses() {
6870
// CHECK-OUTPUT: false
6971
// CHECK-SIL-DAG: sil shared [noinline] @$s4Test20checkIfClassConformsyyxlFSi_Tg5
7072
checkIfClassConforms(27)
@@ -80,6 +82,8 @@ func testProtocol() {
8082
// CHECK-OUTPUT: 1234
8183
// CHECK-SIL-DAG: sil shared_external {{.*}} @$s4Test11callFoo_genyyxlF
8284
callFoo_gen(27)
85+
// CHECK-OUTPUT: 55
86+
callClassMethod(55)
8387
}
8488

8589
func testSubModule() {
@@ -111,7 +115,7 @@ func testKeypath() {
111115
testNestedTypes()
112116
testClass()
113117
testError()
114-
testProtocol()
118+
testProtocolsAndClasses()
115119
testSubModule()
116120
testClosures()
117121
testKeypath()

0 commit comments

Comments
 (0)