#![allow(unsafe_op_in_unsafe_fn, clippy::missing_safety_doc)]
use core::arch::x86_64::*;
#[inline(always)]
unsafe fn make_state_m512(s0: f32, s1: f32, s2: f32, s3: f32) -> __m512 {
unsafe {
let mut v = _mm512_setzero_ps();
v = _mm512_insertf32x4::<0>(v, _mm_set1_ps(s0));
v = _mm512_insertf32x4::<1>(v, _mm_set1_ps(s1));
v = _mm512_insertf32x4::<2>(v, _mm_set1_ps(s2));
v = _mm512_insertf32x4::<3>(v, _mm_set1_ps(s3));
v
}
}
#[target_feature(enable = "avx512f,avx512vl")]
pub unsafe fn dot_product_4x_f32_avx512(weights: &[[f32; 4]], state: &[f32]) -> [f32; 4] {
let len = state.len().min(weights.len());
debug_assert!(weights.len() >= len);
let mut acc512 = _mm512_setzero_ps();
let mut i = 0;
unsafe {
while i + 4 <= len {
let w512 = _mm512_loadu_ps(weights.as_ptr().add(i) as *const f32);
let s512 = make_state_m512(
*state.get_unchecked(i),
*state.get_unchecked(i + 1),
*state.get_unchecked(i + 2),
*state.get_unchecked(i + 3),
);
acc512 = _mm512_fmadd_ps(w512, s512, acc512);
i += 4;
}
if i < len {
let rem = len - i;
let mut s_buf = [0.0f32; 4];
let mut w_buf = [[0.0f32; 4]; 4];
for j in 0..rem {
s_buf[j] = *state.get_unchecked(i + j);
w_buf[j] = *weights.as_ptr().add(i + j);
}
let w512 = _mm512_loadu_ps(w_buf.as_ptr() as *const f32);
let s512 = make_state_m512(s_buf[0], s_buf[1], s_buf[2], s_buf[3]);
acc512 = _mm512_fmadd_ps(w512, s512, acc512);
}
let v0 = _mm512_extractf32x4_ps(acc512, 0);
let v1 = _mm512_extractf32x4_ps(acc512, 1);
let v2 = _mm512_extractf32x4_ps(acc512, 2);
let v3 = _mm512_extractf32x4_ps(acc512, 3);
let r01 = _mm_add_ps(v0, v1);
let r23 = _mm_add_ps(v2, v3);
let result = _mm_add_ps(r01, r23);
let mut out = [0.0f32; 4];
_mm_storeu_ps(out.as_mut_ptr(), result);
out
}
}
#[target_feature(enable = "avx512f,avx512vl")]
pub unsafe fn dot_product_4x_f32_dual_avx512(
weights: &[[f32; 4]],
state_f0: &[f32],
state_f1: &[f32],
) -> ([f32; 4], [f32; 4]) {
let len = core::cmp::min(
weights.len(),
core::cmp::min(state_f0.len(), state_f1.len()),
);
let mut acc_f0 = _mm512_setzero_ps();
let mut acc_f1 = _mm512_setzero_ps();
let mut i = 0;
unsafe {
while i + 4 <= len {
let w512 = _mm512_loadu_ps(weights.as_ptr().add(i) as *const f32);
let s_f0_512 = make_state_m512(
*state_f0.get_unchecked(i),
*state_f0.get_unchecked(i + 1),
*state_f0.get_unchecked(i + 2),
*state_f0.get_unchecked(i + 3),
);
let s_f1_512 = make_state_m512(
*state_f1.get_unchecked(i),
*state_f1.get_unchecked(i + 1),
*state_f1.get_unchecked(i + 2),
*state_f1.get_unchecked(i + 3),
);
acc_f0 = _mm512_fmadd_ps(w512, s_f0_512, acc_f0);
acc_f1 = _mm512_fmadd_ps(w512, s_f1_512, acc_f1);
i += 4;
}
if i < len {
let rem = len - i;
let mut s0_buf = [0.0f32; 4];
let mut s1_buf = [0.0f32; 4];
let mut w_buf = [[0.0f32; 4]; 4];
for j in 0..rem {
s0_buf[j] = *state_f0.get_unchecked(i + j);
s1_buf[j] = *state_f1.get_unchecked(i + j);
w_buf[j] = *weights.as_ptr().add(i + j);
}
let w512 = _mm512_loadu_ps(w_buf.as_ptr() as *const f32);
let s_f0_512 = make_state_m512(s0_buf[0], s0_buf[1], s0_buf[2], s0_buf[3]);
let s_f1_512 = make_state_m512(s1_buf[0], s1_buf[1], s1_buf[2], s1_buf[3]);
acc_f0 = _mm512_fmadd_ps(w512, s_f0_512, acc_f0);
acc_f1 = _mm512_fmadd_ps(w512, s_f1_512, acc_f1);
}
let v0_0 = _mm512_extractf32x4_ps(acc_f0, 0);
let v0_1 = _mm512_extractf32x4_ps(acc_f0, 1);
let v0_2 = _mm512_extractf32x4_ps(acc_f0, 2);
let v0_3 = _mm512_extractf32x4_ps(acc_f0, 3);
let r0_01 = _mm_add_ps(v0_0, v0_1);
let r0_23 = _mm_add_ps(v0_2, v0_3);
let result_f0 = _mm_add_ps(r0_01, r0_23);
let v1_0 = _mm512_extractf32x4_ps(acc_f1, 0);
let v1_1 = _mm512_extractf32x4_ps(acc_f1, 1);
let v1_2 = _mm512_extractf32x4_ps(acc_f1, 2);
let v1_3 = _mm512_extractf32x4_ps(acc_f1, 3);
let r1_01 = _mm_add_ps(v1_0, v1_1);
let r1_23 = _mm_add_ps(v1_2, v1_3);
let result_f1 = _mm_add_ps(r1_01, r1_23);
let mut out_f0 = [0.0f32; 4];
let mut out_f1 = [0.0f32; 4];
_mm_storeu_ps(out_f0.as_mut_ptr(), result_f0);
_mm_storeu_ps(out_f1.as_mut_ptr(), result_f1);
(out_f0, out_f1)
}
}
#[target_feature(enable = "avx512f,avx512vl")]
pub unsafe fn dot_product_4x_f32_accumulate_avx512(
weights: &[[f32; 4]],
state: &[f32],
init: &[f32; 4],
) -> [f32; 4] {
let len = state.len().min(weights.len());
debug_assert!(weights.len() >= len);
let init128 = _mm_loadu_ps(init.as_ptr());
let mut acc512 = _mm512_setzero_ps();
acc512 = _mm512_insertf32x4::<0>(acc512, init128);
let mut i = 0;
unsafe {
while i + 4 <= len {
let w512 = _mm512_loadu_ps(weights.as_ptr().add(i) as *const f32);
let s512 = make_state_m512(
*state.get_unchecked(i),
*state.get_unchecked(i + 1),
*state.get_unchecked(i + 2),
*state.get_unchecked(i + 3),
);
acc512 = _mm512_fmadd_ps(w512, s512, acc512);
i += 4;
}
if i < len {
let rem = len - i;
let mut s_buf = [0.0f32; 4];
let mut w_buf = [[0.0f32; 4]; 4];
for j in 0..rem {
s_buf[j] = *state.get_unchecked(i + j);
w_buf[j] = *weights.as_ptr().add(i + j);
}
let w512 = _mm512_loadu_ps(w_buf.as_ptr() as *const f32);
let s512 = make_state_m512(s_buf[0], s_buf[1], s_buf[2], s_buf[3]);
acc512 = _mm512_fmadd_ps(w512, s512, acc512);
}
let v0 = _mm512_extractf32x4_ps(acc512, 0);
let v1 = _mm512_extractf32x4_ps(acc512, 1);
let v2 = _mm512_extractf32x4_ps(acc512, 2);
let v3 = _mm512_extractf32x4_ps(acc512, 3);
let r01 = _mm_add_ps(v0, v1);
let r23 = _mm_add_ps(v2, v3);
let result = _mm_add_ps(r01, r23);
let mut out = [0.0f32; 4];
_mm_storeu_ps(out.as_mut_ptr(), result);
out
}
}
#[target_feature(enable = "avx512f,avx512vl")]
pub unsafe fn dot_product_4x_f32_dual_accumulate_avx512(
weights: &[[f32; 4]],
state_f0: &[f32],
state_f1: &[f32],
init_f0: &[f32; 4],
init_f1: &[f32; 4],
) -> ([f32; 4], [f32; 4]) {
let len = core::cmp::min(
weights.len(),
core::cmp::min(state_f0.len(), state_f1.len()),
);
let init_f0_128 = _mm_loadu_ps(init_f0.as_ptr());
let init_f1_128 = _mm_loadu_ps(init_f1.as_ptr());
let mut acc_f0 = _mm512_setzero_ps();
let mut acc_f1 = _mm512_setzero_ps();
acc_f0 = _mm512_insertf32x4::<0>(acc_f0, init_f0_128);
acc_f1 = _mm512_insertf32x4::<0>(acc_f1, init_f1_128);
let mut i = 0;
unsafe {
while i + 4 <= len {
let w512 = _mm512_loadu_ps(weights.as_ptr().add(i) as *const f32);
let s_f0_512 = make_state_m512(
*state_f0.get_unchecked(i),
*state_f0.get_unchecked(i + 1),
*state_f0.get_unchecked(i + 2),
*state_f0.get_unchecked(i + 3),
);
let s_f1_512 = make_state_m512(
*state_f1.get_unchecked(i),
*state_f1.get_unchecked(i + 1),
*state_f1.get_unchecked(i + 2),
*state_f1.get_unchecked(i + 3),
);
acc_f0 = _mm512_fmadd_ps(w512, s_f0_512, acc_f0);
acc_f1 = _mm512_fmadd_ps(w512, s_f1_512, acc_f1);
i += 4;
}
if i < len {
let rem = len - i;
let mut s0_buf = [0.0f32; 4];
let mut s1_buf = [0.0f32; 4];
let mut w_buf = [[0.0f32; 4]; 4];
for j in 0..rem {
s0_buf[j] = *state_f0.get_unchecked(i + j);
s1_buf[j] = *state_f1.get_unchecked(i + j);
w_buf[j] = *weights.as_ptr().add(i + j);
}
let w512 = _mm512_loadu_ps(w_buf.as_ptr() as *const f32);
let s_f0_512 = make_state_m512(s0_buf[0], s0_buf[1], s0_buf[2], s0_buf[3]);
let s_f1_512 = make_state_m512(s1_buf[0], s1_buf[1], s1_buf[2], s1_buf[3]);
acc_f0 = _mm512_fmadd_ps(w512, s_f0_512, acc_f0);
acc_f1 = _mm512_fmadd_ps(w512, s_f1_512, acc_f1);
}
let v0_0 = _mm512_extractf32x4_ps(acc_f0, 0);
let v0_1 = _mm512_extractf32x4_ps(acc_f0, 1);
let v0_2 = _mm512_extractf32x4_ps(acc_f0, 2);
let v0_3 = _mm512_extractf32x4_ps(acc_f0, 3);
let r0_01 = _mm_add_ps(v0_0, v0_1);
let r0_23 = _mm_add_ps(v0_2, v0_3);
let result_f0 = _mm_add_ps(r0_01, r0_23);
let v1_0 = _mm512_extractf32x4_ps(acc_f1, 0);
let v1_1 = _mm512_extractf32x4_ps(acc_f1, 1);
let v1_2 = _mm512_extractf32x4_ps(acc_f1, 2);
let v1_3 = _mm512_extractf32x4_ps(acc_f1, 3);
let r1_01 = _mm_add_ps(v1_0, v1_1);
let r1_23 = _mm_add_ps(v1_2, v1_3);
let result_f1 = _mm_add_ps(r1_01, r1_23);
let mut out_f0 = [0.0f32; 4];
let mut out_f1 = [0.0f32; 4];
_mm_storeu_ps(out_f0.as_mut_ptr(), result_f0);
_mm_storeu_ps(out_f1.as_mut_ptr(), result_f1);
(out_f0, out_f1)
}
}