// File: kernel.cpp
#include "loop_101.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_101(struct loop_101_data * input)

{
  uint8_t * a = input->a;
  uint8_t * b = input->b;
  int n = input->n;

  svuint8_t three = svdup_u8(3);
  svbool_t p;
  FOR_LOOP_8(int, i, 0, n - 1, p) {
    svuint8_t b0 = svld1(p, b + i);
    svuint8_t b1 = svld1(p, b + 1 + i);

    svuint16_t b0_u16 = svreinterpret_u16(b0);
    svuint16_t b0_ext = svextb_x(p, b0_u16);
    svuint16_t b0_evn = svmlalb(b0_ext, b1, three);
    svuint16_t b0_ls8 = svlsr_x(p, b0_u16, 8);
    svuint16_t b0_odd = svmlalt(b0_ls8, b1, three);

    svuint16_t b1_u16 = svreinterpret_u16(b1);
    svuint16_t b1_ext = svextb_x(p, b1_u16);
    svuint16_t b1_evn = svmlalb(b1_ext, b0, three);
    svuint16_t b1_ls8 = svlsr_x(p, b1_u16, 8);
    svuint16_t b1_odd = svmlalt(b1_ls8, b0, three);

    svuint8_t a0 = svrshrnt(svrshrnb(b1_evn, 2), b1_odd, 2);
    svuint8_t a1 = svrshrnt(svrshrnb(b0_evn, 2), b0_odd, 2);
    svst2(p, a, svcreate2(a0, a1));

    a += svcntb() * 2;
  }
}