simdeez 3.0.1

SIMD library to abstract over different instruction sets and widths
Documentation
#![allow(dead_code, unused_parens)]

use crate::prelude::*;

macro_rules! test_integer_edges {
    ($name:ident, $simd_ty:ident, $scalar_ty:ty, $unsigned_ty:ty, $bits:expr) => {
        mod $name {
            use super::*;

            simd_unsafe_generate_all!(
                fn shifts(
                    values: &[$scalar_ty],
                    count: i32,
                    left_out: &mut [$scalar_ty],
                    right_out: &mut [$scalar_ty],
                ) {
                    assert_eq!(values.len(), left_out.len());
                    assert_eq!(values.len(), right_out.len());

                    let mut values = values;
                    let mut left_out = left_out;
                    let mut right_out = right_out;

                    while values.len() >= S::$simd_ty::WIDTH {
                        let v = S::$simd_ty::load_from_slice(values);
                        v.shl(count).copy_to_slice(left_out);
                        v.shr(count).copy_to_slice(right_out);

                        values = &values[S::$simd_ty::WIDTH..];
                        left_out = &mut left_out[S::$simd_ty::WIDTH..];
                        right_out = &mut right_out[S::$simd_ty::WIDTH..];
                    }

                    for ((&value, left), right) in values
                        .iter()
                        .zip(left_out.iter_mut())
                        .zip(right_out.iter_mut())
                    {
                        let count = count as u32;
                        *left = value.wrapping_shl(count);
                        *right = ((value as $unsigned_ty).wrapping_shr(count)) as $scalar_ty;
                    }
                }
            );

            simd_unsafe_generate_all!(
                fn abs_values(values: &[$scalar_ty], out: &mut [$scalar_ty]) {
                    assert_eq!(values.len(), out.len());

                    let mut values = values;
                    let mut out = out;

                    while values.len() >= S::$simd_ty::WIDTH {
                        let v = S::$simd_ty::load_from_slice(values);
                        v.abs().copy_to_slice(out);

                        values = &values[S::$simd_ty::WIDTH..];
                        out = &mut out[S::$simd_ty::WIDTH..];
                    }

                    for (&value, slot) in values.iter().zip(out.iter_mut()) {
                        *slot = value.wrapping_abs();
                    }
                }
            );

            #[test]
            fn shift_count_wraps_and_abs_min_wraps() {
                let values: Vec<$scalar_ty> = vec![
                    <$scalar_ty>::MIN,
                    <$scalar_ty>::MIN + 1,
                    -123,
                    -17,
                    -1,
                    0,
                    1,
                    17,
                    123,
                    <$scalar_ty>::MAX - 1,
                    <$scalar_ty>::MAX,
                ]
                .into_iter()
                .cycle()
                .take(257)
                .collect();

                let counts = vec![
                    -257,
                    -129,
                    -65,
                    -33,
                    -1,
                    0,
                    1,
                    7,
                    ($bits - 1) as i32,
                    $bits as i32,
                    ($bits + 1) as i32,
                    3 * ($bits as i32) + 5,
                ];

                for &count in &counts {
                    let mut left = vec![0 as $scalar_ty; values.len()];
                    let mut right = vec![0 as $scalar_ty; values.len()];
                    shifts(&values, count, &mut left, &mut right);

                    let expected_left: Vec<$scalar_ty> = values
                        .iter()
                        .map(|&v| v.wrapping_shl(count as u32))
                        .collect();
                    let expected_right: Vec<$scalar_ty> = values
                        .iter()
                        .map(|&v| ((v as $unsigned_ty).wrapping_shr(count as u32)) as $scalar_ty)
                        .collect();

                    assert_eq!(left, expected_left, "left shift mismatch for count={count}");
                    assert_eq!(
                        right, expected_right,
                        "right shift mismatch for count={count}"
                    );
                }

                let mut abs_out = vec![0 as $scalar_ty; values.len()];
                abs_values(&values, &mut abs_out);
                let expected_abs: Vec<$scalar_ty> =
                    values.iter().map(|&v| v.wrapping_abs()).collect();
                assert_eq!(abs_out, expected_abs);
                assert!(abs_out.contains(&<$scalar_ty>::MIN));
            }
        }
    };
}

test_integer_edges!(i8_edges, Vi8, i8, u8, 8);
test_integer_edges!(i16_edges, Vi16, i16, u16, 16);
test_integer_edges!(i32_edges, Vi32, i32, u32, 32);
test_integer_edges!(i64_edges, Vi64, i64, u64, 64);