#[cfg(target_feature = "sha3")]
use core::arch::aarch64::veor3q_u64;
use core::arch::aarch64::{
uint64x2_t, vcombine_u64, vcreate_u64, vdupq_laneq_u64, vdupq_n_u64, veorq_u64, vextq_u64,
vgetq_lane_u64, vld1q_dup_u64, vld1q_u64, vmull_high_p64, vmull_p64, vreinterpretq_p64_u64,
vshlq_n_u64, vshrq_n_u64, vst1q_lane_u64, vst1q_u64, vzip1q_u64, vzip2q_u64,
};
use core::mem::transmute;
use crate::clmul::register::Register128;
use crate::clmul::wide::{
HIGH_BY_HIGH, HIGH_BY_LOW, LOW_BY_LOW, Lanes64, TAIL_64, reduce_by_multiply,
};
impl Lanes64 for uint64x2_t {
#[inline(always)]
fn zero() -> Self {
unsafe { vdupq_n_u64(0) }
}
#[inline(always)]
fn xor(self, other: Self) -> Self {
unsafe { veorq_u64(self, other) }
}
#[cfg(target_feature = "sha3")]
#[inline(always)]
fn xor3(self, b: Self, c: Self) -> Self {
unsafe { veor3q_u64(self, b, c) }
}
#[inline(always)]
fn clmul<const IMM: i32>(self, other: Self) -> Self {
unsafe {
let product = match IMM {
LOW_BY_LOW => vmull_p64(vgetq_lane_u64::<0>(self), vgetq_lane_u64::<0>(other)),
HIGH_BY_HIGH => {
vmull_high_p64(vreinterpretq_p64_u64(self), vreinterpretq_p64_u64(other))
}
HIGH_BY_LOW => vmull_high_p64(
vreinterpretq_p64_u64(self),
vreinterpretq_p64_u64(vdupq_laneq_u64::<0>(other)),
),
_ => vmull_high_p64(
vreinterpretq_p64_u64(vdupq_laneq_u64::<0>(self)),
vreinterpretq_p64_u64(other),
),
};
transmute::<u128, Self>(product)
}
}
#[inline(always)]
fn unpack_low(self, other: Self) -> Self {
unsafe { vzip1q_u64(self, other) }
}
#[inline(always)]
fn unpack_high(self, other: Self) -> Self {
unsafe { vzip2q_u64(self, other) }
}
#[inline(always)]
fn shl<const N: i32>(self) -> Self {
unsafe { vshlq_n_u64::<N>(self) }
}
#[inline(always)]
fn shr<const N: i32>(self) -> Self {
unsafe { vshrq_n_u64::<N>(self) }
}
#[inline(always)]
fn reduce_lane(self) -> Self {
reduce_by_multiply(self, unsafe { vdupq_n_u64(TAIL_64) })
}
#[inline(always)]
fn reduce_wide(even: Self, odd: Self) -> Self {
even.reduce_lane().unpack_low(odd.reduce_lane())
}
}
impl Register128 for uint64x2_t {
const CHEAP_MULTIPLY: bool = true;
#[inline(always)]
fn lift(value: u64) -> Self {
unsafe { vcombine_u64(vcreate_u64(value), vcreate_u64(0)) }
}
#[inline(always)]
fn lower(self) -> u64 {
unsafe { vgetq_lane_u64::<0>(self) }
}
#[inline(always)]
fn swap(self) -> Self {
unsafe { vextq_u64::<1>(self, self) }
}
#[inline(always)]
fn load(a: &[u64; 3]) -> (Self, Self) {
unsafe { (vld1q_u64(a.as_ptr()), vld1q_dup_u64(&a[2])) }
}
#[inline(always)]
fn store(pair: Self, last: Self) -> [u64; 3] {
let mut out = [0u64; 3];
unsafe {
vst1q_u64(out.as_mut_ptr(), pair);
vst1q_lane_u64::<0>(&mut out[2], last);
}
out
}
#[inline(always)]
fn load_scalar(k: &u64) -> Self {
unsafe { vld1q_dup_u64(k) }
}
}