// File: kernel.cpp
#include "loop_126.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_126(struct loop_126_data * data)

{
  uint32_t *a = data->a;
  uint32_t *b = data->b;
  int n = data->n;

  int pad = get_sve_vl() <= 512 ? 64 : 256;
  uint32_t *lmt = a + (n - (n % pad));
  uint32_t res = 0;
  svuint32_t res_vec = svdup_u32(res);
  svuint32_t tmp_vec = svdup_u32(0);
  svuint32_t pred_vec = svdup_u32(1);
  while (a < lmt) {
    svuint32_t a_vec = svld1(svptrue_b32(), a);
    svuint32_t b_vec = svld1(svptrue_b32(), b);
    res_vec = svmla_x(svptrue_b32(), res_vec, a_vec, b_vec);
    tmp_vec = svand_x(svptrue_b32(), res_vec, pred_vec);
    res_vec = svadd_x(svptrue_b32(), res_vec, tmp_vec);
    a += svcntw();
    b += svcntw();
  }
  res = svaddv(svptrue_b32(), res_vec);
  for (int i = 0; i < (n % pad); i++) {
    res += a[i] * b[i];
    if (res % 2) {
      res++;
    }
  }
  data->res = res;
}