#![allow(
unsafe_op_in_unsafe_fn,
clippy::missing_safety_doc,
clippy::too_many_arguments
)]
use crate::dot4x_simd8_avx2;
use crate::dot4x_simd8_avx2_tail2;
use crate::dot4x_simd16_avx2;
use crate::math::common::half::f16_bits_to_f32_f16c;
use core::arch::x86_64::*;
#[target_feature(enable = "f16c")]
pub unsafe fn dot_product_4x_interleaved_dual_frame_avx2(
weights: &[[u16; 4]],
state_f0: &[f32],
state_f1: &[f32],
) -> ([f32; 4], [f32; 4]) {
let len = state_f0.len().min(state_f1.len()).min(weights.len());
debug_assert!(weights.len() >= len);
let mut i = 0;
unsafe {
let mut sum0_f0 = _mm256_setzero_ps();
let mut sum1_f0 = _mm256_setzero_ps();
let mut sum2_f0 = _mm256_setzero_ps();
let mut sum3_f0 = _mm256_setzero_ps();
let mut sum0_f1 = _mm256_setzero_ps();
let mut sum1_f1 = _mm256_setzero_ps();
let mut sum2_f1 = _mm256_setzero_ps();
let mut sum3_f1 = _mm256_setzero_ps();
dot4x_simd8_avx2_tail2!(
i,
len,
{
let s0_f0 = _mm256_broadcast_ss(&state_f0[i]);
let s1_f0 = _mm256_broadcast_ss(&state_f0[i + 1]);
let s01_f0 = _mm256_blend_ps(s0_f0, s1_f0, 0b11110000);
let s0_f1 = _mm256_broadcast_ss(&state_f1[i]);
let s1_f1 = _mm256_broadcast_ss(&state_f1[i + 1]);
let s01_f1 = _mm256_blend_ps(s0_f1, s1_f1, 0b11110000);
let w01 =
_mm256_cvtph_ps(_mm_loadu_si128(weights.as_ptr().add(i) as *const __m128i));
sum0_f0 = _mm256_fmadd_ps(w01, s01_f0, sum0_f0);
sum0_f1 = _mm256_fmadd_ps(w01, s01_f1, sum0_f1);
let s2_f0 = _mm256_broadcast_ss(&state_f0[i + 2]);
let s3_f0 = _mm256_broadcast_ss(&state_f0[i + 3]);
let s23_f0 = _mm256_blend_ps(s2_f0, s3_f0, 0b11110000);
let s2_f1 = _mm256_broadcast_ss(&state_f1[i + 2]);
let s3_f1 = _mm256_broadcast_ss(&state_f1[i + 3]);
let s23_f1 = _mm256_blend_ps(s2_f1, s3_f1, 0b11110000);
let w23 = _mm256_cvtph_ps(_mm_loadu_si128(
weights.as_ptr().add(i + 2) as *const __m128i
));
sum1_f0 = _mm256_fmadd_ps(w23, s23_f0, sum1_f0);
sum1_f1 = _mm256_fmadd_ps(w23, s23_f1, sum1_f1);
let s4_f0 = _mm256_broadcast_ss(&state_f0[i + 4]);
let s5_f0 = _mm256_broadcast_ss(&state_f0[i + 5]);
let s45_f0 = _mm256_blend_ps(s4_f0, s5_f0, 0b11110000);
let s4_f1 = _mm256_broadcast_ss(&state_f1[i + 4]);
let s5_f1 = _mm256_broadcast_ss(&state_f1[i + 5]);
let s45_f1 = _mm256_blend_ps(s4_f1, s5_f1, 0b11110000);
let w45 = _mm256_cvtph_ps(_mm_loadu_si128(
weights.as_ptr().add(i + 4) as *const __m128i
));
sum2_f0 = _mm256_fmadd_ps(w45, s45_f0, sum2_f0);
sum2_f1 = _mm256_fmadd_ps(w45, s45_f1, sum2_f1);
let s6_f0 = _mm256_broadcast_ss(&state_f0[i + 6]);
let s7_f0 = _mm256_broadcast_ss(&state_f0[i + 7]);
let s67_f0 = _mm256_blend_ps(s6_f0, s7_f0, 0b11110000);
let s6_f1 = _mm256_broadcast_ss(&state_f1[i + 6]);
let s7_f1 = _mm256_broadcast_ss(&state_f1[i + 7]);
let s67_f1 = _mm256_blend_ps(s6_f1, s7_f1, 0b11110000);
let w67 = _mm256_cvtph_ps(_mm_loadu_si128(
weights.as_ptr().add(i + 6) as *const __m128i
));
sum3_f0 = _mm256_fmadd_ps(w67, s67_f0, sum3_f0);
sum3_f1 = _mm256_fmadd_ps(w67, s67_f1, sum3_f1);
},
{
let s0_f0 = _mm256_broadcast_ss(&state_f0[i]);
let s1_f0 = _mm256_broadcast_ss(&state_f0[i + 1]);
let s01_f0 = _mm256_blend_ps(s0_f0, s1_f0, 0b11110000);
let s0_f1 = _mm256_broadcast_ss(&state_f1[i]);
let s1_f1 = _mm256_broadcast_ss(&state_f1[i + 1]);
let s01_f1 = _mm256_blend_ps(s0_f1, s1_f1, 0b11110000);
let w01 =
_mm256_cvtph_ps(_mm_loadu_si128(weights.as_ptr().add(i) as *const __m128i));
sum0_f0 = _mm256_fmadd_ps(w01, s01_f0, sum0_f0);
sum0_f1 = _mm256_fmadd_ps(w01, s01_f1, sum0_f1);
}
);
let sum01_f0 = _mm256_add_ps(sum0_f0, sum1_f0);
let sum23_f0 = _mm256_add_ps(sum2_f0, sum3_f0);
let sum_f0 = _mm256_add_ps(sum01_f0, sum23_f0);
let sum01_f1 = _mm256_add_ps(sum0_f1, sum1_f1);
let sum23_f1 = _mm256_add_ps(sum2_f1, sum3_f1);
let sum_f1 = _mm256_add_ps(sum01_f1, sum23_f1);
let lower_f0 = _mm256_castps256_ps128(sum_f0);
let upper_f0 = _mm256_extractf128_ps(sum_f0, 1);
let mut sum128_f0 = _mm_add_ps(lower_f0, upper_f0);
let lower_f1 = _mm256_castps256_ps128(sum_f1);
let upper_f1 = _mm256_extractf128_ps(sum_f1, 1);
let mut sum128_f1 = _mm_add_ps(lower_f1, upper_f1);
while i < len {
let s0_f0 = _mm_load1_ps(state_f0.as_ptr().add(i));
let s0_f1 = _mm_load1_ps(state_f1.as_ptr().add(i));
let w0 = _mm_cvtph_ps(_mm_loadu_si64(
weights.as_ptr().add(i) as *const u16 as *const u8
));
sum128_f0 = _mm_fmadd_ps(w0, s0_f0, sum128_f0);
sum128_f1 = _mm_fmadd_ps(w0, s0_f1, sum128_f1);
i += 1;
}
let mut out_f0 = [0.0; 4];
let mut out_f1 = [0.0; 4];
_mm_storeu_ps(out_f0.as_mut_ptr(), sum128_f0);
_mm_storeu_ps(out_f1.as_mut_ptr(), sum128_f1);
(out_f0, out_f1)
}
}
#[target_feature(enable = "f16c")]
pub unsafe fn dot_product_batch_4x_avx2(
h0: &[f32],
h1: &[f32],
h2: &[f32],
h3: &[f32],
weights: &[u16],
) -> [f32; 4] {
let len = weights
.len()
.min(h0.len())
.min(h1.len())
.min(h2.len())
.min(h3.len());
debug_assert!(h0.len() >= len && h1.len() >= len && h2.len() >= len && h3.len() >= len);
let mut i = 0;
unsafe {
let mut sum0 = _mm256_setzero_ps();
let mut sum1 = _mm256_setzero_ps();
let mut sum2 = _mm256_setzero_ps();
let mut sum3 = _mm256_setzero_ps();
dot4x_simd16_avx2!(i, len, {
_mm_prefetch::<_MM_HINT_T0>(weights.as_ptr().wrapping_add(i + 32) as *const i8);
_mm_prefetch::<_MM_HINT_T0>(h0.as_ptr().wrapping_add(i + 32) as *const i8);
_mm_prefetch::<_MM_HINT_T0>(h1.as_ptr().wrapping_add(i + 32) as *const i8);
_mm_prefetch::<_MM_HINT_T0>(h2.as_ptr().wrapping_add(i + 32) as *const i8);
_mm_prefetch::<_MM_HINT_T0>(h3.as_ptr().wrapping_add(i + 32) as *const i8);
let vw_0 = _mm256_cvtph_ps(_mm_loadu_si128(weights.as_ptr().add(i) as *const __m128i));
let vh0_0 = _mm256_loadu_ps(h0.as_ptr().add(i));
sum0 = _mm256_fmadd_ps(vw_0, vh0_0, sum0);
let vh1_0 = _mm256_loadu_ps(h1.as_ptr().add(i));
sum1 = _mm256_fmadd_ps(vw_0, vh1_0, sum1);
let vh2_0 = _mm256_loadu_ps(h2.as_ptr().add(i));
sum2 = _mm256_fmadd_ps(vw_0, vh2_0, sum2);
let vh3_0 = _mm256_loadu_ps(h3.as_ptr().add(i));
sum3 = _mm256_fmadd_ps(vw_0, vh3_0, sum3);
let vw_1 = _mm256_cvtph_ps(_mm_loadu_si128(
weights.as_ptr().add(i + 8) as *const __m128i
));
let vh0_1 = _mm256_loadu_ps(h0.as_ptr().add(i + 8));
sum0 = _mm256_fmadd_ps(vw_1, vh0_1, sum0);
let vh1_1 = _mm256_loadu_ps(h1.as_ptr().add(i + 8));
sum1 = _mm256_fmadd_ps(vw_1, vh1_1, sum1);
let vh2_1 = _mm256_loadu_ps(h2.as_ptr().add(i + 8));
sum2 = _mm256_fmadd_ps(vw_1, vh2_1, sum2);
let vh3_1 = _mm256_loadu_ps(h3.as_ptr().add(i + 8));
sum3 = _mm256_fmadd_ps(vw_1, vh3_1, sum3);
});
dot4x_simd8_avx2!(i, len, {
let vw = _mm256_cvtph_ps(_mm_loadu_si128(weights.as_ptr().add(i) as *const __m128i));
let vh0 = _mm256_loadu_ps(h0.as_ptr().add(i));
sum0 = _mm256_fmadd_ps(vw, vh0, sum0);
let vh1 = _mm256_loadu_ps(h1.as_ptr().add(i));
sum1 = _mm256_fmadd_ps(vw, vh1, sum1);
let vh2 = _mm256_loadu_ps(h2.as_ptr().add(i));
sum2 = _mm256_fmadd_ps(vw, vh2, sum2);
let vh3 = _mm256_loadu_ps(h3.as_ptr().add(i));
sum3 = _mm256_fmadd_ps(vw, vh3, sum3);
});
let mut s0 = crate::math::common::utility::hsum_avx2(sum0);
let mut s1 = crate::math::common::utility::hsum_avx2(sum1);
let mut s2 = crate::math::common::utility::hsum_avx2(sum2);
let mut s3 = crate::math::common::utility::hsum_avx2(sum3);
let mut c0 = 0.0f32;
let mut c1 = 0.0f32;
let mut c2 = 0.0f32;
let mut c3 = 0.0f32;
while i < len {
let w = f16_bits_to_f32_f16c(weights[i]);
(s0, c0) = crate::math::common::kahan_add(s0, c0, w * h0[i]);
(s1, c1) = crate::math::common::kahan_add(s1, c1, w * h1[i]);
(s2, c2) = crate::math::common::kahan_add(s2, c2, w * h2[i]);
(s3, c3) = crate::math::common::kahan_add(s3, c3, w * h3[i]);
i += 1;
}
[s0, s1, s2, s3]
}
}