cubek_std/tile/variants/instruction/mma/
writer.rs1use cubecl::{
2 prelude::*,
3 {cmma::MmaDefinition, ir::MatrixIdent},
4};
5
6use crate::{
7 MatrixLayout, as_cmma_layout,
8 tile::{
9 StridedTile,
10 variants::{MmaIOConfig, StoreMethod},
11 },
12};
13
14#[derive(CubeType)]
16pub struct MmaStageWriter {}
17
18#[cube]
19impl MmaStageWriter {
20 pub fn store_fragment<
21 E: Numeric,
22 N: Size,
23 V: Numeric,
24 NV: Size,
25 A: Numeric,
26 B: Numeric,
27 CD: Numeric,
28 >(
29 tile: &mut StridedTile<V, NV>,
30 fragment: &Array<Vector<E, N>>,
31 def: &MmaDefinition<A, B, CD>,
32 #[comptime] ident: MatrixIdent,
33 #[comptime] layout: MatrixLayout,
34 #[comptime] m: u32,
35 #[comptime] config: MmaIOConfig,
36 ) {
37 let vector_layout = def.vector_layout(ident);
38 let transposed = comptime![as_cmma_layout(layout) != vector_layout];
39
40 match config.store_method() {
41 StoreMethod::Manual => {
42 if transposed {
43 store_manual_transposed(tile, fragment, def, ident, layout);
44 } else {
45 store_manual_plain(tile, fragment, def, ident, layout);
46 }
47 }
48 StoreMethod::StoreMatrix => {
49 store_stmatrix::<E, N, V, NV, A, B, CD>(tile, fragment, def, transposed, ident, m)
50 }
51 }
52 }
53}
54
55#[cube]
56fn store_manual_transposed<
57 E: Numeric,
58 N: Size,
59 V: Numeric,
60 NV: Size,
61 A: Numeric,
62 B: Numeric,
63 CD: Numeric,
64>(
65 tile: &mut StridedTile<V, NV>,
66 fragment: &Array<Vector<E, N>>,
67 def: &MmaDefinition<A, B, CD>,
68 #[comptime] ident: MatrixIdent,
69 #[comptime] layout: MatrixLayout,
70) {
71 let num_vectors = def.vectors_per_lane(ident);
72 let vector_size = def.vector_size(ident);
73 let lane_id = UNIT_POS_PLANE;
74
75 let stride = tile.unvectorized_stride();
76 let mut tile = tile.with_vector_size::<Const<1>>();
77
78 let (stride_row, stride_col) = match layout {
79 MatrixLayout::RowMajor => (stride, 1),
80 MatrixLayout::ColMajor => (1, stride),
81 };
82
83 #[unroll]
84 for i in 0..num_vectors {
85 #[unroll]
86 for n in 0..vector_size {
87 let elem_idx = i * vector_size + n;
88 let (row, col) = def.position_of_nth(lane_id, elem_idx as u32, ident);
89 let offset = row * stride_row + col * stride_col;
90 let offset = tile.stage_offset(offset);
91
92 tile.container[offset as usize] = Vector::cast_from(fragment[i].extract(n));
93 }
94 }
95}
96
97#[cube]
98fn store_manual_plain<
99 E: Numeric,
100 N: Size,
101 V: Numeric,
102 NV: Size,
103 A: Numeric,
104 B: Numeric,
105 CD: Numeric,
106>(
107 tile: &mut StridedTile<V, NV>,
108 fragment: &Array<Vector<E, N>>,
109 def: &MmaDefinition<A, B, CD>,
110 #[comptime] ident: MatrixIdent,
111 #[comptime] layout: MatrixLayout,
112) {
113 let num_vectors = def.vectors_per_lane(ident);
114 let vector_size = def.vector_size(ident);
115 let lane_id = UNIT_POS_PLANE;
116 let stride = tile.unvectorized_stride();
117 let mut tile = tile.with_vector_size::<N>();
119
120 let (stride_row, stride_col) = match layout {
121 MatrixLayout::RowMajor => (stride, 1),
122 MatrixLayout::ColMajor => (1, stride),
123 };
124
125 #[unroll]
126 for i in 0..num_vectors {
127 let value = fragment[i];
128 let elem_idx = i * vector_size;
129 let (row, col) = def.position_of_nth(lane_id, elem_idx as u32, ident);
130 let offset = row * stride_row + col * stride_col;
131 let offset = tile.stage_offset(offset / vector_size as u32);
132
133 tile.container[offset as usize] = Vector::cast_from(value);
134 }
135}
136
137#[cube]
144fn store_stmatrix<
145 E: Numeric,
146 N: Size,
147 V: Numeric,
148 NV: Size,
149 A: Numeric,
150 B: Numeric,
151 CD: Numeric,
152>(
153 tile: &mut StridedTile<V, NV>,
154 fragment: &Array<Vector<E, N>>,
155 def: &MmaDefinition<A, B, CD>,
156 #[comptime] transposed: bool,
157 #[comptime] ident: MatrixIdent,
158 #[comptime] m: u32,
159) {
160 let stage_vector_size = tile.container.vector_size().comptime();
161 let stride = tile.unvectorized_stride();
162
163 let elem_size = E::type_size().comptime();
164 let num_regs = def.vectors_per_lane(ident);
165 let width = (16 / elem_size / stage_vector_size) as u32;
166
167 let start = stmatrix_offset::<V, A, B, CD>(stride, def, stage_vector_size, ident, m);
168 let start = tile.stage_offset(start);
169
170 let row_slice = &mut tile.container[start as usize..(start + width) as usize];
171
172 let stage_ty = V::as_type().comptime();
173 let frag_ty = E::as_type().comptime();
174 if stage_ty == frag_ty {
175 let row_slice = row_slice.downcast_mut();
176 def.store_matrix::<Vector<E, NV>, N>(row_slice, fragment, ident, num_regs, transposed);
177 } else {
178 let mut frag = Array::new(num_regs);
179 #[unroll]
180 for i in 0..num_regs {
181 frag[i] = Vector::cast_from(fragment[i]);
182 }
183 def.store_matrix::<_, N>(row_slice, &frag, ident, num_regs, transposed);
184 }
185}
186
187#[cube]
190pub(crate) fn stmatrix_offset<E: Numeric, A: Numeric, B: Numeric, CD: Numeric>(
191 stride: u32,
192 def: &MmaDefinition<A, B, CD>,
193 #[comptime] stage_vector_size: VectorSize,
194 #[comptime] ident: MatrixIdent,
195 #[comptime] m: u32,
196) -> u32 {
197 let (stride_row, stride_col) = (stride, 1);
198
199 let elem_size = E::type_size().comptime();
200 let num_regs = def.vectors_per_lane(ident);
201 let width = (16 / elem_size) as u32;
202 let height = 8;
204
205 let lane = UNIT_POS_PLANE;
207 let sub_lane = lane % height;
208 let nth_matrix = lane / height % num_regs as u32;
209
210 let tiles_row = m / height;
211
212 let row_offs = (nth_matrix % tiles_row) * 8;
214 let col_offs = (nth_matrix / tiles_row) * width;
215
216 let (row, col) = (row_offs + sub_lane, col_offs);
217
218 let start = row * stride_row + col * stride_col;
219 start / stage_vector_size as u32
220}