1use cubecl::{
2 cmma::MmaDefinition,
3 define_size,
4 ir::{DeviceProperties, MatrixIdent, StorageType},
5 prelude::*,
6};
7
8use crate::{
9 MatrixLayout, StageIdent, TileSize,
10 tile::{
11 SharedTile, Tile, TileKind, TileKindExpand, TileScope,
12 variants::instruction::mma::{MmaStageWriter, mma_fill_fragment, mma_load_strided},
13 },
14};
15
16define_size!(pub NL);
20define_size!(pub NR);
21define_size!(pub NA);
22
23#[derive(CubeType)]
29pub struct MmaTile<N: Numeric> {
30 pub fragment: MmaFragment<N>,
31 #[cube(comptime)]
32 pub matrix_layout: MatrixLayout,
33 #[cube(comptime)]
34 pub tile_size: TileSize,
35 #[cube(comptime)]
36 pub mma_io_config: MmaIOConfig,
37}
38
39#[derive(CubeType)]
40pub enum MmaFragment<N: Numeric> {
41 Lhs(Array<Vector<N, NL>>),
42 Rhs(Array<Vector<N, NR>>),
43 Acc(Array<Vector<N, NA>>),
44}
45
46#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
50pub struct MmaIOConfig {
51 pub lhs_load_method: LoadMethod,
52 pub rhs_load_method: LoadMethod,
53 pub acc_load_method: LoadMethod,
54 pub store_method: StoreMethod,
55}
56
57#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
58pub enum LoadMethod {
59 Manual,
60 LoadMatrix,
61}
62
63#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
64pub enum StoreMethod {
65 Manual,
66 StoreMatrix,
67}
68
69impl MmaIOConfig {
70 pub fn new(
71 device_props: &DeviceProperties,
72 lhs_stage: StorageType,
73 rhs_stage: StorageType,
74 acc_stage: StorageType,
75 ) -> Self {
76 Self {
77 lhs_load_method: load_method(device_props, lhs_stage),
78 rhs_load_method: load_method(device_props, rhs_stage),
79 acc_load_method: load_method(device_props, acc_stage),
80 store_method: store_method(device_props, acc_stage),
81 }
82 }
83
84 pub fn load_method(&self, ident: MatrixIdent) -> LoadMethod {
85 match ident {
86 MatrixIdent::A => self.lhs_load_method,
87 MatrixIdent::B => self.rhs_load_method,
88 MatrixIdent::Accumulator => self.acc_load_method,
89 }
90 }
91
92 pub fn store_method(&self) -> StoreMethod {
93 self.store_method
94 }
95}
96
97fn load_method(device_props: &DeviceProperties, dtype: StorageType) -> LoadMethod {
98 if !matches!(dtype, StorageType::Packed(_, _))
99 && device_props.features.matmul.ldmatrix.contains(&dtype)
100 {
101 LoadMethod::LoadMatrix
102 } else {
103 LoadMethod::Manual
104 }
105}
106
107fn store_method(device_props: &DeviceProperties, dtype: StorageType) -> StoreMethod {
108 if !matches!(dtype, StorageType::Packed(_, _))
109 && device_props.features.matmul.stmatrix.contains(&dtype)
110 {
111 StoreMethod::StoreMatrix
112 } else {
113 StoreMethod::Manual
114 }
115}
116
117#[cube]
118fn make_mma_definition<L: Numeric, R: Numeric, A: Numeric>(
119 #[comptime] tile_size: TileSize,
120) -> MmaDefinition<L, R, A> {
121 MmaDefinition::new(
122 tile_size.m() as usize,
123 tile_size.n() as usize,
124 tile_size.k() as usize,
125 )
126}
127
128#[cube]
129#[allow(unused_variables)]
130pub fn mma_register_vector_sizes<L: Numeric, R: Numeric, A: Numeric>(def: MmaDefinition<L, R, A>) {
131 let vector_size_a = def.vector_size(MatrixIdent::A);
132 let vector_size_b = def.vector_size(MatrixIdent::B);
133 let vector_size_acc = def.vector_size(MatrixIdent::Accumulator);
134 intrinsic!(|scope| {
135 scope.register_size::<NL>(vector_size_a);
136 scope.register_size::<NR>(vector_size_b);
137 scope.register_size::<NA>(vector_size_acc);
138 });
139}
140
141#[cube]
142pub fn mma_allocate_lhs<L: Numeric, R: Numeric, A: Numeric, Sc: TileScope>(
143 #[comptime] layout: MatrixLayout,
144 #[comptime] tile_size: TileSize,
145 #[comptime] mma_io_config: MmaIOConfig,
146) -> Tile<L, Sc> {
147 let def = make_mma_definition::<L, R, A>(tile_size);
148 mma_register_vector_sizes(def);
149 let vector_count = def.vectors_per_lane(MatrixIdent::A);
150
151 Tile::from_kind(TileKind::new_Mma(MmaTile::<L> {
152 fragment: MmaFragment::new_Lhs(Array::new(vector_count)),
153 matrix_layout: layout,
154 tile_size,
155 mma_io_config,
156 }))
157}
158
159#[cube]
160pub fn mma_allocate_rhs<R: Numeric, L: Numeric, A: Numeric, Sc: TileScope>(
161 #[comptime] layout: MatrixLayout,
162 #[comptime] tile_size: TileSize,
163 #[comptime] mma_io_config: MmaIOConfig,
164) -> Tile<R, Sc> {
165 let def = make_mma_definition::<L, R, A>(tile_size);
166 mma_register_vector_sizes(def);
167 let vector_count = def.vectors_per_lane(MatrixIdent::B);
168
169 Tile::from_kind(TileKind::new_Mma(MmaTile::<R> {
170 fragment: MmaFragment::new_Rhs(Array::new(vector_count)),
171 matrix_layout: layout,
172 tile_size,
173 mma_io_config,
174 }))
175}
176
177#[cube]
178pub fn mma_allocate_acc<A: Numeric, L: Numeric, R: Numeric, Sc: TileScope>(
179 #[comptime] layout: MatrixLayout,
180 #[comptime] tile_size: TileSize,
181 #[comptime] mma_io_config: MmaIOConfig,
182) -> Tile<A, Sc> {
183 let def = make_mma_definition::<L, R, A>(tile_size);
184 mma_register_vector_sizes(def);
185 let vector_count = def.vectors_per_lane(MatrixIdent::Accumulator);
186
187 Tile::from_kind(TileKind::new_Mma(MmaTile::<A> {
188 fragment: MmaFragment::new_Acc(Array::new(vector_count)),
189 matrix_layout: layout,
190 tile_size,
191 mma_io_config,
192 }))
193}
194
195#[cube]
196impl<A: Numeric> MmaTile<A> {
197 pub fn mma<L: Numeric, R: Numeric>(&mut self, lhs: &MmaTile<L>, rhs: &MmaTile<R>) {
200 match &lhs.fragment {
201 MmaFragment::Lhs(lf) => match &rhs.fragment {
202 MmaFragment::Rhs(rf) => match &mut self.fragment {
203 MmaFragment::Acc(af) => {
204 mma_execute(lf, rf, af, self.matrix_layout, self.tile_size);
205 }
206 MmaFragment::Lhs(_) | MmaFragment::Rhs(_) => {
207 panic!("Mma: expected Acc role for accumulator")
208 }
209 },
210 MmaFragment::Lhs(_) | MmaFragment::Acc(_) => {
211 panic!("Mma: expected Rhs role for rhs")
212 }
213 },
214 MmaFragment::Rhs(_) | MmaFragment::Acc(_) => {
215 panic!("Mma: expected Lhs role for lhs")
216 }
217 }
218 }
219}
220
221#[cube]
222impl<N: Numeric> MmaTile<N> {
223 pub fn copy_from<SE: Numeric, SS: Size, L: Numeric, R: Numeric, A: Numeric, Sc: TileScope>(
230 &mut self,
231 source: &Tile<SE, Sc>,
232 #[comptime] _ident: StageIdent,
233 ) {
234 match &source.kind {
235 TileKind::SharedTile(shared) => match &mut self.fragment {
236 MmaFragment::Lhs(f) => mma_load_lhs_from_shared::<SE, SS, N, R, A>(
237 shared,
238 f,
239 self.matrix_layout,
240 self.tile_size,
241 self.mma_io_config,
242 ),
243 MmaFragment::Rhs(f) => mma_load_rhs_from_shared::<SE, SS, N, L, A>(
244 shared,
245 f,
246 self.matrix_layout,
247 self.tile_size,
248 self.mma_io_config,
249 ),
250 MmaFragment::Acc(f) => mma_load_acc_from_shared::<SE, SS, N, L, R>(
251 shared,
252 f,
253 self.matrix_layout,
254 self.tile_size,
255 self.mma_io_config,
256 ),
257 },
258 TileKind::None => match &mut self.fragment {
259 MmaFragment::Acc(f) => {
260 mma_load_acc_zeros::<N, L, R>(
261 f,
262 self.matrix_layout,
263 self.tile_size,
264 self.mma_io_config,
265 );
266 }
267 MmaFragment::Lhs(_) | MmaFragment::Rhs(_) => {
268 panic!("Mma zero-load only supported for Acc role")
269 }
270 },
271 TileKind::Cmma(_)
272 | TileKind::Mma(_)
273 | TileKind::Register(_)
274 | TileKind::PlaneVec(_)
275 | TileKind::Interleaved(_)
276 | TileKind::Unit(_)
277 | TileKind::WhiteboxFragment(_)
278 | TileKind::RowWise(_)
279 | TileKind::Bounce(_)
280 | TileKind::Stage(_)
281 | TileKind::Partition(_)
282 | TileKind::Pipelined(_) => panic!("MmaTile::copy_from: unsupported source variant"),
283 }
284 }
285
286 pub fn init_zero<L: Numeric, R: Numeric>(&mut self) {
288 match &mut self.fragment {
289 MmaFragment::Acc(f) => {
290 mma_load_acc_zeros::<N, L, R>(
291 f,
292 self.matrix_layout,
293 self.tile_size,
294 self.mma_io_config,
295 );
296 }
297 MmaFragment::Lhs(_) | MmaFragment::Rhs(_) => {
298 panic!("MmaTile::init_zero: only Acc role supported")
299 }
300 }
301 }
302}
303
304#[cube]
309pub fn mma_execute<L: Numeric, R: Numeric, A: Numeric>(
310 lhs: &Array<Vector<L, NL>>,
311 rhs: &Array<Vector<R, NR>>,
312 acc: &mut Array<Vector<A, NA>>,
313 #[comptime] _matrix_layout: MatrixLayout,
314 #[comptime] tile_size: TileSize,
315) {
316 let def = MmaDefinition::<L, R, A>::new(
317 tile_size.m() as usize,
318 tile_size.n() as usize,
319 tile_size.k() as usize,
320 );
321 let out_arr = def.execute(lhs, rhs, &*acc);
322 let num_vectors = def.vectors_per_lane(MatrixIdent::Accumulator);
323 #[unroll]
324 for i in 0..num_vectors {
325 acc[i] = out_arr[i];
326 }
327}
328
329#[cube]
330pub fn mma_load_lhs_from_shared<E: Numeric, ES: Size, L: Numeric, R: Numeric, A: Numeric>(
331 shared: &SharedTile<E>,
332 fragment: &mut Array<Vector<L, NL>>,
333 #[comptime] matrix_layout: MatrixLayout,
334 #[comptime] tile_size: TileSize,
335 #[comptime] mma_io_config: MmaIOConfig,
336) {
337 let shared = shared.view::<ES>();
338 let def = make_mma_definition::<L, R, A>(tile_size);
339 mma_load_strided(
340 &shared,
341 fragment,
342 &def,
343 MatrixIdent::A,
344 matrix_layout,
345 tile_size,
346 mma_io_config,
347 );
348}
349
350#[cube]
351pub fn mma_load_rhs_from_shared<E: Numeric, ES: Size, R: Numeric, L: Numeric, A: Numeric>(
352 shared: &SharedTile<E>,
353 fragment: &mut Array<Vector<R, NR>>,
354 #[comptime] matrix_layout: MatrixLayout,
355 #[comptime] tile_size: TileSize,
356 #[comptime] mma_io_config: MmaIOConfig,
357) {
358 let shared = shared.view::<ES>();
359 let def = make_mma_definition::<L, R, A>(tile_size);
360 mma_load_strided(
361 &shared,
362 fragment,
363 &def,
364 MatrixIdent::B,
365 matrix_layout,
366 tile_size,
367 mma_io_config,
368 );
369}
370
371#[cube]
372pub fn mma_load_acc_from_shared<E: Numeric, ES: Size, A: Numeric, L: Numeric, R: Numeric>(
373 shared: &SharedTile<E>,
374 fragment: &mut Array<Vector<A, NA>>,
375 #[comptime] matrix_layout: MatrixLayout,
376 #[comptime] tile_size: TileSize,
377 #[comptime] mma_io_config: MmaIOConfig,
378) {
379 let shared = shared.view::<ES>();
380 let def = make_mma_definition::<L, R, A>(tile_size);
381 mma_load_strided(
382 &shared,
383 fragment,
384 &def,
385 MatrixIdent::Accumulator,
386 matrix_layout,
387 tile_size,
388 mma_io_config,
389 );
390}
391
392#[cube]
393pub fn mma_load_acc_zeros<A: Numeric, L: Numeric, R: Numeric>(
394 fragment: &mut Array<Vector<A, NA>>,
395 #[comptime] matrix_layout: MatrixLayout,
396 #[comptime] tile_size: TileSize,
397 #[comptime] mma_io_config: MmaIOConfig,
398) {
399 let _ = (matrix_layout, mma_io_config);
400 let def = make_mma_definition::<L, R, A>(tile_size);
401 mma_fill_fragment::<A, NA, A, L, R, A>(
402 &A::from_int(0),
403 fragment,
404 &def,
405 MatrixIdent::Accumulator,
406 );
407}
408
409#[cube]
410pub fn mma_write_to_shared<E: Numeric, ES: Size, A: Numeric, L: Numeric, R: Numeric>(
411 shared: &mut SharedTile<E>,
412 fragment: &Array<Vector<A, NA>>,
413 #[comptime] tile_size: TileSize,
414 #[comptime] mma_io_config: MmaIOConfig,
415) {
416 let mut shared = shared.view::<ES>();
417 let def = make_mma_definition::<L, R, A>(tile_size);
418 let out_layout = comptime!(shared.layout);
419 MmaStageWriter::store_fragment(
420 &mut shared,
421 fragment,
422 &def,
423 MatrixIdent::Accumulator,
424 out_layout,
425 tile_size.m(),
426 mma_io_config,
427 );
428}