summaryrefslogtreecommitdiff
path: root/src/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c171
1 files changed, 164 insertions, 7 deletions
diff --git a/src/main.c b/src/main.c
index d09a87b..b344c11 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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;