use core::arch::x86_64::{
__m512i, _mm_set_epi64x, _mm512_broadcast_i32x4, _mm512_clmulepi64_epi128, _mm512_loadu_si512,
_mm512_setzero_si512, _mm512_shuffle_epi32, _mm512_storeu_si512, _mm512_unpacklo_epi64,
_mm512_xor_si512,
};
#[cfg(not(all(feature = "wide-poly", target_feature = "avx512bw")))]
use core::arch::x86_64::{
_mm512_set1_epi64, _mm512_sllv_epi64, _mm512_srlv_epi64, _mm512_unpackhi_epi64,
};
use p3_field::interleave::{interleave_u128, interleave_u256};
pub(crate) type Reg = __m512i;
pub(crate) const WIDTH: usize = 4;
#[inline(always)]
pub(crate) fn zero() -> Reg {
unsafe { _mm512_setzero_si512() }
}
#[inline(always)]
pub(crate) fn xor(a: Reg, b: Reg) -> Reg {
unsafe { _mm512_xor_si512(a, b) }
}
#[inline(always)]
pub(crate) fn unpack_low_64(a: Reg, b: Reg) -> Reg {
unsafe { _mm512_unpacklo_epi64(a, b) }
}
#[cfg(not(all(feature = "wide-poly", target_feature = "avx512bw")))]
#[inline(always)]
pub(crate) fn unpack_high_64(a: Reg, b: Reg) -> Reg {
unsafe { _mm512_unpackhi_epi64(a, b) }
}
#[cfg(not(all(feature = "wide-poly", target_feature = "avx512bw")))]
#[inline(always)]
pub(crate) fn shl_64<const N: i32>(a: Reg) -> Reg {
unsafe { _mm512_sllv_epi64(a, _mm512_set1_epi64(i64::from(N))) }
}
#[cfg(not(all(feature = "wide-poly", target_feature = "avx512bw")))]
#[inline(always)]
pub(crate) fn shr_64<const N: i32>(a: Reg) -> Reg {
unsafe { _mm512_srlv_epi64(a, _mm512_set1_epi64(i64::from(N))) }
}
#[inline(always)]
pub(crate) fn clmul<const IMM: i32>(a: Reg, b: Reg) -> Reg {
unsafe { _mm512_clmulepi64_epi128::<IMM>(a, b) }
}
#[inline(always)]
pub(crate) fn swap_halves(a: Reg) -> Reg {
unsafe { _mm512_shuffle_epi32::<{ super::SWAP_QUADWORDS }>(a) }
}
#[inline(always)]
pub(crate) fn broadcast(value: u128) -> Reg {
unsafe {
let lane = _mm_set_epi64x((value >> 64) as i64, value as i64);
_mm512_broadcast_i32x4(lane)
}
}
#[inline(always)]
pub(crate) unsafe fn load(from: *const u128) -> Reg {
unsafe { _mm512_loadu_si512(from.cast()) }
}
#[inline(always)]
pub(crate) unsafe fn store(to: *mut u128, value: Reg) {
unsafe { _mm512_storeu_si512(to.cast(), value) }
}
#[inline(always)]
pub(crate) fn interleave(a: Reg, b: Reg, block_len: usize) -> (Reg, Reg) {
match block_len {
1 => interleave_u128(a, b),
2 => interleave_u256(a, b),
WIDTH => (a, b),
_ => panic!("unsupported block_len"),
}
}