Skip to content

Commit a76fa36

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 3e981b7 commit a76fa36

File tree

8 files changed

+103
-3
lines changed

8 files changed

+103
-3
lines changed

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/Option/FrontendOptions.td

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,14 @@ 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+
HelpText<"Output SIL to <path> as additional output during compilation">;
69+
70+
def ir_output_path
71+
: Separate<["-"], "ir-output-path">, MetaVarName<"<path>">,
72+
HelpText<"Output LLVM IR to <path> as additional output during compilation">;
73+
6674
def diagnostic_documentation_path
6775
: Separate<["-"], "diagnostic-documentation-path">, MetaVarName<"<path>">,
6876
HelpText<"Path to diagnostic documentation resources">;
@@ -266,7 +274,7 @@ def serialize_dependency_scan_cache : Flag<["-"], "serialize-dependency-scan-cac
266274

267275
def reuse_dependency_scan_cache : Flag<["-"], "load-dependency-scan-cache">,
268276
HelpText<"For performing a dependency scan, deserialize the scanner's internal state from a prior scan.">;
269-
277+
270278
def validate_prior_dependency_scan_cache : Flag<["-"], "validate-prior-dependency-scan-cache">,
271279
HelpText<"For performing a dependency scan with a prior scanner state, validate module dependencies.">;
272280

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, file_types::TY_LLVM_IR,
1239+
"-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: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -380,12 +380,16 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments()
380380
options::OPT_emit_module_semantic_info_path);
381381
auto optRecordOutput = getSupplementaryFilenamesFromArguments(
382382
options::OPT_save_optimization_record_path);
383+
auto silOutput = getSupplementaryFilenamesFromArguments(
384+
options::OPT_sil_output_path);
385+
auto irOutput = getSupplementaryFilenamesFromArguments(
386+
options::OPT_ir_output_path);
383387
if (!clangHeaderOutput || !moduleOutput || !moduleDocOutput ||
384388
!dependenciesFile || !referenceDependenciesFile ||
385389
!serializedDiagnostics || !loadedModuleTrace || !TBD ||
386390
!moduleInterfaceOutput || !privateModuleInterfaceOutput || !packageModuleInterfaceOutput ||
387391
!moduleSourceInfoOutput || !moduleSummaryOutput || !abiDescriptorOutput ||
388-
!moduleSemanticInfoOutput || !optRecordOutput) {
392+
!moduleSemanticInfoOutput || !optRecordOutput || !silOutput || !irOutput) {
389393
return std::nullopt;
390394
}
391395
std::vector<SupplementaryOutputPaths> result;
@@ -413,6 +417,8 @@ SupplementaryOutputPathsComputer::getSupplementaryOutputPathsFromArguments()
413417
sop.ModuleSemanticInfoOutputPath = (*moduleSemanticInfoOutput)[i];
414418
sop.YAMLOptRecordPath = (*optRecordOutput)[i];
415419
sop.BitstreamOptRecordPath = (*optRecordOutput)[i];
420+
sop.SILOutputPath = (*silOutput)[i];
421+
sop.LLVMIROutputPath = (*irOutput)[i];
416422
result.push_back(sop);
417423
}
418424
return result;
@@ -613,6 +619,9 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput(
613619
file_types::TY_BitstreamOptRecord, "",
614620
defaultSupplementaryOutputPathExcludingExtension);
615621

622+
auto SILOutputPath = pathsFromArguments.SILOutputPath;
623+
auto LLVMIROutputPath = pathsFromArguments.LLVMIROutputPath;
624+
616625
SupplementaryOutputPaths sop;
617626
sop.ClangHeaderOutputPath = clangHeaderOutputPath;
618627
sop.ModuleOutputPath = moduleOutputPath;
@@ -635,6 +644,8 @@ SupplementaryOutputPathsComputer::computeOutputPathsForOneInput(
635644
sop.ModuleSemanticInfoOutputPath = ModuleSemanticInfoOutputPath;
636645
sop.YAMLOptRecordPath = YAMLOptRecordPath;
637646
sop.BitstreamOptRecordPath = bitstreamOptRecordPath;
647+
sop.SILOutputPath = SILOutputPath;
648+
sop.LLVMIROutputPath = LLVMIROutputPath;
638649
return sop;
639650
}
640651

@@ -752,7 +763,9 @@ SupplementaryOutputPathsComputer::readSupplementaryOutputFileMap() const {
752763
options::OPT_emit_private_module_interface_path,
753764
options::OPT_emit_package_module_interface_path,
754765
options::OPT_emit_module_source_info_path,
755-
options::OPT_emit_tbd_path)) {
766+
options::OPT_emit_tbd_path,
767+
options::OPT_sil_output_path,
768+
options::OPT_ir_output_path)) {
756769
Diags.diagnose(SourceLoc(),
757770
diag::error_cannot_have_supplementary_outputs,
758771
A->getSpelling(), "-supplementary-output-file-map");

lib/FrontendTool/FrontendTool.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2100,6 +2100,13 @@ static bool performCompileStepsPostSILGen(CompilerInstance &Instance,
21002100
if (Action == FrontendOptions::ActionType::EmitSIL)
21012101
return writeSIL(*SM, PSPs, Instance, Invocation.getSILOptions());
21022102

2103+
// Write extra SIL output if requested
2104+
if (!PSPs.SupplementaryOutputs.SILOutputPath.empty()) {
2105+
if (writeSIL(*SM, Instance.getMainModule(), Invocation.getSILOptions(),
2106+
PSPs.SupplementaryOutputs.SILOutputPath, Instance.getOutputBackend()))
2107+
return true;
2108+
}
2109+
21032110
assert(Action >= FrontendOptions::ActionType::Immediate &&
21042111
"All actions not requiring IRGen must have been handled!");
21052112
assert(Action != FrontendOptions::ActionType::REPL &&
@@ -2144,6 +2151,17 @@ static bool performCompileStepsPostSILGen(CompilerInstance &Instance,
21442151
generateIR(IRGenOpts, Invocation.getTBDGenOptions(), std::move(SM), PSPs,
21452152
OutputFilename, MSF, HashGlobal, ParallelOutputFilenames);
21462153

2154+
// Write extra LLVM IR output if requested
2155+
if (IRModule && !PSPs.SupplementaryOutputs.LLVMIROutputPath.empty()) {
2156+
if (withOutputPath(Instance.getDiags(), Instance.getOutputBackend(),
2157+
PSPs.SupplementaryOutputs.LLVMIROutputPath,
2158+
[&](raw_ostream &out) -> bool {
2159+
IRModule.getModule()->print(out, nullptr);
2160+
return false;
2161+
}))
2162+
return true;
2163+
}
2164+
21472165
// Cancellation check after IRGen.
21482166
if (Instance.isCancellationRequested())
21492167
return true;

test/Driver/ir-output-path.swift

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-object -ir-output-path %t/test.ll %s -o %t/test.o
3+
// RUN: %FileCheck -input-file %t/test.ll %s --check-prefix=IR-CHECK
4+
// RUN: test -f %t/test.o
5+
6+
// Test that -ir-output-path produces LLVM IR output alongside normal compilation
7+
8+
func testFunction() -> Int {
9+
return 42
10+
}
11+
12+
let _ = testFunction()
13+
14+
// IR-CHECK: @"$s4test0A8FunctionSiyF"
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: echo '"%s": { "sil": "%t/test.sil", "llvm-ir": "%t/test.ll" }' > %t/output-file-map.json
3+
// RUN: %target-swift-frontend -emit-object -supplementary-output-file-map %t/output-file-map.json %s -o %t/test.o -module-name test
4+
// RUN: %FileCheck -input-file %t/test.sil %s --check-prefix=SIL-CHECK
5+
// RUN: %FileCheck -input-file %t/test.ll %s --check-prefix=IR-CHECK
6+
// RUN: test -f %t/test.o
7+
8+
// Test that SIL and IR files can be requested via output file map
9+
10+
func testFunction() -> Int {
11+
return 42
12+
}
13+
14+
let _ = testFunction()
15+
16+
// SIL-CHECK: sil hidden @$s4test0A8FunctionSiyF : $@convention(thin) () -> Int
17+
// IR-CHECK: @"$s4test0A8FunctionSiyF"

test/Driver/sil-output-path.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %target-swift-frontend -emit-object -sil-output-path %t/test.sil %s -o %t/test.o
3+
// RUN: %FileCheck -input-file %t/test.sil %s --check-prefix=SIL-CHECK
4+
// RUN: test -f %t/test.o
5+
6+
// Test that -sil-output-path produces SIL output alongside normal compilation
7+
8+
func testFunction() -> Int {
9+
return 42
10+
}
11+
12+
// SIL-CHECK: sil hidden @$s4test0A8FunctionSiyF : $@convention(thin) () -> Int

0 commit comments

Comments
 (0)