Skip to main content

cubek_matmul/multi_level/components/batch/gemm/matmul/
base.rs

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)]
24/// Launches the matmul kernel
25pub 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        // Map cube + plane coords to the per-plane block origin. Per
137        // variant, each axis is enumerated in *blocks*: the split axis
138        // is `cube_axis * num_planes + plane_id`, the non-split axis is
139        // just `cube_axis`. A block is 1 cell for the axis that the
140        // variant covers per-plane (Dot covers 1×1; OuterN covers 1
141        // M-row × NR N-cols; OuterM covers MR M-rows × 1 N-col), and
142        // `vector_size` cells for the axis it walks in a block.
143        let vs_u32 = comptime!(vector_size as u32);
144
145        let (m_id, n_id) = match comptime!(config.planes_split) {
146            PlanesSplit::M => {
147                // OuterN splits M (and only OuterN uses split_M in v1).
148                // Plane covers one M-row at `block_id`; cube_n indexes
149                // NR-blocks along N → `n_pos_base = cube_n * vs`.
150                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                // OuterM and Dot split N. OuterM: plane covers one
159                // N-col at `block_id`; cube_m indexes MR-blocks along M.
160                // Dot: 1×1 per plane.
161                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}