Skip to content

Commit

Permalink
Merge pull request #172 from CodaFi/christmas-declarations
Browse files Browse the repository at this point in the history
Miscellaneous missing bindings from LLVM 7.0
  • Loading branch information
CodaFi authored Dec 26, 2018
2 parents 98b95ab + 79f974d commit 993c0f3
Show file tree
Hide file tree
Showing 5 changed files with 278 additions and 1 deletion.
18 changes: 18 additions & 0 deletions Sources/LLVM/Alias.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,22 @@ public struct Alias: IRGlobal {
public func asLLVM() -> LLVMValueRef {
return llvm
}

/// Access the target value of this alias.
public var aliasee: IRValue {
get { return LLVMAliasGetAliasee(llvm) }
set { LLVMAliasSetAliasee(llvm, newValue.asLLVM()) }
}

/// Retrieves the previous alias in the module, if there is one.
public func previous() -> Alias? {
guard let previous = LLVMGetPreviousGlobalAlias(llvm) else { return nil }
return Alias(llvm: previous)
}

/// Retrieves the next alias in the module, if there is one.
public func next() -> Alias? {
guard let next = LLVMGetNextGlobalAlias(llvm) else { return nil }
return Alias(llvm: next)
}
}
190 changes: 189 additions & 1 deletion Sources/LLVM/Module.swift
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,29 @@ public final class Module: CustomStringConvertible {
}
}

/// Retrieves the sequence of aliases that make up this module.
public var aliases: AnySequence<Alias> {
var current = firstAlias
return AnySequence<Alias> {
return AnyIterator<Alias> {
defer { current = current?.next() }
return current
}
}
}

/// Retrieves the first alias in this module, if there are any aliases.
public var firstAlias: Alias? {
guard let fn = LLVMGetFirstGlobalAlias(llvm) else { return nil }
return Alias(llvm: fn)
}

/// Retrieves the last alias in this module, if there are any aliases.
public var lastAlias: Alias? {
guard let fn = LLVMGetLastGlobalAlias(llvm) else { return nil }
return Alias(llvm: fn)
}

/// The current debug metadata version number.
public static var debugMetadataVersion: UInt32 {
return LLVMDebugMetadataVersion();
Expand Down Expand Up @@ -301,12 +324,24 @@ extension Module {
/// - parameter name: The name of the function to create.
///
/// - returns: A representation of the newly created function with the given
/// name or nil if such a representation could not be created.
/// name or nil if such a representation could not be created.
public func function(named name: String) -> Function? {
guard let fn = LLVMGetNamedFunction(llvm, name) else { return nil }
return Function(llvm: fn)
}

/// Searches for and retrieves an alias with the given name in this module
/// if that name references an existing alias.
///
/// - parameter name: The name of the alias to search for.
///
/// - returns: A representation of an alias with the given
/// name or nil if no such named alias exists.
public func alias(named name: String) -> Alias? {
guard let alias = LLVMGetNamedGlobalAlias(llvm, name, name.count) else { return nil }
return Alias(llvm: alias)
}

/// Searches for and retrieves a comdat section with the given name in this
/// module. If none is found, one with that name is created and returned.
///
Expand Down Expand Up @@ -397,6 +432,159 @@ extension Module {
}
}

// MARK: Module Flags

extension Module {
/// Represents flags that describe information about the module for use by
/// an external entity e.g. the dynamic linker.
///
/// - Warning: Module flags are not a general runtime metadata infrastructure,
/// and may be stripped by LLVM. As of the current release, LLVM hardcodes
/// support for object-file emission of module flags related to
/// Objective-C.
public class Flags {
/// 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 Behavior {
/// 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

fileprivate 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")
}
}

fileprivate static let behaviorMapping: [Behavior: LLVMModuleFlagBehavior] = [
.error: LLVMModuleFlagBehaviorError,
.warning: LLVMModuleFlagBehaviorWarning,
.require: LLVMModuleFlagBehaviorRequire,
.override: LLVMModuleFlagBehaviorOverride,
.append: LLVMModuleFlagBehaviorAppend,
.appendUnique: LLVMModuleFlagBehaviorAppendUnique,
]
}

/// Represents an entry in the module flags structure.
public struct Entry {
fileprivate let base: Flags
fileprivate let index: UInt32

/// The conflict behavior of this flag.
public var behavior: Behavior {
let raw = LLVMModuleFlagEntriesGetFlagBehavior(self.base.llvm, self.index)
return Behavior(raw: raw)
}

/// The key this flag was inserted with.
public var key: String {
var count = 0
guard let key = LLVMModuleFlagEntriesGetKey(self.base.llvm, self.index, &count) else { return "" }
return String(cString: key)
}

/// The metadata value associated with this flag.
public var metadata: IRMetadata {
return AnyMetadata(llvm: LLVMModuleFlagEntriesGetMetadata(self.base.llvm, self.index))
}
}

private let llvm: OpaquePointer?
private let bounds: Int
fileprivate init(llvm: OpaquePointer?, bounds: Int) {
self.llvm = llvm
self.bounds = bounds
}

deinit {
guard let ptr = llvm else { return }
LLVMDisposeModuleFlagsMetadata(ptr)
}

/// Retrieves a flag at the given index.
///
/// - Parameter index: The index to retrieve.
///
/// - Returns: An entry describing the flag at the given index.
public subscript(_ index: Int) -> Entry {
precondition(index >= 0 && index < self.bounds, "Index out of bounds")
return Entry(base: self, index: UInt32(index))
}

public var count: Int {
return self.bounds
}
}

/// Add a module-level flag to the module-level flags metadata.
///
/// - Parameters:
/// - name: The key for this flag.
/// - value: The metadata node to insert as the value for this flag.
/// - behavior: The resolution strategy to apply should the key for this
/// flag conflict with an existing flag.
public func addFlag(named name: String, value: IRMetadata, behavior: Flags.Behavior) {
let raw = Flags.Behavior.behaviorMapping[behavior]!
LLVMAddModuleFlag(llvm, raw, name, name.count, value.asMetadata())
}

/// A convenience for inserting constant values as module-level flags.
///
/// - Parameters:
/// - name: The key for this flag.
/// - value: The constant value to insert as the metadata for this flag.
/// - behavior: The resolution strategy to apply should the key for this
/// flag conflict with an existing flag.
public func addFlag(named name: String, constant: IRConstant, behavior: Flags.Behavior) {
let raw = Flags.Behavior.behaviorMapping[behavior]!
LLVMAddModuleFlag(llvm, raw, name, name.count, LLVMValueAsMetadata(constant.asLLVM()))
}

/// Retrieves the module-level flags, if they exist.
public var flags: Flags? {
var len = 0
guard let raw = LLVMCopyModuleFlagsMetadata(llvm, &len) else { return nil }
return Flags(llvm: raw, bounds: len)
}
}

extension Bool {
internal var llvm: LLVMBool {
return self ? 1 : 0
Expand Down
3 changes: 3 additions & 0 deletions Sources/LLVM/PassManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ public enum FunctionPass {
case loopReroll
/// This pass is a simple loop unrolling pass.
case loopUnroll
/// This pass is a simple loop unroll-and-jam pass.
case loopUnrollAndJam
/// This pass is a simple loop unswitching pass.
case loopUnswitch
/// This pass performs optimizations related to eliminating `memcpy` calls
Expand Down Expand Up @@ -198,6 +200,7 @@ public class FunctionPassManager {
.loopRotate: LLVMAddLoopRotatePass,
.loopReroll: LLVMAddLoopRerollPass,
.loopUnroll: LLVMAddLoopUnrollPass,
.loopUnrollAndJam: LLVMAddLoopUnrollAndJamPass,
.loopUnswitch: LLVMAddLoopUnswitchPass,
.memCpyOpt: LLVMAddMemCpyOptPass,
.partiallyInlineLibCalls: LLVMAddPartiallyInlineLibCallsPass,
Expand Down
67 changes: 67 additions & 0 deletions Tests/LLVMTests/ModuleMetadataSpec.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import LLVM
import XCTest
import FileCheck
import Foundation

class ModuleMetadataSpec : XCTestCase {
func testAddModuleFlags() {
XCTAssertTrue(fileCheckOutput(of: .stderr, withPrefixes: ["MODULE-FLAGS"]) {
// MODULE-FLAGS: ; ModuleID = 'ModuleFlagsTest'
let module = Module(name: "ModuleFlagsTest")
// MODULE-FLAGS: !llvm.module.flags = !{!0, !1, !2, !3, !4, !5}

// MODULE-FLAGS: !0 = !{i32 [[ERRVAL:\d+]], !"error", i32 [[ERRVAL]]}
module.addFlag(named: "error", constant: IntType.int32.constant(1), behavior: .error)
// MODULE-FLAGS-NEXT: !1 = !{i32 [[WARNVAL:\d+]], !"warning", i32 [[WARNVAL]]}
module.addFlag(named: "warning", constant: IntType.int32.constant(2), behavior: .warning)
// MODULE-FLAGS-NEXT: !2 = !{i32 [[REQUIREVAL:\d+]], !"require", i32 [[REQUIREVAL]]}
module.addFlag(named: "require", constant: IntType.int32.constant(3), behavior: .require)
// MODULE-FLAGS-NEXT: !3 = !{i32 [[OVERRIDEVAL:\d+]], !"override", i32 [[OVERRIDEVAL]]}
module.addFlag(named: "override", constant: IntType.int32.constant(4), behavior: .override)
// MODULE-FLAGS-NEXT: !4 = !{i32 [[APPVAL:\d+]], !"append", i32 [[APPVAL]]}
module.addFlag(named: "append", constant: IntType.int32.constant(5), behavior: .append)
// MODULE-FLAGS-NEXT: !5 = !{i32 [[APPUNIQVAL:\d+]], !"appendUnique", i32 [[APPUNIQVAL]]}
module.addFlag(named: "appendUnique", constant: IntType.int32.constant(6), behavior: .appendUnique)

module.dump()
})
}

func testModuleRetrieveFlags() {
let module = Module(name: "ModuleFlagsTest")
module.addFlag(named: "error", constant: IntType.int32.constant(1), behavior: .error)
module.addFlag(named: "warning", constant: IntType.int32.constant(2), behavior: .warning)
module.addFlag(named: "require", constant: IntType.int32.constant(3), behavior: .require)
module.addFlag(named: "override", constant: IntType.int32.constant(4), behavior: .override)
module.addFlag(named: "append", constant: IntType.int32.constant(5), behavior: .append)
module.addFlag(named: "appendUnique", constant: IntType.int32.constant(6), behavior: .appendUnique)

guard let flags = module.flags else {
XCTFail()
return
}

XCTAssertEqual(flags.count, 6)

XCTAssertEqual(flags[0].behavior, .error)
XCTAssertEqual(flags[1].behavior, .warning)
XCTAssertEqual(flags[2].behavior, .require)
XCTAssertEqual(flags[3].behavior, .override)
XCTAssertEqual(flags[4].behavior, .append)
XCTAssertEqual(flags[5].behavior, .appendUnique)

XCTAssertEqual(flags[0].key, "error")
XCTAssertEqual(flags[1].key, "warning")
XCTAssertEqual(flags[2].key, "require")
XCTAssertEqual(flags[3].key, "override")
XCTAssertEqual(flags[4].key, "append")
XCTAssertEqual(flags[5].key, "appendUnique")
}

#if !os(macOS)
static var allTests = testCase([
("testAddModuleFlags", testAddModuleFlags),
("testModuleRetrieveFlags", testModuleRetrieveFlags),
])
#endif
}
1 change: 1 addition & 0 deletions Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ XCTMain([
// FIXME: These tests cannot run on Linux without SEGFAULT'ing.
// JITSpec.allTests,
ModuleLinkSpec.allTests,
ModuleMetadataSpec.allTests,
])
#endif

0 comments on commit 993c0f3

Please sign in to comment.