use {crate::lanes::Lanes, std::arch::aarch64::*};
#[derive(Clone, Copy)]
pub struct Neon(pub(crate) uint32x4_t);
#[inline(always)]
unsafe fn rot<const R: i32, const L: i32>(x: uint32x4_t) -> uint32x4_t {
const { assert!(R + L == 32) };
vsriq_n_u32::<R>(vshlq_n_u32::<L>(x), x)
}
#[inline(always)]
unsafe fn transpose4(a: [uint32x4_t; 4]) -> [uint32x4_t; 4] {
let t01 = vtrnq_u32(a[0], a[1]);
let t23 = vtrnq_u32(a[2], a[3]);
[
vcombine_u32(vget_low_u32(t01.0), vget_low_u32(t23.0)),
vcombine_u32(vget_low_u32(t01.1), vget_low_u32(t23.1)),
vcombine_u32(vget_high_u32(t01.0), vget_high_u32(t23.0)),
vcombine_u32(vget_high_u32(t01.1), vget_high_u32(t23.1)),
]
}
#[inline(always)]
unsafe fn load_be(p: *const u8, off: usize) -> uint32x4_t {
let raw = vld1q_u8(p.add(off));
vreinterpretq_u32_u8(vrev32q_u8(raw))
}
pub(crate) fn group(msgs: &[crate::batch::Message<'_>], out: &mut [[u8; 32]]) {
crate::batch::hash_lanes::<Neon>(msgs, out)
}
impl Lanes for Neon {
const N: usize = 4;
#[inline(always)]
fn ch(self, y: Self, z: Self) -> Self {
unsafe { Neon(vbslq_u32(self.0, y.0, z.0)) }
}
#[inline(always)]
fn maj(self, y: Self, z: Self) -> Self {
unsafe { Neon(vbslq_u32(veorq_u32(y.0, z.0), self.0, y.0)) }
}
#[inline(always)]
unsafe fn transpose(ptrs: &[*const u8], n: usize) -> [Self; 16] {
debug_assert!((1..=4).contains(&n));
let mut w = [Self::splat(0); 16];
unsafe {
let mut b = [ptrs[0]; 4];
b[..n].copy_from_slice(&ptrs[..n]);
for g in 0..4 {
let off = g * 16;
let loaded = [
load_be(b[0], off),
load_be(b[1], off),
load_be(b[2], off),
load_be(b[3], off),
];
let t = transpose4(loaded);
for (j, tj) in t.into_iter().enumerate() {
w[g * 4 + j] = Neon(tj);
}
}
}
w
}
#[inline(always)]
fn splat(v: u32) -> Self {
unsafe { Neon(vdupq_n_u32(v)) }
}
#[inline(always)]
fn load(v: &[u32]) -> Self {
debug_assert_eq!(v.len(), 4);
unsafe { Neon(vld1q_u32(v.as_ptr())) }
}
#[inline(always)]
fn store(self, out: &mut [u32]) {
debug_assert_eq!(out.len(), 4);
unsafe { vst1q_u32(out.as_mut_ptr(), self.0) }
}
#[inline(always)]
fn add(self, o: Self) -> Self {
unsafe { Neon(vaddq_u32(self.0, o.0)) }
}
#[inline(always)]
fn xor(self, o: Self) -> Self {
unsafe { Neon(veorq_u32(self.0, o.0)) }
}
#[inline(always)]
fn and(self, o: Self) -> Self {
unsafe { Neon(vandq_u32(self.0, o.0)) }
}
#[inline(always)]
fn not_and(self, o: Self) -> Self {
unsafe { Neon(vbicq_u32(o.0, self.0)) }
}
#[inline(always)]
fn shr<const B: u32>(self) -> Self {
unsafe {
let x = self.0;
let r = match B {
3 => vshrq_n_u32::<3>(x),
10 => vshrq_n_u32::<10>(x),
_ => unreachable!(),
};
Neon(r)
}
}
#[inline(always)]
fn rotr<const B: u32>(self) -> Self {
unsafe {
let x = self.0;
let r = match B {
2 => rot::<2, 30>(x),
6 => rot::<6, 26>(x),
7 => rot::<7, 25>(x),
11 => rot::<11, 21>(x),
13 => rot::<13, 19>(x),
17 => rot::<17, 15>(x),
18 => rot::<18, 14>(x),
19 => rot::<19, 13>(x),
22 => rot::<22, 10>(x),
25 => rot::<25, 7>(x),
_ => unreachable!(),
};
Neon(r)
}
}
}