use super::SimdCow;
use crate::align::Alignment;
use crate::arch::SimdArch;
use crate::kernel::SimdKernel;
use crate::ops::UnaryOp;
use crate::scalar::Scalar;
use crate::vec::AlignedVec;
use crate::view::SimdError;
impl<'a, T: 'a, Arch, Align> SimdCow<'a, T, Arch, Align>
where
T: Scalar,
Arch: SimdArch + SimdKernel<T>,
Align: Alignment,
{
#[inline]
pub fn map_cow<Op: UnaryOp<T>>(&self, op: Op) -> SimdCow<'static, T, Arch, Align> {
let data = self.as_ref();
let len = data.len();
let mut out: AlignedVec<T, Align> = AlignedVec::with_capacity(len);
let lane_count = Arch::LANE_COUNT;
let simd_len = (len / lane_count) * lane_count;
let ptr_in = data.as_ptr();
let ptr_out = out.as_mut_ptr();
unsafe {
let load = |p: *const T| -> Arch::Vector {
if crate::align::is_aligned_for_arch::<Arch, Align>() {
Arch::load_aligned(p)
} else {
Arch::load_unaligned(p)
}
};
let store = |p: *mut T, v: Arch::Vector| {
if crate::align::is_aligned_for_arch::<Arch, Align>() {
Arch::store_aligned(p, v);
} else {
Arch::store_unaligned(p, v);
}
};
let mut i = 0usize;
while i < simd_len {
let v = load(ptr_in.add(i));
let r = UnaryOp::apply::<Arch>(op, v);
store(ptr_out.add(i), r);
i += lane_count;
}
for i in simd_len..len {
core::ptr::write(ptr_out.add(i), UnaryOp::apply_scalar(op, *ptr_in.add(i)));
}
out.set_len(len);
}
SimdCow::Owned(out)
}
#[inline]
pub fn fma_cow(
&self,
b: &SimdCow<'_, T, Arch, Align>,
c: &SimdCow<'_, T, Arch, Align>,
) -> Result<SimdCow<'static, T, Arch, Align>, SimdError> {
let data_a = self.as_ref();
let data_b = b.as_ref();
let data_c = c.as_ref();
let len = data_a.len();
if len != data_b.len() || len != data_c.len() {
return Err(SimdError::LengthMismatch);
}
let mut out: AlignedVec<T, Align> = AlignedVec::with_capacity(len);
let lane_count = Arch::LANE_COUNT;
let simd_len = (len / lane_count) * lane_count;
let ptr_a = data_a.as_ptr();
let ptr_b = data_b.as_ptr();
let ptr_c = data_c.as_ptr();
let ptr_o = out.as_mut_ptr();
unsafe {
let load = |p: *const T| -> Arch::Vector {
if crate::align::is_aligned_for_arch::<Arch, Align>() {
Arch::load_aligned(p)
} else {
Arch::load_unaligned(p)
}
};
let store = |p: *mut T, v: Arch::Vector| {
if crate::align::is_aligned_for_arch::<Arch, Align>() {
Arch::store_aligned(p, v);
} else {
Arch::store_unaligned(p, v);
}
};
let mut i = 0usize;
while i < simd_len {
let va = load(ptr_a.add(i));
let vb = load(ptr_b.add(i));
let vc = load(ptr_c.add(i));
let vr = Arch::fmadd(va, vb, vc);
store(ptr_o.add(i), vr);
i += lane_count;
}
for i in simd_len..len {
let value = *ptr_a.add(i) * *ptr_b.add(i) + *ptr_c.add(i);
core::ptr::write(ptr_o.add(i), value);
}
out.set_len(len);
}
Ok(SimdCow::Owned(out))
}
}