10template <
typename Tag,
typename Group,
typename T>
11inline constexpr void gemm(
const Group& group,
20 for (
int col = 0; col < col_extent; ++col) {
21 for (
int row = 0; row < row_extent; ++row) {
23 for (
int k = local_id; k < contract_extent; k += local_size) {
39template <
typename Item,
typename T>
40inline constexpr void gemm(
const Item& item,
44 const auto sg = item.get_sub_group();
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;
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{};
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);
68 for (
int tile_offset = 0; tile_offset < tile_extent; ++tile_offset) {
69 const int k = k_base + tile_offset;
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) {
78 partials[
static_cast<std::size_t
>(row_offset)] += a_value * b_value;
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) {
95template <
typename Item,
typename T>
114 auto* workspace = &gemm_workspace->register_workspace;
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) {
123 if (tile_count > 0) {
124 auto lhs_loader = [&](
int tile_r,
int global_k) {
126 if (global_row >= row_extent) {
131 auto rhs_loader = [&](
int tile_c,
int global_k) {
133 if (global_col >= col_extent) {
151 sycl::group_barrier(item.get_group());
153 for (
int tile_idx = 0; tile_idx < tile_count; ++tile_idx) {
156 const int next_tile_idx = tile_idx + 1;
160 if (next_tile_idx < tile_count) {
189 if (next_tile_idx < tile_count) {
193 sycl::group_barrier(item.get_group());
195 sycl::group_barrier(item.get_sub_group());
209 sycl::group_barrier(item.get_group());
219template <
typename Item,
typename T>
227 const int row_extent = a.
rows();
228 const int col_extent = operand.
b.
cols();
229 const int contract_extent = a.
cols();
236 auto* workspace = &gemm_workspace->optimized_workspace;
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) {
247 auto load_stage = [&](
int k_base,
int stage) {
255 constexpr int iteration = iter;
258 const int lhs_col = packet / lhs_packets_per_col;
262 constexpr int lane = lane_idx;
271 constexpr int iteration = iter;
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;
284 auto accumulate_stage = [&](
const T* lhs_stage,
const T* rhs_stage) {
287 const int t = t0 + unroll;
300 accum[i][j] += lhs_frag[i] * rhs_frag[j];
308 if (tile_count > 0) {
310 item.barrier(sycl::access::fence_space::local_space);
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;
318 item.barrier(sycl::access::fence_space::local_space);
321 const int final_stage = (tile_count - 1) & 1;
324 item.barrier(sycl::access::fence_space::local_space);
328 const int row = row_base + i;
330 const int col = col_base + j;
343template <
typename Tag, DeviceBlasPolicy Policy,
typename T>
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");
353 if (aligned_a && aligned_b &&
377template <
typename Tag, DeviceBlasPolicy Policy,
typename Exec,
typename T>
381 T* workspace =
nullptr) {
408 if constexpr (std::is_same_v<std::remove_cvref_t<Exec>, sycl::nd_item<3>>) {
445template <Transpose TransAV = Transpose::NoTrans, Transpose TransBV = Transpose::NoTrans,
typename Group,
typename T>
446inline constexpr void gemm(
const Group& group,
449 T* workspace =
nullptr) {
459inline constexpr void gemm(
const Group& group,
462 T* workspace =
nullptr) {
478template <
typename T, Transpose TransAV = Transpose::NoTrans, Transpose TransBV = Transpose::NoTrans>
483 bool aligned_a =
false,
484 bool aligned_b =
false) {
486 launch, row_extent, col_extent, contract_extent, aligned_a, aligned_b);
506 bool aligned_a =
false,
507 bool aligned_b =
false) {
509 launch, row_extent, col_extent, contract_extent, aligned_a, aligned_b);
513template <Transpose TransAV = Transpose::NoTrans, Transpose TransBV = Transpose::NoTrans,
typename Group,
typename T>
514inline constexpr void gemm(
const Group& group,
520 T* workspace =
nullptr) {
530inline constexpr void gemm(
const Group& group,
536 T* workspace =
nullptr) {
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.
@ Left
The special operand is on the left.
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 int kOptimizedGemmUnrollK
constexpr void static_for(Fn &&fn)
constexpr bool can_use_matrix_fast_path(const Item &item, int row_extent, int col_extent, int contract_extent, DeviceBlasPolicy policy)
constexpr int kOptimizedGemmVecA
constexpr bool register_matrix_workspace_supported_v
constexpr int kRegisterMatrixTileN
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 kRegisterMatrixTileK
constexpr int kOptimizedGemmTileAStride
constexpr int matrix_tile_group_row(const Item &)
constexpr int kOptimizedGemmThreadsPerGroup
constexpr int kOptimizedGemmStageASize
constexpr int kRegisterMatrixLocalCols
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 int kRegisterMatrixRhsStages
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 int kOptimizedGemmTileBStride
constexpr int kRegisterMatrixThreadTileRows
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 kOptimizedGemmLocalCols
constexpr bool optimized_gemm_workspace_supported_v
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 kOptimizedGemmStageBSize
constexpr int kOptimizedGemmTileN
constexpr int kRegisterMatrixTileM
constexpr int kOptimizedGemmThreadTileCols
constexpr int kOptimizedGemmTileK
constexpr int kOptimizedGemmTileM
constexpr int subgroup_local_id(const Item &item)
constexpr Packet< T, Width > packet_load_aligned(const T *ptr, int offset)
constexpr int kOptimizedGemmVecB
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 kOptimizedGemmThreadTileRows
constexpr int subgroup_count(const Item &item)
constexpr int kRegisterMatrixThreadTileCols
constexpr bool gemm_workspace_supported_v
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.
auto data() const
Base pointer of item 0.
auto rows() const
Row count (the capacity on a heterogeneous batch).
auto ld() const
Dense leading dimension, in elements.
auto cols() const
Column count (the capacity on a heterogeneous batch).
Host-side description of a launch, for the *_workspace_elements queries.
Operands of a matrix-matrix operation: .
KernelMatrixView< T, MatrixFormat::Dense > b
second input matrix