Skip to content

Commit 32136b5

Browse files
committed
Extract attached metadata and add a test
1 parent c486e8e commit 32136b5

File tree

4 files changed

+251
-137
lines changed

4 files changed

+251
-137
lines changed

Sources/LLVM/AttachedMetadata.swift

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
#if SWIFT_PACKAGE
2+
import cllvm
3+
#endif
4+
5+
extension Context {
6+
/// Searches for and retrieves a metadata kind with the given name in this
7+
/// context. If none is found, one with that name is created and its unique
8+
/// identifier is returned.
9+
public func metadataKind(named name: String, in context: Context = .global) -> UInt32 {
10+
return LLVMGetMDKindIDInContext(context.llvm, name, UInt32(name.count))
11+
}
12+
}
13+
14+
extension IRGlobal {
15+
/// Retrieves all metadata entries attached to this global value.
16+
public var metadata: AttachedMetadata {
17+
var count = 0
18+
let ptr = LLVMGlobalCopyAllMetadata(self.asLLVM(), &count)
19+
return AttachedMetadata(llvm: ptr, bounds: count)
20+
}
21+
22+
/// Sets a metadata attachment, erasing the existing metadata attachment if
23+
/// it already exists for the given kind.
24+
///
25+
/// - Parameters:
26+
/// - metadata: The metadata to attach to this global value.
27+
/// - kind: The kind of metadata to attach.
28+
public func addMetadata(_ metadata: IRMetadata, kind: AttachedMetadata.PinnedKind) {
29+
LLVMGlobalSetMetadata(self.asLLVM(), kind.rawValue, metadata.asMetadata())
30+
}
31+
32+
/// Sets a metadata attachment, erasing the existing metadata attachment if
33+
/// it already exists for the given kind.
34+
///
35+
/// - Parameters:
36+
/// - metadata: The metadata to attach to this global value.
37+
/// - kind: The kind of metadata to attach.
38+
public func addMetadata(_ metadata: IRMetadata, kind: UInt32) {
39+
LLVMGlobalSetMetadata(self.asLLVM(), kind, metadata.asMetadata())
40+
}
41+
42+
/// Removes all metadata attachments from this value.
43+
public func removeAllMetadata() {
44+
LLVMGlobalClearMetadata(self.asLLVM())
45+
}
46+
47+
/// Erases a metadata attachment of the given kind if it exists.
48+
///
49+
/// - Parameter kind: The kind of the metadata to remove.
50+
public func eraseAllMetadata(of kind: UInt32) {
51+
LLVMGlobalEraseMetadata(self.asLLVM(), kind)
52+
}
53+
}
54+
55+
extension Instruction {
56+
/// Retrieves all metadata entries attached to this instruction.
57+
public var metadata: AttachedMetadata {
58+
var count = 0
59+
let ptr = LLVMGlobalCopyAllMetadata(self.asLLVM(), &count)
60+
return AttachedMetadata(llvm: ptr, bounds: count)
61+
}
62+
63+
/// Sets a metadata attachment, erasing the existing metadata attachment if
64+
/// it already exists for the given kind.
65+
///
66+
/// - Parameters:
67+
/// - metadata: The metadata to attach to this global value.
68+
/// - kind: The kind of metadata to attach.
69+
public func addMetadata(_ metadata: IRMetadata, kind: AttachedMetadata.PinnedKind) {
70+
LLVMSetMetadata(self.asLLVM(), kind.rawValue, LLVMMetadataAsValue(self.type.context.llvm, metadata.asMetadata()))
71+
}
72+
73+
/// Sets a metadata attachment, erasing the existing metadata attachment if
74+
/// it already exists for the given kind.
75+
///
76+
/// - Parameters:
77+
/// - metadata: The metadata to attach to this global value.
78+
/// - kind: The kind of metadata to attach.
79+
public func addMetadata(_ metadata: IRMetadata, kind: UInt32) {
80+
LLVMSetMetadata(self.asLLVM(), kind, LLVMMetadataAsValue(self.type.context.llvm, metadata.asMetadata()))
81+
}
82+
}
83+
84+
/// Represents a sequence of metadata entries attached to a global value that
85+
/// are uniqued by kind.
86+
public class AttachedMetadata {
87+
/// Metadata kinds that are known to LLVM.
88+
public enum PinnedKind: UInt32 {
89+
/// "dbg"
90+
case dbg = 0
91+
/// "tbaa"
92+
case tbaa = 1
93+
/// "prof"
94+
case prof = 2
95+
/// "fpmath"
96+
case fpmath = 3
97+
/// "range"
98+
case range = 4
99+
/// "tbaa.struct"
100+
case tbaaStruct = 5
101+
/// "invariant.load"
102+
case invariantLoad = 6
103+
/// "alias.scope"
104+
case alias_scope = 7
105+
/// "noalias",
106+
case noalias = 8
107+
/// "nontemporal"
108+
case nontemporal = 9
109+
/// "llvm.mem.parallel_loop_access"
110+
case memParallelLoopAccess = 10
111+
/// "nonnull"
112+
case nonnull = 11
113+
/// "dereferenceable"
114+
case dereferenceable = 12
115+
/// "dereferenceable_or_null"
116+
case dereferenceable_or_null = 13
117+
/// "make.implicit"
118+
case makeImplicit = 14
119+
/// "unpredictable"
120+
case unpredictable = 15
121+
/// "invariant.group"
122+
case invariantGroup = 16
123+
/// "align"
124+
case align = 17
125+
/// "llvm.loop"
126+
case loop = 18
127+
/// "type"
128+
case type = 19
129+
/// "section_prefix"
130+
case sectionPrefix = 20
131+
/// "absolute_symbol"
132+
case absoluteSymbol = 21
133+
/// "associated"
134+
case associated = 22
135+
/// "callees"
136+
case callees = 23
137+
/// "irr_loop"
138+
case irrLoop = 24
139+
/// "llvm.access.group"
140+
case accessGroup = 25
141+
// "callback"
142+
case callback = 26
143+
}
144+
145+
/// Represents an entry in the module flags structure.
146+
public struct Entry {
147+
fileprivate let base: AttachedMetadata
148+
fileprivate let index: UInt32
149+
150+
/// The metadata kind associated with this global metadata.
151+
public var kind: UInt32 {
152+
return LLVMValueMetadataEntriesGetKind(self.base.llvm, self.index)
153+
}
154+
155+
/// The metadata value associated with this entry.
156+
public var metadata: IRMetadata {
157+
return AnyMetadata(llvm: LLVMValueMetadataEntriesGetMetadata(self.base.llvm, self.index))
158+
}
159+
}
160+
161+
private let llvm: OpaquePointer?
162+
private let bounds: Int
163+
fileprivate init(llvm: OpaquePointer?, bounds: Int) {
164+
self.llvm = llvm
165+
self.bounds = bounds
166+
}
167+
168+
deinit {
169+
guard let ptr = llvm else { return }
170+
LLVMDisposeValueMetadataEntries(ptr)
171+
}
172+
173+
/// Retrieves a flag at the given index.
174+
///
175+
/// - Parameter index: The index to retrieve.
176+
///
177+
/// - Returns: An entry describing the flag at the given index.
178+
public subscript(_ index: Int) -> Entry {
179+
precondition(index >= 0 && index < self.bounds, "Index out of bounds")
180+
return Entry(base: self, index: UInt32(index))
181+
}
182+
183+
public var count: Int {
184+
return self.bounds
185+
}
186+
}

Sources/LLVM/IRGlobal.swift

Lines changed: 0 additions & 137 deletions
Original file line numberDiff line numberDiff line change
@@ -79,140 +79,3 @@ extension IRGlobal {
7979
LLVMDeleteGlobal(self.asLLVM())
8080
}
8181
}
82-
83-
// MARK: Global Metadata
84-
85-
extension IRGlobal {
86-
/// Retrieves all metadata entries attached to this global value.
87-
public var metadata: AttachedMetadata {
88-
var count = 0
89-
let ptr = LLVMGlobalCopyAllMetadata(self.asLLVM(), &count)
90-
return AttachedMetadata(llvm: ptr, bounds: count)
91-
}
92-
93-
/// Sets a metadata attachment, erasing the existing metadata attachment if
94-
/// it already exists for the given kind.
95-
///
96-
/// - Parameters:
97-
/// - metadata: The metadata to attach to this global value.
98-
/// - kind: The kind of metadata to attach.
99-
public func addMetadata(_ metadata: IRMetadata, kind: UInt32) {
100-
LLVMGlobalSetMetadata(self.asLLVM(), kind, metadata.asMetadata())
101-
}
102-
103-
/// Removes all metadata attachments from this value.
104-
public func removeAllMetadata() {
105-
LLVMGlobalClearMetadata(self.asLLVM())
106-
}
107-
108-
/// Erases a metadata attachment of the given kind if it exists.
109-
///
110-
/// - Parameter kind: The kind of the metadata to remove.
111-
public func eraseAllMetadata(of kind: UInt32) {
112-
LLVMGlobalEraseMetadata(self.asLLVM(), kind)
113-
}
114-
}
115-
116-
/// Represents a sequence of metadata entries attached to a global value that
117-
/// are uniqued by kind.
118-
public class AttachedMetadata {
119-
/// Metadata kinds that are known to LLVM.
120-
public enum PinnedMetadataKind: UInt32 {
121-
/// "dbg"
122-
case dbg = 0
123-
/// "tbaa"
124-
case tbaa = 1
125-
/// "prof"
126-
case prof = 2
127-
/// "fpmath"
128-
case fpmath = 3
129-
/// "range"
130-
case range = 4
131-
/// "tbaa.struct"
132-
case tbaaStruct = 5
133-
/// "invariant.load"
134-
case invariantLoad = 6
135-
/// "alias.scope"
136-
case alias_scope = 7
137-
/// "noalias",
138-
case noalias = 8
139-
/// "nontemporal"
140-
case nontemporal = 9
141-
/// "llvm.mem.parallel_loop_access"
142-
case memParallelLoopAccess = 10
143-
/// "nonnull"
144-
case nonnull = 11
145-
/// "dereferenceable"
146-
case dereferenceable = 12
147-
/// "dereferenceable_or_null"
148-
case dereferenceable_or_null = 13
149-
/// "make.implicit"
150-
case makeImplicit = 14
151-
/// "unpredictable"
152-
case unpredictable = 15
153-
/// "invariant.group"
154-
case invariantGroup = 16
155-
/// "align"
156-
case align = 17
157-
/// "llvm.loop"
158-
case loop = 18
159-
/// "type"
160-
case type = 19
161-
/// "section_prefix"
162-
case sectionPrefix = 20
163-
/// "absolute_symbol"
164-
case absoluteSymbol = 21
165-
/// "associated"
166-
case associated = 22
167-
/// "callees"
168-
case callees = 23
169-
/// "irr_loop"
170-
case irrLoop = 24
171-
/// "llvm.access.group"
172-
case accessGroup = 25
173-
// "callback"
174-
case callback = 26
175-
}
176-
177-
/// Represents an entry in the module flags structure.
178-
public struct Entry {
179-
fileprivate let base: AttachedMetadata
180-
fileprivate let index: UInt32
181-
182-
/// The metadata kind associated with this global metadata.
183-
public var kind: UInt32 {
184-
return LLVMValueMetadataEntriesGetKind(self.base.llvm, self.index)
185-
}
186-
187-
/// The metadata value associated with this entry.
188-
public var metadata: IRMetadata {
189-
return AnyMetadata(llvm: LLVMValueMetadataEntriesGetMetadata(self.base.llvm, self.index))
190-
}
191-
}
192-
193-
private let llvm: OpaquePointer?
194-
private let bounds: Int
195-
fileprivate init(llvm: OpaquePointer?, bounds: Int) {
196-
self.llvm = llvm
197-
self.bounds = bounds
198-
}
199-
200-
deinit {
201-
guard let ptr = llvm else { return }
202-
LLVMDisposeValueMetadataEntries(ptr)
203-
}
204-
205-
/// Retrieves a flag at the given index.
206-
///
207-
/// - Parameter index: The index to retrieve.
208-
///
209-
/// - Returns: An entry describing the flag at the given index.
210-
public subscript(_ index: Int) -> Entry {
211-
precondition(index >= 0 && index < self.bounds, "Index out of bounds")
212-
return Entry(base: self, index: UInt32(index))
213-
}
214-
215-
public var count: Int {
216-
return self.bounds
217-
}
218-
}

Tests/LLVMTests/iRMetadataSpec.swift

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
2+
import LLVM
3+
import XCTest
4+
import FileCheck
5+
import Foundation
6+
7+
class IRMetadataSpec : XCTestCase {
8+
func testGlobalMetadata() {
9+
XCTAssert(fileCheckOutput(of: .stderr, withPrefixes: ["IRGLOBALMETADATA"]) {
10+
// IRGLOBALMETADATA: ; ModuleID = '[[ModuleName:IRGLOBALMETADATATest]]'
11+
// IRGLOBALMETADATA-NEXT: source_filename = "[[ModuleName]]"
12+
let module = Module(name: "IRGLOBALMETADATATest")
13+
let builder = IRBuilder(module: module)
14+
let dibuilder = DIBuilder(module: module)
15+
16+
let tag = module.context.metadataKind(named: "custom")
17+
18+
// IRGLOBALMETADATA: @customAttachment = global i8 42, !custom !0
19+
let global = builder.addGlobal("customAttachment", initializer: IntType.int8.constant(42))
20+
21+
// IRGLOBALMETADATA: !0 = !DIBasicType(name: "custom_type", encoding: DW_ATE_address)
22+
let type = dibuilder.buildBasicType(named: "custom_type", encoding: .address, flags: [], size: .zero)
23+
global.addMetadata(type, kind: tag)
24+
25+
module.dump()
26+
})
27+
}
28+
29+
func testInstructionMetadata() {
30+
XCTAssert(fileCheckOutput(of: .stderr, withPrefixes: ["IRINSTRMETADATA"]) {
31+
// IRINSTRMETADATA: ; ModuleID = '[[ModuleName:IRINSTRMETADATATest]]'
32+
// IRINSTRMETADATA-NEXT: source_filename = "[[ModuleName]]"
33+
let module = Module(name: "IRINSTRMETADATATest")
34+
let builder = IRBuilder(module: module)
35+
let dibuilder = DIBuilder(module: module)
36+
37+
let tag = module.context.metadataKind(named: "custom")
38+
39+
// IRINSTRMETADATA: define i32 @test() {
40+
let main = builder.addFunction("test",
41+
type: FunctionType(argTypes: [],
42+
returnType: IntType.int32))
43+
// IRINSTRMETADATA-NEXT: entry:
44+
let entry = main.appendBasicBlock(named: "entry")
45+
builder.positionAtEnd(of: entry)
46+
// IRINSTRMETADATA-NEXT: ret i32 42
47+
builder.buildRet(IntType.int32.constant(42))
48+
49+
let type = dibuilder.buildBasicType(named: "custom_type", encoding: .address, flags: [], size: .zero)
50+
builder.insertBlock?.lastInstruction?.addMetadata(type, kind: tag)
51+
// IRINSTRMETADATA-NEXT: }
52+
53+
// IRINSTRMETADATA: !0 = !DIBasicType(name: "custom_type", encoding: DW_ATE_address)
54+
module.dump()
55+
})
56+
}
57+
58+
#if !os(macOS)
59+
static var allTests = testCase([
60+
("testGlobalMetadata", testGlobalMetadata),
61+
])
62+
#endif
63+
}
64+

0 commit comments

Comments
 (0)