use super::common::{USizeConvertTo, iota_slice};
use crate::{
bitmask,
constant::Const,
traits::{ArrayType, BitMaskType, SIMDMask, SIMDVector},
};
pub(crate) fn test_store_simd<T, const N: usize, V>(arch: V::Arch)
where
T: Default + std::marker::Copy + std::cmp::PartialEq + std::fmt::Debug + std::ops::AddAssign,
usize: USizeConvertTo<T>,
Const<N>: ArrayType<T, Type = [T; N]>,
bitmask::BitMask<N, V::Arch>: SIMDMask<Arch = V::Arch>,
V: SIMDVector<Scalar = T, ConstLanes = Const<N>>,
{
let mut output = vec![T::default(); 2 * N];
let mut input = [T::default(); N];
iota_slice(input.as_mut_slice());
for i in input.iter_mut() {
*i += 1.test_convert();
}
let v = V::from_array(arch, input);
for i in 0..N {
output.fill(T::default());
unsafe { v.store_simd(output.as_mut_ptr().add(i)) };
for (j, value) in output.iter().enumerate() {
if j < i {
assert_eq!(
*value,
T::default(),
"values before the write pointer should not be accessed"
);
} else if j < i + N {
assert_eq!(
*value,
(j - i + 1).test_convert(),
"expected index {} to be set to {}",
j,
(j - i + 1)
);
} else {
assert_eq!(
*value,
T::default(),
"values after the write section should not be accessed"
);
}
}
}
for keep_first in 0..=N + 5 {
let offset = N - keep_first.min(N);
let check = |arr: [T; N]| {
for (i, value) in arr.iter().enumerate() {
if i < offset {
assert_eq!(*value, 0.test_convert());
} else {
assert_eq!(*value, (i - offset + 1).test_convert());
}
}
};
let mut output = [T::default(); N];
let ptr = unsafe { output.as_mut_ptr().add(offset) };
unsafe { v.store_simd_first(ptr, keep_first) };
check(output);
let mut output = [T::default(); N];
let ptr = unsafe { output.as_mut_ptr().add(offset) };
unsafe { v.store_simd_masked_logical(ptr, V::Mask::keep_first(arch, keep_first)) };
check(output);
let mut output = [T::default(); N];
let ptr = unsafe { output.as_mut_ptr().add(offset) };
unsafe {
v.store_simd_masked(
ptr,
<Const<N> as BitMaskType<V::Arch>>::Type::keep_first(arch, keep_first),
)
};
check(output);
}
}