1use std::marker::PhantomData;
2
3use cubecl::cube;
4use cubecl::prelude::*;
5
6use crate::{
7 definition::*,
8 multi_level::{
9 args::MatmulArgs,
10 components::batch::{
11 BatchConfig as _, BatchMatmul, BatchMatmulFamily,
12 gemm::{
13 GemmBlueprint, GemmConfig, GemmFamily, PlanesSplit, Variant,
14 mat_layout::MatLayout,
15 matmul::{dot::execute_dot, outer_product::execute_outer_product},
16 },
17 },
18 definition::{cube_pos_to_m_n_batch, *},
19 },
20};
21
22#[cube(launch_unchecked, explicit_define, address_type = "dynamic")]
23#[allow(clippy::type_complexity)]
24pub fn matmul_entry<
26 Args: MatmulArgs<Config = ()>,
27 Lhs: Numeric,
28 LhsSize: Size,
29 Rhs: Numeric,
30 RhsSize: Size,
31 Acc: Numeric,
32 AccSize: Size,
33>(
34 inputs: &<Args as MatmulArgs>::Input<
35 Vector<Lhs, LhsSize>,
36 Vector<Rhs, RhsSize>,
37 Vector<Acc, AccSize>,
38 >,
39 output: &mut <Args as MatmulArgs>::Output<Vector<Acc, AccSize>>,
40 runtime_config: (),
41 cube_mapping: CubeMapping,
42 #[comptime] blueprint: GemmBlueprint,
43 #[define(Lhs, Rhs, Acc)] _global: [ElemType; 3],
44 #[define(LhsSize, RhsSize, AccSize)] _sizes: [usize; 3],
45) {
46 let state = Args::init_state::<Vector<Lhs, LhsSize>, Vector<Rhs, RhsSize>, Vector<Acc, AccSize>>(
47 inputs,
48 output,
49 runtime_config,
50 blueprint.lhs_global_layout_config(),
51 blueprint.rhs_global_layout_config(),
52 blueprint.out_global_layout_config(),
53 );
54
55 let vector_size_lhs = Args::view_lhs(&state).vector_size();
56 let vector_size_rhs = Args::view_rhs(&state).vector_size();
57 let vector_size_out = Args::view_out(&state).vector_size();
58 let vector_sizes = comptime!(MatmulVectorSizes {
59 lhs: vector_size_lhs,
60 rhs: vector_size_rhs,
61 out: vector_size_out,
62 });
63
64 let device_props = comptime::device_properties();
65 let config = comptime!(GemmFamily::expand_config(
66 &device_props,
67 &blueprint,
68 &blueprint.dtypes,
69 &vector_sizes
70 ));
71
72 if comptime!(config.is_err()) {
73 push_validation_error(config.err().unwrap().to_string());
74 comptime!(return);
75 }
76 let config = comptime!(config.unwrap());
77
78 let state = Args::init_state::<Vector<Lhs, LhsSize>, Vector<Rhs, RhsSize>, Vector<Acc, AccSize>>(
79 inputs,
80 output,
81 runtime_config,
82 config.lhs_global_layout_config(),
83 config.rhs_global_layout_config(),
84 config.out_global_layout_config(),
85 );
86
87 let define!(RegisterLhs) = blueprint.dtypes.lhs_register;
88 let define!(RegisterRhs) = blueprint.dtypes.rhs_register;
89 let define!(RegisterAcc) = blueprint.dtypes.acc_register;
90
91 Gemm::<(
92 (Lhs, LhsSize, Lhs, LhsSize, RegisterLhs, LhsSize),
93 (Rhs, RhsSize, Rhs, RhsSize, RegisterRhs, RhsSize),
94 (Acc, AccSize, Acc, AccSize, RegisterAcc, AccSize),
95 )>::execute::<Args>(&state, cube_mapping, config);
96}
97
98pub struct Gemm<MP: MatmulTypes> {
99 _phantom: PhantomData<MP>,
100}
101
102#[cube]
103impl<MP: MatmulTypes> BatchMatmul<(), MP> for Gemm<MP> {
104 type Config = GemmConfig;
105
106 fn execute<Args: MatmulArgs>(
107 state: &Args::State<LhsG<MP>, RhsG<MP>, AccG<MP>>,
108 cube_mapping: CubeMapping,
109 #[comptime] config: Self::Config,
110 ) {
111 let lhs = Args::view_lhs(state);
112 let rhs = Args::view_rhs(state);
113 let out = Args::view_out(state);
114
115 let (_, m, k) = lhs.shape();
116 let (_, _, n) = rhs.shape();
117
118 let (cube_m, cube_n, batch_cube) = cube_pos_to_m_n_batch(&cube_mapping);
119
120 let lhs_batch = Args::batch_lhs(state, batch_cube as usize);
121 let rhs_batch = Args::batch_rhs(state, batch_cube as usize);
122 let out_batch = Args::batch_out(state, batch_cube as usize);
123
124 let lhs_vec = lhs.vector_size();
125 let rhs_vec = rhs.vector_size();
126 let vector_size = comptime![Ord::max(lhs_vec, rhs_vec)];
127 let size!(N) = vector_size;
128
129 let check_bounds = config.check_bounds;
130 let variant = comptime!(config.variant);
131
132 let lhs_view = lhs.view(MatLayout::new(lhs_batch, (m, k)));
133 let rhs_view = rhs.view(MatLayout::new(rhs_batch, (k, n)));
134 let out_view = out.view_mut(MatLayout::new(out_batch, (m, n)));
135
136 let vs_u32 = comptime!(vector_size as u32);
144
145 let (m_id, n_id) = match comptime!(config.planes_split) {
146 PlanesSplit::M => {
147 let block_id = cube_m * config.num_planes + UNIT_POS_Y;
151 match comptime!(variant) {
152 Variant::OuterN => (block_id, cube_n * vs_u32),
153 Variant::OuterM => (block_id * vs_u32, cube_n),
154 Variant::Dot => (block_id, cube_n),
155 }
156 }
157 PlanesSplit::N => {
158 let block_id = cube_n * config.num_planes + UNIT_POS_Y;
162 match comptime!(variant) {
163 Variant::OuterN => (cube_m, block_id * vs_u32),
164 Variant::OuterM => (cube_m * vs_u32, block_id),
165 Variant::Dot => (cube_m, block_id),
166 }
167 }
168 };
169
170 match comptime!(variant) {
171 Variant::Dot => {
172 execute_dot::<LhsG<MP>, RhsG<MP>, AccG<MP>, AccRE<MP>, N>(
173 lhs_view,
174 rhs_view,
175 out_view,
176 m_id,
177 n_id,
178 k,
179 config.plane_dim,
180 vector_size as u32,
181 check_bounds,
182 );
183 }
184 Variant::OuterN => {
185 execute_outer_product::<
186 Global<Lhs<MP>>,
187 Global<Rhs<MP>>,
188 AccG<MP>,
189 AccRE<MP>,
190 GlobalSize<Lhs<MP>>,
191 GlobalSize<Rhs<MP>>,
192 N,
193 >(
194 lhs_view,
195 rhs_view,
196 out_view,
197 m_id,
198 n_id,
199 k,
200 vector_size as u32,
201 true,
202 check_bounds,
203 );
204 }
205 Variant::OuterM => {
206 execute_outer_product::<
207 Global<Lhs<MP>>,
208 Global<Rhs<MP>>,
209 AccG<MP>,
210 AccRE<MP>,
211 GlobalSize<Lhs<MP>>,
212 GlobalSize<Rhs<MP>>,
213 N,
214 >(
215 lhs_view,
216 rhs_view,
217 out_view,
218 m_id,
219 n_id,
220 k,
221 vector_size as u32,
222 false,
223 check_bounds,
224 );
225 }
226 }
227 }
228}