#![allow(unsafe_op_in_unsafe_fn, clippy::missing_safety_doc)]
use crate::dot4x_simd4;
use core::arch::x86_64::*;
#[target_feature(enable = "avx2,fma")]
pub unsafe fn dot_product_8x_f32_avx2(weights: &[[f32; 8]], state: &[f32]) -> [f32; 8] {
let len = state.len();
let mut acc0 = _mm256_setzero_ps();
let mut acc1 = _mm256_setzero_ps();
let mut acc2 = _mm256_setzero_ps();
let mut acc3 = _mm256_setzero_ps();
let mut i = 0;
unsafe {
dot4x_simd4!(i, len, {
let w0 = _mm256_loadu_ps(weights.as_ptr().add(i) as *const f32);
let s0 = _mm256_set1_ps(*state.get_unchecked(i));
acc0 = _mm256_fmadd_ps(w0, s0, acc0);
let w1 = _mm256_loadu_ps(weights.as_ptr().add(i + 1) as *const f32);
let s1 = _mm256_set1_ps(*state.get_unchecked(i + 1));
acc1 = _mm256_fmadd_ps(w1, s1, acc1);
let w2 = _mm256_loadu_ps(weights.as_ptr().add(i + 2) as *const f32);
let s2 = _mm256_set1_ps(*state.get_unchecked(i + 2));
acc2 = _mm256_fmadd_ps(w2, s2, acc2);
let w3 = _mm256_loadu_ps(weights.as_ptr().add(i + 3) as *const f32);
let s3 = _mm256_set1_ps(*state.get_unchecked(i + 3));
acc3 = _mm256_fmadd_ps(w3, s3, acc3);
});
while i < len {
let s = _mm256_set1_ps(*state.get_unchecked(i));
let w = _mm256_loadu_ps(weights.as_ptr().add(i) as *const f32);
acc0 = _mm256_fmadd_ps(w, s, acc0);
i += 1;
}
acc0 = _mm256_add_ps(acc0, acc1);
acc2 = _mm256_add_ps(acc2, acc3);
acc0 = _mm256_add_ps(acc0, acc2);
let mut out = [0.0f32; 8];
_mm256_storeu_ps(out.as_mut_ptr(), acc0);
out
}
}
#[target_feature(enable = "avx2,fma")]
pub unsafe fn dot_product_8x_f32_dual_avx2(
weights: &[[f32; 8]],
state_f0: &[f32],
state_f1: &[f32],
) -> ([f32; 8], [f32; 8]) {
let len = core::cmp::min(
weights.len(),
core::cmp::min(state_f0.len(), state_f1.len()),
);
let mut acc_f0_0 = _mm256_setzero_ps();
let mut acc_f0_1 = _mm256_setzero_ps();
let mut acc_f0_2 = _mm256_setzero_ps();
let mut acc_f0_3 = _mm256_setzero_ps();
let mut acc_f1_0 = _mm256_setzero_ps();
let mut acc_f1_1 = _mm256_setzero_ps();
let mut acc_f1_2 = _mm256_setzero_ps();
let mut acc_f1_3 = _mm256_setzero_ps();
let mut i = 0;
unsafe {
dot4x_simd4!(i, len, {
let w0 = _mm256_loadu_ps(weights.as_ptr().add(i) as *const f32);
let s_f0_0 = _mm256_set1_ps(*state_f0.get_unchecked(i));
let s_f1_0 = _mm256_set1_ps(*state_f1.get_unchecked(i));
acc_f0_0 = _mm256_fmadd_ps(w0, s_f0_0, acc_f0_0);
acc_f1_0 = _mm256_fmadd_ps(w0, s_f1_0, acc_f1_0);
let w1 = _mm256_loadu_ps(weights.as_ptr().add(i + 1) as *const f32);
let s_f0_1 = _mm256_set1_ps(*state_f0.get_unchecked(i + 1));
let s_f1_1 = _mm256_set1_ps(*state_f1.get_unchecked(i + 1));
acc_f0_1 = _mm256_fmadd_ps(w1, s_f0_1, acc_f0_1);
acc_f1_1 = _mm256_fmadd_ps(w1, s_f1_1, acc_f1_1);
let w2 = _mm256_loadu_ps(weights.as_ptr().add(i + 2) as *const f32);
let s_f0_2 = _mm256_set1_ps(*state_f0.get_unchecked(i + 2));
let s_f1_2 = _mm256_set1_ps(*state_f1.get_unchecked(i + 2));
acc_f0_2 = _mm256_fmadd_ps(w2, s_f0_2, acc_f0_2);
acc_f1_2 = _mm256_fmadd_ps(w2, s_f1_2, acc_f1_2);
let w3 = _mm256_loadu_ps(weights.as_ptr().add(i + 3) as *const f32);
let s_f0_3 = _mm256_set1_ps(*state_f0.get_unchecked(i + 3));
let s_f1_3 = _mm256_set1_ps(*state_f1.get_unchecked(i + 3));
acc_f0_3 = _mm256_fmadd_ps(w3, s_f0_3, acc_f0_3);
acc_f1_3 = _mm256_fmadd_ps(w3, s_f1_3, acc_f1_3);
});
while i < len {
let w = _mm256_loadu_ps(weights.as_ptr().add(i) as *const f32);
let s_f0 = _mm256_set1_ps(*state_f0.get_unchecked(i));
let s_f1 = _mm256_set1_ps(*state_f1.get_unchecked(i));
acc_f0_0 = _mm256_fmadd_ps(w, s_f0, acc_f0_0);
acc_f1_0 = _mm256_fmadd_ps(w, s_f1, acc_f1_0);
i += 1;
}
acc_f0_0 = _mm256_add_ps(acc_f0_0, acc_f0_1);
acc_f0_2 = _mm256_add_ps(acc_f0_2, acc_f0_3);
acc_f0_0 = _mm256_add_ps(acc_f0_0, acc_f0_2);
acc_f1_0 = _mm256_add_ps(acc_f1_0, acc_f1_1);
acc_f1_2 = _mm256_add_ps(acc_f1_2, acc_f1_3);
acc_f1_0 = _mm256_add_ps(acc_f1_0, acc_f1_2);
let mut out_f0 = [0.0f32; 8];
let mut out_f1 = [0.0f32; 8];
_mm256_storeu_ps(out_f0.as_mut_ptr(), acc_f0_0);
_mm256_storeu_ps(out_f1.as_mut_ptr(), acc_f1_0);
(out_f0, out_f1)
}
}
#[target_feature(enable = "avx2,fma")]
pub unsafe fn dot_product_8x_f32_accumulate_avx2(
weights: &[[f32; 8]],
state: &[f32],
init: &[f32; 8],
) -> [f32; 8] {
let len = state.len();
let mut acc0 = _mm256_loadu_ps(init.as_ptr());
let mut acc1 = _mm256_setzero_ps();
let mut acc2 = _mm256_setzero_ps();
let mut acc3 = _mm256_setzero_ps();
let mut i = 0;
unsafe {
dot4x_simd4!(i, len, {
let w0 = _mm256_loadu_ps(weights.as_ptr().add(i) as *const f32);
let s0 = _mm256_set1_ps(*state.get_unchecked(i));
acc0 = _mm256_fmadd_ps(w0, s0, acc0);
let w1 = _mm256_loadu_ps(weights.as_ptr().add(i + 1) as *const f32);
let s1 = _mm256_set1_ps(*state.get_unchecked(i + 1));
acc1 = _mm256_fmadd_ps(w1, s1, acc1);
let w2 = _mm256_loadu_ps(weights.as_ptr().add(i + 2) as *const f32);
let s2 = _mm256_set1_ps(*state.get_unchecked(i + 2));
acc2 = _mm256_fmadd_ps(w2, s2, acc2);
let w3 = _mm256_loadu_ps(weights.as_ptr().add(i + 3) as *const f32);
let s3 = _mm256_set1_ps(*state.get_unchecked(i + 3));
acc3 = _mm256_fmadd_ps(w3, s3, acc3);
});
while i < len {
let s = _mm256_set1_ps(*state.get_unchecked(i));
let w = _mm256_loadu_ps(weights.as_ptr().add(i) as *const f32);
acc0 = _mm256_fmadd_ps(w, s, acc0);
i += 1;
}
acc0 = _mm256_add_ps(acc0, acc1);
acc2 = _mm256_add_ps(acc2, acc3);
acc0 = _mm256_add_ps(acc0, acc2);
let mut out = [0.0f32; 8];
_mm256_storeu_ps(out.as_mut_ptr(), acc0);
out
}
}
#[target_feature(enable = "avx2,fma")]
pub unsafe fn dot_product_8x_f32_dual_accumulate_avx2(
weights: &[[f32; 8]],
state_f0: &[f32],
state_f1: &[f32],
init_f0: &[f32; 8],
init_f1: &[f32; 8],
) -> ([f32; 8], [f32; 8]) {
let len = core::cmp::min(
weights.len(),
core::cmp::min(state_f0.len(), state_f1.len()),
);
let mut acc_f0_0 = _mm256_loadu_ps(init_f0.as_ptr());
let mut acc_f0_1 = _mm256_setzero_ps();
let mut acc_f0_2 = _mm256_setzero_ps();
let mut acc_f0_3 = _mm256_setzero_ps();
let mut acc_f1_0 = _mm256_loadu_ps(init_f1.as_ptr());
let mut acc_f1_1 = _mm256_setzero_ps();
let mut acc_f1_2 = _mm256_setzero_ps();
let mut acc_f1_3 = _mm256_setzero_ps();
let mut i = 0;
unsafe {
dot4x_simd4!(i, len, {
let w0 = _mm256_loadu_ps(weights.as_ptr().add(i) as *const f32);
let s_f0_0 = _mm256_set1_ps(*state_f0.get_unchecked(i));
let s_f1_0 = _mm256_set1_ps(*state_f1.get_unchecked(i));
acc_f0_0 = _mm256_fmadd_ps(w0, s_f0_0, acc_f0_0);
acc_f1_0 = _mm256_fmadd_ps(w0, s_f1_0, acc_f1_0);
let w1 = _mm256_loadu_ps(weights.as_ptr().add(i + 1) as *const f32);
let s_f0_1 = _mm256_set1_ps(*state_f0.get_unchecked(i + 1));
let s_f1_1 = _mm256_set1_ps(*state_f1.get_unchecked(i + 1));
acc_f0_1 = _mm256_fmadd_ps(w1, s_f0_1, acc_f0_1);
acc_f1_1 = _mm256_fmadd_ps(w1, s_f1_1, acc_f1_1);
let w2 = _mm256_loadu_ps(weights.as_ptr().add(i + 2) as *const f32);
let s_f0_2 = _mm256_set1_ps(*state_f0.get_unchecked(i + 2));
let s_f1_2 = _mm256_set1_ps(*state_f1.get_unchecked(i + 2));
acc_f0_2 = _mm256_fmadd_ps(w2, s_f0_2, acc_f0_2);
acc_f1_2 = _mm256_fmadd_ps(w2, s_f1_2, acc_f1_2);
let w3 = _mm256_loadu_ps(weights.as_ptr().add(i + 3) as *const f32);
let s_f0_3 = _mm256_set1_ps(*state_f0.get_unchecked(i + 3));
let s_f1_3 = _mm256_set1_ps(*state_f1.get_unchecked(i + 3));
acc_f0_3 = _mm256_fmadd_ps(w3, s_f0_3, acc_f0_3);
acc_f1_3 = _mm256_fmadd_ps(w3, s_f1_3, acc_f1_3);
});
while i < len {
let w = _mm256_loadu_ps(weights.as_ptr().add(i) as *const f32);
let s_f0 = _mm256_set1_ps(*state_f0.get_unchecked(i));
let s_f1 = _mm256_set1_ps(*state_f1.get_unchecked(i));
acc_f0_0 = _mm256_fmadd_ps(w, s_f0, acc_f0_0);
acc_f1_0 = _mm256_fmadd_ps(w, s_f1, acc_f1_0);
i += 1;
}
acc_f0_0 = _mm256_add_ps(acc_f0_0, acc_f0_1);
acc_f0_2 = _mm256_add_ps(acc_f0_2, acc_f0_3);
acc_f0_0 = _mm256_add_ps(acc_f0_0, acc_f0_2);
acc_f1_0 = _mm256_add_ps(acc_f1_0, acc_f1_1);
acc_f1_2 = _mm256_add_ps(acc_f1_2, acc_f1_3);
acc_f1_0 = _mm256_add_ps(acc_f1_0, acc_f1_2);
let mut out_f0 = [0.0f32; 8];
let mut out_f1 = [0.0f32; 8];
_mm256_storeu_ps(out_f0.as_mut_ptr(), acc_f0_0);
_mm256_storeu_ps(out_f1.as_mut_ptr(), acc_f1_0);
(out_f0, out_f1)
}
}