#include #include #define MATRIX_SIZE 400 static struct berg_func *compile_init(struct berg_vm *vm) { struct berg_gpr A = berg_gpr_tmp(0); struct berg_gpr B = berg_gpr_tmp(1); struct berg_gpr I = berg_gpr_tmp(2); struct berg_gpr J = berg_gpr_tmp(3); struct berg_gpr T = berg_gpr_tmp(4); 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); /* outer loop */ berg_movi(f, I, 0); struct berg_label outer = berg_label(f); /* stop if I >= MATRIX_SIZE */ berg_movi(f, T, MATRIX_SIZE); struct berg_reloc outer_jmp = berg_bger(f, I, T); /* inner loop */ berg_movi(f, J, 0); struct berg_label inner = berg_label(f); /* stop if J >= MATRIX_SIZE */ berg_movi(f, T, MATRIX_SIZE); struct berg_reloc inner_jmp = berg_bger(f, J, T); /* &[I][J] = 4 * (J + MATRIX_SIZE * I) */ berg_movi(f, T, MATRIX_SIZE); berg_mulr(f, T, T, I); berg_addr(f, T, T, J); berg_lshi(f, T, T, 2); /* A[I][J] = I */ berg_stxr_32(f, I, A, T); /* B[I][J] = J */ berg_stxr_32(f, J, B, T); berg_addi(f, J, J, 1); berg_patch(f, berg_jmp(f), inner); berg_patch(f, inner_jmp, berg_label(f)); berg_addi(f, I, I, 1); berg_patch(f, berg_jmp(f), outer); berg_patch(f, outer_jmp, berg_label(f)); 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_gpr I = berg_gpr_tmp(3); struct berg_gpr J = berg_gpr_tmp(4); struct berg_gpr K = berg_gpr_tmp(5); struct berg_gpr R = berg_gpr_tmp(6); struct berg_gpr T = berg_gpr_tmp(7); struct berg_gpr AT = berg_gpr_tmp(8); struct berg_gpr BT = berg_gpr_tmp(9); 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); /* outer loop */ berg_movi(f, I, 0); struct berg_label outer = berg_label(f); /* stop if I >= MATRIX_SIZE */ berg_movi(f, T, MATRIX_SIZE); struct berg_reloc outer_jmp = berg_bger(f, I, T); /* inner loop */ berg_movi(f, J, 0); struct berg_label inner = berg_label(f); /* stop if J >= MATRIX_SIZE */ berg_movi(f, T, MATRIX_SIZE); struct berg_reloc inner_jmp = berg_bger(f, J, T); berg_movi(f, R, 0); /* innermost loop */ berg_movi(f, K, 0); struct berg_label innermost = berg_label(f); /* stop if K >= MATRIX_SIZE */ berg_movi(f, T, MATRIX_SIZE); struct berg_reloc innermost_jmp = berg_bger(f, K, T); /* A[I][K] */ /* &[I][K] = 4 * (K + MATRIX_SIZE * I) */ berg_movi(f, T, MATRIX_SIZE); berg_mulr(f, T, T, I); berg_addr(f, T, T, K); berg_lshi(f, T, T, 2); berg_ldxr_i32(f, AT, A, T); /* B[K][J] */ berg_movi(f, T, MATRIX_SIZE); berg_mulr(f, T, T, K); berg_addr(f, T, T, J); berg_lshi(f, T, T, 2); berg_ldxr_i32(f, BT, B, T); /* R += A[I][K] * B[K][J] */ berg_mulr(f, T, AT, BT); berg_addr(f, R, R, T); berg_addi(f, K, K, 1); berg_patch(f, berg_jmp(f), innermost); berg_patch(f, innermost_jmp, berg_label(f)); /* &[I][J] = 4 * (J + MATRIX_SIZE * I) */ berg_movi(f, T, MATRIX_SIZE); berg_mulr(f, T, T, I); berg_addr(f, T, T, J); berg_lshi(f, T, T, 2); /* C[I][J] = R */ berg_stxr_32(f, R, C, T); berg_addi(f, J, J, 1); berg_patch(f, berg_jmp(f), inner); berg_patch(f, inner_jmp, berg_label(f)); berg_addi(f, I, I, 1); berg_patch(f, berg_jmp(f), outer); berg_patch(f, outer_jmp, berg_label(f)); berg_ret(f); compile_berg_func(f); return f; } static struct berg_func *compile_dump(struct berg_vm *vm) { struct berg_gpr A0 = berg_gpr_arg(0); struct berg_gpr C = berg_gpr_tmp(0); struct berg_gpr I = berg_gpr_tmp(1); struct berg_gpr J = berg_gpr_tmp(2); struct berg_gpr T = berg_gpr_tmp(3); struct berg_gpr S = berg_gpr_tmp(4); struct berg_operand operands[] = { berg_operand_gpr(C, BERG_POINTER), }; struct berg_func *f = create_berg_func(vm, BERG_VOID, 1, operands); berg_movi(f, S, 0); /* outer loop */ berg_movi(f, I, 0); struct berg_label outer = berg_label(f); /* stop if I >= MATRIX_SIZE */ berg_movi(f, T, MATRIX_SIZE); struct berg_reloc outer_jmp = berg_bger(f, I, T); /* inner loop */ berg_movi(f, J, 0); struct berg_label inner = berg_label(f); /* stop if J >= MATRIX_SIZE */ berg_movi(f, T, MATRIX_SIZE); struct berg_reloc inner_jmp = berg_bger(f, J, T); /* &[I][J] = 4 * (J + MATRIX_SIZE * I) */ berg_movi(f, T, MATRIX_SIZE); berg_mulr(f, T, T, I); berg_addr(f, T, T, J); berg_lshi(f, T, T, 2); /* S += C[I][J] = I */ berg_ldxr_i32(f, T, C, T); berg_addr(f, S, S, T); berg_addi(f, J, J, 1); berg_patch(f, berg_jmp(f), inner); berg_patch(f, inner_jmp, berg_label(f)); berg_addi(f, I, I, 1); berg_patch(f, berg_jmp(f), outer); berg_patch(f, outer_jmp, berg_label(f)); /* print out 'hash' of matrix */ berg_movr(f, A0, S); berg_ecall(f, T, BERG_PUTI32); 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; }