Skip to content

Commit 649f134

Browse files
committed
Add frontend options to write SIL and LLVM IR as additional compilation output.
This change introduces two new frontend options that enable writing intermediate representations as additional outputs during compilation: -sil-output-path <path>: Outputs SIL to the specified path -ir-output-path <path>: Outputs LLVM IR to the specified path These options can be useful for debugging and analysis tools workflows that need access to intermediate compilation artifacts without requiring separate compiler invocations. rdar://160297898
1 parent f0af54c commit 649f134

15 files changed

+323
-56
lines changed

include/swift/AST/IRGenRequests.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,7 @@ struct IRGenDescriptor {
151151
const PrimarySpecificPaths &PSPs;
152152
StringRef PrivateDiscriminator;
153153
ArrayRef<std::string> parallelOutputFilenames;
154+
ArrayRef<std::string> parallelIROutputFilenames;
154155
llvm::GlobalVariable **outModuleHash;
155156
llvm::raw_pwrite_stream *out = nullptr;
156157

@@ -188,6 +189,7 @@ struct IRGenDescriptor {
188189
PSPs,
189190
PrivateDiscriminator,
190191
{},
192+
{},
191193
outModuleHash};
192194
}
193195

@@ -197,6 +199,7 @@ struct IRGenDescriptor {
197199
std::unique_ptr<SILModule> &&SILMod, StringRef ModuleName,
198200
const PrimarySpecificPaths &PSPs, SymsToEmit symsToEmit = std::nullopt,
199201
ArrayRef<std::string> parallelOutputFilenames = {},
202+
ArrayRef<std::string> parallelIROutputFilenames = {},
200203
llvm::GlobalVariable **outModuleHash = nullptr) {
201204
return IRGenDescriptor{M,
202205
symsToEmit,
@@ -209,6 +212,7 @@ struct IRGenDescriptor {
209212
PSPs,
210213
"",
211214
parallelOutputFilenames,
215+
parallelIROutputFilenames,
212216
outModuleHash};
213217
}
214218

include/swift/Basic/SupplementaryOutputPaths.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,3 +166,9 @@ OUTPUT(YAMLOptRecordPath, TY_YAMLOptRecord)
166166

167167
/// The output path for bitstream optimization record file.
168168
OUTPUT(BitstreamOptRecordPath, TY_BitstreamOptRecord)
169+
170+
/// The output path to which we should output SIL as extra compilation output.
171+
OUTPUT(SILOutputPath, TY_SIL)
172+
173+
/// The output path to which we should output LLVM IR as extra compilation output.
174+
OUTPUT(LLVMIROutputPath, TY_LLVM_IR)

include/swift/FrontendTool/FrontendTool.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ int performFrontend(ArrayRef<const char *> args,
7979
FrontendObserver *observer = nullptr);
8080

8181
bool performCompileStepsPostSema(CompilerInstance &Instance, int &ReturnValue,
82-
FrontendObserver *observer);
82+
FrontendObserver *observer,
83+
ArrayRef<const char *> CommandLineArgs);
8384

8485
} // namespace swift
8586

include/swift/Option/FrontendOptions.td

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,18 @@ def emit_module_semantic_info_path
6363
: Separate<["-"], "emit-module-semantic-info-path">, MetaVarName<"<path>">,
6464
HelpText<"Output semantic info of current module to <path>">;
6565

66+
def sil_output_path
67+
: Separate<["-"], "sil-output-path">, MetaVarName<"<path>">,
68+
Flags<[FrontendOption, NoInteractiveOption, ArgumentIsPath,
69+
SupplementaryOutput, CacheInvariant]>,
70+
HelpText<"Output SIL to <path> as additional output during compilation">;
71+
72+
def ir_output_path
73+
: Separate<["-"], "ir-output-path">, MetaVarName<"<path>">,
74+
Flags<[FrontendOption, NoInteractiveOption, ArgumentIsPath,
75+
SupplementaryOutput, CacheInvariant]>,
76+
HelpText<"Output LLVM IR to <path> as additional output during compilation">;
77+
6678
def diagnostic_documentation_path
6779
: Separate<["-"], "diagnostic-documentation-path">, MetaVarName<"<path>">,
6880
HelpText<"Path to diagnostic documentation resources">;
@@ -266,7 +278,7 @@ def serialize_dependency_scan_cache : Flag<["-"], "serialize-dependency-scan-cac
266278

267279
def reuse_dependency_scan_cache : Flag<["-"], "load-dependency-scan-cache">,
268280
HelpText<"For performing a dependency scan, deserialize the scanner's internal state from a prior scan.">;
269-
281+
270282
def validate_prior_dependency_scan_cache : Flag<["-"], "validate-prior-dependency-scan-cache">,
271283
HelpText<"For performing a dependency scan with a prior scanner state, validate module dependencies.">;
272284

include/swift/Subsystems.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,9 +250,10 @@ namespace swift {
250250
GeneratedModule
251251
performIRGeneration(ModuleDecl *M, const IRGenOptions &Opts,
252252
const TBDGenOptions &TBDOpts,
253-
std::unique_ptr<SILModule> SILMod,
254-
StringRef ModuleName, const PrimarySpecificPaths &PSPs,
253+
std::unique_ptr<SILModule> SILMod, StringRef ModuleName,
254+
const PrimarySpecificPaths &PSPs,
255255
ArrayRef<std::string> parallelOutputFilenames,
256+
ArrayRef<std::string> parallelIROutputFilenames,
256257
llvm::GlobalVariable **outModuleHash = nullptr);
257258

258259
/// Turn the given Swift file into LLVM IR and return the generated module.

lib/Driver/ToolChains.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -943,6 +943,12 @@ void ToolChain::JobContext::addFrontendSupplementaryOutputArguments(
943943
addOutputsOfType(arguments, Output, Args,
944944
file_types::TY_SwiftModuleSummaryFile,
945945
"-emit-module-summary-path");
946+
947+
// Add extra output paths for SIL and LLVM IR
948+
addOutputsOfType(arguments, Output, Args, file_types::TY_SIL,
949+
"-sil-output-path");
950+
addOutputsOfType(arguments, Output, Args, file_types::TY_LLVM_IR,
951+
"-ir-output-path");
946952
}
947953

948954
ToolChain::InvocationInfo
@@ -1226,6 +1232,12 @@ ToolChain::constructInvocation(const MergeModuleJobAction &job,
12261232
addOutputsOfType(Arguments, context.Output, context.Args, file_types::TY_TBD,
12271233
"-emit-tbd-path");
12281234

1235+
// Add extra output paths for SIL and LLVM IR
1236+
addOutputsOfType(Arguments, context.Output, context.Args, file_types::TY_SIL,
1237+
"-sil-output-path");
1238+
addOutputsOfType(Arguments, context.Output, context.Args,
1239+
file_types::TY_LLVM_IR, "-ir-output-path");
1240+
12291241
context.Args.AddLastArg(Arguments, options::OPT_emit_symbol_graph);
12301242
context.Args.AddLastArg(Arguments, options::OPT_emit_symbol_graph_dir);
12311243
context.Args.AddLastArg(Arguments, options::OPT_include_spi_symbols);

lib/Frontend/ArgsToFrontendOutputsConverter.cpp

Lines changed: 60 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -380,18 +380,47 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments()
380380
options::OPT_emit_module_semantic_info_path);
381381
auto optRecordOutput = getSupplementaryFilenamesFromArguments(
382382
options::OPT_save_optimization_record_path);
383+
auto silOutput =
384+
getSupplementaryFilenamesFromArguments(options::OPT_sil_output_path);
385+
auto irOutput =
386+
getSupplementaryFilenamesFromArguments(options::OPT_ir_output_path);
383387
if (!clangHeaderOutput || !moduleOutput || !moduleDocOutput ||
384388
!dependenciesFile || !referenceDependenciesFile ||
385389
!serializedDiagnostics || !loadedModuleTrace || !TBD ||
386-
!moduleInterfaceOutput || !privateModuleInterfaceOutput || !packageModuleInterfaceOutput ||
387-
!moduleSourceInfoOutput || !moduleSummaryOutput || !abiDescriptorOutput ||
388-
!moduleSemanticInfoOutput || !optRecordOutput) {
390+
!moduleInterfaceOutput || !privateModuleInterfaceOutput ||
391+
!packageModuleInterfaceOutput || !moduleSourceInfoOutput ||
392+
!moduleSummaryOutput || !abiDescriptorOutput ||
393+
!moduleSemanticInfoOutput || !optRecordOutput || !silOutput ||
394+
!irOutput) {
389395
return std::nullopt;
390396
}
391397
std::vector<SupplementaryOutputPaths> result;
392398

393399
const unsigned N =
394400
InputsAndOutputs.countOfFilesProducingSupplementaryOutput();
401+
402+
// Find the index of SIL output path matching module name
403+
auto findSILIndexForModuleName = [&]() -> unsigned {
404+
if (!InputsAndOutputs.hasPrimaryInputs() && silOutput->size() > 1) {
405+
// In WMO mode with multiple SIL output paths, find the one whose matches
406+
// module name
407+
for (unsigned i = 0; i < silOutput->size(); ++i) {
408+
StringRef silPath = (*silOutput)[i];
409+
if (!silPath.empty()) {
410+
StringRef basename = llvm::sys::path::stem(silPath);
411+
if (basename == ModuleName) {
412+
return i;
413+
}
414+
}
415+
}
416+
// If no match found, fall back to first
417+
return 0;
418+
}
419+
return 0;
420+
};
421+
422+
unsigned silOutputIndex = findSILIndexForModuleName();
423+
395424
for (unsigned i = 0; i < N; ++i) {
396425
SupplementaryOutputPaths sop;
397426
sop.ClangHeaderOutputPath = (*clangHeaderOutput)[i];
@@ -413,6 +442,8 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments()
413442
sop.ModuleSemanticInfoOutputPath = (*moduleSemanticInfoOutput)[i];
414443
sop.YAMLOptRecordPath = (*optRecordOutput)[i];
415444
sop.BitstreamOptRecordPath = (*optRecordOutput)[i];
445+
sop.SILOutputPath = (*silOutput)[silOutputIndex];
446+
sop.LLVMIROutputPath = (*irOutput)[i];
416447
result.push_back(sop);
417448
}
418449
return result;
@@ -439,6 +470,15 @@ SupplementaryOutputPathsComputer::getSupplementaryFilenamesFromArguments(
439470
paths.emplace_back();
440471
return paths;
441472
}
473+
// Special handling for SIL and IR output paths: allow multiple paths per file
474+
// type
475+
else if ((pathID == options::OPT_sil_output_path ||
476+
pathID == options::OPT_ir_output_path) &&
477+
paths.size() > N) {
478+
// For parallel compilation, we can have multiple SIL/IR output paths
479+
// so return all the paths.
480+
return paths;
481+
}
442482

443483
if (paths.empty())
444484
return std::vector<std::string>(N, std::string());
@@ -613,6 +653,9 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput(
613653
file_types::TY_BitstreamOptRecord, "",
614654
defaultSupplementaryOutputPathExcludingExtension);
615655

656+
auto SILOutputPath = pathsFromArguments.SILOutputPath;
657+
auto LLVMIROutputPath = pathsFromArguments.LLVMIROutputPath;
658+
616659
SupplementaryOutputPaths sop;
617660
sop.ClangHeaderOutputPath = clangHeaderOutputPath;
618661
sop.ModuleOutputPath = moduleOutputPath;
@@ -635,6 +678,8 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput(
635678
sop.ModuleSemanticInfoOutputPath = ModuleSemanticInfoOutputPath;
636679
sop.YAMLOptRecordPath = YAMLOptRecordPath;
637680
sop.BitstreamOptRecordPath = bitstreamOptRecordPath;
681+
sop.SILOutputPath = SILOutputPath;
682+
sop.LLVMIROutputPath = LLVMIROutputPath;
638683
return sop;
639684
}
640685

@@ -741,18 +786,18 @@ createFromTypeToPathMap(const TypeToPathMap *map) {
741786

742787
std::optional<std::vector<SupplementaryOutputPaths>>
743788
SupplementaryOutputPathsComputer::readSupplementaryOutputFileMap() const {
744-
if (Arg *A = Args.getLastArg(options::OPT_emit_objc_header_path,
745-
options::OPT_emit_module_path,
746-
options::OPT_emit_module_doc_path,
747-
options::OPT_emit_dependencies_path,
748-
options::OPT_emit_reference_dependencies_path,
749-
options::OPT_serialize_diagnostics_path,
750-
options::OPT_emit_loaded_module_trace_path,
751-
options::OPT_emit_module_interface_path,
752-
options::OPT_emit_private_module_interface_path,
753-
options::OPT_emit_package_module_interface_path,
754-
options::OPT_emit_module_source_info_path,
755-
options::OPT_emit_tbd_path)) {
789+
if (Arg *A = Args.getLastArg(
790+
options::OPT_emit_objc_header_path, options::OPT_emit_module_path,
791+
options::OPT_emit_module_doc_path,
792+
options::OPT_emit_dependencies_path,
793+
options::OPT_emit_reference_dependencies_path,
794+
options::OPT_serialize_diagnostics_path,
795+
options::OPT_emit_loaded_module_trace_path,
796+
options::OPT_emit_module_interface_path,
797+
options::OPT_emit_private_module_interface_path,
798+
options::OPT_emit_package_module_interface_path,
799+
options::OPT_emit_module_source_info_path, options::OPT_emit_tbd_path,
800+
options::OPT_sil_output_path, options::OPT_ir_output_path)) {
756801
Diags.diagnose(SourceLoc(),
757802
diag::error_cannot_have_supplementary_outputs,
758803
A->getSpelling(), "-supplementary-output-file-map");

0 commit comments

Comments
 (0)