Skip to content

Commit 26d111e

Browse files
authored
Merge pull request #101 from cltnschlosser/cs_embedBitcode
Support -embed-bitcode and -driver-print-bindings
2 parents 28563cb + 717e9c7 commit 26d111e

File tree

10 files changed

+544
-45
lines changed

10 files changed

+544
-45
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ The goal of the new Swift driver is to provide a drop-in replacement for the exi
151151
* [x] Immediate mode
152152
* Features
153153
* [x] Precompiled bridging headers
154-
* [ ] Support embedding of bitcode
154+
* [x] Support embedding of bitcode
155155
* [ ] Incremental compilation
156156
* [x] Parseable output, as used by SwiftPM
157157
* [x] Response files

Sources/SwiftDriver/Driver/Driver.swift

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ public struct Driver {
150150
/// The name of the Swift module being built.
151151
public let moduleName: String
152152

153+
/// Was the module name picked by the driver instead of the user.
154+
public let moduleNameIsFallback: Bool
155+
153156
/// The path of the SDK.
154157
public let sdkPath: String?
155158

@@ -322,7 +325,7 @@ public struct Driver {
322325
Self.computeDebugInfo(&parsedOptions, diagnosticsEngine: diagnosticEngine)
323326

324327
// Determine the module we're building and whether/how the module file itself will be emitted.
325-
(self.moduleOutput, self.moduleName) = try Self.computeModuleInfo(
328+
(self.moduleOutput, self.moduleName, self.moduleNameIsFallback) = try Self.computeModuleInfo(
326329
&parsedOptions, compilerOutputType: compilerOutputType, compilerMode: compilerMode, linkerOutputType: linkerOutputType,
327330
debugInfoLevel: debugInfoLevel, diagnosticsEngine: diagnosticEngine)
328331

@@ -651,6 +654,13 @@ extension Driver {
651654
return
652655
}
653656

657+
if parsedOptions.contains(.driverPrintBindings) {
658+
for job in jobs {
659+
try printBindings(job)
660+
}
661+
return
662+
}
663+
654664
if parsedOptions.contains(.driverPrintGraphviz) {
655665
var serializer = DOTJobGraphSerializer(jobs: jobs)
656666
serializer.writeDOT(to: &stdoutStream)
@@ -725,6 +735,21 @@ extension Driver {
725735
print(result)
726736
}
727737

738+
private func printBindings(_ job: Job) throws {
739+
try stdoutStream <<< #"# ""# <<< toolchain.hostTargetTriple().triple
740+
stdoutStream <<< #"" - ""# <<< job.tool.basename
741+
stdoutStream <<< #"", inputs: ["#
742+
stdoutStream <<< job.inputs.map { "\"" + $0.file.name + "\"" }.joined(separator: ", ")
743+
744+
stdoutStream <<< "], output: {"
745+
746+
stdoutStream <<< job.outputs.map { $0.type.name + ": \"" + $0.file.name + "\"" }.joined(separator: ", ")
747+
748+
stdoutStream <<< "}"
749+
stdoutStream <<< "\n"
750+
stdoutStream.flush()
751+
}
752+
728753
private func printVersion<S: OutputByteStream>(outputStream: inout S) throws {
729754
outputStream.write(try Process.checkNonZeroExit(args: toolchain.getToolPath(.swiftCompiler).pathString, "--version"))
730755
outputStream.flush()
@@ -983,6 +1008,16 @@ extension Driver {
9831008
linkerOutputType = .executable
9841009
}
9851010

1011+
// warn if -embed-bitcode is set and the output type is not an object
1012+
if parsedOptions.hasArgument(.embedBitcode) && compilerOutputType != .object {
1013+
diagnosticsEngine.emit(.warn_ignore_embed_bitcode)
1014+
parsedOptions.eraseArgument(.embedBitcode)
1015+
}
1016+
if parsedOptions.hasArgument(.embedBitcodeMarker) && compilerOutputType != .object {
1017+
diagnosticsEngine.emit(.warn_ignore_embed_bitcode_marker)
1018+
parsedOptions.eraseArgument(.embedBitcodeMarker)
1019+
}
1020+
9861021
return (compilerOutputType, linkerOutputType)
9871022
}
9881023
}
@@ -996,6 +1031,14 @@ extension Diagnostic.Message {
9961031
"""
9971032
)
9981033
}
1034+
1035+
static var warn_ignore_embed_bitcode: Diagnostic.Message {
1036+
.warning("ignoring -embed-bitcode since no object file is being generated")
1037+
}
1038+
1039+
static var warn_ignore_embed_bitcode_marker: Diagnostic.Message {
1040+
.warning("ignoring -embed-bitcode-marker since no object file is being generated")
1041+
}
9991042
}
10001043

10011044
// Multithreading
@@ -1251,7 +1294,7 @@ extension Driver {
12511294
linkerOutputType: LinkOutputType?,
12521295
debugInfoLevel: DebugInfoLevel?,
12531296
diagnosticsEngine: DiagnosticsEngine
1254-
) throws -> (ModuleOutput?, String) {
1297+
) throws -> (ModuleOutput?, String, Bool) {
12551298
// Figure out what kind of module we will output.
12561299
enum ModuleOutputKind {
12571300
case topLevel
@@ -1287,6 +1330,7 @@ extension Driver {
12871330

12881331
// Determine the name of the module.
12891332
var moduleName: String
1333+
var moduleNameIsFallback = false
12901334
if let arg = parsedOptions.getLastArgument(.moduleName) {
12911335
moduleName = arg.asSingle
12921336
} else if compilerMode == .repl {
@@ -1310,7 +1354,7 @@ extension Driver {
13101354
}
13111355

13121356
func fallbackOrDiagnose(_ error: Diagnostic.Message) {
1313-
// FIXME: Current driver notes that this is a "fallback module name".
1357+
moduleNameIsFallback = true
13141358
if compilerOutputType == nil || maybeBuildingExecutable(&parsedOptions, linkerOutputType: linkerOutputType) {
13151359
moduleName = "main"
13161360
}
@@ -1328,7 +1372,7 @@ extension Driver {
13281372

13291373
// If we're not emiting a module, we're done.
13301374
if moduleOutputKind == nil {
1331-
return (nil, moduleName)
1375+
return (nil, moduleName, moduleNameIsFallback)
13321376
}
13331377

13341378
// Determine the module file to output.
@@ -1354,9 +1398,9 @@ extension Driver {
13541398

13551399
switch moduleOutputKind! {
13561400
case .topLevel:
1357-
return (.topLevel(moduleOutputPath), moduleName)
1401+
return (.topLevel(moduleOutputPath), moduleName, moduleNameIsFallback)
13581402
case .auxiliary:
1359-
return (.auxiliary(moduleOutputPath), moduleName)
1403+
return (.auxiliary(moduleOutputPath), moduleName, moduleNameIsFallback)
13601404
}
13611405
}
13621406
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
//===--------------- BackendJob.swift - Swift Backend Job -------------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2019 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
import Foundation
14+
15+
extension Driver {
16+
/// Form a backend job.
17+
mutating func backendJob(input: TypedVirtualPath,
18+
allOutputs: inout [TypedVirtualPath]) throws -> Job {
19+
var commandLine: [Job.ArgTemplate] = swiftCompilerPrefixArgs.map { Job.ArgTemplate.flag($0) }
20+
var inputs = [TypedVirtualPath]()
21+
var outputs = [TypedVirtualPath]()
22+
23+
commandLine.appendFlag("-frontend")
24+
addCompileModeOption(outputType: compilerOutputType, commandLine: &commandLine)
25+
26+
// Add input arguments.
27+
commandLine.appendFlag(.primaryFile)
28+
commandLine.appendPath(input.file)
29+
inputs.append(input)
30+
31+
commandLine.appendFlag(.embedBitcode)
32+
33+
// -embed-bitcode only supports a restricted set of flags.
34+
commandLine.appendFlag(.target)
35+
commandLine.appendFlag(targetTriple.triple)
36+
37+
// Enable address top-byte ignored in the ARM64 backend.
38+
if targetTriple.arch == .aarch64 {
39+
commandLine.appendFlag(.Xllvm)
40+
commandLine.appendFlag("-aarch64-use-tbi")
41+
}
42+
43+
// Handle the CPU and its preferences.
44+
try commandLine.appendLast(.targetCpu, from: &parsedOptions)
45+
46+
// Enable optimizations, but disable all LLVM-IR-level transformations.
47+
try commandLine.appendLast(in: .O, from: &parsedOptions)
48+
commandLine.appendFlag(.disableLlvmOptzns)
49+
50+
try commandLine.appendLast(.parseStdlib, from: &parsedOptions)
51+
52+
commandLine.appendFlag(.moduleName)
53+
commandLine.appendFlag(moduleName)
54+
55+
// Add the output file argument if necessary.
56+
if let compilerOutputType = compilerOutputType {
57+
let output = computePrimaryOutput(for: input,
58+
outputType: compilerOutputType,
59+
isTopLevel: isTopLevelOutput(type: compilerOutputType))
60+
commandLine.appendFlag(.o)
61+
commandLine.appendPath(output.file)
62+
outputs.append(output)
63+
}
64+
65+
allOutputs += outputs
66+
67+
return Job(
68+
kind: .backend,
69+
tool: .absolute(try toolchain.getToolPath(.swiftCompiler)),
70+
commandLine: commandLine,
71+
displayInputs: inputs,
72+
inputs: inputs,
73+
outputs: outputs,
74+
supportsResponseFiles: true
75+
)
76+
}
77+
}

Sources/SwiftDriver/Jobs/CompileJob.swift

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import SwiftOptions
1414

1515
extension Driver {
1616
/// Add the appropriate compile mode option to the command line for a compile job.
17-
private mutating func addCompileModeOption(outputType: FileType?, commandLine: inout [Job.ArgTemplate]) {
17+
mutating func addCompileModeOption(outputType: FileType?, commandLine: inout [Job.ArgTemplate]) {
1818
if let compileOption = outputType?.frontendCompileOption {
1919
commandLine.appendFlag(compileOption)
2020
} else {
@@ -26,7 +26,7 @@ extension Driver {
2626
}
2727
}
2828

29-
fileprivate mutating func computePrimaryOutput(for input: TypedVirtualPath, outputType: FileType,
29+
mutating func computePrimaryOutput(for input: TypedVirtualPath, outputType: FileType,
3030
isTopLevel: Bool) -> TypedVirtualPath {
3131
if let path = outputFileMap?.existingOutput(inputFile: input.file, outputType: outputType) {
3232
return TypedVirtualPath(file: path, type: outputType)
@@ -56,28 +56,31 @@ extension Driver {
5656
return TypedVirtualPath(file: .relative(.init(baseName.appendingFileTypeExtension(outputType))), type: outputType)
5757
}
5858

59-
/// Add the compiler inputs for a frontend compilation job, and return the
60-
/// corresponding primary set of outputs.
61-
mutating func addCompileInputs(primaryInputs: [TypedVirtualPath],
62-
inputs: inout [TypedVirtualPath],
63-
commandLine: inout [Job.ArgTemplate]) -> [TypedVirtualPath] {
64-
// Is this compile job top-level
65-
let isTopLevel: Bool
66-
67-
switch compilerOutputType {
59+
/// Is this compile job top-level
60+
func isTopLevelOutput(type: FileType?) -> Bool {
61+
switch type {
6862
case .assembly, .sil, .raw_sil, .llvmIR, .ast, .jsonDependencies:
69-
isTopLevel = true
63+
return true
7064
case .object:
71-
isTopLevel = (linkerOutputType == nil)
65+
return (linkerOutputType == nil)
7266
case .swiftModule:
73-
isTopLevel = compilerMode.isSingleCompilation && moduleOutput?.isTopLevel ?? false
67+
return compilerMode.isSingleCompilation && moduleOutput?.isTopLevel ?? false
7468
case .swift, .sib, .image, .dSYM, .dependencies, .autolink,
7569
.swiftDocumentation, .swiftInterface,
7670
.swiftSourceInfoFile, .raw_sib, .llvmBitcode, .diagnostics,
7771
.objcHeader, .swiftDeps, .remap, .importedModules, .tbd, .moduleTrace,
7872
.indexData, .optimizationRecord, .pcm, .pch, nil:
79-
isTopLevel = false
73+
return false
8074
}
75+
}
76+
77+
/// Add the compiler inputs for a frontend compilation job, and return the
78+
/// corresponding primary set of outputs.
79+
mutating func addCompileInputs(primaryInputs: [TypedVirtualPath],
80+
inputs: inout [TypedVirtualPath],
81+
outputType: FileType?,
82+
commandLine: inout [Job.ArgTemplate]) -> [TypedVirtualPath] {
83+
let isTopLevel = isTopLevelOutput(type: outputType)
8184

8285
// Collect the set of input files that are part of the Swift compilation.
8386
let swiftInputFiles: [TypedVirtualPath] = inputFiles.filter { $0.type.isPartOfSwiftCompilation }
@@ -104,16 +107,16 @@ extension Driver {
104107

105108
// If there is a primary output or we are doing multithreaded compiles,
106109
// add an output for the input.
107-
if let compilerOutputType = compilerOutputType,
108-
isPrimary || (!usesPrimaryFileInputs && isMultithreaded && compilerOutputType.isAfterLLVM) {
110+
if let outputType = outputType,
111+
isPrimary || (!usesPrimaryFileInputs && isMultithreaded && outputType.isAfterLLVM) {
109112
primaryOutputs.append(computePrimaryOutput(for: input,
110-
outputType: compilerOutputType,
113+
outputType: outputType,
111114
isTopLevel: isTopLevel))
112115
}
113116
}
114117

115118
// When not using primary file inputs or multithreading, add a single output.
116-
if let outputType = compilerOutputType,
119+
if let outputType = outputType,
117120
!usesPrimaryFileInputs && !(isMultithreaded && outputType.isAfterLLVM) {
118121
primaryOutputs.append(computePrimaryOutput(
119122
for: TypedVirtualPath(file: try! VirtualPath(path: ""),
@@ -133,7 +136,10 @@ extension Driver {
133136

134137
commandLine.appendFlag("-frontend")
135138
addCompileModeOption(outputType: outputType, commandLine: &commandLine)
136-
let primaryOutputs = addCompileInputs(primaryInputs: primaryInputs, inputs: &inputs, commandLine: &commandLine)
139+
let primaryOutputs = addCompileInputs(primaryInputs: primaryInputs,
140+
inputs: &inputs,
141+
outputType: outputType,
142+
commandLine: &commandLine)
137143
outputs += primaryOutputs
138144
outputs += try addFrontendSupplementaryOutputArguments(commandLine: &commandLine, primaryInputs: primaryInputs)
139145

Sources/SwiftDriver/Jobs/Job.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import Foundation
1616
public struct Job: Codable, Equatable, Hashable {
1717
public enum Kind: String, Codable {
1818
case compile
19+
case backend
1920
case mergeModule = "merge-module"
2021
case link
2122
case generateDSYM = "generate-dsym"

Sources/SwiftDriver/Jobs/LinkJob.swift

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,9 @@ import TSCBasic
1414
extension Driver {
1515

1616
/// Compute the output file for an image output.
17-
private func outputFileForImage(inputs: [TypedVirtualPath]) -> VirtualPath {
18-
// FIXME: The check for __bad__ here, is
19-
if inputs.count == 1 && moduleName == "__bad__" && inputs.first!.file != .standardInput {
20-
// FIXME: llvm::sys::path::stem(BaseInput);
17+
private var outputFileForImage: VirtualPath {
18+
if inputFiles.count == 1 && moduleNameIsFallback && inputFiles[0].file != .standardInput {
19+
return .relative(RelativePath(inputFiles[0].file.basenameWithoutExt))
2120
}
2221

2322
let outputName =
@@ -35,7 +34,7 @@ extension Driver {
3534
if let output = parsedOptions.getLastArgument(.o) {
3635
outputFile = try VirtualPath(path: output.asSingle)
3736
} else {
38-
outputFile = outputFileForImage(inputs: inputs)
37+
outputFile = outputFileForImage
3938
}
4039

4140
// Defer to the toolchain for platform-specific linking
@@ -58,7 +57,7 @@ extension Driver {
5857
tool: .absolute(toolPath),
5958
commandLine: commandLine,
6059
inputs: inputs,
61-
outputs: [.init(file: outputFile, type: .object)]
60+
outputs: [.init(file: outputFile, type: .image)]
6261
)
6362
}
6463
}

0 commit comments

Comments
 (0)