hermes_simd_core/view/
scan.rs1use crate::align::Alignment;
2use crate::arch::SimdArch;
3use crate::execution::ExecutionMode;
4use crate::kernel::SimdKernel;
5use crate::ops::{ScanMode, ScanOp};
6use crate::scalar::Scalar;
7use crate::view::{SimdError, SimdView};
8use core::mem::MaybeUninit;
9
10impl<'a, T: 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode, Ref: 'a>
11 SimdView<'a, T, Arch, Align, Mode, Ref>
12where
13 T: Scalar,
14{
15 #[inline(always)]
21 pub fn prefix_scan<Op, SMode>(
22 &self,
23 out: &mut [T],
24 op: Op,
25 mode: SMode,
26 ) -> Result<(), SimdError>
27 where
28 Op: ScanOp<T>,
29 SMode: ScanMode,
30 {
31 let out_uninit = unsafe {
35 core::slice::from_raw_parts_mut(out.as_mut_ptr() as *mut MaybeUninit<T>, out.len())
36 };
37 self.prefix_scan_into_uninit(out_uninit, op, mode)?;
38 Ok(())
39 }
40
41 #[inline]
54 pub fn prefix_scan_into_uninit<'o, Op, SMode>(
55 &self,
56 out: &'o mut [MaybeUninit<T>],
57 _op: Op,
58 _mode: SMode,
59 ) -> Result<&'o mut [T], SimdError>
60 where
61 Op: ScanOp<T>,
62 SMode: ScanMode,
63 {
64 let len = self.len();
65 if out.len() < len {
66 return Err(SimdError::InsufficientOutputLength);
67 }
68
69 let src = self.as_slice();
70 let lane_count = Arch::LANE_COUNT;
71 let simd_len = (len / lane_count) * lane_count;
72 let ptr_in = src.as_ptr();
73 let ptr_out = out.as_mut_ptr().cast::<T>();
77
78 let mut carry = Op::identity();
79
80 unsafe {
85 let load = |p: *const T| {
86 if crate::align::is_aligned_for_arch::<Arch, Align>() {
87 Arch::load_aligned(p)
88 } else {
89 Arch::load_unaligned(p)
90 }
91 };
92 let store = |p: *mut T, v: Arch::Vector| {
93 if crate::align::is_aligned_for_arch::<Arch, Align>() {
94 Arch::store_aligned(p, v)
95 } else {
96 Arch::store_unaligned(p, v)
97 }
98 };
99
100 for i in (0..simd_len).step_by(lane_count) {
101 let v = load(ptr_in.add(i));
102 let (r, next_carry) = Arch::scan_vector::<Op, SMode>(v, carry);
103 store(ptr_out.add(i), r);
104 carry = next_carry;
105 }
106
107 if SMode::IS_INCLUSIVE {
108 for i in simd_len..len {
109 carry = Op::combine(carry, src[i]);
110 core::ptr::write(ptr_out.add(i), carry);
111 }
112 } else {
113 for i in simd_len..len {
114 let temp = src[i];
115 core::ptr::write(ptr_out.add(i), carry);
116 carry = Op::combine(carry, temp);
117 }
118 }
119
120 Ok(core::slice::from_raw_parts_mut(ptr_out, len))
122 }
123 }
124}
125
126impl<'a, T: 'a, Arch: SimdArch + SimdKernel<T>, Align: Alignment, Mode: ExecutionMode>
127 SimdView<'a, T, Arch, Align, Mode, &'a mut [T]>
128where
129 T: Scalar,
130{
131 #[inline(always)]
138 pub fn prefix_scan_in_place<Op, SMode>(&mut self, _op: Op, _mode: SMode)
139 where
140 Op: ScanOp<T>,
141 SMode: ScanMode,
142 {
143 let data = self.as_slice_mut();
144 let len = data.len();
145 if len == 0 {
146 return;
147 }
148
149 let lane_count = Arch::LANE_COUNT;
150 let simd_len = (len / lane_count) * lane_count;
151 let ptr = data.as_mut_ptr();
152
153 let mut carry = Op::identity();
154
155 unsafe {
156 let load = |p: *const T| {
157 if crate::align::is_aligned_for_arch::<Arch, Align>() {
158 Arch::load_aligned(p)
159 } else {
160 Arch::load_unaligned(p)
161 }
162 };
163 let store = |p: *mut T, v: Arch::Vector| {
164 if crate::align::is_aligned_for_arch::<Arch, Align>() {
165 Arch::store_aligned(p, v)
166 } else {
167 Arch::store_unaligned(p, v)
168 }
169 };
170
171 for i in (0..simd_len).step_by(lane_count) {
172 let v = load(ptr.add(i));
173 let (r, next_carry) = Arch::scan_vector::<Op, SMode>(v, carry);
174 store(ptr.add(i), r);
175 carry = next_carry;
176 }
177 }
178
179 if SMode::IS_INCLUSIVE {
180 for x in &mut data[simd_len..] {
181 carry = Op::combine(carry, *x);
182 *x = carry;
183 }
184 } else {
185 for x in &mut data[simd_len..] {
186 let temp = *x;
187 *x = carry;
188 carry = Op::combine(carry, temp);
189 }
190 }
191 }
192}