| 149 | } |
| 150 | |
| 151 | std::string GetKernelForConv(const Convolution2DAttributes& params) { |
| 152 | const int num_output_slices = GetNumOutputSlices(params.weights.shape.o); |
| 153 | std::string code; |
| 154 | code.reserve(16 * 1024); // Reserve large enough buffer. |
| 155 | const bool is_1x1 = |
| 156 | params.weights.shape.w == 1 && params.weights.shape.h == 1; |
| 157 | const bool is_strided = params.strides.w > 1 || params.strides.h > 1; |
| 158 | const int src_group_size = GetSrcBatchSize(params.weights.shape.o); |
| 159 | |
| 160 | const int src_depth = IntegralDivideRoundUp(params.weights.shape.i, 4); |
| 161 | const int src_groups = src_depth / src_group_size; |
| 162 | const int src_depth_aligned = AlignByN(src_depth, src_group_size); |
| 163 | const int reminder_src_depth = src_depth - src_groups * src_group_size; |
| 164 | |
| 165 | code = absl::Substitute(R"( |
| 166 | #include <metal_stdlib> |
| 167 | using namespace metal; |
| 168 | constant int src_depth_groups = $0; |
| 169 | constant int src_offset = $1; |
| 170 | constant int kernel_x = $2; |
| 171 | constant int kernel_y = $3; |
| 172 | struct uniforms { |
| 173 | int4 stride_padding; |
| 174 | int4 dillation_layer_offsets; |
| 175 | int4 size; |
| 176 | int4 z_offset; |
| 177 | }; |
| 178 | $$0 |
| 179 | kernel void ComputeFunction( |
| 180 | $$1 |
| 181 | uint tid[[thread_index_in_threadgroup]], |
| 182 | uint3 gid[[thread_position_in_grid]]) |
| 183 | { |
| 184 | const bool outside = static_cast<int>(gid.x) >= params.size.z || |
| 185 | static_cast<int>(gid.y) >= params.size.w; |
| 186 | )", |
| 187 | src_groups, src_depth_aligned, params.weights.shape.w, |
| 188 | params.weights.shape.h); |
| 189 | code += GetValuesDeclarationPart(num_output_slices, is_1x1); |
| 190 | |
| 191 | if (!is_1x1) { |
| 192 | code += R"( |
| 193 | for(int ky = 0; ky < kernel_y; ++ky) { |
| 194 | for(int kx = 0; kx < kernel_x; ++kx) { |
| 195 | int2 coords = int2(gid.xy) * params.stride_padding.xy + int2(kx, ky) * |
| 196 | params.dillation_layer_offsets.xy - params.stride_padding.zw; |
| 197 | const bool el_outside = coords.x < 0 || coords.y < 0 || coords.x >= params.size.x || |
| 198 | coords.y >= params.size.y; |
| 199 | const FLT multiplier = el_outside ? 0.0f : 1.0f; |
| 200 | )"; |
| 201 | } else { |
| 202 | code += "const FLT multiplier = 1.0f;\n"; |
| 203 | code += "int2 coords = int2(gid.xy)"; |
| 204 | if (is_strided) { |
| 205 | code += " * params.stride_padding.xy"; |
| 206 | } |
| 207 | code += ";\n"; |
| 208 | } |
no test coverage detected