Skip to content

Commit 22f771b

Browse files
committed
Add indirect branches
1 parent da748e4 commit 22f771b

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

Sources/LLVM/BasicBlock.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,3 +86,20 @@ public struct BasicBlock: IRValue {
8686
LLVMMoveBasicBlockAfter(llvm, block.llvm)
8787
}
8888
}
89+
90+
extension BasicBlock {
91+
/// A `Address` represents a function-relative address of a basic block for
92+
/// use with the `indirectbr` instruction.
93+
public struct Address: IRValue {
94+
internal let llvm: LLVMValueRef
95+
96+
internal init(llvm: LLVMValueRef) {
97+
self.llvm = llvm
98+
}
99+
100+
/// Retrieves the underlying LLVM value object.
101+
public func asLLVM() -> LLVMValueRef {
102+
return llvm
103+
}
104+
}
105+
}

Sources/LLVM/Function.swift

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,35 @@ public class Function: IRGlobal {
9090
}
9191
}
9292

93+
/// Computes the address of the specified basic block in this function, and
94+
/// always has an `i8*` type.
95+
///
96+
/// Taking the address of the entry block is illegal.
97+
///
98+
/// This value only has defined behavior when used as an operand to the
99+
/// `indirectbr` instruction, or for comparisons against null. Pointer
100+
/// equality tests between labels addresses results in undefined behavior
101+
/// — though, again, comparison against null is ok, and no label is equal to
102+
/// the null pointer. This may be passed around as an opaque pointer sized
103+
/// value as long as the bits are not inspected. This allows `ptrtoint` and
104+
/// arithmetic to be performed on these values so long as the original value
105+
/// is reconstituted before the indirectbr instruction.
106+
///
107+
/// Finally, some targets may provide defined semantics when using the value
108+
/// as the operand to an inline assembly, but that is target specific.
109+
///
110+
/// - parameter block: The basic block to compute the address of.
111+
///
112+
/// - returns: An IRValue representing the address of the given basic block
113+
/// in this function, else nil if the address cannot be computed or the
114+
/// basic block does not reside in this function.
115+
public func address(of block: BasicBlock) -> BasicBlock.Address? {
116+
guard let addr = LLVMBlockAddress(llvm, block.llvm) else {
117+
return nil
118+
}
119+
return BasicBlock.Address(llvm: addr)
120+
}
121+
93122
/// Retrieves the previous function in the module, if there is one.
94123
public func previous() -> Function? {
95124
guard let previous = LLVMGetPreviousFunction(llvm) else { return nil }

Sources/LLVM/IRBuilder.swift

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,25 @@ public class IRBuilder {
864864
return LLVMBuildCondBr(llvm, condition.asLLVM(), then.asLLVM(), `else`.asLLVM())
865865
}
866866

867+
/// Build an indirect branch to a label within the current function.
868+
///
869+
/// - parameter address: The address of the label to branch to.
870+
/// - parameter destinations: The set of possible destinations the address may
871+
/// point to. The same block may appear multiple times in this list, though
872+
/// this isn't particularly useful.
873+
///
874+
/// - returns: An IRValue representing `void`.
875+
@discardableResult
876+
public func buildIndirectBr(address: BasicBlock.Address, destinations: [BasicBlock]) -> IRValue {
877+
guard let ret = LLVMBuildIndirectBr(llvm, address.asLLVM(), UInt32(destinations.count)) else {
878+
fatalError("Unable to build indirect branch to address \(address)")
879+
}
880+
for dest in destinations {
881+
LLVMAddDestination(ret, dest.llvm)
882+
}
883+
return ret
884+
}
885+
867886
/// Builds a return from the current function back to the calling function
868887
/// with the given value.
869888
///

0 commit comments

Comments
 (0)