Skip to content
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 README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ builder.positionAtEnd(of: entryBB)
let local = builder.buildAlloca(type: FloatType.double, name: "local")

// Compare to the condition
let test = builder.buildICmp(function.parameters[0], IntType.int1.zero(), .notEqual)
let test = builder.buildICmp(function.parameters[0], IntType.int1.zero(), .equal)

// Create basic blocks for "then", "else", and "merge"
let thenBB = function.appendBasicBlock(named: "then")
Expand Down
22 changes: 6 additions & 16 deletions Sources/LLVM/JIT.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ public final class JIT {
/// The underlying LLVMExecutionEngineRef backing this JIT.
internal let llvm: LLVMExecutionEngineRef

private static var linkOnce: () = {
return LLVMLinkInMCJIT()
}()

/// Creates a Just In Time compiler that will compile the code in the
/// provided `Module` to the architecture of the provided `TargetMachine`,
/// and execute it.
Expand All @@ -41,6 +45,8 @@ public final class JIT {
/// - machine: The target machine which you're compiling for
/// - throws: JITError
public init(module: Module, machine: TargetMachine) throws {
_ = JIT.linkOnce

var jit: LLVMExecutionEngineRef?
var error: UnsafeMutablePointer<Int8>?
if LLVMCreateExecutionEngineForModule(&jit, module.llvm, &error) != 0 {
Expand All @@ -54,22 +60,6 @@ public final class JIT {
LLVMRunStaticConstructors(self.llvm)
}

/// Runs the specified function with the provided arguments by compiling
/// it to machine code for the target architecture used to initialize this
/// JIT.
///
/// - parameters:
/// - function: The function you wish to execute
/// - args: The arguments you wish to pass to the function
/// - returns: The LLVM value that the function returned
public func runFunction(_ function: Function, args: [IRValue]) -> IRValue {
var irArgs = args.map { $0.asLLVM() as Optional }
return irArgs.withUnsafeMutableBufferPointer { buf in
return LLVMRunFunction(llvm, function.asLLVM(),
UInt32(buf.count), buf.baseAddress)
}
}

/// Retrieves a pointer to the function compiled by this JIT.
/// - parameter name: The name of the function you wish to look up.
/// - returns: A pointer to the result of compiling the specified function.
Expand Down
79 changes: 79 additions & 0 deletions Tests/LLVMTests/JITSpec.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import LLVM
import XCTest
import FileCheck
import Foundation

class JITSpec : XCTestCase {
func testFibonacci() {
XCTAssert(fileCheckOutput(withPrefixes: ["JIT"]) {
let module = Module(name: "Fibonacci")
let builder = IRBuilder(module: module)

let function = builder.addFunction(
"calculateFibs",
type: FunctionType(argTypes: [IntType.int1],
returnType: FloatType.double)
)
let entryBB = function.appendBasicBlock(named: "entry")
builder.positionAtEnd(of: entryBB)

// allocate space for a local value
let local = builder.buildAlloca(type: FloatType.double, name: "local")

// Compare to the condition
let test = builder.buildICmp(function.parameters[0], IntType.int1.zero(), .equal)

// Create basic blocks for "then", "else", and "merge"
let thenBB = function.appendBasicBlock(named: "then")
let elseBB = function.appendBasicBlock(named: "else")
let mergeBB = function.appendBasicBlock(named: "merge")

builder.buildCondBr(condition: test, then: thenBB, else: elseBB)

// MARK: Then Block

builder.positionAtEnd(of: thenBB)
// local = 1/89, the fibonacci series (sort of)
let thenVal = FloatType.double.constant(1/89)
// Branch to the merge block
builder.buildBr(mergeBB)

// MARK: Else Block
builder.positionAtEnd(of: elseBB)
// local = 1/109, the fibonacci series (sort of) backwards
let elseVal = FloatType.double.constant(1/109)
// Branch to the merge block
builder.buildBr(mergeBB)

// MARK: Merge Block

builder.positionAtEnd(of: mergeBB)
let phi = builder.buildPhi(FloatType.double, name: "phi_example")
phi.addIncoming([
(thenVal, thenBB),
(elseVal, elseBB),
])
builder.buildStore(phi, to: local)
let ret = builder.buildLoad(local, name: "ret")
builder.buildRet(ret)

// Setup the JIT
let jit = try! JIT(module: module, machine: TargetMachine())
typealias FnPtr = @convention(c) (Bool) -> Double
// Retrieve a handle to the function we're going to invoke
let fnAddr = jit.addressOfFunction(name: "calculateFibs")
let fn = unsafeBitCast(fnAddr, to: FnPtr.self)
// JIT: 0.00917431192660551
print(fn(true))
// JIT-NEXT: 0.0112359550561798
print(fn(false))
})
}

#if !os(macOS)
static var allTests = testCase([
("testFibonacci", testFibonacci),
])
#endif
}

1 change: 1 addition & 0 deletions Tests/LinuxMain.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ XCTMain([
IRExceptionSpec.allTests,
IROperationSpec.allTests,
FileCheckSpec.allTests,
JITSpec.allTests,
])
#endif