aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.c
blob: 7f5d010bf1154fea43143385d8b0631315977eb6 (plain) (blame)
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();
}