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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
|
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/Core.h>
#include "alloc.h"
#include "codegen.h"
#include "common.h"
#include "errors.h"
#include "parser.h"
static size_t codegenstmt(LLVMBuilderRef, struct ast, struct lexemes,
size_t);
static size_t codegenexpr(LLVMBuilderRef, struct ast, struct lexemes,
size_t, LLVMValueRef *)
__attribute__((nonnull));
void
codegen(struct ast ast, struct lexemes toks)
{
LLVMModuleRef mod = LLVMModuleCreateWithName("oryx");
for (size_t i = 0; i < ast.len;) {
if (ast.kinds[i] != ASTCDECL)
err("codegen: Expected constant declaration");
size_t expr = ast.kids[i].rhs;
if (ast.kinds[expr] != ASTFN) {
assert(!"not implemented");
__builtin_unreachable();
}
size_t proto = ast.kids[expr].lhs, body = ast.kids[expr].rhs;
LLVMTypeRef ret;
LLVMTypeRef params[] = {0};
if (ast.kids[proto].rhs == AST_EMPTY)
ret = LLVMVoidType();
else {
size_t type = ast.kids[proto].rhs;
struct strview sv = toks.strs[ast.lexemes[type]];
/* TODO: Make int 32bit on 32bit platforms */
if (strncmp("int", sv.p, sv.len) == 0)
ret = LLVMInt64Type();
else
err("codegen: Unknown type: %.*s", (int)sv.len, sv.p);
}
LLVMTypeRef fnproto = LLVMFunctionType(ret, params, 0, false);
struct strview sv = toks.strs[ast.lexemes[i]];
char *fnname = bufalloc(NULL, sv.len + 1, 1);
((char *)memcpy(fnname, sv.p, sv.len))[sv.len] = 0;
LLVMValueRef fn = LLVMAddFunction(mod, fnname, fnproto);
LLVMBasicBlockRef entry = LLVMAppendBasicBlock(fn, "entry");
LLVMBuilderRef builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(builder, entry);
free(fnname);
for (i = ast.kids[body].lhs; i <= ast.kids[body].rhs;)
i = codegenstmt(builder, ast, toks, i);
LLVMDisposeBuilder(builder);
}
char *error = NULL;
LLVMVerifyModule(mod, LLVMAbortProcessAction, &error);
LLVMDisposeMessage(error);
LLVMDumpModule(mod);
LLVMDisposeModule(mod);
}
size_t
codegenstmt(LLVMBuilderRef builder, struct ast ast, struct lexemes toks,
size_t i)
{
switch (ast.kinds[i]) {
case ASTRET:
if (ast.kids[i].rhs == AST_EMPTY) {
LLVMBuildRetVoid(builder);
return i + 1;
}
LLVMValueRef v;
i = codegenexpr(builder, ast, toks, ast.kids[i].rhs, &v);
LLVMBuildRet(builder, v);
return i;
}
assert(!"unreachable");
__builtin_unreachable();
}
size_t
codegenexpr(LLVMBuilderRef builder, struct ast ast, struct lexemes toks,
size_t i, LLVMValueRef *v)
{
(void)builder;
switch (ast.kinds[i]) {
case ASTNUMLIT: {
/* TODO: Arbitrary precision? */
struct strview sv = toks.strs[ast.lexemes[i]];
/* TODO: Temporary one-time-use allocator? */
size_t len = 0;
char *p = bufalloc(NULL, sv.len, 1);
for (size_t i = 0; i < sv.len; i++) {
if (sv.p[i] != '\'')
p[len++] = sv.p[i];
}
*v = LLVMConstIntOfStringAndSize(LLVMInt64Type(), p, len, 10);
free(p);
return i + 1;
}
}
assert(!"unreachable");
__builtin_unreachable();
}
|