Skip to content

Commit e54b433

Browse files
authored
Merge pull request #199 from CodaFi/mdbuilder
Port MDBuilder
2 parents 1fb77e6 + 17cab0f commit e54b433

File tree

7 files changed

+874
-4
lines changed

7 files changed

+874
-4
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: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ public protocol _IRMetadataInitializerHack {
2222
/// Metadata does not have a type, and is not a value. If referenced from a call
2323
/// instruction, it uses the metadata type.
2424
///
25+
/// Debug Information
26+
/// =================
27+
///
2528
/// The idea of LLVM debugging information is to capture how the important
2629
/// pieces of the source-language’s Abstract Syntax Tree map onto LLVM code.
2730
/// LLVM takes a number of positions on the impact of the broader compilation
@@ -388,6 +391,129 @@ public struct NameSpaceMetadata: DIScope {
388391
}
389392
}
390393

394+
/// `MDString` nodes represent string constants in metadata nodes.
395+
public struct MDString: IRMetadata, ExpressibleByStringLiteral {
396+
public typealias StringLiteralType = String
397+
398+
private let llvm: LLVMMetadataRef
399+
400+
public init(llvm: LLVMMetadataRef) {
401+
self.llvm = llvm
402+
}
403+
404+
/// Create an `MDString` node from the given string value.
405+
///
406+
/// - Parameters:
407+
/// - value: The string value to assign to this metadata node.
408+
public init(_ value: String) {
409+
self.llvm = LLVMValueAsMetadata(LLVMMDString(value, UInt32(value.count)))
410+
}
411+
412+
public init(stringLiteral value: String) {
413+
self.llvm = LLVMValueAsMetadata(LLVMMDString(value, UInt32(value.count)))
414+
}
415+
416+
public func asMetadata() -> LLVMMetadataRef {
417+
return llvm
418+
}
419+
}
420+
421+
/// `MDNode` objects represent generic nodes in a metadata graph.
422+
///
423+
/// A metadata node is a tuple of references to other metadata. In general,
424+
/// metadata graphs are acyclic and terminate in metadata nodes without
425+
/// operands.
426+
public struct MDNode: IRMetadata {
427+
private let llvm: LLVMMetadataRef
428+
429+
public init(llvm: LLVMMetadataRef) {
430+
self.llvm = llvm
431+
}
432+
433+
/// Create a metadata node in the given context with the given operands.
434+
///
435+
/// - Parameters:
436+
/// - context: The context to allocate the node in.
437+
/// - operands: The operands to attach to the metadata node.
438+
public init(in context: Context = .global, operands: [IRMetadata]) {
439+
var operands = operands.map { $0.asMetadata() as Optional }
440+
self.llvm = operands.withUnsafeMutableBufferPointer { buf in
441+
return LLVMMDNodeInContext2(context.llvm, buf.baseAddress!, UInt32(buf.count))
442+
}
443+
}
444+
445+
/// Create a metadata node with the value of a given constant.
446+
///
447+
/// - Parameters:
448+
/// - constant: The constant value to attach to the node.
449+
public init(constant: IRConstant) {
450+
self.llvm = LLVMValueAsMetadata(constant.asLLVM())
451+
}
452+
453+
public func asMetadata() -> LLVMMetadataRef {
454+
return llvm
455+
}
456+
}
457+
458+
/// Represents a temporary metadata node.
459+
///
460+
/// Temporary metadata nodes aid in the construction of cyclic metadata. The
461+
/// typical construction pattern is usually as follows:
462+
///
463+
/// // Allocate a temporary temp node
464+
/// let temp = TemporaryMDNode(in: context, operands: [])
465+
/// // Prepare the operands to the metadata node...
466+
/// var ops = [IRMetadata]()
467+
/// // ...
468+
/// // Create the real node
469+
/// let root = MDNode(in: context, operands: ops)
470+
///
471+
/// At this point we have the following metadata structure:
472+
///
473+
/// // !0 = metadata !{} <- temp
474+
/// // !1 = metadata !{metadata !0} <- root
475+
/// // Replace the temp operand with the root node
476+
///
477+
/// The knot is tied by RAUW'ing the temporary node:
478+
///
479+
/// temp.replaceAllUses(with: root)
480+
/// // We now have
481+
/// // !1 = metadata !{metadata !1} <- self-referential root
482+
///
483+
/// - Warning: It is critical that temporary metadata nodes be "RAUW'd"
484+
/// (replace-all-uses-with) before the metadata graph is finalized. After
485+
/// that time, all remaining temporary metadata nodes will become unresolved
486+
/// metadata.
487+
public class TemporaryMDNode: IRMetadata {
488+
private let llvm: LLVMMetadataRef
489+
490+
required public init(llvm: LLVMMetadataRef) {
491+
self.llvm = llvm
492+
}
493+
494+
/// Create a new temporary metadata node in the given context with the
495+
/// given operands.
496+
///
497+
/// - Parameters:
498+
/// - context: The context to allocate the node in.
499+
/// - operands: The operands to attach to the metadata node.
500+
public init(in context: Context = .global, operands: [IRMetadata]) {
501+
var operands = operands.map { $0.asMetadata() as Optional }
502+
self.llvm = operands.withUnsafeMutableBufferPointer { buf in
503+
return LLVMTemporaryMDNode(context.llvm, buf.baseAddress!, buf.count)
504+
}
505+
}
506+
507+
/// Deinitialize this value and dispose of its resources.
508+
deinit {
509+
LLVMDisposeTemporaryMDNode(self.llvm)
510+
}
511+
512+
public func asMetadata() -> LLVMMetadataRef {
513+
return llvm
514+
}
515+
}
516+
391517
/// `ExpressionMetadata` nodes represent expressions that are inspired by the
392518
/// DWARF expression language. They are used in debug intrinsics (such as
393519
/// llvm.dbg.declare and llvm.dbg.value) to describe how the referenced LLVM

0 commit comments

Comments
 (0)