cubecl_tile/tile/accumulator/
smem_slots.rs1use core::marker::PhantomData;
12
13use cubecl::ir::{ExpandValue, VectorSize};
14use cubecl::prelude::*;
15use cubecl::unexpanded;
16use cubecl_std::tensor::{
17 ErasedTensor, ErasedTensorExpand, ErasedTensorOperationsExpand, ReadsLines, WriteOnly,
18 WritesLines,
19};
20
21use crate::*;
22
23#[derive(CubeType)]
32pub struct SmemSlotsAccumulation<A: Numeric> {
33 values: Shared<[A]>,
34 like: Tile,
36 pub source: Tile,
39}
40
41#[cube]
42impl Tile {
43 pub fn smem_slots_accumulation<A: Numeric>(
48 &self,
49 #[comptime] writers: usize,
50 ) -> SmemSlotsAccumulation<A> {
51 let define!(Served) = self.element;
52 let space = comptime!(self.place.space.clone());
53 let width = self.vector_size();
54 let size!(W) = width;
55 let form = comptime!(StageForm::dense(
56 &space,
57 width,
58 StageStorage::Strided,
59 LineBytes(A::size().comptime() * width)
60 ));
61 let values = Shared::<[A]>::new_slice(comptime!(form.cells() * width * writers));
62 sync_cube();
64
65 let units = self.units();
66 let source = Memory::smem_backed::<Served>(
67 space,
68 width,
69 comptime!(FillUnits::cube(units)),
70 Backing::new_ReadCall(RawCall::of::<Served>(
71 ErasedTensor::<Served, ReadOnly>::of_smem_slots_sum::<A, W>(&values, writers),
72 )),
73 comptime!(Packing::Plain),
74 comptime!(form.clone()),
75 RuntimeMap::integral(comptime!(form.physical_rank())),
76 ComptimeOption::new_None(),
77 comptime!(Write::Replace),
78 comptime!(Overhang::Never),
79 );
80 SmemSlotsAccumulation::<A> {
81 values,
82 like: self.clone(),
83 source: source.nested_like(self),
84 }
85 }
86}
87
88#[cube]
89impl<A: Numeric> SmemSlotsAccumulation<A> {
90 fn sink(&self, writer: usize) -> Tile {
92 let space = comptime!(self.like.place.space.clone());
93 let width = self.like.vector_size();
94 let size!(W) = width;
95 let form = comptime!(StageForm::dense(
96 &space,
97 width,
98 StageStorage::Strided,
99 LineBytes(A::size().comptime() * width)
100 ));
101 let slot = comptime!(form.cells() * width);
102 let units = self.like.units();
103 let sink = Memory::smem_backed::<A>(
104 space,
105 width,
106 comptime!(FillUnits::cube(units)),
107 Backing::new_WriteCall(RawCall::of::<A>(
108 ErasedTensor::<A, WriteOnly>::of_smem_slot::<W>(&self.values, writer * slot, slot),
109 )),
110 comptime!(Packing::Plain),
111 comptime!(form.clone()),
112 RuntimeMap::integral(comptime!(form.physical_rank())),
113 ComptimeOption::new_None(),
114 comptime!(Write::Replace),
115 comptime!(Overhang::Masked),
116 );
117 sink.nested_like(&self.like)
118 }
119
120 pub fn drain(&self, partial: &Tile, writer: usize) {
124 partial.drained_into(&self.sink(writer));
125 sync_cube();
126 }
127
128 #[allow(dead_code)] fn store_line<W: Size>(
131 values: &mut Shared<[A]>,
132 start: usize,
133 index: usize,
134 value: Vector<A, W>,
135 ) {
136 #[unroll]
137 for j in 0..W::value() {
138 values[start + index * W::value() + j] = value.extract(j);
139 }
140 }
141
142 #[allow(dead_code)] fn sum_line<T: Numeric, W: Size>(
145 values: &Shared<[A]>,
146 #[comptime] writers: usize,
147 index: usize,
148 ) -> Vector<T, W> {
149 let slot = values.len() / writers;
150 let mut line = Vector::<T, W>::empty();
151 #[unroll]
152 for j in 0..W::value() {
153 let cell = index * W::value() + j;
154 let mut sum = values[cell];
155 #[unroll]
156 for writer in 1..writers {
157 sum += values[writer * slot + cell];
158 }
159 line.insert(j, T::cast_from(sum));
160 }
161 line
162 }
163}
164
165pub(crate) trait SmemSlotsSink<E: Numeric> {
167 fn of_smem_slot<W: Size>(
170 _values: &Shared<[E]>,
171 _start: usize,
172 _len: usize,
173 ) -> ErasedTensor<E, WriteOnly> {
174 unexpanded!()
175 }
176
177 fn __expand_of_smem_slot<W: Size>(
178 _scope: &Scope,
179 values: &<Shared<[E]> as CubeType>::ExpandType,
180 start: NativeExpand<usize>,
181 len: usize,
182 ) -> ErasedTensorExpand<E, WriteOnly> {
183 ErasedTensorExpand::new(SmemSlot::<E, W> {
184 values: ExpandTypeClone::clone_unchecked(values),
185 start,
186 len,
187 _e: PhantomData,
188 })
189 }
190}
191
192impl<E: Numeric> SmemSlotsSink<E> for ErasedTensor<E, WriteOnly> {}
193
194pub(crate) trait SmemSlotsSumSource<T: Numeric> {
196 fn of_smem_slots_sum<A: Numeric, W: Size>(
199 _values: &Shared<[A]>,
200 _writers: usize,
201 ) -> ErasedTensor<T, ReadOnly> {
202 unexpanded!()
203 }
204
205 fn __expand_of_smem_slots_sum<A: Numeric, W: Size>(
206 _scope: &Scope,
207 values: &<Shared<[A]> as CubeType>::ExpandType,
208 writers: usize,
209 ) -> ErasedTensorExpand<T, ReadOnly> {
210 ErasedTensorExpand::new(SmemSlotsSum::<A, T, W> {
211 values: ExpandTypeClone::clone_unchecked(values),
212 writers,
213 _t: PhantomData,
214 })
215 }
216}
217
218impl<T: Numeric> SmemSlotsSumSource<T> for ErasedTensor<T, ReadOnly> {}
219
220struct SmemSlot<E: Numeric, W: Size> {
222 values: <Shared<[E]> as CubeType>::ExpandType,
223 start: NativeExpand<usize>,
224 len: usize,
226 _e: PhantomData<(E, W)>,
227}
228
229impl<E: Numeric, W: Size> ErasedTensorOperationsExpand<E> for SmemSlot<E, W> {
230 fn __expand_vector_size_method(&self, scope: &Scope) -> VectorSize {
231 W::__expand_value(scope)
232 }
233
234 fn __expand_lines_method(&self, scope: &Scope) -> NativeExpand<usize> {
235 (self.len / W::__expand_value(scope)).__expand_runtime_method(scope)
236 }
237
238 fn __expand_write_line_method(
239 &mut self,
240 scope: &Scope,
241 index: NativeExpand<usize>,
242 value: ExpandValue,
243 ) {
244 SmemSlotsAccumulation::<E>::__expand_store_line::<W>(
245 scope,
246 &mut self.values,
247 self.start,
248 index,
249 value.into(),
250 );
251 }
252}
253
254impl<E: Numeric, W: Size> WritesLines<E> for SmemSlot<E, W> {}
255
256struct SmemSlotsSum<A: Numeric, T: Numeric, W: Size> {
259 values: <Shared<[A]> as CubeType>::ExpandType,
260 writers: usize,
261 _t: PhantomData<(T, W)>,
262}
263
264impl<A: Numeric, T: Numeric, W: Size> ErasedTensorOperationsExpand<T> for SmemSlotsSum<A, T, W> {
265 fn __expand_vector_size_method(&self, scope: &Scope) -> VectorSize {
266 W::__expand_value(scope)
267 }
268
269 fn __expand_lines_method(&self, scope: &Scope) -> NativeExpand<usize> {
270 let scalars = self.values.__expand_len_method(scope);
271 let per_line = (self.writers * W::__expand_value(scope)).__expand_runtime_method(scope);
272 scalars.__expand_div_method(scope, per_line)
273 }
274
275 fn __expand_read_line_method(&self, scope: &Scope, index: NativeExpand<usize>) -> ExpandValue {
276 SmemSlotsAccumulation::<A>::__expand_sum_line::<T, W>(
277 scope,
278 &self.values,
279 self.writers,
280 index,
281 )
282 .expand
283 }
284}
285
286impl<A: Numeric, T: Numeric, W: Size> ReadsLines<T> for SmemSlotsSum<A, T, W> {}