Skip to content

Commit edf00a9

Browse files
committed
Reorganize module
1 parent 224d66f commit edf00a9

File tree

1 file changed

+183
-151
lines changed

1 file changed

+183
-151
lines changed

Sources/LLVM/Module.swift

Lines changed: 183 additions & 151 deletions
Original file line numberDiff line numberDiff line change
@@ -2,98 +2,98 @@
22
import cllvm
33
#endif
44

5-
/// A `Context` represents execution states for the core LLVM IR system.
6-
public class Context {
7-
internal let llvm: LLVMContextRef
8-
internal let ownsContext: Bool
9-
10-
/// Retrieves the global context instance.
11-
public static let global = Context(llvm: LLVMGetGlobalContext()!)
12-
13-
/// Creates a `Context` object using `LLVMContextCreate`
14-
public init() {
15-
llvm = LLVMContextCreate()
16-
ownsContext = true
17-
}
18-
19-
/// Creates a `Context` object from an `LLVMContextRef` object.
20-
public init(llvm: LLVMContextRef, ownsContext: Bool = false) {
21-
self.llvm = llvm
22-
self.ownsContext = ownsContext
23-
}
24-
25-
/// Returns whether the given context is set to discard all value names.
26-
///
27-
/// If true, only the names of GlobalValue objects will be available in
28-
/// the IR. This can be used to save memory and runtime, especially in
29-
/// release mode.
30-
public var discardValueNames: Bool {
31-
get { return LLVMContextShouldDiscardValueNames(self.llvm) != 0 }
32-
set { LLVMContextSetDiscardValueNames(self.llvm, newValue.llvm) }
33-
}
34-
35-
/// Deinitialize this value and dispose of its resources.
36-
deinit {
37-
guard self.ownsContext else {
38-
return
39-
}
40-
LLVMContextDispose(self.llvm)
41-
}
42-
}
43-
44-
/// Represents the possible errors that can be thrown while interacting with a
45-
/// `Module` object.
46-
public enum ModuleError: Error, CustomStringConvertible {
47-
/// Thrown when a module does not pass the module verification process.
48-
/// Includes the reason the module did not pass verification.
49-
case didNotPassVerification(String)
50-
/// Thrown when a module cannot be printed at a given path. Provides the
51-
/// erroneous path and a deeper reason why printing to that path failed.
52-
case couldNotPrint(path: String, error: String)
53-
/// Thrown when a module cannot emit bitcode because it contains erroneous
54-
/// declarations.
55-
case couldNotEmitBitCode(path: String)
56-
57-
public var description: String {
58-
switch self {
59-
case .didNotPassVerification(let message):
60-
return "module did not pass verification: \(message)"
61-
case .couldNotPrint(let path, let error):
62-
return "could not print to file \(path): \(error)"
63-
case .couldNotEmitBitCode(let path):
64-
return "could not emit bitcode to file \(path) for an unknown reason"
65-
}
66-
}
67-
}
68-
695
/// A `Module` represents the top-level structure of an LLVM program. An LLVM
706
/// module is effectively a translation unit or a collection of translation
717
/// units merged together.
8+
///
9+
/// LLVM programs are composed of `Module`s consisting of functions, global
10+
/// variables, symbol table entries, and metadata. Modules may be combined
11+
/// together with the LLVM linker, which merges function (and global variable)
12+
/// definitions, resolves forward declarations, and merges symbol table entries.
13+
///
14+
/// Verifying a Module
15+
/// ==================
16+
///
17+
/// A module naturally grows to encompass a large amount of data during code
18+
/// generation. To verify that the module is well-formed and suitable for
19+
/// submission to later phases of LLVM, call `Module.verify()`. If the module
20+
/// does not pass verification, an error describing the cause will be thrown.
21+
///
22+
/// let module = Module(name: "Example")
23+
/// let builder = IRBuilder(module: module)
24+
/// let main = builder.addFunction("main",
25+
/// type: FunctionType(argTypes: [],
26+
/// returnType: VoidType()))
27+
/// let entry = main.appendBasicBlock(named: "entry")
28+
/// builder.positionAtEnd(of: entry)
29+
/// builder.buildRet(main.address(of: entry)!)
30+
///
31+
/// try module.verify()
32+
/// // The following error is thrown:
33+
/// // module did not pass verification: blockaddress may not be used with the entry block!
34+
/// // Found return instr that returns non-void in Function of void return type!
35+
///
36+
/// The built-in verifier attempts to be correct at the cost of completeness.
37+
/// For strictest checking, invoke the `lli` tool on any IR that is generated.
38+
///
39+
/// Threading Considerations
40+
/// ========================
41+
///
42+
/// A module value is associated with exactly one LLVM context. That context,
43+
/// and its creating thread, must be used to access and mutate this module as
44+
/// LLVM provides no locking or atomicity guarantees.
45+
///
46+
/// Printing The Contents of a Module
47+
/// =================================
48+
///
49+
/// The contents of a module are mostly machine-independent. It is often useful
50+
/// while debugging to view this machine-independent IR. A module responds to
51+
/// `Module.dump()` by printing this representation to standard output. To
52+
/// dump the module to a file, use `Module.print(to:)`. In general, a module
53+
/// must be associated with a `TargetMachine` and a target environment for its
54+
/// contents to be fully useful for export to later file formats such as object
55+
/// files or bitcode. See `TargetMachine.emitToFile(module:type:path)` for more
56+
/// details.
57+
///
58+
/// Module Flags
59+
/// ============
60+
///
61+
/// To convey information about a module to LLVM's various subsystems, a module
62+
/// may have flags attached. These flags are keyed by global strings, and
63+
/// attached as metadata to the module with the privileged `llvm.module.flags`
64+
/// metadata identifier. Certain flags have hard-coded meanings in LLVM such as
65+
/// the Objective-C garbage collection flags or the linker options flags. Most
66+
/// other flags are stripped from any resulting object files.
7267
public final class Module: CustomStringConvertible {
7368
internal let llvm: LLVMModuleRef
7469
internal var ownsContext: Bool = true
7570

71+
/// Returns the context associated with this module.
72+
public let context: Context
73+
74+
7675
/// Creates a `Module` with the given name.
7776
///
7877
/// - parameter name: The name of the module.
7978
/// - parameter context: The context to associate this module with. If no
80-
/// context is provided, one will be inferred.
81-
public init(name: String, context: Context? = nil) {
79+
/// context is provided, the global context is assumed.
80+
public init(name: String, context: Context = .global) {
8281

8382
// Ensure the LLVM initializer is called when the first module is created
8483
initializeLLVM()
8584

86-
if let context = context {
87-
llvm = LLVMModuleCreateWithNameInContext(name, context.llvm)
88-
self.context = context
89-
} else {
90-
llvm = LLVMModuleCreateWithName(name)
91-
self.context = Context(llvm: LLVMGetModuleContext(llvm)!)
92-
}
85+
self.llvm = LLVMModuleCreateWithNameInContext(name, context.llvm)
86+
self.context = context
9387
}
9488

95-
/// Returns the context associated with this module.
96-
public let context: Context
89+
90+
/// Deinitialize this value and dispose of its resources.
91+
deinit {
92+
guard self.ownsContext else {
93+
return
94+
}
95+
LLVMDisposeModule(llvm)
96+
}
9797

9898
/// Obtain the target triple for this module.
9999
public var targetTriple: Triple {
@@ -143,71 +143,6 @@ public final class Module: CustomStringConvertible {
143143
}
144144
}
145145

146-
/// Print a representation of a module to a file at the given path.
147-
///
148-
/// If the provided path is not suitable for writing, this function will throw
149-
/// `ModuleError.couldNotPrint`.
150-
///
151-
/// - parameter path: The path to write the module's representation to.
152-
public func print(to path: String) throws {
153-
var err: UnsafeMutablePointer<Int8>?
154-
path.withCString { cString in
155-
let mutable = strdup(cString)
156-
LLVMPrintModuleToFile(llvm, mutable, &err)
157-
free(mutable)
158-
}
159-
if let err = err {
160-
defer { LLVMDisposeMessage(err) }
161-
throw ModuleError.couldNotPrint(path: path, error: String(cString: err))
162-
}
163-
}
164-
165-
/// Writes the bitcode of elements in this module to a file at the given path.
166-
///
167-
/// If the provided path is not suitable for writing, this function will throw
168-
/// `ModuleError.couldNotEmitBitCode`.
169-
///
170-
/// - parameter path: The path to write the module's representation to.
171-
public func emitBitCode(to path: String) throws {
172-
let status = path.withCString { cString -> Int32 in
173-
let mutable = strdup(cString)
174-
defer { free(mutable) }
175-
return LLVMWriteBitcodeToFile(llvm, mutable)
176-
}
177-
178-
if status != 0 {
179-
throw ModuleError.couldNotEmitBitCode(path: path)
180-
}
181-
}
182-
183-
/// Verifies that this module is valid, taking the specified action if not.
184-
/// If this module did not pass verification, a description of any invalid
185-
/// constructs is provided with the thrown
186-
/// `ModuleError.didNotPassVerification` error.
187-
public func verify() throws {
188-
var message: UnsafeMutablePointer<Int8>?
189-
let status = Int(LLVMVerifyModule(llvm, LLVMReturnStatusAction, &message))
190-
if let message = message, status == 1 {
191-
defer { LLVMDisposeMessage(message) }
192-
throw ModuleError.didNotPassVerification(String(cString: message))
193-
}
194-
}
195-
196-
/// Links the given module with this module. If the link succeeds, this
197-
/// module will the composite of the two input modules.
198-
///
199-
/// The result of this function is `true` if the link succeeds, or `false`
200-
/// otherwise - unlike `llvm::Linker::linkModules`.
201-
///
202-
/// - parameter other: The module to link with this module.
203-
public func link(_ other: Module) -> Bool {
204-
// First clone the other module; `LLVMLinkModules2` consumes the source
205-
// module via a move and that module still owns its ModuleRef.
206-
let otherClone = LLVMCloneModule(other.llvm)
207-
// N.B. Returns `true` on error.
208-
return LLVMLinkModules2(self.llvm, otherClone) == 0
209-
}
210-
211146
/// Retrieves the sequence of functions that make up this module.
212147
public var functions: AnySequence<Function> {
213148
var current = firstFunction
@@ -309,14 +244,28 @@ public final class Module: CustomStringConvertible {
309244
public var debugMetadataVersion: UInt32 {
310245
return LLVMGetModuleDebugMetadataVersion(self.llvm)
311246
}
247+
}
312248

313-
/// Strip debug info in the module if it exists.
249+
// MARK: Module Printing
250+
251+
extension Module {
252+
/// Print a representation of a module to a file at the given path.
314253
///
315-
/// To do this, we remove all calls to the debugger intrinsics and any named
316-
/// metadata for debugging. We also remove debug locations for instructions.
317-
/// Return true if module is modified.
318-
public func stripDebugInfo() -> Bool {
319-
return LLVMStripModuleDebugInfo(self.llvm) != 0
254+
/// If the provided path is not suitable for writing, this function will throw
255+
/// `ModuleError.couldNotPrint`.
256+
///
257+
/// - parameter path: The path to write the module's representation to.
258+
public func print(to path: String) throws {
259+
var err: UnsafeMutablePointer<Int8>?
260+
path.withCString { cString in
261+
let mutable = strdup(cString)
262+
LLVMPrintModuleToFile(llvm, mutable, &err)
263+
free(mutable)
264+
}
265+
if let err = err {
266+
defer { LLVMDisposeMessage(err) }
267+
throw ModuleError.couldNotPrint(path: path, error: String(cString: err))
268+
}
320269
}
321270

322271
/// Dump a representation of this module to stderr.
@@ -330,13 +279,69 @@ public final class Module: CustomStringConvertible {
330279
defer { LLVMDisposeMessage(cStr) }
331280
return String(cString: cStr)
332281
}
282+
}
333283

334-
/// Deinitialize this value and dispose of its resources.
335-
deinit {
336-
guard self.ownsContext else {
337-
return
284+
// MARK: Module Emission
285+
286+
extension Module {
287+
/// Writes the bitcode of elements in this module to a file at the given path.
288+
///
289+
/// If the provided path is not suitable for writing, this function will throw
290+
/// `ModuleError.couldNotEmitBitCode`.
291+
///
292+
/// - parameter path: The path to write the module's representation to.
293+
public func emitBitCode(to path: String) throws {
294+
let status = path.withCString { cString -> Int32 in
295+
let mutable = strdup(cString)
296+
defer { free(mutable) }
297+
return LLVMWriteBitcodeToFile(llvm, mutable)
338298
}
339-
LLVMDisposeModule(llvm)
299+
300+
if status != 0 {
301+
throw ModuleError.couldNotEmitBitCode(path: path)
302+
}
303+
}
304+
}
305+
306+
// MARK: Module Actions
307+
308+
extension Module {
309+
/// Verifies that this module is valid, taking the specified action if not.
310+
/// If this module did not pass verification, a description of any invalid
311+
/// constructs is provided with the thrown
312+
/// `ModuleError.didNotPassVerification` error.
313+
public func verify() throws {
314+
var message: UnsafeMutablePointer<Int8>?
315+
let status = Int(LLVMVerifyModule(llvm, LLVMReturnStatusAction, &message))
316+
if let message = message, status == 1 {
317+
defer { LLVMDisposeMessage(message) }
318+
throw ModuleError.didNotPassVerification(String(cString: message))
319+
}
320+
}
321+
322+
/// Links the given module with this module. If the link succeeds, this
323+
/// module will the composite of the two input modules.
324+
///
325+
/// The result of this function is `true` if the link succeeds, or `false`
326+
/// otherwise.
327+
///
328+
/// - parameter other: The module to link with this module.
329+
public func link(_ other: Module) -> Bool {
330+
// First clone the other module; `LLVMLinkModules2` consumes the source
331+
// module via a move and that module still owns its ModuleRef.
332+
let otherClone = LLVMCloneModule(other.llvm)
333+
// N.B. Returns `true` on error.
334+
return LLVMLinkModules2(self.llvm, otherClone) == 0
335+
}
336+
337+
338+
/// Strip debug info in the module if it exists.
339+
///
340+
/// To do this, we remove all calls to the debugger intrinsics and any named
341+
/// metadata for debugging. We also remove debug locations for instructions.
342+
/// Return true if module is modified.
343+
public func stripDebugInfo() -> Bool {
344+
return LLVMStripModuleDebugInfo(self.llvm) != 0
340345
}
341346
}
342347

@@ -720,6 +725,33 @@ extension Module {
720725
}
721726
}
722727

728+
// MARK: Module Errors
729+
730+
/// Represents the possible errors that can be thrown while interacting with a
731+
/// `Module` object.
732+
public enum ModuleError: Error, CustomStringConvertible {
733+
/// Thrown when a module does not pass the module verification process.
734+
/// Includes the reason the module did not pass verification.
735+
case didNotPassVerification(String)
736+
/// Thrown when a module cannot be printed at a given path. Provides the
737+
/// erroneous path and a deeper reason why printing to that path failed.
738+
case couldNotPrint(path: String, error: String)
739+
/// Thrown when a module cannot emit bitcode because it contains erroneous
740+
/// declarations.
741+
case couldNotEmitBitCode(path: String)
742+
743+
public var description: String {
744+
switch self {
745+
case .didNotPassVerification(let message):
746+
return "module did not pass verification: \(message)"
747+
case .couldNotPrint(let path, let error):
748+
return "could not print to file \(path): \(error)"
749+
case .couldNotEmitBitCode(let path):
750+
return "could not emit bitcode to file \(path) for an unknown reason"
751+
}
752+
}
753+
}
754+
723755
extension Bool {
724756
internal var llvm: LLVMBool {
725757
return self ? 1 : 0

0 commit comments

Comments
 (0)