rudnn/convolution/components/global/layout/
tma_im2col.rs1use ruda_kernel::dsl as kernel_dsl;
2use ruda_kernel::dsl::prelude::*;
3use ruda_kernel::library::FastDivmod;
4use ruda_kernel::library::tensor::layout::CoordsDyn;
5use ruda_kernel::library::tensor::layout::Layout;
6use ruda_kernel::library::tensor::layout::LayoutExpand;
7use rublas::kernel_ir::launch::BatchedCoords;
8
9use crate::convolution::components::{
10 ConvolutionOperation, ConvolutionParams, ConvolutionProblem, global::layout::NhwcCoords,
11};
12
13#[derive(RudaType, RudaLaunch)]
15pub struct TmaIm2colLayout {
16 shape_out: Sequence<FastDivmod<u32>>,
17 padded_channels: FastDivmod<u32>,
18 rows: u32,
19 cols: u32,
20 #[ruda(comptime)]
21 params: ConvolutionParams,
22 #[ruda(comptime)]
23 check_kernel: bool,
24}
25
26#[ruda]
27impl TmaIm2colLayout {
28 pub fn new(
29 shape_out: Sequence<FastDivmod<u32>>,
30 padded_channels: FastDivmod<u32>,
31 rows: u32,
32 cols: u32,
33 #[comptime] params: ConvolutionParams,
34 #[comptime] check_kernel: bool,
35 ) -> Self {
36 TmaIm2colLayout {
37 shape_out,
38 padded_channels,
39 params,
40 check_kernel,
41 rows,
42 cols,
43 }
44 }
45}
46
47#[ruda]
48impl Layout for TmaIm2colLayout {
49 type Coordinates = BatchedCoords;
50 type SourceCoordinates = (NhwcCoords, CoordsDyn);
51
52 fn to_source_pos(&self, pos: Self::Coordinates) -> Self::SourceCoordinates {
53 let (_, m, k) = pos;
54 let params = self.params.comptime();
55
56 let (n_offs, spatial_offsets) = div_mod_seq(m, &self.shape_out);
57 let spatial_dims = spatial_offsets.len();
58
59 let mut in_offs = Sequence::<i32>::new();
60
61 #[unroll]
62 for dim in 0..spatial_dims {
63 let stride = params.stride[dim] as i32;
64 let pad = params.padding[dim];
65 let out_pos = spatial_offsets[dim] as i32;
66 let offs = match params.operation {
67 ConvolutionOperation::Forward | ConvolutionOperation::BackwardWeight => {
68 out_pos * stride - pad
69 }
70 ConvolutionOperation::ForwardTransposed | ConvolutionOperation::BackwardData => {
71 let ksize = params.kernel_size[dim] as i32;
72 (out_pos + pad - ((ksize - 1) * params.dilation[dim] as i32)) / stride
73 }
74 };
75 in_offs.push(offs);
76 }
77
78 let (mut k_idx, channel_start) = self.padded_channels.div_mod(k);
79
80 let mut pos = NhwcCoords {
81 batch: n_offs,
82 spatial: in_offs,
83 channel: channel_start,
84 };
85
86 let mut k_offs = Sequence::new();
87 let k_rank = params.dimensionality.num_dims();
88
89 #[unroll]
90 for i in 0..k_rank {
91 let dim = k_rank - i - 1;
92 let k_size = params.kernel_size[dim];
93 let k_pos = k_idx % k_size;
94
95 let k_pos = match params.operation {
96 ConvolutionOperation::Forward | ConvolutionOperation::BackwardWeight => k_pos,
97 ConvolutionOperation::ForwardTransposed | ConvolutionOperation::BackwardData => {
98 k_size - k_pos - 1
101 }
102 };
103 k_offs.push(k_pos * params.dilation[dim]);
104 k_idx /= k_size;
105 }
106
107 if self.check_kernel.comptime() {
108 let kernel_mask = (k_idx > 0) as u32 * 0x7FFFFF00u32;
114 pos.channel = pos.channel.max(kernel_mask);
115 }
116
117 (pos, k_offs.rev())
118 }
119
120 fn is_in_bounds(&self, _pos: Self::Coordinates) -> bool {
121 true.runtime()
122 }
123
124 fn shape(&self) -> Self::Coordinates {
125 (1, self.rows, self.cols)
126 }
127
128 fn to_source_pos_checked(&self, pos: Self::Coordinates) -> (Self::SourceCoordinates, bool) {
129 (self.to_source_pos(pos), self.is_in_bounds(pos))
130 }
131}
132
133#[ruda]
136pub(crate) fn div_mod_seq(pos: u32, shape: &Sequence<FastDivmod<u32>>) -> (u32, Sequence<u32>) {
137 let rank = shape.len().comptime();
138 let mut offs = pos;
139 let mut out = Sequence::new();
140
141 #[unroll]
142 for i in 0..rank {
143 let dim = rank - i - 1;
144 let (rem, offs_local) = shape[dim].div_mod(offs);
145 out.push(offs_local);
146 offs = rem;
147 }
148
149 (offs, out.rev())
150}
151
152impl<R: Runtime> TmaIm2colLayoutLaunch<R> {
153 pub fn from_args(problem: &ConvolutionProblem, check_kernel: bool) -> Self {
154 let shape_out = problem.out_shape.iter().map(|it| *it as u32).collect();
155
156 let padded_channels = problem.padded_channels as u32;
157 let params = ConvolutionParams::from_problem(problem);
158
159 match problem.operation {
160 ConvolutionOperation::Forward
161 | ConvolutionOperation::ForwardTransposed
162 | ConvolutionOperation::BackwardData => {
163 Self::from_args_lhs(problem, shape_out, padded_channels, params, check_kernel)
164 }
165 ConvolutionOperation::BackwardWeight => {
166 Self::from_args_rhs(problem, shape_out, padded_channels, params, check_kernel)
167 }
168 }
169 }
170
171 fn from_args_lhs(
172 problem: &ConvolutionProblem,
173 shape_out: SequenceArg<R, FastDivmod<u32>>,
174 padded_channels: u32,
175 params: ConvolutionParams,
176 check_kernel: bool,
177 ) -> Self {
178 let shape_m = problem.m as u32;
179 let shape_k = problem.k as u32;
180
181 TmaIm2colLayoutLaunch::new(
182 shape_out,
183 padded_channels,
184 shape_m,
185 shape_k,
186 params,
187 check_kernel,
188 )
189 }
190
191 fn from_args_rhs(
192 problem: &ConvolutionProblem,
193 shape_out: SequenceArg<R, FastDivmod<u32>>,
194 padded_channels: u32,
195 params: ConvolutionParams,
196 check_kernel: bool,
197 ) -> Self {
198 let shape_k = problem.k as u32;
199 let shape_n = problem.n as u32;
200
201 TmaIm2colLayoutLaunch::new(
202 shape_out,
203 padded_channels,
204 shape_k,
205 shape_n,
206 params,
207 check_kernel,
208 )
209 }
210}