Skip to content

Commit 5d998b8

Browse files
Merge pull request #59368 from aschwaighofer/single_module_in_num_threads_5.7
[5.7] IRGen: Add a frontend option to force single LLVM module emission in multithreaded mode
2 parents 96c7e06 + 91473cc commit 5d998b8

File tree

9 files changed

+105
-24
lines changed

9 files changed

+105
-24
lines changed

include/swift/AST/IRGenOptions.h

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ class IRGenOptions {
284284
/// objects.
285285
unsigned EmitStackPromotionChecks : 1;
286286

287+
unsigned UseSingleModuleLLVMEmission : 1;
288+
287289
/// Emit functions to separate sections.
288290
unsigned FunctionSections : 1;
289291

@@ -447,13 +449,13 @@ class IRGenOptions {
447449
DebugInfoFormat(IRGenDebugInfoFormat::None),
448450
DisableClangModuleSkeletonCUs(false), UseJIT(false),
449451
DisableLLVMOptzns(false), DisableSwiftSpecificLLVMOptzns(false),
450-
Playground(false),
451-
EmitStackPromotionChecks(false), FunctionSections(false),
452+
Playground(false), EmitStackPromotionChecks(false),
453+
UseSingleModuleLLVMEmission(false), FunctionSections(false),
452454
PrintInlineTree(false), EmbedMode(IRGenEmbedMode::None),
453455
LLVMLTOKind(IRGenLLVMLTOKind::None),
454456
SwiftAsyncFramePointer(SwiftAsyncFramePointerKind::Auto),
455-
HasValueNamesSetting(false),
456-
ValueNames(false), ReflectionMetadata(ReflectionMetadataMode::Runtime),
457+
HasValueNamesSetting(false), ValueNames(false),
458+
ReflectionMetadata(ReflectionMetadataMode::Runtime),
457459
EnableReflectionNames(true), EnableAnonymousContextMangledNames(false),
458460
ForcePublicLinkage(false), LazyInitializeClassMetadata(false),
459461
LazyInitializeProtocolConformances(false),
@@ -468,8 +470,7 @@ class IRGenOptions {
468470
EnableGlobalISel(false), VirtualFunctionElimination(false),
469471
WitnessMethodElimination(false), ConditionalRuntimeRecords(false),
470472
InternalizeAtLink(false), InternalizeSymbols(false),
471-
NoPreallocatedInstantiationCaches(false),
472-
CmdArgs(),
473+
NoPreallocatedInstantiationCaches(false), CmdArgs(),
473474
SanitizeCoverage(llvm::SanitizerCoverageOptions()),
474475
TypeInfoFilter(TypeInfoDumpFilter::All) {}
475476

@@ -524,8 +525,8 @@ class IRGenOptions {
524525
return llvm::hash_value(0);
525526
}
526527

527-
bool hasMultipleIRGenThreads() const { return NumThreads > 1; }
528-
bool shouldPerformIRGenerationInParallel() const { return NumThreads != 0; }
528+
bool hasMultipleIRGenThreads() const { return !UseSingleModuleLLVMEmission && NumThreads > 1; }
529+
bool shouldPerformIRGenerationInParallel() const { return !UseSingleModuleLLVMEmission && NumThreads != 0; }
529530
bool hasMultipleIGMs() const { return hasMultipleIRGenThreads(); }
530531
};
531532

include/swift/Option/FrontendOptions.td

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,10 @@ def function_sections: Flag<["-"], "function-sections">,
499499
Flags<[FrontendOption, NoInteractiveOption]>,
500500
HelpText<"Emit functions to separate sections.">;
501501

502+
def enable_single_module_llvm_emission: Flag<["-"], "enable-single-module-llvm-emission">,
503+
Flags<[FrontendOption, NoInteractiveOption]>,
504+
HelpText<"Emit LLVM IR into a single LLVM module in multithreaded mode.">;
505+
502506
def stack_promotion_checks : Flag<["-"], "emit-stack-promotion-checks">,
503507
HelpText<"Emit runtime checks for correct stack promotion of objects.">;
504508

include/swift/Subsystems.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,11 @@ namespace swift {
258258
llvm::Module *Module,
259259
StringRef OutputFilename);
260260

261+
bool writeEmptyOutputFilesFor(
262+
const ASTContext &Context,
263+
std::vector<std::string> &ParallelOutputFilenames,
264+
const IRGenOptions &IRGenOpts);
265+
261266
/// Run the LLVM passes. In multi-threaded compilation this will be done for
262267
/// multiple LLVM modules in parallel.
263268
/// \param Diags The Diagnostic Engine.

lib/Frontend/CompilerInvocation.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2326,6 +2326,9 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
23262326
"-num-threads");
23272327
}
23282328
}
2329+
Opts.UseSingleModuleLLVMEmission =
2330+
Opts.NumThreads != 0 &&
2331+
Args.hasArg(OPT_enable_single_module_llvm_emission);
23292332

23302333
if (SWIFT_ENABLE_GLOBAL_ISEL_ARM64 &&
23312334
Triple.getArch() == llvm::Triple::aarch64 &&

lib/FrontendTool/FrontendTool.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,13 @@ static bool performCompileStepsPostSILGen(CompilerInstance &Instance,
17241724
publicCMOSymbols))
17251725
return true;
17261726

1727+
if (IRGenOpts.UseSingleModuleLLVMEmission) {
1728+
// Pretend the other files that drivers/build systems expect exist by
1729+
// creating empty files.
1730+
if (writeEmptyOutputFilesFor(Context, ParallelOutputFilenames, IRGenOpts))
1731+
return true;
1732+
}
1733+
17271734
return generateCode(Instance, OutputFilename, IRModule.getModule(),
17281735
HashGlobal);
17291736
}

lib/IRGen/IRGen.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1485,7 +1485,8 @@ GeneratedModule swift::performIRGeneration(
14851485
outModuleHash);
14861486

14871487
if (Opts.shouldPerformIRGenerationInParallel() &&
1488-
!parallelOutputFilenames.empty()) {
1488+
!parallelOutputFilenames.empty() &&
1489+
!Opts.UseSingleModuleLLVMEmission) {
14891490
::performParallelIRGeneration(desc);
14901491
// TODO: Parallel LLVM compilation cannot be used if a (single) module is
14911492
// needed as return value.

lib/IRGen/IRGenModule.cpp

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include "swift/IRGen/Linking.h"
2929
#include "swift/Runtime/RuntimeFnWrappersGen.h"
3030
#include "swift/Runtime/Config.h"
31+
#include "swift/Subsystems.h"
3132
#include "clang/AST/ASTContext.h"
3233
#include "clang/Basic/CharInfo.h"
3334
#include "clang/Basic/TargetInfo.h"
@@ -1614,12 +1615,7 @@ void IRGenModule::emitAutolinkInfo() {
16141615
}
16151616
}
16161617

1617-
void IRGenModule::cleanupClangCodeGenMetadata() {
1618-
// Remove llvm.ident that ClangCodeGen might have left in the module.
1619-
auto *LLVMIdent = Module.getNamedMetadata("llvm.ident");
1620-
if (LLVMIdent)
1621-
Module.eraseNamedMetadata(LLVMIdent);
1622-
1618+
void emitSwiftVersionNumberIntoModule(llvm::Module *Module) {
16231619
// LLVM's object-file emission collects a fixed set of keys for the
16241620
// image info.
16251621
// Using "Objective-C Garbage Collection" as the key here is a hack,
@@ -1629,21 +1625,29 @@ void IRGenModule::cleanupClangCodeGenMetadata() {
16291625
const char *ObjectiveCGarbageCollection = "Objective-C Garbage Collection";
16301626
uint8_t Major, Minor;
16311627
std::tie(Major, Minor) = version::getSwiftNumericVersion();
1632-
uint32_t Value = (Major << 24) | (Minor << 16) | (swiftVersion << 8);
1633-
1634-
if (Module.getModuleFlag(ObjectiveCGarbageCollection)) {
1628+
uint32_t Value =
1629+
(Major << 24) | (Minor << 16) | (IRGenModule::swiftVersion << 8);
1630+
auto &llvmContext = Module->getContext();
1631+
if (Module->getModuleFlag(ObjectiveCGarbageCollection)) {
16351632
bool FoundOldEntry = replaceModuleFlagsEntry(
1636-
Module.getContext(), Module, ObjectiveCGarbageCollection,
1633+
llvmContext, *Module, ObjectiveCGarbageCollection,
16371634
llvm::Module::Override,
1638-
llvm::ConstantAsMetadata::get(
1639-
llvm::ConstantInt::get(Int32Ty, Value)));
1635+
llvm::ConstantAsMetadata::get(llvm::ConstantInt::get(
1636+
llvm::Type::getInt32Ty(llvmContext), Value)));
16401637

16411638
(void)FoundOldEntry;
16421639
assert(FoundOldEntry && "Could not replace old module flag entry?");
16431640
} else
1644-
Module.addModuleFlag(llvm::Module::Override,
1645-
ObjectiveCGarbageCollection,
1646-
Value);
1641+
Module->addModuleFlag(llvm::Module::Override, ObjectiveCGarbageCollection,
1642+
Value);
1643+
}
1644+
1645+
void IRGenModule::cleanupClangCodeGenMetadata() {
1646+
// Remove llvm.ident that ClangCodeGen might have left in the module.
1647+
auto *LLVMIdent = Module.getNamedMetadata("llvm.ident");
1648+
if (LLVMIdent)
1649+
Module.eraseNamedMetadata(LLVMIdent);
1650+
emitSwiftVersionNumberIntoModule(&Module);
16471651
}
16481652

16491653
bool IRGenModule::finalize() {
@@ -1862,3 +1866,40 @@ bool IRGenModule::isConcurrencyAvailable() {
18621866
AvailabilityContext::forDeploymentTarget(ctx);
18631867
return deploymentAvailability.isContainedIn(ctx.getConcurrencyAvailability());
18641868
}
1869+
1870+
/// Pretend the other files that drivers/build systems expect exist by
1871+
/// creating empty files. Used by UseSingleModuleLLVMEmission when
1872+
/// num-threads > 0.
1873+
bool swift::writeEmptyOutputFilesFor(
1874+
const ASTContext &Context,
1875+
std::vector<std::string>& ParallelOutputFilenames,
1876+
const IRGenOptions &IRGenOpts) {
1877+
1878+
for (auto fileName : ParallelOutputFilenames) {
1879+
// The first output file, was use for genuine output.
1880+
if (fileName == ParallelOutputFilenames[0])
1881+
continue;
1882+
1883+
std::unique_ptr<llvm::LLVMContext> llvmContext(new llvm::LLVMContext());
1884+
std::unique_ptr<clang::CodeGenerator> clangCodeGen(
1885+
createClangCodeGenerator(const_cast<ASTContext&>(Context),
1886+
*llvmContext, IRGenOpts, fileName, ""));
1887+
auto *llvmModule = clangCodeGen->GetModule();
1888+
1889+
auto *clangImporter = static_cast<ClangImporter *>(
1890+
Context.getClangModuleLoader());
1891+
llvmModule->setTargetTriple(
1892+
clangImporter->getTargetInfo().getTargetOpts().Triple);
1893+
1894+
// Add LLVM module flags.
1895+
auto &clangASTContext = clangImporter->getClangASTContext();
1896+
clangCodeGen->HandleTranslationUnit(
1897+
const_cast<clang::ASTContext &>(clangASTContext));
1898+
1899+
emitSwiftVersionNumberIntoModule(llvmModule);
1900+
1901+
swift::performLLVM(IRGenOpts, const_cast<ASTContext&>(Context),
1902+
llvmModule, fileName);
1903+
}
1904+
return false;
1905+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
public func B() {
2+
print("B")
3+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -module-name X -num-threads 1 -O -enable-single-module-llvm-emission -emit-ir %s %S/Inputs/single-module-num-threads-2.swift -o %t/single-module-num-threads.ll -o %t/single-module-num-threads-2.ll
3+
// RUN: %FileCheck %s < %t/single-module-num-threads.ll
4+
// RUN: %FileCheck %s --check-prefix=EMPTY < %t/single-module-num-threads-2.ll
5+
6+
// CHECK: define{{.*}} swiftcc void @"$s1X1AyyF"()
7+
// CHECK: define{{.*}} swiftcc void @"$s1X1ByyF"()
8+
9+
// EMPTY-NOT: s1X1AyyF
10+
// EMPTY-NOT: s1X1ByyF
11+
12+
// Make sure that with enable-single-module-llvm-emission we emit all code into
13+
// one llvm module.
14+
public func A() {
15+
print("A")
16+
}

0 commit comments

Comments
 (0)