#[cfg(target_arch = "aarch64")]
use core::arch::aarch64::*;
use crate::key::SortableKey;
#[cfg(target_arch = "aarch64")]
#[inline]
unsafe fn sort_network_4(v: uint32x4_t) -> uint32x4_t {
let mut r = v;
{
let s = vrev64q_u32(r); let lo = vminq_u32(r, s);
let hi = vmaxq_u32(r, s);
let mask = vcombine_u32(vcreate_u32(0), vcreate_u32(0xFFFFFFFF_00000000));
r = vbslq_u32(
vreinterpretq_u32_u64(vdupq_n_u64(0x00000000_FFFFFFFF)),
lo,
hi,
);
let lo0 = vgetq_lane_u32(lo, 0);
let hi1 = vgetq_lane_u32(hi, 1);
let lo2 = vgetq_lane_u32(lo, 2);
let hi3 = vgetq_lane_u32(hi, 3);
r = vsetq_lane_u32(lo0, r, 0);
r = vsetq_lane_u32(hi1, r, 1);
r = vsetq_lane_u32(lo2, r, 2);
r = vsetq_lane_u32(hi3, r, 3);
}
{
let s = vextq_u32(r, r, 2);
let lo = vminq_u32(r, s);
let hi = vmaxq_u32(r, s);
let lo_low = vget_low_u32(vreinterpretq_u32_u64(vreinterpretq_u64_u32(lo)));
let hi_high = vget_high_u32(vreinterpretq_u32_u64(vreinterpretq_u64_u32(hi)));
r = vcombine_u32(vget_low_u32(lo), vget_high_u32(hi));
}
{
let s = vextq_u32(r, r, 0); let v1 = vgetq_lane_u32(r, 1);
let v2 = vgetq_lane_u32(r, 2);
if v1 > v2 {
r = vsetq_lane_u32(v2, r, 1);
r = vsetq_lane_u32(v1, r, 2);
}
}
r
}
#[cfg(target_arch = "aarch64")]
pub unsafe fn sort_u32_8(slice: &mut [u32]) {
let len = slice.len();
if len <= 1 {
return;
}
if len <= 4 {
let mut buf = [u32::MAX; 4];
buf[..len].copy_from_slice(slice);
let v = vld1q_u32(buf.as_ptr());
let sorted = sort_network_4(v);
vst1q_u32(buf.as_mut_ptr(), sorted);
slice.copy_from_slice(&buf[..len]);
} else {
let mut buf_lo = [u32::MAX; 4];
let mut buf_hi = [u32::MAX; 4];
buf_lo.copy_from_slice(&slice[..4]);
let hi_len = len - 4;
buf_hi[..hi_len].copy_from_slice(&slice[4..]);
let mut lo = sort_network_4(vld1q_u32(buf_lo.as_ptr()));
let mut hi = sort_network_4(vld1q_u32(buf_hi.as_ptr()));
let hi_rev = vrev64q_u32(hi);
let hi_rev = vextq_u32(hi_rev, hi_rev, 2); let new_lo = vminq_u32(lo, hi_rev);
let new_hi = vmaxq_u32(lo, hi_rev);
lo = merge_within_4(new_lo);
hi = merge_within_4(new_hi);
vst1q_u32(buf_lo.as_mut_ptr(), lo);
vst1q_u32(buf_hi.as_mut_ptr(), hi);
slice[..4].copy_from_slice(&buf_lo);
slice[4..].copy_from_slice(&buf_hi[..hi_len]);
}
}
#[cfg(target_arch = "aarch64")]
#[inline]
unsafe fn merge_within_4(v: uint32x4_t) -> uint32x4_t {
let mut r = v;
{
let s = vextq_u32(r, r, 2);
let lo = vminq_u32(r, s);
let hi = vmaxq_u32(r, s);
r = vcombine_u32(vget_low_u32(lo), vget_high_u32(hi));
}
{
let v1 = vgetq_lane_u32(r, 1);
let v0 = vgetq_lane_u32(r, 0);
if v0 > v1 {
r = vsetq_lane_u32(v1, r, 0);
r = vsetq_lane_u32(v0, r, 1);
}
let v2 = vgetq_lane_u32(r, 2);
let v3 = vgetq_lane_u32(r, 3);
if v2 > v3 {
r = vsetq_lane_u32(v3, r, 2);
r = vsetq_lane_u32(v2, r, 3);
}
}
r
}
#[cfg(target_arch = "aarch64")]
pub unsafe fn sort_tiny_u32_keys_generic<T: SortableKey>(slice: &mut [T]) {
let len = slice.len();
if len <= 1 {
return;
}
let mut keys: [u32; 8] = [u32::MAX; 8];
for (i, elem) in slice.iter().enumerate() {
let key = elem.to_radix_key();
keys[i] = core::ptr::read(&key as *const T::Key as *const u32);
}
sort_u32_8(&mut keys[..len]);
for (i, elem) in slice.iter_mut().enumerate() {
let key = core::ptr::read(&keys[i] as *const u32 as *const T::Key);
*elem = T::from_radix_key(key);
}
}
#[inline]
pub fn is_available() -> bool {
cfg!(target_arch = "aarch64")
}