summaryrefslogtreecommitdiff
path: root/src/main.c
blob: d09a87baa5a96256c999ac5e277121c8b6c4e76e (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
#include <stddef.h>
#include <berg/vm.h>

#define MATRIX_SIZE 400

static struct berg_func *compile_init(struct berg_vm *vm)
{
	struct berg_gpr A = berg_gpr(0);
	struct berg_gpr B = berg_gpr(1);
	struct berg_operand operands[] = {
		/** @todo pointer bounds in type signature? */
		berg_operand_gpr(A, BERG_POINTER),
		berg_operand_gpr(B, BERG_POINTER),
	};
	struct berg_func *f = create_berg_func(vm, BERG_VOID, 2, operands);

	berg_ret(f);
	compile_berg_func(f);
	return f;
}

static struct berg_func *compile_mult(struct berg_vm *vm)
{
	/* interesting, not using anything with a register means it gets treated
	 * as a oneshot reg, which is an issue for arguments. */
	struct berg_gpr A = berg_gpr_tmp(0);
	struct berg_gpr B = berg_gpr_tmp(1);
	struct berg_gpr C = berg_gpr_tmp(2);
	struct berg_operand operands[] = {
		berg_operand_gpr(A, BERG_POINTER),
		berg_operand_gpr(B, BERG_POINTER),
		berg_operand_gpr(C, BERG_POINTER),
	};
	struct berg_func *f = create_berg_func(vm, BERG_VOID, 3, operands);

	/* should be fixed in ejit itself but for now, just pretend we're doing
	 * something with the registers */
	berg_movr(f, B, A);
	berg_movr(f, C, B);
	berg_movr(f, A, C);

	berg_ret(f);
	compile_berg_func(f);
	return f;
}

static struct berg_func *compile_dump(struct berg_vm *vm)
{
	struct berg_gpr C = berg_gpr_tmp(0);
	struct berg_operand operands[] = {
		berg_operand_gpr(C, BERG_POINTER),
	};
	struct berg_func *f = create_berg_func(vm, BERG_VOID, 1, operands);

	berg_ret(f);
	compile_berg_func(f);
	return f;
}

static struct berg_func *compile_main(struct berg_vm *vm, struct berg_func *init, struct berg_func *mult, struct berg_func *dump)
{
	struct berg_gpr T = berg_gpr_tmp(0);
	struct berg_gpr A = berg_gpr_tmp(1);
	struct berg_gpr B = berg_gpr_tmp(2);
	struct berg_gpr C = berg_gpr_tmp(3);
	struct berg_func *f = create_berg_func(vm, BERG_VOID, 0, NULL);

	struct berg_gpr A0 = berg_gpr_arg(0);
	struct berg_gpr A1 = berg_gpr_arg(1);
	struct berg_gpr A2 = berg_gpr_arg(2);

	/* alloc matrixes */
	berg_movi(f, A0, MATRIX_SIZE * MATRIX_SIZE * sizeof(int));
	/* ecall takes some fixed registers, 0-1 (at least for now, will have to
	 * think of a proper ABI at some point) */
	berg_ecall(f, A, BERG_MALLOC);
	berg_ecall(f, B, BERG_MALLOC);
	berg_ecall(f, C, BERG_MALLOC);

	/** @todo come up with ABI for calls */
	berg_movr(f, A0, A);
	berg_movr(f, A1, B);
	berg_call(f, init);

	berg_movr(f, A2, C);
	berg_call(f, mult);

	berg_movr(f, A0, C);
	berg_call(f, dump);

	/* we don't really do anything with the return value so just dump it
	 * into T (should I have some kind of X0 register like in riscv?) */
	berg_movr(f, A0, A);
	berg_ecall(f, T, BERG_FREE);

	berg_movr(f, A0, B);
	berg_ecall(f, T, BERG_FREE);

	berg_movr(f, A0, C);
	berg_ecall(f, T, BERG_FREE);

	berg_ret(f);
	compile_berg_func(f);
	return f;
}

int main(int argc, char *argv[argc])
{
	struct berg_vm *vm = create_berg_vm();
	struct berg_func *init = compile_init(vm);
	struct berg_func *mult = compile_mult(vm);
	struct berg_func *dump = compile_dump(vm);
	struct berg_func *mn = compile_main(vm, init, mult, dump);

	run_berg_func(mn);
	destroy_berg_vm(vm);
	return 0;
}