Skip to content

Commit dd26f01

Browse files
authored
Merge pull request #196 from CodaFi/very-instructive
Introduce IRInstruction
2 parents 8ba2bb1 + 0b6fc5a commit dd26f01

File tree

12 files changed

+248
-80
lines changed

12 files changed

+248
-80
lines changed

Sources/LLVM/AttachedMetadata.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ extension IRGlobal {
5252
}
5353
}
5454

55-
extension Instruction {
55+
extension IRInstruction {
5656
/// Retrieves all metadata entries attached to this instruction.
5757
public var metadata: AttachedMetadata {
5858
var count = 0

Sources/LLVM/BasicBlock.swift

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,13 +61,13 @@ public struct BasicBlock: IRValue {
6161
}
6262

6363
/// Returns the first instruction in the basic block, if it exists.
64-
public var firstInstruction: Instruction? {
64+
public var firstInstruction: IRInstruction? {
6565
guard let val = LLVMGetFirstInstruction(llvm) else { return nil }
6666
return Instruction(llvm: val)
6767
}
6868

6969
/// Returns the first instruction in the basic block, if it exists.
70-
public var lastInstruction: Instruction? {
70+
public var lastInstruction: IRInstruction? {
7171
guard let val = LLVMGetLastInstruction(llvm) else { return nil }
7272
return Instruction(llvm: val)
7373
}
@@ -98,10 +98,10 @@ public struct BasicBlock: IRValue {
9898
}
9999

100100
/// Returns a sequence of the Instructions that make up this basic block.
101-
public var instructions: AnySequence<Instruction> {
101+
public var instructions: AnySequence<IRInstruction> {
102102
var current = firstInstruction
103-
return AnySequence<Instruction> {
104-
return AnyIterator<Instruction> {
103+
return AnySequence<IRInstruction> {
104+
return AnyIterator<IRInstruction> {
105105
defer { current = current?.next() }
106106
return current
107107
}

Sources/LLVM/Call.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import cllvm
33
#endif
44

55
/// Represents a simple function call.
6-
public struct Call: IRValue {
6+
public struct Call: IRInstruction {
77
let llvm: LLVMValueRef
88

99
/// Retrieves the underlying LLVM value object.
@@ -43,7 +43,7 @@ public struct Call: IRValue {
4343
}
4444

4545
/// Represents a function call that may transfer control to an exception handler.
46-
public struct Invoke: IRValue {
46+
public struct Invoke: IRInstruction {
4747
let llvm: LLVMValueRef
4848

4949
/// Retrieves the underlying LLVM value object.

Sources/LLVM/DIBuilder.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ extension DIBuilder {
6565
/// - location: The location of the variable in source.
6666
public func buildDeclare(
6767
of variable: IRValue,
68-
before: Instruction,
68+
before: IRInstruction,
6969
metadata: LocalVariableMetadata,
7070
expr: ExpressionMetadata,
7171
location: DebugLocation
@@ -133,7 +133,7 @@ extension DIBuilder {
133133
public func buildDbgValue(
134134
of value: IRValue,
135135
to metadata: LocalVariableMetadata,
136-
before: Instruction,
136+
before: IRInstruction,
137137
expr: ExpressionMetadata,
138138
location: DebugLocation
139139
) {

Sources/LLVM/IRBuilder.swift

Lines changed: 56 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -556,7 +556,7 @@ extension IRBuilder {
556556
/// - parameter name: The name for the newly inserted instruction.
557557
///
558558
/// - returns: A value representing the value selected for by the condition.
559-
public func buildSelect(_ cond: IRValue, then: IRValue, else: IRValue, name: String = "") -> IRValue {
559+
public func buildSelect(_ cond: IRValue, then: IRValue, else: IRValue, name: String = "") -> IRInstruction {
560560
if let ty = cond.type as? IntType {
561561
precondition(ty.width == 1, "Switch statement condition must have bitwidth of 1, instead has bitwidth of \(ty.width)")
562562
return LLVMBuildSelect(llvm, cond.asLLVM(), then.asLLVM(), `else`.asLLVM(), name)
@@ -644,7 +644,7 @@ extension IRBuilder {
644644
///
645645
/// - returns: A value representing `void`.
646646
@discardableResult
647-
public func buildBr(_ block: BasicBlock) -> IRValue {
647+
public func buildBr(_ block: BasicBlock) -> IRInstruction {
648648
return LLVMBuildBr(llvm, block.llvm)
649649
}
650650

@@ -665,7 +665,7 @@ extension IRBuilder {
665665
///
666666
/// - returns: A value representing `void`.
667667
@discardableResult
668-
public func buildCondBr(condition: IRValue, then: BasicBlock, `else`: BasicBlock) -> IRValue {
668+
public func buildCondBr(condition: IRValue, then: BasicBlock, `else`: BasicBlock) -> IRInstruction {
669669
return LLVMBuildCondBr(llvm, condition.asLLVM(), then.asLLVM(), `else`.asLLVM())
670670
}
671671

@@ -686,7 +686,7 @@ extension IRBuilder {
686686
///
687687
/// - returns: An IRValue representing `void`.
688688
@discardableResult
689-
public func buildIndirectBr(address: BasicBlock.Address, destinations: [BasicBlock]) -> IRValue {
689+
public func buildIndirectBr(address: BasicBlock.Address, destinations: [BasicBlock]) -> IRInstruction {
690690
guard let ret = LLVMBuildIndirectBr(llvm, address.asLLVM(), UInt32(destinations.count)) else {
691691
fatalError("Unable to build indirect branch to address \(address)")
692692
}
@@ -710,7 +710,7 @@ extension IRBuilder {
710710
///
711711
/// - returns: A value representing `void`.
712712
@discardableResult
713-
public func buildRet(_ val: IRValue) -> IRValue {
713+
public func buildRet(_ val: IRValue) -> IRInstruction {
714714
return LLVMBuildRet(llvm, val.asLLVM())
715715
}
716716

@@ -725,7 +725,7 @@ extension IRBuilder {
725725
///
726726
/// - returns: A value representing `void`.
727727
@discardableResult
728-
public func buildRetVoid() -> IRValue {
728+
public func buildRetVoid() -> IRInstruction {
729729
return LLVMBuildRetVoid(llvm)
730730
}
731731

@@ -738,18 +738,19 @@ extension IRBuilder {
738738
///
739739
/// - returns: A value representing `void`.
740740
@discardableResult
741-
public func buildUnreachable() -> IRValue {
741+
public func buildUnreachable() -> IRInstruction {
742742
return LLVMBuildUnreachable(llvm)
743743
}
744744

745745
/// Build a return from the current function back to the calling function with
746746
/// the given array of values as members of an aggregate.
747747
///
748-
/// - parameter values: The values to insert as members of the returned aggregate.
748+
/// - parameter values: The values to insert as members of the returned
749+
/// aggregate.
749750
///
750751
/// - returns: A value representing `void`.
751752
@discardableResult
752-
public func buildRetAggregate(of values: [IRValue]) -> IRValue {
753+
public func buildRetAggregate(of values: [IRValue]) -> IRInstruction {
753754
var values = values.map { $0.asLLVM() as Optional }
754755
return values.withUnsafeMutableBufferPointer { buf in
755756
return LLVMBuildAggregateRet(llvm, buf.baseAddress!, UInt32(buf.count))
@@ -842,10 +843,10 @@ extension IRBuilder {
842843
///
843844
/// - returns: A value of the given type representing the result of matching
844845
/// a clause during unwinding.
845-
public func buildLandingPad(returning type: IRType, personalityFn: Function? = nil, clauses: [LandingPadClause], cleanup: Bool = false, name: String = "") -> IRValue {
846+
public func buildLandingPad(returning type: IRType, personalityFn: Function? = nil, clauses: [LandingPadClause], cleanup: Bool = false, name: String = "") -> IRInstruction {
846847
precondition(cleanup || !clauses.isEmpty, "Landing pad must be created with clauses or as cleanup")
847848

848-
let lp : IRValue = LLVMBuildLandingPad(llvm, type.asLLVM(), personalityFn?.asLLVM(), UInt32(clauses.count), name)
849+
let lp: IRInstruction = LLVMBuildLandingPad(llvm, type.asLLVM(), personalityFn?.asLLVM(), UInt32(clauses.count), name)
849850
for clause in clauses {
850851
LLVMAddClause(lp.asLLVM(), clause.asLLVM())
851852
}
@@ -911,7 +912,7 @@ extension IRBuilder {
911912
///
912913
/// - returns: A value representing `void`.
913914
public func buildAlloca(type: IRType, count: IRValue? = nil,
914-
alignment: Alignment = .zero, name: String = "") -> IRValue {
915+
alignment: Alignment = .zero, name: String = "") -> IRInstruction {
915916
let allocaInst: LLVMValueRef
916917
if let count = count {
917918
allocaInst = LLVMBuildArrayAlloca(llvm, type.asLLVM(), count.asLLVM(), name)
@@ -934,7 +935,7 @@ extension IRBuilder {
934935
///
935936
/// - returns: A value representing `void`.
936937
@discardableResult
937-
public func buildStore(_ val: IRValue, to ptr: IRValue, ordering: AtomicOrdering = .notAtomic, volatile: Bool = false, alignment: Alignment = .zero) -> IRValue {
938+
public func buildStore(_ val: IRValue, to ptr: IRValue, ordering: AtomicOrdering = .notAtomic, volatile: Bool = false, alignment: Alignment = .zero) -> IRInstruction {
938939
let storeInst = LLVMBuildStore(llvm, val.asLLVM(), ptr.asLLVM())!
939940
LLVMSetOrdering(storeInst, ordering.llvm)
940941
LLVMSetVolatile(storeInst, volatile.llvm)
@@ -954,7 +955,7 @@ extension IRBuilder {
954955
///
955956
/// - returns: A value representing the result of a load from the given
956957
/// pointer value.
957-
public func buildLoad(_ ptr: IRValue, ordering: AtomicOrdering = .notAtomic, volatile: Bool = false, alignment: Alignment = .zero, name: String = "") -> IRValue {
958+
public func buildLoad(_ ptr: IRValue, ordering: AtomicOrdering = .notAtomic, volatile: Bool = false, alignment: Alignment = .zero, name: String = "") -> IRInstruction {
958959
let loadInst = LLVMBuildLoad(llvm, ptr.asLLVM(), name)!
959960
LLVMSetOrdering(loadInst, ordering.llvm)
960961
LLVMSetVolatile(loadInst, volatile.llvm)
@@ -1258,6 +1259,31 @@ extension IRBuilder {
12581259
}
12591260
}
12601261

1262+
/// Build an expression that returns the difference between two pointer
1263+
/// values, dividing out the size of the pointed-to objects.
1264+
///
1265+
/// This is intended to implement C-style pointer subtraction. As such, the
1266+
/// pointers must be appropriately aligned for their element types and
1267+
/// pointing into the same object.
1268+
///
1269+
/// - parameter lhs: The first pointer (the minuend).
1270+
/// - parameter rhs: The second pointer (the subtrahend).
1271+
/// - parameter name: The name for the newly inserted instruction.
1272+
///
1273+
/// - returns: A IRValue representing a 64-bit integer value of the difference
1274+
/// of the two pointer values modulo the size of the pointed-to objects.
1275+
public func buildPointerDifference(_ lhs: IRValue, _ rhs: IRValue, name: String = "") -> IRValue {
1276+
precondition(
1277+
lhs.type is PointerType && rhs.type is PointerType,
1278+
"Cannot take pointer diff of \(lhs.type) and \(rhs.type)."
1279+
)
1280+
return LLVMBuildPtrDiff(llvm, lhs.asLLVM(), rhs.asLLVM(), name)
1281+
}
1282+
}
1283+
1284+
// MARK: Type Information
1285+
1286+
extension IRBuilder {
12611287
/// Build a constant expression that returns the alignment of the given type
12621288
/// in bytes.
12631289
///
@@ -1279,27 +1305,6 @@ extension IRBuilder {
12791305
public func buildSizeOf(_ val: IRType) -> IRValue {
12801306
return LLVMSizeOf(val.asLLVM())
12811307
}
1282-
1283-
/// Build an expression that returns the difference between two pointer
1284-
/// values, dividing out the size of the pointed-to objects.
1285-
///
1286-
/// This is intended to implement C-style pointer subtraction. As such, the
1287-
/// pointers must be appropriately aligned for their element types and
1288-
/// pointing into the same object.
1289-
///
1290-
/// - parameter lhs: The first pointer (the minuend).
1291-
/// - parameter rhs: The second pointer (the subtrahend).
1292-
/// - parameter name: The name for the newly inserted instruction.
1293-
///
1294-
/// - returns: A IRValue representing a 64-bit integer value of the difference
1295-
/// of the two pointer values modulo the size of the pointed-to objects.
1296-
public func buildPointerDifference(_ lhs: IRValue, _ rhs: IRValue, name: String = "") -> IRValue {
1297-
precondition(
1298-
lhs.type is PointerType && rhs.type is PointerType,
1299-
"Cannot take pointer diff of \(lhs.type) and \(rhs.type)."
1300-
)
1301-
return LLVMBuildPtrDiff(llvm, lhs.asLLVM(), rhs.asLLVM(), name)
1302-
}
13031308
}
13041309

13051310
// MARK: Atomic Instructions
@@ -1333,7 +1338,8 @@ extension IRBuilder {
13331338
/// - parameter name: The name for the newly inserted instruction.
13341339
///
13351340
/// - returns: A value representing `void`.
1336-
public func buildFence(ordering: AtomicOrdering, singleThreaded: Bool = false, name: String = "") -> IRValue {
1341+
@discardableResult
1342+
public func buildFence(ordering: AtomicOrdering, singleThreaded: Bool = false, name: String = "") -> IRInstruction {
13371343
return LLVMBuildFence(llvm, ordering.llvm, singleThreaded.llvm, name)
13381344
}
13391345

@@ -1424,7 +1430,7 @@ extension IRBuilder {
14241430
/// C array.
14251431
/// - parameter name: The intended name for the `malloc`'d value.
14261432
public func buildMalloc(_ type: IRType, count: IRValue? = nil,
1427-
name: String = "") -> IRValue {
1433+
name: String = "") -> IRInstruction {
14281434
if let count = count {
14291435
return LLVMBuildArrayMalloc(llvm, type.asLLVM(), count.asLLVM(), name)
14301436
} else {
@@ -1438,7 +1444,7 @@ extension IRBuilder {
14381444
/// - parameter ptr: The pointer to `free`.
14391445
/// - returns: The `free` instruction.
14401446
@discardableResult
1441-
public func buildFree(_ ptr: IRValue) -> IRValue {
1447+
public func buildFree(_ ptr: IRValue) -> IRInstruction {
14421448
return LLVMBuildFree(llvm, ptr.asLLVM())
14431449
}
14441450
}
@@ -1464,12 +1470,14 @@ extension IRBuilder {
14641470
/// relied upon to perform consistently. For more information, see the
14651471
/// language reference's section on [Volatile Memory
14661472
/// Access](http://llvm.org/docs/LangRef.html#volatile-memory-accesses).
1473+
@discardableResult
14671474
public func buildMemset(
14681475
to dest: IRValue, of value: IRValue, length: IRValue,
14691476
alignment: Alignment, volatile: Bool = false
1470-
) {
1471-
let instruction = LLVMBuildMemSet(self.llvm, dest.asLLVM(), value.asLLVM(), length.asLLVM(), alignment.rawValue)
1477+
) -> IRInstruction {
1478+
let instruction = LLVMBuildMemSet(self.llvm, dest.asLLVM(), value.asLLVM(), length.asLLVM(), alignment.rawValue)!
14721479
LLVMSetVolatile(instruction, volatile.llvm)
1480+
return instruction
14731481
}
14741482

14751483
/// Builds a call to the `llvm.memcpy.*` family of intrinsics to copy a block
@@ -1495,13 +1503,15 @@ extension IRBuilder {
14951503
/// relied upon to perform consistently. For more information, see the
14961504
/// language reference's section on [Volatile Memory
14971505
/// Access](http://llvm.org/docs/LangRef.html#volatile-memory-accesses).
1506+
@discardableResult
14981507
public func buildMemCpy(
14991508
to dest: IRValue, _ destAlign: Alignment,
15001509
from src: IRValue, _ srcAlign: Alignment,
15011510
length: IRValue, volatile: Bool = false
1502-
) {
1503-
let instruction = LLVMBuildMemCpy(self.llvm, dest.asLLVM(), destAlign.rawValue, src.asLLVM(), srcAlign.rawValue, length.asLLVM())
1511+
) -> IRInstruction {
1512+
let instruction = LLVMBuildMemCpy(self.llvm, dest.asLLVM(), destAlign.rawValue, src.asLLVM(), srcAlign.rawValue, length.asLLVM())!
15041513
LLVMSetVolatile(instruction, volatile.llvm)
1514+
return instruction
15051515
}
15061516

15071517
/// Builds a call to the `llvm.memmove.*` family of intrinsics to move a
@@ -1527,13 +1537,15 @@ extension IRBuilder {
15271537
/// relied upon to perform consistently. For more information, see the
15281538
/// language reference's section on [Volatile Memory
15291539
/// Access](http://llvm.org/docs/LangRef.html#volatile-memory-accesses).
1540+
@discardableResult
15301541
public func buildMemMove(
15311542
to dest: IRValue, _ destAlign: Alignment,
15321543
from src: IRValue, _ srcAlign: Alignment,
15331544
length: IRValue, volatile: Bool = false
1534-
) {
1535-
let instruction = LLVMBuildMemMove(self.llvm, dest.asLLVM(), destAlign.rawValue, src.asLLVM(), srcAlign.rawValue, length.asLLVM())
1545+
) -> IRInstruction {
1546+
let instruction = LLVMBuildMemMove(self.llvm, dest.asLLVM(), destAlign.rawValue, src.asLLVM(), srcAlign.rawValue, length.asLLVM())!
15361547
LLVMSetVolatile(instruction, volatile.llvm)
1548+
return instruction
15371549
}
15381550
}
15391551

Sources/LLVM/IRValue.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,11 @@ public extension IRValue {
2020
return LLVMIsConstant(asLLVM()) != 0
2121
}
2222

23+
/// Returns whether this value is an instruction.
24+
var isInstruction: Bool {
25+
return LLVMIsAInstruction(asLLVM()) != nil
26+
}
27+
2328
/// Returns whether this value has been initialized with the special `undef`
2429
/// value.
2530
///
@@ -151,6 +156,12 @@ extension LLVMValueRef: IRValue {
151156
}
152157
}
153158

159+
// N.B. This conformance is strictly not correct, but LLVM-C chooses to muddy
160+
// the difference between LLVMValueRef and a number of what should be refined
161+
// types. What matters is that we verify any returned `IRInstruction` values
162+
// are actually instructions.
163+
extension LLVMValueRef: IRInstruction {}
164+
154165
extension Int: IRValue {
155166
/// Retrieves the underlying LLVM value object.
156167
public func asLLVM() -> LLVMValueRef {

0 commit comments

Comments
 (0)