Skip to content

Commit 7bc5935

Browse files
authored
Merge pull request #80 from CodaFi/readme-and-weep
Update README
2 parents d60cc80 + 910f9e3 commit 7bc5935

File tree

1 file changed

+161
-23
lines changed

1 file changed

+161
-23
lines changed

README.md

Lines changed: 161 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,185 @@
1-
2-
31
# LLVMSwift
42
[![Build Status](https://travis-ci.org/trill-lang/LLVMSwift.svg?branch=master)](https://travis-ci.org/trill-lang/LLVMSwift) [![Documentation](https://cdn.rawgit.com/trill-lang/LLVMSwift/master/docs/badge.svg)](https://trill-lang.github.io/LLVMSwift) [![Slack Invite](https://llvmswift-slack.herokuapp.com/badge.svg)](https://llvmswift-slack.herokuapp.com)
53

6-
LLVMSwift is a set of Swifty API wrappers for the LLVM C API.
7-
It makes compiler development feel great from Swift!
4+
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.
5+
6+
## Introduction
87

9-
## Usage
8+
### LLVM IR
109

11-
To start emitting IR, you'll want to create a `Module` object, with an optional `Context` parameter,
12-
and an `IRBuilder` that will build instructions for that module.
10+
The root unit of organization of an LLVM IR program is a `Module`
1311

1412
```swift
1513
let module = Module(name: "main")
16-
let builder = IRBuilder(module: module)
1714
```
1815

19-
Once you do that, you can start adding functions, global variables, and generating instructions!
16+
LLVM IR is construction is done with an `IRBuilder` object. An `IRBuilder` is a cursor pointed inside a context, and as such has ways of extending that context and moving around inside of it.
17+
18+
Defining a simple function and moving the cursor to a point where we can begin inserting instructions is done like so:
2019

2120
```swift
22-
let main = builder.addFunction(name: "main",
23-
type: FunctionType(argTypes: [],
24-
returnType: VoidType()))
21+
let builder = IRBuilder(module: module)
22+
23+
let main = builder.addFunction(
24+
name: "main",
25+
type: FunctionType(argTypes: [],
26+
returnType: VoidType())
27+
)
2528
let entry = main.appendBasicBlock(named: "entry")
2629
builder.positionAtEnd(of: entry)
30+
```
31+
32+
Inserting instructions creates native `IRValue` placeholder objects that allow us to structure LLVM IR programs just like Swift programs:
2733

28-
builder.buildRetVoid()
34+
```swift
35+
let constant = IntType.int64.constant(21)
36+
let sum = builder.buildAdd(constant, constant)
37+
builder.buildRet(sum)
38+
```
39+
40+
This simple program generates the following IR:
2941

30-
module.dump()
42+
```llvm
43+
// module.dump()
44+
45+
define void @main() {
46+
entry:
47+
ret i64 42
48+
}
3149
```
3250

33-
The IRBuilder class has methods for almost all functions from the LLVM C API, like:
51+
### Types
52+
53+
LLVM IR is a strong, statically typed language. As such, values and functions
54+
are tagged with their types, and conversions between them must be explicit (see
55+
[Conversion Operators](http://llvm.org/docs/LangRef.html#conversion-operations)).
56+
LLVMSwift represents this with values conforming to the `IRType` protocol and defines
57+
the following types:
3458

35-
- `builder.buildAdd`
36-
- `builder.buildSub`
37-
- `builder.buildMul`
38-
- `builder.buildCondBr`
39-
- `builder.addSwitch`
59+
|**Type** | **Represents** |
60+
|:---:|:---:|
61+
| VoidType | Nothing; Has no size |
62+
| IntType | Integer and Boolean values (`i1`) |
63+
| FloatType | Floating-point values |
64+
| FunctionType | Function values |
65+
| LabelType | Code labels |
66+
| TokenType | Values paired with instructions |
67+
| MetadataType | Embedded metadata |
68+
| X86MMXType | X86 MMX values |
69+
| PointerType | Pointer values |
70+
| VectorType | SIMD data |
71+
| ArrayType | Homogeneous values |
72+
| Structure Type | Heterogeneous values |
4073

41-
and so many more.
4274

43-
Plus, it provides common wrappers around oft-used types like `Function`, `Global`, `Switch`, and `PhiNode`.
75+
### Control Flow
76+
77+
Control flow is changed through the unconditional and conditional `br` instruction.
78+
79+
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:
80+
81+
```swift
82+
func calculateFibs(_ backward : Bool) -> Double {
83+
let retVal : Double
84+
if !backward {
85+
// the fibonacci series (sort of)
86+
retVal = 1/89
87+
} else {
88+
// the fibonacci series (sort of) backwards
89+
retVal = 1/109
90+
}
91+
return retVal
92+
}
93+
```
94+
95+
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:
96+
97+
```swift
98+
let function = builder.addFunction(
99+
"calculateFibs",
100+
type: FunctionType(argTypes: [IntType.int1],
101+
returnType: FloatType.double)
102+
)
103+
let entryBB = function.appendBasicBlock(named: "entry")
104+
builder.positionAtEnd(of: entryBB)
105+
106+
// allocate space for a local value
107+
let local = builder.buildAlloca(type: FloatType.double, name: "local")
108+
109+
// Compare to the condition
110+
let test = builder.buildICmp(function.parameters[0], IntType.int1.zero(), .notEqual)
111+
112+
// Create basic blocks for "then", "else", and "merge"
113+
let thenBB = function.appendBasicBlock(named: "then")
114+
let elseBB = function.appendBasicBlock(named: "else")
115+
let mergeBB = function.appendBasicBlock(named: "merge")
116+
117+
builder.buildCondBr(condition: test, then: thenBB, else: elseBB)
118+
119+
// MARK: Then Block
120+
builder.positionAtEnd(of: thenBB)
121+
// local = 1/89, the fibonacci series (sort of)
122+
let thenVal = FloatType.double.constant(1/89)
123+
builder.buildStore(thenVal, to: local)
124+
// Branch to the merge block
125+
builder.buildBr(mergeBB)
126+
127+
// MARK: Else Block
128+
builder.positionAtEnd(of: elseBB)
129+
// local = 1/109, the fibonacci series (sort of) backwards
130+
let elseVal = FloatType.double.constant(1/109)
131+
builder.buildStore(elseVal, to: local)
132+
// Branch to the merge block
133+
builder.buildBr(mergeBB)
134+
135+
// MARK: Merge Block
136+
builder.positionAtEnd(of: mergeBB)
137+
let phi = builder.buildPhi(FloatType.double, name: "phi_example")
138+
phi.addIncoming([
139+
(thenVal, thenBB),
140+
(elseVal, elseBB),
141+
])
142+
builder.buildRet(phi)
143+
```
144+
145+
This program generates the following IR:
146+
147+
```llvm
148+
define double @calculateFibs(i1) {
149+
entry:
150+
%local = alloca double
151+
%1 = icmp ne i1 %0, false
152+
br i1 %1, label %then, label %else
153+
154+
then: ; preds = %entry
155+
store double 0x3F8702E05C0B8170, double* %local
156+
br label %merge
157+
158+
else: ; preds = %entry
159+
store double 0x3F82C9FB4D812CA0, double* %local
160+
br label %merge
161+
162+
merge: ; preds = %else, %then
163+
%phi_example = phi double [ 0x3F8702E05C0B8170, %then ], [ 0x3F82C9FB4D812CA0, %else ]
164+
ret double %phi_example
165+
}
166+
```
167+
168+
### JIT
169+
170+
LLVMSwift provides a JIT abstraction to make executing code in LLVM modules quick and easy. Let's execute the PHI node example from before:
171+
172+
```swift
173+
// Setup the JIT
174+
let jit = try! JIT(module: module, machine: TargetMachine())
175+
typealias FnPtr = @convention(c) (Bool) -> Double
176+
// Retrieve a handle to the function we're going to invoke
177+
let fnAddr = jit.addressOfFunction(name: "calculateFibs")
178+
let fn = unsafeBitCast(fnAddr, to: FnPtr.self)
179+
// Call the function!
180+
print(fn(true)) // 0.00917431192660551...
181+
print(fn(false)) // 0.0112359550561798...
182+
```
44183

45184
## Installation
46185

@@ -86,4 +225,3 @@ all its code generation.
86225

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

0 commit comments

Comments
 (0)