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 circular_pad2d_forward<
33 T: Triton,
34 D: Num,
35 const PT: i32,
36 const PB: i32,
37 const PL: i32,
38 const PR: i32,
39 const BLOCK_OW: i32,
40>(
41 input_ptr: T::Pointer<D>,
42 output_ptr: T::Pointer<D>,
43 _B: i32,
44 C: i32,
45 H: i32,
46 W: i32,
47 OH: i32,
48 OW: i32,
49) where
50 T::I32Tensor: Tensor<i32, 1>,
51 T::I32Tensor: Comparison<i32, BoolTensor = T::BoolTensor>,
52 T::BoolTensor: BitAnd<Output = T::BoolTensor>,
53 T::BoolTensor: BitOr<Output = T::BoolTensor>,
54 T::Pointer<D>: AddOffsets<i32, 1, T::I32Tensor, Output = T::Tensor<T::Pointer<D>>>,
55{
56 let pid = T::program_id(Axis::X);
57 let num_ow_tiles = T::cdiv(OW, BLOCK_OW);
58
59 let ow_tile = pid % num_ow_tiles;
60 let rest = pid / num_ow_tiles;
61 let oh = rest % OH;
62 let bc = rest / OH;
63 let c = bc % C;
64 let b = bc / C;
65
66 let ow_start = ow_tile * BLOCK_OW;
67 let ow_range = T::arange(0, BLOCK_OW) + ow_start;
68 let ow_mask = ow_range.lt(OW);
69
70 let ih_raw = oh - PT;
72 let ih = (ih_raw + H) % H;
73
74 let in_bc_base = (b * C + c) * H * W + ih * W;
75 let out_bc_base = ((b * C + c) * OH + oh) * OW;
76
77 let iw_raw = ow_range - PL;
78 let cond_left = iw_raw.lt(0);
79 let cond_right = iw_raw.ge(W);
80 let in_bounds = iw_raw.ge(0) & iw_raw.lt(W);
81
82 let iw_wrap_left = iw_raw + W;
83 let iw_wrap_right = iw_raw - W;
84
85 let zeros = T::zeros::<D>(&[BLOCK_OW]);
86 let val_center = T::load(
87 input_ptr.add_offsets(iw_raw + in_bc_base),
88 Some(ow_mask & in_bounds),
89 Some(zeros),
90 &[],
91 None,
92 None,
93 None,
94 false,
95 );
96 let val_left = T::load(
97 input_ptr.add_offsets(iw_wrap_left + in_bc_base),
98 Some(ow_mask & cond_left),
99 Some(zeros),
100 &[],
101 None,
102 None,
103 None,
104 false,
105 );
106 let val_right = T::load(
107 input_ptr.add_offsets(iw_wrap_right + in_bc_base),
108 Some(ow_mask & cond_right),
109 Some(zeros),
110 &[],
111 None,
112 None,
113 None,
114 false,
115 );
116
117 let result = T::where_(
118 cond_left,
119 val_left,
120 T::where_(cond_right, val_right, val_center),
121 );
122
123 let out_offsets = ow_range + out_bc_base;
124 T::store(
125 output_ptr.add_offsets(out_offsets),
126 result,
127 Some(ow_mask),
128 &[],
129 None,
130 None,
131 );
132}
133
134#[kernel]
136pub fn circular_pad2d_backward<
137 T: Triton,
138 D: Num,
139 const PT: i32,
140 const PB: i32,
141 const PL: i32,
142 const PR: i32,
143 const BLOCK_OW: i32,
144>(
145 dy_ptr: T::Pointer<D>,
146 dx_ptr: T::Pointer<D>,
147 _B: i32,
148 C: i32,
149 H: i32,
150 W: i32,
151 OH: i32,
152 OW: i32,
153) where
154 T::I32Tensor: Tensor<i32, 1>,
155 T::I32Tensor: Comparison<i32, BoolTensor = T::BoolTensor>,
156 T::BoolTensor: BitAnd<Output = T::BoolTensor>,
157 T::BoolTensor: BitOr<Output = T::BoolTensor>,
158 T::Pointer<D>: AddOffsets<i32, 1, T::I32Tensor, Output = T::Tensor<T::Pointer<D>>>,
159{
160 let pid = T::program_id(Axis::X);
161 let num_ow_tiles = T::cdiv(OW, BLOCK_OW);
162
163 let ow_tile = pid % num_ow_tiles;
164 let rest = pid / num_ow_tiles;
165 let oh = rest % OH;
166 let bc = rest / OH;
167 let c = bc % C;
168 let b = bc / C;
169
170 let ow_start = ow_tile * BLOCK_OW;
171 let ow_range = T::arange(0, BLOCK_OW) + ow_start;
172 let ow_mask = ow_range.lt(OW);
173
174 let ih_raw = oh - PT;
175 let ih = (ih_raw + H) % H;
176
177 let dy_bc_base = ((b * C + c) * OH + oh) * OW;
178 let dx_bc_base = (b * C + c) * H * W + ih * W;
179
180 let dy_offsets = ow_range + dy_bc_base;
181 let dy_tile = T::load(
182 dy_ptr.add_offsets(dy_offsets),
183 Some(ow_mask),
184 Some(T::zeros::<D>(&[BLOCK_OW])),
185 &[],
186 None,
187 None,
188 None,
189 false,
190 );
191
192 let iw_raw = ow_range - PL;
193 let cond_left = iw_raw.lt(0);
194 let cond_right = iw_raw.ge(W);
195 let in_bounds = iw_raw.ge(0) & iw_raw.lt(W);
196
197 let iw_wrap_left = iw_raw + W;
198 let iw_wrap_right = iw_raw - W;
199
200 T::atomic_add(
201 dx_ptr.add_offsets(iw_raw + dx_bc_base),
202 dy_tile,
203 Some(ow_mask & in_bounds),
204 None,
205 None,
206 );
207 T::atomic_add(
208 dx_ptr.add_offsets(iw_wrap_left + dx_bc_base),
209 dy_tile,
210 Some(ow_mask & cond_left),
211 None,
212 None,
213 );
214 T::atomic_add(
215 dx_ptr.add_offsets(iw_wrap_right + dx_bc_base),
216 dy_tile,
217 Some(ow_mask & cond_right),
218 None,
219 None,
220 );
221}
222
223pub struct CircularPad2dOp<'a, T: Num> {
224 pub forward: CircularPad2dForward<T>,
225 pub backward: CircularPad2dBackward<T>,
226 _marker: core::marker::PhantomData<&'a ()>,
227}