#include "../lib.h"

#define REPLICA_COUNT 1
#define MAT_SIZE 3

static uint32_t X[MAT_SIZE * MAT_SIZE] = {
    0, 1, 2, //
    3, 4, 5, //
    6, 7, 8  //
};
static uint32_t Y[MAT_SIZE * MAT_SIZE] = {
    8, 7, 6, //
    5, 4, 3, //
    2, 1, 0  //
};
static uint32_t Calculated[MAT_SIZE * MAT_SIZE] = {0};

static INLINE uint32_t *idx(uint32_t *matrix, uint8_t x, uint8_t y) {
  return &matrix[y * MAT_SIZE + x];
}

template <const unsigned int N> static INLINE void matrix(void) {
  for (uint8_t y = 0; y < MAT_SIZE; ++y) {
    for (uint8_t x = 0; x < MAT_SIZE; ++x) {
      for (uint8_t k = 0; k < MAT_SIZE; ++k) {
        *idx(Calculated, x, y) += (*idx(X, k, y)) * (*idx(Y, x, k));
      }
    }
  }
}

static int cmp(uint32_t *A, uint32_t *B) {
  for (uint8_t i = 0; i < MAT_SIZE * MAT_SIZE; ++i) {
    if (A[i] != B[i]) {
      return 0;
    }
  }
  return 1;
}

extern "C" EXPORT("wasm_module") int wasm_module(void) {
  fail_start_trace();

  matrix<0>();

  fail_stop_trace();

  uint32_t Expected[MAT_SIZE * MAT_SIZE] = {
      9,  6,  3,  //
      54, 42, 30, //
      99, 78, 57  //
  };

  if (cmp(Calculated, Expected)) {
    PRINT("result correct.\n");
    fail_marker_positive();
    return 0;
  } else {
    PRINT("result incorrect.\n");
    fail_marker_negative();
    return 1;
  }
}
