1#![allow(non_snake_case)]
18
19use core::ops::{BitAnd, BitOr};
20
21use teeny_core::dtype::Num;
22use teeny_macros::kernel;
23use teeny_triton::triton::{
24 types::{AddOffsets, Comparison, Tensor},
25 *,
26};
27
28#[kernel]
32pub fn replication_pad3d_forward<
33 T: Triton,
34 D: Num,
35 const PD1: i32,
36 const PD2: i32,
37 const PH1: i32,
38 const PH2: i32,
39 const PW1: i32,
40 const PW2: i32,
41 const BLOCK_OW: i32,
42>(
43 input_ptr: T::Pointer<D>,
44 output_ptr: T::Pointer<D>,
45 _B: i32,
46 C: i32,
47 Dv: i32,
48 H: i32,
49 W: i32,
50 OD: i32,
51 OH: i32,
52 OW: i32,
53) where
54 T::I32Tensor: Tensor<i32, 1>,
55 T::I32Tensor: Comparison<i32, BoolTensor = T::BoolTensor>,
56 T::BoolTensor: BitAnd<Output = T::BoolTensor>,
57 T::BoolTensor: BitOr<Output = T::BoolTensor>,
58 T::Pointer<D>: AddOffsets<i32, 1, T::I32Tensor, Output = T::Tensor<T::Pointer<D>>>,
59{
60 let pid = T::program_id(Axis::X);
61 let num_ow_tiles = T::cdiv(OW, BLOCK_OW);
62
63 let ow_tile = pid % num_ow_tiles;
64 let rest = pid / num_ow_tiles;
65 let oh = rest % OH;
66 let rest2 = rest / OH;
67 let od = rest2 % OD;
68 let bco = rest2 / OD;
69 let c = bco % C;
70 let b = bco / C;
71
72 let ow_start = ow_tile * BLOCK_OW;
73 let ow_range = T::arange(0, BLOCK_OW) + ow_start;
74 let ow_mask = ow_range.lt(OW);
75
76 let id_raw = od - PD1;
77 let id = if id_raw < 0 {
78 0
79 } else if id_raw >= Dv {
80 Dv - 1
81 } else {
82 id_raw
83 };
84
85 let ih_raw = oh - PH1;
86 let ih = if ih_raw < 0 {
87 0
88 } else if ih_raw >= H {
89 H - 1
90 } else {
91 ih_raw
92 };
93
94 let in_bc_base = ((b * C + c) * Dv + id) * H * W + ih * W;
95 let out_bc_base = (((b * C + c) * OD + od) * OH + oh) * OW;
96
97 let iw_raw = ow_range - PW1;
98 let cond_left = iw_raw.lt(0);
99 let cond_right = iw_raw.ge(W);
100 let in_bounds = iw_raw.ge(0) & iw_raw.lt(W);
101
102 #[allow(clippy::erasing_op)]
103 let zero_iw = iw_raw * 0;
104 #[allow(clippy::erasing_op)]
105 let wm1_iw = iw_raw * 0 + (W - 1);
106
107 let zeros = T::zeros::<D>(&[BLOCK_OW]);
108 let val_center = T::load(
109 input_ptr.add_offsets(iw_raw + in_bc_base),
110 Some(ow_mask & in_bounds),
111 Some(zeros),
112 &[],
113 None,
114 None,
115 None,
116 false,
117 );
118 let val_left = T::load(
119 input_ptr.add_offsets(zero_iw + in_bc_base),
120 Some(ow_mask & cond_left),
121 Some(zeros),
122 &[],
123 None,
124 None,
125 None,
126 false,
127 );
128 let val_right = T::load(
129 input_ptr.add_offsets(wm1_iw + in_bc_base),
130 Some(ow_mask & cond_right),
131 Some(zeros),
132 &[],
133 None,
134 None,
135 None,
136 false,
137 );
138
139 let result = T::where_(
140 cond_left,
141 val_left,
142 T::where_(cond_right, val_right, val_center),
143 );
144
145 let out_offsets = ow_range + out_bc_base;
146 T::store(
147 output_ptr.add_offsets(out_offsets),
148 result,
149 Some(ow_mask),
150 &[],
151 None,
152 None,
153 );
154}
155
156#[kernel]
158pub fn replication_pad3d_backward<
159 T: Triton,
160 D: Num,
161 const PD1: i32,
162 const PD2: i32,
163 const PH1: i32,
164 const PH2: i32,
165 const PW1: i32,
166 const PW2: i32,
167 const BLOCK_OW: i32,
168>(
169 dy_ptr: T::Pointer<D>,
170 dx_ptr: T::Pointer<D>,
171 _B: i32,
172 C: i32,
173 Dv: i32,
174 H: i32,
175 W: i32,
176 OD: i32,
177 OH: i32,
178 OW: i32,
179) where
180 T::I32Tensor: Tensor<i32, 1>,
181 T::I32Tensor: Comparison<i32, BoolTensor = T::BoolTensor>,
182 T::BoolTensor: BitAnd<Output = T::BoolTensor>,
183 T::BoolTensor: BitOr<Output = T::BoolTensor>,
184 T::Pointer<D>: AddOffsets<i32, 1, T::I32Tensor, Output = T::Tensor<T::Pointer<D>>>,
185{
186 let pid = T::program_id(Axis::X);
187 let num_ow_tiles = T::cdiv(OW, BLOCK_OW);
188
189 let ow_tile = pid % num_ow_tiles;
190 let rest = pid / num_ow_tiles;
191 let oh = rest % OH;
192 let rest2 = rest / OH;
193 let od = rest2 % OD;
194 let bco = rest2 / OD;
195 let c = bco % C;
196 let b = bco / C;
197
198 let ow_start = ow_tile * BLOCK_OW;
199 let ow_range = T::arange(0, BLOCK_OW) + ow_start;
200 let ow_mask = ow_range.lt(OW);
201
202 let id_raw = od - PD1;
203 let id = if id_raw < 0 {
204 0
205 } else if id_raw >= Dv {
206 Dv - 1
207 } else {
208 id_raw
209 };
210
211 let ih_raw = oh - PH1;
212 let ih = if ih_raw < 0 {
213 0
214 } else if ih_raw >= H {
215 H - 1
216 } else {
217 ih_raw
218 };
219
220 let dy_bc_base = (((b * C + c) * OD + od) * OH + oh) * OW;
221 let dx_bc_base = ((b * C + c) * Dv + id) * H * W + ih * W;
222
223 let dy_offsets = ow_range + dy_bc_base;
224 let dy_tile = T::load(
225 dy_ptr.add_offsets(dy_offsets),
226 Some(ow_mask),
227 Some(T::zeros::<D>(&[BLOCK_OW])),
228 &[],
229 None,
230 None,
231 None,
232 false,
233 );
234
235 let iw_raw = ow_range - PW1;
236 let cond_left = iw_raw.lt(0);
237 let cond_right = iw_raw.ge(W);
238 let in_bounds = iw_raw.ge(0) & iw_raw.lt(W);
239
240 #[allow(clippy::erasing_op)]
241 let zero_iw = iw_raw * 0;
242 #[allow(clippy::erasing_op)]
243 let wm1_iw = iw_raw * 0 + (W - 1);
244
245 T::atomic_add(
246 dx_ptr.add_offsets(iw_raw + dx_bc_base),
247 dy_tile,
248 Some(ow_mask & in_bounds),
249 None,
250 None,
251 );
252 T::atomic_add(
253 dx_ptr.add_offsets(zero_iw + dx_bc_base),
254 dy_tile,
255 Some(ow_mask & cond_left),
256 None,
257 None,
258 );
259 T::atomic_add(
260 dx_ptr.add_offsets(wm1_iw + dx_bc_base),
261 dy_tile,
262 Some(ow_mask & cond_right),
263 None,
264 None,
265 );
266}
267
268pub struct ReplicationPad3dOp<'a, T: Num> {
269 pub forward: ReplicationPad3dForward<T>,
270 pub backward: ReplicationPad3dBackward<T>,
271 _marker: core::marker::PhantomData<&'a ()>,
272}