use super::{days_ms, f16, i256, months_days_ns};
use super::{BitChunk, BitChunkIter, NativeType};
pub trait FromMaskChunk<T> {
fn from_chunk(v: T) -> Self;
}
pub unsafe trait NativeSimd: Sized + Default + Copy {
const LANES: usize;
type Native: NativeType;
type Chunk: BitChunk;
type Mask: FromMaskChunk<Self::Chunk>;
fn select(self, mask: Self::Mask, default: Self) -> Self;
fn from_chunk(v: &[Self::Native]) -> Self;
fn from_incomplete_chunk(v: &[Self::Native], remaining: Self::Native) -> Self;
fn align(values: &[Self::Native]) -> (&[Self::Native], &[Self], &[Self::Native]);
}
pub trait Simd: NativeType {
type Simd: NativeSimd<Native = Self>;
}
#[cfg(not(feature = "simd"))]
mod native;
#[cfg(not(feature = "simd"))]
pub use native::*;
#[cfg(feature = "simd")]
mod packed;
#[cfg(feature = "simd")]
pub use packed::*;
macro_rules! native_simd {
($name:tt, $type:ty, $lanes:expr, $mask:ty) => {
#[allow(non_camel_case_types)]
#[derive(Copy, Clone)]
pub struct $name(pub [$type; $lanes]);
unsafe impl NativeSimd for $name {
const LANES: usize = $lanes;
type Native = $type;
type Chunk = $mask;
type Mask = $mask;
#[inline]
fn select(self, mask: $mask, default: Self) -> Self {
let mut reduced = default;
let iter = BitChunkIter::new(mask, Self::LANES);
for (i, b) in (0..Self::LANES).zip(iter) {
reduced[i] = if b { self[i] } else { reduced[i] };
}
reduced
}
#[inline]
fn from_chunk(v: &[$type]) -> Self {
($name)(v.try_into().unwrap())
}
#[inline]
fn from_incomplete_chunk(v: &[$type], remaining: $type) -> Self {
let mut a = [remaining; $lanes];
a.iter_mut().zip(v.iter()).for_each(|(a, b)| *a = *b);
Self(a)
}
#[inline]
fn align(values: &[Self::Native]) -> (&[Self::Native], &[Self], &[Self::Native]) {
unsafe { values.align_to::<Self>() }
}
}
impl std::ops::Index<usize> for $name {
type Output = $type;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
&self.0[index]
}
}
impl std::ops::IndexMut<usize> for $name {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
&mut self.0[index]
}
}
impl Default for $name {
#[inline]
fn default() -> Self {
($name)([<$type>::default(); $lanes])
}
}
};
}
pub(super) use native_simd;
native_simd!(f16x32, f16, 32, u32);
native_simd!(days_msx8, days_ms, 8, u8);
native_simd!(months_days_nsx8, months_days_ns, 8, u8);
native_simd!(i128x8, i128, 8, u8);
native_simd!(i256x8, i256, 8, u8);
impl<T: BitChunk> FromMaskChunk<T> for T {
#[inline]
fn from_chunk(v: T) -> Self {
v
}
}
macro_rules! native {
($type:ty, $simd:ty) => {
impl Simd for $type {
type Simd = $simd;
}
};
}
native!(u8, u8x64);
native!(u16, u16x32);
native!(u32, u32x16);
native!(u64, u64x8);
native!(i8, i8x64);
native!(i16, i16x32);
native!(i32, i32x16);
native!(i64, i64x8);
native!(f16, f16x32);
native!(f32, f32x16);
native!(f64, f64x8);
native!(i128, i128x8);
native!(i256, i256x8);
native!(days_ms, days_msx8);
native!(months_days_ns, months_days_nsx8);