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