22import 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.
7267public 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+
723755extension Bool {
724756 internal var llvm : LLVMBool {
725757 return self ? 1 : 0
0 commit comments