use core::fmt::Debug;
use std::{vec, vec::Vec};
use crate::{
vload_high, vload_low, vload_unaligned, vstore_high, vstore_low, vstore_unaligned, Scalar, Simd,
};
use super::for_each_backend;
#[inline(always)]
fn test_half_ops_impl<S: Simd, T: Scalar>(src: &[T]) -> Vec<Vec<T>> {
let lanes = T::lanes::<S>();
let mut loaded = [vec![T::default(); lanes], vec![T::default(); lanes]];
let mut stored = [vec![T::default(); lanes + 1], vec![T::default(); lanes + 1]];
unsafe {
vstore_unaligned(loaded[0].as_mut_ptr(), vload_low::<S, T>(src.as_ptr()));
vstore_unaligned(loaded[1].as_mut_ptr(), vload_high::<S, T>(src.as_ptr()));
let full = vload_unaligned::<S, T>(src.as_ptr());
vstore_low(stored[0].as_mut_ptr().add(1), full);
vstore_high(stored[1].as_mut_ptr().add(1), full);
}
let [low, high] = loaded;
let [store_low, store_high] = stored.map(|s| s[1..].to_vec());
vec![low, high, store_low, store_high]
}
fn check_half_ops<T: Scalar + PartialEq + Debug>(src: &[T], out: &[Vec<T>]) {
let [low, high, store_low, store_high] = out else {
unreachable!()
};
let (lanes, zero) = (low.len(), T::default());
let half = lanes / 2;
assert_eq!(low[..half], src[..half], "vload_low");
assert!(
low[half..].iter().all(|x| *x == zero),
"vload_low upper half"
);
assert_eq!(high[half..], src[half..lanes], "vload_high");
assert!(
high[..half].iter().all(|x| *x == zero),
"vload_high lower half"
);
assert_eq!(store_low[..half], src[..half], "vstore_low");
assert!(
store_low[half..].iter().all(|x| *x == zero),
"vstore_low wrote past its half"
);
assert_eq!(store_high[half..], src[half..lanes], "vstore_high");
assert!(
store_high[..half].iter().all(|x| *x == zero),
"vstore_high wrote outside its half"
);
}
macro_rules! testgen_half_ops {
($($ty: ty),*) => {
$(::paste::paste! {
#[::wasm_bindgen_test::wasm_bindgen_test(unsupported = test)]
fn [<test_half_ops_ $ty>]() {
let src: Vec<$ty> = (1..=65).map(|i| i as $ty).collect();
let src = &src[1..];
for_each_backend!(test_half_ops_impl, $ty, src, |out: &[Vec<$ty>]| {
check_half_ops(src, out)
});
}
})*
};
}
testgen_half_ops!(u8, u16, u32);