group_blas_gemm.hh
Go to the documentation of this file.
1#pragma once
2
5
6namespace batchlas::device {
7
8namespace detail::generic {
9
10template <typename Tag, typename Group, typename T>
11inline constexpr void gemm(const Group& group,
13 MatrixMatrixOperand<T> operand) {
14 const int local_id = detail::group_local_linear_id(group);
15 const int local_size = detail::group_local_linear_range(group);
16 const int row_extent = detail::output_size<Tag::trans_a>(a);
17 const int col_extent = detail::input_size<Tag::trans_b>(operand.b);
18 const int contract_extent = detail::input_size<Tag::trans_a>(a);
19
20 for (int col = 0; col < col_extent; ++col) {
21 for (int row = 0; row < row_extent; ++row) {
22 T partial{};
23 for (int k = local_id; k < contract_extent; k += local_size) {
24 partial += detail::matrix_entry<Tag::trans_a>(a, row, k) *
26 }
27 partial = detail::reduce_sum_group(group, partial);
28 if (detail::group_is_leader(group)) {
29 detail::write_matrix_output(operand, row, col, partial);
30 }
31 }
32 }
33}
34
35} // namespace detail::generic
36
38
39template <typename Item, typename T>
40inline constexpr void gemm(const Item& item,
43 GeneralMatrixTransform transform) {
44 const auto sg = item.get_sub_group();
45 const int sg_size = subgroup_size(item);
46 const int lane = subgroup_local_id(item);
47 const int sg_id = subgroup_group_id(item);
48 const int total_sg = subgroup_count(item);
49 const int row_extent = detail::output_size(a, transform.trans_a);
50 const int col_extent = detail::input_size(operand.b, transform.trans_b);
51 const int contract_extent = detail::input_size(a, transform.trans_a);
52 const int tile_k = matrix_tile_k(contract_extent, sg_size, Side::Left);
53 const int rows_per_sg = matrix_rows_per_subgroup(row_extent, total_sg, sg_size, contract_extent, Side::Left);
54 const int col_tiles = (col_extent + sg_size - 1) / sg_size;
55 const int row_tiles = (row_extent + rows_per_sg - 1) / rows_per_sg;
56
57 for (int linear_tile = sg_id; linear_tile < row_tiles * col_tiles; linear_tile += total_sg) {
58 const int tile_row = linear_tile / col_tiles;
59 const int tile_col = linear_tile % col_tiles;
60 const int base_row = tile_row * rows_per_sg;
61 const int base_col = tile_col * sg_size;
62 const int col = base_col + lane;
63 std::array<T, detail::subgroup::kMaxMatrixRowsPerSubgroup> partials{};
64
65 for (int k_base = 0; k_base < contract_extent; k_base += tile_k) {
66 const int tile_extent = std::min(tile_k, contract_extent - k_base);
67
68 for (int tile_offset = 0; tile_offset < tile_extent; ++tile_offset) {
69 const int k = k_base + tile_offset;
70 const T b_value = col < col_extent ? detail::matrix_entry(operand.b, k, col, transform.trans_b) : T(0);
71 for (int row_offset = 0; row_offset < rows_per_sg; ++row_offset) {
72 const int row = base_row + row_offset;
73 if (row >= row_extent || col >= col_extent) {
74 continue;
75 }
76 const T a_lane = lane == row_offset ? detail::matrix_entry(a, row, k, transform.trans_a) : T(0);
77 const T a_value = batchlas::portable::select_from_group(sg, a_lane, static_cast<uint32_t>(row_offset));
78 partials[static_cast<std::size_t>(row_offset)] += a_value * b_value;
79 }
80 }
81 }
82
83 if (col < col_extent) {
84 for (int row_offset = 0; row_offset < rows_per_sg; ++row_offset) {
85 const int row = base_row + row_offset;
86 if (row >= row_extent) {
87 continue;
88 }
89 detail::write_matrix_output(operand, row, col, partials[static_cast<std::size_t>(row_offset)]);
90 }
91 }
92 }
93}
94
95template <typename Item, typename T>
96inline constexpr void gemm_register_tiled(const Item& item,
99 GeneralMatrixTransform transform,
100 detail::subgroup::GemmWorkspace<T>* gemm_workspace) {
101 const int linear_tid = detail::item_local_linear_id(item);
102 const int subgroup_id = detail::subgroup::subgroup_group_id(item);
103 const int local_row = linear_tid / detail::subgroup::kRegisterMatrixLocalCols;
104 const int local_col = linear_tid % detail::subgroup::kRegisterMatrixLocalCols;
105 const int row_extent = detail::output_size(a, transform.trans_a);
106 const int col_extent = detail::input_size(operand.b, transform.trans_b);
107 const int contract_extent = detail::input_size(a, transform.trans_a);
110 const int tile_row_start = detail::subgroup::matrix_tile_group_row(item);
111 const int tile_col_start = detail::subgroup::matrix_tile_group_col(item);
112 const int tile_row_stride = detail::subgroup::matrix_tile_group_row_stride(item);
113 const int tile_col_stride = detail::subgroup::matrix_tile_group_col_stride(item);
114 auto* workspace = &gemm_workspace->register_workspace;
115
116 for (int tile_row = tile_row_start; tile_row < row_tiles; tile_row += tile_row_stride) {
117 for (int tile_col = tile_col_start; tile_col < col_tiles; tile_col += tile_col_stride) {
121 const int tile_count = (contract_extent + detail::subgroup::kRegisterMatrixTileK - 1) / detail::subgroup::kRegisterMatrixTileK;
122
123 if (tile_count > 0) {
124 auto lhs_loader = [&](int tile_r, int global_k) {
125 const int global_row = tile_row * detail::subgroup::kRegisterMatrixTileM + tile_r;
126 if (global_row >= row_extent) {
127 return T(0);
128 }
129 return detail::matrix_entry(a, global_row, global_k, transform.trans_a);
130 };
131 auto rhs_loader = [&](int tile_c, int global_k) {
132 const int global_col = tile_col * detail::subgroup::kRegisterMatrixTileN + tile_c;
133 if (global_col >= col_extent) {
134 return T(0);
135 }
136 return detail::matrix_entry(operand.b, global_k, global_col, transform.trans_b);
137 };
138
140 workspace,
141 linear_tid,
142 subgroup_id,
143 0,
144 0,
145 true,
146 true,
147 0,
148 std::min(detail::subgroup::kRegisterMatrixTileK, contract_extent),
149 lhs_loader,
150 rhs_loader);
151 sycl::group_barrier(item.get_group());
152
153 for (int tile_idx = 0; tile_idx < tile_count; ++tile_idx) {
154 const int current_tile_extent = std::min(detail::subgroup::kRegisterMatrixTileK,
155 contract_extent - tile_idx * detail::subgroup::kRegisterMatrixTileK);
156 const int next_tile_idx = tile_idx + 1;
157 const int current_lhs_stage = detail::subgroup::register_matrix_lhs_stage(tile_idx);
158 const int current_rhs_stage = detail::subgroup::register_matrix_rhs_stage(tile_idx);
159
160 if (next_tile_idx < tile_count) {
161 const int next_k_base = next_tile_idx * detail::subgroup::kRegisterMatrixTileK;
162 const int next_tile_extent = std::min(detail::subgroup::kRegisterMatrixTileK, contract_extent - next_k_base);
165 workspace,
166 linear_tid,
167 subgroup_id,
168 current_lhs_stage,
170 false,
172 next_k_base,
173 next_tile_extent,
174 lhs_loader,
175 rhs_loader);
176 }
177 }
178
180 workspace,
181 subgroup_id,
182 current_lhs_stage,
183 current_rhs_stage,
184 local_row,
185 local_col,
186 current_tile_extent,
187 accum);
188
189 if (next_tile_idx < tile_count) {
190 const int next_k_base = next_tile_idx * detail::subgroup::kRegisterMatrixTileK;
191 const int next_tile_extent = std::min(detail::subgroup::kRegisterMatrixTileK, contract_extent - next_k_base);
193 sycl::group_barrier(item.get_group());
194 } else {
195 sycl::group_barrier(item.get_sub_group());
196 }
198 workspace,
199 linear_tid,
200 subgroup_id,
201 0,
203 true,
205 next_k_base,
206 next_tile_extent,
207 lhs_loader,
208 rhs_loader);
209 sycl::group_barrier(item.get_group());
210 }
211 }
212 }
213
214 detail::subgroup::write_register_matrix_tile(operand, row_base, col_base, row_extent, col_extent, accum);
215 }
216 }
217}
218
219template <typename Item, typename T>
220inline constexpr void gemm_aligned_nn_large(const Item& item,
223 detail::subgroup::GemmWorkspace<T>* gemm_workspace) {
224 const int linear_tid = detail::item_local_linear_id(item);
225 const int local_row = linear_tid / detail::subgroup::kOptimizedGemmLocalCols;
226 const int local_col = linear_tid % detail::subgroup::kOptimizedGemmLocalCols;
227 const int row_extent = a.rows();
228 const int col_extent = operand.b.cols();
229 const int contract_extent = a.cols();
230 const int row_tiles = row_extent / detail::subgroup::kOptimizedGemmTileM;
231 const int col_tiles = col_extent / detail::subgroup::kRegisterMatrixTileN;
232 const int tile_row_start = detail::subgroup::matrix_tile_group_row(item);
233 const int tile_col_start = detail::subgroup::matrix_tile_group_col(item);
234 const int tile_row_stride = detail::subgroup::matrix_tile_group_row_stride(item);
235 const int tile_col_stride = detail::subgroup::matrix_tile_group_col_stride(item);
236 auto* workspace = &gemm_workspace->optimized_workspace;
237
238 for (int tile_row = tile_row_start; tile_row < row_tiles; tile_row += tile_row_stride) {
239 for (int tile_col = tile_col_start; tile_col < col_tiles; tile_col += tile_col_stride) {
241
242 for (int subtile_col = 0; subtile_col < detail::subgroup::kRegisterMatrixTileN / detail::subgroup::kOptimizedGemmTileN; ++subtile_col) {
243 const int col_tile_base = tile_col * detail::subgroup::kRegisterMatrixTileN + subtile_col * detail::subgroup::kOptimizedGemmTileN;
244 const int col_base = col_tile_base + local_col * detail::subgroup::kOptimizedGemmThreadTileCols;
246
247 auto load_stage = [&](int k_base, int stage) {
248 T* lhs_stage = workspace->lhs + stage * detail::subgroup::kOptimizedGemmStageASize;
249 T* rhs_stage = workspace->rhs + stage * detail::subgroup::kOptimizedGemmStageBSize;
250
252 constexpr int lhs_packet_count = lhs_packets_per_col * detail::subgroup::kOptimizedGemmTileK;
253 constexpr int lhs_packet_iterations = lhs_packet_count / detail::subgroup::kOptimizedGemmThreadsPerGroup;
255 constexpr int iteration = iter;
256 const int packet = linear_tid + iteration * detail::subgroup::kOptimizedGemmThreadsPerGroup;
257 const int lhs_row = (packet % lhs_packets_per_col) * detail::subgroup::kOptimizedGemmVecA;
258 const int lhs_col = packet / lhs_packets_per_col;
259 const int base = (k_base + lhs_col) * a.ld() + tile_row * detail::subgroup::kOptimizedGemmTileM + lhs_row;
262 constexpr int lane = lane_idx;
263 lhs_stage[lhs_col * detail::subgroup::kOptimizedGemmTileAStride + lhs_row + lane] = packet_values[lane];
264 });
265 });
266
268 constexpr int rhs_packet_count = detail::subgroup::kOptimizedGemmTileN * rhs_packets_per_col;
269 constexpr int rhs_packet_iterations = rhs_packet_count / detail::subgroup::kOptimizedGemmThreadsPerGroup;
271 constexpr int iteration = iter;
272 const int packet = linear_tid + iteration * detail::subgroup::kOptimizedGemmThreadsPerGroup;
273 const int rhs_row = (packet % rhs_packets_per_col) * detail::subgroup::kOptimizedGemmVecB;
274 const int rhs_col = packet / rhs_packets_per_col;
275 const int base = (col_tile_base + rhs_col) * operand.b.ld() + k_base + rhs_row;
278 constexpr int lane = lane_idx;
279 rhs_stage[rhs_col * detail::subgroup::kOptimizedGemmTileBStride + rhs_row + lane] = packet_values[lane];
280 });
281 });
282 };
283
284 auto accumulate_stage = [&](const T* lhs_stage, const T* rhs_stage) {
286 for (int unroll = 0; unroll < detail::subgroup::kOptimizedGemmUnrollK; ++unroll) {
287 const int t = t0 + unroll;
290 for (int i = 0; i < detail::subgroup::kOptimizedGemmThreadTileRows; ++i) {
291 lhs_frag[i] = lhs_stage[t * detail::subgroup::kOptimizedGemmTileAStride +
293 }
294 for (int j = 0; j < detail::subgroup::kOptimizedGemmThreadTileCols; ++j) {
295 rhs_frag[j] = rhs_stage[(local_col * detail::subgroup::kOptimizedGemmThreadTileCols + j) *
297 }
298 for (int i = 0; i < detail::subgroup::kOptimizedGemmThreadTileRows; ++i) {
299 for (int j = 0; j < detail::subgroup::kOptimizedGemmThreadTileCols; ++j) {
300 accum[i][j] += lhs_frag[i] * rhs_frag[j];
301 }
302 }
303 }
304 }
305 };
306
307 const int tile_count = contract_extent / detail::subgroup::kOptimizedGemmTileK;
308 if (tile_count > 0) {
309 load_stage(0, 0);
310 item.barrier(sycl::access::fence_space::local_space);
311
312 for (int tile_idx = 0; tile_idx + 1 < tile_count; ++tile_idx) {
313 const int current_stage = tile_idx & 1;
314 const int next_stage = current_stage ^ 1;
315 load_stage((tile_idx + 1) * detail::subgroup::kOptimizedGemmTileK, next_stage);
316 accumulate_stage(workspace->lhs + current_stage * detail::subgroup::kOptimizedGemmStageASize,
317 workspace->rhs + current_stage * detail::subgroup::kOptimizedGemmStageBSize);
318 item.barrier(sycl::access::fence_space::local_space);
319 }
320
321 const int final_stage = (tile_count - 1) & 1;
322 accumulate_stage(workspace->lhs + final_stage * detail::subgroup::kOptimizedGemmStageASize,
323 workspace->rhs + final_stage * detail::subgroup::kOptimizedGemmStageBSize);
324 item.barrier(sycl::access::fence_space::local_space);
325 }
326
327 for (int i = 0; i < detail::subgroup::kOptimizedGemmThreadTileRows; ++i) {
328 const int row = row_base + i;
329 for (int j = 0; j < detail::subgroup::kOptimizedGemmThreadTileCols; ++j) {
330 const int col = col_base + j;
331 detail::write_matrix_output(operand, row, col, accum[i][j]);
332 }
333 }
334 }
335 }
336 }
337}
338
339} // namespace detail::subgroup
340
341namespace detail {
342
343template <typename Tag, DeviceBlasPolicy Policy, typename T>
344inline constexpr std::size_t gemm_workspace_elements(const DeviceBlasLaunchInfo& launch,
345 int row_extent,
346 int col_extent,
347 int contract_extent,
348 bool aligned_a = false,
349 bool aligned_b = false) {
350 assert(row_extent >= 0 && col_extent >= 0 && contract_extent >= 0 &&
351 "device::gemm workspace query expects non-negative matrix extents");
352
353 if (aligned_a && aligned_b &&
355 row_extent,
356 col_extent,
357 contract_extent,
358 Tag::trans_a,
359 Tag::trans_b,
360 Policy) &&
363 }
364
365 if (detail::subgroup::can_use_matrix_register_fast_path<T>(launch, row_extent, col_extent, contract_extent, Policy)) {
366 // Size for GemmWorkspace when it fits: the call may still take the aligned-NN path at run time.
367 // The predicate already requires register_matrix_workspace_supported_v<T>, so the else arm is safe.
370 } else {
372 }
373 }
374 return 0;
375}
376
377template <typename Tag, DeviceBlasPolicy Policy, typename Exec, typename T>
378inline constexpr void dispatch_gemm(const Exec& exec,
381 T* workspace = nullptr) {
382 const GeneralMatrixTransform transform{.trans_a = Tag::trans_a, .trans_b = Tag::trans_b};
383 validate_gemm_operand(a, operand, transform);
384
385 if constexpr (detail::NdItemLike<Exec>) {
386 auto* gemm_workspace = workspace == nullptr ? nullptr : detail::workspace_ptr_cast<detail::subgroup::GemmWorkspace<T>>(workspace);
387
388 if (gemm_workspace != nullptr && detail::subgroup::can_use_matrix_aligned_nn_large_fast_path<T>(exec, a, operand, transform, Policy) &&
390 detail::subgroup::gemm_aligned_nn_large(exec, a, operand, gemm_workspace);
391 return;
392 }
393
394 const int row_extent = detail::output_size(a, transform.trans_a);
395 const int col_extent = detail::input_size(operand.b, transform.trans_b);
396 const int contract_extent = detail::input_size(a, transform.trans_a);
397 if (gemm_workspace != nullptr && detail::subgroup::can_use_matrix_register_fast_path<T>(exec, row_extent, col_extent, contract_extent, Policy) &&
399 detail::subgroup::gemm_register_tiled(exec, a, operand, transform, gemm_workspace);
400 return;
401 }
402 if (detail::subgroup::can_use_matrix_fast_path<T>(exec, row_extent, col_extent, contract_extent, Policy)) {
403 detail::subgroup::gemm(exec, a, operand, transform);
404 return;
405 }
406 // 3-D launch, no fast path: only tile-group (0, 0) runs the generic loop, else the groups race.
407 // evidence: docs/design/device-group-blas.md#device-group-blas-the-3-d-launch-generic-fallback
408 if constexpr (std::is_same_v<std::remove_cvref_t<Exec>, sycl::nd_item<3>>) {
411 generic::gemm<Tag>(exec, a, operand);
412 }
413 return;
414 }
415 }
416
417 generic::gemm<Tag>(exec, a, operand);
418}
419
420} // namespace detail
421
422/// @addtogroup api_device_blas
423/// @{
424
425/// @brief General matrix-matrix product \f$ C := \alpha\,\mathrm{op}(A)\,\mathrm{op}(B) + \beta\,C \f$.
426///
427/// With \f$\mathrm{op}(A)\f$ m x k and \f$\mathrm{op}(B)\f$ k x n, `C` is m x n.
428/// Path selection, first eligible wins: the aligned NN kernel (`float`, a
429/// workspace, 256 work-items, m a multiple of 128, n of 64 and k of 32,
430/// 4-element-aligned `A` and `B`), the register-tiled kernel (`float`, a
431/// workspace, 256 work-items, m >= 4, n >= 8, k >= 32), the sub-group kernel
432/// (`float`, sub-group size admitted by the policy, m >= 8 and n, k at least
433/// the sub-group size), then the generic group reduction. The first three need
434/// an `nd_item` executor.
435/// @tparam TransAV op() applied to `A`
436/// @tparam TransBV op() applied to `B`
437/// @tparam Group `sycl::group`, `sycl::sub_group`, `sycl::nd_item<1>` or `sycl::nd_item<3>`; every work-item must call
438/// @param group executor. With `nd_item<3>`, work-group ids 1 and 2 tile the output, and without a fast path only tile-group (0, 0) computes.
439/// @param a single matrix, m x k (NoTrans) or k x m
440/// @param operand `B`, `C` (m x n, must not alias `A` or `B`), `alpha`, `beta`
441/// @param workspace local memory of gemm_workspace_elements() elements, or `nullptr`
442/// @pre `C` holds finite values even when `beta == 0`; conforming shapes (checked by `assert` only).
443/// @note On the generic path each `C` element is written by the group leader; barrier before other work-items read `C`.
444/// @see @ref design_device_group_blas
445template <Transpose TransAV = Transpose::NoTrans, Transpose TransBV = Transpose::NoTrans, typename Group, typename T>
446inline constexpr void gemm(const Group& group,
449 T* workspace = nullptr) {
451}
452
453/// @brief As gemm(), with an explicit DeviceBlasPolicy.
454template <DeviceBlasPolicy Policy,
457 typename Group,
458 typename T>
459inline constexpr void gemm(const Group& group,
462 T* workspace = nullptr) {
464}
465
466/// @brief Local memory, in elements of `T`, that gemm() can use for this launch and shape.
467///
468/// Allocate it as a `sycl::local_accessor<T, 1>` and pass its pointer; when the
469/// result is 0 pass `nullptr`. Use the same template arguments as the call.
470/// @param launch description of the launch the call runs in
471/// @param row_extent m, rows of `C`
472/// @param col_extent n, columns of `C`
473/// @param contract_extent k
474/// @param aligned_a the caller guarantees `A` meets the aligned NN kernel's 4-element alignment
475/// @param aligned_b the same for `B`
476/// @return element count, or 0 when no staged path applies
477/// @ingroup api_device_blas_lowlevel
478template <typename T, Transpose TransAV = Transpose::NoTrans, Transpose TransBV = Transpose::NoTrans>
479inline constexpr std::size_t gemm_workspace_elements(const DeviceBlasLaunchInfo& launch,
480 int row_extent,
481 int col_extent,
482 int contract_extent,
483 bool aligned_a = false,
484 bool aligned_b = false) {
486 launch, row_extent, col_extent, contract_extent, aligned_a, aligned_b);
487}
488
489/// @brief Local memory, in elements of `T`, that gemm() can use under `Policy`; 0 means pass `nullptr`.
490/// @param launch description of the launch the call runs in
491/// @param row_extent rows of `C`
492/// @param col_extent columns of `C`
493/// @param contract_extent contraction length k
494/// @param aligned_a the caller guarantees `A` meets the aligned kernel's 4-element alignment
495/// @param aligned_b the same for `B`
496/// @return element count, or 0 when no staged path applies
497/// @ingroup api_device_blas_lowlevel
498template <typename T,
502inline constexpr std::size_t gemm_workspace_elements(const DeviceBlasLaunchInfo& launch,
503 int row_extent,
504 int col_extent,
505 int contract_extent,
506 bool aligned_a = false,
507 bool aligned_b = false) {
509 launch, row_extent, col_extent, contract_extent, aligned_a, aligned_b);
510}
511
512/// @brief As gemm(), with the operands passed separately instead of in an operand struct.
513template <Transpose TransAV = Transpose::NoTrans, Transpose TransBV = Transpose::NoTrans, typename Group, typename T>
514inline constexpr void gemm(const Group& group,
518 T alpha = T(1),
519 T beta = T(0),
520 T* workspace = nullptr) {
521 gemm<TransAV, TransBV>(group, a, make_matmat_operand(b, c, alpha, beta), workspace);
522}
523
524/// @brief As gemm(), with an explicit DeviceBlasPolicy and the operands passed separately.
525template <DeviceBlasPolicy Policy,
528 typename Group,
529 typename T>
530inline constexpr void gemm(const Group& group,
534 T alpha = T(1),
535 T beta = T(0),
536 T* workspace = nullptr) {
537 gemm<Policy, TransAV, TransBV>(group, a, make_matmat_operand(b, c, alpha, beta), workspace);
538}
539
540/// @}
541
542} // namespace batchlas::device
Policy
Synchronous or asynchronous execution policy.
constexpr std::size_t gemm_workspace_elements(const DeviceBlasLaunchInfo &launch, int row_extent, int col_extent, int contract_extent, bool aligned_a=false, bool aligned_b=false)
Local memory, in elements of T, that gemm() can use for this launch and shape.
constexpr MatrixMatrixOperand< T > make_matmat_operand(const KernelMatrixView< T, MatrixFormat::Dense > &b, const KernelMatrixView< T, MatrixFormat::Dense > &c, T alpha=T(1), T beta=T(0))
Builds a MatrixMatrixOperand.
DeviceBlasPolicy
Which implementation family a device BLAS call may use.
constexpr void gemm(const Group &group, const KernelMatrixView< T, MatrixFormat::Dense > &a, MatrixMatrixOperand< T > operand, T *workspace=nullptr)
General matrix-matrix product .
@ Auto
any eligible path; the sub-group fast paths accept sub-group size 16 or 32
Transpose
The operator op() applied to an operand: op(A) = A, A^T or A^H.
Definition enums.hh:171
@ NoTrans
op(A) = A.
Definition enums.hh:172
@ Left
The special operand is on the left.
Definition enums.hh:320
T select_from_group(Group g, T x, Id id)
sycl::select_from_group for any trivially copyable T. Collective.
constexpr void gemm(const Group &group, const KernelMatrixView< T, MatrixFormat::Dense > &a, MatrixMatrixOperand< T > operand)
constexpr bool can_use_matrix_fast_path(const Item &item, int row_extent, int col_extent, int contract_extent, DeviceBlasPolicy policy)
constexpr int subgroup_group_id(const Item &item)
constexpr void gemm(const Item &item, const KernelMatrixView< T, MatrixFormat::Dense > &a, MatrixMatrixOperand< T > operand, GeneralMatrixTransform transform)
constexpr int matrix_tile_group_row(const Item &)
constexpr void gemm_register_tiled(const Item &item, const KernelMatrixView< T, MatrixFormat::Dense > &a, MatrixMatrixOperand< T > operand, GeneralMatrixTransform transform, detail::subgroup::GemmWorkspace< T > *gemm_workspace)
constexpr int subgroup_size(const Item &item)
constexpr void gemm_aligned_nn_large(const Item &item, const KernelMatrixView< T, MatrixFormat::Dense > &a, MatrixMatrixOperand< T > operand, detail::subgroup::GemmWorkspace< T > *gemm_workspace)
constexpr int matrix_tile_group_col(const Item &)
constexpr int matrix_rows_per_subgroup(int row_extent, int total_sg, int sg_size, int contract_extent, Side side)
constexpr void write_register_matrix_tile(MatrixMatrixOperand< T > operand, int row_base, int col_base, int row_extent, int col_extent, const RegisterMatrixAccumTile< T > &accum)
constexpr void load_register_matrix_stage(const Item &item, RegisterMatrixWorkspace< T > *workspace, int linear_tid, int subgroup_id, int lhs_stage, int rhs_stage, bool load_lhs, bool load_rhs, int k_base, int tile_extent, LhsLoader &&lhs_loader, RhsLoader &&rhs_loader)
constexpr int matrix_tile_k(int contract_extent, int sg_size, Side side)
constexpr int matrix_tile_group_row_stride(const Item &)
constexpr bool can_use_matrix_aligned_nn_large_fast_path(const Item &item, int row_extent, int col_extent, int contract_extent, Transpose trans_a, Transpose trans_b, DeviceBlasPolicy policy)
constexpr int matrix_tile_group_col_stride(const Item &)
constexpr int register_matrix_rhs_stage(int tile_idx)
constexpr int register_matrix_lhs_stage(int tile_idx)
constexpr bool can_use_matrix_register_fast_path(const Item &item, int row_extent, int col_extent, int contract_extent, DeviceBlasPolicy policy)
constexpr int subgroup_local_id(const Item &item)
constexpr Packet< T, Width > packet_load_aligned(const T *ptr, int offset)
constexpr void accumulate_register_matrix_stage(const Item &item, const RegisterMatrixWorkspace< T > *workspace, int subgroup_id, int lhs_stage, int rhs_stage, int local_row, int local_col, int tile_extent, RegisterMatrixAccumTile< T > &accum)
constexpr int subgroup_count(const Item &item)
constexpr std::size_t gemm_workspace_elements(const DeviceBlasLaunchInfo &launch, int row_extent, int col_extent, int contract_extent, bool aligned_a=false, bool aligned_b=false)
constexpr int output_size(const KernelMatrixView< T, MatrixFormat::Dense > &a, Transpose trans)
constexpr void write_matrix_output(const MatrixMatrixOperand< T > &operand, int row, int col, const T &value)
constexpr int group_local_linear_id(const Group &group)
constexpr int input_size(const KernelMatrixView< T, MatrixFormat::Dense > &a, Transpose trans)
constexpr void validate_gemm_operand(const KernelMatrixView< T, MatrixFormat::Dense > &a, const MatrixMatrixOperand< T > &operand, GeneralMatrixTransform transform)
constexpr int group_local_linear_range(const Group &group)
constexpr Workspace * workspace_ptr_cast(T *workspace)
constexpr T matrix_entry(const KernelMatrixView< T, MatrixFormat::Dense > &a, int row, int col, Transpose trans)
constexpr T reduce_sum_group(const Group &group, const T &value)
constexpr int item_local_linear_id(const Item &item)
constexpr std::size_t workspace_elements_v
constexpr void dispatch_gemm(const Exec &exec, const KernelMatrixView< T, MatrixFormat::Dense > &a, MatrixMatrixOperand< T > operand, T *workspace=nullptr)
constexpr bool group_is_leader(const Group &group)
Trivially copyable view of a MatrixView for use inside a SYCL kernel.
Definition matrix.hh:145
auto data() const
Base pointer of item 0.
Definition matrix.hh:217
auto rows() const
Row count (the capacity on a heterogeneous batch).
Definition matrix.hh:219
auto ld() const
Dense leading dimension, in elements.
Definition matrix.hh:227
auto cols() const
Column count (the capacity on a heterogeneous batch).
Definition matrix.hh:223
Host-side description of a launch, for the *_workspace_elements queries.
Runtime transpose modes of a general matrix-matrix product.
Operands of a matrix-matrix operation: .
KernelMatrixView< T, MatrixFormat::Dense > b
second input matrix