use crate::repack::common::*;
use crate::repack::q6_kx8::*;
use crate::Q6_K_BLOCK_ELEMS;
use std::arch::x86_64::*;
use super::{bcast8, load_f16x8, rows8_from_pairs, scale_lanes_i8};
#[target_feature(enable = "avx2,fma")]
pub unsafe fn gemm_q6_kx8_q8_k_avx2(
packed: &[u8],
tile: &Q8KActsX4,
n_cols: usize,
out: &mut [f32],
) {
let nb = n_cols / Q6_K_BLOCK_ELEMS;
let na = tile.na;
let m4b = _mm256_set1_epi8(0x0F);
let m3 = _mm256_set1_epi8(0x03);
let m30 = _mm256_set1_epi8(0x30);
let bias32 = _mm256_set1_epi8(32);
let mut acc = [_mm256_setzero_ps(); Q8K_ACTS_X4_NC];
for l in 0..nb {
let blk = packed.as_ptr().add(l * Q6_KX8_BLOCK_BYTES);
let d_vec = load_f16x8(blk);
let scales = blk.add(16);
let ql = blk.add(144);
let qh = blk.add(1168);
let acts = tile.qs.as_ptr().add(l * Q6_K_BLOCK_ELEMS * 4);
let mut sc_v = [[[_mm256_setzero_si256(); 2]; 2]; 16];
for (k, per_k) in sc_v.iter_mut().enumerate() {
let base_l = (k / 8) * 128 + (k % 8) * 8;
let si_l = base_l / 16;
for half in 0..2 {
per_k[0][half] = scale_lanes_i8(scales, si_l * 8 + half * 4);
per_k[1][half] = scale_lanes_i8(scales, (si_l + 4) * 8 + half * 4);
}
}
for a in 0..na {
let mut i32acc = [_mm256_setzero_si256(); 2];
for (k, per_k) in sc_v.iter().enumerate() {
let base_l = (k / 8) * 128 + (k % 8) * 8;
let run_l = base_l / 8;
let sh_l = _mm_cvtsi32_si128((((k % 8) / 4) * 2) as i32);
let sh_h = _mm_cvtsi32_si128(((((k % 8) / 4) * 2) + 4) as i32);
let qh_chunk = (k / 8) * 4 + (k % 4);
let a_l = bcast8(acts.add(run_l * 32 + a * 8));
let a_h = bcast8(acts.add((run_l + 8) * 32 + a * 8));
for half in 0..2 {
let qlv = _mm256_loadu_si256(ql.add(k * 64 + half * 32) as *const __m256i);
let qhv =
_mm256_loadu_si256(qh.add(qh_chunk * 64 + half * 32) as *const __m256i);
let u_l = _mm256_or_si256(
_mm256_and_si256(qlv, m4b),
_mm256_and_si256(
_mm256_slli_epi16(_mm256_and_si256(_mm256_srl_epi16(qhv, sh_l), m3), 4),
m30,
),
);
let u_h = _mm256_or_si256(
_mm256_and_si256(_mm256_srli_epi16(qlv, 4), m4b),
_mm256_and_si256(
_mm256_slli_epi16(_mm256_and_si256(_mm256_srl_epi16(qhv, sh_h), m3), 4),
m30,
),
);
let p_l = _mm256_sub_epi16(
_mm256_maddubs_epi16(u_l, a_l),
_mm256_maddubs_epi16(bias32, a_l),
);
let p_h = _mm256_sub_epi16(
_mm256_maddubs_epi16(u_h, a_h),
_mm256_maddubs_epi16(bias32, a_h),
);
i32acc[half] = _mm256_add_epi32(
i32acc[half],
_mm256_add_epi32(
_mm256_madd_epi16(p_l, per_k[0][half]),
_mm256_madd_epi16(p_h, per_k[1][half]),
),
);
}
}
acc[a] = _mm256_fmadd_ps(
_mm256_cvtepi32_ps(rows8_from_pairs(i32acc[0], i32acc[1])),
_mm256_mul_ps(d_vec, _mm256_set1_ps(tile.d[l * 4 + a])),
acc[a],
);
}
}
for a in 0..na {
let mut v = [0f32; 8];
_mm256_storeu_ps(v.as_mut_ptr(), acc[a]);
for (j, got) in v.iter().enumerate() {
out[j * na + a] = *got;
}
}
}