Quick Primer On LLVM IR: (For Those Already Familiar With LLVM IR, Feel Free To)
Quick Primer On LLVM IR: (For Those Already Familiar With LLVM IR, Feel Free To)
(For those already familiar with LLVM IR, feel free to jump to the next
section).
Compilers are therefore often split into three components, the front-
end, middle-end and back-end; each with a specific task that takes IR
as input and/or produces IR as output.
To get a glimpse of what LLVM IR assembly may look like, lets consider
the following C program.
1
2 int f(int a, int b) {
3 return a + 2*b;
4}
5
6 int main() {
7 return f(10, 20);
}
1
2
3 define i32 @f(i32 %a, i32 %b) {
4 ; <label>:0
5 %1 = mul i32 2, %b
6 %2 = add i32 %a, %1
7 ret i32 %2
8 }
9
1 define i32 @main() {
0 ; <label>:0
1 %1 = call i32 @f(i32 10, i32 20)
1 ret i32 %1
1 }
2
Basic block
Instruction
Terminator instruction
To handle variables that are assigned more than once in the original
source code, a notion of phi instructions are used in LLVM IR.
A phi instruction essentially returns one value from a set of incoming
values, based on the control flow path taken during execution to reach
the phi instruction. Each incoming value is therefore associated with a
predecessor basic block.
The official LLVM bindings for Go uses Cgo to provide access to the rich
and powerful API of the LLVM compiler framework, while
the llir/llvm project is entirely written in Go and relies on LLVM IR to
interact with the LLVM compiler framework.
Usage examples
Now, lets consider a few concrete usage examples. Given that we have
a library to work with, what may we wish to do with LLVM IR?
1 // This example program parses an LLVM IR assembly file, and prints the parsed
2 // module to standard output.
3 package main
4
5
6
7
8
9
1
0
1 import (
1 "fmt"
1
2 "github.com/llir/llvm/asm"
1 )
3
1 func main() {
4 // Parse LLVM IR assembly file.
1 m, err := asm.ParseFile("foo.ll")
5 if err != nil {
1 panic(err)
6 }
1 // process, interpret or optimize LLVM IR.
7
1 // Print LLVM IR module.
8 fmt.Println(m)
1 }
9
2
0
2
1
1 // This example produces LLVM IR code equivalent to the following C code, which
2 // implements a pseudo-random number generator.
3 //
4 // int abs(int x);
5 //
6 // int seed = 0;
7 //
8 // // ref: https://en.wikipedia.org/wiki/Linear_congruential_generator
9 // // a = 0x15A4E35
1 // // c = 1
0 // int rand(void) {
1 // seed = seed*0x15A4E35 + 1;
1 // return abs(seed);
1
2
1 // }
3 package main
1
4 import (
1 "fmt"
5
1 "github.com/llir/llvm/ir"
6 "github.com/llir/llvm/ir/constant"
1 "github.com/llir/llvm/ir/types"
7 )
1
8 func main() {
1 // Create convenience types and constants.
9 i32 := types.I32
2 zero := constant.NewInt(i32, 0)
0 a := constant.NewInt(i32, 0x15A4E35) // multiplier of the PRNG.
2 c := constant.NewInt(i32, 1) // increment of the PRNG.
1
2 // Create a new LLVM IR module.
2 m := ir.NewModule()
2
3 // Create an external function declaration and append it to the module.
2 //
4 // int abs(int x);
2 abs := m.NewFunc("abs", i32, ir.NewParam("x", i32))
5
2 // Create a global variable definition and append it to the module.
6 //
2 // int seed = 0;
7 seed := m.NewGlobalDef("seed", zero)
2
8 // Create a function definition and append it to the module.
2 //
9 // int rand(void) { ... }
3 rand := m.NewFunc("rand", i32)
0
3 // Create an unnamed entry basic block and append it to the `rand` function.
1 entry := rand.NewBlock("")
3
2 // Create instructions and append them to the entry basic block.
3 tmp1 := entry.NewLoad(seed)
3 tmp2 := entry.NewMul(tmp1, a)
3 tmp3 := entry.NewAdd(tmp2, c)
4 entry.NewStore(tmp3, seed)
3 tmp4 := entry.NewCall(abs, tmp3)
5 entry.NewRet(tmp4)
3
6 // Print the LLVM IR assembly of the module.
3 fmt.Println(m)
7 }
3
8
3
9
4
0
4
1
4
2
4
3
4
4
4
5
4
6
4
7
4
8
4
9
5
0
5
1
5
2
5
3
5
4
5
5
5
6
5
7
5
8
5
9
6
0
6
1
6
2
6
3
Closing notes
The design and implementation of llir/llvm has been guided by a
community of people who have contributed – not only by writing code –
but through shared discussions, pair-programming sessions, bug
hunting, profiling investigations, and most of all, a curiosity for learning
and taking on exciting challenges.