A Swift wrapper for the LLVM C API (version 11.0)
# LLVMSwift
[![Build Status](https://travis-ci.org/llvm-swift/LLVMSwift.svg?branch=master)](https://travis-ci.org/llvm-swift/LLVMSwift) [![Documentation](https://cdn.rawgit.com/llvm-swift/LLVMSwift/master/docs/badge.svg)](https://llvm-swift.github.io/LLVMSwift) [![Slack Invite](https://llvmswift-slack.herokuapp.com/badge.svg)](https://llvmswift-slack.herokuapp.com)

LLVMSwift is a pure Swift interface to the [LLVM](http://llvm.org) API and its associated libraries. It provides native, easy-to-use components to make compiler development fun.

## Introduction

### LLVM IR

The root unit of organization of an LLVM IR program is a `Module`

```swift
let module = Module(name: "main")
```

LLVM IR construction is handled by `IRBuilder` objects.  An `IRBuilder` is a cursor pointed inside a context, and as such has ways of extending that context and moving around inside of it.

Defining a function and moving the cursor to a point where we can begin inserting instructions is done like so:

```swift
let builder = IRBuilder(module: module)

let main = builder.addFunction("main",
                               type: FunctionType([], IntType.int64))
let entry = main.appendBasicBlock(named: "entry")
builder.positionAtEnd(of: entry)
```

Inserting instructions creates native `IRValue` placeholder objects that allow us to structure LLVM IR programs just like Swift programs:

```swift
let constant = IntType.int64.constant(21)
let sum = builder.buildAdd(constant, constant)
builder.buildRet(sum)
```

This simple program generates the following IR:

```llvm
// module.dump()

define i64 @main() {
entry:
  ret i64 42
}
```

### Types

LLVM IR is a strong, statically typed language.  As such, values and functions
are tagged with their types, and conversions between them must be explicit (see
[Conversion Operators](http://llvm.org/docs/LangRef.html#conversion-operations)).
LLVMSwift represents this with values conforming to the `IRType` protocol and defines
the following types:

|**Type** | **Represents** |
|:---:|:---:|
| VoidType | Nothing; Has no size |
| IntType | Integer and Boolean values (`i1`) |
| FloatType | Floating-point values |
| FunctionType | Function values |
| LabelType | Code labels |
| TokenType | Values paired with instructions |
| MetadataType | Embedded metadata |
| X86MMXType | X86 MMX values |
| PointerType | Pointer values |
| VectorType | SIMD data |
| ArrayType | Homogeneous values |
| Structure Type | Heterogeneous values |


### Control Flow

Control flow is changed through the unconditional and conditional `br` instruction.

LLVM is also famous for a control-flow specific IR construct called a [PHI node](http://llvm.org/docs/LangRef.html#phi-instruction).  Because all instructions in LLVM IR are in SSA (Single Static Assignment) form, a PHI node is necessary when the value of a variable assignment depends on the path the flow of control takes through the program.  For example, let's try to build the following Swift program in IR:

```swift
func calculateFibs(_ backward : Bool) -> Double {
  let retVal : Double
  if !backward {
    // the fibonacci series (sort of)
    retVal = 1/89
  } else {
    // the fibonacci series (sort of) backwards
    retVal = 1/109
  }
  return retVal
}
```

Notice that the value of `retVal` depends on the path the flow of control takes through this program, so we must emit a PHI node to properly initialize it:

```swift
let function = builder.addFunction("calculateFibs", 
                                   type: FunctionType([IntType.int1], 
                                                      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, type: FloatType.double, name: "ret")
builder.buildRet(ret)
```

This program generates the following IR:

```llvm
define double @calculateFibs(i1) {
entry:
  %local = alloca double
  %1 = icmp ne i1 %0, false
  br i1 %1, label %then, label %else

then:                                             ; preds = %entry
  br label %merge

else:                                             ; preds = %entry
  br label %merge

merge:                                            ; preds = %else, %then
  %phi_example = phi double [ 0x3F8702E05C0B8170, %then ], [ 0x3F82C9FB4D812CA0, %else ]
  store double %phi_example, double* %local
  %ret = load double, double* %local
  ret double %ret
}
```

### JIT

LLVMSwift provides a JIT abstraction to make executing code in LLVM modules quick and easy.  Let's execute the PHI node example from before:

```swift
// Setup the JIT
let jit = try JIT(machine: TargetMachine())
typealias FnPtr = @convention(c) (Bool) -> Double
_ = try jit.addEagerlyCompiledIR(module) { (name) -> JIT.TargetAddress in
  return JIT.TargetAddress()
}
// Retrieve a handle to the function we're going to invoke
let addr = try jit.address(of: "calculateFibs")
let fn = unsafeBitCast(addr, to: FnPtr.self)
// Call the function!
print(fn(true)) // 0.00917431192660551...
print(fn(false)) // 0.0112359550561798...
```

## Installation

There are a couple annoying steps you need to accomplish before building
LLVMSwift:

- Install LLVM 11.0+ using your favorite package manager. For example:
  - `brew install llvm@11`
- Ensure `llvm-config` is in your `PATH`
  - That will reside in the `/bin` folder wherever your package manager
    installed LLVM.
- Create a pkg-config file for your specific LLVM installation.
  - We have a utility for this: `swift utils/make-pkgconfig.swift`

Once you do that, you can add LLVMSwift as a dependency for your own Swift
compiler projects!

### Installation with Swift Package Manager

```swift
.package(url: "https://github.com/llvm-swift/LLVMSwift.git", from: "0.8.0")
```

### Installation without Swift Package Manager

We really recommend using SwiftPM with LLVMSwift, but if your project is
structured in such a way that makes using SwiftPM impractical or impossible,
use the following instructions: 

- Xcode:
  - Add this repository as a git submodule
  - Add the files in `Sources/` to your Xcode project.
  - Under `Library Search Paths` add the output of `llvm-config --libdir`
  - Under `Header Search Paths` add the output of `llvm-config --includedir`
  - Under `Link Target with Libraries` drag in
    `/path/to/your/llvm/lib/libLLVM.dylib`

This project is used by [Trill](https://github.com/harlanhaskins/trill) for
all its code generation.

## Authors

- Harlan Haskins ([@harlanhaskins](https://github.com/harlanhaskins))
- Robert Widmann ([@CodaFi](https://github.com/CodaFi))

## License

This project is released under the MIT license, a copy of which is available
in this repo.

