|
| 1 | +import LLVM |
| 2 | +import XCTest |
| 3 | +import FileCheck |
| 4 | +import Foundation |
| 5 | + |
| 6 | +class JITSpec : XCTestCase { |
| 7 | + func testFibonacci() { |
| 8 | + XCTAssert(fileCheckOutput(withPrefixes: ["JIT"]) { |
| 9 | + let module = Module(name: "Fibonacci") |
| 10 | + let builder = IRBuilder(module: module) |
| 11 | + |
| 12 | + let function = builder.addFunction( |
| 13 | + "calculateFibs", |
| 14 | + type: FunctionType(argTypes: [IntType.int1], |
| 15 | + returnType: FloatType.double) |
| 16 | + ) |
| 17 | + let entryBB = function.appendBasicBlock(named: "entry") |
| 18 | + builder.positionAtEnd(of: entryBB) |
| 19 | + |
| 20 | + // allocate space for a local value |
| 21 | + let local = builder.buildAlloca(type: FloatType.double, name: "local") |
| 22 | + |
| 23 | + // Compare to the condition |
| 24 | + let test = builder.buildICmp(function.parameters[0], IntType.int1.zero(), .equal) |
| 25 | + |
| 26 | + // Create basic blocks for "then", "else", and "merge" |
| 27 | + let thenBB = function.appendBasicBlock(named: "then") |
| 28 | + let elseBB = function.appendBasicBlock(named: "else") |
| 29 | + let mergeBB = function.appendBasicBlock(named: "merge") |
| 30 | + |
| 31 | + builder.buildCondBr(condition: test, then: thenBB, else: elseBB) |
| 32 | + |
| 33 | + // MARK: Then Block |
| 34 | + |
| 35 | + builder.positionAtEnd(of: thenBB) |
| 36 | + // local = 1/89, the fibonacci series (sort of) |
| 37 | + let thenVal = FloatType.double.constant(1/89) |
| 38 | + // Branch to the merge block |
| 39 | + builder.buildBr(mergeBB) |
| 40 | + |
| 41 | + // MARK: Else Block |
| 42 | + builder.positionAtEnd(of: elseBB) |
| 43 | + // local = 1/109, the fibonacci series (sort of) backwards |
| 44 | + let elseVal = FloatType.double.constant(1/109) |
| 45 | + // Branch to the merge block |
| 46 | + builder.buildBr(mergeBB) |
| 47 | + |
| 48 | + // MARK: Merge Block |
| 49 | + |
| 50 | + builder.positionAtEnd(of: mergeBB) |
| 51 | + let phi = builder.buildPhi(FloatType.double, name: "phi_example") |
| 52 | + phi.addIncoming([ |
| 53 | + (thenVal, thenBB), |
| 54 | + (elseVal, elseBB), |
| 55 | + ]) |
| 56 | + builder.buildStore(phi, to: local) |
| 57 | + let ret = builder.buildLoad(local, name: "ret") |
| 58 | + builder.buildRet(ret) |
| 59 | + |
| 60 | + // Setup the JIT |
| 61 | + let jit = try! JIT(module: module, machine: TargetMachine()) |
| 62 | + typealias FnPtr = @convention(c) (Bool) -> Double |
| 63 | + // Retrieve a handle to the function we're going to invoke |
| 64 | + let fnAddr = jit.addressOfFunction(name: "calculateFibs") |
| 65 | + let fn = unsafeBitCast(fnAddr, to: FnPtr.self) |
| 66 | + // JIT: 0.00917431192660551 |
| 67 | + print(fn(true)) |
| 68 | + // JIT-NEXT: 0.0112359550561798 |
| 69 | + print(fn(false)) |
| 70 | + }) |
| 71 | + } |
| 72 | + |
| 73 | + #if !os(macOS) |
| 74 | + static var allTests = testCase([ |
| 75 | + ("testFibonacci", testFibonacci), |
| 76 | + ]) |
| 77 | + #endif |
| 78 | +} |
| 79 | + |
0 commit comments