Skip to content

Commit 7c240dc

Browse files
committed
AST: Optimize collectLinkLibraries()
SourceFile::collectLinkLibraries() did not depend on the source file, so let's move this logic up into ModuleDecl::collectLinkLibraries().
1 parent adf9d4f commit 7c240dc

File tree

5 files changed

+136
-116
lines changed

5 files changed

+136
-116
lines changed

lib/AST/Module.cpp

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2136,45 +2136,57 @@ bool ModuleDecl::registerEntryPointFile(
21362136
}
21372137

21382138
void ModuleDecl::collectLinkLibraries(LinkLibraryCallback callback) const {
2139-
// FIXME: The proper way to do this depends on the decls used.
2140-
FORWARD(collectLinkLibraries, (callback));
2141-
}
2139+
bool hasSourceFile = false;
2140+
2141+
for (auto *file : getFiles()) {
2142+
if (isa<SourceFile>(file)) {
2143+
hasSourceFile = true;
2144+
} else {
2145+
file->collectLinkLibraries(callback);
2146+
}
2147+
2148+
if (auto *synth = file->getSynthesizedFile()) {
2149+
synth->collectLinkLibraries(callback);
2150+
}
2151+
}
2152+
2153+
if (!hasSourceFile)
2154+
return;
21422155

2143-
void
2144-
SourceFile::collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const {
21452156
llvm::SmallDenseSet<ModuleDecl *, 32> visited;
21462157
SmallVector<ImportedModule, 32> stack;
21472158

21482159
ModuleDecl::ImportFilter filter = {
21492160
ModuleDecl::ImportFilterKind::Exported,
21502161
ModuleDecl::ImportFilterKind::Default};
21512162

2152-
auto *topLevel = getParentModule();
2153-
21542163
ModuleDecl::ImportFilter topLevelFilter = filter;
21552164
topLevelFilter |= ModuleDecl::ImportFilterKind::ImplementationOnly;
21562165
topLevelFilter |= ModuleDecl::ImportFilterKind::InternalOrBelow;
21572166
topLevelFilter |= ModuleDecl::ImportFilterKind::PackageOnly,
21582167
topLevelFilter |= ModuleDecl::ImportFilterKind::SPIOnly;
2159-
topLevel->getImportedModules(stack, topLevelFilter);
2168+
getImportedModules(stack, topLevelFilter);
21602169

21612170
// Make sure the top-level module is first; we want pre-order-ish traversal.
2162-
stack.emplace_back(ImportPath::Access(), topLevel);
2171+
stack.emplace_back(ImportPath::Access(), const_cast<ModuleDecl *>(this));
21632172

21642173
while (!stack.empty()) {
21652174
auto next = stack.pop_back_val().importedModule;
21662175

21672176
if (!visited.insert(next).second)
21682177
continue;
21692178

2170-
if (next->getName() != getParentModule()->getName()) {
2179+
if (next->getName() != getName()) {
21712180
next->collectLinkLibraries(callback);
21722181
}
21732182

21742183
next->getImportedModules(stack, filter);
21752184
}
21762185
}
21772186

2187+
void
2188+
SourceFile::collectLinkLibraries(ModuleDecl::LinkLibraryCallback callback) const {}
2189+
21782190
bool ModuleDecl::walk(ASTWalker &Walker) {
21792191
llvm::SaveAndRestore<ASTWalker::ParentTy> SAR(Walker.Parent, this);
21802192
for (auto SF : getFiles())

lib/IRGen/GenDecl.cpp

Lines changed: 0 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -469,103 +469,6 @@ void IRGenModule::emitSourceFile(SourceFile &SF) {
469469
emitGlobalDecl(localDecl);
470470
for (auto *opaqueDecl : SF.getOpaqueReturnTypeDecls())
471471
maybeEmitOpaqueTypeDecl(opaqueDecl);
472-
473-
SF.collectLinkLibraries([this](LinkLibrary linkLib) {
474-
this->addLinkLibrary(linkLib);
475-
});
476-
477-
if (ObjCInterop)
478-
this->addLinkLibrary(LinkLibrary("objc", LibraryKind::Library));
479-
480-
// If C++ interop is enabled, add -lc++ on Darwin and -lstdc++ on linux.
481-
// Also link with C++ bridging utility module (Cxx) and C++ stdlib overlay
482-
// (std) if available.
483-
if (Context.LangOpts.EnableCXXInterop) {
484-
const llvm::Triple &target = Context.LangOpts.Target;
485-
if (target.isOSDarwin())
486-
this->addLinkLibrary(LinkLibrary("c++", LibraryKind::Library));
487-
else if (target.isOSLinux())
488-
this->addLinkLibrary(LinkLibrary("stdc++", LibraryKind::Library));
489-
490-
// Do not try to link Cxx with itself.
491-
if (!getSwiftModule()->getName().is("Cxx")) {
492-
bool isStatic = false;
493-
if (const auto *M = Context.getModuleByName("Cxx"))
494-
isStatic = M->isStaticLibrary();
495-
this->addLinkLibrary(LinkLibrary(target.isOSWindows() && isStatic
496-
? "libswiftCxx"
497-
: "swiftCxx",
498-
LibraryKind::Library));
499-
}
500-
501-
// Do not try to link CxxStdlib with the C++ standard library, Cxx or
502-
// itself.
503-
if (llvm::none_of(llvm::ArrayRef{"Cxx", "CxxStdlib", "std"},
504-
[M = getSwiftModule()->getName().str()](StringRef Name) {
505-
return M == Name;
506-
})) {
507-
// Only link with CxxStdlib on platforms where the overlay is available.
508-
switch (target.getOS()) {
509-
case llvm::Triple::Linux:
510-
if (!target.isAndroid())
511-
this->addLinkLibrary(LinkLibrary("swiftCxxStdlib",
512-
LibraryKind::Library));
513-
break;
514-
case llvm::Triple::Win32: {
515-
bool isStatic = Context.getModuleByName("CxxStdlib")->isStaticLibrary();
516-
this->addLinkLibrary(
517-
LinkLibrary(isStatic ? "libswiftCxxStdlib" : "swiftCxxStdlib",
518-
LibraryKind::Library));
519-
break;
520-
}
521-
default:
522-
if (target.isOSDarwin())
523-
this->addLinkLibrary(LinkLibrary("swiftCxxStdlib",
524-
LibraryKind::Library));
525-
break;
526-
}
527-
}
528-
}
529-
530-
// FIXME: It'd be better to have the driver invocation or build system that
531-
// executes the linker introduce these compatibility libraries, since at
532-
// that point we know whether we're building an executable, which is the only
533-
// place where the compatibility libraries take effect. For the benefit of
534-
// build systems that build Swift code, but don't use Swift to drive
535-
// the linker, we can also use autolinking to pull in the compatibility
536-
// libraries. This may however cause the library to get pulled in in
537-
// situations where it isn't useful, such as for dylibs, though this is
538-
// harmless aside from code size.
539-
if (!IRGen.Opts.UseJIT && !Context.LangOpts.hasFeature(Feature::Embedded)) {
540-
auto addBackDeployLib = [&](llvm::VersionTuple version,
541-
StringRef libraryName, bool forceLoad) {
542-
std::optional<llvm::VersionTuple> compatibilityVersion;
543-
if (libraryName == "swiftCompatibilityDynamicReplacements") {
544-
compatibilityVersion = IRGen.Opts.
545-
AutolinkRuntimeCompatibilityDynamicReplacementLibraryVersion;
546-
} else if (libraryName == "swiftCompatibilityConcurrency") {
547-
compatibilityVersion =
548-
IRGen.Opts.AutolinkRuntimeCompatibilityConcurrencyLibraryVersion;
549-
} else {
550-
compatibilityVersion = IRGen.Opts.
551-
AutolinkRuntimeCompatibilityLibraryVersion;
552-
}
553-
554-
if (!compatibilityVersion)
555-
return;
556-
557-
if (*compatibilityVersion > version)
558-
return;
559-
560-
this->addLinkLibrary(LinkLibrary(libraryName,
561-
LibraryKind::Library,
562-
forceLoad));
563-
};
564-
565-
#define BACK_DEPLOYMENT_LIB(Version, Filter, LibraryName, ForceLoad) \
566-
addBackDeployLib(llvm::VersionTuple Version, LibraryName, ForceLoad);
567-
#include "swift/Frontend/BackDeploymentLibs.def"
568-
}
569472
}
570473

571474
/// Emit all the top-level code in the synthesized file unit.

lib/IRGen/IRGen.cpp

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1180,13 +1180,11 @@ GeneratedModule IRGenRequest::evaluate(Evaluator &evaluator,
11801180
if (auto *synthSFU = file->getSynthesizedFile()) {
11811181
IGM.emitSynthesizedFileUnit(*synthSFU);
11821182
}
1183-
} else {
1184-
file->collectLinkLibraries([&IGM](LinkLibrary LinkLib) {
1185-
IGM.addLinkLibrary(LinkLib);
1186-
});
11871183
}
11881184
}
11891185

1186+
IGM.addLinkLibraries();
1187+
11901188
// Okay, emit any definitions that we suddenly need.
11911189
irgen.emitLazyDefinitions();
11921190

@@ -1401,7 +1399,6 @@ static void performParallelIRGeneration(IRGenDescriptor desc) {
14011399
IRGenModule *IGM = new IRGenModule(
14021400
irgen, std::move(targetMachine), nextSF, desc.ModuleName, *OutputIter++,
14031401
nextSF->getFilename(), nextSF->getPrivateDiscriminator().str());
1404-
IGMcreated = true;
14051402

14061403
initLLVMModule(*IGM, *SILMod);
14071404
if (!DidRunSILCodeGenPreparePasses) {
@@ -1412,6 +1409,11 @@ static void performParallelIRGeneration(IRGenDescriptor desc) {
14121409
}
14131410

14141411
(void)layoutStringsEnabled(*IGM, /*diagnose*/ true);
1412+
1413+
// Only need to do this once.
1414+
if (!IGMcreated)
1415+
IGM->addLinkLibraries();
1416+
IGMcreated = true;
14151417
}
14161418

14171419
if (!IGMcreated) {
@@ -1434,10 +1436,6 @@ static void performParallelIRGeneration(IRGenDescriptor desc) {
14341436
CurrentIGMPtr IGM = irgen.getGenModule(synthSFU);
14351437
IGM->emitSynthesizedFileUnit(*synthSFU);
14361438
}
1437-
} else {
1438-
File->collectLinkLibraries([&](LinkLibrary LinkLib) {
1439-
irgen.getPrimaryIGM()->addLinkLibrary(LinkLib);
1440-
});
14411439
}
14421440
}
14431441

lib/IRGen/IRGenModule.cpp

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/AST/IRGenOptions.h"
2222
#include "swift/AST/IRGenRequests.h"
2323
#include "swift/AST/Module.h"
24+
#include "swift/AST/ModuleDependencies.h"
2425
#include "swift/Basic/LLVMExtras.h"
2526
#include "swift/ClangImporter/ClangImporter.h"
2627
#include "swift/Demangling/ManglingMacros.h"
@@ -1608,6 +1609,110 @@ void IRGenModule::addLinkLibrary(const LinkLibrary &linkLib) {
16081609
}
16091610
}
16101611

1612+
void IRGenModule::addLinkLibraries() {
1613+
auto registerLinkLibrary = [this](const LinkLibrary &ll) {
1614+
this->addLinkLibrary(ll);
1615+
};
1616+
1617+
getSwiftModule()->collectLinkLibraries(
1618+
[registerLinkLibrary](LinkLibrary linkLib) {
1619+
registerLinkLibrary(linkLib);
1620+
});
1621+
1622+
if (ObjCInterop)
1623+
registerLinkLibrary(LinkLibrary("objc", LibraryKind::Library));
1624+
1625+
// If C++ interop is enabled, add -lc++ on Darwin and -lstdc++ on linux.
1626+
// Also link with C++ bridging utility module (Cxx) and C++ stdlib overlay
1627+
// (std) if available.
1628+
if (Context.LangOpts.EnableCXXInterop) {
1629+
const llvm::Triple &target = Context.LangOpts.Target;
1630+
if (target.isOSDarwin())
1631+
registerLinkLibrary(LinkLibrary("c++", LibraryKind::Library));
1632+
else if (target.isOSLinux())
1633+
registerLinkLibrary(LinkLibrary("stdc++", LibraryKind::Library));
1634+
1635+
// Do not try to link Cxx with itself.
1636+
if (!getSwiftModule()->getName().is("Cxx")) {
1637+
bool isStatic = false;
1638+
if (const auto *M = Context.getModuleByName("Cxx"))
1639+
isStatic = M->isStaticLibrary();
1640+
registerLinkLibrary(LinkLibrary(target.isOSWindows() && isStatic
1641+
? "libswiftCxx"
1642+
: "swiftCxx",
1643+
LibraryKind::Library));
1644+
}
1645+
1646+
// Do not try to link CxxStdlib with the C++ standard library, Cxx or
1647+
// itself.
1648+
if (llvm::none_of(llvm::ArrayRef{"Cxx", "CxxStdlib", "std"},
1649+
[M = getSwiftModule()->getName().str()](StringRef Name) {
1650+
return M == Name;
1651+
})) {
1652+
// Only link with CxxStdlib on platforms where the overlay is available.
1653+
switch (target.getOS()) {
1654+
case llvm::Triple::Linux:
1655+
if (!target.isAndroid())
1656+
registerLinkLibrary(LinkLibrary("swiftCxxStdlib",
1657+
LibraryKind::Library));
1658+
break;
1659+
case llvm::Triple::Win32: {
1660+
bool isStatic = Context.getModuleByName("CxxStdlib")->isStaticLibrary();
1661+
registerLinkLibrary(
1662+
LinkLibrary(isStatic ? "libswiftCxxStdlib" : "swiftCxxStdlib",
1663+
LibraryKind::Library));
1664+
break;
1665+
}
1666+
default:
1667+
if (target.isOSDarwin())
1668+
registerLinkLibrary(LinkLibrary("swiftCxxStdlib",
1669+
LibraryKind::Library));
1670+
break;
1671+
}
1672+
}
1673+
}
1674+
1675+
// FIXME: It'd be better to have the driver invocation or build system that
1676+
// executes the linker introduce these compatibility libraries, since at
1677+
// that point we know whether we're building an executable, which is the only
1678+
// place where the compatibility libraries take effect. For the benefit of
1679+
// build systems that build Swift code, but don't use Swift to drive
1680+
// the linker, we can also use autolinking to pull in the compatibility
1681+
// libraries. This may however cause the library to get pulled in in
1682+
// situations where it isn't useful, such as for dylibs, though this is
1683+
// harmless aside from code size.
1684+
if (!IRGen.Opts.UseJIT && !Context.LangOpts.hasFeature(Feature::Embedded)) {
1685+
auto addBackDeployLib = [&](llvm::VersionTuple version,
1686+
StringRef libraryName, bool forceLoad) {
1687+
std::optional<llvm::VersionTuple> compatibilityVersion;
1688+
if (libraryName == "swiftCompatibilityDynamicReplacements") {
1689+
compatibilityVersion = IRGen.Opts.
1690+
AutolinkRuntimeCompatibilityDynamicReplacementLibraryVersion;
1691+
} else if (libraryName == "swiftCompatibilityConcurrency") {
1692+
compatibilityVersion =
1693+
IRGen.Opts.AutolinkRuntimeCompatibilityConcurrencyLibraryVersion;
1694+
} else {
1695+
compatibilityVersion = IRGen.Opts.
1696+
AutolinkRuntimeCompatibilityLibraryVersion;
1697+
}
1698+
1699+
if (!compatibilityVersion)
1700+
return;
1701+
1702+
if (*compatibilityVersion > version)
1703+
return;
1704+
1705+
registerLinkLibrary(LinkLibrary(libraryName,
1706+
LibraryKind::Library,
1707+
forceLoad));
1708+
};
1709+
1710+
#define BACK_DEPLOYMENT_LIB(Version, Filter, LibraryName, ForceLoad) \
1711+
addBackDeployLib(llvm::VersionTuple Version, LibraryName, ForceLoad);
1712+
#include "swift/Frontend/BackDeploymentLibs.def"
1713+
}
1714+
}
1715+
16111716
static bool replaceModuleFlagsEntry(llvm::LLVMContext &Ctx,
16121717
llvm::Module &Module, StringRef EntryName,
16131718
llvm::Module::ModFlagBehavior Behavior,

lib/IRGen/IRGenModule.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1563,6 +1563,8 @@ private: \
15631563

15641564
void emitSourceFile(SourceFile &SF);
15651565
void emitSynthesizedFileUnit(SynthesizedFileUnit &SFU);
1566+
1567+
void addLinkLibraries();
15661568
void addLinkLibrary(const LinkLibrary &linkLib);
15671569

15681570
/// Attempt to finalize the module.

0 commit comments

Comments
 (0)