packed_simd icon indicating copy to clipboard operation
packed_simd copied to clipboard

easier functions to work with slices with dynamic length

Open vova616 opened this issue 6 years ago • 2 comments

I searched for an easy way to deal with sizes that cannot be always in the length you want so I made something like this and wondered why this isn't part of the library? or maybe I missed it?

The names/impl can change but thats the idea

pub trait SimdMap<T> where Self: Sized {
    #[inline(always)]
    fn simd_map<F>(slice: &mut [T], mut func: F) where F: FnMut(Self) -> Self;
}

impl SimdMap<u8> for u8x64 {
    #[inline(always)]
    fn simd_map<F>(mut slice: &mut [u8], mut func: F) where F: FnMut(Self) -> Self {
        while slice.len() >= Self::lanes() {
            func(Self::from_slice_unaligned(slice)).write_to_slice_unaligned(&mut slice);
            slice = &mut slice[Self::lanes()..];
        }
        let mut temp = [0u8; Self::lanes()];
        temp[..slice.len()].copy_from_slice(slice);
        func(Self::from_slice_unaligned(&temp)).write_to_slice_unaligned(&mut temp);
        slice.copy_from_slice(&temp[..slice.len()]);
    }
}

then I can use this on any size buffer with the types I want and I don't have to worry about too much stuff or size

pub fn xor(buff: &mut [u8]) {
    u8x64::simd_map(buff, |data| {
        data ^ 0x15
    });
}

vova616 avatar Apr 25 '19 23:04 vova616

something like this could work too

fn sum_ver(x: &[f32]) -> f32 {
    //assert_eq!(x.len() % f32x8::lanes(), 0);  //not needed
    x.simd_iter().sum::<f32x8>().sum()
}

using this

pub struct SimdIter<'a, T,D> {
    slice: &'a [D],
    phantom: std::marker::PhantomData<T>
}

pub trait SimdIterator<'a,T,D> {

    #[inline(always)]
    fn simd_iter(&'a self) -> SimdIter<'a,T,D>;
}

impl<'a> Iterator for SimdIter<'a,f32x8,f32> {
    type Item = f32x8;

    fn next(&mut self) -> Option<Self::Item> {
        if self.slice.len() >= Self::Item::lanes() {
            let data = Self::Item::from_slice_unaligned(self.slice);
            self.slice = &self.slice[Self::Item::lanes()..];
            Some(data)
        } else if self.slice.len() > 0 {
            let mut temp = [0f32; Self::Item::lanes()];
            temp[..self.slice.len()].copy_from_slice(self.slice);
            self.slice = &self.slice[0..0];
            Some(Self::Item::from_slice_unaligned(&temp))
        } else {
            None
        }
    }
}



impl<'a,T,D> SimdIterator<'a,T,D> for &[D] {
    fn simd_iter(&'a self) -> SimdIter<'a,T,D> {
        SimdIter{ slice: self, phantom: PhantomData }
    }
}

vova616 avatar Apr 26 '19 00:04 vova616

Many crates do something like that, yes, e.g., https://crates.io/crates/simd_aligned

gnzlbg avatar Apr 29 '19 10:04 gnzlbg