diff --git a/Sources/LLVM/IRBuilder.swift b/Sources/LLVM/IRBuilder.swift index e07ef987..b9250abb 100644 --- a/Sources/LLVM/IRBuilder.swift +++ b/Sources/LLVM/IRBuilder.swift @@ -1349,6 +1349,29 @@ public class IRBuilder { return Alias(llvm: LLVMAddAlias(module.llvm, type.asLLVM(), aliasee.asLLVM(), name)) } + /// Adds the provided metadata value to the operands of a named metadata node + /// at module level. If the named metadata node does not exist, then it will + /// create a named metadata node with the provided value. + /// + /// - Parameters: + /// - name: The name for the named metadata node. + /// - value: The value to add to the named metata. + public func addNamedMetadataOperand(name: String, value: IRMetadata) { + LLVMAddNamedMetadataOperand(module.llvm, name, value.asLLVM()) + } + + public func namedMetadataOperands(name: String) -> [IRMetadata] { + let count = Int(LLVMGetNamedMetadataNumOperands(module.llvm, name)) + let ptr = UnsafeMutablePointer.allocate(capacity: count) + defer { free(ptr) } + LLVMGetNamedMetadataOperands(module.llvm, name, ptr) + let buf = UnsafeMutableBufferPointer(start: ptr, count: count) + return buf.flatMap { + guard let llvm = $0 else { return nil } + return MetadataNode.fromLLVM(llvm) + } + } + deinit { LLVMDisposeBuilder(llvm) } diff --git a/Sources/LLVM/IRValue+Kinds.swift b/Sources/LLVM/IRValue+Kinds.swift index ae7967cf..0cb6c462 100644 --- a/Sources/LLVM/IRValue+Kinds.swift +++ b/Sources/LLVM/IRValue+Kinds.swift @@ -3,7 +3,6 @@ import cllvm // Automatically generated from the macros in llvm/Core.h public extension IRValue { - /// Whether or not the underlying LLVM value is an `Argument` public var isAArgument: Bool { return LLVMIsAArgument(asLLVM()) != nil @@ -154,6 +153,16 @@ public extension IRValue { return LLVMIsADbgDeclareInst(asLLVM()) != nil } + /// Whether or not the underlying LLVM value is an `MDString` + public var isAnMDString: Bool { + return LLVMIsAMDString(asLLVM()) != nil + } + + /// Whether or not the underlying LLVM value is an `MDNode` + public var isAnMDNode: Bool { + return LLVMIsAMDNode(asLLVM()) != nil + } + /// Whether or not the underlying LLVM value is a `MemIntrinsic` public var isAMemIntrinsic: Bool { return LLVMIsAMemIntrinsic(asLLVM()) != nil diff --git a/Sources/LLVM/IRValue.swift b/Sources/LLVM/IRValue.swift index 76be97c7..f1321359 100644 --- a/Sources/LLVM/IRValue.swift +++ b/Sources/LLVM/IRValue.swift @@ -24,6 +24,32 @@ public extension IRValue { return LLVMIsConstant(asLLVM()) != 0 } + /// Returns whether this IRValue has any metadata attached. + public var hasMetadata: Bool { + return LLVMHasMetadata(asLLVM()) != 0 + } + + /// Returns the metadata attached to this value for the specified kind. + /// + /// - parameter kind: The kind of metadata you're looking for + /// - returns: The metadata attached to this node for the specified kind, + /// or `nil` if no metadata is attached. + public func metadata(kind: MetadataKind) -> IRMetadata? { + guard let meta = LLVMGetMetadata(asLLVM(), kind.rawValue) else { + return nil + } + return MetadataNode.fromLLVM(meta) + } + + /// Sets the metadata of the provided kind for this value. + /// + /// - parameters: + /// - value: The metadata value you wish to set. + /// - kind: The kind of metadata you wish to set. + public func setMetadata(_ value: IRMetadata, kind: MetadataKind) { + LLVMSetMetadata(asLLVM(), kind.rawValue, value.asLLVM()) + } + /// Returns whether this value has been initialized with the special `undef` /// value. /// diff --git a/Sources/LLVM/MetadataType.swift b/Sources/LLVM/MetadataType.swift index 27c168b8..604a475c 100644 --- a/Sources/LLVM/MetadataType.swift +++ b/Sources/LLVM/MetadataType.swift @@ -15,3 +15,185 @@ public struct MetadataType: IRType { return llvm } } + +/// Represents the debugInfofferent kinds of metadata available +public protocol IRMetadata: IRValue {} + +extension IRMetadata { + /// Retrieves the operands to which this metadata is attached + public var operands: [IRValue] { + let count = Int(LLVMGetMDNodeNumOperands(asLLVM())) + let ptr = UnsafeMutablePointer.allocate(capacity: count) + LLVMGetMDNodeOperands(asLLVM(), ptr) + + var operands = [IRValue]() + for i in 0.. IRMetadata { + if llvm.isAnMDString { return MetadataString(llvm: llvm) } + return MetadataNode(llvm: llvm) + } + + /// Creates a `MetadataNode` with the provided values, in the provided + /// context. If no context is provided, it will be created in the global + /// context. + /// + /// - parameters: + /// - values: The values to add to the metadata + /// - context: The context in which to create the metadata. Defaults to + /// `nil`, which means the global context. + public init(values: [IRValue], in context: Context? = nil) { + var vals = values.map { $0.asLLVM() as Optional } + self.llvm = vals.withUnsafeMutableBufferPointer { buf in + if let context = context { + return LLVMMDNodeInContext(context.llvm, buf.baseAddress, + UInt32(buf.count)) + } else { + return LLVMMDNode(buf.baseAddress, UInt32(buf.count)) + } + } + } + + /// Returns the underlying `LLVMValueRef` backing this node. + public func asLLVM() -> LLVMValueRef { + return llvm + } +} + +/// A `MetadataString` is an arbitrary string of metadata attached to an +/// instruction or value. +public struct MetadataString: IRMetadata, ExpressibleByStringLiteral { + let llvm: LLVMValueRef + + /// Creates a `MetadataString` from an underlying LLVM value + /// + /// - parameter llvm: The LLVM value for this `MDString` + internal init(llvm: LLVMValueRef) { + self.llvm = llvm + } + + /// Creates a `MetadataString` with the provided string as a value, in the + /// provided context. If no context is provided, it will be created in the + /// global context. + /// + /// - parameters: + /// - string: The string with which to create this node. + /// - context: The context in which to create this node. + public init(_ string: String, in context: Context? = nil) { + if let context = context { + self.llvm = LLVMMDStringInContext(context.llvm, string, + UInt32(string.utf8.count)) + } else { + self.llvm = LLVMMDString(string, UInt32(string.utf8.count)) + } + } + + /// Creates a `MetadataString` from a `String` literal. + /// + /// - parameter value: The string with which to create this node. + public init(stringLiteral value: String) { + self.init(value) + } + + /// Creates a `MetadataString` from a `UnicodeScalar` literal. + /// + /// - parameter value: The string with which to create this node. + public init(unicodeScalarLiteral value: String) { + self.init(value) + } + + /// Creates a `MetadataString` from a `ExtendedGraphemeClusterLiteral` + /// literal. + /// + /// - parameter value: The string with which to create this node. + public init(extendedGraphemeClusterLiteral value: String) { + self.init(value) + } + + /// Returns the underlying `LLVMValueRef` backing this string. + public func asLLVM() -> LLVMValueRef { + return llvm + } +} + +/// Enumerates the possible kinds of metadata that LLVM supports. +/// - note: These must match, exactly, the enum in `llvm/Metadata.h` +public enum MetadataKind: UInt32 { + /// A simple metadata node with a `tuple` of operands. + case tuple = 0 + + /// A debug location in source code, used for debug info and otherwise. + case debugInfoLocation = 1 + + /// An un-specialized DWARF-like metadata node. The first operand is a + /// (possibly empty) null-separated `MetadataString` header that contains + /// arbitrary fields. The remaining operands are references to other metadata. + case genericDebugInfoNode = 2 + + /// An array subrange. + case debugInfoSubrange = 3 + + /// A wrapper for an enumerator (e.g. `x` and `y` in `enum { case x, y }`) + case debugInfoEnumerator = 4 + + /// A basic type, like 'Int' or 'Double'. + case debugInfoBasicType = 5 + + /// A derived type. This includes qualified types, pointers, references, + /// friends, typedefs, and class members. + case debugInfoDerivedType = 6 + + /// A composite type, like a struct or vector. + case debugInfoCompositeType = 7 + + /// A type corresponding to a function. It has one child node, `types`, + /// a tuple of type metadata. + /// The first element is the return type of the function, or `null` if + /// the function returns void. The rest are the parameter types of the + /// function, in order. + case debugInfoSubroutineType = 8 + + /// A file node. + case debugInfoFile = 9 + case debugInfoCompileUnit = 10 + case debugInfoSubprogram = 11 + case debugInfoLexicalBlock = 12 + case debugInfoLexicalBlockFile = 13 + case debugInfoNamespace = 14 + case debugInfoModule = 15 + case debugInfoTemplateTypeParameter = 16 + case debugInfoTemplateValueParameter = 17 + case debugInfoGlobalVariable = 18 + case debugInfoLocalVariable = 19 + case debugInfoExpression = 20 + case debugInfoObjCProperty = 21 + case debugInfoImportedEntity = 22 + case constantAsMetadata = 23 + case localAsMetadata = 24 + case string = 25 + case debugInfoMacro = 26 + case debugInfoMacroFile = 27 +} diff --git a/Sources/LLVM/Utilities.swift b/Sources/LLVM/Utilities.swift new file mode 100644 index 00000000..8b76e6d8 --- /dev/null +++ b/Sources/LLVM/Utilities.swift @@ -0,0 +1,19 @@ +// +// Utilities.swift +// LLVM +// +// Created by Harlan Haskins on 1/15/17. +// +// + +import Foundation + +extension UnsafeMutablePointer { + internal func asArray(count: Int) -> [Pointee] { + var vals = [Pointee]() + for i in 0..