use crate::align::Alignment;
use crate::arch::SimdArch;
use crate::execution::ExecutionMode;
use crate::kernel::SimdKernel;
use crate::ops::{Add, ElementOp, Mul};
use crate::scalar::Scalar;
use crate::view::{SimdError, SimdView};
impl<'a, T: 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
SimdView<'a, T, Arch, Align, Mode, &'a mut [T]>
where
T: Scalar,
{
#[inline(always)]
pub fn transform_in_place<ORef, Op>(
&mut self,
other: &SimdView<'_, T, Arch, Align, Mode, ORef>,
op: Op,
) -> Result<(), SimdError>
where
ORef: 'a,
Op: ElementOp<T>,
{
super::check_lengths_equal(self.len(), other.len())?;
let len = self.len();
let lane_count = Arch::LANE_COUNT;
let simd_len = (len / lane_count) * lane_count;
let ptr_self = self.as_slice_mut().as_mut_ptr();
let ptr_other = other.as_slice().as_ptr();
unsafe {
let load_self = |p: *const T| {
if crate::align::is_aligned_for_arch::<Arch, Align>() {
Arch::load_aligned(p)
} else {
Arch::load_unaligned(p)
}
};
let load_other = |p: *const T| {
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);
}
};
for i in (0..simd_len).step_by(lane_count) {
let va = load_self(ptr_self.add(i) as *const T);
let vb = load_other(ptr_other.add(i));
let vr = op.apply::<Arch>(va, vb);
store(ptr_self.add(i), vr);
}
}
let s_mut_slice = self.as_slice_mut();
let o_slice = other.as_slice();
for i in simd_len..len {
s_mut_slice[i] = op.apply_scalar(s_mut_slice[i], o_slice[i]);
}
Ok(())
}
#[inline(always)]
pub fn add_assign<ORef>(
&mut self,
other: &SimdView<'_, T, Arch, Align, Mode, ORef>,
) -> Result<(), SimdError>
where
ORef: 'a,
{
self.transform_in_place(other, Add)
}
#[inline(always)]
pub fn mul_assign<ORef>(
&mut self,
other: &SimdView<'_, T, Arch, Align, Mode, ORef>,
) -> Result<(), SimdError>
where
ORef: 'a,
{
self.transform_in_place(other, Mul)
}
}