#![allow(
unsafe_op_in_unsafe_fn,
clippy::missing_safety_doc,
clippy::too_many_arguments
)]
use core::arch::x86_64::*;
#[target_feature(enable = "avx512f,avx512vl")]
pub unsafe fn dot_product_4x_interleaved_dual_frame_avx512(
weights: &[[u16; 4]],
state_f0: &[f32],
state_f1: &[f32],
) -> ([f32; 4], [f32; 4]) {
let len = weights.len().min(state_f0.len()).min(state_f1.len());
debug_assert!(weights.len() >= len);
let mut i = 0;
unsafe {
let perm_idx = _mm512_set_epi32(3, 3, 3, 3, 2, 2, 2, 2, 1, 1, 1, 1, 0, 0, 0, 0);
let mut sum0_a0 = _mm512_setzero_ps();
let mut sum0_a1 = _mm512_setzero_ps();
let mut sum0_a2 = _mm512_setzero_ps();
let mut sum0_a3 = _mm512_setzero_ps();
let mut sum0_b0 = _mm512_setzero_ps();
let mut sum0_b1 = _mm512_setzero_ps();
let mut sum0_b2 = _mm512_setzero_ps();
let mut sum0_b3 = _mm512_setzero_ps();
let mut sum1_a0 = _mm512_setzero_ps();
let mut sum1_a1 = _mm512_setzero_ps();
let mut sum1_a2 = _mm512_setzero_ps();
let mut sum1_a3 = _mm512_setzero_ps();
let mut sum1_b0 = _mm512_setzero_ps();
let mut sum1_b1 = _mm512_setzero_ps();
let mut sum1_b2 = _mm512_setzero_ps();
let mut sum1_b3 = _mm512_setzero_ps();
while i + 32 <= len {
_mm_prefetch::<_MM_HINT_T0>(state_f0.as_ptr().wrapping_add(i + 64) as *const i8);
_mm_prefetch::<_MM_HINT_T0>(state_f1.as_ptr().wrapping_add(i + 64) as *const i8);
_mm_prefetch::<_MM_HINT_T0>(weights.as_ptr().wrapping_add(i + 16) as *const i8);
_mm_prefetch::<_MM_HINT_T0>(weights.as_ptr().wrapping_add(i + 32) as *const i8);
let w_a =
_mm512_cvtph_ps(_mm256_loadu_si256(weights.as_ptr().add(i) as *const __m256i));
let s0_a = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f0.as_ptr().add(i))),
);
let s1_a = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f1.as_ptr().add(i))),
);
sum0_a0 = _mm512_fmadd_ps(w_a, s0_a, sum0_a0);
sum1_a0 = _mm512_fmadd_ps(w_a, s1_a, sum1_a0);
let w_b = _mm512_cvtph_ps(_mm256_loadu_si256(
weights.as_ptr().add(i + 4) as *const __m256i
));
let s0_b = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f0.as_ptr().add(i + 4))),
);
let s1_b = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f1.as_ptr().add(i + 4))),
);
sum0_a1 = _mm512_fmadd_ps(w_b, s0_b, sum0_a1);
sum1_a1 = _mm512_fmadd_ps(w_b, s1_b, sum1_a1);
let w_c = _mm512_cvtph_ps(_mm256_loadu_si256(
weights.as_ptr().add(i + 8) as *const __m256i
));
let s0_c = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f0.as_ptr().add(i + 8))),
);
let s1_c = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f1.as_ptr().add(i + 8))),
);
sum0_a2 = _mm512_fmadd_ps(w_c, s0_c, sum0_a2);
sum1_a2 = _mm512_fmadd_ps(w_c, s1_c, sum1_a2);
let w_d = _mm512_cvtph_ps(_mm256_loadu_si256(
weights.as_ptr().add(i + 12) as *const __m256i
));
let s0_d = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f0.as_ptr().add(i + 12))),
);
let s1_d = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f1.as_ptr().add(i + 12))),
);
sum0_a3 = _mm512_fmadd_ps(w_d, s0_d, sum0_a3);
sum1_a3 = _mm512_fmadd_ps(w_d, s1_d, sum1_a3);
let w_e = _mm512_cvtph_ps(_mm256_loadu_si256(
weights.as_ptr().add(i + 16) as *const __m256i
));
let s0_e = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f0.as_ptr().add(i + 16))),
);
let s1_e = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f1.as_ptr().add(i + 16))),
);
sum0_b0 = _mm512_fmadd_ps(w_e, s0_e, sum0_b0);
sum1_b0 = _mm512_fmadd_ps(w_e, s1_e, sum1_b0);
let w_f = _mm512_cvtph_ps(_mm256_loadu_si256(
weights.as_ptr().add(i + 20) as *const __m256i
));
let s0_f = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f0.as_ptr().add(i + 20))),
);
let s1_f = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f1.as_ptr().add(i + 20))),
);
sum0_b1 = _mm512_fmadd_ps(w_f, s0_f, sum0_b1);
sum1_b1 = _mm512_fmadd_ps(w_f, s1_f, sum1_b1);
let w_g = _mm512_cvtph_ps(_mm256_loadu_si256(
weights.as_ptr().add(i + 24) as *const __m256i
));
let s0_g = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f0.as_ptr().add(i + 24))),
);
let s1_g = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f1.as_ptr().add(i + 24))),
);
sum0_b2 = _mm512_fmadd_ps(w_g, s0_g, sum0_b2);
sum1_b2 = _mm512_fmadd_ps(w_g, s1_g, sum1_b2);
let w_h = _mm512_cvtph_ps(_mm256_loadu_si256(
weights.as_ptr().add(i + 28) as *const __m256i
));
let s0_h = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f0.as_ptr().add(i + 28))),
);
let s1_h = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f1.as_ptr().add(i + 28))),
);
sum0_b3 = _mm512_fmadd_ps(w_h, s0_h, sum0_b3);
sum1_b3 = _mm512_fmadd_ps(w_h, s1_h, sum1_b3);
i += 32;
}
while i + 16 <= len {
let w_a =
_mm512_cvtph_ps(_mm256_loadu_si256(weights.as_ptr().add(i) as *const __m256i));
let s0_a = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f0.as_ptr().add(i))),
);
let s1_a = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f1.as_ptr().add(i))),
);
sum0_a0 = _mm512_fmadd_ps(w_a, s0_a, sum0_a0);
sum1_a0 = _mm512_fmadd_ps(w_a, s1_a, sum1_a0);
let w_b = _mm512_cvtph_ps(_mm256_loadu_si256(
weights.as_ptr().add(i + 4) as *const __m256i
));
let s0_b = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f0.as_ptr().add(i + 4))),
);
let s1_b = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f1.as_ptr().add(i + 4))),
);
sum0_a1 = _mm512_fmadd_ps(w_b, s0_b, sum0_a1);
sum1_a1 = _mm512_fmadd_ps(w_b, s1_b, sum1_a1);
let w_c = _mm512_cvtph_ps(_mm256_loadu_si256(
weights.as_ptr().add(i + 8) as *const __m256i
));
let s0_c = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f0.as_ptr().add(i + 8))),
);
let s1_c = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f1.as_ptr().add(i + 8))),
);
sum0_a2 = _mm512_fmadd_ps(w_c, s0_c, sum0_a2);
sum1_a2 = _mm512_fmadd_ps(w_c, s1_c, sum1_a2);
let w_d = _mm512_cvtph_ps(_mm256_loadu_si256(
weights.as_ptr().add(i + 12) as *const __m256i
));
let s0_d = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f0.as_ptr().add(i + 12))),
);
let s1_d = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f1.as_ptr().add(i + 12))),
);
sum0_a3 = _mm512_fmadd_ps(w_d, s0_d, sum0_a3);
sum1_a3 = _mm512_fmadd_ps(w_d, s1_d, sum1_a3);
i += 16;
}
while i + 4 <= len {
let w = _mm512_cvtph_ps(_mm256_loadu_si256(weights.as_ptr().add(i) as *const __m256i));
let s0 = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f0.as_ptr().add(i))),
);
let s1 = _mm512_permutexvar_ps(
perm_idx,
_mm512_castps128_ps512(_mm_loadu_ps(state_f1.as_ptr().add(i))),
);
sum0_a0 = _mm512_fmadd_ps(w, s0, sum0_a0);
sum1_a0 = _mm512_fmadd_ps(w, s1, sum1_a0);
i += 4;
}
let s0_ab = _mm512_add_ps(
_mm512_add_ps(sum0_a0, sum0_a1),
_mm512_add_ps(sum0_a2, sum0_a3),
);
let s0_all = _mm512_add_ps(
s0_ab,
_mm512_add_ps(
_mm512_add_ps(sum0_b0, sum0_b1),
_mm512_add_ps(sum0_b2, sum0_b3),
),
);
let s1_ab = _mm512_add_ps(
_mm512_add_ps(sum1_a0, sum1_a1),
_mm512_add_ps(sum1_a2, sum1_a3),
);
let s1_all = _mm512_add_ps(
s1_ab,
_mm512_add_ps(
_mm512_add_ps(sum1_b0, sum1_b1),
_mm512_add_ps(sum1_b2, sum1_b3),
),
);
let lo0 = _mm512_extractf32x4_ps(s0_all, 0);
let hi00 = _mm512_extractf32x4_ps(s0_all, 1);
let hi01 = _mm512_extractf32x4_ps(s0_all, 2);
let hi02 = _mm512_extractf32x4_ps(s0_all, 3);
let mut sum128_f0 = _mm_add_ps(_mm_add_ps(lo0, hi00), _mm_add_ps(hi01, hi02));
let lo1 = _mm512_extractf32x4_ps(s1_all, 0);
let hi10 = _mm512_extractf32x4_ps(s1_all, 1);
let hi11 = _mm512_extractf32x4_ps(s1_all, 2);
let hi12 = _mm512_extractf32x4_ps(s1_all, 3);
let mut sum128_f1 = _mm_add_ps(_mm_add_ps(lo1, hi10), _mm_add_ps(hi11, hi12));
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)
}
}