Skip to content

A Hodge-Podge of Fixes and Features #98

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 5 commits into from
Sep 7, 2017
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
2 changes: 1 addition & 1 deletion Sources/LLVM/Global.swift
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public struct Global: IRGlobal {

/// Accesses the model of reference for this global variable if it is
/// thread-local.
public var threadLocalMode: ThreadLocalModel {
public var threadLocalModel: ThreadLocalModel {
get { return ThreadLocalModel(llvm: LLVMGetThreadLocalMode(asLLVM())) }
set { LLVMSetThreadLocalMode(asLLVM(), newValue.llvm) }
}
Expand Down
73 changes: 64 additions & 9 deletions Sources/LLVM/IRBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -200,10 +200,8 @@ public enum AtomicOrdering: Comparable {
.sequentiallyConsistent: LLVMAtomicOrderingSequentiallyConsistent,
]

public static func ==(lhs: AtomicOrdering, rhs: AtomicOrdering) -> Bool {
return lhs.llvm == rhs.llvm
}

/// Returns whether the left atomic ordering is strictly weaker than the
/// right atomic order.
public static func <(lhs: AtomicOrdering, rhs: AtomicOrdering) -> Bool {
return lhs.llvm.rawValue < rhs.llvm.rawValue
}
Expand Down Expand Up @@ -1094,25 +1092,40 @@ public class IRBuilder {
return LLVMBuildAlloca(llvm, type.asLLVM(), name)
}

/// Build a store instruction that stores the first value into the location
/// Builds a store instruction that stores the first value into the location
/// given in the second value.
///
/// - parameter val: The source value.
/// - parameter ptr: The destination pointer to store into.
/// - parameter ordering: The ordering effect of the fence for this store,
/// if any. Defaults to a nonatomic store.
/// - parameter volatile: Whether this is a store to a volatile memory location.
///
/// - returns: A value representing `void`.
@discardableResult
public func buildStore(_ val: IRValue, to ptr: IRValue) -> IRValue {
return LLVMBuildStore(llvm, val.asLLVM(), ptr.asLLVM())
public func buildStore(_ val: IRValue, to ptr: IRValue, ordering: AtomicOrdering = .notAtomic, volatile: Bool = false) -> IRValue {
let storeInst = LLVMBuildStore(llvm, val.asLLVM(), ptr.asLLVM())!
LLVMSetOrdering(storeInst, ordering.llvm)
LLVMSetVolatile(storeInst, volatile.llvm)
return storeInst
}

/// Builds a load instruction that loads a value from the location in the
/// given value.
///
/// - parameter ptr: The pointer value to load from.
/// - parameter ordering: The ordering effect of the fence for this load,
/// if any. Defaults to a nonatomic load.
/// - parameter volatile: Whether this is a load from a volatile memory location.
/// - parameter name: The name for the newly inserted instruction.
///
/// - returns: A value representing the result of a load from the given
/// pointer value.
public func buildLoad(_ ptr: IRValue, name: String = "") -> IRValue {
return LLVMBuildLoad(llvm, ptr.asLLVM(), name)
public func buildLoad(_ ptr: IRValue, ordering: AtomicOrdering = .notAtomic, volatile: Bool = false, name: String = "") -> IRValue {
let loadInst = LLVMBuildLoad(llvm, ptr.asLLVM(), name)!
LLVMSetOrdering(loadInst, ordering.llvm)
LLVMSetVolatile(loadInst, volatile.llvm)
return loadInst
}

/// Builds a `GEP` (Get Element Pointer) instruction with a resultant value
Expand Down Expand Up @@ -1706,6 +1719,48 @@ public class IRBuilder {
return Alias(llvm: LLVMAddAlias(module.llvm, type.asLLVM(), aliasee.asLLVM(), name))
}

// MARK: Inline Assembly

/// Builds a value representing an inline assembly expression (as opposed to
/// module-level inline assembly).
///
/// LLVM represents inline assembler as a template string (containing the
/// instructions to emit), a list of operand constraints (stored as a string),
/// and some flags.
///
/// The template string supports argument substitution of the operands using
/// "$" followed by a number, to indicate substitution of the given
/// register/memory location, as specified by the constraint string.
/// "${NUM:MODIFIER}" may also be used, where MODIFIER is a target-specific
/// annotation for how to print the operand (see [Asm Template Argument
/// Modifiers](https://llvm.org/docs/LangRef.html#inline-asm-modifiers)).
///
/// LLVM’s support for inline asm is modeled closely on the requirements of
/// Clang’s GCC-compatible inline-asm support. Thus, the feature-set and the
/// constraint and modifier codes are similar or identical to those in GCC’s
/// inline asm support.
///
/// However, the syntax of the template and constraint strings is not the
/// same as the syntax accepted by GCC and Clang, and, while most constraint
/// letters are passed through as-is by Clang, some get translated to other
/// codes when converting from the C source to the LLVM assembly.
///
/// - parameter asm: The inline assembly expression template string.
/// - parameter type: The type of the parameters and return value of the
/// assembly expression string.
/// - parameter constraints: A comma-separated string, each element containing
/// one or more constraint codes.
/// - parameter hasSideEffects: Whether this inline asm expression has
/// side effects. Defaults to `false`.
/// - parameter needsAlignedStack: Whether the function containing the
/// asm needs to align its stack conservatively. Defaults to `true`.
///
/// - returns: A representation of the newly created inline assembly
/// expression.
public func buildInlineAssembly(_ asm: String, type: FunctionType, constraints: String = "", hasSideEffects: Bool = true, needsAlignedStack: Bool = true) -> IRValue {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a URL we can point to for more information? Or is this documentation already better than the existing LLVM doc...?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This kind of is LLVM's docs on this. Paraphrased and updated a bit with references to external stuff.

return LLVMConstInlineAsm(type.asLLVM(), asm, constraints, hasSideEffects.llvm, needsAlignedStack.llvm)
}

deinit {
LLVMDisposeBuilder(llvm)
}
Expand Down
6 changes: 6 additions & 0 deletions Sources/LLVM/Switch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ public struct Switch: IRValue {
LLVMAddCase(llvm, value.asLLVM(), block.asLLVM())
}

/// Retrieves the basic block the flow of control reaches should a
/// value not match any of the cases in the branch table.
var defaultDestination: BasicBlock {
return BasicBlock(llvm: LLVMGetSwitchDefaultDest(self.llvm))
}

/// Retrieves the underlying LLVM value object.
public func asLLVM() -> LLVMValueRef {
return llvm
Expand Down
6 changes: 6 additions & 0 deletions Tests/LLVMTests/IRBuilderSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,12 @@ class IRBuilderSpec : XCTestCase {
// CONTROLFLOW-NEXT: store i64 1, i64* %var
builder.buildStore(IntType.int64.constant(1), to: variable)

// CONTROLFLOW-NEXT: store volatile i64 1, i64* %var
builder.buildStore(IntType.int64.constant(1), to: variable, volatile: true)

// CONTROLFLOW-NEXT: store atomic i64 1, i64* %var
builder.buildStore(IntType.int64.constant(1), to: variable, ordering: .sequentiallyConsistent)

// CONTROLFLOW-NEXT: %0 = load i64, i64* %var
let load = builder.buildLoad(variable)

Expand Down