diff --git a/Package.swift b/Package.swift index 89ee13f..06fccd4 100644 --- a/Package.swift +++ b/Package.swift @@ -91,7 +91,7 @@ func getTargets() -> [Target] { let llvmTarget: Target = .target( name: "LLVM", dependencies: ["CLLVM"], - path: "llvm-api/LLVM", + // path: "llvm-api/LLVM", cSettings: [ .unsafeFlags(cFlags), ], @@ -103,13 +103,13 @@ func getTargets() -> [Target] { } else { let customSystemLibrary: Target = .systemLibrary( name: "CLLVM", - path: "llvm-api/CLLVM", - pkgConfig: "cllvm" + // path: "llvm-api/CLLVM", + pkgConfig: "llvm" ) let llvmTarget: Target = .target( name: "LLVM", - dependencies: ["CLLVM"], - path: "llvm-api/LLVM" + dependencies: ["CLLVM"] + // path: "llvm-api/LLVM" ) return [customSystemLibrary, llvmTarget] } diff --git a/README.md b/README.md index 2da030b..237f924 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,12 @@ brew install llvm - [x] v17.0 - [x] v18.0 +### XCode support + +To develop correctly with XCode it's necessary to generate package-config: `llvm.pc`: +- `sh utils/llvm-pkg.swift` - will generate package config and copy to your default `pkg-config` path. + +After that XCode should correctly recognize LLVM headers path, and can build project. ### Troubleshooting @@ -108,6 +114,9 @@ llc --version brew info llvm ``` +- **conditional build**: `Package.swift` supports conditional builds: + - for CLI build: `CLI_BUILD swift build` - it get's LLVM veriabels form Environment sets. + - `swift build` - if presented `llvm.pc` package config - To get more insights take a look current project [Github CI config](.github/workflows/swift.yaml). ### LICENS: [MIT](LICENSE) diff --git a/Source/CLLVM/bridge.h b/Source/CLLVM/bridge.h new file mode 100644 index 0000000..d540bad --- /dev/null +++ b/Source/CLLVM/bridge.h @@ -0,0 +1,39 @@ +// +// bridge.h +// llvm-codegen +// +// Created by Evgeny Ukhanov on 22/12/2023. +// + +#ifndef bridge_h +#define bridge_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* bridge_h */ diff --git a/Source/CLLVM/module.modulemap b/Source/CLLVM/module.modulemap new file mode 100644 index 0000000..b197055 --- /dev/null +++ b/Source/CLLVM/module.modulemap @@ -0,0 +1,11 @@ +// +// module.modulemap +// llvm-codegen +// +// Created by Evgeny Ukhanov on 22/12/2023. +// + +module CLLVM [system] { + header "bridge.h" + export * +} diff --git a/Source/LLVM/Core/AddressSpace.swift b/Source/LLVM/Core/AddressSpace.swift new file mode 100644 index 0000000..8c3ccf7 --- /dev/null +++ b/Source/LLVM/Core/AddressSpace.swift @@ -0,0 +1,64 @@ +import CLLVM + +/// An address space is an identifier for a target-specific range of address values. An address space is a +/// fundamental part of the type of a pointer value and the type of operations that manipulate memory. +/// +/// LLVM affords a default address space (numbered zero) and places a number of assumptions on pointer +/// values within that address space: +/// - The pointer must have a fixed integral value +/// - The null pointer has a bit-value of 0 +/// +/// These assumptions are not guaranteed to hold in any other address space. In particular, a target may +/// allow pointers in non-default address spaces to have *non-integral* types. Non-integral pointer types +/// represent pointers that have an unspecified bitwise representation; that is, the integral representation may +/// be target dependent or have an unstable value. Further, outside of the default address space, it is not +/// always the case that the `null` pointer value, especially as returned by +/// `constPointerNull()` has a bit value of 0. e.g. A non-default address space may use +/// an offset-based or segment-based addressing mode in which 0 is a valid, addressable pointer value. +/// +/// Target-Level Address Space Overrides +/// ==================================== +/// +/// A target may choose to override the default address space for code, data, and local allocations through the +/// data layout string. This has multiple uses. For example, the address space of an `alloca` is *only* +/// configurable via the data layout string, because it is a target-dependent property. There are also +/// use-cases for overriding language standards e.g. the C standard requires the address-of operator applied +/// to values on the stack to result in a pointer in the default address space. However, many OpenCL-based +/// targets consider the stack to be a private region, and place such pointers in a non-default address space. +/// +/// Care must be taken when interacting with these non-standard targets. The IR printer currently does not +/// print anything when the default address space is attached to an instruction or value, and values will still +/// report being assigned to that space. However, these values are still subject to the backend's interpretation +/// of the data layout string overrides and as such may not always reside in the default address space when +/// it comes time to codegen them. +/// +/// Restrictions +/// ============ +/// +/// There are currently a number of artificial restrictions on values and operations that have non-default +/// address spaces: +/// - A `bitcast` between two pointer values residing in different address spaces, even if those two +/// values have the same size, is always an illegal operation. Use an `addrspacecast` instead or +/// always use `buildPointerCast()` to get the correct operation. +/// - The so-called "null pointer" has a bit value that may differ from address space to address space. This +/// exposes bugs in optimizer passes and lowerings that did not consider this possibility. +/// - A pointer value may not necessarily "round-trip" when converted between address spaces, even if +/// annotated `nonnull` and `dereferenceable`. This is especially true of non-integral pointer types. +/// - Though the zero address space is the default, many backends and some errant passes interpret this to +/// mean a "lack of address space" and may miscompile code with pointers in mixed address spaces. +/// - A number of intriniscs that operate on memory currently do not support a non-default address space. +/// - The address space is ultimately an integer value and in theory an address space identifier may take on +/// any value. In practice, LLVM guarantees only 24 bits of precision, though higher address space +/// identifiers may succeed in being properly represented. +public struct AddressSpace: Equatable { + let rawValue: UInt32 + + /// LLVM's default address space. + public static let zero = AddressSpace(0) + + /// Creates and initializes an address space with the given identifier. + /// - Parameter identifier: The raw, integral address space identifier. + public init(_ identifier: UInt32) { + rawValue = identifier + } +} diff --git a/Source/LLVM/Core/BasicBlock.swift b/Source/LLVM/Core/BasicBlock.swift new file mode 100644 index 0000000..9bac86a --- /dev/null +++ b/Source/LLVM/Core/BasicBlock.swift @@ -0,0 +1,371 @@ +import CLLVM + +/// A `BasicBlock` represents a basic block in an LLVM IR program. A basic +/// block contains a sequence of instructions, a pointer to its parent block and +/// its follower block, and an optional label that gives the basic block an +/// entry in the symbol table. Because of this label, the type of every basic +/// block is `LabelType`. +/// +/// A basic block can be thought of as a sequence of instructions, and indeed +/// its member instructions may be iterated over with a `for-in` loop. A well- +/// formed basic block has as its last instruction a "terminator" that produces +/// a transfer of control flow and possibly yields a value. All other +/// instructions in the middle of the basic block may not be "terminator" +/// instructions. Basic blocks are not required to be well-formed until +/// code generation is complete. +/// +/// Creating a Basic Block +/// ====================== +/// +/// By default, the initializer for a basic block merely creates the block but +/// does not associate it with a function. +/// +/// let module = Module(name: "Example") +/// let func = builder.addFunction("example", +/// type: FunctionType([], VoidType())) +/// +/// // This basic block is "floating" outside of a function. +/// let floatingBB = BasicBlock(name: "floating") +/// // Until we associate it with a function by calling `Function.append(_:)`. +/// func.append(floatingBB) +/// +/// A basic block may be created and automatically inserted at the end of a +/// function by calling `Function.appendBasicBlock()`. +/// +/// let module = Module(name: "Example") +/// let func = builder.addFunction("example", +/// type: FunctionType([], VoidType())) +/// +/// // This basic block is "attached" to the example function. +/// let attachedBB = func.appendBasicBlock(named: "attached") +/// +/// The Address of a Basic Block +/// ============================ +/// +/// Basic blocks (except the entry block) may have their labels appear in the +/// symbol table. Naturally, these labels are associated with address values +/// in the final object file. The value of that address may be accessed for the +/// purpose of an indirect call or a direct comparisson by calling +/// `Function.address(of:)` and providing one of the function's child blocks as +/// an argument. Providing any other basic block outside of the function as an +/// argument value is undefined. +/// +/// The Entry Block +/// =============== +/// +/// The first basic block (the entry block) in a `Function` is special: +/// +/// - The entry block is immediately executed when the flow of control enters +/// its parent function. +/// - The entry block is not allowed to have predecessor basic blocks +/// (i.e. there cannot be any branches to the entry block of a function). +/// - The address of the entry block is not a well-defined value. +/// - The entry block cannot have PHI nodes. This is enforced structurally, +/// as the entry block can have no predecessor blocks to serve as operands +/// to the PHI node. +/// - Static `alloca` instructions situated in the entry block are treated +/// specially by most LLVM backends. For example, FastISel keeps track of +/// static `alloca` values in the entry block to more efficiently reference +/// them from the base pointer of the stack frame. +public struct BasicBlock: BasicBlockRef { + private let llvm: LLVMBasicBlockRef + + /// `BasicBlock` context + public let context: Context? + + /// Retrieves the underlying LLVM value object. + public var basicBlockRef: LLVMBasicBlockRef { llvm } + + /// Creates a `BasicBlock` from an `BasicBlockRef` object. + public init(basicBlockRef: BasicBlockRef) { + llvm = basicBlockRef.basicBlockRef + context = nil + } + + /// Init by LLVM ref + private init(llvm: LLVMBasicBlockRef) { + self.llvm = llvm + context = nil + } + + /// Create a new basic block in Context without inserting it into a function. + /// + /// The basic block should be inserted into a function or destroyed before + /// the builder is finalized. + public init(context: Context, name: String) { + llvm = LLVMCreateBasicBlockInContext(context.contextRef, name) + self.context = context + } + + /// Create a new basic block without inserting it into a function. + public static func createBasicBlockInContext(context: Context, name: String) -> BasicBlockRef? { + guard let blockRef = LLVMCreateBasicBlockInContext(context.contextRef, name) else { return nil } + return BasicBlock(llvm: blockRef) + } + + /// Given that this block and a given block share a parent function, move this + /// block before the given block in that function's basic block list. + /// + /// - Parameter position: The basic block that acts as a position before + /// which this block will be moved. + public func moveBasicBlockBefore(position: BasicBlockRef) { + Self.moveBasicBlockBefore(basicBlock: self, position: position) + } + + /// Given that this block and a given block share a parent function, move this + /// block before the given block in that function's basic block list. + public static func moveBasicBlockBefore(basicBlock: BasicBlockRef, position: BasicBlockRef) { + LLVMMoveBasicBlockBefore(basicBlock.basicBlockRef, position.basicBlockRef) + } + + /// Given that this block and a given block share a parent function, move this + /// block after the given block in that function's basic block list. + /// + /// - Parameter position: The basic block that acts as a position after + /// which this block will be moved. + public func moveBasicBlockAfter(position: BasicBlockRef) { + Self.moveBasicBlockAfter(basicBlock: self, position: position) + } + + /// Given that this block and a given block share a parent function, move this + /// block after the given block in that function's basic block list. + public static func moveBasicBlockAfter(basicBlock: BasicBlockRef, position: BasicBlockRef) { + LLVMMoveBasicBlockAfter(basicBlock.basicBlockRef, position.basicBlockRef) + } + + /// Retrieves the name of this basic block. + public var getBasicBlockName: String { + Self.getBasicBlockName(basicBlock: self) + } + + /// Retrieves the name of this basic block. + public static func getBasicBlockName(basicBlock: BasicBlockRef) -> String { + guard let cString = LLVMGetBasicBlockName(basicBlock.basicBlockRef) else { return "" } + return String(cString: cString) + } + + /// Returns the first instruction in the basic block, if it exists. + public var getFirstInstruction: ValueRef? { + Self.getFirstInstruction(basicBlock: self) + } + + /// Returns the first instruction in the basic block, if it exists. + public static func getFirstInstruction(basicBlock: BasicBlockRef) -> ValueRef? { + guard let val = LLVMGetFirstInstruction(basicBlock.basicBlockRef) else { return nil } + return Value(llvm: val) + } + + /// Returns the first instruction in the basic block, if it exists. + public var getLastInstruction: ValueRef? { + Self.getLastInstruction(basicBlock: self) + } + + /// Returns the first instruction in the basic block, if it exists. + public static func getLastInstruction(basicBlock: BasicBlockRef) -> ValueRef? { + guard let val = LLVMGetLastInstruction(basicBlock.basicBlockRef) else { return nil } + return Value(llvm: val) + } + + /// Returns the parent function of this basic block, if it exists. + public var getBasicBlockParent: Function? { + Self.getBasicBlockParent(basicBlock: self) + } + + /// Returns the parent function of this basic block, if it exists. + public static func getBasicBlockParent(basicBlock: BasicBlockRef) -> Function? { + guard let functionRef = LLVMGetBasicBlockParent(basicBlock.basicBlockRef) else { return nil } + return Function(llvm: functionRef) + } + + /// Returns the basic block following this basic block, if it exists. + public var getNextBasicBlock: BasicBlockRef? { + Self.getNextBasicBlock(basicBlock: self) + } + + /// Returns the basic block following this basic block, if it exists. + public static func getNextBasicBlock(basicBlock: BasicBlockRef) -> BasicBlockRef? { + guard let blockRef = LLVMGetNextBasicBlock(basicBlock.basicBlockRef) else { return nil } + return BasicBlock(llvm: blockRef) + } + + /// Returns the basic block before this basic block, if it exists. + public var getPreviousBasicBlock: BasicBlock? { + Self.getPreviousBasicBlock(basicBlock: self) + } + + /// Returns the basic block before this basic block, if it exists. + public static func getPreviousBasicBlock(basicBlock: BasicBlockRef) -> BasicBlock? { + guard let blockRef = LLVMGetPreviousBasicBlock(basicBlock.basicBlockRef) else { return nil } + return BasicBlock(llvm: blockRef) + } + + /// Removes this basic block from a function but keeps it alive. + public func removeBasicBlockFromParent() { + Self.removeBasicBlockFromParent(basicBlock: self) + } + + /// Removes this basic block from a function but keeps it alive. + /// + /// - note: To ensure correct removal of the block, you must invalidate any + /// references to it and its child instructions. The block must also + /// have no successor blocks that make reference to it. + public static func removeBasicBlockFromParent(basicBlock: BasicBlockRef) { + LLVMRemoveBasicBlockFromParent(basicBlock.basicBlockRef) + } + + /// Moves this basic block before the given basic block. + public func moveBasicBlockBefore(block: BasicBlockRef) { + Self.moveBasicBlockBefore(basicBlock: self, block: block) + } + + /// Moves this basic block before the given basic block. + public static func moveBasicBlockBefore(basicBlock: BasicBlockRef, block: BasicBlockRef) { + LLVMMoveBasicBlockBefore(basicBlock.basicBlockRef, block.basicBlockRef) + } + + /// Moves this basic block after the given basic block. + public func moveBasicBlockAfter(block: BasicBlockRef) { + Self.moveBasicBlockAfter(basicBlock: self, block: block) + } + + /// Moves this basic block after the given basic block. + public static func moveBasicBlockAfter(basicBlock: BasicBlockRef, block: BasicBlockRef) { + LLVMMoveBasicBlockAfter(basicBlock.basicBlockRef, block.basicBlockRef) + } + + /// Remove a basic block from a function and delete it. + /// This deletes the basic block from its containing function and deletes + /// the basic block itself. + public func deleteBasicBlock() { + Self.deleteBasicBlock(basicBlockRef: self) + } + + /// Remove a basic block from a function and delete it. + /// This deletes the basic block from its containing function and deletes + /// the basic block itself. + public static func deleteBasicBlock(basicBlockRef: BasicBlockRef) { + LLVMDeleteBasicBlock(basicBlockRef.basicBlockRef) + } + + /// Convert a basic block instance to a value type. + public var basicBlockAsValue: ValueRef? { + Self.basicBlockAsValue(basicBlockRef: self) + } + + /// Convert a basic block instance to a value type. + public static func basicBlockAsValue(basicBlockRef: BasicBlockRef) -> ValueRef? { + guard let valueRef = LLVMBasicBlockAsValue(basicBlockRef.basicBlockRef) else { return nil } + return Value(llvm: valueRef) + } + + /// Determine whether an LLVMValueRef is itself a basic block. + public static func valueIsBasicBlock(valueRef: ValueRef) -> Bool { + LLVMValueIsBasicBlock(valueRef.valueRef) != 0 + } + + /// Convert an `LLVMValueRef` to an `LLVMBasicBlockRef` instance. + public static func valueAsBasicBlock(valueRef: ValueRef) -> BasicBlockRef { + Self(llvm: LLVMValueAsBasicBlock(valueRef.valueRef)) + } + + /// Obtain the number of basic blocks in a function. + /// For specified `functionValueRef` + public static func countBasicBlocks(funcValueRef: ValueRef) -> UInt32 { + LLVMCountBasicBlocks(funcValueRef.valueRef) + } + + /// Obtain all of the basic blocks in a function. + /// Return array of BasicBlockRef instances. + public static func getBasicBlocks(funcValueRef: ValueRef) -> [BasicBlockRef] { + let blockCount = Self.countBasicBlocks(funcValueRef: funcValueRef) + var basicBlocks = [LLVMBasicBlockRef?](repeating: nil, count: Int(blockCount)) + basicBlocks.withUnsafeMutableBufferPointer { bufferPointer in + LLVMGetBasicBlocks(funcValueRef.valueRef, bufferPointer.baseAddress) + } + return basicBlocks.map { Self(llvm: $0!) } + } + + /// Obtain the first basic block in a function. + /// + /// The first basic block in a function is special in two ways: it is + /// immediately executed on entrance to the function, and it is not allowed to + /// have predecessor basic blocks (i.e. there can not be any branches to the + /// entry block of a function). Because the block can have no predecessors, it + /// also cannot have any PHI nodes. + public static func getFirstBasicBlock(funcValueRef: ValueRef) -> BasicBlockRef? { + guard let blockRef = LLVMGetFirstBasicBlock(funcValueRef.valueRef) else { return nil } + return Self(llvm: blockRef) + } + + /// Obtain the last basic block in a function. + public static func getLastBasicBlock(funcValueRef: ValueRef) -> BasicBlockRef? { + guard let blockRef = LLVMGetLastBasicBlock(funcValueRef.valueRef) else { return nil } + return Self(llvm: blockRef) + } + + /// Obtain the basic block that corresponds to the entry point of a function. + public static func getEntryBasicBlock(funcValueRef: ValueRef) -> BasicBlockRef? { + guard let blockRef = LLVMGetEntryBasicBlock(funcValueRef.valueRef) else { return nil } + return Self(llvm: blockRef) + } + + /// Insert the given basic block after the insertion point of the given builder. + /// The insertion point must be valid. + /// - note: for example for builder before call make sure use `LLVMPositionBuilderAtEnd` or similar fucntion. + public static func insertExistingBasicBlockAfterInsertBlock(builderRef: BuilderRef, blockRef: BasicBlockRef) { + LLVMInsertExistingBasicBlockAfterInsertBlock(builderRef.builderRef, blockRef.basicBlockRef) + } + + /// Append the given basic block to the basic block list of the given function. + public static func appendExistingBasicBlock(funcValueRef: ValueRef, blockRef: BasicBlockRef) { + LLVMAppendExistingBasicBlock(funcValueRef.valueRef, blockRef.basicBlockRef) + } + + /// Append named basic block to the end of a function in Context. + /// Return BasicBlock + public static func appendBasicBlockInContext(contextRef: ContextRef, funcValueRef: ValueRef, blockName: String) -> BasicBlockRef { + Self(llvm: LLVMAppendBasicBlockInContext(contextRef.contextRef, funcValueRef.valueRef, blockName)) + } + + /// Append named basic block to the end of a function using the global context. + /// Return BasicBlock + public static func appendBasicBlock(funcValueRef: ValueRef, blockName: String) -> BasicBlockRef { + Self(llvm: LLVMAppendBasicBlock(funcValueRef.valueRef, blockName)) + } + + /// Insert named basic block in a function before another basic block in Context. + /// - parameter context: context of insertion + /// - parameter before: before BasicBlock + /// - parameter name: name of block + /// Return BasicBlock + public static func insertBasicBlockInContext(contextRef: ContextRef, before: BasicBlockRef, blockName: String) -> BasicBlockRef { + Self(llvm: LLVMInsertBasicBlockInContext(contextRef.contextRef, before.basicBlockRef, blockName)) + } + + /// Insert named basic block in a function using the global context. + /// - parameter before: before BasicBlock + /// - parameter name: name of block + /// Return BasicBlock + public static func insertBasicBlock(before: BasicBlockRef, blockName: String) -> BasicBlockRef { + Self(llvm: LLVMInsertBasicBlock(before.basicBlockRef, blockName)) + } + + /// Returns the terminator instruction for current block. If a basic block is well formed or `nil` if it is not well formed. + public var getBasicBlockTerminator: ValueRef? { + guard let valueRef = LLVMGetBasicBlockTerminator(llvm) else { return nil } + return Value(llvm: valueRef) + } + + /// Returns the terminator instruction if a basic block is well formed or `nil` if it is not well formed. + /// The returned LLVMValueRef corresponds to an llvm::Instruction. + public static func getBasicBlockTerminator(basicBlockRef: BasicBlockRef) -> ValueRef? { + guard let valueRef = LLVMGetBasicBlockTerminator(basicBlockRef.basicBlockRef) else { return nil } + return Value(llvm: valueRef) + } +} + +extension BasicBlock: Equatable { + public static func == (lhs: BasicBlock, rhs: BasicBlock) -> Bool { + lhs.basicBlockRef == rhs.basicBlockRef + } +} diff --git a/Source/LLVM/Core/Context.swift b/Source/LLVM/Core/Context.swift new file mode 100644 index 0000000..2468a7f --- /dev/null +++ b/Source/LLVM/Core/Context.swift @@ -0,0 +1,240 @@ +import CLLVM + +/// A `Context` is an LLVM compilation session environment. +/// - SeeAlso: https://llvm.org/docs/ProgrammersManual.html#achieving-isolation-with-llvmcontext +/// +/// A `Context` is a container for the global state of an execution of the +/// LLVM environment and tooling. It contains independent copies of global and +/// module-level entities like types, metadata attachments, and constants. +/// +/// An LLVM context is needed for interacting with LLVM in a concurrent +/// environment. Because a context maintains state independent of any other +/// context, it is recommended that each thread of execution be assigned a unique +/// context. LLVM's core infrastructure and API provides no locking guarantees +/// and no atomicity guarantees. +public final class Context: ContextRef { + private let llvm: LLVMContextRef + + /// Retrieves the underlying LLVM type object. + public var contextRef: LLVMContextRef { llvm } + + /// Diagnostic handler type + public typealias DiagnosticHandler = @convention(c) (LLVMDiagnosticInfoRef?, UnsafeMutableRawPointer?) -> Void + + public typealias YieldCallback = @convention(c) (LLVMContextRef?, UnsafeMutableRawPointer?) -> Void + + /// Retrieves the global context instance. + /// + /// The global context is an particularly convenient instance managed by LLVM + /// itself. It is the default context provided for any operations that + /// require it. + /// + /// - WARNING: Failure to specify the correct context in concurrent + /// environments can lead to data corruption. In general, it is always + /// recommended that each thread of execution attempting to access the LLVM + /// API have its own `Context` instance, rather than rely on this global + /// context. + public static let global = Context(llvm: LLVMGetGlobalContext()!) + + /// Creates a new `Context` object. + public init() { + llvm = LLVMContextCreate() + } + + /// Creates a `Context` object from an `LLVMContextRef` object. + public init(llvm: LLVMContextRef) { + self.llvm = llvm + } + + /// Get the diagnostic handler of current context. + public var getDiagnosticHandler: DiagnosticHandler? { + LLVMContextGetDiagnosticHandler(llvm) + } + + /// Set the diagnostic handler for current context. + public func setDiagnosticHandler(handler: DiagnosticHandler?, diagnosticContext: UnsafeMutableRawPointer?) { + LLVMContextSetDiagnosticHandler(llvm, handler.self, diagnosticContext) + } + + /// Retrieve whether the given context is set to discard all value names. + public func shouldDiscardValueNames() -> Bool { + LLVMContextShouldDiscardValueNames(llvm) != 0 + } + + /// Set whether the given context discards all value names. + /// If true, only the names of GlobalValue objects will be available in the IR. + /// This can be used to save memory and runtime, especially in release mode. + public func setDiscardValueNames(discard: Bool) { + LLVMContextSetDiscardValueNames(llvm, discard.llvm) + } + + /// Returns whether the given context is set to discard all value names. + /// + /// If true, only the names of GlobalValue objects will be available in + /// the IR. This can be used to save memory and processing time, especially + /// in release environments. + public var discardValueNames: Bool { + get { + // Retrieve whether the given context is set to discard all value names. + shouldDiscardValueNames() + } + set { + // Set whether the given context discards all value names. + setDiscardValueNames(discard: newValue) + } + } + + /// Get the diagnostic context of this context. + public func getDiagnosticContext() -> UnsafeMutableRawPointer { + LLVMContextGetDiagnosticContext(llvm) + } + + /// Set the yield callback function for this context. + public func setYieldCallback(callback: YieldCallback?, opaqueHandle: UnsafeMutableRawPointer?) { + LLVMContextSetYieldCallback(llvm, callback, opaqueHandle) + } + + /// Return a string representation of the DiagnosticInfo. Use + /// `Core.disposeMessage` (`LLVMDisposeMessage`) to free the string. + public static func getDiagInfoDescription(diagnosticInfo: DiagnosticInfoRef) -> String? { + guard let cString = LLVMGetDiagInfoDescription(diagnosticInfo.diagnosticInfoRef) else { return nil } + defer { Core.disposeMessage(cString) } + return String(cString: cString) + } + + /// Return an enum LLVMDiagnosticSeverity. + public static func getDiagInfoSeverity(diagnosticInfo: DiagnosticInfoRef) -> DiagnosticSeverity? { + DiagnosticSeverity(from: LLVMGetDiagInfoSeverity(diagnosticInfo.diagnosticInfoRef)) + } + + /// Get Metadata KindId by name in current Context. + /// Useful for working with Metadata + public func getMDKindIDInContext(name: String) -> UInt32 { + name.withCString { cString in + LLVMGetMDKindIDInContext(llvm, cString, UInt32(name.utf8.count)) + } + } + + public static func getMDKindID(name: String) -> UInt32 { + name.withCString { cString in + LLVMGetMDKindID(cString, UInt32(name.utf8.count)) + } + } + + /// Return an unique id given the name of a enum attribute, + /// or 0 if no attribute by that name exists. + /// + /// See http://llvm.org/docs/LangRef.html#parameter-attributes + /// and http://llvm.org/docs/LangRef.html#function-attributes + /// for the list of available attributes. + /// + /// NB: Attribute names and/or id are subject to change without + /// going through the C API deprecation cycle. + public static func getEnumAttributeKindForName(name: String) -> UInt32 { + name.withCString { cString in + LLVMGetEnumAttributeKindForName(cString, name.utf8.count) + } + } + + /// Get last enum attribute + public static func getLastEnumAttributeKind() -> UInt32 { + LLVMGetLastEnumAttributeKind() + } + + struct Attribute: AttributeRef { + var attributeRef: LLVMAttributeRef + } + + /// Create an enum attribute. + public func createEnumAttribute(kindID: UInt32, value: UInt64) -> AttributeRef? { + guard let attributeRef = LLVMCreateEnumAttribute(llvm, kindID, value) else { return nil } + return Attribute(attributeRef: attributeRef) + } + + /// Get the unique id corresponding to the enum attribute passed as argument. + public static func getEnumAttributeKind(attributeRef: AttributeRef) -> UInt32 { + LLVMGetEnumAttributeKind(attributeRef.attributeRef) + } + + /// Get the enum attribute's value. 0 is returned if none exists. + public static func getEnumAttributeValue(attributeRef: AttributeRef) -> UInt64 { + LLVMGetEnumAttributeValue(attributeRef.attributeRef) + } + + /// Create a type attribute + public func createTypeAttribute(kindID: UInt32, typeRef: TypeRef) -> AttributeRef? { + guard let attributeRef = LLVMCreateTypeAttribute(llvm, kindID, typeRef.typeRef) else { return nil } + return Attribute(attributeRef: attributeRef) + } + + /// Get the type attribute's value. + public static func getTypeAttributeValue(attributeRef: AttributeRef) -> TypeRef? { + guard let typeRef = LLVMGetTypeAttributeValue(attributeRef.attributeRef) else { return nil } + return Types(llvm: typeRef) + } + + /// Create a string attribute. + public func createStringAttribute(key: String, value: String) -> AttributeRef? { + let attribute = key.withCString { keyCString in + value.withCString { valueCString in + LLVMCreateStringAttribute(llvm, keyCString, UInt32(key.utf8.count), valueCString, UInt32(value.utf8.count)) + } + } + guard let attributeRef = attribute else { return nil } + return Attribute(attributeRef: attributeRef) + } + + /// Get the string attribute's kind. + public static func getStringAttributeKind(attributeRef: AttributeRef) -> String? { + var length: UInt32 = 0 + guard let cString = LLVMGetStringAttributeKind(attributeRef.attributeRef, &length) else { return nil } + return String(cString: cString) + } + + /// Get the string attribute's value. + public static func getStringAttributeValue(attributeRef: AttributeRef) -> String? { + var length: UInt32 = 0 + guard let cString = + LLVMGetStringAttributeValue(attributeRef.attributeRef, &length) else { return nil } + return String(cString: cString) + } + + /// Check for the types of attributes. + public static func isEnumAttribute(attributeRef: AttributeRef) -> Bool { + LLVMIsEnumAttribute(attributeRef.attributeRef) != 0 + } + + /// Check for the types of attributes. + public static func isStringAttribute(attributeRef: AttributeRef) -> Bool { + LLVMIsStringAttribute(attributeRef.attributeRef) != 0 + } + + /// Check for the types of attributes. + public static func isTypeAttribute(attributeRef: AttributeRef) -> Bool { + LLVMIsTypeAttribute(attributeRef.attributeRef) != 0 + } + + /// Obtain a Type from a context by its registered name. + public func getTypeByName2(name: String) -> TypeRef? { + name.withCString { cString in + guard let typeRef = LLVMGetTypeByName2(llvm, cString) else { return nil } + return Types(llvm: typeRef) + } + } + + ///Destroy a context instance. + /// + /// This should be called for every call to LLVMContextCreate() or memory will be leaked. + public func dispose() { + LLVMContextDispose(llvm) + } + + /// Deinitialize this value and dispose of its resources. + /// + /// Destroy a context instance. + /// This should be called for every call to LLVMContextCreate() or memory + /// will be leaked. + deinit { + self.dispose() + } +} diff --git a/Source/LLVM/Core/Core.swift b/Source/LLVM/Core/Core.swift new file mode 100644 index 0000000..3e0bd83 --- /dev/null +++ b/Source/LLVM/Core/Core.swift @@ -0,0 +1,82 @@ +import CLLVM + +/// This modules provide an interface to libLLVMCore, which implements the LLVM intermediate representation as well +/// as other related types and utilities. +/// +/// Many exotic languages can interoperate with C code but have a harder time with C++ due to name mangling. So in addition to C, +/// this interface enables tools written in such languages. +/// - SeeAlso: https://llvm.org/doxygen/group__LLVMCCore.html +enum Core { + /// Return the major, minor, and patch version of LLVM + /// The version components are returned via the function's three output + /// parameters or skipped if a NULL pointer was supplied - return 0. + public static func getVersion() -> (major: UInt32, minor: UInt32, patch: UInt32) { + var major: UInt32 = 0 + var minor: UInt32 = 0 + var patch: UInt32 = 0 + + withUnsafeMutablePointer(to: &major) { majorPtr in + withUnsafeMutablePointer(to: &minor) { minorPtr in + withUnsafeMutablePointer(to: &patch) { patchPtr in + LLVMGetVersion(majorPtr, minorPtr, patchPtr) + } + } + } + return (major, minor, patch) + } + + /// Create message string reference. Run [disposeMessage] to free message. + /// It useful when LLVM wait as parameter LLVM-string + /// + /// - SeeAlso: `disposeLLVMMessage` + public static func createMessage(with message: String) -> UnsafeMutablePointer? { + message.withCString { cString in + LLVMCreateMessage(cString) + } + } + + /// Dispose LLVM message + public static func disposeMessage(_ message: UnsafeMutablePointer?) { + LLVMDisposeMessage(message) + } + + /// This function permanently loads the dynamic library at the given path. + /// It is safe to call this function multiple times for the same library. + public static func loadLibraryPermanently(filename: String) -> Bool { + filename.withCString { cString in + LLVMLoadLibraryPermanently(cString) != 0 + } + } + + /// This function parses the given arguments using the LLVM command line parser. + /// Note that the only stable thing about this function is its signature; you + /// cannot rely on any particular set of command line arguments being interpreted + /// the same way across LLVM versions. + public static func parseCommandLineOptions(arguments: [String], overview: String) { + let cArgs = arguments.map { $0.withCString(strdup) } + defer { cArgs.forEach { free($0) } } + overview.withCString { cOverview in + let cArgsPointers = cArgs.map { UnsafePointer($0) } + cArgsPointers.withUnsafeBufferPointer { cArgsPointersBuffer in + LLVMParseCommandLineOptions(Int32(arguments.count), cArgsPointersBuffer.baseAddress, cOverview) + } + } + } + + /// This function will search through all previously loaded dynamic + /// libraries for the symbol `symbolName`. If it is found, the address of + /// that symbol is returned. If not, null is returned. + public static func searchForAddressOfSymbol(symbolName: String) -> UnsafeMutableRawPointer? { + symbolName.withCString { cString in + LLVMSearchForAddressOfSymbol(cString) + } + } + + /// This functions permanently adds the symbol \p symbolName with the + /// value `symbolValue`. These symbols are searched before any libraries. + public static func addSymbol(symbolName: String, symbolValue: UnsafeMutableRawPointer) { + symbolName.withCString { cString in + LLVMAddSymbol(cString, symbolValue) + } + } +} diff --git a/Source/LLVM/Core/Diagnostic.swift b/Source/LLVM/Core/Diagnostic.swift new file mode 100644 index 0000000..10d0ba8 --- /dev/null +++ b/Source/LLVM/Core/Diagnostic.swift @@ -0,0 +1,22 @@ +import CLLVM + +/// Diagnostic functionality +public struct Diagnostic: DiagnosticInfoRef { + private var llvm: LLVMDiagnosticInfoRef + public var diagnosticInfoRef: LLVMDiagnosticInfoRef { llvm } + + /// Init DIagnosticInfo + public init(llvm: LLVMDiagnosticInfoRef) { + self.llvm = llvm + } + + /// Return a string representation of the DiagnosticInfo. + public var getDiagInfoDescription: String? { + Context.getDiagInfoDescription(diagnosticInfo: self) + } + + /// Return an enum LLVMDiagnosticSeverity. + public var getDiagInfoSeverity: DiagnosticSeverity? { + Context.getDiagInfoSeverity(diagnosticInfo: self) + } +} diff --git a/Source/LLVM/Core/Functions.swift b/Source/LLVM/Core/Functions.swift new file mode 100644 index 0000000..ddf12ef --- /dev/null +++ b/Source/LLVM/Core/Functions.swift @@ -0,0 +1,135 @@ +import CLLVM + +/// A `Function` represents a named function body in LLVM IR source. Functions +/// in LLVM IR encapsulate a list of parameters and a sequence of basic blocks +/// and provide a way to append to that sequence to build out its body. +/// +/// A LLVM function definition contains a list of basic blocks, starting with +/// a privileged first block called the "entry block". After the entry blocks' +/// terminating instruction come zero or more other basic blocks. The path the +/// flow of control can potentially take, from each block to its terminator +/// and on to other blocks, forms the "Control Flow Graph" (CFG) for the +/// function. The nodes of the CFG are the basic blocks, and the edges are +/// directed from the terminator instruction of one block to any number of +/// potential target blocks. +/// +/// Additional basic blocks may be created and appended to the function at +/// any time. +/// +/// let module = Module(name: "Example") +/// let builder = Builder(module: module) +/// let fun = builder.addFunction("example", +/// type: FunctionType([], VoidType())) +/// // Create and append the entry block +/// let entryBB = fun.appendBasicBlock(named: "entry") +/// // Create and append a standalone basic block +/// let freestanding = BasicBlock(name: "freestanding") +/// fun.append(freestanding) +/// +/// An LLVM function always has the type `FunctionType`. This type is used to +/// determine the number and kind of parameters to the function as well as its +/// return value, if any. The parameter values, which would normally enter +/// the entry block, are instead attached to the function and are accessible +/// via the `parameters` property. +/// +/// Calling Convention +/// ================== +/// +/// By default, all functions in LLVM are invoked with the C calling convention +/// but the exact calling convention of both a function declaration and a +/// `call` instruction are fully configurable. +/// +/// let module = Module(name: "Example") +/// let builder = Builder(module: module) +/// let fun = builder.addFunction("example", +/// type: FunctionType([], VoidType())) +/// // Switch to swiftcc +/// fun.callingConvention = .swift +/// +/// The calling convention of a function and a corresponding call instruction +/// must match or the result is undefined. +/// +/// Sections +/// ======== +/// +/// A function may optionally state the section in the object file it +/// should reside in through the use of a metadata attachment. This can be +/// useful to satisfy target-specific data layout constraints, or to provide +/// some hints to optimizers and linkers. +/// +/// let mdBuilder = MDBuilder() +/// // __attribute__((hot)) +/// let hotAttr = mdBuilder.buildFunctionSectionPrefix(".hot") +/// +/// let module = Module(name: "Example") +/// let builder = Builder(module: module) +/// let fun = builder.addFunction("example", +/// type: FunctionType([], VoidType())) +/// // Attach the metadata +/// fun.addMetadata(hotAttr, kind: .sectionPrefix) +/// +/// For targets that support it, a function may also specify a COMDAT section. +/// +/// fun.comdat = module.comdat(named: "example") +/// +/// Debug Information +/// ================= +/// +/// A function may also carry debug information through special subprogram +/// nodes. These nodes are intended to capture the structure of the function +/// as it appears in the source so that it is available for inspection by a +/// debugger. +public struct Function: ValueRef { + private let llvm: LLVMValueRef + + /// Retrieves the underlying LLVM value object. + public var valueRef: LLVMValueRef { llvm } + + /// Init function by LLVM Value + public init(llvm: LLVMValueRef) { + self.llvm = llvm + } + + /// Get the number of basic blocks for current function + public var countBasicBlocks: UInt32 { + BasicBlock.countBasicBlocks(funcValueRef: self) + } + + /// Get all of the basic blocks in the current function. + public var getBasicBlocks: [BasicBlockRef] { + BasicBlock.getBasicBlocks(funcValueRef: self) + } + + /// Get the first basic block for current function. + public var getFirstBasicBlock: BasicBlockRef? { + BasicBlock.getFirstBasicBlock(funcValueRef: self) + } + + /// Get the last basic block for current function. + public var getLastBasicBlock: BasicBlockRef? { + BasicBlock.getLastBasicBlock(funcValueRef: self) + } + + /// Get the basic block that corresponds to the entry point of the current function. + public var getEntryBasicBlock: BasicBlockRef? { BasicBlock.getEntryBasicBlock(funcValueRef: self) } + + /// Append the given basic block to the basic block list for the current function. + public func appendExistingBasicBlock(funcValueRef _: ValueRef, blockRef: BasicBlockRef) { BasicBlock.appendExistingBasicBlock(funcValueRef: self, blockRef: blockRef) + } + + /// Append named basic block to the end of a function in Context. + /// Return BasicBlock + public func appendBasicBlockInContext(contextRef: ContextRef, blockName: String) -> BasicBlockRef { BasicBlock.appendBasicBlockInContext(contextRef: contextRef, funcValueRef: self, blockName: blockName) + } + + /// Append named basic block to the end of the current function using the global context. + /// Return BasicBlock + public func appendBasicBlock(blockName: String) -> BasicBlockRef { BasicBlock.appendBasicBlock(funcValueRef: self, blockName: blockName) + } +} + +extension Function: Equatable { + public static func == (lhs: Function, rhs: Function) -> Bool { + lhs.valueRef == rhs.valueRef + } +} diff --git a/Source/LLVM/Core/Modules.swift b/Source/LLVM/Core/Modules.swift new file mode 100644 index 0000000..3212ab8 --- /dev/null +++ b/Source/LLVM/Core/Modules.swift @@ -0,0 +1,287 @@ +import CLLVM + +/// Modules represent the top-level structure in an LLVM program. An LLVM +/// module is effectively a translation unit or a collection of +/// translation units merged together. +public final class Module: ModuleRef { + private let llvm: LLVMModuleRef + + /// Retrieves the underlying LLVM value object. + public var moduleRef: LLVMModuleRef { llvm } + + public enum InlineAsmDialect { + case att + case intel + } + + /// Named Metadata Node + public class NamedMetadataNode: NamedMetadataNodeRef { + private var llvm: LLVMNamedMDNodeRef + + /// Retrieves the underlying LLVM value object. + public var namedMetadataNodeRef: LLVMNamedMDNodeRef { llvm } + + init(llvm: LLVMNamedMDNodeRef) { + self.llvm = llvm + } + + /// Advance a `NamedMetaDataNode` iterator to the next `NamedMetaDataNode`. + /// + /// Returns NULL if the iterator was already at the end and there are no more + /// named metadata nodes. + public func getNext() -> NamedMetadataNode? { + guard let nextRef = LLVMGetNextNamedMetadata(llvm) else { + return nil + } + return NamedMetadataNode(llvm: nextRef) + } + + /// Decrement a `NamedMetaDataNode` iterator to the previous `NamedMetaDataNode`. + /// + /// Returns NULL if the iterator was already at the beginning and there are + /// no previously named metadata nodes. + public func getPrevious() -> NamedMetadataNode? { + guard let prevRef = LLVMGetPreviousNamedMetadata(llvm) else { + return nil + } + return NamedMetadataNode(llvm: prevRef) + } + + /// Retrieve the name of a `NamedMetadataNode`. + public func getName() -> String? { + var length: size_t = 0 + guard let cStr = LLVMGetNamedMetadataName(llvm, &length) else { + return nil + } + return String(cString: cStr) + } + } + + /// Enumerates the supported behaviors for resolving collisions when two + /// module flags share the same key. These collisions can occur when the + /// different flags are inserted under the same key, or when modules + /// containing flags under the same key are merged. + public enum ModuleFlagBehavior { + /// Emits an error if two values disagree, otherwise the resulting value + /// is that of the operands. + case error + /// Emits a warning if two values disagree. The result value will be the + /// operand for the flag from the first module being linked. + case warning + /// Adds a requirement that another module flag be present and have a + /// specified value after linking is performed. The value must be a + /// metadata pair, where the first element of the pair is the ID of the + /// module flag to be restricted, and the second element of the pair is + /// the value the module flag should be restricted to. This behavior can + /// be used to restrict the allowable results (via triggering of an error) + /// of linking IDs with the **Override** behavior. + case require + /// Uses the specified value, regardless of the behavior or value of the + /// other module. If both modules specify **Override**, but the values + /// differ, an error will be emitted. + case override + /// Appends the two values, which are required to be metadata nodes. + case append + /// Appends the two values, which are required to be metadata + /// nodes. However, duplicate entries in the second list are dropped + /// during the append operation. + case appendUnique + + init(raw: LLVMModuleFlagBehavior) { + switch raw { + case LLVMModuleFlagBehaviorError: + self = .error + case LLVMModuleFlagBehaviorWarning: + self = .warning + case LLVMModuleFlagBehaviorRequire: + self = .require + case LLVMModuleFlagBehaviorOverride: + self = .override + case LLVMModuleFlagBehaviorAppend: + self = .append + case LLVMModuleFlagBehaviorAppendUnique: + self = .appendUnique + default: + fatalError("Unknown behavior kind") + } + } + } + + class Metadata: MetadataRef { + private let llvm:LLVMMetadataRef + public var metadataRef: LLVMMetadataRef { + llvm } + public init(llvm: LLVMMetadataRef ) { + self.llvm = llvm + } + } + + public class ModuleFlagEntry { + private let llvm: OpaquePointer? + private let bounds: Int + + public init(llvm:OpaquePointer?, bounds: Int) { + self.llvm = llvm + self.bounds = bounds + } + + /// Get Metadata flags etries count + public var count: Int { self.bounds } + + /// Returns the flag behavior for a module flag entry at a specific index. + public func getFlagBehavior(at index: UInt32) -> ModuleFlagBehavior { + let bh = LLVMModuleFlagEntriesGetFlagBehavior(llvm, index) + return ModuleFlagBehavior(raw: bh) + } + + /// Returns the key for a module flag entry at a specific index. + public func getKey(at index: UInt32) -> String { + var length: Int = 0 + let keyPointer = LLVMModuleFlagEntriesGetKey(llvm, index, &length) + return String(cString: keyPointer!) + + } + + /// Returns the metadata for a module flag entry at a specific index. + public func getMetadata(at index: UInt32) -> MetadataRef { + let metadata = LLVMModuleFlagEntriesGetMetadata(llvm, index)! + return Metadata(llvm: metadata) + } + + /// Deinitialize this value and dispose of its resources. + deinit { + guard let ptr = llvm else { return } + LLVMDisposeModuleFlagsMetadata(ptr) + } + } + + /// Init function by LLVM Value + public init(llvm: LLVMModuleRef) { + self.llvm = llvm + } + + /// Create a new, empty module in the global context. + /// + /// This is equivalent to calling LLVMModuleCreateWithNameInContext with + /// LLVMGetGlobalContext() as the context parameter. + /// + /// Every invocation should be paired with LLVMDisposeModule() or memory will be leaked. + public init(name: String) { + llvm = name.withCString { cString in + LLVMModuleCreateWithName(cString) + } + } + + /// Create a new, empty module in a specific context. + /// + /// Every invocation should be paired with LLVMDisposeModule() or memory will be leaked. + public init(name: String, context: ContextRef) { + llvm = name.withCString { cString in + LLVMModuleCreateWithNameInContext(cString, context.contextRef) + } + } + + /// Return an exact copy of the specified module. + public func cloneModule() -> Self { + let new_module = LLVMCloneModule(llvm)! + return Self(llvm: new_module) + } + + /// Get and Set the identifier of a module. + public var moduleIdentifier: String { + get { + self.getModuleIdentifier + } + set { + self.setModuleIdentifier(identifier: newValue) + } + } + + /// Obtain the identifier of a module. + public var getModuleIdentifier: String { + var length: UInt = 0 + guard let cString = LLVMGetModuleIdentifier(llvm, &length) else { return "" } + return String(cString: cString) + } + + /// Set the identifier of a module to a string Ident with length Len. + public func setModuleIdentifier(identifier: String) { + identifier.withCString { cString in + LLVMSetModuleIdentifier(llvm, cString, identifier.count) + } + } + + /// Get and Set the original source file name of a module to a string Name + public var sourceFileName: String { + get { + self.getSourceFileName! + } + set { + self.setSourceFileName(fileName: newValue) + } + } + + ///Set the original source file name of a module to a string Name + public func setSourceFileName(fileName: String) { + fileName.withCString { cString in + LLVMSetSourceFileName(llvm, cString, fileName.utf8.count) + } + } + + /// Obtain the module's original source file name. + public var getSourceFileName: String? { + var length: Int = 0 + guard let cString = LLVMGetSourceFileName(llvm, &length) else { + return nil + } + return String(cString: cString) + } + + /// Set the data layout for a module. + public func setDataLayout(dataLayout: String) { + dataLayout.withCString { cString in + LLVMSetDataLayout(llvm, cString) + } + } + + /// Obtain the data layout for a module. + public var getDataLayout: String? { + guard let cString = LLVMGetDataLayoutStr(llvm) else { + return nil + } + return String(cString: cString) + } + + + /// Obtain the target triple for a module. + func getTargetTriple() -> String { + guard let targetTriplePointer = LLVMGetTarget(llvm) else { + return "" + } + return String(cString: targetTriplePointer) + } + + /// Set the target triple for a module. + public func setTarget(triple: String) { + triple.withCString { cString in + LLVMSetTarget(llvm, cString) + } + } + + /// Returns the module flags as an array of flag-key-value triples. The caller + /// is responsible for freeing this array by calling + /// `LLVMDisposeModuleFlagsMetadata`. + public func copyModuleFlagsMetadata() -> ModuleFlagEntry? { + var length: Int = 0 + guard let flagsPointer = LLVMCopyModuleFlagsMetadata(llvm, &length) else { return nil } + + return ModuleFlagEntry(llvm: flagsPointer, bounds: length) + } + + /// Destroy a module instance. + /// + /// This must be called for every created module or memory will be leaked. + deinit { + LLVMDisposeModule(llvm) + } +} diff --git a/Source/LLVM/Core/Types/Array.swift b/Source/LLVM/Core/Types/Array.swift new file mode 100644 index 0000000..9acaa2e --- /dev/null +++ b/Source/LLVM/Core/Types/Array.swift @@ -0,0 +1,112 @@ +import CLLVM + +/// `ArrayType` is a very simple derived type that arranges elements +/// sequentially in memory. `ArrayType` requires a size (number of elements) and +/// an underlying data type. +public struct ArrayType: TypeRef { + private var llvm: LLVMTypeRef + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// The type of elements in this array. + public let elementType: TypeRef + + /// Array counter kind + public enum ArrayCountKind { + case x32(UInt32) + case x64(UInt64) + } + + /// The number of elements in this array. + public let count: ArrayCountKind + + /// Creates an array type from an underlying element type and count. + /// Maximum size of array limited by `UInt32` + /// The created type will exist in the context that its element type exists in. + /// - note: Deprecated by `llvm-c` + @available(*, deprecated, message: "Use 64-Int size instead") + public init(elementType: TypeRef, count: UInt32) { + self.elementType = elementType + self.count = .x32(count) + llvm = LLVMArrayType(elementType.typeRef, count) + } + + /// Creates an array type from an underlying element type and count. + /// Maximum size of array limited by `UInt64` + /// The created type will exist in the context that its element type exists in. + public init(elementType: TypeRef, count: UInt64) { + self.elementType = elementType + self.count = .x64(count) + llvm = LLVMArrayType2(elementType.typeRef, count) + } + + /// Init with predefined `TypeRef` + public init(typeRef: TypeRef) { + elementType = ArrayType.getElementType(typeRef: typeRef)! + count = .x64(ArrayType.getArrayLength2(typeRef: typeRef)) + llvm = typeRef.typeRef + } + + /// Get the length of an array type for 32 bits array size. + /// This only works on types that represent arrays. + /// - note: Deprecated by `llvm-c` + @available(*, deprecated, message: "Use getArrayLength2 instead, do not use 32-bit size arrays") + public static func getArrayLength(arrayType: TypeRef) -> UInt32 { + LLVMGetArrayLength(arrayType.typeRef) + } + + /// Get the length of an array type for 64 bits array size - for current array + /// This only works on types that represent arrays. + public var getArrayLength2: UInt64 { + Self.getArrayLength2(typeRef: self) + } + + /// Get the length of an array type for 64 bits array size. + /// This only works on types that represent arrays. + public static func getArrayLength2(typeRef: TypeRef) -> UInt64 { + LLVMGetArrayLength2(typeRef.typeRef) + } + + /// Get the element type of the current array type. + public var getElementType: TypeRef? { + Self.getElementType(typeRef: self) + } + + /// Get the element type of an array type. + public static func getElementType(typeRef: TypeRef) -> TypeRef? { + guard let newTypeRef = LLVMGetElementType(typeRef.typeRef) else { return nil } + return Types(llvm: newTypeRef) + } + + /// Return the number of types in the derived type for the current array. + public var getNumContainedTypes: UInt32 { + Self.getNumContainedTypes(typeRef: self) + } + + /// Return the number of types in the derived type. + public static func getNumContainedTypes(typeRef: TypeRef) -> UInt32 { + LLVMGetNumContainedTypes(typeRef.typeRef) + } + + /// Returns type's subtypes for the current array + public var getSubtypes: [TypeRef] { + Self.getSubtypes(typeRef: self) + } + + /// Returns type's subtypes + public static func getSubtypes(typeRef: TypeRef) -> [TypeRef] { + let subtypeCount = ArrayType.getNumContainedTypes(typeRef: typeRef) + var subtypes = [LLVMTypeRef?](repeating: nil, count: Int(subtypeCount)) + subtypes.withUnsafeMutableBufferPointer { bufferPointer in + LLVMGetSubtypes(typeRef.typeRef, bufferPointer.baseAddress) + } + return subtypes.map { Types(llvm: $0!) } + } +} + +extension ArrayType: Equatable { + public static func == (lhs: ArrayType, rhs: ArrayType) -> Bool { + lhs.typeRef == rhs.typeRef + } +} diff --git a/Source/LLVM/Core/Types/Float.swift b/Source/LLVM/Core/Types/Float.swift new file mode 100644 index 0000000..c39cfd1 --- /dev/null +++ b/Source/LLVM/Core/Types/Float.swift @@ -0,0 +1,157 @@ +import CLLVM + +/// `FloatingType` representations of a floating value of a particular +/// bit width and semantics. +public class FloatingType: TypeRef { + var llvm: LLVMTypeRef + + /// Returns the context associated with this type. + public let context: Context? + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// For parent classes init with predefined `FloatType` in global context + init(typeRef: LLVMTypeRef) { + llvm = typeRef + context = nil + } + + /// For parent classes init with predefined `FloatType` in Context + init(typeRef: LLVMTypeRef, context: Context) { + llvm = typeRef + self.context = context + } +} + +/// 16-bit floating point type +public class HalfType: FloatingType { + /// Creates an instance of the `HalfType` type in the global context. + public init() { + super.init(typeRef: LLVMHalfType()) + } + + /// Creates an instance of the `HalfType` type in the Context. + public init(in context: Context) { + super.init(typeRef: LLVMHalfTypeInContext(context.contextRef)) + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + super.init(typeRef: typeRef.typeRef, context: context) + } +} + +/// 16-bit brain floating point type +public class BFloatType: FloatingType { + /// Creates an instance of the `BFloatType` type in the global context. + public init() { + super.init(typeRef: LLVMBFloatType()) + } + + /// Creates an instance of the `BFloatType` type in the Context. + public init(in context: Context) { + super.init(typeRef: LLVMBFloatTypeInContext(context.contextRef)) + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + super.init(typeRef: typeRef.typeRef, context: context) + } +} + +/// 32-bit floating point type +public class FloatType: FloatingType { + /// Creates an instance of the `FloatType` type in the global context. + public init() { + super.init(typeRef: LLVMFloatType()) + } + + /// Creates an instance of the `FloatType` type in the Context. + public init(in context: Context) { + super.init(typeRef: LLVMFloatTypeInContext(context.contextRef)) + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + super.init(typeRef: typeRef.typeRef, context: context) + } +} + +/// 64-bit floating point type +public class DoubleType: FloatingType { + /// Creates an instance of the `DoubleType` type in the global context. + public init() { + super.init(typeRef: LLVMDoubleType()) + } + + /// Creates an instance of the `DoubleType` type in the Context. + public init(in context: Context) { + super.init(typeRef: LLVMDoubleTypeInContext(context.contextRef)) + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + super.init(typeRef: typeRef.typeRef, context: context) + } +} + +/// 80-bit floating point (X87) type +public class X86FP80Type: FloatingType { + /// Creates an instance of the `x86FP80Type` type in the global context. + public init() { + super.init(typeRef: LLVMX86FP80Type()) + } + + /// Creates an instance of the `x86FP80Type` type in the Context. + public init(in context: Context) { + super.init(typeRef: LLVMX86FP80TypeInContext(context.contextRef)) + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + super.init(typeRef: typeRef.typeRef, context: context) + } +} + +/// 128-bit floating point (112-bit mantissa) type +public class FP128Type: FloatingType { + /// Creates an instance of the `FP128Type` type in the global context. + public init() { + super.init(typeRef: LLVMFP128Type()) + } + + /// Creates an instance of the `FP128Type` type in the Context. + public init(in context: Context) { + super.init(typeRef: LLVMFP128TypeInContext(context.contextRef)) + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + super.init(typeRef: typeRef.typeRef, context: context) + } +} + +/// 128-bit floating point (two 64-bits) type +public class PPCFP128Type: FloatingType { + /// Creates an instance of the `PPCFP128Type` type in the global context. + public init() { + super.init(typeRef: LLVMPPCFP128Type()) + } + + /// Creates an instance of the `PPCFP128Type` type in the Context. + public init(in context: Context) { + super.init(typeRef: LLVMPPCFP128TypeInContext(context.contextRef)) + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + super.init(typeRef: typeRef.typeRef, context: context) + } +} + +extension FloatingType: Equatable { + public static func == (lhs: FloatingType, rhs: FloatingType) -> Bool { + lhs.typeRef == rhs.typeRef + } +} diff --git a/Source/LLVM/Core/Types/Function.swift b/Source/LLVM/Core/Types/Function.swift new file mode 100644 index 0000000..ae75be4 --- /dev/null +++ b/Source/LLVM/Core/Types/Function.swift @@ -0,0 +1,82 @@ +import CLLVM + +public struct FunctionType: TypeRef { + var llvm: LLVMTypeRef + + /// Function return type. + public let returnType: TypeRef + + public let parameterTypes: [TypeRef] + + public let isVariadic: Bool + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// For parent classes init with predefined `FunctionType` in Context + public init(returnType: TypeRef, parameterTypes: [TypeRef], isVariadic: Bool = false) { + var mutableParamTypes = parameterTypes.map { $0.typeRef as Optional } + llvm = mutableParamTypes.withUnsafeMutableBufferPointer { paramsBuffer in + LLVMFunctionType(returnType.typeRef, paramsBuffer.baseAddress, UInt32(parameterTypes.count), isVariadic.llvm)! + } + self.returnType = returnType + self.parameterTypes = parameterTypes + self.isVariadic = isVariadic + } + + /// Get the Type current function type returns. + public var getReturnType: TypeRef { + Self.getReturnType(funcType: self) + } + + /// Get the Type this function Type returns. + /// Also useful with: Types(funcReturnTy).getTypeKind, Types(funcReturnTy).getContext + public static func getReturnType(funcType: TypeRef) -> TypeRef { + Types(llvm: LLVMGetReturnType(funcType.typeRef)) + } + + /// Returns whether the current function type is variadic. + public var isFunctionVarArg: Bool { + Self.isFunctionVarArg(funcType: self) + } + + /// Returns whether a function type is variadic. + public static func isFunctionVarArg(funcType: TypeRef) -> Bool { + LLVMIsFunctionVarArg(funcType.typeRef) != 0 + } + + /// Get the number of parameters current function accepts. + public var countParamTypes: UInt32 { + Self.countParamTypes(funcType: self) + } + + /// Get the number of parameters this function accepts. + public static func countParamTypes(funcType: TypeRef) -> UInt32 { + LLVMCountParamTypes(funcType.typeRef) + } + + /// Get the types of a function's parameters. + public var getParamTypes: [TypeRef] { + Self.getParamTypes(funcType: self) + } + + /// Get the types of a function's parameters. + public static func getParamTypes(funcType: TypeRef) -> [TypeRef] { + // The Dest parameter should point to a pre-allocated array of + // LLVMTypeRef at least LLVMCountParamTypes() large. On return, the + // first LLVMCountParamTypes() entries in the array will be populated + // with LLVMTypeRef instances. + let count = Int(Self.countParamTypes(funcType: funcType)) + var paramTypes = [LLVMTypeRef?](repeating: nil, count: count) + paramTypes.withUnsafeMutableBufferPointer { bufferPointer in + LLVMGetParamTypes(funcType.typeRef, bufferPointer.baseAddress) + } + return paramTypes.map { Types(llvm: $0!) } + } +} + +extension FunctionType: Equatable { + public static func == (lhs: FunctionType, rhs: FunctionType) -> Bool { + lhs.typeRef == rhs.typeRef + } +} diff --git a/Source/LLVM/Core/Types/Int.swift b/Source/LLVM/Core/Types/Int.swift new file mode 100644 index 0000000..9704bc9 --- /dev/null +++ b/Source/LLVM/Core/Types/Int.swift @@ -0,0 +1,162 @@ +import CLLVM + +/// The `IntType` represents an integral value of a specified bit width. +/// +/// The `IntType` is a very simple type that simply specifies an arbitrary bit +/// width for the integer type desired. Any bit width from 1 bit to (2^23)-1 +/// (about 8 million) can be specified. +public class IntType: TypeRef { + var llvm: LLVMTypeRef + + /// Returns the context associated with this type. + public let context: Context? + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// Get `IntType` width for current type instance + public var getIntTypeWidth: UInt32 { LLVMGetIntTypeWidth(llvm) } + + /// Get `IntType` width for type instance from parameter + public static func getIntTypeWidth(ty: TypeRef) -> UInt32 { + LLVMGetIntTypeWidth(ty.typeRef) + } + + /// For parent classes init with predefined `IntType` in global context + init(typeRef: LLVMTypeRef) { + llvm = typeRef + context = nil + } + + /// For parent classes init with predefined `IntType` in Context + init(typeRef: LLVMTypeRef, context: Context) { + llvm = typeRef + self.context = context + } + + /// Creates an instance of the `IntType` type on the global context. + public init(bits: UInt32) { + llvm = LLVMIntType(bits) + context = nil + } + + /// Creates an instance of the `IntType` type in the context. + public init(bits: UInt32, in context: Context) { + llvm = LLVMIntTypeInContext(context.contextRef, bits) + self.context = context + } +} + +/// `Int1Type` int type with 1-bits (aka Bool type) +public class Int1Type: IntType { + /// Creates an instance of the `Int1Type` type in the global context. + public init() { + super.init(typeRef: LLVMInt1Type()) + } + + /// Creates an instance of the `Int1Type` type in the Context. + public init(in context: Context) { + super.init(typeRef: LLVMInt1TypeInContext(context.contextRef), context: context) + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + super.init(typeRef: typeRef.typeRef, context: context) + } +} + +/// `Int8Type` int type with 8-bits +public class Int8Type: IntType { + /// Creates an instance of the `Int8Type` type in the global context. + public init() { + super.init(typeRef: LLVMInt8Type()) + } + + /// Creates an instance of the `Int8Type` type in the Context. + public init(in context: Context) { + super.init(typeRef: LLVMInt8TypeInContext(context.contextRef), context: context) + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + super.init(typeRef: typeRef.typeRef, context: context) + } +} + +/// `Int16Type` int type with 16-bits +public class Int16Type: IntType { + /// Creates an instance of the `Int16Type` type in the global context. + public init() { + super.init(typeRef: LLVMInt16Type()) + } + + /// Creates an instance of the `Int16Type` type in the Context. + public init(in context: Context) { + super.init(typeRef: LLVMInt16TypeInContext(context.contextRef), context: context) + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + super.init(typeRef: typeRef.typeRef, context: context) + } +} + +/// `Int32Type` int type with 32-bits +public class Int32Type: IntType { + /// Creates an instance of the `Int32Type` type in the global context. + public init() { + super.init(typeRef: LLVMInt32Type()) + } + + /// Creates an instance of the `Int32Type` type in the Context. + public init(in context: Context) { + super.init(typeRef: LLVMInt32TypeInContext(context.contextRef), context: context) + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + super.init(typeRef: typeRef.typeRef, context: context) + } +} + +/// `Int64Type` int type with 64-bits +public class Int64Type: IntType { + /// Creates an instance of the `Int64Type` type in the global context. + public init() { + super.init(typeRef: LLVMInt64Type()) + } + + /// Creates an instance of the `Int64Type` type in the Context. + public init(in context: Context) { + super.init(typeRef: LLVMInt64TypeInContext(context.contextRef), context: context) + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + super.init(typeRef: typeRef.typeRef, context: context) + } +} + +/// `Int128Type` int type with 128-bits +public class Int128Type: IntType { + /// Creates an instance of the `Int128Type` type in the global context. + public init() { + super.init(typeRef: LLVMInt128Type()) + } + + /// Creates an instance of the `Int128Type` type in the Context. + public init(in context: Context) { + super.init(typeRef: LLVMInt128TypeInContext(context.contextRef), context: context) + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + super.init(typeRef: typeRef.typeRef, context: context) + } +} + +extension IntType: Equatable { + public static func == (lhs: IntType, rhs: IntType) -> Bool { + lhs.typeRef == rhs.typeRef + } +} diff --git a/Source/LLVM/Core/Types/Other/Label.swift b/Source/LLVM/Core/Types/Other/Label.swift new file mode 100644 index 0000000..4d0168b --- /dev/null +++ b/Source/LLVM/Core/Types/Other/Label.swift @@ -0,0 +1,36 @@ +import CLLVM + +/// `LabelType` represents code labels. +public struct LabelType: TypeRef { + private let llvm: LLVMTypeRef + + /// Returns the context associated with this type. + public let context: Context? + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// Creates an instance of the `Label` type on the global context. + public init() { + llvm = LLVMLabelType() + context = nil + } + + /// Creates an instance of the `Label` type in the context. + public init(in context: Context) { + llvm = LLVMLabelTypeInContext(context.contextRef) + self.context = context + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + llvm = typeRef.typeRef + self.context = context + } +} + +extension LabelType: Equatable { + public static func == (lhs: LabelType, rhs: LabelType) -> Bool { + lhs.typeRef == rhs.typeRef + } +} diff --git a/Source/LLVM/Core/Types/Other/Metadata.swift b/Source/LLVM/Core/Types/Other/Metadata.swift new file mode 100644 index 0000000..4d86114 --- /dev/null +++ b/Source/LLVM/Core/Types/Other/Metadata.swift @@ -0,0 +1,31 @@ +import CLLVM + +/// The `MetadataType` type represents embedded metadata. No derived types may +/// be created from metadata except for function arguments. +public struct MetadataType: TypeRef { + private let llvm: LLVMTypeRef + + /// Returns the context associated with this type. + public let context: Context? + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// Creates an instance of the `MetadataType` type in the context. + public init(in context: Context) { + llvm = LLVMMetadataTypeInContext(context.contextRef) + self.context = context + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + llvm = typeRef.typeRef + self.context = context + } +} + +extension MetadataType: Equatable { + public static func == (lhs: MetadataType, rhs: MetadataType) -> Bool { + lhs.typeRef == rhs.typeRef + } +} diff --git a/Source/LLVM/Core/Types/Other/TargetExt.swift b/Source/LLVM/Core/Types/Other/TargetExt.swift new file mode 100644 index 0000000..a6faec5 --- /dev/null +++ b/Source/LLVM/Core/Types/Other/TargetExt.swift @@ -0,0 +1,42 @@ +import CLLVM + +/// Target extension type +public struct TargetExtType: TypeRef { + private let llvm: LLVMTypeRef + + /// Returns the context associated with this type. + public let context: Context? + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// Creates an instance of the `TargetExt` type in the context. + public init(in context: Context, name: String, typeParams: [TypeRef], intParams: [UInt32]) { + var mutableTypeParams = typeParams.map { $0.typeRef as Optional } + var mutableIntParams = intParams + llvm = name.withCString { cName in + mutableTypeParams.withUnsafeMutableBufferPointer { typeParamsBuffer in + mutableIntParams.withUnsafeMutableBufferPointer { intParamsBuffer in + LLVMTargetExtTypeInContext(context.contextRef, cName, + typeParamsBuffer.baseAddress, + UInt32(typeParams.count), + intParamsBuffer.baseAddress, + UInt32(intParams.count))! + } + } + } + self.context = context + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + llvm = typeRef.typeRef + self.context = context + } +} + +extension TargetExtType: Equatable { + public static func == (lhs: TargetExtType, rhs: TargetExtType) -> Bool { + lhs.typeRef == rhs.typeRef + } +} diff --git a/Source/LLVM/Core/Types/Other/Token.swift b/Source/LLVM/Core/Types/Other/Token.swift new file mode 100644 index 0000000..d0b2a5f --- /dev/null +++ b/Source/LLVM/Core/Types/Other/Token.swift @@ -0,0 +1,32 @@ +import CLLVM + +/// `TokenType` is used when a value is associated with an instruction but all +/// uses of the value must not attempt to introspect or obscure it. As such, it +/// is not appropriate to have a `PHI` or `select` of type `TokenType`. +public struct TokenType: TypeRef { + private let llvm: LLVMTypeRef + + /// Returns the context associated with this type. + public let context: Context? + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// Creates an instance of the `Token` type in the context. + public init(in context: Context) { + llvm = LLVMTokenTypeInContext(context.contextRef) + self.context = context + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + llvm = typeRef.typeRef + self.context = context + } +} + +extension TokenType: Equatable { + public static func == (lhs: TokenType, rhs: TokenType) -> Bool { + lhs.typeRef == rhs.typeRef + } +} diff --git a/Source/LLVM/Core/Types/Other/Void.swift b/Source/LLVM/Core/Types/Other/Void.swift new file mode 100644 index 0000000..6e99b1a --- /dev/null +++ b/Source/LLVM/Core/Types/Other/Void.swift @@ -0,0 +1,36 @@ +import CLLVM + +/// The `Void` type represents empty value and has no size. +public struct VoidType: TypeRef { + private let llvm: LLVMTypeRef + + /// Returns the context associated with this type. + public let context: Context? + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// Creates an instance of the `Void` type on the global context. + public init() { + llvm = LLVMVoidType() + context = nil + } + + /// Creates an instance of the `Void` type in the context. + public init(in context: Context) { + llvm = LLVMVoidTypeInContext(context.contextRef) + self.context = context + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + llvm = typeRef.typeRef + self.context = context + } +} + +extension VoidType: Equatable { + public static func == (lhs: VoidType, rhs: VoidType) -> Bool { + lhs.typeRef == rhs.typeRef + } +} diff --git a/Source/LLVM/Core/Types/Other/X86AMX.swift b/Source/LLVM/Core/Types/Other/X86AMX.swift new file mode 100644 index 0000000..91905da --- /dev/null +++ b/Source/LLVM/Core/Types/Other/X86AMX.swift @@ -0,0 +1,36 @@ +import CLLVM + +/// `X86AMXType` represents a value held in an AMX on an x86 machine. +public struct X86AMXType: TypeRef { + private let llvm: LLVMTypeRef + + /// Returns the context associated with this type. + public let context: Context? + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// Creates an instance of the `X86AMX` type on the global context. + public init() { + llvm = LLVMX86AMXType() + context = nil + } + + /// Creates an instance of the `X86AMX` type in the context. + public init(in context: Context) { + llvm = LLVMX86AMXTypeInContext(context.contextRef) + self.context = context + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + llvm = typeRef.typeRef + self.context = context + } +} + +extension X86AMXType: Equatable { + public static func == (lhs: X86AMXType, rhs: X86AMXType) -> Bool { + lhs.typeRef == rhs.typeRef + } +} diff --git a/Source/LLVM/Core/Types/Other/X86MMX.swift b/Source/LLVM/Core/Types/Other/X86MMX.swift new file mode 100644 index 0000000..a065b22 --- /dev/null +++ b/Source/LLVM/Core/Types/Other/X86MMX.swift @@ -0,0 +1,41 @@ +import CLLVM + +/// `X86MMXType` represents a value held in an MMX register on an x86 machine. +/// +/// The operations allowed on it are quite limited: parameters and return +/// values, load and store, and bitcast. User-specified MMX instructions are +/// represented as intrinsic or asm calls with arguments and/or results of this +/// type. There are no arrays, vectors or constants of this type. +public struct X86MMXType: TypeRef { + private let llvm: LLVMTypeRef + + /// Returns the context associated with this type. + public let context: Context? + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// Creates an instance of the `LLVMX86MMX` type on the global context. + public init() { + llvm = LLVMX86MMXType() + context = nil + } + + /// Creates an instance of the `LLVMX86MMX` type in the context. + public init(in context: Context) { + llvm = LLVMX86MMXTypeInContext(context.contextRef) + self.context = context + } + + /// Init with predefined `TypeRef` and `Context` + public init(typeRef: TypeRef, context: Context) { + llvm = typeRef.typeRef + self.context = context + } +} + +extension X86MMXType: Equatable { + public static func == (lhs: X86MMXType, rhs: X86MMXType) -> Bool { + lhs.typeRef == rhs.typeRef + } +} diff --git a/Source/LLVM/Core/Types/Pointer.swift b/Source/LLVM/Core/Types/Pointer.swift new file mode 100644 index 0000000..64c3421 --- /dev/null +++ b/Source/LLVM/Core/Types/Pointer.swift @@ -0,0 +1,92 @@ +import CLLVM + +/// `PointerType` is used to specify memory locations. Pointers are commonly +/// used to reference objects in memory. +/// +/// `PointerType` may have an optional address space attribute defining the +/// numbered address space where the pointed-to object resides. The default +/// address space is number zero. The semantics of non-zero address spaces are +/// target-specific. +/// +/// Note that LLVM does not permit pointers to void `(void*)` nor does it permit +/// pointers to labels `(label*)`. Use `ptr` instead. +public struct PointerType: TypeRef { + var llvm: LLVMTypeRef + + /// Returns the context associated with this type. + public let context: Context? + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// Retrieves the type of the value being pointed to. + public let pointee: TypeRef? + + /// Retrieves the address space where the pointed-to object resides. + public let addressSpace: AddressSpace + + /// Create a `PointerType` pointer type that points to a defined type and an optional address space. + /// The created type will exist in the context that its pointee type exists in . + /// + /// - parameter pointee: The type of the pointed-to object. + /// - parameter addressSpace: The optional address space where the pointed-to object resides. + /// - note: The context of this type is taken from it's pointee + public init(pointee: TypeRef, addressSpace: AddressSpace = .zero) { + if pointee is VoidType || pointee is LabelType { + fatalError("Attempted to form pointer to unexpected Void or Label type - use pointer to IntType.int8 instead") + } + self.pointee = pointee + self.addressSpace = addressSpace + llvm = LLVMPointerType(pointee.typeRef, UInt32(addressSpace.rawValue)) + context = nil + } + + /// Create an opaque pointer type in a context. + public init(in context: Context, addressSpace: AddressSpace = .zero) { + pointee = nil + self.addressSpace = addressSpace + llvm = LLVMPointerTypeInContext(context.contextRef, UInt32(addressSpace.rawValue)) + self.context = context + } + + /// Determine whether a pointer is opaque. + /// True if this is an instance of an opaque PointerType. + public var pointerTypeIsOpaque: Bool { + Self.pointerTypeIsOpaque(typeRef: self) + } + + /// Determine whether a pointer is opaque. + /// True if this is an instance of an opaque PointerType. + public static func pointerTypeIsOpaque(typeRef: TypeRef) -> Bool { + LLVMPointerTypeIsOpaque(typeRef.typeRef) != 0 + } + + /// Get the address space of a pointer type. + /// This only works on types that represent pointers. + public var getPointerAddressSpace: AddressSpace { + Self.getPointerAddressSpace(typeRef: self) + } + + /// Get the address space of a pointer type. + /// This only works on types that represent pointers. + public static func getPointerAddressSpace(typeRef: TypeRef) -> AddressSpace { + AddressSpace(LLVMGetPointerAddressSpace(typeRef.typeRef)) + } + + // Get the element type of an Pointer type. + public var getElementType: TypeRef? { + Self.getElementType(typeRef: self) + } + + /// Get the element type of an Pointer type. + public static func getElementType(typeRef: TypeRef) -> TypeRef? { + guard let newTypeRef = LLVMGetElementType(typeRef.typeRef) else { return nil } + return Types(llvm: newTypeRef) + } +} + +extension PointerType: Equatable { + public static func == (lhs: PointerType, rhs: PointerType) -> Bool { + lhs.typeRef == rhs.typeRef + } +} diff --git a/Source/LLVM/Core/Types/Struct.swift b/Source/LLVM/Core/Types/Struct.swift new file mode 100644 index 0000000..53737df --- /dev/null +++ b/Source/LLVM/Core/Types/Struct.swift @@ -0,0 +1,174 @@ +import CLLVM + +/// `StructType` is used to represent a collection of data members together in +/// memory. The elements of a structure may be any type that has a size. +/// +/// Structures in memory are accessed using `load` and `store` by getting a +/// pointer to a field with the ‘getelementptr‘ instruction. Structures in +/// registers are accessed using the `extractvalue` and `insertvalue` +/// instructions. +/// +/// Structures may optionally be "packed" structures, which indicate that the +/// alignment of the struct is one byte, and that there is no padding between +/// the elements. In non-packed structs, padding between field types is inserted +/// as defined by the `DataLayout` of the module, which is required to match +/// what the underlying code generator expects. +/// +/// Structures can either be "literal" or "identified". A literal structure is +/// defined inline with other types (e.g. {i32, i32}*) whereas identified types +/// are always defined at the top level with a name. Literal types are uniqued +/// by their contents and can never be recursive or opaque since there is no way +/// to write one. Identified types can be recursive, can be opaqued, and are +/// never uniqued. +public struct StructType: TypeRef { + var llvm: LLVMTypeRef + + /// Returns the context associated with this type. + public let context: Context? + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// Create a new structure type in a context. + /// A structure is specified by a list of inner elements/types and + /// whether these can be packed together. + public init(in context: Context, elementTypes: [TypeRef], isPacked: Bool = false) { + var mutElementTypes = elementTypes.map { $0.typeRef as Optional } + llvm = mutElementTypes.withUnsafeMutableBufferPointer { bufferPointer in + LLVMStructTypeInContext(context.contextRef, bufferPointer.baseAddress, UInt32(elementTypes.count), isPacked.llvm)! + } + self.context = context + } + + /// Create a new structure type in the global context. + /// A structure is specified by a list of inner elements/types and + /// whether these can be packed together. + public init(elementTypes: [TypeRef], isPacked: Bool = false) { + var mutElementTypes = elementTypes.map { $0.typeRef as Optional } + llvm = mutElementTypes.withUnsafeMutableBufferPointer { bufferPointer in + LLVMStructType(bufferPointer.baseAddress, UInt32(elementTypes.count), isPacked.llvm)! + } + context = nil + } + + /// Init with predefined `TypeRef` in global context + init(typeRef: TypeRef) { + llvm = typeRef.typeRef + context = nil + } + + /// Determine whether a structure is opaque. + /// Return true if this is a struct type with an identity that has an + /// unspecified body. + public var isOpaqueStruct: Bool { + Self.isOpaqueStruct(typeRef: self) + } + + /// Determine whether a structure is opaque. + public static func isOpaqueStruct(typeRef: TypeRef) -> Bool { + LLVMIsOpaqueStruct(typeRef.typeRef) != 0 + } + + /// Determine whether a structure is packed. + /// Returns true if this is a packed struct type. + /// + /// A packed struct type includes no padding between fields and is thus + /// laid out in one contiguous region of memory with its elements laid out + /// one after the other. A non-packed struct type includes padding according + /// to the data layout of the target. + public var isPackedStruct: Bool { + Self.isPackedStruct(typeRef: self) + } + + /// Determine whether a structure is packed. + public static func isPackedStruct(typeRef: TypeRef) -> Bool { + LLVMIsPackedStruct(typeRef.typeRef) != 0 + } + + /// Returns true if this is a literal struct type. + /// + /// A literal struct type is uniqued by structural equivalence - that is, + /// regardless of how it is named, two literal structures are equal if + /// their fields are equal. + public var isLiteralStruct: Bool { + Self.isLiteralStruct(typeRef: self) + } + + /// Determine whether a structure is literal. + public static func isLiteralStruct(typeRef: TypeRef) -> Bool { + LLVMIsLiteralStruct(typeRef.typeRef) != 0 + } + + /// Get the type of the element at a given index in the current structure. + public func getTypeAtIndex(index: UInt32) -> TypeRef? { + Self.structGetTypeAtIndex(typeRef: self, index: index) + } + + /// Get the type of the element at a given index in the structure. + public static func structGetTypeAtIndex(typeRef: TypeRef, index: UInt32) -> TypeRef? { + guard let typeRef = LLVMStructGetTypeAtIndex(typeRef.typeRef, index) else { return nil } + return Types(llvm: typeRef) + } + + /// Obtain the name of the current structure. + public var getStructName: String { + Self.getStructName(typeRef: self) + } + + /// Obtain the name of a structure. + public static func getStructName(typeRef: TypeRef) -> String { + guard let cString = LLVMGetStructName(typeRef.typeRef) else { return "" } + return String(cString: cString) + } + + /// Set the contents of the current structure. + public func setBody(elementTypes: [TypeRef], isPacked: Bool = false) { + StructType.structSetBody(typeRef: self, elementTypes: elementTypes, isPacked: isPacked) + } + + /// Set the contents of the structure. + public static func structSetBody(typeRef: TypeRef, elementTypes: [TypeRef], isPacked: Bool = false) { + var mutElementTypes = elementTypes.map { $0.typeRef as Optional } + mutElementTypes.withUnsafeMutableBufferPointer { bufferPointer in + LLVMStructSetBody(typeRef.typeRef, bufferPointer.baseAddress, UInt32(elementTypes.count), isPacked.llvm) + } + } + + // Get the number of elements defined inside the current structure. + public var countStructElementTypes: UInt32 { + Self.countStructElementTypes(typeRef: self) + } + + /// Get the number of elements defined inside the structure. + public static func countStructElementTypes(typeRef: TypeRef) -> UInt32 { + LLVMCountStructElementTypes(typeRef.typeRef) + } + + /// Get the elements within current structure. + public var structElementTypes: [TypeRef] { + Self.structElementTypes(typeRef: self) + } + + /// Get the elements within a structure. + /// + /// The function is passed the address of a pre-allocated array of + /// LLVMTypeRef at least LLVMCountStructElementTypes() long. After + /// invocation, this array will be populated with the structure's + /// elements. The objects in the destination array will have a lifetime + /// of the structure type itself, which is the lifetime of the context it + /// is contained in. + public static func structElementTypes(typeRef: TypeRef) -> [TypeRef] { + let elementCount = Self.countStructElementTypes(typeRef: typeRef) + var elementTypes = [LLVMTypeRef?](repeating: nil, count: Int(elementCount)) + elementTypes.withUnsafeMutableBufferPointer { bufferPointer in + LLVMGetStructElementTypes(typeRef.typeRef, bufferPointer.baseAddress) + } + return elementTypes.map { Types(llvm: $0!) } + } +} + +extension StructType: Equatable { + public static func == (lhs: StructType, rhs: StructType) -> Bool { + lhs.typeRef == rhs.typeRef + } +} diff --git a/Source/LLVM/Core/Types/Types.swift b/Source/LLVM/Core/Types/Types.swift new file mode 100644 index 0000000..1231e6f --- /dev/null +++ b/Source/LLVM/Core/Types/Types.swift @@ -0,0 +1,723 @@ +import CLLVM + +/// Used to represent an attributes. +public protocol AttributeRef { + var attributeRef: LLVMAttributeRef { get } +} + +/// Represents a basic block of instructions in LLVM IR. +public protocol BasicBlockRef { + var basicBlockRef: LLVMBasicBlockRef { get } +} + +public protocol BinaryRef { + var binaryRef: LLVMBinaryRef { get } +} + +/// Represents an LLVM basic block builder. +public protocol BuilderRef { + var builderRef: LLVMBuilderRef { get } +} + +public protocol ComdatRef { + var comdatRef: LLVMComdatRef { get } +} + +/// The top-level container for all LLVM global data. +public protocol ContextRef { + var contextRef: LLVMContextRef { get } +} + +public protocol DiagnosticInfoRef { + var diagnosticInfoRef: LLVMDiagnosticInfoRef { get } +} + +/// Represents an LLVM debug info builder. +public protocol DIBuilderRef { + var dIBuilderRef: LLVMDIBuilderRef { get } +} + +public protocol JITEventListenerRef { + var jitEventListenerRef: LLVMJITEventListenerRef { get } +} + +/// LLVM uses a polymorphic type hierarchy which C cannot represent, therefore parameters must be passed as base types. +/// Despite the declared types, most of the functions provided operate only on branches of the type hierarchy. The declared parameter +/// names are descriptive and specify which type is required. Additionally, each type hierarchy is documented along with the functions +/// that operate upon it. For more detail, refer to LLVM's C++ code. If in doubt, refer to Core.cpp, which performs parameter downcasts +/// in the form unwrap(Param). Used to pass regions of memory through LLVM interfaces. +public protocol MemoryBufferRef { + var memoryBufferRef: LLVMMemoryBufferRef { get } +} + +/// Represents an LLVM Metadata. +public protocol MetadataRef { + var metadataRef: LLVMMetadataRef { get } +} + +/// Interface used to provide a module to JIT or interpreter. +public protocol ModuleFlagEntry { + // `LLVMModuleFlagEntry` not found + // var moduleFlagEntry: LLVMModuleFlagEntry { get } +} + +/// Interface used to provide a module to JIT or interpreter. +public protocol ModuleProviderRef { + var moduleProviderRef: LLVMModuleProviderRef { get } +} + +/// The top-level container for all other LLVM Intermediate Representation (IR) objects. +public protocol ModuleRef { + var moduleRef: LLVMModuleRef { get } +} + +/// Represents an LLVM Named Metadata Node (NamedMDNodeRef). +public protocol NamedMetadataNodeRef { + var namedMetadataNodeRef: LLVMNamedMDNodeRef { get } +} + +public protocol OperandBundleRef { + // `LLVMOperandBundleRef` not found + // var operandBundleRef: LLVMOperandBundleRef { get } +} + +public protocol PassManagerRef { + var passManagerRef: LLVMPassManagerRef { get } +} + +/// Each value in the LLVM IR has a type, an LLVMTypeRef. +public protocol TypeRef { + var typeRef: LLVMTypeRef { get } +} + +public extension TypeRef { + /// Get concrete type in their Context. + /// For the result can be applied operations: `is`, `as?`, `as!` + var getConcreteTypeInContext: TypeRef { + let ty = Types(typeRef: self) + switch ty.getTypeKind { + case .IntegerTypeKind: + let intWidth = IntType.getIntTypeWidth(ty: self) + return switch intWidth { + case 1: Int1Type(typeRef: self, context: ty.getTypeContext) + case 8: Int8Type(typeRef: self, context: ty.getTypeContext) + case 16: Int16Type(typeRef: self, context: ty.getTypeContext) + case 32: Int32Type(typeRef: self, context: ty.getTypeContext) + case 64: Int64Type(typeRef: self, context: ty.getTypeContext) + case 128: Int128Type(typeRef: self, context: ty.getTypeContext) + default: IntType(bits: intWidth, in: ty.getTypeContext) + } + case .VoidTypeKind: return VoidType(typeRef: self, context: ty.getTypeContext) + case .HalfTypeKind: return HalfType(typeRef: self, context: ty.getTypeContext) + case .FloatTypeKind: return FloatType(typeRef: self, context: ty.getTypeContext) + case .DoubleTypeKind: return DoubleType(typeRef: self, context: ty.getTypeContext) + case .X86_FP80TypeKind: return X86FP80Type(typeRef: self, context: ty.getTypeContext) + case .FP128TypeKind: return FP128Type(typeRef: self, context: ty.getTypeContext) + case .PPC_FP128TypeKind: return PPCFP128Type(typeRef: self, context: ty.getTypeContext) + case .LabelTypeKind: return LabelType(typeRef: self, context: ty.getTypeContext) + case .FunctionTypeKind: + let paramTypes = FunctionType.getParamTypes(funcType: self) + let returnTy = FunctionType.getReturnType(funcType: self) + let isVarArg = FunctionType.isFunctionVarArg(funcType: self) + return FunctionType(returnType: returnTy, parameterTypes: paramTypes, isVariadic: isVarArg) + case .StructTypeKind: return StructType(typeRef: self) + case .ArrayTypeKind: return ArrayType(typeRef: self) + case .PointerTypeKind: + let pointee = PointerType.getElementType(typeRef: self)! + let addressSpace = PointerType.getPointerAddressSpace(typeRef: self) + return PointerType(pointee: pointee, addressSpace: addressSpace) + case .VectorTypeKind: return VectorType(typeRef: self) + case .MetadataTypeKind: return MetadataType(typeRef: self, context: ty.getTypeContext) + case .X86_MMXTypeKind: return X86MMXType(typeRef: self, context: ty.getTypeContext) + case .TokenTypeKind: return TokenType(typeRef: self, context: ty.getTypeContext) + case .ScalableVectorTypeKind: return ScalableVectorType(typeRef: self) + case .BFloatTypeKind: return BFloatType(typeRef: self, context: ty.getTypeContext) + case .X86_AMXTypeKind: return X86AMXType(typeRef: self, context: ty.getTypeContext) + case .TargetExtTypeKind: return TargetExtType(typeRef: self, context: ty.getTypeContext) + } + } +} + +/// Used to get the users and uses of a Value. +public protocol UseRef { + var useRef: LLVMUseRef { get } +} + +/// Represents an entry in a Global Object's metadata attachments. +@available(*, unavailable, message: "Unavailable for current LLVM-C API") +public protocol ValueMetadataEntry { + // `LLVMValueMetadataEntry` not found + // var valueMetadataEntry: LLVMValueMetadataEntry { get } +} + +/// Represents an individual value in LLVM IR. +public protocol ValueRef { + var valueRef: LLVMValueRef { get } +} + +public struct Types: TypeRef { + let llvm: LLVMTypeRef + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// Init `Types` by `TypeRef` + public init(typeRef: TypeRef) { + llvm = typeRef.typeRef + } + + /// Init `Types` by `LLVMTypeRef` + public init(llvm: LLVMTypeRef) { + self.llvm = llvm + } + + /// Obtain the enumerated type of a Type instance. + public var getTypeKind: TypeKind { + TypeKind(from: LLVMGetTypeKind(typeRef))! + } + + /// Whether the type has a known size. + public var typeIsSized: Bool { + LLVMTypeIsSized(typeRef) != 0 + } + + /// Obtain the context to which this type instance is associated. + public var getTypeContext: Context { + Context(llvm: LLVMGetTypeContext(typeRef)) + } + + /// Dump a representation of a type to stderr. + public func dumpType() { + LLVMDumpType(typeRef) + } + + /// Return a string representation of the type. + public func printTypeToString() -> String { + guard let cString = LLVMPrintTypeToString(typeRef) else { return "" } + return String(cString: cString) + } +} + +public extension Bool { + /// Get `LLVM` representation for Boolean type + var llvm: Int32 { self ? 1 : 0 } +} + +/// Declarations for `LLVMOpcode` +public enum Opcode: UInt32 { + /* Terminator Instructions */ + case Ret = 1 + case Br = 2 + case Switch = 3 + case IndirectBr = 4 + case Invoke = 5 + /* removed 6 due to API changes */ + case Unreachable = 7 + case CallBr = 67 + + /* Standard Unary Operators */ + case FNeg = 66 + + /* Standard Binary Operators */ + case Add = 8 + case FAdd = 9 + case Sub = 10 + case FSub = 11 + case Mul = 12 + case FMul = 13 + case UDiv = 14 + case SDiv = 15 + case FDiv = 16 + case URem = 17 + case SRem = 18 + case FRem = 19 + + /* Logical Operators */ + case Shl = 20 + case LShr = 21 + case AShr = 22 + case And = 23 + case Or = 24 + case Xor = 25 + + /* Memory Operators */ + case Alloca = 26 + case Load = 27 + case Store = 28 + case GetElementPtr = 29 + + /* Cast Operators */ + case Trunc = 30 + case ZExt = 31 + case SExt = 32 + case FPToUI = 33 + case FPToSI = 34 + case UIToFP = 35 + case SIToFP = 36 + case FPTrunc = 37 + case FPExt = 38 + case PtrToInt = 39 + case IntToPtr = 40 + case BitCast = 41 + case AddrSpaceCast = 60 + + /* Other Operators */ + case ICmp = 42 + case FCmp = 43 + case PHI = 44 + case Call = 45 + case Select = 46 + case UserOp1 = 47 + case UserOp2 = 48 + case AArg = 49 + case ExtractElement = 50 + case InsertElement = 51 + case ShuffleVector = 52 + case ExtractValue = 53 + case InsertValue = 54 + case Freeze = 68 + + /* Atomic operators */ + case Fence = 55 + case AtomicCmpXchg = 56 + case AtomicRMW = 57 + + /* Exception Handling Operators */ + case Resume = 58 + case LandingPad = 59 + case CleanupRet = 61 + case CatchRet = 62 + case CatchPad = 63 + case CleanupPad = 64 + case CatchSwitch = 65 + + /// Init enum from `LLVMOpcode` + public init?(from val: LLVMOpcode) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMOpcode` from current type + public var llvm: LLVMOpcode { LLVMOpcode(rawValue: rawValue) } +} + +public enum TypeKind: UInt32 { + case VoidTypeKind = 0 /** < type with no size */ + case HalfTypeKind /** < 16 bit floating point type */ + case FloatTypeKind /** < 32 bit floating point type */ + case DoubleTypeKind /** < 64 bit floating point type */ + case X86_FP80TypeKind /** < 80 bit floating point type (X87) */ + case FP128TypeKind /** < 128 bit floating point type (112-bit mantissa) */ + case PPC_FP128TypeKind /** < 128 bit floating point type (two 64-bits) */ + case LabelTypeKind /** < Labels */ + case IntegerTypeKind /** < Arbitrary bit width integers */ + case FunctionTypeKind /** < Functions */ + case StructTypeKind /** < Structures */ + case ArrayTypeKind /** < Arrays */ + case PointerTypeKind /** < Pointers */ + case VectorTypeKind /** < Fixed width SIMD vector type */ + case MetadataTypeKind /** < Metadata */ + case X86_MMXTypeKind /** < X86 MMX */ + case TokenTypeKind /** < Tokens */ + case ScalableVectorTypeKind /** < Scalable SIMD vector type */ + case BFloatTypeKind /** < 16 bit brain floating point type */ + case X86_AMXTypeKind /** < X86 AMX */ + case TargetExtTypeKind /** < Target extension type */ + + /// Init enum from `LLVMTypeKind` + public init?(from val: LLVMTypeKind) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMTypeKind` from current type + public var llvm: LLVMTypeKind { LLVMTypeKind(rawValue: rawValue) } +} + +public enum Linkage: UInt32 { + case ExternalLinkage = 0 /** < Externally visible function */ + case AvailableExternallyLinkage + case LinkOnceAnyLinkage /** < Keep one copy of function when linking (inline) */ + case LinkOnceODRLinkage /** < Same, but only replaced by something equivalent. */ + case LinkOnceODRAutoHideLinkage /** < Obsolete */ + case WeakAnyLinkage /** < Keep one copy of function when linking (weak) */ + case WeakODRLinkage /** < Same, but only replaced by equivalent. */ + case AppendingLinkage /** < Special purpose, only applies to global arrays */ + case InternalLinkage /** < Rename collisions when linking functions) */ + case PrivateLinkage /** < Like Internal, but omit from symbol table */ + case DLLImportLinkage /** < Obsolete */ + case DLLExportLinkage /** < Obsolete */ + case ExternalWeakLinkage /** < ExternalWeak linkage description */ + case GhostLinkage /** < Obsolete */ + case CommonLinkage /** < Tentative definitions */ + case LinkerPrivateLinkage /** < Like Private, but linker removes. */ + case LinkerPrivateWeakLinkage /** < Like LinkerPrivate, but is weak. */ + + /// Init enum from `LLVMLinkage` + public init?(from ty: LLVMLinkage) { + self.init(rawValue: ty.rawValue) + } + + /// Get `LLVMLinkage` from current type + public var llvm: LLVMLinkage { LLVMLinkage(rawValue: rawValue) } +} + +public enum Visibility: UInt32 { + case DefaultVisibility = 0 /** < The GV is visible */ + case HiddenVisibility /** < The GV is hidden */ + case ProtectedVisibility /** < The GV is protected */ + + /// Init enum from `LLVMTVisibility` + public init?(from val: LLVMVisibility) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMTypeKind` from current type + public var llvm: LLVMVisibility { LLVMVisibility(rawValue: rawValue) } +} + +public enum UnnamedAddr: UInt32 { + case NoUnnamedAddr = 0 /** < Address of the GV is significant. */ + case LocalUnnamedAddr /** < Address of the GV is locally insignificant. */ + case GlobalUnnamedAddr /** < Address of the GV is globally insignificant. */ + + /// Init enum from `LLVMUnnamedAddr` + public init?(from ty: LLVMUnnamedAddr) { + self.init(rawValue: ty.rawValue) + } + + /// Get `LLVMUnnamedAddr` from current type + public var llvm: LLVMUnnamedAddr { LLVMUnnamedAddr(rawValue: rawValue) } +} + +public enum DLLStorageClass: UInt32 { + case DefaultStorageClass = 0 + case DLLImportStorageClass = 1 /** < Function to be imported from DLL. */ + case DLLExportStorageClass = 2 /** < Function to be accessible from DLL. */ + + /// Init enum from `LLVMDLLStorageClass` + public init?(from val: LLVMDLLStorageClass) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMDLLStorageClass` from current type + public var llvm: LLVMDLLStorageClass { LLVMDLLStorageClass(rawValue: rawValue) } +} + +public enum CallConv: UInt32 { + case CCallConv = 0 + case FastCallConv = 8 + case ColdCallConv = 9 + case GHCCallConv = 10 + case HiPECallConv = 11 + case WebKitJSCallConv = 12 + case AnyRegCallConv = 13 + case PreserveMostCallConv = 14 + case PreserveAllCallConv = 15 + case SwiftCallConv = 16 + case CXXFASTTLSCallConv = 17 + case X86StdcallCallConv = 64 + case X86FastcallCallConv = 65 + case ARMAPCSCallConv = 66 + case ARMAAPCSCallConv = 67 + case ARMAAPCSVFPCallConv = 68 + case MSP430INTRCallConv = 69 + case X86ThisCallCallConv = 70 + case PTXKernelCallConv = 71 + case PTXDeviceCallConv = 72 + case SPIRFUNCCallConv = 75 + case SPIRKERNELCallConv = 76 + case IntelOCLBICallConv = 77 + case X8664SysVCallConv = 78 + case Win64CallConv = 79 + case X86VectorCallCallConv = 80 + case HHVMCallConv = 81 + case HHVMCCallConv = 82 + case X86INTRCallConv = 83 + case AVRINTRCallConv = 84 + case AVRSIGNALCallConv = 85 + case AVRBUILTINCallConv = 86 + case AMDGPUVSCallConv = 87 + case AMDGPUGSCallConv = 88 + case AMDGPUPSCallConv = 89 + case AMDGPUCSCallConv = 90 + case AMDGPUKERNELCallConv = 91 + case X86RegCallCallConv = 92 + case AMDGPUHSCallConv = 93 + case MSP430BUILTINCallConv = 94 + case AMDGPULSCallConv = 95 + case AMDGPUESCallConv = 96 + + /// Init enum from `LLVMCallConv` + public init?(from val: LLVMCallConv) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMCallConv` from current type + public var llvm: LLVMCallConv { LLVMCallConv(rawValue: rawValue) } +} + +public enum ValueKind: UInt32 { + case ArgumentValueKind = 0 + case BasicBlockValueKind + case MemoryUseValueKind + case MemoryDefValueKind + case MemoryPhiValueKind + + case FunctionValueKind + case GlobalAliasValueKind + case GlobalIFuncValueKind + case GlobalVariableValueKind + case lockAddressValueKind + case ConstantExprValueKind + case ConstantArrayValueKind + case ConstantStructValueKind + case ConstantVectorValueKind + + case UndefValueValueKind + case ConstantAggregateZeroValueKind + case ConstantDataArrayValueKind + case ConstantDataVectorValueKind + case ConstantIntValueKind + case ConstantFPValueKind + case ConstantPointerNullValueKind + case ConstantTokenNoneValueKind + + case MetadataAsValueValueKind + case InlineAsmValueKind + + case InstructionValueKind + case PoisonValueValueKind + case ConstantTargetNoneValueKind + + /// Init enum from `LLVMValueKind` + public init?(from val: LLVMValueKind) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMValueKind` from current type + public var llvm: LLVMValueKind { LLVMValueKind(rawValue: rawValue) } +} + +public enum IntPredicate: UInt32 { + case IntEQ = 32 /** < equal */ + case IntNE /** < not equal */ + case IntUGT /** < unsigned greater than */ + case IntUGE /** < unsigned greater or equal */ + case IntULT /** < unsigned less than */ + case IntULE /** < unsigned less or equal */ + case IntSGT /** < signed greater than */ + case IntSGE /** < signed greater or equal */ + case IntSLT /** < signed less than */ + case IntSLE /** < signed less or equal */ + + /// Init enum from `LLVMIntPredicate` + public init?(from val: LLVMIntPredicate) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMIntPredicate` from current type + public var llvm: LLVMIntPredicate { LLVMIntPredicate(rawValue: rawValue) } +} + +public enum RealPredicate: UInt32 { + case RealPredicateFalse = 0 /** < Always false (always folded) */ + case RealOEQ /** < True if ordered and equal */ + case EealOGT /** < True if ordered and greater than */ + case RealOGE /** < True if ordered and greater than or equal */ + case RealOLT /** < True if ordered and less than */ + case RealOLE /** < True if ordered and less than or equal */ + case RealONE /** < True if ordered and operands are unequal */ + case RealORD /** < True if ordered (no nans) */ + case RealUNO /** < True if unordered: isnan(X) | isnan(Y) */ + case RealUEQ /** < True if unordered or equal */ + case RealUGT /** < True if unordered or greater than */ + case RealUGE /** < True if unordered, greater than, or equal */ + case RealULT /** < True if unordered or less than */ + case RealULE /** < True if unordered, less than, or equal */ + case RealUNE /** < True if unordered or not equal */ + case RealPredicateTrue /** < Always true (always folded) */ + + /// Init enum from `LLVMRealPredicate` + public init?(from val: LLVMRealPredicate) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMRealPredicate` from current type + public var llvm: LLVMRealPredicate { LLVMRealPredicate(rawValue: rawValue) } +} + +public enum LandingPadClauseTy: UInt32 { + case LandingPadCatch = 0 /** < A catch clause */ + case LandingPadFilter /** < A filter clause */ + + /// Init enum from `LLVMLandingPadClauseTy` + public init?(from val: LLVMLandingPadClauseTy) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMLandingPadClauseTy` from current type + public var llvm: LLVMLandingPadClauseTy { LLVMLandingPadClauseTy(rawValue: rawValue) } +} + +public enum ThreadLocalMode: UInt32 { + case NotThreadLocal = 0 + case GeneralDynamicTLSModel + case LocalDynamicTLSModel + case InitialExecTLSModel + case LocalExecTLSModel + + /// Init enum from `LLVMThreadLocalMode` + public init?(from val: LLVMThreadLocalMode) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMThreadLocalMode` from current type + public var llvm: LLVMThreadLocalMode { LLVMThreadLocalMode(rawValue: rawValue) } +} + +public enum AtomicOrdering: UInt32 { + case AtomicOrderingNotAtomic = 0 /** < A load or store which is not atomic */ + /// Lowest level of atomicity, guarantees somewhat sane results, lock free. + case AtomicOrderingUnordered = 1 + /// guarantees that if you take all the operations affecting a specific address, a consistent ordering exists + case AtomicOrderingMonotonic = 2 + /// Acquire provides a barrier of the sort + /// necessary to acquire a lock to access other memory with normal loads and stores. + case AtomicOrderingAcquire = 4 + /// Release is similar to Acquire, but with a barrier of the sort necessary to release a lock. + case AtomicOrderingRelease = 5 + /// provides both an Acquire and Release barrier (for fences and operations which both read and memory). + case AtomicOrderingAcquireRelease = 6 + /// provides Acquire semantics for loads and Release semantics for stores. + /// Additionally, it guarantees that a total ordering exists between + /// SequentiallyConsistent operations. + case AtomicOrderingSequentiallyConsistent = 7 + /// Init enum from `LLVMAtomicOrdering` + public init?(from val: LLVMAtomicOrdering) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMAtomicOrdering` from current type + public var llvm: LLVMAtomicOrdering { LLVMAtomicOrdering(rawValue: rawValue) } +} + +public enum AtomicRMWBinOp: UInt32 { + case AtomicRMWBinOpXchg = 0 /** < Set the new value and return the one old */ + case AtomicRMWBinOpAdd /** < Add a value and return the old one */ + case AtomicRMWBinOpSub /** < Subtract a value and return the old one */ + case AtomicRMWBinOpAnd /** < And a value and return the old one */ + case AtomicRMWBinOpNand /** < Not-And a value and return the old one */ + case AtomicRMWBinOpOr /** < OR a value and return the old one */ + case AtomicRMWBinOpXor /** < Xor a value and return the old one */ + case AtomicRMWBinOpMax /** < Sets the value if it's greater than the original using a signed comparison and return the old one */ + case AtomicRMWBinOpMin /** < Sets the value if it's Smaller than the original using a signed comparison and return the old one */ + case AtomicRMWBinOpUMax /** < Sets the value if it's greater than the original using an unsigned comparison and return the old one */ + case AtomicRMWBinOpUMin /** < Sets the value if it's greater than the original using an unsigned comparison and return the old one */ + case AtomicRMWBinOpFAdd /** < Add a floating point value and return the old one */ + case AtomicRMWBinOpFSub /** < Subtract a floating point value and return the old one */ + case AtomicRMWBinOpFMax /** < Sets the value if it's greater than the original using an floating point comparison return the old one */ + case AtomicRMWBinOpFMin /** < Sets the value if it's smaller than the original using an floating point comparison and return the old one */ + /// Init enum from `LLVMAtomicRMWBinOp` + public init?(from val: LLVMAtomicRMWBinOp) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMAtomicRMWBinOp` from current type + public var llvm: LLVMAtomicRMWBinOp { LLVMAtomicRMWBinOp(rawValue: rawValue) } +} + +public enum DiagnosticSeverity: UInt32 { + case DSError = 0 + case DSWarning + case DSRemark + case DSNote + + /// Init enum from `LLVMDiagnosticSeverity` + public init?(from val: LLVMDiagnosticSeverity) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMDiagnosticSeverity` from current type + public var llvm: LLVMDiagnosticSeverity { LLVMDiagnosticSeverity(rawValue: rawValue) } +} + +public enum InlineAsmDialect: UInt32 { + case InlineAsmDialectATT = 0 + case InlineAsmDialectIntel + + /// Init enum from `LLVMInlineAsmDialect` + public init?(from val: LLVMInlineAsmDialect) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMInlineAsmDialect` from current type + public var llvm: LLVMInlineAsmDialect { LLVMInlineAsmDialect(rawValue: rawValue) } +} + +public enum ModuleFlagBehavior: UInt32 { + /// Emits an error if two values disagree, otherwise the resulting value is + /// that of the operands. + case ModuleFlagBehaviorError = 0 + + /// Emits a warning if two values disagree. The result value will be the + /// operand for the flag from the first module being linked. + case ModuleFlagBehaviorWarning + + /// Adds a requirement that another module flag be present and have a + /// specified value after linking is performed. The value must be a metadata + /// pair, where the first element of the pair is the ID of the module flag + /// to be restricted, and the second element of the pair is the value the + /// module flag should be restricted to. This behavior can be used to + /// restrict the allowable results (via triggering of an error) of linking + /// IDs with the **Override** behavior. + case ModuleFlagBehaviorRequire + + /// Uses the specified value, regardless of the behavior or value of the + /// other module. If both modules specify **Override**, but the values + /// differ, an error will be emitted. + case ModuleFlagBehaviorOverride + + /// Appends the two values, which are required to be metadata nodes. + case ModuleFlagBehaviorAppend + + /// Appends the two values, which are required to be metadata + /// nodes. However, duplicate entries in the second list are dropped + /// during the append operation. + case ModuleFlagBehaviorAppendUnique + + /// Init enum from `LLVMModuleFlagBehavior` + public init?(from val: LLVMModuleFlagBehavior) { + self.init(rawValue: val.rawValue) + } + + /// Get `LLVMModuleFlagBehavior` from current type + public var llvm: LLVMModuleFlagBehavior { LLVMModuleFlagBehavior(rawValue: rawValue) } +} + +/// Attribute index is parameter number from 1 to N. +public struct AttributeIndex2 { + let llvm: LLVMAttributeIndex + + public init?(from val: LLVMAttributeIndex) { + llvm = val + } + + public init(index: UInt32) { + llvm = LLVMAttributeIndex(index) + } + + /// Get attribute index + public var index: UInt32 { llvm } +} + +/// `LLVMAttributeReturnIndex` is anonymous enum +public struct AttributeReturnIndex { + public var llvm = LLVMAttributeReturnIndex +} + +/// `LLVMAttributeFunctionIndex` is anonymous enum +/// ISO C restricts enumerator values to range of 'int' +/// (4294967295 is too large) +/// LLVMAttributeFunctionIndex = ~0U, +public struct AttributeFunctionIndex { + public var llvm = LLVMAttributeFunctionIndex +} diff --git a/Source/LLVM/Core/Types/Vector.swift b/Source/LLVM/Core/Types/Vector.swift new file mode 100644 index 0000000..93c6ec8 --- /dev/null +++ b/Source/LLVM/Core/Types/Vector.swift @@ -0,0 +1,99 @@ +import CLLVM + +/// A `VectorType` is a simple derived type that represents a vector of +/// elements. `VectorType`s are used when multiple primitive data are operated +/// in parallel using a single instruction (SIMD). A vector type requires a size +/// (number of elements) and an underlying primitive data type. +public class VectorType: TypeRef { + private var llvm: LLVMTypeRef + + /// Retrieves the underlying LLVM type object. + public var typeRef: LLVMTypeRef { llvm } + + /// The type of elements in this array. + public let elementType: TypeRef + + /// The number of elements in this vector. + public let count: UInt32 + + /// Create a vector type that contains a defined type and has a specific number of elements. + /// The created type will exist in the context thats its element type exists in. + public init(elementType: TypeRef, count: UInt32) { + self.elementType = elementType + self.count = count + llvm = LLVMVectorType(elementType.typeRef, count) + } + + /// Init with predefined `TypeRef` + public init(typeRef: TypeRef) { + elementType = VectorType.getElementType(typeRef: typeRef)! + count = VectorType.getVectorSize(typeRef: typeRef) + llvm = typeRef.typeRef + } + + /// Init for pre-init vector for depended class + init(for vecTy: LLVMTypeRef, elementType: TypeRef, count: UInt32) { + self.elementType = elementType + self.count = count + llvm = vecTy + } + + /// Get the (possibly scalable) number of elements in the current vector type. + /// This only works on types that represent vectors (fixed or scalable). + public var getVectorSize: UInt32 { + Self.getVectorSize(typeRef: self) + } + + /// Get the (possibly scalable) number of elements in a vector type. + /// This only works on types that represent vectors (fixed or scalable). + public static func getVectorSize(typeRef: TypeRef) -> UInt32 { + LLVMGetVectorSize(typeRef.typeRef) + } + + /// Get the element type of the currect vector type. + public var getElementType: TypeRef? { + Self.getElementType(typeRef: self) + } + + /// Get the element type of an vector type. + public static func getElementType(typeRef: TypeRef) -> TypeRef? { + guard let newTypeRef = LLVMGetElementType(typeRef.typeRef) else { return nil } + return Types(llvm: newTypeRef) + } + + /// Returns type's subtypes for current vector + public var getSubtypes: [TypeRef] { + Self.getSubtypes(typeRef: self) + } + + /// Returns type's subtypes + public static func getSubtypes(typeRef: TypeRef) -> [TypeRef] { + let subtypeCount = LLVMGetNumContainedTypes(typeRef.typeRef) + var subtypes = [LLVMTypeRef?](repeating: nil, count: Int(subtypeCount)) + subtypes.withUnsafeMutableBufferPointer { bufferPointer in + LLVMGetSubtypes(typeRef.typeRef, bufferPointer.baseAddress) + } + return subtypes.map { Types(llvm: $0!) } + } +} + +extension VectorType: Equatable { + public static func == (lhs: VectorType, rhs: VectorType) -> Bool { + lhs.typeRef == rhs.typeRef + } +} + +// LLVMScalableVectorType +public class ScalableVectorType: VectorType { + /// Create a vector type that contains a defined type and has a scalable number of elements. + /// The created type will exist in the context thats its element type exists in. + override public init(elementType: TypeRef, count: UInt32) { + let llvm = LLVMScalableVectorType(elementType.typeRef, count)! + super.init(for: llvm, elementType: elementType, count: count) + } + + /// Init with predefined `TypeRef` + override public init(typeRef: TypeRef) { + super.init(typeRef: typeRef) + } +} diff --git a/Source/LLVM/Core/Values/Constants/Composite.swift b/Source/LLVM/Core/Values/Constants/Composite.swift new file mode 100644 index 0000000..31b5f49 --- /dev/null +++ b/Source/LLVM/Core/Values/Constants/Composite.swift @@ -0,0 +1,146 @@ +import CLLVM + +/// Functions in this group operate on composite constants. +public enum CompositeConstant { + /// Create a ConstantDataSequential and initialize it with a string. + public static func constStringInContext(context: ContextRef, str: String, dontNullTerminate: Bool) -> Value { + let valueRef = str.withCString { cStr in + let length = UInt32(str.utf8.count) + return LLVMConstStringInContext(context.contextRef, cStr, length, dontNullTerminate.llvm)! + } + return Value(llvm: valueRef) + } + + /// Create a ConstantDataSequential with string content in the global context. + /// This is the same as `constStringInContext` except it operates on the global context. + public static func constString(str: String, dontNullTerminate: Bool) -> Value { + let valueRef = str.withCString { cStr in + let length = UInt32(str.utf8.count) + return LLVMConstString(cStr, length, dontNullTerminate.llvm)! + } + return Value(llvm: valueRef) + } + + /// Returns true if the specified constant is an array of i8. + public static func isConstantString(value: ValueRef) -> Bool { + LLVMIsConstantString(value.valueRef) != 0 + } + + /// Get the given constant data sequential as a string. + public static func getString(value: ValueRef) -> (String, UInt) { + var length: UInt = 0 + let lengthPtr = UnsafeMutablePointer.allocate(capacity: 1) + defer { + lengthPtr.deallocate() + } + + if let cStr = LLVMGetAsString(value.valueRef, lengthPtr) { + length = lengthPtr.pointee + let swiftStr = String(cString: cStr) + return (swiftStr, length) + } else { + return ("", 0) + } + } + + /// Create an anonymous `ConstantStruct` with the specified values. + public static func constStructInContext(context: ContextRef, constantVals: [ValueRef], packed: Bool) -> Value? { + let count = UInt32(constantVals.count) + let vals = UnsafeMutablePointer.allocate(capacity: Int(count)) + defer { + vals.deallocate() + } + + for (index, val) in constantVals.enumerated() { + vals[index] = val.valueRef + } + guard let valueRef = LLVMConstStructInContext(context.contextRef, vals, count, packed.llvm) else { return nil } + return Value(llvm: valueRef) + } + + /// Create a `ConstantStruct` in the global Context. + /// This is the same as `constStructInContext` except it operates on the global `Context`. + public static func createLLVMConstStruct(constantVals: [ValueRef], packed: Bool) -> Value? { + let count = UInt32(constantVals.count) + let vals = UnsafeMutablePointer.allocate(capacity: Int(count)) + defer { + vals.deallocate() + } + + for (index, val) in constantVals.enumerated() { + vals[index] = val.valueRef + } + guard let valueRef = LLVMConstStruct(vals, count, packed.llvm) else { return nil } + return Value(llvm: valueRef) + } + + /// Create a `ConstantArray` from values. + @available(*, deprecated, message: "ConstArray is deprecated in favor of the API accurate constArray2") + public static func createLLVMConstArray(elementType: TypeRef, constantValues: [ValueRef]) -> Value? { + let length = UInt32(constantValues.count) + let values = UnsafeMutablePointer.allocate(capacity: Int(length)) + defer { + values.deallocate() + } + + for (index, value) in constantValues.enumerated() { + values[index] = value.valueRef + } + guard let valueRef = LLVMConstArray(elementType.typeRef, values, length) else { return nil } + return Value(llvm: valueRef) + } + + /// Create a ConstantArray from values. + public static func constArray2(elementType: TypeRef, constantValues: [ValueRef]) -> Value? { + let length = UInt64(constantValues.count) + let values = UnsafeMutablePointer.allocate(capacity: Int(length)) + defer { + values.deallocate() + } + + for (index, value) in constantValues.enumerated() { + values[index] = value.valueRef + } + guard let valueRef = LLVMConstArray2(elementType.typeRef, values, length) else { return nil } + return Value(llvm: valueRef) + } + + /// Create a non-anonymous `ConstantStruct` from values. + public static func constNamedStruct(structType: TypeRef, constantValues: [ValueRef]) -> Value? { + let count = UInt32(constantValues.count) + let values = UnsafeMutablePointer.allocate(capacity: Int(count)) + defer { + values.deallocate() + } + + for (index, value) in constantValues.enumerated() { + values[index] = value.valueRef + } + guard let valueRef = LLVMConstNamedStruct(structType.typeRef, values, count) else { return nil } + return Value(llvm: valueRef) + } + + /// Get element of a constant aggregate (struct, array or vector) at the + /// specified index. Returns null if the index is out of range, or it's not + /// possible to determine the element (e.g., because the constant is a + /// constant expression.) + public static func getAggregateElement(aggregate: ValueRef, index: UInt32) -> Value? { + guard let valueRef = LLVMGetAggregateElement(aggregate.valueRef, index) else { return nil } + return Value(llvm: valueRef) + } + + /// Create a ConstantVector from values. + public static func constVector(scalarConstantValues: [ValueRef]) -> Value? { + let size = UInt32(scalarConstantValues.count) + let values = UnsafeMutablePointer.allocate(capacity: Int(size)) + defer { + values.deallocate() + } + + for (index, value) in scalarConstantValues.enumerated() { + values[index] = value.valueRef + } + guard let valueRef = LLVMConstVector(values, size) else { return nil } + return Value(llvm: valueRef) + } +} diff --git a/Source/LLVM/Core/Values/Constants/Constants.swift b/Source/LLVM/Core/Values/Constants/Constants.swift new file mode 100644 index 0000000..fa88c11 --- /dev/null +++ b/Source/LLVM/Core/Values/Constants/Constants.swift @@ -0,0 +1,40 @@ +import CLLVM + +/// This section contains APIs for interacting with LLVMValueRef that correspond to llvm::Constant instances. More... +public enum Constants { + /// Obtain a constant value referring to the null instance of a type. + public static func constNull(typeRef: TypeRef) -> Value? { + guard let valueRef = LLVMConstNull(typeRef.typeRef) else { return nil } + return Value(llvm: valueRef) + } + + /// Obtain a constant value referring to the instance of a type consisting of all ones. + /// This is only valid for integer types. + public static func constAllOnes(typeRef: TypeRef) -> Value? { + guard let valueRef = LLVMConstAllOnes(typeRef.typeRef) else { return nil } + return Value(llvm: valueRef) + } + + /// Obtain a constant value referring to an undefined value of a type. + public static func getUndef(typeRef: TypeRef) -> Value? { + guard let valueRef = LLVMGetUndef(typeRef.typeRef) else { return nil } + return Value(llvm: valueRef) + } + + /// Obtain a constant value referring to a poison value of a type. + public static func getPoison(typeRef: TypeRef) -> Value? { + guard let valueRef = LLVMGetPoison(typeRef.typeRef) else { return nil } + return Value(llvm: valueRef) + } + + // Determine whether a value instance is null. + public static func constPointerNull(valueRef: ValueRef) -> Bool { + LLVMIsNull(valueRef.valueRef) != 0 + } + + /// Obtain a constant that is a constant pointer pointing to NULL for a specified type. + public static func constPointerNull(typeRef: TypeRef) -> Value? { + guard let valueRef = LLVMConstPointerNull(typeRef.typeRef) else { return nil } + return Value(llvm: valueRef) + } +} diff --git a/Source/LLVM/Core/Values/Constants/Expressions.swift b/Source/LLVM/Core/Values/Constants/Expressions.swift new file mode 100644 index 0000000..f5f74a8 --- /dev/null +++ b/Source/LLVM/Core/Values/Constants/Expressions.swift @@ -0,0 +1,280 @@ +import CLLVM + +/* + /// Functions in this group correspond to APIs on `ConstantExpressions` . + public enum ConstantExpressions { + public static func getConstOpcode(constantVal: ValueRef) -> Opcode { + let opcode = LLVMGetConstOpcode(constantVal.valueRef) + return Opcode(from: opcode)! + } + + public static func alignOf(typeRef: TypeRef) -> Value { + let valueRef = LLVMAlignOf(typeRef.typeRef)! + return Value(llvm: valueRef) + } + + public static func sizeOf(typeRef: TypeRef) -> Value { + let valueRef = LLVMSizeOf(typeRef.typeRef)! + return Value(llvm: valueRef) + } + + public func constNSWNeg(_ constantVal: ValueRef) -> Value { + let valueRef = LLVMConstNSWNeg(constantVal.valueRef)! + return Value(llvm: valueRef) + } + + public func constNUWNeg(_ constantVal: ValueRef) -> Value { + let valueRef = LLVMConstNUWNeg(constantVal.valueRef)! + return Value(llvm: valueRef) + } + + public static func constNeg(constantVal: ValueRef) -> Value { + let valueRef = LLVMConstNeg(constantVal.valueRef)! + return Value(llvm: valueRef) + } + + public func constNot(_ constantVal: LLVMValueRef) -> LLVMValueRef { + LLVMConstNot(constantVal) + } + + public func constAdd(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstAdd(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constNSWAdd(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstNSWAdd(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constNUWAdd(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstNUWAdd(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constSub(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstSub(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constNSWSub(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstNSWSub(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constNUWSub(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstNUWSub(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constMul(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstMul(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constNSWMul(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstNSWMul(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constNUWMul(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstNUWMul(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constAnd(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstAnd(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constOr(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstOr(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constXor(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstXor(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constICmp(_ predicate: IntPredicate, _ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstICmp(predicate.llvm, lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constFCmp(_ predicate: RealPredicate, _ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstFCmp(predicate.llvm, lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constShl(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstShl(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constLShr(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstLShr(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constAShr(_ lhsConstant: ValueRef, _ rhsConstant: ValueRef) -> Value { + let valueRef = LLVMConstAShr(lhsConstant.valueRef, rhsConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constGEP2(_ type: TypeRef, _ constantVal: ValueRef, _ constantIndices: [ValueRef], _ numIndices: UInt32) -> Value { + let indices = UnsafeMutablePointer.allocate(capacity: Int(numIndices)) + defer { + indices.deallocate() + } + + for (index, value) in constantIndices.enumerated() { + guard index < numIndices else { break } + indices[index] = value.valueRef + } + + let valueRef = LLVMConstGEP2(type.typeRef, constantVal.valueRef, indices, numIndices)! + return Value(llvm: valueRef) + } + + public func constInBoundsGEP2(_ type: TypeRef, _ constantVal: ValueRef, _ constantIndices: [ValueRef], _ numIndices: UInt32) -> Value { + let indices = UnsafeMutablePointer.allocate(capacity: Int(numIndices)) + defer { + indices.deallocate() + } + + for (index, value) in constantIndices.enumerated() { + guard index < numIndices else { break } + indices[index] = value.valueRef + } + + let valueRef = LLVMConstInBoundsGEP2(type.typeRef, constantVal.valueRef, indices, numIndices)! + return Value(llvm: valueRef) + } + + public func constTrunc(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstTrunc(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + public func constSExt(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstSExt(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + public func constZExt(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstZExt(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + public func constFPTrunc(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstFPTrunc(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + public func constFPExt(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstFPExt(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + public func constUIToFP(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstUIToFP(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + public func constSIToFP(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstSIToFP(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + public func constFPToUI(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstFPToUI(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + // public func constFPToSI(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + // let valueRef = LLVMConstFPToSI(constantVal.valueRef, toType.typeRef)! + // return Value(llvm: valueRef) + // } + + public func constPtrToInt(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstPtrToInt(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + public func constIntToPtr(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstIntToPtr(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + public func constBitCast(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstBitCast(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + public func constAddrSpaceCast(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstAddrSpaceCast(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + // public func constZExtOrBitCast(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + // let valueRef = LLVMConstZExtOrBitCast(constantVal.valueRef, toType.typeRef)! + // return Value(llvm: valueRef) + // } + + public func constSExtOrBitCast(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstSExtOrBitCast(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + public func constTruncOrBitCast(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstTruncOrBitCast(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + public func constPointerCast(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + let valueRef = LLVMConstPointerCast(constantVal.valueRef, toType.typeRef)! + return Value(llvm: valueRef) + } + + // public func constIntCast(_ constantVal: ValueRef, _ toType: TypeRef, _ isSigned: Bool) -> Value { + // let valueRef = LLVMConstIntCast(constantVal.valueRef, toType.typeRef, isSigned.llvm)! + // return Value(llvm: valueRef) + // } + + // public func constFPCast(_ constantVal: ValueRef, _ toType: TypeRef) -> Value { + // let valueRef = LLVMConstFPCast(constantVal.valueRef, toType.typeRef)! + // return Value(llvm: valueRef) + // } + + public func constExtractElement(_ vectorConstant: ValueRef, _ indexConstant: ValueRef) -> Value { + let valueRef = LLVMConstExtractElement(vectorConstant.valueRef, indexConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constInsertElement(_ vectorConstant: ValueRef, _ elementValueConstant: ValueRef, _ indexConstant: ValueRef) -> Value { + let valueRef = LLVMConstInsertElement(vectorConstant.valueRef, elementValueConstant.valueRef, indexConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func constShuffleVector(_ vectorAConstant: ValueRef, _ vectorBConstant: ValueRef, _ maskConstant: ValueRef) -> Value { + let valueRef = LLVMConstShuffleVector(vectorAConstant.valueRef, vectorBConstant.valueRef, maskConstant.valueRef)! + return Value(llvm: valueRef) + } + + public func blockAddress(_ function: ValueRef, _ basicBlock: BasicBlockRef) -> Value { + let valueRef = LLVMBlockAddress(function.valueRef, basicBlock.basicBlockRef)! + return Value(llvm: valueRef) + } + + @available(*, deprecated, message: "Use LLVMGetInlineAsm instead") + public func constInlineAsm(type: TypeRef, asmString: String, constraints: String, hasSideEffects: Bool, isAlignStack: Bool) -> Value { + let valueRef = asmString.withCString { asmStr in + constraints.withCString { consStr in + LLVMConstInlineAsm(type.typeRef, asmStr, consStr, hasSideEffects.llvm, isAlignStack.llvm)! + } + } + return Value(llvm: valueRef) + } + } + */ diff --git a/Source/LLVM/Core/Values/Constants/Scalar.swift b/Source/LLVM/Core/Values/Constants/Scalar.swift new file mode 100644 index 0000000..50cfac7 --- /dev/null +++ b/Source/LLVM/Core/Values/Constants/Scalar.swift @@ -0,0 +1,81 @@ +import CLLVM + +/// Functions in this group model ValueRef instances that correspond to constants referring to scalar types. +public enum ScalarConstant { + /// Obtain a constant value for an integer type. + public static func constInt(intTy: TypeRef, n: UInt64, signExtend: Bool) -> Value { + let valueRef = LLVMConstInt(intTy.typeRef, n, signExtend.llvm)! + return Value(llvm: valueRef) + } + + /// Obtain a constant value for an integer of arbitrary precision. + public static func constIntOfArbitraryPrecision(intType: TypeRef, words: [UInt64]) -> Value? { + let numWords = UInt32(words.count) + let valueRef = words.withUnsafeBufferPointer { bufferPointer in + LLVMConstIntOfArbitraryPrecision(intType.typeRef, numWords, bufferPointer.baseAddress)! + } + return Value(llvm: valueRef) + } + + /// Obtain a constant value for an integer parsed from a string. + /// A similar API, `constIntOfStringAndSize` is also available. If the + /// string's length is available, it is preferred to call that function instead. + public static func constIntOfString(intType: TypeRef, text: String, radix: UInt8) -> Value { + let valueRef = text.withCString { cString in + LLVMConstIntOfString(intType.typeRef, cString, radix)! + } + return Value(llvm: valueRef) + } + + /// Obtain a constant value for an integer parsed from a string with specified length. + public static func constIntOfStringAndSize(intType: TypeRef, text: String, radix: UInt8) -> Value { + let valueRef = text.withCString { cString in + let length = UInt32(text.utf8.count) + return LLVMConstIntOfStringAndSize(intType.typeRef, cString, length, radix)! + } + return Value(llvm: valueRef) + } + + /// Obtain a constant value referring to a double floating point value. + public static func constReal(realType: TypeRef, n: Double) -> Value { + let valueRef = LLVMConstReal(realType.typeRef, n)! + return Value(llvm: valueRef) + } + + /// Obtain a constant for a floating point value parsed from a string. + /// A similar API, LLVMConstRealOfStringAndSize is also available. It + /// should be used if the input string's length is known. + public static func constRealOfString(realType: TypeRef, text: String) -> Value { + let valueRef = text.withCString { cString in + LLVMConstRealOfString(realType.typeRef, cString)! + } + return Value(llvm: valueRef) + } + + /// Obtain a constant for a floating point value parsed from a string. + public static func constRealOfStringAndSize(realType: TypeRef, text: String) -> Value { + let valueRef = text.withCString { cString in + let length = UInt32(text.utf8.count) + return LLVMConstRealOfStringAndSize(realType.typeRef, cString, length)! + } + return Value(llvm: valueRef) + } + + /// Obtain the zero extended value for an integer constant value. + public static func constIntZExtValue(constantVal: ValueRef) -> UInt64 { + LLVMConstIntGetZExtValue(constantVal.valueRef) + } + + /// Obtain the sign extended value for an integer constant value. + public static func constIntSExtValue(constantVal: ValueRef) -> Int64 { + LLVMConstIntGetSExtValue(constantVal.valueRef) + } + + /// Obtain the double value for an floating point constant value. + /// losesInfo indicates if some precision was lost in the conversion. + public static func constRealGetDouble(constantVal: ValueRef) -> (Double, Bool) { + var losesInfo: LLVMBool = 0 + let val = LLVMConstRealGetDouble(constantVal.valueRef, &losesInfo) + return (val, losesInfo != 0) + } +} diff --git a/Source/LLVM/Core/Values/Value.swift b/Source/LLVM/Core/Values/Value.swift new file mode 100644 index 0000000..f5dac51 --- /dev/null +++ b/Source/LLVM/Core/Values/Value.swift @@ -0,0 +1,18 @@ +import CLLVM + +public struct Value: ValueRef { + let llvm: LLVMValueRef + + /// Retrieves the underlying LLVM type object. + public var valueRef: LLVMValueRef { llvm } + + /// Init `Values` by `ValueRef` + public init(valueRef: ValueRef) { + llvm = valueRef.valueRef + } + + /// Init `Values` by `LLVMValueRef` + public init(llvm: LLVMValueRef) { + self.llvm = llvm + } +} diff --git a/llvm-api/LLVM/Core/AddressSpace.swift b/llvm-api/LLVM/Core/AddressSpace.swift index 8c3ccf7..9615bb7 100644 --- a/llvm-api/LLVM/Core/AddressSpace.swift +++ b/llvm-api/LLVM/Core/AddressSpace.swift @@ -11,7 +11,7 @@ import CLLVM /// These assumptions are not guaranteed to hold in any other address space. In particular, a target may /// allow pointers in non-default address spaces to have *non-integral* types. Non-integral pointer types /// represent pointers that have an unspecified bitwise representation; that is, the integral representation may -/// be target dependent or have an unstable value. Further, outside of the default address space, it is not +/// be target dependent or have an unstable value./// Further, outside of the default address space, it is not /// always the case that the `null` pointer value, especially as returned by /// `constPointerNull()` has a bit value of 0. e.g. A non-default address space may use /// an offset-based or segment-based addressing mode in which 0 is a valid, addressable pointer value. diff --git a/utils/llvm-pkg.swift b/utils/llvm-pkg.swift new file mode 100755 index 0000000..5d1672f --- /dev/null +++ b/utils/llvm-pkg.swift @@ -0,0 +1,134 @@ +#!/usr/bin/env swift +import Foundation + +#if os(Linux) + let libCPP = "-L/usr/lib -lc++" +#elseif os(macOS) + let libCPP = "-lc++" +#endif + +/// Runs the specified program at the provided path. +/// - parameter path: The full path of the executable you +/// wish to run. +/// - parameter args: The arguments you wish to pass to the +/// process. +/// - returns: The standard output of the process, or nil if it was empty. +func run(_ path: String, args: [String] = []) -> String? { + print("Running \(path) \(args.joined(separator: " "))...") + let pipe = Pipe() + let process = Process() + process.executableURL = URL(fileURLWithPath: path) + process.arguments = args + process.standardOutput = pipe + try? process.run() + process.waitUntilExit() + + let data = pipe.fileHandleForReading.readDataToEndOfFile() + guard let result = String(data: data, encoding: .utf8)? + .trimmingCharacters(in: .whitespacesAndNewlines), + !result.isEmpty else { return nil } + return result +} + +/// Finds the location of the provided binary on your system. +func which(_ name: String) -> String? { + return run("/usr/bin/which", args: [name]) +} + +extension String: Error { + /// Replaces all occurrences of characters in the provided set with + /// the provided string. + func replacing(charactersIn characterSet: CharacterSet, + with separator: String) -> String { + let components = self.components(separatedBy: characterSet) + return components.joined(separator: separator) + } +} + +func makeFile() throws { + let brewPrefix = { + guard let brew = which("brew") else { return nil } + return run(brew, args: ["--prefix"]) + }() ?? "/usr/local" + + let pkgConfigPath = "\(brewPrefix)/lib/pkgconfig" + let pkgConfigDir = URL(fileURLWithPath: pkgConfigPath) + + // Make /lib/pkgconfig if it doesn't already exist + if !FileManager.default.fileExists(atPath: pkgConfigPath) { + try FileManager.default.createDirectory(at: pkgConfigDir, + withIntermediateDirectories: true) + } + let cllvmPath = pkgConfigDir.appendingPathComponent("llvm.pc") + let brewLLVMConfig = { which("\(brewPrefix)/opt/llvm/bin/llvm-config") } + + /// Ensure we have llvm-config in the PATH + guard let llvmConfig = which("llvm-config-15") ?? which("llvm-config") ?? brewLLVMConfig() else { + throw "Failed to find llvm-config. Ensure llvm-config is installed and " + + "in your PATH" + } + + /// Extract the info we need from llvm-config + + print("Found llvm-config at \(llvmConfig)...") + + let versionStr = run(llvmConfig, args: ["--version"])! + .replacing(charactersIn: .newlines, with: "") + .replacingOccurrences(of: "svn", with: "") + let components = versionStr.components(separatedBy: ".") + .compactMap { Int($0) } + + guard components.count == 3 else { + throw "Invalid version number \(versionStr)" + } + + let version = (components[0], components[1], components[2]) + + guard version >= (15, 0, 0) else { + throw "LLVMSwift requires LLVM version >=15.0.0, but you have \(versionStr)" + } + + print("LLVM version is \(versionStr)") + + let ldFlags = run(llvmConfig, args: ["--ldflags", "--libs", "all", + "--system-libs"])! + .replacing(charactersIn: .newlines, with: " ") + .components(separatedBy: " ") + .filter { !$0.hasPrefix("-W") } + .joined(separator: " ") + + // SwiftPM has a whitelisted set of cflags that it understands, and + // unfortunately that includes almost everything but the include dir. + + let cFlags = run(llvmConfig, args: ["--cflags"])! + .replacing(charactersIn: .newlines, with: "") + .components(separatedBy: " ") + .filter { $0.hasPrefix("-I") } + .joined(separator: " ") + + /// Emit the pkg-config file to the path + + let s = [ + "Name: cllvm", + "Description: The llvm library", + "Version: \(versionStr)", + "Libs: \(ldFlags) \(libCPP)", + "Requires.private:", + "Cflags: \(cFlags)", + ].joined(separator: "\n") + + print("Writing pkg-config file to \(cllvmPath.path)...") + + try s.write(toFile: cllvmPath.path, atomically: true, encoding: .utf8) + + print("\nSuccessfully wrote pkg-config file!") + print("Make sure to re-run this script when you update LLVM.") +} + +do { + try makeFile() +} catch { + print("error: \(error)") + exit(-1) +} +