Skip to content

Commit

Permalink
Merge pull request #168 from CodaFi/dreamliner
Browse files Browse the repository at this point in the history
Add accessors for inline assembly
  • Loading branch information
CodaFi authored Jan 3, 2019
2 parents 993c0f3 + b90baf4 commit f74e159
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 11 deletions.
19 changes: 17 additions & 2 deletions Sources/LLVM/IRBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1599,11 +1599,26 @@ extension IRBuilder {
///
/// - 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 {
return LLVMConstInlineAsm(type.asLLVM(), asm, constraints, hasSideEffects.llvm, needsAlignedStack.llvm)
public func buildInlineAssembly(
_ asm: String, dialect: InlineAssemblyDialect, type: FunctionType,
constraints: String = "",
hasSideEffects: Bool = true, needsAlignedStack: Bool = true
) -> IRValue {
var asm = asm.utf8CString
var constraints = constraints.utf8CString
return asm.withUnsafeMutableBufferPointer { asm in
return constraints.withUnsafeMutableBufferPointer { constraints in
return LLVMGetInlineAsm(type.asLLVM(),
asm.baseAddress, asm.count,
constraints.baseAddress, constraints.count,
hasSideEffects.llvm, needsAlignedStack.llvm,
dialect.llvm)
}
}
}
}


private func lowerVector(_ type: IRType) -> IRType {
guard let vectorType = type as? VectorType else {
return type
Expand Down
21 changes: 21 additions & 0 deletions Sources/LLVM/Module.swift
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,18 @@ public final class Module: CustomStringConvertible {
}
}

/// Retrieves the inline assembly for this module, if any.
public var inlineAssembly: String {
get {
var length: Int = 0
guard let id = LLVMGetModuleInlineAsm(llvm, &length) else { return "" }
return String(cString: id)
}
set {
LLVMSetModuleInlineAsm2(llvm, newValue, newValue.utf8.count)
}
}

/// Print a representation of a module to a file at the given path.
///
/// If the provided path is not suitable for writing, this function will throw
Expand Down Expand Up @@ -430,6 +442,15 @@ extension Module {
public func addAlias(name: String, to aliasee: IRGlobal, type: IRType) -> Alias {
return Alias(llvm: LLVMAddAlias(llvm, type.asLLVM(), aliasee.asLLVM(), name))
}

/// Append to the module-scope inline assembly blocks.
///
/// A trailing newline is added if the given string doesn't have one.
///
/// - parameter asm: The inline assembly expression template string.
public func appendInlineAssembly(_ asm: String) {
LLVMAppendModuleInlineAsm(llvm, asm, asm.count)
}
}

// MARK: Module Flags
Expand Down
54 changes: 45 additions & 9 deletions Sources/LLVM/Operation.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,16 @@ public enum IntPredicate {
/// less than or equal to the second.
case signedLessThanOrEqual

static let predicateMapping: [IntPredicate: LLVMIntPredicate] = [
private static let predicateMapping: [IntPredicate: LLVMIntPredicate] = [
.equal: LLVMIntEQ, .notEqual: LLVMIntNE, .unsignedGreaterThan: LLVMIntUGT,
.unsignedGreaterThanOrEqual: LLVMIntUGE, .unsignedLessThan: LLVMIntULT,
.unsignedLessThanOrEqual: LLVMIntULE, .signedGreaterThan: LLVMIntSGT,
.signedGreaterThanOrEqual: LLVMIntSGE, .signedLessThan: LLVMIntSLT,
.signedLessThanOrEqual: LLVMIntSLE,
]
]

/// Retrieves the corresponding `LLVMIntPredicate`.
public var llvm: LLVMIntPredicate {
var llvm: LLVMIntPredicate {
return IntPredicate.predicateMapping[self]!
}
}
Expand Down Expand Up @@ -100,7 +100,7 @@ public enum RealPredicate {
/// No comparison, always returns `true`.
case `true`

static let predicateMapping: [RealPredicate: LLVMRealPredicate] = [
private static let predicateMapping: [RealPredicate: LLVMRealPredicate] = [
.false: LLVMRealPredicateFalse, .orderedEqual: LLVMRealOEQ,
.orderedGreaterThan: LLVMRealOGT, .orderedGreaterThanOrEqual: LLVMRealOGE,
.orderedLessThan: LLVMRealOLT, .orderedLessThanOrEqual: LLVMRealOLE,
Expand All @@ -109,10 +109,10 @@ public enum RealPredicate {
.unorderedGreaterThanOrEqual: LLVMRealUGE, .unorderedLessThan: LLVMRealULT,
.unorderedLessThanOrEqual: LLVMRealULE, .unorderedNotEqual: LLVMRealUNE,
.true: LLVMRealPredicateTrue,
]
]

/// Retrieves the corresponding `LLVMRealPredicate`.
public var llvm: LLVMRealPredicate {
var llvm: LLVMRealPredicate {
return RealPredicate.predicateMapping[self]!
}
}
Expand Down Expand Up @@ -207,7 +207,7 @@ public enum AtomicOrdering: Comparable {
}

/// Retrieves the corresponding `LLVMAtomicOrdering`.
public var llvm: LLVMAtomicOrdering {
var llvm: LLVMAtomicOrdering {
return AtomicOrdering.orderingMapping[self]!
}
}
Expand Down Expand Up @@ -290,7 +290,7 @@ public enum AtomicReadModifyWriteOperation {
/// ```
case umin

static let atomicRMWMapping: [AtomicReadModifyWriteOperation: LLVMAtomicRMWBinOp] = [
private static let atomicRMWMapping: [AtomicReadModifyWriteOperation: LLVMAtomicRMWBinOp] = [
.xchg: LLVMAtomicRMWBinOpXchg, .add: LLVMAtomicRMWBinOpAdd,
.sub: LLVMAtomicRMWBinOpSub, .and: LLVMAtomicRMWBinOpAnd,
.nand: LLVMAtomicRMWBinOpNand, .or: LLVMAtomicRMWBinOpOr,
Expand All @@ -300,7 +300,43 @@ public enum AtomicReadModifyWriteOperation {
]

/// Retrieves the corresponding `LLVMAtomicRMWBinOp`.
public var llvm: LLVMAtomicRMWBinOp {
var llvm: LLVMAtomicRMWBinOp {
return AtomicReadModifyWriteOperation.atomicRMWMapping[self]!
}
}

/// Enumerates the dialects of inline assembly LLVM's parsers can handle.
public enum InlineAssemblyDialect {
/// The dialect of assembly created at Bell Labs by AT&T.
///
/// AT&T syntax differs from Intel syntax in a number of ways. Notably:
///
/// - The source operand is before the destination operand
/// - Immediate operands are prefixed by a dollar-sign (`$`)
/// - Register operands are preceded by a percent-sign (`%`)
/// - The size of memory operands is determined from the last character of the
/// the opcode name. Valid suffixes include `b` for "byte" (8-bit),
/// `w` for "word" (16-bit), `l` for "long-word" (32-bit), and `q` for
/// "quad-word" (64-bit) memory references
case att
/// The dialect of assembly created at Intel.
///
/// Intel syntax differs from AT&T syntax in a number of ways. Notably:
///
/// - The destination operand is before the source operand
/// - Immediate and register operands have no prefix.
/// - Memory operands are annotated with their sizes. Valid annotations
/// include `byte ptr` (8-bit), `word ptr` (16-bit), `dword ptr` (32-bit) and
/// `qword ptr` (64-bit).
case intel

private static let dialectMapping: [InlineAssemblyDialect: LLVMInlineAsmDialect] = [
.att: LLVMInlineAsmDialectATT,
.intel: LLVMInlineAsmDialectIntel,
]

/// Retrieves the corresponding `LLVMInlineAsmDialect`.
var llvm: LLVMInlineAsmDialect {
return InlineAssemblyDialect.dialectMapping[self]!
}
}
36 changes: 36 additions & 0 deletions Tests/LLVMTests/IRBuilderSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,42 @@ class IRBuilderSpec : XCTestCase {
module.dump()
})

XCTAssert(fileCheckOutput(of: .stderr, withPrefixes: ["IRBUILDER-INLINE-ASM"]) {
// IRBUILDER-INLINE-ASM: ; ModuleID = '[[ModuleName:IRBuilderInlineAsmTest]]'
// IRBUILDER-INLINE-ASM-NEXT: source_filename = "[[ModuleName]]"
let module = Module(name: "IRBuilderInlineAsmTest")
let builder = IRBuilder(module: module)

// IRBUILDER-INLINE-ASM: module asm "i32 (i32) asm \22bswap $0\22, \22=r,r\22"
module.appendInlineAssembly("""
i32 (i32) asm "bswap $0", "=r,r"
""")
// IRBUILDER-INLINE-ASM-NEXT: %X = call i32 asm \22bswap $0\22, \22=r,r\22(i32 %Y)
module.appendInlineAssembly("""
%X = call i32 asm "bswap $0", "=r,r"(i32 %Y)
""")

// IRBUILDER-INLINE-ASM: @a = global i32 1
let g1 = builder.addGlobal("a", type: IntType.int32)
g1.initializer = Int32(1)

// IRBUILDER-INLINE-ASM: define void @main() {
let main = builder.addFunction("main",
type: FunctionType(argTypes: [],
returnType: VoidType()))
// IRBUILDER-INLINE-ASM-NEXT: entry:
let entry = main.appendBasicBlock(named: "entry")
builder.positionAtEnd(of: entry)
let ty = FunctionType(argTypes: [ PointerType(pointee: IntType.int32) ], returnType: VoidType())
let emptyASM = builder.buildInlineAssembly("", dialect: .att, type: ty, constraints: "=r,0", hasSideEffects: true, needsAlignedStack: true)
// IRBUILDER-INLINE-ASM-NEXT: call void asm sideeffect alignstack "\00", "=r,0\00"(i32* @a)
_ = builder.buildCall(emptyASM, args: [ g1 ])
// IRBUILDER-INLINE-ASM-NEXT: ret void
builder.buildRetVoid()
// IRBUILDER-INLINE-ASM-NEXT: }
module.dump()
})

// MARK: Arithmetic Instructions

XCTAssert(fileCheckOutput(of: .stderr, withPrefixes: ["IRBUILDERARITH"]) {
Expand Down

0 comments on commit f74e159

Please sign in to comment.