diff options
Diffstat (limited to 'src/main.c')
-rw-r--r-- | src/main.c | 171 |
1 files changed, 164 insertions, 7 deletions
@@ -5,8 +5,12 @@ 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_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), @@ -14,6 +18,42 @@ static struct berg_func *compile_init(struct berg_vm *vm) }; 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; @@ -26,6 +66,14 @@ static struct berg_func *compile_mult(struct berg_vm *vm) 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), @@ -33,11 +81,73 @@ static struct berg_func *compile_mult(struct berg_vm *vm) }; 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); + /* 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); @@ -46,12 +156,59 @@ static struct berg_func *compile_mult(struct berg_vm *vm) 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; |