Skip to content

Commit 0b6fc5a

Browse files
committed
Introduce IRInstruction
In order to unify the many structures we have that each represent instruction values, introduce the IRInstruction protocol. LLVMValueRef now unconditionally conforms to IRInstruction to facilitate dynamic casts. Note that this is strictly not correct. In particular, constant folding means the result of a lot of IRBuilder calls wind up as just plain values. Therefore, the return types for IRBuilder functions has only been refined in as many places where we can guarantee constant-folding will always produce an instruction or instruction sequence. Ultimately, this protocol greases the wheels for a more robust AttachedMetadata API for which we need new shims.
1 parent 8ba2bb1 commit 0b6fc5a

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)