#[target_feature(enable = "avx2,fma")]
pub(super) unsafe fn dot_f32_avx2(q: &[f32], row_bytes: &[u8]) -> f32 {
unsafe {
use std::arch::x86_64::*;
let dim = q.len();
let mut acc = _mm256_setzero_ps();
let row_ptr = row_bytes.as_ptr() as *const f32;
let chunks = dim / 8;
for i in 0..chunks {
let qv = _mm256_loadu_ps(q.as_ptr().add(i * 8));
let rv = _mm256_loadu_ps(row_ptr.add(i * 8));
acc = _mm256_fmadd_ps(qv, rv, acc);
}
let mut tail = 0.0f32;
for (i, &qv) in q.iter().enumerate().skip(chunks * 8) {
let off = i * 4;
let v = f32::from_le_bytes([
row_bytes[off],
row_bytes[off + 1],
row_bytes[off + 2],
row_bytes[off + 3],
]);
tail += qv * v;
}
let mut buf = [0.0f32; 8];
_mm256_storeu_ps(buf.as_mut_ptr(), acc);
buf.iter().sum::<f32>() + tail
}
}
#[target_feature(enable = "avx2,fma")]
pub(super) unsafe fn dot_f32_i4_avx2(
q: &[f32],
codes: &[u8],
group_scales: &[f32],
dim: usize,
block: usize,
scratch: &mut [f32],
) -> f32 {
unsafe {
use std::arch::x86_64::*;
let nbytes = dim / 2;
let chunks = nbytes / 16;
let lo_mask = _mm_set1_epi8(0x0F);
for c in 0..chunks {
let packed = _mm_loadu_si128(codes.as_ptr().add(c * 16) as *const __m128i);
let lo_masked = _mm_and_si128(packed, lo_mask);
let lo = mm_srai_epi8_4(_mm_slli_epi16(lo_masked, 4));
let hi = mm_srai_epi8_4(packed);
let lo_part = _mm_unpacklo_epi8(lo, hi); let hi_part = _mm_unpackhi_epi8(lo, hi); store_i8x16_as_f32(lo_part, &mut scratch[c * 32..]);
store_i8x16_as_f32(hi_part, &mut scratch[c * 32 + 16..]);
}
for idx in (chunks * 32)..dim {
let byte = codes[idx / 2];
let nib = if idx % 2 == 0 { byte } else { byte >> 4 };
let n = nib & 0x0F;
let s = if n & 0x08 != 0 {
(n | 0xF0) as i8
} else {
n as i8
};
scratch[idx] = s as f32;
}
dot_scratch_blocked(q, scratch, group_scales, dim, block)
}
}
#[target_feature(enable = "avx2,fma")]
#[allow(unused_unsafe)]
unsafe fn mm_srai_epi8_4(v: std::arch::x86_64::__m128i) -> std::arch::x86_64::__m128i {
unsafe {
use std::arch::x86_64::*;
let sra16 = _mm_srai_epi16(v, 4);
let hi_bytes = _mm_and_si128(sra16, _mm_set1_epi16(0xFF00u16 as i16));
let lo16 = _mm_srai_epi16(_mm_srai_epi16(_mm_slli_epi16(v, 8), 4), 8);
let lo_bytes = _mm_and_si128(lo16, _mm_set1_epi16(0x00FF));
_mm_or_si128(hi_bytes, lo_bytes)
}
}
#[target_feature(enable = "avx2,fma")]
unsafe fn store_i8x16_as_f32(v: std::arch::x86_64::__m128i, out: &mut [f32]) {
assert!(out.len() >= 16, "store_i8x16_as_f32: need 16 lanes");
unsafe {
use std::arch::x86_64::*;
let lo = _mm256_cvtepi8_epi32(v);
let hi = _mm256_cvtepi8_epi32(_mm_srli_si128(v, 8));
_mm256_storeu_ps(out.as_mut_ptr(), _mm256_cvtepi32_ps(lo));
_mm256_storeu_ps(out.as_mut_ptr().add(8), _mm256_cvtepi32_ps(hi));
}
}
#[inline]
fn dot_scratch_blocked(
q: &[f32],
scratch: &[f32],
group_scales: &[f32],
dim: usize,
block: usize,
) -> f32 {
let mut acc = 0.0f32;
let _ = dim;
for (g, &scale) in group_scales.iter().enumerate() {
let mut part = 0.0f32;
let base = g * block;
for j in 0..block {
part += q[base + j] * scratch[base + j];
}
acc += part * scale;
}
acc
}
#[target_feature(enable = "avx2,fma")]
pub(super) unsafe fn dot_f32_i8_avx2(q: &[f32], row: &[i8]) -> f32 {
unsafe {
use std::arch::x86_64::*;
let dim = q.len();
let mut acc = _mm256_setzero_ps();
let chunks = dim / 8;
for i in 0..chunks {
let i8_ptr = row.as_ptr().add(i * 8) as *const i64;
let raw = _mm_set1_epi64x(i8_ptr.read_unaligned());
let widened = _mm256_cvtepi8_epi32(raw);
let f = _mm256_cvtepi32_ps(widened);
let qv = _mm256_loadu_ps(q.as_ptr().add(i * 8));
acc = _mm256_fmadd_ps(qv, f, acc);
}
let mut tail = 0.0f32;
for i in (chunks * 8)..dim {
tail += q[i] * (row[i] as f32);
}
let mut buf = [0.0f32; 8];
_mm256_storeu_ps(buf.as_mut_ptr(), acc);
buf.iter().sum::<f32>() + tail
}
}