Skip to main content

cubek_convolution/launch/
base.rs

1//! Unified `launch_ref` entry point for the convolution kernel family.
2//!
3//! Picks the right `Routine` impl from `ConvAlgorithm`, threads the
4//! `Strategy` (`Specific` / `Forced`) into a matmul `BlueprintStrategy`, and
5//! dispatches to the per-operation helper based on `ConvolutionInputs`.
6
7use cubecl::client::Client;
8use cubek_matmul::{
9    definition::MatmulElems,
10    multi_level::{
11        components::tile::TileMatmulKind, definition::BatchMatmulBlueprint, routines::TilingArgs,
12    },
13    routine::BlueprintStrategy,
14};
15
16use crate::{components::ConvolutionOperation, definition::ConvBlueprint};
17
18fn blueprint_operation(blueprint: &ConvBlueprint) -> ConvolutionOperation {
19    match blueprint {
20        ConvBlueprint::Forward(_) => ConvolutionOperation::Forward,
21        ConvBlueprint::BackwardData(_) => ConvolutionOperation::BackwardData,
22        ConvBlueprint::BackwardWeight(_) => ConvolutionOperation::BackwardWeight,
23    }
24}
25
26use crate::{
27    components::ConvSetupError,
28    kernels::{backward_data, backward_weight, forward},
29    launch::{
30        ConvAlgorithm, ConvolutionArgs, ConvolutionInputs, Strategy, strategy::AcceleratedTileKind,
31        unit,
32    },
33    routines::{
34        Routine,
35        simple::{
36            SimpleAsyncCyclicConv, SimpleAsyncStridedConv, SimpleAsyncTmaConv,
37            SimpleSyncCyclicConv, SimpleSyncStridedConv, SimpleSyncTilewiseConv,
38        },
39        specialized::{
40            SpecializedAsyncCyclicConv, SpecializedAsyncStridedConv, SpecializedTmaConv,
41        },
42    },
43};
44
45/// Map `AcceleratedTileKind` → matmul's `TileMatmulKind`.
46pub(crate) fn tile_kind_to_dispatch(kind: AcceleratedTileKind) -> TileMatmulKind {
47    match kind {
48        AcceleratedTileKind::Cmma => TileMatmulKind::Cmma,
49        AcceleratedTileKind::Mma => TileMatmulKind::Mma,
50    }
51}
52
53/// The single public convolution entry point.
54///
55/// Routes the `inputs` (whose discriminant is the operation) and `strategy`
56/// (algorithm + tile-matmul kind, optionally a forced blueprint) into the right
57/// generic `Routine` and per-operation launch helper.
58#[allow(clippy::result_large_err)]
59pub fn launch_ref<const N_SPATIAL: usize>(
60    strategy: &Strategy,
61    client: &Client,
62    inputs: ConvolutionInputs,
63    args: ConvolutionArgs<N_SPATIAL>,
64    dtypes: MatmulElems,
65) -> Result<(), ConvSetupError> {
66    let (algorithm, tile_kind, forced_matmul) = match strategy {
67        Strategy::Inferred {
68            algorithm,
69            tile_kind,
70        } => (*algorithm, *tile_kind, None),
71        Strategy::Forced {
72            algorithm,
73            blueprint,
74        } => {
75            debug_assert_eq!(
76                inputs.operation(),
77                blueprint_operation(blueprint),
78                "Strategy::Forced blueprint variant does not match the inputs operation",
79            );
80            let matmul = blueprint.matmul().clone();
81            // For Forced, tile_kind is encoded inside the matmul blueprint, so
82            // the explicit tile_kind here is unused; we pass Cmma as a benign
83            // default (it gets overwritten by the forced blueprint).
84            (*algorithm, AcceleratedTileKind::Cmma, Some(matmul))
85        }
86        Strategy::Unit(strategy) => {
87            return unit::launch(*strategy, client, inputs, args, dtypes);
88        }
89    };
90
91    // Backward-data does not currently support the TMA reading strategy.
92    if inputs.operation() == ConvolutionOperation::BackwardData
93        && algorithm == ConvAlgorithm::SimpleAsyncTma
94    {
95        return Err(crate::kernels::backward_data::launch::unsupported_tma_error());
96    }
97
98    dispatch_routine::<N_SPATIAL>(
99        algorithm,
100        tile_kind,
101        forced_matmul,
102        client,
103        inputs,
104        args,
105        dtypes,
106    )
107}
108
109/// Dispatch on `ConvAlgorithm` to instantiate the right concrete `Routine`
110/// generic, then forward to the per-operation helper.
111#[allow(clippy::result_large_err, clippy::too_many_arguments)]
112fn dispatch_routine<const N_SPATIAL: usize>(
113    algorithm: ConvAlgorithm,
114    tile_kind: AcceleratedTileKind,
115    forced_matmul: Option<BatchMatmulBlueprint>,
116    client: &Client,
117    inputs: ConvolutionInputs,
118    args: ConvolutionArgs<N_SPATIAL>,
119    dtypes: MatmulElems,
120) -> Result<(), ConvSetupError> {
121    let kind = tile_kind_to_dispatch(tile_kind);
122    match algorithm {
123        ConvAlgorithm::SimpleSyncCyclic => dispatch_inputs::<N_SPATIAL, SimpleSyncCyclicConv>(
124            client,
125            inputs,
126            args,
127            kind,
128            forced_matmul,
129            dtypes,
130        ),
131        ConvAlgorithm::SimpleSyncStrided => dispatch_inputs::<N_SPATIAL, SimpleSyncStridedConv>(
132            client,
133            inputs,
134            args,
135            kind,
136            forced_matmul,
137            dtypes,
138        ),
139        ConvAlgorithm::SimpleSyncTilewise => dispatch_inputs::<N_SPATIAL, SimpleSyncTilewiseConv>(
140            client,
141            inputs,
142            args,
143            kind,
144            forced_matmul,
145            dtypes,
146        ),
147        ConvAlgorithm::SimpleAsyncCyclic => dispatch_inputs::<N_SPATIAL, SimpleAsyncCyclicConv>(
148            client,
149            inputs,
150            args,
151            kind,
152            forced_matmul,
153            dtypes,
154        ),
155        ConvAlgorithm::SimpleAsyncStrided => dispatch_inputs::<N_SPATIAL, SimpleAsyncStridedConv>(
156            client,
157            inputs,
158            args,
159            kind,
160            forced_matmul,
161            dtypes,
162        ),
163        ConvAlgorithm::SimpleAsyncTma => dispatch_inputs::<N_SPATIAL, SimpleAsyncTmaConv>(
164            client,
165            inputs,
166            args,
167            kind,
168            forced_matmul,
169            dtypes,
170        ),
171        ConvAlgorithm::SpecializedAsyncCyclic => {
172            dispatch_inputs::<N_SPATIAL, SpecializedAsyncCyclicConv>(
173                client,
174                inputs,
175                args,
176                kind,
177                forced_matmul,
178                dtypes,
179            )
180        }
181        ConvAlgorithm::SpecializedAsyncStrided => {
182            dispatch_inputs::<N_SPATIAL, SpecializedAsyncStridedConv>(
183                client,
184                inputs,
185                args,
186                kind,
187                forced_matmul,
188                dtypes,
189            )
190        }
191        ConvAlgorithm::SpecializedTma => dispatch_inputs::<N_SPATIAL, SpecializedTmaConv>(
192            client,
193            inputs,
194            args,
195            kind,
196            forced_matmul,
197            dtypes,
198        ),
199    }
200}
201
202/// Branch on operation and forward to the per-op launcher.
203///
204/// All three per-op `ConcreteArgs` traits share the same name and the same
205/// blanket impls on `TensorArgs<RuntimeArgs>` / `TensorMapArgs<RuntimeArgs>`,
206/// so the where clause simply requires an impl per operation.
207#[allow(clippy::result_large_err, clippy::too_many_arguments)]
208fn dispatch_inputs<const N_SPATIAL: usize, Rt: Routine<Blueprint = BatchMatmulBlueprint>>(
209    client: &Client,
210    inputs: ConvolutionInputs,
211    args: ConvolutionArgs<N_SPATIAL>,
212    tile_matmul: TileMatmulKind,
213    forced_matmul: Option<BatchMatmulBlueprint>,
214    dtypes: MatmulElems,
215) -> Result<(), ConvSetupError>
216where
217    Rt::Args: forward::args::ConcreteArgs<Rt::MatmulRoutine>
218        + backward_data::args::ConcreteArgs<Rt::MatmulRoutine>
219        + backward_weight::args::ConcreteArgs<Rt::MatmulRoutine>,
220    Rt::Strategy: TilingArgs,
221{
222    let blueprint_strategy = build_blueprint_strategy::<Rt>(tile_matmul, forced_matmul);
223
224    match inputs {
225        ConvolutionInputs::Forward {
226            input,
227            weight,
228            bias,
229            out,
230        } => forward::launch::launch_internal::<N_SPATIAL, Rt>(
231            client,
232            input,
233            weight,
234            bias,
235            out,
236            args,
237            &blueprint_strategy,
238            dtypes,
239        ),
240        ConvolutionInputs::BackwardData {
241            out_grad,
242            weights,
243            in_grad,
244        } => backward_data::launch::launch_internal::<N_SPATIAL, Rt>(
245            client,
246            out_grad,
247            weights,
248            in_grad,
249            args,
250            &blueprint_strategy,
251            dtypes,
252        ),
253        ConvolutionInputs::BackwardWeight {
254            input,
255            out_grad,
256            weight_grad,
257        } => backward_weight::launch::launch_internal::<N_SPATIAL, Rt>(
258            client,
259            input,
260            out_grad,
261            weight_grad,
262            args,
263            &blueprint_strategy,
264            dtypes,
265        ),
266    }
267}
268
269/// Build a matmul `BlueprintStrategy` from either a forced `BatchMatmulBlueprint`
270/// (extracted from `ConvBlueprint`) or an `Inferred` strategy stamped with the
271/// requested tile-matmul kind.
272fn build_blueprint_strategy<Rt: Routine<Blueprint = BatchMatmulBlueprint>>(
273    tile_matmul: TileMatmulKind,
274    forced_matmul: Option<BatchMatmulBlueprint>,
275) -> BlueprintStrategy<Rt::MatmulRoutine>
276where
277    Rt::Strategy: TilingArgs,
278{
279    match forced_matmul {
280        Some(matmul) => BlueprintStrategy::Forced(matmul),
281        None => {
282            let mut s = <Rt::MatmulRoutine as cubek_std::legacy::Routine>::Strategy::default();
283            s.set_tile_matmul(tile_matmul);
284            BlueprintStrategy::Inferred(s)
285        }
286    }
287}