diff options
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 118 |
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; +} |