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;
}
|