From 2c3a082755d4c0c8c84be40003fd199dfbf3c87f Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Fri, 22 Oct 2021 10:12:41 +0200 Subject: [PATCH 1/2] Exnted Module with Flag and Metadata funcitons --- llvm-api/LLVM/Core/Context.swift | 9 +- llvm-api/LLVM/Core/Modules.swift | 204 +++++++++++++++++++++++++-- llvm-api/LLVM/Core/Types/Types.swift | 6 +- 3 files changed, 202 insertions(+), 17 deletions(-) diff --git a/llvm-api/LLVM/Core/Context.swift b/llvm-api/LLVM/Core/Context.swift index 88fda05..2468a7f 100644 --- a/llvm-api/LLVM/Core/Context.swift +++ b/llvm-api/LLVM/Core/Context.swift @@ -222,12 +222,19 @@ public final class Context: ContextRef { } } + ///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 { - LLVMContextDispose(llvm) + self.dispose() } } diff --git a/llvm-api/LLVM/Core/Modules.swift b/llvm-api/LLVM/Core/Modules.swift index 6a97bbd..3212ab8 100644 --- a/llvm-api/LLVM/Core/Modules.swift +++ b/llvm-api/LLVM/Core/Modules.swift @@ -9,6 +9,152 @@ public final class Module: ModuleRef { /// 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 @@ -36,33 +182,46 @@ public final class Module: ModuleRef { } /// Return an exact copy of the specified module. - public func clone_nodule() -> ModuleRef { + 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 getLLVMModuleIdentifier: String { + public var getModuleIdentifier: String { var length: UInt = 0 guard let cString = LLVMGetModuleIdentifier(llvm, &length) else { return "" } return String(cString: cString) } - public func setLLVMModuleIdentifier(module: LLVMModuleRef, identifier: String) { + /// Set the identifier of a module to a string Ident with length Len. + public func setModuleIdentifier(identifier: String) { identifier.withCString { cString in - LLVMSetModuleIdentifier(module, cString, identifier.count) + LLVMSetModuleIdentifier(llvm, cString, identifier.count) } } - public var getModuleIdentifier: String? { - var length: UInt = 0 - guard let cString = LLVMGetModuleIdentifier(llvm, &length) else { - return nil + /// 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) } - return String(cString: cString) } - /// Set the identifier of a module to a string Ident with length Len. + ///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) @@ -71,7 +230,7 @@ public final class Module: ModuleRef { /// Obtain the module's original source file name. public var getSourceFileName: String? { - var length: size_t = 0 + var length: Int = 0 guard let cString = LLVMGetSourceFileName(llvm, &length) else { return nil } @@ -79,9 +238,9 @@ public final class Module: ModuleRef { } /// Set the data layout for a module. - public func setDataLayout(module: LLVMModuleRef, dataLayout: String) { + public func setDataLayout(dataLayout: String) { dataLayout.withCString { cString in - LLVMSetDataLayout(module, cString) + LLVMSetDataLayout(llvm, cString) } } @@ -93,6 +252,15 @@ public final class Module: ModuleRef { 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 @@ -100,6 +268,16 @@ public final class Module: ModuleRef { } } + /// 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. diff --git a/llvm-api/LLVM/Core/Types/Types.swift b/llvm-api/LLVM/Core/Types/Types.swift index 216507a..1231e6f 100644 --- a/llvm-api/LLVM/Core/Types/Types.swift +++ b/llvm-api/LLVM/Core/Types/Types.swift @@ -71,9 +71,9 @@ public protocol ModuleRef { var moduleRef: LLVMModuleRef { get } } -/// Represents an LLVM Named Metadata Node. -public protocol NamedMDNodeRef { - var namedMDNodeRef: LLVMNamedMDNodeRef { get } +/// Represents an LLVM Named Metadata Node (NamedMDNodeRef). +public protocol NamedMetadataNodeRef { + var namedMetadataNodeRef: LLVMNamedMDNodeRef { get } } public protocol OperandBundleRef { From 0157b3d2c1c2a6038ea17a17402a8c6d1d8756cd Mon Sep 17 00:00:00 2001 From: Evgeny Ukhanov Date: Tue, 23 Jul 2024 00:19:26 +0200 Subject: [PATCH 2/2] Extend README --- README.md | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 58 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 9f6827c..2da030b 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,68 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![Swift CI](https://github.com/mrLSD/llvm-api-swift/actions/workflows/swift.yaml/badge.svg)](https://github.com/mrLSD/llvm-api-swift/actions/workflows/swift.yaml) -# `llvm-api-swift` +
+

mrLSD/llvm-api-swift

+
`llvm-api-swift` is a library representing Swift LLVM API, a pure Swift interface to the [LLVM API](https://llvm.org/docs/) and its associated libraries. It provides native, easy-to-use components to create compilers codegen backend. It contains LLVM bindings, components and toolset for efficiently use LLVM as compilers backend implementation on Swift. +## Overview + +The `llvm-api-swift` provides a robust and comprehensive interface to the LLVM Compiler Infrastructure, +leveraging the `LLVM-C API` to offer a blend of safety, flexibility, and extendability. This library +is designed to serve as a powerful tool for developers looking to create backends for compilers, enabling +them to harness the full potential of **LLVM** in a secure and user-friendly manner. + +## Safety + +Safety is a paramount concern in the design of this library. By building on the `LLVM-C API`, we ensure that +interactions +with the **LLVM** infrastructure are conducted in a type-safe and memory-safe manner. The library employs Swift’s +stringent +safety guarantees to prevent common issues such as null pointer dereferencing, buffer overflows, and memory leaks. This +commitment to safety allows developers to focus on the functionality of their compiler backends without worrying about +underlying security vulnerabilities. + +## Flexibility + +Flexibility is another core attribute of the `llvm-api-swift`. The library provides a rich set of APIs that cover a wide +range of LLVM’s capabilities, from module management and inline assembly to debugging metadata and function iteration. +Developers can easily access and manipulate **LLVM** constructs, enabling the creation of highly customized and +optimized +compiler backends. The library’s design ensures that it can adapt to various use cases and requirements, making it an +ideal choice for a diverse set of compiler development projects based on Swift. + +## Extendability + +The 'llvm-api-swift' is built with extendability in mind. It is designed to be easily extendable, allowing developers to +add +new functionalities and support for additional **LLVM** features as needed. The modular structure of the library +facilitates +the incorporation of new components, ensuring that it can grow and evolve alongside the **LLVM** ecosystem. This +extendability ensures that the library remains relevant and useful as **LLVM** continues to advance and expand its +capabilities. + +## Why LLVM? + +**LLVM** (Low-Level Virtual Machine) is a powerful and versatile compiler infrastructure that provides a collection of +modular and reusable compiler and toolchain technologies. It is widely used in the development of modern compilers, +providing a framework for optimizing intermediate representations and generating machine code for various target +architectures. LLVM’s ability to support multiple languages and platforms, coupled with its extensive optimization +capabilities, makes it an essential tool for compiler developers. By leveraging **LLVM**, developers can create highly +efficient and portable compilers that meet the demands of today’s diverse computing environments. + +## Design + +The `llvm-api-awift` library adheres to the structure of the `LLVM C API`, ensuring easy navigation through the extensive LLVM +functions. Logical elements are grouped into modules, providing a clear organizational structure. Within these modules, +Rust structures are introduced to wrap LLVM types, implementing corresponding functions for the wrapped LLVM types. This +approach enhances flexibility and usability while maintaining the original LLVM code structure. The design avoids +unnecessary complexity in the code and documentation, remaining fully aligned with the `LLVM API`. This alignment allows +developers to easily navigate the `llvm-api-swift` library using existing LLVM-C documentation. + ### Compatibility with LLVM-C API When creating the library, we were guided by **full compatibility** with [LLVM-C API](https://llvm.org/doxygen/group__LLVMC.html). @@ -15,8 +71,7 @@ And filling the components also with the appropriate `LLVM-C API`. When implementing Swift types, we were guided by the approach of abstracting away from C types, completely transforming them into Swift types. At the same time adhering to the principles of a safety and reliability implementation - without explicit memory management, means of safe techniques, functions provided by Swift. - -### Requirements +## Requirements - Supported OS: MacOS 12.0 or above