#if defined(__aarch64__) || defined(_M_ARM64)
#include "semq_dispatch.h"
#include <arm_sve.h>
#include <stddef.h>
#include <stdint.h>
static inline svfloat64_t widen_lo_f32(svbool_t p64, svfloat32_t f) {
return svcvt_f64_x(p64, svzip1_f32(f, f));
}
static inline svfloat64_t widen_hi_f32(svbool_t p64, svfloat32_t f) {
return svcvt_f64_x(p64, svzip2_f32(f, f));
}
static inline svfloat64_t widen_lo_s32(svbool_t p64, svint32_t v) {
return svcvt_f64_x(p64, svzip1_s32(v, v));
}
static inline svfloat64_t widen_hi_s32(svbool_t p64, svint32_t v) {
return svcvt_f64_x(p64, svzip2_s32(v, v));
}
static inline svint32_t pack_64_to_32(svbool_t p64, svint64_t lo, svint64_t hi) {
svint64_t imin = svdup_n_s64((int64_t)INT32_MIN);
svint64_t imax = svdup_n_s64((int64_t)INT32_MAX);
lo = svmax_s64_x(p64, svmin_s64_x(p64, lo, imax), imin);
hi = svmax_s64_x(p64, svmin_s64_x(p64, hi, imax), imin);
return svuzp1_s32(svreinterpret_s32_s64(lo),
svreinterpret_s32_s64(hi));
}
static inline svint32_t scale_round_lane(
svbool_t p32, svbool_t p64, svfloat32_t f, svfloat64_t dsc) {
svfloat64_t d_lo = svmul_f64_x(p64, widen_lo_f32(p64, f), dsc);
svfloat64_t d_hi = svmul_f64_x(p64, widen_hi_f32(p64, f), dsc);
d_lo = svrintn_f64_x(p64, d_lo);
d_hi = svrintn_f64_x(p64, d_hi);
svint64_t v_lo = svcvt_s64_f64_x(p64, d_lo);
svint64_t v_hi = svcvt_s64_f64_x(p64, d_hi);
(void)p32;
return pack_64_to_32(p64, v_lo, v_hi);
}
static inline svuint32_t mod_9_u32(svbool_t p32, svuint32_t a) {
svuint32_t high = svmulh_u32_x(p32, a, svdup_n_u32(0x38E38E39u));
svuint32_t q = svlsr_n_u32_x(p32, high, 1);
return svmls_n_u32_x(p32, a, q, 9u);
}
static inline svuint32_t encode_int32_lane(svbool_t p32, svint32_t v) {
svbool_t pos = svcmpgt_n_s32(p32, v, 0);
svbool_t neg = svcmplt_n_s32(p32, v, 0);
svint32_t s = svdup_n_s32(1);
s = svadd_n_s32_m(pos, s, 1);
s = svsub_n_s32_m(neg, s, 1);
svuint32_t a = svreinterpret_u32_s32(svabs_s32_x(p32, v));
svuint32_t am1 = svsub_n_u32_x(p32, a, 1u);
svuint32_t r = mod_9_u32(p32, am1);
svuint32_t g_p = svadd_n_u32_x(p32, r, 1u);
svbool_t nz_mask = svcmpne_n_u32(p32, a, 0u);
svuint32_t g = svsel_u32(nz_mask, g_p, svdup_n_u32(0u));
svuint32_t s_u = svreinterpret_u32_s32(s);
return svmla_n_u32_x(p32, g, s_u, 10u);
}
static semq_status_t sve_encode(
const float* input,
uint32_t dim,
uint32_t scale,
semq_code_t* output) {
svfloat64_t dsc = svdup_n_f64((double)scale);
svbool_t p64 = svptrue_b64();
uint64_t n = (uint64_t)dim;
for (uint64_t i = 0; i < n; i += svcntw()) {
svbool_t p32 = svwhilelt_b32(i, n);
svfloat32_t f = svld1_f32(p32, input + i);
svint32_t v = scale_round_lane(p32, p64, f, dsc);
svuint32_t code = encode_int32_lane(p32, v);
svst1b_u32(p32, output + i, code);
}
return SEMQ_OK;
}
static semq_status_t sve_reconstruct(
const semq_code_t* codes,
uint32_t dim,
uint32_t scale,
double* output) {
svfloat64_t dsc = svdup_n_f64((double)scale);
svbool_t p64 = svptrue_b64();
uint64_t n = (uint64_t)dim;
for (uint64_t i = 0; i < n; i += svcntw()) {
svbool_t p32 = svwhilelt_b32(i, n);
svint32_t c32 = svld1ub_s32(p32, codes + i);
svint32_t q = svasr_n_s32_x(p32,
svmul_n_s32_x(p32, c32, 26), 8);
svint32_t r = svmls_n_s32_x(p32, c32, q, 10);
svint32_t sign = svsub_n_s32_x(p32, q, 1);
svint32_t gs = svmul_s32_x(p32, r, sign);
svfloat64_t f_lo = svdiv_f64_x(p64, widen_lo_s32(p64, gs), dsc);
svfloat64_t f_hi = svdiv_f64_x(p64, widen_hi_s32(p64, gs), dsc);
svbool_t p64_lo = svwhilelt_b64(i, n);
svbool_t p64_hi = svwhilelt_b64(i + svcntd(), n);
svst1_f64(p64_lo, output + i, f_lo);
svst1_f64(p64_hi, output + i + svcntd(), f_hi);
}
return SEMQ_OK;
}
const semq_backend_t SEMQ_SVE_BACKEND = {
.encode = sve_encode,
.reconstruct = sve_reconstruct
};
#endif