Skip to content

Commit 6ef4ec1

Browse files
committed
IRGen: Add a frontend option to force single LLVM module emission in multithreaded mode
This allows to experiment with single module LLVM emission without having to change drivers that expect multiple output files.
1 parent 5ed21c6 commit 6ef4ec1

File tree

7 files changed

+61
-9
lines changed

7 files changed

+61
-9
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
#ifndef NDEBUG
@@ -530,8 +531,8 @@ class IRGenOptions {
530531
return llvm::hash_value(0);
531532
}
532533

533-
bool hasMultipleIRGenThreads() const { return NumThreads > 1; }
534-
bool shouldPerformIRGenerationInParallel() const { return NumThreads != 0; }
534+
bool hasMultipleIRGenThreads() const { return !UseSingleModuleLLVMEmission && NumThreads > 1; }
535+
bool shouldPerformIRGenerationInParallel() const { return !UseSingleModuleLLVMEmission && NumThreads != 0; }
535536
bool hasMultipleIGMs() const { return hasMultipleIRGenThreads(); }
536537
};
537538

include/swift/Option/FrontendOptions.td

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

508+
def enable_single_module_llvm_emission: Flag<["-"], "enable-single-module-llvm-emission">,
509+
Flags<[FrontendOption, NoInteractiveOption]>,
510+
HelpText<"Emit LLVM IR into a single LLVM module in multithreaded mode.">;
511+
508512
def stack_promotion_checks : Flag<["-"], "emit-stack-promotion-checks">,
509513
HelpText<"Emit runtime checks for correct stack promotion of objects.">;
510514

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
@@ -2299,6 +2299,9 @@ static bool ParseIRGenArgs(IRGenOptions &Opts, ArgList &Args,
22992299
"-num-threads");
23002300
}
23012301
}
2302+
Opts.UseSingleModuleLLVMEmission =
2303+
Opts.NumThreads != 0 &&
2304+
Args.hasArg(OPT_enable_single_module_llvm_emission);
23022305

23032306
if (SWIFT_ENABLE_GLOBAL_ISEL_ARM64 &&
23042307
Triple.getArch() == llvm::Triple::aarch64 &&

lib/FrontendTool/FrontendTool.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,6 +1727,13 @@ static bool performCompileStepsPostSILGen(CompilerInstance &Instance,
17271727
if (validateTBDIfNeeded(Invocation, MSF, *IRModule.getModule()))
17281728
return true;
17291729

1730+
if (IRGenOpts.UseSingleModuleLLVMEmission) {
1731+
// Pretend the other files that drivers/build systems expect exist by
1732+
// creating empty files.
1733+
if (writeEmptyOutputFilesFor(Context, ParallelOutputFilenames, IRGenOpts))
1734+
return true;
1735+
}
1736+
17301737
return generateCode(Instance, OutputFilename, IRModule.getModule(),
17311738
HashGlobal);
17321739
}

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: 31 additions & 0 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"
@@ -1884,3 +1885,33 @@ bool IRGenModule::isConcurrencyAvailable() {
18841885
AvailabilityContext::forDeploymentTarget(ctx);
18851886
return deploymentAvailability.isContainedIn(ctx.getConcurrencyAvailability());
18861887
}
1888+
1889+
/// Pretend the other files that drivers/build systems expect exist by
1890+
/// creating empty files. Used by UseSingleModuleLLVMEmission when
1891+
/// num-threads > 0.
1892+
bool swift::writeEmptyOutputFilesFor(
1893+
const ASTContext &Context,
1894+
std::vector<std::string>& ParallelOutputFilenames,
1895+
const IRGenOptions &IRGenOpts) {
1896+
1897+
for (auto fileName : ParallelOutputFilenames) {
1898+
// The first output file, was use for genuine output.
1899+
if (fileName == ParallelOutputFilenames[0])
1900+
continue;
1901+
1902+
std::unique_ptr<llvm::LLVMContext> llvmContext(new llvm::LLVMContext());
1903+
std::unique_ptr<clang::CodeGenerator> clangCodeGen(
1904+
createClangCodeGenerator(const_cast<ASTContext&>(Context),
1905+
*llvmContext, IRGenOpts, fileName, ""));
1906+
auto *llvmModule = clangCodeGen->GetModule();
1907+
1908+
auto *clangImporter = static_cast<ClangImporter *>(
1909+
Context.getClangModuleLoader());
1910+
llvmModule->setTargetTriple(
1911+
clangImporter->getTargetInfo().getTargetOpts().Triple);
1912+
1913+
swift::performLLVM(IRGenOpts, const_cast<ASTContext&>(Context),
1914+
llvmModule, fileName);
1915+
}
1916+
return false;
1917+
}

0 commit comments

Comments
 (0)