#if defined(__x86_64__) || defined(_M_X64)
#include "semq_dispatch.h"
#include <immintrin.h>
#include <math.h>
#include <stdint.h>
static int64_t scaled_round_one(float x, uint32_t scale) {
if (!isfinite(x)) {
return 0;
}
double y = nearbyint((double)x * (double)scale);
if (y >= 9.2233720368547748e18) {
return INT64_MAX;
}
if (y <= -9.2233720368547758e18) {
return INT64_MIN;
}
return (int64_t)y;
}
static uint8_t reduce_one(uint64_t a) {
if (a == 0u) return 0u;
return (uint8_t)(1u + (uint32_t)((a - 1u) % 9u));
}
static semq_code_t scalar_op(float x, uint32_t scale) {
int64_t v = scaled_round_one(x, scale);
unsigned int s = (v > 0) ? 2u : ((v < 0) ? 0u : 1u);
uint64_t a;
if (v == INT64_MIN) {
a = (uint64_t)INT64_MAX + 1u;
} else {
a = (v < 0) ? (uint64_t)(-v) : (uint64_t)v;
}
return (semq_code_t)(s * 10u + (unsigned int)reduce_one(a));
}
static double scalar_inverse(semq_code_t code, uint32_t scale) {
int sign = (int)(code / 10u) - 1;
unsigned int g = (unsigned int)(code % 10u);
return ((double)g * (double)sign) / (double)scale;
}
static inline __m256i scale_round_8(__m256 f, __m256d dsc) {
__m256d d_lo = _mm256_mul_pd(_mm256_cvtps_pd(_mm256_castps256_ps128(f)), dsc);
__m256d d_hi = _mm256_mul_pd(_mm256_cvtps_pd(_mm256_extractf128_ps(f, 1)), dsc);
__m128i lo = _mm256_cvtpd_epi32(d_lo);
__m128i hi = _mm256_cvtpd_epi32(d_hi);
return _mm256_setr_m128i(lo, hi);
}
static inline __m256i mod_9_u32(__m256i a) {
const __m256i magic = _mm256_set1_epi32((int)0x38E38E39u);
__m256i prod_even = _mm256_mul_epu32(a, magic);
__m256i a_odd = _mm256_srli_epi64(a, 32);
__m256i m_odd = _mm256_srli_epi64(magic, 32);
__m256i prod_odd = _mm256_mul_epu32(a_odd, m_odd);
__m256i q_even = _mm256_srli_epi64(prod_even, 33);
__m256i q_odd = _mm256_srli_epi64(prod_odd, 33);
__m256i q_odd_in_odd = _mm256_slli_epi64(q_odd, 32);
__m256i mask_lo32 = _mm256_set1_epi64x((long long)0x00000000FFFFFFFFULL);
__m256i q = _mm256_or_si256(_mm256_and_si256(q_even, mask_lo32), q_odd_in_odd);
__m256i nine = _mm256_set1_epi32(9);
return _mm256_sub_epi32(a, _mm256_mullo_epi32(q, nine));
}
static inline __m256i encode_int32_8(__m256i v) {
const __m256i Z = _mm256_setzero_si256();
const __m256i ONE = _mm256_set1_epi32(1);
__m256i pos = _mm256_cmpgt_epi32(v, Z);
__m256i neg = _mm256_cmpgt_epi32(Z, v);
__m256i sgn = _mm256_sub_epi32(neg, pos);
__m256i s = _mm256_add_epi32(ONE, sgn);
__m256i a = _mm256_abs_epi32(v);
__m256i am1 = _mm256_sub_epi32(a, ONE);
__m256i r = mod_9_u32(am1);
__m256i g_pos = _mm256_add_epi32(r, ONE);
__m256i nz = _mm256_xor_si256(_mm256_cmpeq_epi32(a, Z),
_mm256_set1_epi32(-1));
__m256i g = _mm256_and_si256(g_pos, nz);
__m256i ten = _mm256_set1_epi32(10);
return _mm256_add_epi32(_mm256_mullo_epi32(s, ten), g);
}
static inline __m256i pack_codes_32(__m256i a, __m256i b, __m256i c, __m256i d) {
__m256i ab16 = _mm256_packus_epi32(a, b);
__m256i cd16 = _mm256_packus_epi32(c, d);
__m256i abcd = _mm256_packus_epi16(ab16, cd16);
const __m256i perm = _mm256_setr_epi32(0, 4, 1, 5, 2, 6, 3, 7);
return _mm256_permutevar8x32_epi32(abcd, perm);
}
static semq_status_t avx2_encode(
const float* input,
uint32_t dim,
uint32_t scale,
semq_code_t* output) {
__m256d dsc = _mm256_set1_pd((double)scale);
uint32_t i = 0;
for (; i + 32u <= dim; i += 32u) {
__m256 f0 = _mm256_loadu_ps(input + i + 0u);
__m256 f1 = _mm256_loadu_ps(input + i + 8u);
__m256 f2 = _mm256_loadu_ps(input + i + 16u);
__m256 f3 = _mm256_loadu_ps(input + i + 24u);
__m256i v0 = scale_round_8(f0, dsc);
__m256i v1 = scale_round_8(f1, dsc);
__m256i v2 = scale_round_8(f2, dsc);
__m256i v3 = scale_round_8(f3, dsc);
__m256i c0 = encode_int32_8(v0);
__m256i c1 = encode_int32_8(v1);
__m256i c2 = encode_int32_8(v2);
__m256i c3 = encode_int32_8(v3);
_mm256_storeu_si256((__m256i*)(output + i),
pack_codes_32(c0, c1, c2, c3));
}
for (; i < dim; ++i) {
output[i] = scalar_op(input[i], scale);
}
return SEMQ_OK;
}
static semq_status_t avx2_reconstruct(
const semq_code_t* codes,
uint32_t dim,
uint32_t scale,
double* output) {
__m256d dsc = _mm256_set1_pd((double)scale);
uint32_t i = 0u;
for (; i + 8u <= dim; i += 8u) {
__m128i c8 = _mm_loadl_epi64((const __m128i*)(codes + i));
__m256i c32 = _mm256_cvtepu8_epi32(c8);
__m256i magic26 = _mm256_set1_epi32(26);
__m256i q = _mm256_srli_epi32(_mm256_mullo_epi32(c32, magic26), 8);
__m256i r = _mm256_sub_epi32(c32,
_mm256_mullo_epi32(q, _mm256_set1_epi32(10)));
__m256i sign = _mm256_sub_epi32(q, _mm256_set1_epi32(1));
__m256i gs = _mm256_mullo_epi32(r, sign);
__m256d f_lo = _mm256_cvtepi32_pd(_mm256_castsi256_si128(gs));
__m256d f_hi = _mm256_cvtepi32_pd(_mm256_extracti128_si256(gs, 1));
f_lo = _mm256_div_pd(f_lo, dsc);
f_hi = _mm256_div_pd(f_hi, dsc);
_mm256_storeu_pd(output + i + 0, f_lo);
_mm256_storeu_pd(output + i + 4, f_hi);
}
for (; i < dim; ++i) {
output[i] = scalar_inverse(codes[i], scale);
}
return SEMQ_OK;
}
const semq_backend_t SEMQ_AVX2_BACKEND = {
.encode = avx2_encode,
.reconstruct = avx2_reconstruct
};
#endif