cubecl_tile/tile/accumulator/
smem_accumulation.rs1use core::marker::PhantomData;
4
5use cubecl::ir::{ExpandValue, VectorSize};
6use cubecl::prelude::*;
7use cubecl::unexpanded;
8use cubecl_std::tensor::{
9 ErasedTensor, ErasedTensorExpand, ErasedTensorOperationsExpand, ReadsLines, WriteOnly,
10 WritesLines,
11};
12
13use crate::*;
14
15#[derive(CubeType)]
18pub struct SmemAccumulation {
19 pub sink: Tile,
21 pub source: Tile,
24}
25
26#[cube]
27impl Tile {
28 pub fn smem_accumulation<A: Numeric>(&self) -> SmemAccumulation {
31 let define!(Served) = self.element;
32 let space = comptime!(self.place.space.clone());
33 let elem_bytes = A::size().comptime();
34 let form = comptime!(StageForm::dense(
35 &space,
36 1,
37 StageStorage::Strided,
38 LineBytes(elem_bytes)
39 ));
40 let cells = comptime!(form.cells());
41 let values = Shared::<[Atomic<A>]>::new_slice(cells);
42 sync_cube();
44 let mut cell = UNIT_POS as usize;
45 while cell < cells {
46 values[cell].store(A::from_int(0));
47 cell += CUBE_DIM as usize;
48 }
49 sync_cube();
50
51 let units = self.units();
52 let sink = Memory::smem_backed::<A>(
53 comptime!(space.clone()),
54 1usize,
55 comptime!(FillUnits::cube(units)),
56 Backing::new_WriteCall(RawCall::of::<A>(
57 ErasedTensor::<A, WriteOnly>::of_smem_accumulate(&values),
58 )),
59 comptime!(Packing::Plain),
60 comptime!(form.clone()),
61 RuntimeMap::integral(comptime!(form.physical_rank())),
62 ComptimeOption::new_None(),
63 comptime!(Write::Accumulate),
64 comptime!(Overhang::Masked),
65 );
66 let source = Memory::smem_backed::<Served>(
67 space,
68 1usize,
69 comptime!(FillUnits::cube(units)),
70 Backing::new_ReadCall(RawCall::of::<Served>(
71 ErasedTensor::<Served, ReadOnly>::of_smem_load::<A>(&values),
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 SmemAccumulation {
81 sink: sink.nested_like(self),
82 source: source.nested_like(self),
83 }
84 }
85}
86
87pub(crate) trait SmemAccumulateSink<E: Numeric> {
89 fn of_smem_accumulate(_values: &Shared<[Atomic<E>]>) -> ErasedTensor<E, WriteOnly> {
91 unexpanded!()
92 }
93
94 fn __expand_of_smem_accumulate(
95 _scope: &Scope,
96 values: &<Shared<[Atomic<E>]> as CubeType>::ExpandType,
97 ) -> ErasedTensorExpand<E, WriteOnly> {
98 ErasedTensorExpand::new(SmemAccumulate::<E> {
99 values: ExpandTypeClone::clone_unchecked(values),
100 _e: PhantomData,
101 })
102 }
103}
104
105impl<E: Numeric> SmemAccumulateSink<E> for ErasedTensor<E, WriteOnly> {}
106
107pub(crate) trait SmemLoadSource<T: Numeric> {
109 fn of_smem_load<A: Numeric>(_values: &Shared<[Atomic<A>]>) -> ErasedTensor<T, ReadOnly> {
111 unexpanded!()
112 }
113
114 fn __expand_of_smem_load<A: Numeric>(
115 _scope: &Scope,
116 values: &<Shared<[Atomic<A>]> as CubeType>::ExpandType,
117 ) -> ErasedTensorExpand<T, ReadOnly> {
118 ErasedTensorExpand::new(SmemLoad::<A, T> {
119 values: ExpandTypeClone::clone_unchecked(values),
120 _t: PhantomData,
121 })
122 }
123}
124
125impl<T: Numeric> SmemLoadSource<T> for ErasedTensor<T, ReadOnly> {}
126
127struct SmemAccumulate<E: Numeric> {
129 values: <Shared<[Atomic<E>]> as CubeType>::ExpandType,
130 _e: PhantomData<E>,
131}
132
133impl<E: Numeric> ErasedTensorOperationsExpand<E> for SmemAccumulate<E> {
134 fn __expand_vector_size_method(&self, _scope: &Scope) -> VectorSize {
135 1
136 }
137
138 fn __expand_lines_method(&self, scope: &Scope) -> NativeExpand<usize> {
139 self.values.__expand_len_method(scope)
140 }
141
142 fn __expand_write_line_method(
143 &mut self,
144 scope: &Scope,
145 index: NativeExpand<usize>,
146 value: ExpandValue,
147 ) {
148 accumulate_cell::expand::<E>(scope, &self.values, index, value.into());
149 }
150}
151
152impl<E: Numeric> WritesLines<E> for SmemAccumulate<E> {}
153
154struct SmemLoad<A: Numeric, T: Numeric> {
156 values: <Shared<[Atomic<A>]> as CubeType>::ExpandType,
157 _t: PhantomData<T>,
158}
159
160impl<A: Numeric, T: Numeric> ErasedTensorOperationsExpand<T> for SmemLoad<A, T> {
161 fn __expand_vector_size_method(&self, _scope: &Scope) -> VectorSize {
162 1
163 }
164
165 fn __expand_lines_method(&self, scope: &Scope) -> NativeExpand<usize> {
166 self.values.__expand_len_method(scope)
167 }
168
169 fn __expand_read_line_method(&self, scope: &Scope, index: NativeExpand<usize>) -> ExpandValue {
170 load_cell::expand::<A, T>(scope, &self.values, index).expand
171 }
172}
173
174impl<A: Numeric, T: Numeric> ReadsLines<T> for SmemLoad<A, T> {}
175
176#[cube]
178fn accumulate_cell<E: Numeric>(
179 values: &Shared<[Atomic<E>]>,
180 index: usize,
181 value: Vector<E, Const<1>>,
182) {
183 values[index].fetch_add(value.extract(0usize));
184}
185
186#[cube]
188fn load_cell<A: Numeric, T: Numeric>(
189 values: &Shared<[Atomic<A>]>,
190 index: usize,
191) -> Vector<T, Const<1>> {
192 Vector::new(T::cast_from(values[index].load()))
193}