1use ruda_kernel::dsl as kernel_dsl;
2use ruda_kernel::dsl::Runtime;
3use ruda_kernel::dsl::client::ComputeClient;
4use ruda_kernel::dsl::prelude::*;
5use ruda_kernel::library::tensor::launch::ViewArg;
6use ruda_kernel::library::tensor::layout::VirtualLayoutLaunch;
7use ruda_kernel::library::tensor::layout::chain::Chain;
8use ruda_kernel::library::tensor::layout::chain::ChainLaunch;
9use ruda_kernel::dsl::zspace::shape;
10use ruda_kernel::dsl::zspace::strides;
11use rublas::kernel_ir::{
12 components::global::memory::{GlobalLayoutConfig, NoopLayout, NoopLayoutLaunch},
13 definition::{Blueprint, MatmulElems, TilingBlueprint},
14 launch::*,
15 routines::Routine,
16};
17use ruda_kernel::tiling::launch::tma::remap_storage_for_tma;
18use ruda_kernel::tiling::{InputBinding, MatrixLayout, stage::SwizzleMode};
19use enumset::EnumSet;
20
21use crate::convolution::components::{
22 ConvolutionParams, ConvolutionProblem,
23 global::{
24 args::{RuntimeArgs, RuntimeArgsLaunch},
25 layout::{
26 BiasLayout, Im2colLayout, Im2colLayoutLaunch, NhwcCheck, NhwcLayout, NhwcLayoutLaunch,
27 OutLayout, OutLayoutLaunch, TmaIm2colLayout, TmaIm2colLayoutLaunch, WeightLayout,
28 WeightLayoutLaunch,
29 },
30 },
31};
32
33pub trait ConcreteArgs<A: Routine<RuntimeArgs>>:
34 MatmulArgs<
35 Input<Vector<Lhs, LhsSize>, Vector<Rhs, RhsSize>, Vector<Acc, AccSize>>: ConcreteInputsFactory<A>,
36 Output<Vector<Acc, AccSize>>: ConcreteOutputFactory<A>,
37 Config = RuntimeArgs,
38 >
39{
40 fn adjust_problem<R: Runtime>(
41 client: &ComputeClient<R>,
42 problem: ConvolutionProblem,
43 blueprint: &A::Blueprint,
44 dtypes: &MatmulElems,
45 ) -> ConvolutionProblem;
46}
47
48impl<A: Routine<RuntimeArgs>> ConcreteArgs<A> for TensorArgs<RuntimeArgs> {
49 fn adjust_problem<R: Runtime>(
50 client: &ComputeClient<R>,
51 mut problem: ConvolutionProblem,
52 _blueprint: &A::Blueprint,
53 dtypes: &MatmulElems,
54 ) -> ConvolutionProblem {
55 let load_width = client.properties().hardware.load_width;
56 let channel_align = load_width as usize / dtypes.lhs_global.size_bits();
57 let padded_channels = problem.channels.next_multiple_of(channel_align);
58 let shape_k = problem.kernel_size.iter().product::<u32>() as usize * padded_channels;
59
60 problem.k = shape_k;
61 problem.padded_channels = padded_channels;
62
63 problem
64 }
65}
66
67impl<A: Routine<RuntimeArgs, Blueprint = TilingBlueprint>> ConcreteArgs<A>
68 for TensorMapArgs<RuntimeArgs>
69{
70 fn adjust_problem<R: Runtime>(
71 _client: &ComputeClient<R>,
72 mut problem: ConvolutionProblem,
73 blueprint: &TilingBlueprint,
74 _dtypes: &MatmulElems,
75 ) -> ConvolutionProblem {
76 let channel_align = match blueprint.swizzle_modes.lhs {
77 SwizzleMode::None => blueprint.tiling_scheme.tile_size.k() as usize,
78 _ => blueprint.tiling_scheme.elements_per_stage_along_k() as usize,
79 };
80 let padded_channels = problem.channels.next_multiple_of(channel_align);
81 let shape_k = problem.kernel_size.iter().product::<u32>() as usize * padded_channels;
82
83 problem.k = shape_k;
84 problem.padded_channels = padded_channels;
85
86 problem
87 }
88}
89
90pub trait ConcreteInputsFactory<A: Routine<RuntimeArgs>>: LaunchArg {
93 #[allow(clippy::too_many_arguments)]
94 fn create<R: Runtime>(
95 lhs: InputBinding<R>,
96 rhs: InputBinding<R>,
97 bias: Option<InputBinding<R>>,
98 blueprint: &A::Blueprint,
99 problem: &ConvolutionProblem,
100 dtypes: &MatmulElems,
101 ) -> (Self::RuntimeArg<R>, RuntimeArgsLaunch<R>);
102}
103
104pub trait ConcreteOutputFactory<A: Routine<RuntimeArgs>>: LaunchArg {
107 fn create<R: Runtime>(
108 out: TensorBinding<R>,
109 blueprint: &A::Blueprint,
110 problem: &ConvolutionProblem,
111 dtypes: &MatmulElems,
112 ) -> Self::RuntimeArg<R>;
113}
114
115impl<Lhs: RudaPrimitive, Rhs: RudaPrimitive, EO: RudaPrimitive, A: Routine<RuntimeArgs>>
116 ConcreteInputsFactory<A> for TensorInputs<Lhs, Rhs, EO>
117{
118 fn create<R: Runtime>(
119 lhs: InputBinding<R>,
120 rhs: InputBinding<R>,
121 bias: Option<InputBinding<R>>,
122 blueprint: &A::Blueprint,
123 problem: &ConvolutionProblem,
124 _dtypes: &MatmulElems,
125 ) -> (Self::RuntimeArg<R>, RuntimeArgsLaunch<R>) {
126 type LhsLayout = Chain<NhwcLayout, Im2colLayout>;
127 type RhsLayout = Chain<NhwcLayout, WeightLayout>;
128
129 let padded_channels = problem.padded_channels as u32;
130 let conv_params = ConvolutionParams::from_problem(problem);
131
132 let layout_lhs = Im2colLayoutLaunch::from_args(
133 problem,
134 conv_params,
135 blueprint.lhs_global_layout_config(),
136 );
137 let layout_rhs =
138 WeightLayoutLaunch::from_args(problem, blueprint.rhs_global_layout_config());
139
140 let layout_lhs = {
141 let mut checks = EnumSet::empty();
142 if problem.should_check_spatial_bounds() {
143 checks.insert(NhwcCheck::Spatial);
144 }
145 if problem.should_check_channel() {
146 checks.insert(NhwcCheck::Channel);
147 }
148 let global = NhwcLayoutLaunch::checked(checks);
149 ChainLaunch::new(global, layout_lhs)
150 };
151 let layout_rhs = {
152 let mut checks = EnumSet::empty();
153 if problem.should_check_channel() {
154 checks.insert(NhwcCheck::Channel);
155 }
156 let global = NhwcLayoutLaunch::checked(checks);
157 ChainLaunch::new(global, layout_rhs)
158 };
159
160 let inputs = TensorInputsLaunch::new(
161 VirtualLayoutLaunch::new::<NoopLayout>(NoopLayoutLaunch::new()),
162 ViewArg::new_tensor::<LhsLayout>(lhs.into_data().into_tensor_arg(), layout_lhs),
163 VirtualLayoutLaunch::new::<NoopLayout>(NoopLayoutLaunch::new()),
164 ViewArg::new_tensor::<RhsLayout>(rhs.into_data().into_tensor_arg(), layout_rhs),
165 bias.as_ref()
166 .map(|_| VirtualLayoutLaunch::new::<NoopLayout>(NoopLayoutLaunch::new()))
167 .into(),
168 bias.map(|bias| {
169 ViewArg::new_tensor::<BiasLayout>(bias.into_data().into_tensor_arg(), ())
170 })
171 .into(),
172 );
173
174 let runtime_args = RuntimeArgsLaunch::new(
175 problem.k as u32,
176 problem.channels as u32,
177 padded_channels,
178 conv_params.operation,
179 );
180
181 (inputs, runtime_args)
182 }
183}
184
185impl<EG: RudaPrimitive, A: Routine<RuntimeArgs>> ConcreteOutputFactory<A> for TensorOutput<EG> {
186 fn create<R: Runtime>(
187 out: TensorBinding<R>,
188 blueprint: &A::Blueprint,
189 problem: &ConvolutionProblem,
190 _dtypes: &MatmulElems,
191 ) -> Self::RuntimeArg<R> {
192 type Layout = Chain<NhwcLayout, OutLayout>;
193
194 let global = NhwcLayoutLaunch::unchecked();
195 let layout = OutLayoutLaunch::from_args(problem, blueprint.out_global_layout_config());
196 let layout = ChainLaunch::new(global, layout);
197 let view = ViewArg::new_tensor::<Layout>(out.into_tensor_arg(), layout);
198 let batch = VirtualLayoutLaunch::new::<NoopLayout>(NoopLayoutLaunch::new());
199 TensorOutputLaunch::new(view, batch)
200 }
201}
202
203impl<
204 Lhs: RudaPrimitive,
205 Rhs: RudaPrimitive,
206 EO: RudaPrimitive,
207 A: Routine<RuntimeArgs, Blueprint = TilingBlueprint>,
208> ConcreteInputsFactory<A> for TensorMapInputs<Lhs, Rhs, EO>
209{
210 fn create<R: Runtime>(
211 lhs: InputBinding<R>,
212 rhs: InputBinding<R>,
213 bias: Option<InputBinding<R>>,
214 blueprint: &TilingBlueprint,
215 problem: &ConvolutionProblem,
216 dtypes: &MatmulElems,
217 ) -> (Self::RuntimeArg<R>, RuntimeArgsLaunch<R>) {
218 let tiling_scheme = blueprint.tiling_scheme;
219 let stage_m = tiling_scheme.elements_per_stage_along_m();
220 let stage_n = tiling_scheme.elements_per_stage_along_n();
221
222 let tile_size_k = match blueprint.swizzle_modes.lhs {
223 SwizzleMode::None => tiling_scheme.tile_size.k,
224 _ => tiling_scheme.elements_per_stage_along_k(),
225 };
226
227 let mut stage_size_rhs = shape![1; problem.dimensionality.num_dims()];
228 stage_size_rhs.insert(0, stage_n as usize);
229 stage_size_rhs.push(tile_size_k as usize);
230
231 let lhs_elem = remap_storage_for_tma(dtypes.lhs_stage);
232
233 let mut elem_stride = strides![1; 2 + problem.stride.len()];
234
235 for (i, stride) in problem.stride.iter().enumerate() {
236 elem_stride[i + 1] = *stride as usize;
237 }
238
239 let lhs = TensorMapArg::new(
240 Im2colArgs {
241 pixel_box_lower_corner: calculate_lower_corner(&problem.padding),
242 pixel_box_upper_corner: calculate_upper_corner(
243 &problem.padding,
244 &problem.kernel_size,
245 &problem.dilation,
246 ),
247 channels_per_pixel: tile_size_k,
248 pixels_per_column: stage_m,
249 },
250 lhs.clone().into_data().into_tensor_arg(),
251 lhs_elem,
252 )
253 .with_elem_stride(elem_stride)
254 .with_swizzle(blueprint.swizzle_modes.lhs.into());
255
256 let rhs = TensorMapArg::new(
257 TiledArgs {
258 tile_size: stage_size_rhs,
259 },
260 rhs.clone().into_data().into_tensor_arg(),
261 dtypes.rhs_global,
262 )
263 .with_swizzle(blueprint.swizzle_modes.rhs.into());
264
265 let padded_channels = problem.padded_channels as u32;
266 let shape_k = problem.k as u32;
267
268 let stages_lhs = A::num_stages().lhs;
272 let stages_size_k = blueprint.tiling_scheme.elements_per_stage_along_k() * stages_lhs;
273 let check_kernel = !shape_k.is_multiple_of(stages_size_k);
274 let lhs_layout = TmaIm2colLayoutLaunch::from_args(problem, check_kernel);
275 let rhs_layout = WeightLayoutLaunch::from_args(
276 problem,
277 GlobalLayoutConfig {
278 check_row_bounds: false,
279 check_col_bounds: false,
280 matrix_layout: MatrixLayout::ColMajor,
281 },
282 );
283
284 let bias = bias
285 .map(|bias| ViewArg::new_tensor::<BiasLayout>(bias.into_data().into_tensor_arg(), ()));
286
287 let inputs = TensorMapInputsLaunch::new(
288 ViewArg::new_tensor_map_im2col::<TmaIm2colLayout, _, _>(lhs, lhs_layout),
289 ViewArg::new_tensor_map_tiled::<WeightLayout>(rhs, rhs_layout),
290 bias.into(),
291 ComptimeOptionArgs::Some(VirtualLayoutLaunch::new::<NoopLayout>(
292 NoopLayoutLaunch::new(),
293 )),
294 );
295
296 let runtime_args = RuntimeArgsLaunch::new(
297 shape_k,
298 problem.channels as u32,
299 padded_channels,
300 problem.operation,
301 );
302
303 (inputs, runtime_args)
304 }
305}
306
307fn calculate_lower_corner(padding: &[i32]) -> Vec<i32> {
308 padding.iter().map(|padding| -*padding).collect()
309}
310
311fn calculate_upper_corner(padding: &[i32], kernel_size: &[u32], dilation: &[u32]) -> Vec<i32> {
312 padding
313 .iter()
314 .zip(kernel_size)
315 .zip(dilation)
316 .map(|((padding, kernel_size), dilation)| {
317 *padding - (*kernel_size - 1) as i32 * *dilation as i32
318 })
319 .collect()
320}