Skip to content

Commit 2ccb4f7

Browse files
committed
Port the MDBuilder
1 parent 1fb77e6 commit 2ccb4f7

File tree

7 files changed

+475
-2
lines changed

7 files changed

+475
-2
lines changed

Sources/LLVM/IRBuilder.swift

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,13 @@ extension IRBuilder {
9494
get { return LLVMGetCurrentDebugLocation2(self.llvm).map(DebugLocation.init(llvm:)) }
9595
set { LLVMSetCurrentDebugLocation2(self.llvm, newValue?.asMetadata()) }
9696
}
97+
98+
/// Set the floating point math metadata to be used for floating-point
99+
/// operations.
100+
public var defaultFloatingPointMathTag: MDNode? {
101+
get { return LLVMBuilderGetDefaultFPMathTag(self.llvm).map(MDNode.init(llvm:)) }
102+
set { LLVMBuilderSetDefaultFPMathTag(self.llvm, newValue?.asMetadata()) }
103+
}
97104
}
98105

99106
// MARK: Convenience Instructions
@@ -666,8 +673,12 @@ extension IRBuilder {
666673
///
667674
/// - returns: A value representing `void`.
668675
@discardableResult
669-
public func buildCondBr(condition: IRValue, then: BasicBlock, `else`: BasicBlock) -> IRInstruction {
670-
return LLVMBuildCondBr(llvm, condition.asLLVM(), then.asLLVM(), `else`.asLLVM())
676+
public func buildCondBr(
677+
condition: IRValue, then: BasicBlock, `else`: BasicBlock) -> IRInstruction {
678+
guard let instr: IRInstruction = LLVMBuildCondBr(llvm, condition.asLLVM(), then.asLLVM(), `else`.asLLVM()) else {
679+
fatalError("Unable to build conditional branch")
680+
}
681+
return instr
671682
}
672683

673684
/// Build an indirect branch to a label within the current function.

Sources/LLVM/IRGlobal.swift

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#if SWIFT_PACKAGE
22
import cllvm
3+
import llvmshims
34
#endif
45

56
/// An `IRGlobal` is a value, alias, or function that exists at the top level of
@@ -66,6 +67,14 @@ extension IRGlobal {
6667
set { LLVMSetSection(asLLVM(), newValue) }
6768
}
6869

70+
/// Retrieves a global unique identifier for this global value.
71+
///
72+
/// This is a 64 bits hash that is used by PGO and ThinLTO to have a compact
73+
/// unique way to identify a symbol.
74+
public var guid: UInt64 {
75+
return LLVMGlobalGetGUID(self.asLLVM())
76+
}
77+
6978
/// Removes this global value from the module and deallocates it.
7079
///
7180
/// - note: To ensure correct removal of the global value, you must invalidate

Sources/LLVM/IRMetadata.swift

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -388,6 +388,70 @@ public struct NameSpaceMetadata: DIScope {
388388
}
389389
}
390390

391+
/// `MDString` nodes represent string constants in metadata nodes.
392+
public struct MDString: IRMetadata {
393+
private let llvm: LLVMMetadataRef
394+
395+
public init(llvm: LLVMMetadataRef) {
396+
self.llvm = llvm
397+
}
398+
399+
public init(_ value: String) {
400+
self.llvm = LLVMValueAsMetadata(LLVMMDString(value, UInt32(value.count)))
401+
}
402+
403+
public func asMetadata() -> LLVMMetadataRef {
404+
return llvm
405+
}
406+
}
407+
408+
/// `MDNode` nodes represent generic metadata nodes.
409+
public struct MDNode: IRMetadata {
410+
private let llvm: LLVMMetadataRef
411+
412+
public init(llvm: LLVMMetadataRef) {
413+
self.llvm = llvm
414+
}
415+
416+
public init(in context: Context = .global, operands: [IRMetadata]) {
417+
var operands = operands.map { $0.asMetadata() as Optional }
418+
self.llvm = operands.withUnsafeMutableBufferPointer { buf in
419+
return LLVMMDNodeInContext2(context.llvm, buf.baseAddress!, UInt32(buf.count))
420+
}
421+
}
422+
423+
public init(constant: IRConstant) {
424+
self.llvm = LLVMValueAsMetadata(constant.asLLVM())
425+
}
426+
427+
public func asMetadata() -> LLVMMetadataRef {
428+
return llvm
429+
}
430+
}
431+
432+
public class TemporaryMDNode: IRMetadata {
433+
private let llvm: LLVMMetadataRef
434+
435+
required public init(llvm: LLVMMetadataRef) {
436+
self.llvm = llvm
437+
}
438+
439+
public init(in context: Context = .global, operands: [IRMetadata]) {
440+
var operands = operands.map { $0.asMetadata() as Optional }
441+
self.llvm = operands.withUnsafeMutableBufferPointer { buf in
442+
return LLVMTemporaryMDNode(context.llvm, buf.baseAddress!, buf.count)
443+
}
444+
}
445+
446+
deinit {
447+
LLVMDisposeTemporaryMDNode(self.llvm)
448+
}
449+
450+
public func asMetadata() -> LLVMMetadataRef {
451+
return llvm
452+
}
453+
}
454+
391455
/// `ExpressionMetadata` nodes represent expressions that are inspired by the
392456
/// DWARF expression language. They are used in debug intrinsics (such as
393457
/// llvm.dbg.declare and llvm.dbg.value) to describe how the referenced LLVM

Sources/LLVM/MDBuilder.swift

Lines changed: 258 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,258 @@
1+
#if SWIFT_PACKAGE
2+
import cllvm
3+
import llvmshims
4+
#endif
5+
6+
public struct TBAAStructField {
7+
public let offset: Size
8+
public let size: Size
9+
public let type: MDNode
10+
}
11+
12+
public final class MDBuilder {
13+
let context: Context
14+
15+
public init(in context: Context = .global) {
16+
self.context = context
17+
}
18+
}
19+
20+
extension MDBuilder {
21+
public func buildFPMath(_ accuracy: Float) -> MDNode? {
22+
guard accuracy > 0.0 else {
23+
return nil
24+
}
25+
let op = MDNode(constant: FloatType.float.constant(Double(accuracy)))
26+
return MDNode(in: self.context, operands: [ op ])
27+
}
28+
}
29+
30+
extension MDBuilder {
31+
public func buildBranchWeights(_ weights: [Int]) -> MDNode {
32+
precondition(weights.count >= 1, "Branch weights must have at least one value")
33+
var ops = [IRMetadata]()
34+
ops.reserveCapacity(weights.count + 1)
35+
ops.append(MDString("branch_weights"))
36+
let int32Ty = IntType.int32
37+
for weight in weights {
38+
ops.append(MDNode(constant: int32Ty.constant(weight)))
39+
}
40+
return MDNode(in: self.context, operands: ops)
41+
}
42+
}
43+
44+
extension MDBuilder {
45+
public func buildUnpredictable() -> MDNode {
46+
return MDNode(in: self.context, operands: [])
47+
}
48+
}
49+
50+
extension MDBuilder {
51+
public func buildFunctionSectionPrefix(_ prefix: String) -> MDNode {
52+
return MDNode(in: self.context, operands: [
53+
MDString("function_section_prefix"),
54+
MDString(prefix),
55+
])
56+
}
57+
}
58+
59+
extension MDBuilder {
60+
public func buildRange(_ lo: APInt, _ hi: APInt) -> MDNode? {
61+
precondition(lo.bitWidth == hi.bitWidth, "Bitwidth of range limits must match!")
62+
guard lo != hi else {
63+
return nil
64+
}
65+
66+
return MDNode(in: self.context, operands: [
67+
MDNode(llvm: LLVMValueAsMetadata(lo.asLLVM())),
68+
MDNode(llvm: LLVMValueAsMetadata(hi.asLLVM())),
69+
])
70+
}
71+
}
72+
73+
extension MDBuilder {
74+
public func buildCallees(_ callees: [Function]) -> MDNode {
75+
var ops = [IRMetadata]()
76+
ops.reserveCapacity(callees.count)
77+
for callee in callees {
78+
ops.append(MDNode(constant: callee))
79+
}
80+
return MDNode(in: self.context, operands: ops)
81+
}
82+
}
83+
84+
extension MDBuilder {
85+
public func buildCallbackEncoding(_ calleeArgNo: UInt, _ arguments: [Int], varArgPassed: Bool) -> MDNode {
86+
var ops = [IRMetadata]()
87+
let int64 = IntType.int64
88+
ops.append(MDNode(constant: int64.constant(calleeArgNo)))
89+
for argNo in arguments {
90+
ops.append(MDNode(constant: int64.constant(argNo)))
91+
}
92+
ops.append(MDNode(constant: IntType.int1.constant(varArgPassed ? 1 : 0)))
93+
return MDNode(in: self.context, operands: ops)
94+
}
95+
}
96+
97+
extension MDBuilder {
98+
public func buildAnonymousAARoot(_ name: String, _ extra: MDNode? = nil) -> MDNode {
99+
// To ensure uniqueness the root node is self-referential.
100+
let dummy = TemporaryMDNode(in: self.context, operands: [])
101+
var ops = [IRMetadata]()
102+
if let extra = extra {
103+
ops.append(extra)
104+
}
105+
if !name.isEmpty {
106+
ops.append(MDString(name))
107+
}
108+
let root = MDNode(in: self.context, operands: ops)
109+
// At this point we have
110+
// !0 = metadata !{} <- dummy
111+
// !1 = metadata !{metadata !0} <- root
112+
// Replace the dummy operand with the root node itself and delete the dummy.
113+
dummy.replaceAllUses(with: root)
114+
// We now have
115+
// !1 = metadata !{metadata !1} <- self-referential root
116+
return root
117+
}
118+
119+
public func buildTBAARoot(_ name: String) -> MDNode {
120+
return MDNode(in: self.context, operands: [ MDString(name) ])
121+
}
122+
123+
public func buildTBAANode(_ name: String, parent: MDNode, isConstant: Bool) -> MDNode {
124+
if isConstant {
125+
let flags = IntType.int64.constant(1)
126+
return MDNode(in: self.context, operands: [
127+
MDString(name),
128+
parent,
129+
MDNode(constant: flags)
130+
])
131+
}
132+
return MDNode(in: self.context, operands: [
133+
MDString(name),
134+
parent
135+
])
136+
}
137+
138+
public func buildAliasScopeDomain(_ name: String, _ domain: MDNode? = nil) -> MDNode {
139+
if let domain = domain {
140+
return MDNode(in: self.context, operands: [ MDString(name), domain ])
141+
}
142+
return MDNode(in: self.context, operands: [ MDString(name) ])
143+
}
144+
145+
public func buildTBAAStructNode(_ fields: [TBAAStructField]) -> MDNode {
146+
var ops = [IRMetadata]()
147+
ops.reserveCapacity(fields.count * 3)
148+
let int64 = IntType.int64
149+
for field in fields {
150+
ops.append(MDNode(constant: int64.constant(field.offset.rawValue)))
151+
ops.append(MDNode(constant: int64.constant(field.size.rawValue)))
152+
ops.append(field.type)
153+
}
154+
return MDNode(in: self.context, operands: ops)
155+
}
156+
157+
public func buildTBAAStructTypeName(_ name: String, fields: [(MDNode, Size)]) -> MDNode {
158+
var ops = [IRMetadata]()
159+
ops.reserveCapacity(fields.count * 2 + 1)
160+
let int64 = IntType.int64
161+
ops.append(MDString(name))
162+
for (type, offset) in fields {
163+
ops.append(type)
164+
ops.append(MDNode(constant: int64.constant(offset.rawValue)))
165+
}
166+
return MDNode(in: self.context, operands: ops)
167+
}
168+
169+
public func buildTBAAScalarTypeNode(_ name: String, _ parent: MDNode, _ offset: Size) -> MDNode {
170+
let off = IntType.int64.constant(offset.rawValue)
171+
return MDNode(in: self.context, operands: [
172+
MDString(name),
173+
parent,
174+
MDNode(constant: off)
175+
])
176+
}
177+
178+
public func buildTBAAStructTagNode(_ baseType: MDNode, _ accessType: MDNode, _ offset: Size, _ isConstant: Bool) -> MDNode {
179+
let int64 = IntType.int64
180+
let off = int64.constant(offset.rawValue)
181+
if isConstant {
182+
return MDNode(in: self.context, operands: [
183+
baseType,
184+
accessType,
185+
MDNode(constant: off),
186+
MDNode(constant: int64.constant(1))
187+
])
188+
}
189+
return MDNode(in: self.context, operands: [
190+
baseType,
191+
accessType,
192+
MDNode(constant: off),
193+
])
194+
}
195+
196+
public func buildTBAATypeNode(_ parent: MDNode, _ size: Size, _ id: IRMetadata, _ fields: [TBAAStructField]) -> MDNode {
197+
var ops = [IRMetadata]()
198+
ops.reserveCapacity(3 + fields.count * 3)
199+
let int64 = IntType.int64
200+
ops.append(parent)
201+
ops.append(MDNode(constant: int64.constant(size.rawValue)))
202+
ops.append(id)
203+
for field in fields {
204+
ops.append(field.type)
205+
ops.append(MDNode(constant: int64.constant(field.offset.rawValue)))
206+
ops.append(MDNode(constant: int64.constant(field.size.rawValue)))
207+
}
208+
return MDNode(in: self.context, operands: ops)
209+
}
210+
211+
public func buildTBAAAccessTag(_ baseType: MDNode, _ accessType: MDNode, _ offset: Size, _ size: Size, _ isImmutable: Bool) -> MDNode {
212+
let int64 = IntType.int64
213+
let off = MDNode(constant: int64.constant(offset.rawValue))
214+
let siz = MDNode(constant: int64.constant(size.rawValue))
215+
if isImmutable {
216+
return MDNode(in: self.context, operands: [
217+
baseType,
218+
accessType,
219+
off,
220+
siz,
221+
MDNode(constant: int64.constant(1)),
222+
])
223+
}
224+
return MDNode(in: self.context, operands: [
225+
baseType,
226+
accessType,
227+
off,
228+
siz,
229+
])
230+
}
231+
}
232+
233+
extension MDBuilder {
234+
public func buildIrrLoopHeaderWeight(_ weight: UInt64) -> MDNode {
235+
return MDNode(in: self.context, operands: [
236+
MDString("loop_header_weight"),
237+
MDNode(constant: IntType.int64.constant(weight))
238+
])
239+
}
240+
}
241+
242+
extension MDBuilder {
243+
public func buildFunctionEntryCount(_ count: UInt64, _ synthetic: Bool, _ imports: Set<UInt64>) -> MDNode {
244+
let int64 = IntType.int64
245+
var ops = [IRMetadata]()
246+
if synthetic {
247+
ops.append(MDString("synthetic_function_entry_count"))
248+
} else {
249+
ops.append(MDString("function_entry_count"))
250+
}
251+
ops.append(MDNode(constant: int64.constant(count)))
252+
for id in imports.sorted() {
253+
ops.append(MDNode(constant: int64.constant(id)))
254+
}
255+
return MDNode(in: self.context, operands: ops)
256+
}
257+
}
258+

0 commit comments

Comments
 (0)