Skip to content

Commit f8e35f0

Browse files
authored
Merge pull request #76151 from slavapestov/compiler-perf-fixes-6.0
[6.0] Cherry-pick a couple of compile-time performance optimizations
2 parents 2ef2a5f + a95040c commit f8e35f0

File tree

9 files changed

+203
-164
lines changed

9 files changed

+203
-164
lines changed

include/swift/AST/FileUnit.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -125,17 +125,6 @@ class FileUnit : public DeclContext, public ASTAllocated<FileUnit> {
125125
const ModuleDecl *importedModule,
126126
llvm::SmallSetVector<Identifier, 4> &spiGroups) const {};
127127

128-
/// Checks whether this file imports \c module as \c @_weakLinked.
129-
virtual bool importsModuleAsWeakLinked(const ModuleDecl *module) const {
130-
// For source files, this should be overridden to inspect the import
131-
// declarations in the file. Other kinds of file units, like serialized
132-
// modules, can just use this default implementation since the @_weakLinked
133-
// attribute is not transitive. If module C is imported @_weakLinked by
134-
// module B, that does not imply that module A imports module C @_weakLinked
135-
// if it imports module B.
136-
return false;
137-
}
138-
139128
virtual std::optional<Fingerprint>
140129
loadFingerprint(const IterableDeclContext *IDC) const {
141130
return std::nullopt;

include/swift/AST/ImportCache.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,13 +127,18 @@ class alignas(ImportedModule) ImportCache {
127127
llvm::DenseMap<std::tuple<const ModuleDecl *,
128128
const DeclContext *>,
129129
bool> SwiftOnlyCache;
130+
llvm::DenseMap<const ModuleDecl *, ArrayRef<ModuleDecl *>> WeakCache;
130131

131132
ImportPath::Access EmptyAccessPath;
132133

133134
ArrayRef<ImportPath::Access> allocateArray(
134135
ASTContext &ctx,
135136
SmallVectorImpl<ImportPath::Access> &results);
136137

138+
ArrayRef<ModuleDecl *> allocateArray(
139+
ASTContext &ctx,
140+
llvm::SetVector<ModuleDecl *> &results);
141+
137142
ImportSet &getImportSet(ASTContext &ctx,
138143
ArrayRef<ImportedModule> topLevelImports);
139144

@@ -167,6 +172,13 @@ class alignas(ImportedModule) ImportCache {
167172
const ModuleDecl *other,
168173
const DeclContext *dc);
169174

175+
/// Returns all weak-linked imported modules.
176+
ArrayRef<ModuleDecl *>
177+
getWeakImports(const ModuleDecl *mod);
178+
179+
bool isWeakImportedBy(const ModuleDecl *mod,
180+
const ModuleDecl *from);
181+
170182
/// This is a hack to cope with main file parsing and REPL parsing, where
171183
/// we can add ImportDecls after import resolution.
172184
void clear() {

include/swift/AST/SourceFile.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -474,9 +474,6 @@ class SourceFile final : public FileUnit {
474474
const ModuleDecl *importedModule,
475475
llvm::SmallSetVector<Identifier, 4> &spiGroups) const override;
476476

477-
/// Is \p module imported as \c @_weakLinked by this file?
478-
bool importsModuleAsWeakLinked(const ModuleDecl *module) const override;
479-
480477
// Is \p targetDecl accessible as an explicitly imported SPI from this file?
481478
bool isImportedAsSPI(const ValueDecl *targetDecl) const;
482479

lib/AST/ImportCache.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "swift/AST/FileUnit.h"
2222
#include "swift/AST/ImportCache.h"
2323
#include "swift/AST/Module.h"
24+
#include "swift/AST/SourceFile.h"
2425

2526
using namespace swift;
2627
using namespace namelookup;
@@ -391,3 +392,56 @@ swift::namelookup::getAllImports(const DeclContext *dc) {
391392
return dc->getASTContext().getImportCache().getImportSet(dc)
392393
.getAllImports();
393394
}
395+
396+
ArrayRef<ModuleDecl *> ImportCache::allocateArray(
397+
ASTContext &ctx,
398+
llvm::SetVector<ModuleDecl *> &results) {
399+
if (results.empty())
400+
return {};
401+
else
402+
return ctx.AllocateCopy(results.getArrayRef());
403+
}
404+
405+
ArrayRef<ModuleDecl *>
406+
ImportCache::getWeakImports(const ModuleDecl *mod) {
407+
auto found = WeakCache.find(mod);
408+
if (found != WeakCache.end())
409+
return found->second;
410+
411+
llvm::SetVector<ModuleDecl *> result;
412+
413+
for (auto file : mod->getFiles()) {
414+
auto *sf = dyn_cast<SourceFile>(file);
415+
// Other kinds of file units, like serialized modules, can just use this
416+
// default implementation since the @_weakLinked attribute is not
417+
// transitive. If module C is imported @_weakLinked by module B, that does
418+
// not imply that module A imports module C @_weakLinked if it imports
419+
// module B.
420+
if (!sf)
421+
continue;
422+
423+
for (auto &import : sf->getImports()) {
424+
if (!import.options.contains(ImportFlags::WeakLinked))
425+
continue;
426+
427+
ModuleDecl *importedModule = import.module.importedModule;
428+
result.insert(importedModule);
429+
430+
auto reexportedModules = getImportSet(importedModule).getAllImports();
431+
for (auto reexportedModule : reexportedModules) {
432+
result.insert(reexportedModule.importedModule);
433+
}
434+
}
435+
}
436+
437+
auto resultArray = allocateArray(mod->getASTContext(), result);
438+
WeakCache[mod] = resultArray;
439+
return resultArray;
440+
}
441+
442+
bool ImportCache::isWeakImportedBy(const ModuleDecl *mod,
443+
const ModuleDecl *from) {
444+
auto weakImports = getWeakImports(from);
445+
return std::find(weakImports.begin(), weakImports.end(), mod)
446+
!= weakImports.end();
447+
}

lib/AST/Module.cpp

Lines changed: 23 additions & 44 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())
@@ -3090,35 +3102,6 @@ bool SourceFile::isImportedAsSPI(const ValueDecl *targetDecl) const {
30903102
return false;
30913103
}
30923104

3093-
bool SourceFile::importsModuleAsWeakLinked(const ModuleDecl *module) const {
3094-
for (auto &import : *Imports) {
3095-
if (!import.options.contains(ImportFlags::WeakLinked))
3096-
continue;
3097-
3098-
const ModuleDecl *importedModule = import.module.importedModule;
3099-
if (module == importedModule)
3100-
return true;
3101-
3102-
// Also check whether the target module is actually the underlyingClang
3103-
// module for this @_weakLinked import.
3104-
const ModuleDecl *clangModule =
3105-
importedModule->getUnderlyingModuleIfOverlay();
3106-
if (module == clangModule)
3107-
return true;
3108-
3109-
// Traverse the exported modules of this weakly-linked module to ensure
3110-
// that we weak-link declarations from its exported peers.
3111-
SmallVector<ImportedModule, 8> reexportedModules;
3112-
importedModule->getImportedModules(reexportedModules,
3113-
ModuleDecl::ImportFilterKind::Exported);
3114-
for (const ImportedModule &reexportedModule : reexportedModules) {
3115-
if (module == reexportedModule.importedModule)
3116-
return true;
3117-
}
3118-
}
3119-
return false;
3120-
}
3121-
31223105
bool ModuleDecl::isImportedAsSPI(const SpecializeAttr *attr,
31233106
const ValueDecl *targetDecl) const {
31243107
auto declSPIGroups = attr->getSPIGroups();
@@ -3150,11 +3133,7 @@ bool ModuleDecl::isImportedAsSPI(Identifier spiGroup,
31503133
}
31513134

31523135
bool ModuleDecl::isImportedAsWeakLinked(const ModuleDecl *module) const {
3153-
for (auto file : getFiles()) {
3154-
if (file->importsModuleAsWeakLinked(module))
3155-
return true;
3156-
}
3157-
return false;
3136+
return getASTContext().getImportCache().isWeakImportedBy(module, this);
31583137
}
31593138

31603139
bool Decl::isSPI() const {

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

0 commit comments

Comments
 (0)