Skip to content

Commit bf3a4ec

Browse files
CodaFiharlanhaskins
authored andcommitted
Document Some Values (#3)
* Document Global * Document Module * Document PhiNode * Document Switch * Document Use
1 parent 3bd58f8 commit bf3a4ec

File tree

5 files changed

+198
-64
lines changed

5 files changed

+198
-64
lines changed

Sources/LLVMSwift/Global.swift

Lines changed: 36 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,40 @@
11
import cllvm
22

3+
/// A `Global` represents a region of memory allocated at compile time instead
4+
/// of at runtime. A global variable must either have an initializer, or make
5+
/// reference to an external definition that has an initializer.
36
public struct Global: IRValue {
4-
internal let llvm: LLVMValueRef
5-
6-
public var isExternallyInitialized: Bool {
7-
get { return LLVMIsExternallyInitialized(llvm) != 0 }
8-
set { LLVMSetExternallyInitialized(llvm, newValue.llvm) }
9-
}
10-
11-
public var initializer: IRValue {
12-
get { return LLVMGetInitializer(asLLVM()) }
13-
set { LLVMSetInitializer(asLLVM(), newValue.asLLVM()) }
14-
}
15-
16-
public var isGlobalConstant: Bool {
17-
get { return LLVMIsGlobalConstant(asLLVM()) != 0 }
18-
set { LLVMSetGlobalConstant(asLLVM(), newValue.llvm) }
19-
}
20-
21-
public var isThreadLocal: Bool {
22-
get { return LLVMIsThreadLocal(asLLVM()) != 0 }
23-
set { LLVMSetThreadLocal(asLLVM(), newValue.llvm) }
24-
}
25-
26-
public func asLLVM() -> LLVMValueRef {
27-
return llvm
28-
}
7+
internal let llvm: LLVMValueRef
8+
9+
/// Returns whether this global variable has no initializer because it makes
10+
/// reference to an initialized value in another translation unit.
11+
public var isExternallyInitialized: Bool {
12+
get { return LLVMIsExternallyInitialized(llvm) != 0 }
13+
set { LLVMSetExternallyInitialized(llvm, newValue.llvm) }
14+
}
15+
16+
/// Retrieves the initializer for this global variable, if it exists.
17+
public var initializer: IRValue? {
18+
get { return LLVMGetInitializer(asLLVM()) }
19+
set { LLVMSetInitializer(asLLVM(), newValue!.asLLVM()) }
20+
}
21+
22+
/// Returns whether this global variable is a constant, whether or not the
23+
/// final definition of the global is not.
24+
public var isGlobalConstant: Bool {
25+
get { return LLVMIsGlobalConstant(asLLVM()) != 0 }
26+
set { LLVMSetGlobalConstant(asLLVM(), newValue.llvm) }
27+
}
28+
29+
/// Returns whether this global variable is thread-local. That is, returns
30+
/// if this variable is not shared by multiple threads.
31+
public var isThreadLocal: Bool {
32+
get { return LLVMIsThreadLocal(asLLVM()) != 0 }
33+
set { LLVMSetThreadLocal(asLLVM(), newValue.llvm) }
34+
}
35+
36+
/// Retrieves the underlying LLVM value object.
37+
public func asLLVM() -> LLVMValueRef {
38+
return llvm
39+
}
2940
}

Sources/LLVMSwift/Module.swift

Lines changed: 64 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,31 @@
11
import cllvm
22

3+
/// A `Context` represents execution states for the core LLVM IR system.
34
public class Context {
45
internal let llvm: LLVMContextRef
6+
7+
/// Retrieves the global context instance.
58
public static let global = Context(llvm: LLVMGetGlobalContext()!)
9+
10+
/// Creates a `Context` object from an `LLVMContextRef` object.
611
public init(llvm: LLVMContextRef) {
712
self.llvm = llvm
813
}
914
}
1015

16+
/// Represents the possible errors that can be thrown while interacting with a
17+
/// `Module` object.
1118
public enum ModuleError: Error, CustomStringConvertible {
19+
/// Thrown when a module does not pass the module verification process.
20+
/// Includes the reason the module did not pass verification.
1221
case didNotPassVerification(String)
22+
/// Thrown when a module cannot be printed at a given path. Provides the
23+
/// erroneous path and a deeper reason why printing to that path failed.
1324
case couldNotPrint(path: String, error: String)
25+
/// Thrown when a module cannot emit bitcode because it contains erroneous
26+
/// declarations.
1427
case couldNotEmitBitCode(path: String)
15-
28+
1629
public var description: String {
1730
switch self {
1831
case .didNotPassVerification(let message):
@@ -25,8 +38,17 @@ public enum ModuleError: Error, CustomStringConvertible {
2538
}
2639
}
2740

41+
/// A `Module` represents the top-level structure of an LLVM program. An LLVM
42+
/// module is effectively a translation unit or a collection of translation
43+
/// units merged together.
2844
public final class Module {
2945
internal let llvm: LLVMModuleRef
46+
47+
/// Creates a `Module` with the given name.
48+
///
49+
/// - parameter name: The name of the module.
50+
/// - parameter context: The context to associate this module with. If no
51+
/// context is provided, one will be inferred.
3052
public init(name: String, context: Context? = nil) {
3153
if let context = context {
3254
llvm = LLVMModuleCreateWithNameInContext(name, context.llvm)
@@ -36,13 +58,21 @@ public final class Module {
3658
self.context = Context(llvm: LLVMGetModuleContext(llvm)!)
3759
}
3860
}
39-
61+
62+
/// Returns the context associated with this module.
4063
public let context: Context
41-
64+
65+
/// Obtain the data layout for this module.
4266
public var dataLayout: TargetData {
4367
return TargetData(llvm: LLVMGetModuleDataLayout(llvm))
4468
}
45-
69+
70+
/// Print a representation of a module to a file at the given path.
71+
///
72+
/// If the provided path is not suitable for writing, this function will throw
73+
/// `ModuleError.couldNotPrint`.
74+
///
75+
/// - parameter path: The path to write the module's representation to.
4676
public func print(to path: String) throws {
4777
var err: UnsafeMutablePointer<Int8>?
4878
path.withCString { cString in
@@ -55,7 +85,13 @@ public final class Module {
5585
throw ModuleError.couldNotPrint(path: path, error: String(cString: err))
5686
}
5787
}
58-
88+
89+
/// Writes the bitcode of elements in this module to a file at the given path.
90+
///
91+
/// If the provided path is not suitable for writing, this function will throw
92+
/// `ModuleError.couldNotEmitBitCode`.
93+
///
94+
/// - parameter path: The path to write the module's representation to.
5995
public func emitBitCode(to path: String) throws {
6096
let status = path.withCString { cString -> Int32 in
6197
let mutable = strdup(cString)
@@ -67,17 +103,35 @@ public final class Module {
67103
throw ModuleError.couldNotEmitBitCode(path: path)
68104
}
69105
}
70-
106+
107+
/// Searches for and retrieves a type with the given name in this module if
108+
/// that name references an existing type.
109+
///
110+
/// - parameter name: The name of the type to create.
111+
///
112+
/// - returns: A representation of the newly created type with the given name
113+
/// or nil if such a representation could not be created.
71114
public func type(named name: String) -> IRType? {
72115
guard let type = LLVMGetTypeByName(llvm, name) else { return nil }
73116
return convertType(type)
74117
}
75-
118+
119+
/// Searches for and retrieves a function with the given name in this module
120+
/// if that name references an existing function.
121+
///
122+
/// - parameter name: The name of the function to create.
123+
///
124+
/// - returns: A representation of the newly created function with the given
125+
/// name or nil if such a representation could not be created.
76126
public func function(named name: String) -> Function? {
77127
guard let fn = LLVMGetNamedFunction(llvm, name) else { return nil }
78128
return Function(llvm: fn)
79129
}
80-
130+
131+
/// Verifies that this module is valid, taking the specified action if not.
132+
/// If this module did not pass verification, a description of any invalid
133+
/// constructs is provided with the thrown
134+
/// `ModuleError.didNotPassVerification` error.
81135
public func verify() throws {
82136
var message: UnsafeMutablePointer<Int8>?
83137
let status = Int(LLVMVerifyModule(llvm, LLVMReturnStatusAction, &message))
@@ -86,7 +140,8 @@ public final class Module {
86140
throw ModuleError.didNotPassVerification(String(cString: message))
87141
}
88142
}
89-
143+
144+
/// Dump a representation of this module to stderr.
90145
public func dump() {
91146
LLVMDumpModule(llvm)
92147
}

Sources/LLVMSwift/PhiNode.swift

Lines changed: 59 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,47 @@
11
import cllvm
22

3+
/// A `PhiNode` object represents a PHI node.
4+
///
5+
/// Because all instructions in LLVM IR are in SSA (Single Static Assignment)
6+
/// form, a PHI node is necessary when the value of a variable assignment
7+
/// depends on the path the flow of control takes through the program. For
8+
/// example:
9+
///
10+
/// ```swift
11+
/// var a = 1
12+
/// if c == 42 {
13+
/// a = 2
14+
/// }
15+
/// let b = a
16+
/// ```
17+
///
18+
/// The value of `b` in this program depends on the value of the condition
19+
/// involving the variable `c`. Because `b` must be assigned to once, a PHI
20+
/// node is created and the program effectively is transformed into the
21+
/// following:
22+
///
23+
/// ```swift
24+
/// let aNoCond = 1
25+
/// if c == 42 {
26+
/// let aCondTrue = 2
27+
/// }
28+
/// let b = PHI(aNoCond, aCondTrue)
29+
/// ```
30+
///
31+
/// If the flow of control reaches `aCondTrue`, the value of `b` is `2`, else it
32+
/// is `1` and SSA semantics are preserved.
333
public struct PhiNode: IRValue {
434
internal let llvm: LLVMValueRef
5-
35+
36+
/// Adds a list of incoming value and their associated basic blocks to the end
37+
/// of the list of incoming values for this PHI node.
38+
///
39+
/// - parameter valueMap: A list of incoming values and their associated basic
40+
/// blocks.
641
public func addIncoming(_ valueMap: [(IRValue, BasicBlock)]) {
742
var values = valueMap.map { $0.0.asLLVM() as Optional }
843
var blocks = valueMap.map { $0.1.asLLVM() as Optional }
9-
44+
1045
values.withUnsafeMutableBufferPointer { valueBuf in
1146
blocks.withUnsafeMutableBufferPointer { blockBuf in
1247
LLVMAddIncoming(llvm,
@@ -16,27 +51,44 @@ public struct PhiNode: IRValue {
1651
}
1752
}
1853
}
19-
54+
55+
/// Obtain the incoming values and their associated basic blocks for this PHI
56+
/// node.
2057
public var incoming: [(IRValue, BasicBlock)] {
2158
let count = Int(LLVMCountIncoming(llvm))
2259
var values = [(IRValue, BasicBlock)]()
2360
for i in 0..<count {
2461
guard let value = incomingValue(at: i),
25-
let block = incomingBlock(at: i) else { continue }
62+
let block = incomingBlock(at: i) else { continue }
2663
values.append((value, block))
2764
}
2865
return values
2966
}
30-
67+
68+
/// Retrieves the incoming value for the given index for this PHI node, if it
69+
/// exists.
70+
///
71+
/// - parameter index: The index of the incoming value to retrieve.
72+
///
73+
/// - returns: A value representing the incoming value to this PHI node at
74+
/// the given index, if it exists.
3175
public func incomingValue(at index: Int) -> IRValue? {
3276
return LLVMGetIncomingValue(llvm, UInt32(index))
3377
}
34-
78+
79+
/// Retrieves the incoming basic block for the given index for this PHI node,
80+
/// if it exists.
81+
///
82+
/// - parameter index: The index of the incoming basic block to retrieve.
83+
///
84+
/// - returns: A value representing the incoming basic block to this PHI node
85+
/// at the given index, if it exists.
3586
public func incomingBlock(at index: Int) -> BasicBlock? {
3687
guard let blockRef = LLVMGetIncomingBlock(llvm, UInt32(index)) else { return nil }
3788
return BasicBlock(llvm: blockRef)
3889
}
39-
90+
91+
/// Retrieves the underlying LLVM value object.
4092
public func asLLVM() -> LLVMValueRef {
4193
return llvm
4294
}

Sources/LLVMSwift/Switch.swift

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,24 @@
11
import cllvm
22

3+
/// A `Switch` represents a `switch` instruction. A `switch` instruction
4+
/// defines a jump table of values and destination basic blocks to pass the flow
5+
/// of control to if a condition value matches. If no match is made, control
6+
/// flow passes to the default basic block.
37
public struct Switch: IRValue {
4-
internal let llvm: LLVMValueRef
5-
6-
public func addCase(_ value: IRValue, _ block: BasicBlock) {
7-
LLVMAddCase(llvm, value.asLLVM(), block.asLLVM())
8-
}
9-
10-
public func asLLVM() -> LLVMValueRef {
11-
return llvm
12-
}
8+
internal let llvm: LLVMValueRef
9+
10+
/// Inserts a case with the given value and destination basic block in the
11+
/// jump table of this `switch` instruction.
12+
///
13+
/// - parameter value: The value that acts as the selector for this case.
14+
/// - parameter block: The destination block for the flow of control if this
15+
/// case is matched.
16+
public func addCase(_ value: IRValue, _ block: BasicBlock) {
17+
LLVMAddCase(llvm, value.asLLVM(), block.asLLVM())
18+
}
19+
20+
/// Retrieves the underlying LLVM value object.
21+
public func asLLVM() -> LLVMValueRef {
22+
return llvm
23+
}
1324
}

Sources/LLVMSwift/Use.swift

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
import cllvm
22

3+
/// `Use` represents an iterator over the uses and users of a particular value
4+
/// in an LLVM program.
35
public struct Use {
4-
internal let llvm: LLVMUseRef
5-
6-
public func next() -> Use? {
7-
guard let next = LLVMGetNextUse(llvm) else { return nil }
8-
return Use(llvm: next)
9-
}
10-
11-
public func user() -> IRValue? {
12-
return LLVMGetUser(llvm)
13-
}
14-
15-
public func usedValue() -> IRValue? {
16-
return LLVMGetUsedValue(llvm)
17-
}
6+
internal let llvm: LLVMUseRef
7+
8+
/// Retrieves the next use of a value.
9+
public func next() -> Use? {
10+
guard let next = LLVMGetNextUse(llvm) else { return nil }
11+
return Use(llvm: next)
12+
}
13+
14+
/// Obtain the user value for this `User` object.
15+
public func user() -> IRValue? {
16+
return LLVMGetUser(llvm)
17+
}
18+
19+
/// Obtain the value this `User` object corresponds to.
20+
public func usedValue() -> IRValue? {
21+
return LLVMGetUsedValue(llvm)
22+
}
1823
}

0 commit comments

Comments
 (0)