Skip to main content

cubek_matmul/launch/
args.rs

1use std::marker::PhantomData;
2
3use cubecl::std::tensor::{
4    View,
5    launch::ViewArg,
6    layout::{Coords1d, VirtualLayout, VirtualLayoutLaunch},
7};
8use cubecl::{
9    prelude::*,
10    zspace::{metadata::Metadata, shape, strides},
11};
12use cubecl::{server::TensorMapMeta, unexpanded};
13
14use crate::components::{
15    global::memory::{
16        BatchLayout, BatchLayoutLaunch, GlobalLayout, GlobalLayoutConfig, GlobalLayoutLaunch,
17        GlobalScaleLayout, NoopLayout, NoopLayoutLaunch, SimpleTmaGlobalLayout,
18        SimpleTmaGlobalLayoutLaunch,
19    },
20    stage::SwizzleMode,
21};
22use crate::definition::{
23    self, Blueprint as _, MatmulElems, MatmulLineSizes, MatmulProblem, TilingBlueprint,
24};
25use crate::launch::handle::MatmulInputHandleRef;
26use crate::routines::Routine;
27
28/// Input argument
29pub type InputArg<MA> =
30    <MA as MatmulArgs>::Input<NumericExpand<0>, NumericExpand<1>, NumericExpand<2>>;
31
32/// Output argument
33pub type OutputArg<MA> = <MA as MatmulArgs>::Output<NumericExpand<2>>;
34
35/// Config argument
36pub type ConfigArg<MA> = <MA as MatmulArgs>::Config;
37
38/// Input runtime argument
39pub type InputRuntimeArg<'a, MA, R> = <InputArg<MA> as LaunchArg>::RuntimeArg<'a, R>;
40
41/// Config runtime argument
42pub type ConfigRuntimeArg<'a, MA, R> = <ConfigArg<MA> as LaunchArg>::RuntimeArg<'a, R>;
43
44/// Output runtime argument
45pub type OutputRuntimeArg<'a, MA, R> = <OutputArg<MA> as LaunchArg>::RuntimeArg<'a, R>;
46
47pub type BatchedCoords = (usize, u32, u32);
48
49/// Create the input runtime arguments for a matmul kernel that works on concrete inputs and
50/// output (not fused).
51pub trait ConcreteInputsFactory<A: Routine<()>>: LaunchArg {
52    #[allow(clippy::too_many_arguments)]
53    fn create<'a, R: Runtime>(
54        client: &ComputeClient<R>,
55        lhs: &'a MatmulInputHandleRef<'a, R>,
56        rhs: &'a MatmulInputHandleRef<'a, R>,
57        blueprint: &A::Blueprint,
58        problem: &MatmulProblem,
59        line_sizes: &MatmulLineSizes,
60        dtypes: &MatmulElems,
61    ) -> Self::RuntimeArg<'a, R>;
62}
63
64/// Create the output runtime argument for a matmul kernel that works on concrete inputs and
65/// output (not fused).
66pub trait ConcreteOutputFactory<A: Routine<()>>: LaunchArg {
67    #[allow(clippy::too_many_arguments)]
68    fn create<'a, R: Runtime>(
69        client: &ComputeClient<R>,
70        out: &'a TensorHandleRef<'a, R>,
71        blueprint: &A::Blueprint,
72        problem: &MatmulProblem,
73        line_sizes: &MatmulLineSizes,
74        dtypes: &MatmulElems,
75    ) -> Self::RuntimeArg<'a, R>;
76}
77
78pub trait RuntimeConfig: LaunchArg + CubeType + Clone + Send + Sync {}
79impl<T: LaunchArg + CubeType + Clone + Send + Sync> RuntimeConfig for T {}
80
81#[cube]
82/// Arguments for the matrix multiplication algorithm.
83pub trait MatmulArgs: Send + Sync + 'static + Clone {
84    /// Type used for the input.
85    type Input<Lhs: Numeric, Rhs: Numeric, EO: Numeric>: LaunchArg + CubeType;
86
87    /// Type used for the output.
88    type Output<EO: Numeric>: LaunchArg + CubeType;
89
90    /// Type used for runtime configuration.
91    type Config: RuntimeConfig;
92
93    /// Inner state that is used to create tensor inputs and
94    /// tensor outputs.
95    type State<Lhs: Numeric, Rhs: Numeric, EO: Numeric>: CubeType;
96
97    /// Init the state.
98    fn init_state<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
99        input: &Self::Input<Lhs, Rhs, EO>,
100        output: &mut Self::Output<EO>,
101        config: Self::Config,
102        #[comptime] lhs_layout_config: GlobalLayoutConfig,
103        #[comptime] rhs_layout_config: GlobalLayoutConfig,
104        #[comptime] out_layout_config: GlobalLayoutConfig,
105    ) -> Self::State<Lhs, Rhs, EO>;
106
107    fn view_lhs<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
108        _state: &Self::State<Lhs, Rhs, EO>,
109    ) -> View<Line<Lhs>, BatchedCoords> {
110        unexpanded!()
111    }
112    fn batch_lhs<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
113        _state: &Self::State<Lhs, Rhs, EO>,
114        _batch: usize,
115    ) -> usize {
116        unexpanded!()
117    }
118    fn view_rhs<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
119        _state: &Self::State<Lhs, Rhs, EO>,
120    ) -> View<Line<Rhs>, BatchedCoords> {
121        unexpanded!()
122    }
123    fn batch_rhs<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
124        _state: &Self::State<Lhs, Rhs, EO>,
125        _batch: usize,
126    ) -> usize {
127        unexpanded!()
128    }
129    fn view_acc<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
130        _state: &Self::State<Lhs, Rhs, EO>,
131    ) -> Option<View<Line<EO>, BatchedCoords>> {
132        unexpanded!()
133    }
134    fn batch_acc<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
135        _state: &Self::State<Lhs, Rhs, EO>,
136        _batch: usize,
137    ) -> usize {
138        unexpanded!()
139    }
140    fn view_out<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
141        _state: &mut Self::State<Lhs, Rhs, EO>,
142    ) -> View<Line<EO>, BatchedCoords, ReadWrite> {
143        unexpanded!()
144    }
145    fn batch_out<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
146        _state: &Self::State<Lhs, Rhs, EO>,
147        _batch: usize,
148    ) -> usize {
149        unexpanded!()
150    }
151
152    fn runtime_config<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
153        _state: &Self::State<Lhs, Rhs, EO>,
154    ) -> Self::Config {
155        unexpanded!()
156    }
157}
158
159#[derive(Clone, Copy)]
160/// Identification of the tensor input.
161pub enum TensorInputIdent {
162    Lhs,
163    Rhs,
164}
165
166#[derive(Clone)]
167/// Type implementing [MatmulArgs] where all inputs and the output are materialized tensors.
168///
169/// Other types might implement [MatmulArgs] for fused matrix multiplication kernels.
170pub struct TensorArgs<Config: RuntimeConfig = ()> {
171    _config: PhantomData<Config>,
172}
173
174#[derive(CubeLaunch, CubeType, Clone, Copy)]
175/// Input representation for [TensorArgs] implementing [MatmulArgs].
176pub struct TensorInputs<Lhs: Numeric, Rhs: Numeric, Acc: Numeric> {
177    /// The lhs tensor.
178    lhs: View<Line<Lhs>, BatchedCoords>,
179    lhs_batch: VirtualLayout<Coords1d, Coords1d>,
180    /// The rhs tensor.
181    rhs: View<Line<Rhs>, BatchedCoords>,
182    rhs_batch: VirtualLayout<Coords1d, Coords1d>,
183    /// The tensor for loading the accumulator, if present
184    acc: Option<View<Line<Acc>, BatchedCoords>>,
185    acc_batch: Option<VirtualLayout<Coords1d, Coords1d>>,
186}
187
188impl<Lhs: Numeric, Rhs: Numeric, Acc: Numeric, A: Routine<()>> ConcreteInputsFactory<A>
189    for TensorInputs<Lhs, Rhs, Acc>
190{
191    fn create<'a, R: Runtime>(
192        client: &ComputeClient<R>,
193        lhs: &'a MatmulInputHandleRef<'a, R>,
194        rhs: &'a MatmulInputHandleRef<'a, R>,
195        blueprint: &A::Blueprint,
196        problem: &MatmulProblem,
197        line_sizes: &MatmulLineSizes,
198        _dtypes: &MatmulElems,
199    ) -> Self::RuntimeArg<'a, R> {
200        let view = |handle: &'a MatmulInputHandleRef<'a, R>,
201                    config: GlobalLayoutConfig,
202                    line_size| match handle {
203            MatmulInputHandleRef::Normal(handle, _dtype) => {
204                let layout = GlobalLayoutLaunch::from_handle(handle, line_size, config);
205                ViewArg::new::<GlobalLayout>(handle.as_array_arg(line_size), layout)
206            }
207            MatmulInputHandleRef::Quantized {
208                data,
209                scale,
210                shape,
211                scheme,
212                ..
213            } => {
214                let (data_layout, scales_layout) = GlobalLayoutLaunch::from_quantized_handle(
215                    client, data, scale, shape, problem, **scheme, line_size, config,
216                );
217                let data_view =
218                    ViewArg::new::<GlobalLayout>(data.as_array_arg(line_size), data_layout);
219                let scales_view =
220                    ViewArg::new::<GlobalScaleLayout>(scale.as_array_arg(1), scales_layout);
221                ViewArg::new_quantized(data_view, scales_view, **scheme)
222            }
223        };
224        let batch_layout = |handle: &'a MatmulInputHandleRef<'a, R>| match handle {
225            MatmulInputHandleRef::Normal(handle, _dtype) => {
226                let layout = BatchLayoutLaunch::from_handle(client, handle, problem);
227                VirtualLayoutLaunch::new::<BatchLayout>(layout)
228            }
229            MatmulInputHandleRef::Quantized { .. } => {
230                VirtualLayoutLaunch::new::<NoopLayout>(NoopLayoutLaunch::new())
231            }
232        };
233
234        TensorInputsLaunch::new(
235            view(lhs, blueprint.lhs_global_layout_config(), line_sizes.lhs),
236            batch_layout(lhs),
237            view(rhs, blueprint.rhs_global_layout_config(), line_sizes.rhs),
238            batch_layout(rhs),
239            OptionArgs::None,
240            OptionArgs::None,
241        )
242    }
243}
244
245#[derive(CubeType, CubeLaunch, Clone, Copy)]
246pub struct TensorOutput<EG: Numeric> {
247    view: View<Line<EG>, BatchedCoords, ReadWrite>,
248    batch: VirtualLayout<Coords1d, Coords1d>,
249}
250
251impl<EG: Numeric, A: Routine<()>> ConcreteOutputFactory<A> for TensorOutput<EG> {
252    fn create<'a, R: Runtime>(
253        client: &ComputeClient<R>,
254        out: &'a TensorHandleRef<'a, R>,
255        blueprint: &A::Blueprint,
256        problem: &MatmulProblem,
257        line_sizes: &MatmulLineSizes,
258        _dtypes: &MatmulElems,
259    ) -> Self::RuntimeArg<'a, R> {
260        let layout = GlobalLayoutLaunch::from_handle(
261            out,
262            line_sizes.out,
263            blueprint.out_global_layout_config(),
264        );
265        let batch = BatchLayoutLaunch::from_handle(client, out, problem);
266        let view = ViewArg::new::<GlobalLayout>(out.as_array_arg(line_sizes.out), layout);
267        TensorOutputLaunch::new(view, VirtualLayoutLaunch::new::<BatchLayout>(batch))
268    }
269}
270
271#[cube]
272impl<Config: RuntimeConfig> MatmulArgs for TensorArgs<Config> {
273    type Output<EO: Numeric> = TensorOutput<EO>;
274    type Input<Lhs: Numeric, Rhs: Numeric, EO: Numeric> = TensorInputs<Lhs, Rhs, EO>;
275    type Config = Config;
276    type State<Lhs: Numeric, Rhs: Numeric, EO: Numeric> =
277        (TensorInputs<Lhs, Rhs, EO>, TensorOutput<EO>, Config);
278
279    fn init_state<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
280        input: &Self::Input<Lhs, Rhs, EO>,
281        output: &mut Self::Output<EO>,
282        config: Self::Config,
283        #[comptime] _lhs_layout_config: GlobalLayoutConfig,
284        #[comptime] _rhs_layout_config: GlobalLayoutConfig,
285        #[comptime] _out_layout_config: GlobalLayoutConfig,
286    ) -> Self::State<Lhs, Rhs, EO> {
287        (*input, *output, config)
288    }
289
290    fn view_lhs<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
291        state: &Self::State<Lhs, Rhs, EO>,
292    ) -> View<Line<Lhs>, BatchedCoords> {
293        state.0.lhs
294    }
295
296    fn batch_lhs<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
297        state: &Self::State<Lhs, Rhs, EO>,
298        batch: usize,
299    ) -> usize {
300        state.0.lhs_batch.to_source_pos(batch)
301    }
302
303    fn view_rhs<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
304        state: &Self::State<Lhs, Rhs, EO>,
305    ) -> View<Line<Rhs>, BatchedCoords> {
306        state.0.rhs
307    }
308
309    fn batch_rhs<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
310        state: &Self::State<Lhs, Rhs, EO>,
311        batch: usize,
312    ) -> usize {
313        state.0.rhs_batch.to_source_pos(batch)
314    }
315
316    fn view_acc<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
317        state: &Self::State<Lhs, Rhs, EO>,
318    ) -> Option<View<Line<EO>, BatchedCoords>> {
319        state.0.acc
320    }
321
322    fn batch_acc<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
323        state: &Self::State<Lhs, Rhs, EO>,
324        batch: usize,
325    ) -> usize {
326        match state.0.acc_batch {
327            Some(layout) => layout.to_source_pos(batch),
328            None => batch,
329        }
330    }
331
332    fn view_out<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
333        state: &mut Self::State<Lhs, Rhs, EO>,
334    ) -> View<Line<EO>, BatchedCoords, ReadWrite> {
335        state.1.view
336    }
337
338    fn batch_out<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
339        state: &Self::State<Lhs, Rhs, EO>,
340        batch: usize,
341    ) -> usize {
342        state.1.batch.to_source_pos(batch)
343    }
344
345    fn runtime_config<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
346        state: &Self::State<Lhs, Rhs, EO>,
347    ) -> Self::Config {
348        state.2.clone()
349    }
350}
351
352#[derive(Clone)]
353/// Type implementing [MatmulArgs] where all inputs and the output are materialized tensor maps.
354///
355/// Other types might implement [MatmulArgs] for fused matrix multiplication kernels.
356pub struct TensorMapArgs<Config: RuntimeConfig = ()> {
357    _config: PhantomData<Config>,
358}
359
360#[derive(CubeLaunch, CubeType, Clone, Copy)]
361/// Input representation for [TensorArgs] implementing [MatmulArgs].
362pub struct TensorMapInputs<Lhs: Numeric, Rhs: Numeric, EO: Numeric> {
363    /// The lhs tensor.
364    pub lhs: View<Line<Lhs>, BatchedCoords>,
365    /// The rhs tensor.
366    pub rhs: View<Line<Rhs>, BatchedCoords>,
367    /// The accumulator
368    pub acc: Option<View<Line<EO>, BatchedCoords>>,
369    /// The accumulator batch layout
370    pub acc_batch: Option<VirtualLayout<Coords1d, Coords1d>>,
371}
372
373impl<Lhs: Numeric, Rhs: Numeric, EO: Numeric, A: Routine<(), Blueprint = TilingBlueprint>>
374    ConcreteInputsFactory<A> for TensorMapInputs<Lhs, Rhs, EO>
375{
376    fn create<'a, R: Runtime>(
377        _client: &ComputeClient<R>,
378        lhs_handle: &'a MatmulInputHandleRef<'a, R>,
379        rhs_handle: &'a MatmulInputHandleRef<'a, R>,
380        blueprint: &A::Blueprint,
381        problem: &MatmulProblem,
382        line_sizes: &MatmulLineSizes,
383        dtypes: &MatmulElems,
384    ) -> Self::RuntimeArg<'a, R> {
385        let lhs = lhs_handle.data();
386        let rhs = rhs_handle.data();
387
388        let tiling_scheme = blueprint.tiling_scheme;
389        let stage_m = tiling_scheme.elements_per_stage_along_m();
390        let stage_n = tiling_scheme.elements_per_stage_along_n();
391        let stage_k = tiling_scheme.elements_per_stage_along_k();
392
393        // Loaders use dynamic layout based on swizzle setting. For no swizzle, contiguous tiles are
394        // loaded and TMA loads single tile wide columns.
395        // For swizzled, bank conflicts aren't an issue so the tile size is the full stage.
396        let stage_size_lhs = match blueprint.swizzle_modes.lhs {
397            SwizzleMode::None => match problem.lhs_layout {
398                definition::MatrixLayout::RowMajor => {
399                    shape![1, stage_m as usize, tiling_scheme.tile_size.k as usize]
400                }
401                definition::MatrixLayout::ColMajor => {
402                    shape![1, stage_k as usize, tiling_scheme.tile_size.m as usize]
403                }
404            },
405            _ => match problem.lhs_layout {
406                definition::MatrixLayout::RowMajor => {
407                    shape![1, stage_m as usize, stage_k as usize]
408                }
409                definition::MatrixLayout::ColMajor => {
410                    shape![1, stage_k as usize, stage_m as usize]
411                }
412            },
413        };
414        let stage_size_rhs = match blueprint.swizzle_modes.rhs {
415            SwizzleMode::None => match problem.rhs_layout {
416                definition::MatrixLayout::RowMajor => {
417                    shape![1, stage_k as usize, tiling_scheme.tile_size.n as usize]
418                }
419                definition::MatrixLayout::ColMajor => {
420                    shape![1, stage_n as usize, tiling_scheme.tile_size.k as usize]
421                }
422            },
423            _ => match problem.rhs_layout {
424                definition::MatrixLayout::RowMajor => {
425                    shape![1, stage_k as usize, stage_n as usize]
426                }
427                definition::MatrixLayout::ColMajor => {
428                    shape![1, stage_n as usize, stage_k as usize]
429                }
430            },
431        };
432
433        let lhs_rank = lhs.shape.len();
434        let mut lhs_shape = shape![
435            problem.lhs_batches.iter().product(),
436            lhs.shape[lhs_rank - 2],
437            lhs.shape[lhs_rank - 1],
438        ];
439        let mut lhs_strides = if lhs_rank > 2 {
440            lhs.strides[lhs_rank - 3..].into()
441        } else {
442            strides![lhs.strides[0], lhs.strides[1]]
443        };
444
445        let rhs_rank = rhs.shape.len();
446        let mut rhs_shape = shape![
447            problem.rhs_batches.iter().product(),
448            rhs.shape[rhs_rank - 2],
449            rhs.shape[rhs_rank - 1],
450        ];
451        let mut rhs_strides = if rhs_rank > 2 {
452            rhs.strides[rhs_rank - 3..].into()
453        } else {
454            strides![rhs.strides[0], rhs.strides[1]]
455        };
456
457        let mut lhs_transposed = false;
458        let mut rhs_transposed = false;
459
460        let lhs_rank = lhs_strides.len();
461        let rhs_rank = rhs_strides.len();
462
463        // TMA assumes the last stride is contiguous and won't even take it, so we need to map it
464        // with transposed shape and stride. Tensor metadata still has the normal layout.
465        if matches!(problem.lhs_layout, definition::MatrixLayout::ColMajor) {
466            lhs_shape.swap(2, 1);
467            lhs_strides.swap(lhs_rank - 1, lhs_rank - 2);
468            lhs_transposed = true;
469        }
470        if matches!(problem.rhs_layout, definition::MatrixLayout::ColMajor) {
471            rhs_shape.swap(2, 1);
472            rhs_strides.swap(rhs_rank - 1, rhs_rank - 2);
473            rhs_transposed = true;
474        }
475
476        // Insert batch stride after swap so we can easily get the non-contiguous stride
477        if lhs_rank == 2 {
478            let stride = lhs_strides[0];
479            lhs_strides.insert(0, stride);
480        }
481        if rhs_rank == 2 {
482            let stride = rhs_strides[0];
483            rhs_strides.insert(0, stride);
484        }
485
486        // f32 gets remapped to tf32 for the tensor map just to ensure CUDA loads them correctly.
487        // It shouldn't matter, but it's better to be safe.
488        let lhs_elem = if dtypes.lhs_stage == f32::as_type_native_unchecked() {
489            tf32::as_type_native_unchecked()
490        } else {
491            dtypes.lhs_stage
492        };
493        let rhs_elem = if dtypes.rhs_stage == f32::as_type_native_unchecked() {
494            tf32::as_type_native_unchecked()
495        } else {
496            dtypes.rhs_stage
497        };
498
499        let meta_lhs = TensorMapMeta {
500            format: TensorMapFormat::Tiled(TiledArgs {
501                tile_size: stage_size_lhs,
502            }),
503            metadata: Metadata::new(lhs_shape.clone(), lhs_strides),
504            elem_stride: strides![1, 1, 1],
505            interleave: TensorMapInterleave::None,
506            swizzle: blueprint.swizzle_modes.lhs.into(),
507            prefetch: TensorMapPrefetch::None,
508            oob_fill: OobFill::Zero,
509            storage_ty: lhs_elem,
510        };
511
512        let meta_rhs = TensorMapMeta {
513            format: TensorMapFormat::Tiled(TiledArgs {
514                tile_size: stage_size_rhs,
515            }),
516            metadata: Metadata::new(rhs_shape.clone(), rhs_strides),
517            elem_stride: strides![1, 1, 1],
518            interleave: TensorMapInterleave::None,
519            swizzle: blueprint.swizzle_modes.rhs.into(),
520            prefetch: TensorMapPrefetch::None,
521            oob_fill: OobFill::Zero,
522            storage_ty: rhs_elem,
523        };
524
525        let lhs = TensorMapArg {
526            tensor: lhs.as_tensor_arg(line_sizes.lhs),
527            metadata: meta_lhs,
528            _kind: PhantomData,
529        };
530        let rhs = TensorMapArg {
531            tensor: rhs.as_tensor_arg(line_sizes.rhs),
532            metadata: meta_rhs,
533            _kind: PhantomData,
534        };
535
536        let view = |buffer, shape: &[usize], transposed| {
537            let batches = ScalarArg::new(shape[0]);
538            let (rows, cols) = match transposed {
539                true => (
540                    ScalarArg::new(shape[2] as u32),
541                    ScalarArg::new(shape[1] as u32),
542                ),
543                false => (
544                    ScalarArg::new(shape[1] as u32),
545                    ScalarArg::new(shape[2] as u32),
546                ),
547            };
548            let shape = (batches, rows, cols);
549            let layout = SimpleTmaGlobalLayoutLaunch::new(transposed, shape);
550            ViewArg::new_tensor_map_tiled::<SimpleTmaGlobalLayout>(buffer, layout)
551        };
552
553        TensorMapInputsLaunch::new(
554            view(lhs, &lhs_shape, lhs_transposed),
555            view(rhs, &rhs_shape, rhs_transposed),
556            OptionArgs::None,
557            OptionArgs::None,
558        )
559    }
560}
561
562#[cube]
563impl<Config: RuntimeConfig> MatmulArgs for TensorMapArgs<Config> {
564    type Input<Lhs: Numeric, Rhs: Numeric, EO: Numeric> = TensorMapInputs<Lhs, Rhs, EO>;
565    type Output<EO: Numeric> = TensorOutput<EO>;
566    type Config = Config;
567    type State<Lhs: Numeric, Rhs: Numeric, EO: Numeric> =
568        (TensorMapInputs<Lhs, Rhs, EO>, TensorOutput<EO>, Config);
569
570    fn init_state<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
571        input: &Self::Input<Lhs, Rhs, EO>,
572        output: &mut Self::Output<EO>,
573        config: Self::Config,
574        #[comptime] _lhs_layout_config: GlobalLayoutConfig,
575        #[comptime] _rhs_layout_config: GlobalLayoutConfig,
576        #[comptime] _out_layout_config: GlobalLayoutConfig,
577    ) -> Self::State<Lhs, Rhs, EO> {
578        (*input, *output, config)
579    }
580
581    fn view_lhs<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
582        state: &Self::State<Lhs, Rhs, EO>,
583    ) -> View<Line<Lhs>, BatchedCoords> {
584        state.0.lhs
585    }
586
587    fn batch_lhs<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
588        _state: &Self::State<Lhs, Rhs, EO>,
589        batch: usize,
590    ) -> usize {
591        batch
592    }
593
594    fn view_rhs<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
595        state: &Self::State<Lhs, Rhs, EO>,
596    ) -> View<Line<Rhs>, BatchedCoords> {
597        state.0.rhs
598    }
599
600    fn batch_rhs<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
601        _state: &Self::State<Lhs, Rhs, EO>,
602        batch: usize,
603    ) -> usize {
604        batch
605    }
606
607    fn view_acc<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
608        state: &Self::State<Lhs, Rhs, EO>,
609    ) -> Option<View<Line<EO>, BatchedCoords>> {
610        state.0.acc
611    }
612
613    fn batch_acc<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
614        state: &Self::State<Lhs, Rhs, EO>,
615        batch: usize,
616    ) -> usize {
617        match state.0.acc_batch {
618            Option::Some(layout) => layout.to_source_pos(batch),
619            Option::None => batch,
620        }
621    }
622
623    fn view_out<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
624        state: &mut Self::State<Lhs, Rhs, EO>,
625    ) -> View<Line<EO>, BatchedCoords, ReadWrite> {
626        state.1.view
627    }
628
629    fn batch_out<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
630        state: &Self::State<Lhs, Rhs, EO>,
631        batch: usize,
632    ) -> usize {
633        state.1.batch.to_source_pos(batch)
634    }
635
636    fn runtime_config<Lhs: Numeric, Rhs: Numeric, EO: Numeric>(
637        state: &Self::State<Lhs, Rhs, EO>,
638    ) -> Self::Config {
639        state.2.clone()
640    }
641}