summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/src/main.c b/src/main.c
new file mode 100644
index 0000000..d09a87b
--- /dev/null
+++ b/src/main.c
@@ -0,0 +1,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;
+}