Skip to content

Commit 8bf76e3

Browse files
committed
Add SIL and IR generation support to -save-temps option
This extends -save-temps to emit SIL and IR alongside existing temporary files. In the case where an output file map is used with -save-temps, e.g. incremental compilation, only emit the SIL and IR if it has been requested as an output in the filemap. rdar://160297896
1 parent c792635 commit 8bf76e3

File tree

2 files changed

+92
-13
lines changed

2 files changed

+92
-13
lines changed

Sources/SwiftDriver/Jobs/FrontendJobHelpers.swift

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,10 @@ extension Driver {
690690
} else if let directory = directory {
691691
let outputPath = try generateSupplementaryOutputPath(for: inputFile, outputType: outputType, directory: directory)
692692
flaggedInputOutputPairs.append((flag: flag, input: inputFile, output: outputPath))
693+
} else if parsedOptions.hasArgument(.saveTemps) {
694+
// When using -save-temps without explicit directories, output to current directory
695+
let outputPath = try generateSupplementaryOutputPath(for: inputFile, outputType: outputType, directory: ".")
696+
flaggedInputOutputPairs.append((flag: flag, input: inputFile, output: outputPath))
693697
}
694698
}
695699
}
@@ -707,7 +711,7 @@ extension Driver {
707711
let directory = parsedOptions.getLastArgument(directoryOption)?.asSingle
708712
let hasFileMapEntries = outputFileMap?.hasEntries(for: outputType) ?? false
709713

710-
if directory != nil || hasFileMapEntries {
714+
if directory != nil || hasFileMapEntries || (parsedOptions.hasArgument(.saveTemps) && !hasFileMapEntries) {
711715
let inputsToProcess: [TypedVirtualPath]
712716
if compilerMode.usesPrimaryFileInputs {
713717
inputsToProcess = input.map { [$0] } ?? []
@@ -807,17 +811,40 @@ extension Driver {
807811
input: input,
808812
flag: "-serialize-diagnostics-path")
809813

810-
try addOutputOfType(
811-
outputType: .sil,
812-
finalOutputPath: silOutputPath,
813-
input: input,
814-
flag: "-sil-output-path")
814+
// Add SIL and IR outputs when explicitly requested via directory options, file maps, or -save-temps
815+
let saveTempsWithoutFileMap = parsedOptions.hasArgument(.saveTemps) && outputFileMap == nil
816+
let hasSilFileMapEntries = outputFileMap?.hasEntries(for: .sil) ?? false
817+
let hasIrFileMapEntries = outputFileMap?.hasEntries(for: .llvmIR) ?? false
815818

816-
try addOutputOfType(
817-
outputType: .llvmIR,
818-
finalOutputPath: llvmIROutputPath,
819-
input: input,
820-
flag: "-ir-output-path")
819+
let silOutputPathSupported = Driver.isOptionFound("-sil-output-path", allOpts: supportedFrontendFlags)
820+
let irOutputPathSupported = Driver.isOptionFound("-ir-output-path", allOpts: supportedFrontendFlags)
821+
822+
if !silOutputPathSupported && (parsedOptions.hasArgument(.silOutputDir) || hasSilFileMapEntries) {
823+
diagnosticEngine.emit(.warning("frontend does not support -sil-output-path; SIL output will not be emitted"))
824+
}
825+
826+
if !irOutputPathSupported && (parsedOptions.hasArgument(.irOutputDir) || hasIrFileMapEntries) {
827+
diagnosticEngine.emit(.warning("frontend does not support -ir-output-path; IR output will not be emitted"))
828+
}
829+
830+
let shouldAddSilOutput = silOutputPathSupported && (parsedOptions.hasArgument(.silOutputDir) || saveTempsWithoutFileMap || hasSilFileMapEntries)
831+
let shouldAddIrOutput = irOutputPathSupported && (parsedOptions.hasArgument(.irOutputDir) || saveTempsWithoutFileMap || hasIrFileMapEntries)
832+
833+
if shouldAddSilOutput {
834+
try addOutputOfType(
835+
outputType: .sil,
836+
finalOutputPath: silOutputPath,
837+
input: input,
838+
flag: "-sil-output-path")
839+
}
840+
841+
if shouldAddIrOutput {
842+
try addOutputOfType(
843+
outputType: .llvmIR,
844+
finalOutputPath: llvmIROutputPath,
845+
input: input,
846+
flag: "-ir-output-path")
847+
}
821848
}
822849

823850
if compilerMode.usesPrimaryFileInputs {

Tests/SwiftDriverTests/JobExecutorTests.swift

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,8 +536,12 @@ final class JobExecutorTests: XCTestCase {
536536
executor: executor)
537537
let jobs = try driver.planBuild()
538538
XCTAssertEqual(jobs.removingAutolinkExtractJobs().map(\.kind), [.compile, .link])
539-
XCTAssertEqual(jobs[0].outputs.count, 1)
540-
let compileOutput = jobs[0].outputs[0].file
539+
// With -save-temps, we now have additional SIL and IR outputs, so expect more outputs
540+
XCTAssertTrue(jobs[0].outputs.count >= 1, "Should have at least the object file output")
541+
// Find the main object file output
542+
let objectOutput = jobs[0].outputs.first { $0.type == .object }
543+
XCTAssertNotNil(objectOutput, "Should have object file output")
544+
let compileOutput = objectOutput!.file
541545
guard matchTemporary(compileOutput, "main.o") else {
542546
XCTFail("unexpected output")
543547
return
@@ -585,5 +589,53 @@ final class JobExecutorTests: XCTestCase {
585589
)
586590
}
587591
}
592+
593+
// Test that -save-temps also saves SIL and IR intermediate files
594+
do {
595+
// Skip test if frontend doesn't support these options
596+
let diags = DiagnosticsEngine()
597+
let executor = try SwiftDriverExecutor(diagnosticsEngine: diags,
598+
processSet: ProcessSet(),
599+
fileSystem: localFileSystem,
600+
env: ProcessEnv.block)
601+
let checkDriver = try Driver(args: ["swiftc", "foo.swift"] + getHostToolchainSdkArg(executor),
602+
envBlock: ProcessEnv.block,
603+
diagnosticsOutput: .engine(diags),
604+
fileSystem: localFileSystem,
605+
executor: executor)
606+
guard Driver.isOptionFound("-sil-output-path", allOpts: checkDriver.supportedFrontendFlags) &&
607+
Driver.isOptionFound("-ir-output-path", allOpts: checkDriver.supportedFrontendFlags) else {
608+
throw XCTSkip("Skipping: frontend does not support -sil-output-path or -ir-output-path")
609+
}
610+
611+
try withTemporaryDirectory { path in
612+
let main = path.appending(component: "main.swift")
613+
try localFileSystem.writeFileContents(main, bytes: "print(\"hello, world!\")")
614+
let diags = DiagnosticsEngine()
615+
let executor = try SwiftDriverExecutor(diagnosticsEngine: diags,
616+
processSet: ProcessSet(),
617+
fileSystem: localFileSystem,
618+
env: ProcessEnv.block)
619+
let outputPath = path.appending(component: "finalOutput")
620+
var driver = try Driver(args: ["swiftc", main.pathString,
621+
"-save-temps",
622+
"-o", outputPath.pathString] + getHostToolchainSdkArg(executor),
623+
envBlock: ProcessEnv.block,
624+
diagnosticsOutput: .engine(diags),
625+
fileSystem: localFileSystem,
626+
executor: executor)
627+
let jobs = try driver.planBuild()
628+
let compileJobs = jobs.removingAutolinkExtractJobs()
629+
XCTAssertEqual(compileJobs.map(\.kind), [.compile, .link])
630+
631+
let compileJob = compileJobs[0]
632+
633+
XCTAssertTrue(compileJob.commandLine.contains(.flag("-sil-output-path")))
634+
XCTAssertTrue(compileJob.commandLine.contains(.flag("-ir-output-path")))
635+
636+
let hasMultipleOutputs = compileJob.outputs.count > 1
637+
XCTAssertTrue(hasMultipleOutputs, "Should have additional SIL/IR outputs when using -save-temps")
638+
}
639+
}
588640
}
589641
}

0 commit comments

Comments
 (0)