Skip to content

Commit 647e0c7

Browse files
authored
Merge pull request #2 from mrLSD/feat/extend-module
Feat: Exnted Module with Flag and Metadata funcitons
2 parents 7b72ed6 + 0157b3d commit 647e0c7

File tree

4 files changed

+260
-20
lines changed

4 files changed

+260
-20
lines changed

README.md

+58-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,68 @@
11
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
22
[![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)
33

4-
# `llvm-api-swift`
4+
<center>
5+
<h1>mrLSD<code>/llvm-api-swift</code></h1>
6+
</center>
57

68
`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.
79
It provides native, easy-to-use components to create compilers codegen backend. It contains LLVM bindings,
810
components and toolset for efficiently use LLVM as compilers backend implementation on Swift.
911

12+
## Overview
13+
14+
The `llvm-api-swift` provides a robust and comprehensive interface to the LLVM Compiler Infrastructure,
15+
leveraging the `LLVM-C API` to offer a blend of safety, flexibility, and extendability. This library
16+
is designed to serve as a powerful tool for developers looking to create backends for compilers, enabling
17+
them to harness the full potential of **LLVM** in a secure and user-friendly manner.
18+
19+
## Safety
20+
21+
Safety is a paramount concern in the design of this library. By building on the `LLVM-C API`, we ensure that
22+
interactions
23+
with the **LLVM** infrastructure are conducted in a type-safe and memory-safe manner. The library employs Swift’s
24+
stringent
25+
safety guarantees to prevent common issues such as null pointer dereferencing, buffer overflows, and memory leaks. This
26+
commitment to safety allows developers to focus on the functionality of their compiler backends without worrying about
27+
underlying security vulnerabilities.
28+
29+
## Flexibility
30+
31+
Flexibility is another core attribute of the `llvm-api-swift`. The library provides a rich set of APIs that cover a wide
32+
range of LLVM’s capabilities, from module management and inline assembly to debugging metadata and function iteration.
33+
Developers can easily access and manipulate **LLVM** constructs, enabling the creation of highly customized and
34+
optimized
35+
compiler backends. The library’s design ensures that it can adapt to various use cases and requirements, making it an
36+
ideal choice for a diverse set of compiler development projects based on Swift.
37+
38+
## Extendability
39+
40+
The 'llvm-api-swift' is built with extendability in mind. It is designed to be easily extendable, allowing developers to
41+
add
42+
new functionalities and support for additional **LLVM** features as needed. The modular structure of the library
43+
facilitates
44+
the incorporation of new components, ensuring that it can grow and evolve alongside the **LLVM** ecosystem. This
45+
extendability ensures that the library remains relevant and useful as **LLVM** continues to advance and expand its
46+
capabilities.
47+
48+
## Why LLVM?
49+
50+
**LLVM** (Low-Level Virtual Machine) is a powerful and versatile compiler infrastructure that provides a collection of
51+
modular and reusable compiler and toolchain technologies. It is widely used in the development of modern compilers,
52+
providing a framework for optimizing intermediate representations and generating machine code for various target
53+
architectures. LLVM’s ability to support multiple languages and platforms, coupled with its extensive optimization
54+
capabilities, makes it an essential tool for compiler developers. By leveraging **LLVM**, developers can create highly
55+
efficient and portable compilers that meet the demands of today’s diverse computing environments.
56+
57+
## Design
58+
59+
The `llvm-api-awift` library adheres to the structure of the `LLVM C API`, ensuring easy navigation through the extensive LLVM
60+
functions. Logical elements are grouped into modules, providing a clear organizational structure. Within these modules,
61+
Rust structures are introduced to wrap LLVM types, implementing corresponding functions for the wrapped LLVM types. This
62+
approach enhances flexibility and usability while maintaining the original LLVM code structure. The design avoids
63+
unnecessary complexity in the code and documentation, remaining fully aligned with the `LLVM API`. This alignment allows
64+
developers to easily navigate the `llvm-api-swift` library using existing LLVM-C documentation.
65+
1066
### Compatibility with LLVM-C API
1167

1268
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`.
1571
When implementing Swift types, we were guided by the approach of abstracting away from C types, completely transforming them into Swift types.
1672
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.
1773

18-
19-
### Requirements
74+
## Requirements
2075

2176
- Supported OS: MacOS 12.0 or above
2277

llvm-api/LLVM/Core/Context.swift

+8-1
Original file line numberDiff line numberDiff line change
@@ -222,12 +222,19 @@ public final class Context: ContextRef {
222222
}
223223
}
224224

225+
///Destroy a context instance.
226+
///
227+
/// This should be called for every call to LLVMContextCreate() or memory will be leaked.
228+
public func dispose() {
229+
LLVMContextDispose(llvm)
230+
}
231+
225232
/// Deinitialize this value and dispose of its resources.
226233
///
227234
/// Destroy a context instance.
228235
/// This should be called for every call to LLVMContextCreate() or memory
229236
/// will be leaked.
230237
deinit {
231-
LLVMContextDispose(llvm)
238+
self.dispose()
232239
}
233240
}

llvm-api/LLVM/Core/Modules.swift

+191-13
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,152 @@ public final class Module: ModuleRef {
99
/// Retrieves the underlying LLVM value object.
1010
public var moduleRef: LLVMModuleRef { llvm }
1111

12+
public enum InlineAsmDialect {
13+
case att
14+
case intel
15+
}
16+
17+
/// Named Metadata Node
18+
public class NamedMetadataNode: NamedMetadataNodeRef {
19+
private var llvm: LLVMNamedMDNodeRef
20+
21+
/// Retrieves the underlying LLVM value object.
22+
public var namedMetadataNodeRef: LLVMNamedMDNodeRef { llvm }
23+
24+
init(llvm: LLVMNamedMDNodeRef) {
25+
self.llvm = llvm
26+
}
27+
28+
/// Advance a `NamedMetaDataNode` iterator to the next `NamedMetaDataNode`.
29+
///
30+
/// Returns NULL if the iterator was already at the end and there are no more
31+
/// named metadata nodes.
32+
public func getNext() -> NamedMetadataNode? {
33+
guard let nextRef = LLVMGetNextNamedMetadata(llvm) else {
34+
return nil
35+
}
36+
return NamedMetadataNode(llvm: nextRef)
37+
}
38+
39+
/// Decrement a `NamedMetaDataNode` iterator to the previous `NamedMetaDataNode`.
40+
///
41+
/// Returns NULL if the iterator was already at the beginning and there are
42+
/// no previously named metadata nodes.
43+
public func getPrevious() -> NamedMetadataNode? {
44+
guard let prevRef = LLVMGetPreviousNamedMetadata(llvm) else {
45+
return nil
46+
}
47+
return NamedMetadataNode(llvm: prevRef)
48+
}
49+
50+
/// Retrieve the name of a `NamedMetadataNode`.
51+
public func getName() -> String? {
52+
var length: size_t = 0
53+
guard let cStr = LLVMGetNamedMetadataName(llvm, &length) else {
54+
return nil
55+
}
56+
return String(cString: cStr)
57+
}
58+
}
59+
60+
/// Enumerates the supported behaviors for resolving collisions when two
61+
/// module flags share the same key. These collisions can occur when the
62+
/// different flags are inserted under the same key, or when modules
63+
/// containing flags under the same key are merged.
64+
public enum ModuleFlagBehavior {
65+
/// Emits an error if two values disagree, otherwise the resulting value
66+
/// is that of the operands.
67+
case error
68+
/// Emits a warning if two values disagree. The result value will be the
69+
/// operand for the flag from the first module being linked.
70+
case warning
71+
/// Adds a requirement that another module flag be present and have a
72+
/// specified value after linking is performed. The value must be a
73+
/// metadata pair, where the first element of the pair is the ID of the
74+
/// module flag to be restricted, and the second element of the pair is
75+
/// the value the module flag should be restricted to. This behavior can
76+
/// be used to restrict the allowable results (via triggering of an error)
77+
/// of linking IDs with the **Override** behavior.
78+
case require
79+
/// Uses the specified value, regardless of the behavior or value of the
80+
/// other module. If both modules specify **Override**, but the values
81+
/// differ, an error will be emitted.
82+
case override
83+
/// Appends the two values, which are required to be metadata nodes.
84+
case append
85+
/// Appends the two values, which are required to be metadata
86+
/// nodes. However, duplicate entries in the second list are dropped
87+
/// during the append operation.
88+
case appendUnique
89+
90+
init(raw: LLVMModuleFlagBehavior) {
91+
switch raw {
92+
case LLVMModuleFlagBehaviorError:
93+
self = .error
94+
case LLVMModuleFlagBehaviorWarning:
95+
self = .warning
96+
case LLVMModuleFlagBehaviorRequire:
97+
self = .require
98+
case LLVMModuleFlagBehaviorOverride:
99+
self = .override
100+
case LLVMModuleFlagBehaviorAppend:
101+
self = .append
102+
case LLVMModuleFlagBehaviorAppendUnique:
103+
self = .appendUnique
104+
default:
105+
fatalError("Unknown behavior kind")
106+
}
107+
}
108+
}
109+
110+
class Metadata: MetadataRef {
111+
private let llvm:LLVMMetadataRef
112+
public var metadataRef: LLVMMetadataRef {
113+
llvm }
114+
public init(llvm: LLVMMetadataRef ) {
115+
self.llvm = llvm
116+
}
117+
}
118+
119+
public class ModuleFlagEntry {
120+
private let llvm: OpaquePointer?
121+
private let bounds: Int
122+
123+
public init(llvm:OpaquePointer?, bounds: Int) {
124+
self.llvm = llvm
125+
self.bounds = bounds
126+
}
127+
128+
/// Get Metadata flags etries count
129+
public var count: Int { self.bounds }
130+
131+
/// Returns the flag behavior for a module flag entry at a specific index.
132+
public func getFlagBehavior(at index: UInt32) -> ModuleFlagBehavior {
133+
let bh = LLVMModuleFlagEntriesGetFlagBehavior(llvm, index)
134+
return ModuleFlagBehavior(raw: bh)
135+
}
136+
137+
/// Returns the key for a module flag entry at a specific index.
138+
public func getKey(at index: UInt32) -> String {
139+
var length: Int = 0
140+
let keyPointer = LLVMModuleFlagEntriesGetKey(llvm, index, &length)
141+
return String(cString: keyPointer!)
142+
143+
}
144+
145+
/// Returns the metadata for a module flag entry at a specific index.
146+
public func getMetadata(at index: UInt32) -> MetadataRef {
147+
let metadata = LLVMModuleFlagEntriesGetMetadata(llvm, index)!
148+
return Metadata(llvm: metadata)
149+
}
150+
151+
/// Deinitialize this value and dispose of its resources.
152+
deinit {
153+
guard let ptr = llvm else { return }
154+
LLVMDisposeModuleFlagsMetadata(ptr)
155+
}
156+
}
157+
12158
/// Init function by LLVM Value
13159
public init(llvm: LLVMModuleRef) {
14160
self.llvm = llvm
@@ -36,33 +182,46 @@ public final class Module: ModuleRef {
36182
}
37183

38184
/// Return an exact copy of the specified module.
39-
public func clone_nodule() -> ModuleRef {
185+
public func cloneModule() -> Self {
40186
let new_module = LLVMCloneModule(llvm)!
41187
return Self(llvm: new_module)
42188
}
43189

190+
/// Get and Set the identifier of a module.
191+
public var moduleIdentifier: String {
192+
get {
193+
self.getModuleIdentifier
194+
}
195+
set {
196+
self.setModuleIdentifier(identifier: newValue)
197+
}
198+
}
199+
44200
/// Obtain the identifier of a module.
45-
public var getLLVMModuleIdentifier: String {
201+
public var getModuleIdentifier: String {
46202
var length: UInt = 0
47203
guard let cString = LLVMGetModuleIdentifier(llvm, &length) else { return "" }
48204
return String(cString: cString)
49205
}
50206

51-
public func setLLVMModuleIdentifier(module: LLVMModuleRef, identifier: String) {
207+
/// Set the identifier of a module to a string Ident with length Len.
208+
public func setModuleIdentifier(identifier: String) {
52209
identifier.withCString { cString in
53-
LLVMSetModuleIdentifier(module, cString, identifier.count)
210+
LLVMSetModuleIdentifier(llvm, cString, identifier.count)
54211
}
55212
}
56213

57-
public var getModuleIdentifier: String? {
58-
var length: UInt = 0
59-
guard let cString = LLVMGetModuleIdentifier(llvm, &length) else {
60-
return nil
214+
/// Get and Set the original source file name of a module to a string Name
215+
public var sourceFileName: String {
216+
get {
217+
self.getSourceFileName!
218+
}
219+
set {
220+
self.setSourceFileName(fileName: newValue)
61221
}
62-
return String(cString: cString)
63222
}
64223

65-
/// Set the identifier of a module to a string Ident with length Len.
224+
///Set the original source file name of a module to a string Name
66225
public func setSourceFileName(fileName: String) {
67226
fileName.withCString { cString in
68227
LLVMSetSourceFileName(llvm, cString, fileName.utf8.count)
@@ -71,17 +230,17 @@ public final class Module: ModuleRef {
71230

72231
/// Obtain the module's original source file name.
73232
public var getSourceFileName: String? {
74-
var length: size_t = 0
233+
var length: Int = 0
75234
guard let cString = LLVMGetSourceFileName(llvm, &length) else {
76235
return nil
77236
}
78237
return String(cString: cString)
79238
}
80239

81240
/// Set the data layout for a module.
82-
public func setDataLayout(module: LLVMModuleRef, dataLayout: String) {
241+
public func setDataLayout(dataLayout: String) {
83242
dataLayout.withCString { cString in
84-
LLVMSetDataLayout(module, cString)
243+
LLVMSetDataLayout(llvm, cString)
85244
}
86245
}
87246

@@ -93,13 +252,32 @@ public final class Module: ModuleRef {
93252
return String(cString: cString)
94253
}
95254

255+
256+
/// Obtain the target triple for a module.
257+
func getTargetTriple() -> String {
258+
guard let targetTriplePointer = LLVMGetTarget(llvm) else {
259+
return ""
260+
}
261+
return String(cString: targetTriplePointer)
262+
}
263+
96264
/// Set the target triple for a module.
97265
public func setTarget(triple: String) {
98266
triple.withCString { cString in
99267
LLVMSetTarget(llvm, cString)
100268
}
101269
}
102270

271+
/// Returns the module flags as an array of flag-key-value triples. The caller
272+
/// is responsible for freeing this array by calling
273+
/// `LLVMDisposeModuleFlagsMetadata`.
274+
public func copyModuleFlagsMetadata() -> ModuleFlagEntry? {
275+
var length: Int = 0
276+
guard let flagsPointer = LLVMCopyModuleFlagsMetadata(llvm, &length) else { return nil }
277+
278+
return ModuleFlagEntry(llvm: flagsPointer, bounds: length)
279+
}
280+
103281
/// Destroy a module instance.
104282
///
105283
/// This must be called for every created module or memory will be leaked.

llvm-api/LLVM/Core/Types/Types.swift

+3-3
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,9 @@ public protocol ModuleRef {
7171
var moduleRef: LLVMModuleRef { get }
7272
}
7373

74-
/// Represents an LLVM Named Metadata Node.
75-
public protocol NamedMDNodeRef {
76-
var namedMDNodeRef: LLVMNamedMDNodeRef { get }
74+
/// Represents an LLVM Named Metadata Node (NamedMDNodeRef).
75+
public protocol NamedMetadataNodeRef {
76+
var namedMetadataNodeRef: LLVMNamedMDNodeRef { get }
7777
}
7878

7979
public protocol OperandBundleRef {

0 commit comments

Comments
 (0)