Skip to main content

cubek_matmul/
args.rs

1use std::marker::PhantomData;
2
3use cubecl::prelude::*;
4use cubecl::std::tensor::{
5    View, ViewMut,
6    launch::ViewArg,
7    layout::{Coords1d, VirtualLayout, VirtualLayoutLaunch},
8};
9use cubecl::unexpanded;
10use cubek_std::launch::tma::tma_operand;
11use cubek_std::{InputBinding, MatrixLayout, stage::SwizzleMode};
12
13use crate::components::global::memory::{
14    BatchLayout, BatchLayoutLaunch, GlobalLayout, GlobalLayoutConfig, GlobalLayoutLaunch,
15    GlobalScaleLayout, NoopLayout, NoopLayoutLaunch, SimpleTmaGlobalLayout,
16    SimpleTmaGlobalLayoutLaunch,
17};
18use crate::{
19    definition::{Blueprint as _, MatmulElems, MatmulProblem, MatmulVectorSizes},
20    routines::BatchMatmulRoutine,
21};
22
23define_scalar!(pub Lhs);
24define_scalar!(pub Rhs);
25define_scalar!(pub Acc);
26
27define_size!(pub LhsSize);
28define_size!(pub RhsSize);
29define_size!(pub AccSize);
30
31/// Input argument
32pub type InputArg<MA> =
33    <MA as MatmulArgs>::Input<Vector<Lhs, LhsSize>, Vector<Rhs, RhsSize>, Vector<Acc, AccSize>>;
34
35/// Output argument
36pub type OutputArg<MA> = <MA as MatmulArgs>::Output<Vector<Acc, AccSize>>;
37
38/// Config argument
39pub type ConfigArg<MA> = <MA as MatmulArgs>::Config;
40
41/// Input runtime argument
42pub type InputRuntimeArg<MA, R> = <InputArg<MA> as LaunchArg>::RuntimeArg<R>;
43
44/// Config runtime argument
45pub type ConfigRuntimeArg<MA, R> = <ConfigArg<MA> as LaunchArg>::RuntimeArg<R>;
46
47/// Output runtime argument
48pub type OutputRuntimeArg<MA, R> = <OutputArg<MA> as LaunchArg>::RuntimeArg<R>;
49
50pub type BatchedCoords = (usize, u32, u32);
51
52/// Create the input runtime arguments for a matmul kernel that works on concrete inputs and
53/// output (not fused).
54pub trait ConcreteInputsFactory<A: BatchMatmulRoutine<()>>: LaunchArg {
55    #[allow(clippy::too_many_arguments)]
56    fn create<R: Runtime>(
57        lhs: InputBinding<R>,
58        rhs: InputBinding<R>,
59        blueprint: &A::Blueprint,
60        problem: &MatmulProblem,
61        vector_sizes: &MatmulVectorSizes,
62        dtypes: &MatmulElems,
63    ) -> Self::RuntimeArg<R>;
64}
65
66/// Create the output runtime argument for a matmul kernel that works on concrete inputs and
67/// output (not fused).
68pub trait ConcreteOutputFactory<A: BatchMatmulRoutine<()>>: LaunchArg {
69    #[allow(clippy::too_many_arguments)]
70    fn create<R: Runtime>(
71        out: TensorBinding<R>,
72        blueprint: &A::Blueprint,
73        problem: &MatmulProblem,
74        vector_sizes: &MatmulVectorSizes,
75        dtypes: &MatmulElems,
76    ) -> Self::RuntimeArg<R>;
77}
78
79pub trait RuntimeConfig: LaunchArg + CubeType<ExpandType: Clone> + Clone + Send + Sync {}
80impl<T: LaunchArg + CubeType<ExpandType: Clone> + Clone + Send + Sync> RuntimeConfig for T {}
81
82#[cube]
83/// Arguments for the matrix multiplication algorithm.
84pub trait MatmulArgs: Send + Sync + 'static + Clone {
85    /// Type used for the input.
86    type Input<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>: LaunchArg + CubeType;
87
88    /// Type used for the output.
89    type Output<EO: CubePrimitive>: LaunchArg + CubeType;
90
91    /// Type used for runtime configuration.
92    type Config: RuntimeConfig;
93
94    /// Inner state that is used to create tensor inputs and
95    /// tensor outputs.
96    type State<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>: CubeType;
97
98    /// Init the state.
99    fn init_state<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
100        input: &Self::Input<Lhs, Rhs, EO>,
101        output: &mut Self::Output<EO>,
102        config: Self::Config,
103        #[comptime] lhs_layout_config: GlobalLayoutConfig,
104        #[comptime] rhs_layout_config: GlobalLayoutConfig,
105        #[comptime] out_layout_config: GlobalLayoutConfig,
106    ) -> Self::State<Lhs, Rhs, EO>;
107
108    fn view_lhs<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
109        _state: &Self::State<Lhs, Rhs, EO>,
110    ) -> View<'_, Lhs, BatchedCoords> {
111        unexpanded!()
112    }
113    fn batch_lhs<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
114        _state: &Self::State<Lhs, Rhs, EO>,
115        _batch: usize,
116    ) -> usize {
117        unexpanded!()
118    }
119    fn view_rhs<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
120        _state: &Self::State<Lhs, Rhs, EO>,
121    ) -> View<'_, Rhs, BatchedCoords> {
122        unexpanded!()
123    }
124    fn batch_rhs<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
125        _state: &Self::State<Lhs, Rhs, EO>,
126        _batch: usize,
127    ) -> usize {
128        unexpanded!()
129    }
130    fn view_acc<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
131        _state: &Self::State<Lhs, Rhs, EO>,
132    ) -> ComptimeOption<View<'_, EO, BatchedCoords>> {
133        unexpanded!()
134    }
135    fn batch_acc<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
136        _state: &Self::State<Lhs, Rhs, EO>,
137        _batch: usize,
138    ) -> usize {
139        unexpanded!()
140    }
141    fn view_out<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
142        _state: &Self::State<Lhs, Rhs, EO>,
143    ) -> ViewMut<'_, EO, BatchedCoords> {
144        unexpanded!()
145    }
146    fn batch_out<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
147        _state: &Self::State<Lhs, Rhs, EO>,
148        _batch: usize,
149    ) -> usize {
150        unexpanded!()
151    }
152
153    fn runtime_config<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
154        _state: &Self::State<Lhs, Rhs, EO>,
155    ) -> Self::Config {
156        unexpanded!()
157    }
158}
159
160#[derive(Clone, Copy)]
161/// Identification of the tensor input.
162pub enum TensorInputIdent {
163    Lhs,
164    Rhs,
165}
166
167#[derive(Clone)]
168/// Type implementing [MatmulArgs] where all inputs and the output are materialized tensors.
169///
170/// Other types might implement [MatmulArgs] for fused matrix multiplication kernels.
171pub struct TensorArgs<Config: RuntimeConfig = ()> {
172    _config: PhantomData<Config>,
173}
174
175#[derive(CubeLaunch, CubeType, Clone)]
176#[expand(derive(Clone))]
177/// Input representation for [TensorArgs] implementing [MatmulArgs].
178pub struct TensorInputs<Lhs: CubePrimitive, Rhs: CubePrimitive, Acc: CubePrimitive> {
179    /// The lhs tensor.
180    lhs_batch: VirtualLayout<Coords1d, Coords1d>,
181    lhs: View<'static, Lhs, BatchedCoords>,
182    /// The rhs tensor.
183    rhs_batch: VirtualLayout<Coords1d, Coords1d>,
184    rhs: View<'static, Rhs, BatchedCoords>,
185    /// The tensor for loading the accumulator, if present
186    acc_batch: ComptimeOption<VirtualLayout<Coords1d, Coords1d>>,
187    acc: ComptimeOption<View<'static, Acc, BatchedCoords>>,
188}
189
190impl<Lhs: CubePrimitive, Rhs: CubePrimitive, Acc: CubePrimitive, A: BatchMatmulRoutine<()>>
191    ConcreteInputsFactory<A> for TensorInputs<Lhs, Rhs, Acc>
192{
193    fn create<R: Runtime>(
194        lhs: InputBinding<R>,
195        rhs: InputBinding<R>,
196        blueprint: &A::Blueprint,
197        problem: &MatmulProblem,
198        vector_sizes: &MatmulVectorSizes,
199        _dtypes: &MatmulElems,
200    ) -> Self::RuntimeArg<R> {
201        let view = |handle: InputBinding<R>, config: GlobalLayoutConfig, vector_size| match handle {
202            InputBinding::Normal(handle, _dtype) => {
203                let layout = GlobalLayoutLaunch::from_handle(&handle, vector_size, config);
204                ViewArg::new_tensor::<GlobalLayout>(handle.into_tensor_arg(), layout)
205            }
206            InputBinding::Quantized {
207                data,
208                scale,
209                shape,
210                scheme,
211                ..
212            } => {
213                let (data_layout, scales_layout) = GlobalLayoutLaunch::from_quantized_handle(
214                    &data,
215                    &scale,
216                    &shape,
217                    problem,
218                    scheme,
219                    vector_size,
220                    config,
221                );
222                let data_view =
223                    ViewArg::new_tensor::<GlobalLayout>(data.into_tensor_arg(), data_layout);
224                let scales_view = ViewArg::new_tensor::<GlobalScaleLayout>(
225                    scale.into_tensor_arg(),
226                    scales_layout,
227                );
228                ViewArg::new_quantized(data_view, scales_view, scheme)
229            }
230        };
231        let batch_layout = |handle: &InputBinding<R>| match handle {
232            InputBinding::Normal(handle, _dtype) => {
233                let layout = BatchLayoutLaunch::from_handle(handle, problem);
234                VirtualLayoutLaunch::new::<BatchLayout>(layout)
235            }
236            InputBinding::Quantized { .. } => {
237                VirtualLayoutLaunch::new::<NoopLayout>(NoopLayoutLaunch::new())
238            }
239        };
240
241        TensorInputsLaunch::new(
242            batch_layout(&lhs),
243            view(lhs, blueprint.lhs_global_layout_config(), vector_sizes.lhs),
244            batch_layout(&rhs),
245            view(rhs, blueprint.rhs_global_layout_config(), vector_sizes.rhs),
246            ComptimeOptionArgs::None,
247            ComptimeOptionArgs::None,
248        )
249    }
250}
251
252#[derive(CubeType, CubeLaunch, Clone)]
253#[expand(derive(Clone))]
254pub struct TensorOutput<EG: CubePrimitive> {
255    view: ViewMut<'static, EG, BatchedCoords>,
256    batch: VirtualLayout<Coords1d, Coords1d>,
257}
258
259impl<EG: CubePrimitive, A: BatchMatmulRoutine<()>> ConcreteOutputFactory<A> for TensorOutput<EG> {
260    fn create<R: Runtime>(
261        out: TensorBinding<R>,
262        blueprint: &A::Blueprint,
263        problem: &MatmulProblem,
264        vector_sizes: &MatmulVectorSizes,
265        _dtypes: &MatmulElems,
266    ) -> Self::RuntimeArg<R> {
267        let layout = GlobalLayoutLaunch::from_handle(
268            &out,
269            vector_sizes.out,
270            blueprint.out_global_layout_config(),
271        );
272        let batch = BatchLayoutLaunch::from_handle(&out, problem);
273        let view = ViewArg::new_tensor::<GlobalLayout>(out.into_tensor_arg(), layout);
274        TensorOutputLaunch::new(view, VirtualLayoutLaunch::new::<BatchLayout>(batch))
275    }
276}
277
278#[cube]
279impl<Config: RuntimeConfig> MatmulArgs for TensorArgs<Config> {
280    type Output<EO: CubePrimitive> = TensorOutput<EO>;
281    type Input<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive> =
282        TensorInputs<Lhs, Rhs, EO>;
283    type Config = Config;
284    type State<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive> =
285        (TensorInputs<Lhs, Rhs, EO>, TensorOutput<EO>, Config);
286
287    fn init_state<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
288        input: &Self::Input<Lhs, Rhs, EO>,
289        output: &mut Self::Output<EO>,
290        config: Self::Config,
291        #[comptime] _lhs_layout_config: GlobalLayoutConfig,
292        #[comptime] _rhs_layout_config: GlobalLayoutConfig,
293        #[comptime] _out_layout_config: GlobalLayoutConfig,
294    ) -> Self::State<Lhs, Rhs, EO> {
295        (input.clone(), output.clone(), config)
296    }
297
298    fn view_lhs<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
299        state: &Self::State<Lhs, Rhs, EO>,
300    ) -> View<'_, Lhs, BatchedCoords> {
301        state.0.lhs
302    }
303
304    fn batch_lhs<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
305        state: &Self::State<Lhs, Rhs, EO>,
306        batch: usize,
307    ) -> usize {
308        state.0.lhs_batch.to_source_pos(batch)
309    }
310
311    fn view_rhs<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
312        state: &Self::State<Lhs, Rhs, EO>,
313    ) -> View<'_, Rhs, BatchedCoords> {
314        state.0.rhs
315    }
316
317    fn batch_rhs<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
318        state: &Self::State<Lhs, Rhs, EO>,
319        batch: usize,
320    ) -> usize {
321        state.0.rhs_batch.to_source_pos(batch)
322    }
323
324    fn view_acc<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
325        state: &Self::State<Lhs, Rhs, EO>,
326    ) -> ComptimeOption<View<'_, EO, BatchedCoords>> {
327        state.0.acc.map(|view| view) // Lifetime coercion hack
328    }
329
330    fn batch_acc<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
331        state: &Self::State<Lhs, Rhs, EO>,
332        batch: usize,
333    ) -> usize {
334        #[comptime]
335        match &state.0.acc_batch {
336            ComptimeOption::Some(layout) => layout.to_source_pos(batch),
337            ComptimeOption::None => batch,
338        }
339    }
340
341    fn view_out<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
342        state: &Self::State<Lhs, Rhs, EO>,
343    ) -> ViewMut<'_, EO, BatchedCoords> {
344        state.1.view
345    }
346
347    fn batch_out<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
348        state: &Self::State<Lhs, Rhs, EO>,
349        batch: usize,
350    ) -> usize {
351        state.1.batch.to_source_pos(batch)
352    }
353
354    fn runtime_config<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
355        state: &Self::State<Lhs, Rhs, EO>,
356    ) -> Self::Config {
357        state.2.clone()
358    }
359}
360
361#[derive(Clone)]
362/// Type implementing [MatmulArgs] where all inputs and the output are materialized tensor maps.
363///
364/// Other types might implement [MatmulArgs] for fused matrix multiplication kernels.
365pub struct TensorMapArgs<Config: RuntimeConfig = ()> {
366    _config: PhantomData<Config>,
367}
368
369#[derive(CubeLaunch, CubeType, Clone)]
370#[expand(derive(Clone))]
371/// Input representation for [TensorArgs] implementing [MatmulArgs].
372pub struct TensorMapInputs<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive> {
373    /// The lhs tensor.
374    pub lhs: View<'static, Lhs, BatchedCoords>,
375    /// The rhs tensor.
376    pub rhs: View<'static, Rhs, BatchedCoords>,
377    /// The accumulator
378    pub acc: ComptimeOption<View<'static, EO, BatchedCoords>>,
379    /// The accumulator batch layout
380    pub acc_batch: ComptimeOption<VirtualLayout<Coords1d, Coords1d>>,
381}
382
383impl<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive, A: BatchMatmulRoutine<()>>
384    ConcreteInputsFactory<A> for TensorMapInputs<Lhs, Rhs, EO>
385{
386    fn create<R: Runtime>(
387        lhs_handle: InputBinding<R>,
388        rhs_handle: InputBinding<R>,
389        blueprint: &A::Blueprint,
390        problem: &MatmulProblem,
391        _vector_sizes: &MatmulVectorSizes,
392        dtypes: &MatmulElems,
393    ) -> Self::RuntimeArg<R> {
394        let lhs = lhs_handle.into_data();
395        let rhs = rhs_handle.into_data();
396
397        let tiling_scheme = blueprint.tiling_scheme();
398        let stage_m = tiling_scheme.elements_per_stage_along_m() as usize;
399        let stage_n = tiling_scheme.elements_per_stage_along_n() as usize;
400        let stage_k = tiling_scheme.elements_per_stage_along_k() as usize;
401        let (tile_m, tile_n, tile_k) = (
402            tiling_scheme.tile_size.m as usize,
403            tiling_scheme.tile_size.n as usize,
404            tiling_scheme.tile_size.k as usize,
405        );
406
407        // Boxes in logical (rows, cols); `tma_operand` puts them in descriptor order. Without
408        // swizzle, bank conflicts cap the box at a single-tile-wide strip along the contiguous
409        // axis; swizzled loads the full stage per box.
410        let box_lhs = match blueprint.swizzle_modes().lhs {
411            SwizzleMode::None => match problem.lhs_layout {
412                MatrixLayout::RowMajor => (stage_m, tile_k),
413                MatrixLayout::ColMajor => (tile_m, stage_k),
414            },
415            _ => (stage_m, stage_k),
416        };
417        let box_rhs = match blueprint.swizzle_modes().rhs {
418            SwizzleMode::None => match problem.rhs_layout {
419                MatrixLayout::RowMajor => (stage_k, tile_n),
420                MatrixLayout::ColMajor => (tile_k, stage_n),
421            },
422            _ => (stage_k, stage_n),
423        };
424
425        // Logical (batches, rows, cols), read before `tma_operand` consumes the bindings.
426        let dims = |binding: &TensorBinding<R>, batches: &[usize]| {
427            let rank = binding.shape.len();
428            (
429                batches.iter().product::<usize>(),
430                binding.shape[rank - 2] as u32,
431                binding.shape[rank - 1] as u32,
432            )
433        };
434        let lhs_dims = dims(&lhs, &problem.lhs_batches);
435        let rhs_dims = dims(&rhs, &problem.rhs_batches);
436
437        let (lhs, lhs_transposed) = tma_operand(
438            lhs,
439            lhs_dims.0,
440            problem.lhs_layout,
441            box_lhs,
442            dtypes.lhs_stage,
443            blueprint.swizzle_modes().lhs.into(),
444        );
445        let (rhs, rhs_transposed) = tma_operand(
446            rhs,
447            rhs_dims.0,
448            problem.rhs_layout,
449            box_rhs,
450            dtypes.rhs_stage,
451            blueprint.swizzle_modes().rhs.into(),
452        );
453
454        let view = |buffer, shape: (usize, u32, u32), transposed| {
455            let layout = SimpleTmaGlobalLayoutLaunch::new(transposed, shape);
456            ViewArg::new_tensor_map_tiled::<SimpleTmaGlobalLayout>(buffer, layout)
457        };
458
459        TensorMapInputsLaunch::new(
460            view(lhs, lhs_dims, lhs_transposed),
461            view(rhs, rhs_dims, rhs_transposed),
462            ComptimeOptionArgs::None,
463            ComptimeOptionArgs::None,
464        )
465    }
466}
467
468#[cube]
469impl<Config: RuntimeConfig> MatmulArgs for TensorMapArgs<Config> {
470    type Input<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive> =
471        TensorMapInputs<Lhs, Rhs, EO>;
472    type Output<EO: CubePrimitive> = TensorOutput<EO>;
473    type Config = Config;
474    type State<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive> =
475        (TensorMapInputs<Lhs, Rhs, EO>, TensorOutput<EO>, Config);
476
477    fn init_state<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
478        input: &Self::Input<Lhs, Rhs, EO>,
479        output: &mut Self::Output<EO>,
480        config: Self::Config,
481        #[comptime] _lhs_layout_config: GlobalLayoutConfig,
482        #[comptime] _rhs_layout_config: GlobalLayoutConfig,
483        #[comptime] _out_layout_config: GlobalLayoutConfig,
484    ) -> Self::State<Lhs, Rhs, EO> {
485        (input.clone(), output.clone(), config)
486    }
487
488    fn view_lhs<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
489        state: &Self::State<Lhs, Rhs, EO>,
490    ) -> View<'_, Lhs, BatchedCoords> {
491        state.0.lhs
492    }
493
494    fn batch_lhs<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
495        _state: &Self::State<Lhs, Rhs, EO>,
496        batch: usize,
497    ) -> usize {
498        batch
499    }
500
501    fn view_rhs<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
502        state: &Self::State<Lhs, Rhs, EO>,
503    ) -> View<'_, Rhs, BatchedCoords> {
504        state.0.rhs
505    }
506
507    fn batch_rhs<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
508        _state: &Self::State<Lhs, Rhs, EO>,
509        batch: usize,
510    ) -> usize {
511        batch
512    }
513
514    fn view_acc<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
515        state: &Self::State<Lhs, Rhs, EO>,
516    ) -> ComptimeOption<View<'_, EO, BatchedCoords>> {
517        state.0.acc.map(|view| view) // Lifetime coercion hack
518    }
519
520    fn batch_acc<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
521        state: &Self::State<Lhs, Rhs, EO>,
522        batch: usize,
523    ) -> usize {
524        #[comptime]
525        #[comptime]
526        match &state.0.acc_batch {
527            ComptimeOption::Some(layout) => layout.to_source_pos(batch),
528            ComptimeOption::None => batch,
529        }
530    }
531
532    fn view_out<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
533        state: &Self::State<Lhs, Rhs, EO>,
534    ) -> ViewMut<'_, EO, BatchedCoords> {
535        state.1.view
536    }
537
538    fn batch_out<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
539        state: &Self::State<Lhs, Rhs, EO>,
540        batch: usize,
541    ) -> usize {
542        state.1.batch.to_source_pos(batch)
543    }
544
545    fn runtime_config<Lhs: CubePrimitive, Rhs: CubePrimitive, EO: CubePrimitive>(
546        state: &Self::State<Lhs, Rhs, EO>,
547    ) -> Self::Config {
548        state.2.clone()
549    }
550}