From 468303df82c66a5eac6a34f237e4a8905f5aa2b9 Mon Sep 17 00:00:00 2001 From: Robert Widmann Date: Sun, 26 Feb 2017 15:29:20 -0500 Subject: [PATCH] Model Call and Invoke as higher level structures --- Sources/LLVM/Call.swift | 66 ++++++++++++++++++++++++++++++++++++ Sources/LLVM/IRBuilder.swift | 8 ++--- 2 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 Sources/LLVM/Call.swift diff --git a/Sources/LLVM/Call.swift b/Sources/LLVM/Call.swift new file mode 100644 index 00000000..a10b6338 --- /dev/null +++ b/Sources/LLVM/Call.swift @@ -0,0 +1,66 @@ +#if !NO_SWIFTPM +import cllvm +#endif + +/// Represents a simple function call. +public struct Call: IRValue { + let llvm: LLVMValueRef + + /// Retrieves the underlying LLVM value object. + public func asLLVM() -> LLVMValueRef { + return self.llvm + } + + /// Retrieves the number of argument operands passed by this call. + public var argumentCount: Int { + return Int(LLVMGetNumArgOperands(self.llvm)) + } + + /// Accesses the calling convention for this function call. + public var callingConvention: CallingConvention { + get { return CallingConvention(rawValue: LLVMGetInstructionCallConv(self.llvm))! } + set { LLVMSetInstructionCallConv(self.llvm, newValue.rawValue) } + } + + /// Returns whether this function call is a tail call. That is, if the callee + /// may reuse the stack memory of the caller. + /// + /// This attribute requires support from the target architecture. + public var isTailCall: Bool { + get { return LLVMIsTailCall(self.llvm) != 0 } + set { LLVMSetTailCall(self.llvm, newValue.llvm) } + } + + /// Retrieves the alignment of the parameter at the given index. + /// + /// This property is currently set-only due to limitations of the LLVM C API. + /// + /// - parameter i: The index of the parameter to retrieve. + /// - parameter alignment: The alignment to apply to the parameter. + public func setParameterAlignment(at i : Int, to alignment: Int) { + LLVMSetInstrParamAlignment(self.llvm, UInt32(i), UInt32(alignment)) + } +} + +/// Represents a function call that may transfer control to an exception handler. +public struct Invoke: IRValue { + let llvm: LLVMValueRef + + /// Retrieves the underlying LLVM value object. + public func asLLVM() -> LLVMValueRef { + return self.llvm + } + + /// Accesses the destination block the flow of control will transfer to if an + /// exception does not occur. + public var normalDestination: BasicBlock { + get { return BasicBlock(llvm: LLVMGetNormalDest(self.llvm)) } + set { LLVMSetNormalDest(self.llvm, newValue.asLLVM()) } + } + + /// Accesses the destination block that exception unwinding will jump to. + public var unwindDestination: BasicBlock { + get { return BasicBlock(llvm: LLVMGetUnwindDest(self.llvm)) } + set { LLVMSetUnwindDest(self.llvm, newValue.asLLVM()) } + } +} diff --git a/Sources/LLVM/IRBuilder.swift b/Sources/LLVM/IRBuilder.swift index 4e273b14..41ef8280 100644 --- a/Sources/LLVM/IRBuilder.swift +++ b/Sources/LLVM/IRBuilder.swift @@ -965,10 +965,10 @@ public class IRBuilder { /// - parameter name: The name for the newly inserted instruction. /// /// - returns: A value representing the result of returning from the callee. - public func buildCall(_ fn: IRValue, args: [IRValue], name: String = "") -> IRValue { + public func buildCall(_ fn: IRValue, args: [IRValue], name: String = "") -> Call { var args = args.map { $0.asLLVM() as Optional } return args.withUnsafeMutableBufferPointer { buf in - return LLVMBuildCall(llvm, fn.asLLVM(), buf.baseAddress!, UInt32(buf.count), name) + return Call(llvm: LLVMBuildCall(llvm, fn.asLLVM(), buf.baseAddress!, UInt32(buf.count), name)) } } @@ -994,12 +994,12 @@ public class IRBuilder { /// - returns: A value representing the result of returning from the callee /// under normal circumstances. Under exceptional circumstances, the value /// represents the value of any `resume` instruction in the `catch` block. - public func buildInvoke(_ fn: IRValue, args: [IRValue], next: BasicBlock, catch: BasicBlock, name: String = "") -> IRValue { + public func buildInvoke(_ fn: IRValue, args: [IRValue], next: BasicBlock, catch: BasicBlock, name: String = "") -> Invoke { precondition(`catch`.firstInstruction!.opCode == .landingPad, "First instruction of catch block must be a landing pad") var args = args.map { $0.asLLVM() as Optional } return args.withUnsafeMutableBufferPointer { buf in - return LLVMBuildInvoke(llvm, fn.asLLVM(), buf.baseAddress!, UInt32(buf.count), next.llvm, `catch`.llvm, name) + return Invoke(llvm: LLVMBuildInvoke(llvm, fn.asLLVM(), buf.baseAddress!, UInt32(buf.count), next.llvm, `catch`.llvm, name)) } }