// File: kernel.cpp
#include "loop_038.h"
#include <stdint.h>
#include <arm_sve.h>
#define restrict __restrict
#define SC_SVE_ATTR
#define FOR_COND(P, S, I, N) svptest_first(svptrue_b##S(), P = svwhilelt_b##S(I, N))
#define FOR_LOOP(T, I, M, N, P, S, W) for (T I = M; FOR_COND(P, S, I, N); I += svcnt##W())
#define FOR_LOOP_8(T, I, M, N, P)  FOR_LOOP(T, I, M, N, P, 8, b)
#define FOR_LOOP_16(T, I, M, N, P) FOR_LOOP(T, I, M, N, P, 16, h)
#define FOR_LOOP_32(T, I, M, N, P) FOR_LOOP(T, I, M, N, P, 32, w)
#define FOR_LOOP_64(T, I, M, N, P) FOR_LOOP(T, I, M, N, P, 64, d)
static inline uint32_t get_sve_vl(void) {
  uint64_t vl = 0; asm volatile("incb %[vl], all, mul #8" : [vl] "+r"(vl) : :);
  return (uint32_t)vl;
}
static inline uint32_t get_vl(void) { return get_sve_vl(); }

extern "C" void inner_loop_038(struct loop_038_data * data)

{
  float16_t *a = data->a;
  float16_t *b = data->b;
  float16_t *c = data->c;
  int dim = data->dim;
  svfloat16_t k_vec = svdup_f16(0.25f);

  for (int row = 0; row < dim - 1; row++) {
    float16_t *s0 = a + (row * dim);
    float16_t *s1 = a + (row * dim) + 1;
    float16_t *s2 = a + ((row + 1) * dim);
    float16_t *s3 = a + ((row + 1) * dim) + 1;
    float16_t *ac = b + (row * dim);
    float16_t *ad = c + (row * dim);
    svbool_t p;
    FOR_LOOP_16(int32_t, col, 0, dim - 1, p) {
      svfloat16_t s0_vec = svld1(p, s0 + col);
      svfloat16_t s1_vec = svld1(p, s1 + col);
      svfloat16_t s2_vec = svld1(p, s2 + col);
      svfloat16_t s3_vec = svld1(p, s3 + col);
      svfloat16_t ac_vec = svld1(p, ac + col);
      ac_vec = svadd_x(p, ac_vec, svmul_x(p, s0_vec, k_vec));
      ac_vec = svadd_x(p, ac_vec, svmul_x(p, s1_vec, k_vec));
      ac_vec = svadd_x(p, ac_vec, svmul_x(p, s2_vec, k_vec));
      ac_vec = svadd_x(p, ac_vec, svmul_x(p, s3_vec, k_vec));
      svst1(p, ad + col, ac_vec);
    }
  }
}