-
Notifications
You must be signed in to change notification settings - Fork 1
/
LlvmCodeGenerator.kt
103 lines (90 loc) · 3.63 KB
/
LlvmCodeGenerator.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
package eu.jameshamilton.bf.backend.llvm
import eu.jameshamilton.bf.backend.CodeGenerator
import eu.jameshamilton.bf.frontend.Node
import java.io.File
class LlvmCodeGenerator : CodeGenerator {
override fun generate(program: Node.Program, output: File?) {
output?.writeText(program.accept(LlvmComposer()))
}
class LlvmComposer : Node.Visitor<String> {
private var ptr = 0
private var n = 0
override fun visitProgram(program: Node.Program): String = declare(4) { (memory, ptr, i, j) ->
this.ptr = ptr
"""
|define i32 @main() {
| %$memory = alloca [30000 x i8], align 16
| %$ptr = alloca i8*, align 8
| %$i = bitcast [30000 x i8]* %$memory to i8*
| call void @llvm.memset.p0i8.i64(i8* align 16 %$i, i8 0, i64 30000, i1 false)
| %$j = getelementptr inbounds [30000 x i8], [30000 x i8]* %$memory, i64 0, i64 0
| store i8* %$j, i8** %$ptr, align 8
|${program.bodyAccept(this, ::concat)}
| ret i32 0
|}
|
|declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg)
|declare i32 @putchar(i32)
|declare i32 @getchar()
|
""".trimMargin()
}
override fun visitMove(move: Node.Move): String = declare(2) { (i, j) ->
"""
| %$i = load i8*, i8** %$ptr, align 8
| %$j = getelementptr inbounds i8, i8* %$i, i64 ${move.amount}
| store i8* %$j, i8** %$ptr, align 8
""".trimMargin()
}
override fun visitAdd(add: Node.Add): String = declare(3) { (a, b, c) ->
"""
| %$a = load i8*, i8** %$ptr, align 8
| %$b = load i8, i8* %$a, align 1
| %$c = add i8 %$b, ${add.amount}
| store i8 %$c, i8* %$a, align 1
""".trimMargin()
}
override fun visitZero(zero: Node.Zero): String = declare(1) { (a) ->
"""
|%$a = load i8*, i8** %$ptr, align 8
|store i8 0, i8* %$a, align 1
""".trimMargin()
}
override fun visitLoop(loop: Node.Loop): String = declare(5) { (cond, a, b, c, body) ->
"""
| br label %$cond
|$cond:
| %$a = load i8*, i8** %$ptr, align 8
| %$b = load i8, i8* %$a, align 1
| %$c = icmp ne i8 %$b, 0
| br i1 %$c, label %$body, label %end$cond
|$body:
|${loop.bodyAccept(this, ::concat)}
| br label %$cond
|end$cond:
""".trimMargin()
}
override fun visitPrint(print: Node.Print): String = declare(4) { (a, b, c, d) ->
"""
| %$a = load i8*, i8** %$ptr, align 8
| %$b = load i8, i8* %$a, align 1
| %$c = sext i8 %$b to i32
| %$d = call i32 @putchar(i32 %$c)
""".trimMargin()
}
override fun visitRead(read: Node.Read): String = declare(3) { (a, b, c) ->
"""
| %$a = call i32 @getchar()
| %$b = trunc i32 %$a to i8
| %$c = load i8*, i8** %$ptr, align 8
| store i8 %$b, i8* %$c, align 1
""".trimMargin()
}
private fun <R> declare(n: Int, block: (List<Int>) -> R): R {
this.n += n
return block((this.n - n + 1..this.n).toList())
}
private operator fun <T> List<T>.component6() = this[5]
private fun concat(a: String, b: String) = "$a\n$b"
}
}