Skip to content

Miscellaneous missing bindings from LLVM 7.0 #172

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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