59 static_cast<std::size_t
>(::batchlas::device_limits::subgroup_workspace_budget_bytes());
61template <std::
size_t FixedElements, std::
size_t ElementsPerSubgroup,
typename T>
64 if constexpr (budget_elements <= FixedElements) {
67 constexpr std::size_t remaining_elements = budget_elements - FixedElements;
68 constexpr std::size_t subgroup_limit = ElementsPerSubgroup == 0
70 : (remaining_elements / ElementsPerSubgroup);
93template <
int Count,
typename Fn, std::size_t... I>
95 (fn(std::integral_constant<
int,
static_cast<int>(I)>{}), ...);
98template <
int Count,
typename Fn>
105 std::array<T, kRegisterMatrixThreadTileRows * kRegisterMatrixThreadTileCols>
values{};
107 template <
int Row,
int Col>
108 inline constexpr T&
get() {
109 return std::get<Row * kRegisterMatrixThreadTileCols + Col>(
values);
112 template <
int Row,
int Col>
113 inline constexpr const T&
get()
const {
114 return std::get<Row * kRegisterMatrixThreadTileCols + Col>(
values);
120 std::array<T, kComplexRank2kThreadTileRows * kComplexRank2kThreadTileCols>
values{};
122 template <
int Row,
int Col>
123 inline constexpr T&
get() {
124 return std::get<Row * kComplexRank2kThreadTileCols + Col>(
values);
127 template <
int Row,
int Col>
128 inline constexpr const T&
get()
const {
129 return std::get<Row * kComplexRank2kThreadTileCols + Col>(
values);
191template <
typename T,
int W
idth>
197template <
typename T,
int W
idth>
200 static_cast<void>(ptr);
201 static_cast<void>(ld);
202 static_cast<void>(stride);
205 const auto address =
reinterpret_cast<std::uintptr_t
>(ptr);
206 return (address %
alignof(sycl::vec<T, Width>) == 0) && (ld % Width == 0) && (stride % Width == 0);
212template <
typename T,
int W
idth>
218template <
typename T,
int W
idth>
221template <
typename T,
int W
idth>
234template <
typename Item>
239template <
typename Item>
244template <
typename Item>
249template <
typename Item>
255 return static_cast<int>(item.get_group(1));
259 return static_cast<int>(item.get_group(2));
263 return std::max(1,
static_cast<int>(item.get_group_range(1)));
267 return std::max(1,
static_cast<int>(item.get_group_range(2)));
270template <
typename Item>
272 return static_cast<int>(item.get_sub_group().get_local_range().size());
279template <
typename Item>
281 return static_cast<int>(item.get_sub_group().get_local_linear_id());
284template <
typename Item>
289template <
typename Item>
300template <
typename Exec>
302 return std::is_same_v<std::remove_cvref_t<Exec>, sycl::nd_item<3>>;
310 if (extent >= total_sg * max_rows) {
313 if (max_rows >= 4 && extent >= total_sg * 2) {
320 if (contract_extent >= 256 && sg_size == 32) {
323 if (contract_extent >= 128) {
334 if (side ==
Side::Left && sg_size == 32 && contract_extent >= 128 && row_extent >= total_sg * 8) {
345 return actual_size == 16;
347 return actual_size == 32;
349 return actual_size == 16 || actual_size == 32;
354template <
typename T,
typename Item>
360 if constexpr (!std::is_same_v<T, float>) {
372 return row_extent >= 8 && col_extent >= sg_size && contract_extent >= sg_size;
375template <
typename T,
typename Item>
384 if constexpr (!std::is_same_v<T, float>) {
400template <
typename T,
typename Item>
409template <
typename T,
typename Item>
415 if constexpr (!std::is_same_v<T, float>) {
445template <
typename T,
typename Item>
453 if constexpr (!std::is_same_v<T, float>) {
479template <
typename T,
typename Item>
485template <
typename T,
typename Item>
491 if constexpr (!std::is_same_v<T, std::complex<float>>) {
515 contract_extent >= 16 &&
516 operand.
c.
rows() == extent &&
517 operand.
c.
cols() == extent;
520template <
typename T,
typename Item>
525 if constexpr (!std::is_same_v<T, std::complex<float>>) {
547 contract_extent >= 16 &&
551template <
typename T,
typename Item>
557template <
typename T,
typename Item>
563 if constexpr (!std::is_same_v<T, std::complex<float>>) {
587 contract_extent >= 16 &&
588 operand.
c.
rows() == extent &&
589 operand.
c.
cols() == extent;
592template <
typename T,
typename Item>
597 if constexpr (!std::is_same_v<T, std::complex<float>>) {
619 contract_extent >= 16 &&
623template <
typename T,
typename Item>
629template <
typename T,
typename Item>
635 if constexpr (!std::is_same_v<T, float>) {
659 contract_extent >= 16 &&
660 operand.
c.
rows() == extent &&
661 operand.
c.
cols() == extent;
664template <
typename T,
typename Item>
669 if constexpr (!std::is_same_v<T, float>) {
691 contract_extent >= 16 &&
695template <
typename T,
typename Item>
701template <
typename T,
typename Item>
707 if constexpr (!std::is_same_v<T, float>) {
731 contract_extent >= 16 &&
732 operand.
c.
rows() == extent &&
733 operand.
c.
cols() == extent;
736template <
typename T,
typename Item>
741 if constexpr (!std::is_same_v<T, float>) {
763 contract_extent >= 16 &&
802 const int first_row = std::min(row_extent - 1, row_base);
804 if (first_row < 0 || last_row < 0) {
813 const int first_col = std::min(col_extent - 1, col_base);
815 if (first_col < 0 || last_col < 0) {
836 return transform.
uplo ==
Uplo::Lower ? std::min(contract_extent, last_row + 1) : contract_extent;
838 return transform.
uplo ==
Uplo::Lower ? contract_extent : std::min(contract_extent, last_row + 1);
846 return transform.
uplo ==
Uplo::Lower ? contract_extent : std::min(contract_extent, last_col + 1);
848 return transform.
uplo ==
Uplo::Lower ? std::min(contract_extent, last_col + 1) : contract_extent;
851template <
typename Item,
typename T,
typename LhsLoader,
typename RhsLoader>
862 LhsLoader&& lhs_loader,
863 RhsLoader&& rhs_loader) {
865 T* lhs_stage_ptr = workspace->
lhs[subgroup_id][lhs_stage];
866 T* rhs_stage_ptr = workspace->
rhs[rhs_stage];
874 tile_k < tile_extent ? lhs_loader(tile_r, k_base + tile_k) : T(0);
882 tile_k < tile_extent ? rhs_loader(tile_c, k_base + tile_k) : T(0);
889 std::array<T, kRegisterMatrixThreadTileRows>
lhs{};
890 std::array<T, kRegisterMatrixThreadTileCols>
rhs{};
894 return std::get<Row>(
lhs);
899 return std::get<Row>(
lhs);
904 return std::get<Col>(
rhs);
909 return std::get<Col>(
rhs);
913template <
typename Item,
typename T>
923 const auto sg = item.get_sub_group();
929 const int rhs_source_lane_base = sg_col;
930 const T* lhs_stage_ptr = workspace->
lhs[subgroup_id][lhs_stage];
931 const T* rhs_stage_ptr = workspace->
rhs[rhs_stage];
934 for (
int kk = 0; kk < tile_extent; ++kk) {
937 constexpr int i = row_idx;
943 constexpr int j = col_idx;
945 fragments.template rhs_value<j>() =
950 constexpr int i = row_idx;
951 const T lhs_value = fragments.template lhs_value<i>();
953 constexpr int j = col_idx;
954 accum.template get<i, j>() += lhs_value * fragments.template rhs_value<j>();
968 constexpr int i = row_idx;
969 const int row = row_base + i;
970 if (row >= row_extent) {
974 constexpr int j = col_idx;
975 const int col = col_base + j;
976 if (col >= col_extent) {
984template <
typename T,
typename Transform>
992 constexpr int i = row_idx;
993 const int row = row_base + i;
998 constexpr int j = col_idx;
999 const int col = col_base + j;
1003 T value = operand.
beta * operand.
c(row, col) + accum.template get<i, j>();
1005 if (transform.hermitian && row == col) {
1006 value = T(value.real(),
typename T::value_type(0));
1009 operand.
c(row, col) = value;
1014template <
typename T,
typename Transform>
1016 Transform transform,
1022 constexpr int i = row_idx;
1023 const int row = row_base + i;
1024 if (row >= extent) {
1028 constexpr int j = col_idx;
1029 const int col = col_base + j;
1033 T value = operand.
beta * operand.
c(row, col) + accum.template get<i, j>();
1035 if (transform.hermitian && row == col) {
1036 value = T(value.real(),
typename T::value_type(0));
1039 operand.
c(row, col) = value;
1044template <
typename Item,
typename T,
typename LhsLoader,
typename RhsLoader>
1049 int contract_extent,
1050 LhsLoader&& lhs_loader,
1051 RhsLoader&& rhs_loader,
1054 if (tile_count <= 0) {
1070 sycl::group_barrier(item.get_group());
1072 for (
int tile_idx = 0; tile_idx < tile_count; ++tile_idx) {
1074 const int current_tile_extent = std::min(
kRegisterMatrixTileK, contract_extent - current_k_base);
1075 const int next_tile_idx = tile_idx + 1;
1079 if (next_tile_idx < tile_count) {
1105 current_tile_extent,
1108 if (next_tile_idx < tile_count) {
1112 sycl::group_barrier(item.get_group());
1114 sycl::group_barrier(item.get_sub_group());
1128 sycl::group_barrier(item.get_group());
1132 sycl::group_barrier(item.get_group());
1135template <
int TileK,
int TileAStr
ide,
typename Workspace,
typename Item,
typename T,
typename LhsLoader,
typename RhsLoader>
1137 Workspace* workspace,
1142 int contract_extent,
1143 LhsLoader&& lhs_loader,
1144 RhsLoader&& rhs_loader,
1146 const auto sg = item.get_sub_group();
1152 const int rhs_source_lane_base = sg_col;
1154 T* lhs_tile = workspace->lhs[subgroup_id];
1155 T* rhs_tile = workspace->rhs;
1157 for (
int k_base = 0; k_base < contract_extent; k_base += TileK) {
1158 const int tile_extent = std::min(TileK, contract_extent - k_base);
1161 const int subgroup_tile_r = index / TileK;
1162 const int tile_k = index % TileK;
1164 lhs_tile[subgroup_tile_r * TileAStride + tile_k] =
1165 tile_k < tile_extent ? lhs_loader(tile_r, k_base + tile_k) : T(0);
1171 tile_k < tile_extent ? rhs_loader(tile_c, k_base + tile_k) : T(0);
1173 sycl::group_barrier(item.get_group());
1175 for (
int kk = 0; kk < tile_extent; ++kk) {
1176 std::array<T, kComplexRank2kThreadTileRows> lhs_frag{};
1177 std::array<T, kComplexRank2kThreadTileCols> rhs_frag{};
1180 constexpr int i = row_idx;
1181 const T lhs_lane = sg_col == 0 ? lhs_tile[(lhs_row_base + i) * TileAStride + kk] : T(0);
1182 lhs_frag[
static_cast<std::size_t
>(i)] =
1187 constexpr int j = col_idx;
1189 rhs_frag[
static_cast<std::size_t
>(j)] =
1194 constexpr int i = row_idx;
1195 const T lhs_value = lhs_frag[
static_cast<std::size_t
>(i)];
1197 constexpr int j = col_idx;
1198 accum.template get<i, j>() += lhs_value * rhs_frag[
static_cast<std::size_t
>(j)];
1203 sycl::group_barrier(item.get_group());
A std::complex scalar (std::complex<float>, std::complex<double>).
DeviceBlasPolicy
Which implementation family a device BLAS call may use.
@ Subgroup16
fast paths only when the actual sub-group size is 16
@ Auto
any eligible path; the sub-group fast paths accept sub-group size 16 or 32
@ Subgroup32
fast paths only when the actual sub-group size is 32
@ Generic
the portable group-reduction path only; never stages through local memory
@ NdItem3D
the call receives a sycl::nd_item<3> whose dimensions 1 and 2 index output tiles
Transpose
The operator op() applied to an operand: op(A) = A, A^T or A^H.
Side
Side on which a special operand multiplies: op(A) * B or B * op(A).
@ Lower
The lower triangle (i >= j).
@ 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 bool can_use_rankk_register_fast_path(const Item &item, int extent, int contract_extent, DeviceBlasPolicy policy)
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 kMaxMatrixRowsPerSubgroup
constexpr int triangular_begin(int index, int extent, TriangularTransform transform, Side side)
constexpr int kComplexRank2kTileN
constexpr int kComplexRank2kInKernelTileAStride
constexpr int kOptimizedGemmVecA
constexpr bool can_use_rank2k_register_fast_path(const Item &item, int extent, int contract_extent, DeviceBlasPolicy policy)
constexpr int kComplexRank2kTileAStride
constexpr bool register_matrix_workspace_supported_v
constexpr int kRegisterMatrixTileN
constexpr int triangular_end(int index, int extent, TriangularTransform transform, Side side)
constexpr void static_for_impl(Fn &&fn, std::index_sequence< I... >)
constexpr int kRegisterMatrixSubgroupTileM
constexpr int kComplexRank2kInKernelWorkspaceMaxSubgroupsPerWorkGroup
constexpr int subgroup_group_id(const Item &item)
constexpr int kRegisterMatrixTileK
constexpr int kOptimizedGemmTileAStride
constexpr int matrix_tile_group_row(const Item &)
constexpr int kOptimizedGemmThreadsPerGroup
constexpr std::size_t kSubgroupWorkspaceBudgetBytes
constexpr int kOptimizedGemmStageASize
constexpr int kRegisterMatrixLocalCols
constexpr bool supports_packet4_v
constexpr void accumulate_rank2k_register_tiled_pass(const Item &item, RegisterMatrixWorkspace< T > *workspace, int linear_tid, int subgroup_id, int contract_extent, LhsLoader &&lhs_loader, RhsLoader &&rhs_loader, RegisterMatrixAccumTile< T > &accum)
constexpr int kOptimizedGemmStages
constexpr bool subgroup_policy_matches(DeviceBlasPolicy policy, int actual_size)
constexpr bool supports_aligned_packet_loads(const T *ptr, int ld, int stride)
constexpr bool complex_rank2k_in_kernel_workspace_supported_v
constexpr int subgroup_size(const Item &item)
constexpr int kRegisterMatrixRhsStages
constexpr int kRegisterMatrixLocalRows
constexpr int kComplexRank2kInKernelTileK
constexpr int kComplexRank2kTileK
constexpr bool complex_rank2k_workspace_supported_v
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 kRegisterMatrixSubgroupRows
constexpr int kRegisterMatrixLhsStages
constexpr int kComplexRank2kThreadTileCols
constexpr int kOptimizedGemmTileBStride
constexpr int kComplexRank2kThreadTileRows
constexpr int kMaxSupportedSubgroupSize
constexpr int kRegisterMatrixThreadTileRows
constexpr int kComplexRank2kSubgroupTileM
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 int kOptimizedGemmLocalRows
constexpr bool optimized_gemm_workspace_supported_v
constexpr int matrix_tile_group_row_stride(const Item &)
constexpr int kComplexRank2kWorkspaceMaxSubgroupsPerWorkGroup
constexpr int kComplexRank2kTileBStride
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 &)
std::conditional_t< supports_packet_v< T, Width >, sycl::vec< T, Width >, PacketArray< T, Width > > Packet
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 bool can_use_complex_rank2k_tiled_fast_path(const Item &item, int extent, int contract_extent, DeviceBlasPolicy policy)
constexpr int kOptimizedGemmTileN
constexpr int rows_per_subgroup(int extent, int total_sg, int max_rows)
constexpr int kRegisterMatrixTileM
constexpr int kOptimizedGemmThreadTileCols
constexpr void accumulate_complex_rank2k_tiled_pass_impl(const Item &item, Workspace *workspace, int linear_tid, int subgroup_id, int local_row, int local_col, int contract_extent, LhsLoader &&lhs_loader, RhsLoader &&rhs_loader, ComplexRank2kAccumTile< T > &accum)
constexpr int kOptimizedGemmTileK
constexpr int kComplexRank2kLocalCols
constexpr int kRegisterMatrixThreadsPerGroup
constexpr int kComplexRank2kSubgroupRows
constexpr int kComplexRank2kThreadsPerGroup
constexpr int kRegisterMatrixTileAStride
constexpr int kComplexRank2kTileM
constexpr int kComplexRank2kLocalRows
constexpr int kOptimizedGemmTileM
constexpr int subgroup_local_id(const Item &item)
constexpr int triangular_tile_end(int row_base, int row_extent, int col_base, int col_extent, int contract_extent, TriangularTransform transform)
constexpr int kMaxSubgroupsPerWorkGroup
constexpr Packet< T, Width > packet_load_aligned(const T *ptr, int offset)
constexpr int subgroup_limit_for_workspace_v
constexpr bool supports_packet_v
constexpr void write_rank2k_register_tile(MatrixMatrixOperand< T > operand, Transform transform, int row_base, int col_base, int extent, const RegisterMatrixAccumTile< T > &accum)
constexpr int kOptimizedGemmVecB
constexpr bool can_use_complex_rankk_tiled_fast_path(const Item &item, int extent, int contract_extent, DeviceBlasPolicy policy)
constexpr int kRegisterMatrixTileBStride
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 triangular_tile_begin(int row_base, int row_extent, int col_base, int col_extent, int contract_extent, TriangularTransform transform)
constexpr bool is_nd_item_3d_launch(const Exec &)
constexpr int subgroup_count(const Item &item)
constexpr void write_complex_rank2k_tile(MatrixMatrixOperand< T > operand, Transform transform, int row_base, int col_base, int extent, const ComplexRank2kAccumTile< T > &accum)
constexpr int kRegisterMatrixThreadTileCols
constexpr bool gemm_workspace_supported_v
constexpr int kRegisterMatrixWorkspaceMaxSubgroupsPerWorkGroup
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 input_size(const KernelMatrixView< T, MatrixFormat::Dense > &a, Transpose trans)
constexpr int group_local_linear_range(const Group &group)
constexpr int item_local_linear_id(const Item &item)
constexpr bool triangular_storage_contains(int row, int col)
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).
auto stride() const
Dense batch stride, in elements.
Host-side description of a launch, for the *_workspace_elements queries.
DeviceBlasLaunchKind kind
executor the call receives
int subgroup_size
sub-group size of the kernel; 1 for DeviceBlasLaunchKind::Group
Operands of a matrix-matrix operation: .
KernelMatrixView< T, MatrixFormat::Dense > c
output matrix; read (scaled by beta) and overwritten
T beta
scale of the input C; 0 still reads C
KernelMatrixView< T, MatrixFormat::Dense > b
second input matrix
Operands of a rank-k update: .
KernelMatrixView< T, MatrixFormat::Dense > c
square output; only the uplo triangle is touched
constexpr const T & get() const
std::array< T, kComplexRank2kThreadTileRows *kComplexRank2kThreadTileCols > values
T rhs[kComplexRank2kInKernelTileK *kComplexRank2kTileBStride]
T lhs[kMaxSubgroups][kComplexRank2kSubgroupTileM *kComplexRank2kInKernelTileAStride]
static constexpr int kMaxSubgroups
T lhs[kMaxSubgroups][kComplexRank2kSubgroupTileM *kComplexRank2kTileAStride]
T rhs[kComplexRank2kTileK *kComplexRank2kTileBStride]
static constexpr int kMaxSubgroups
T rhs[kOptimizedGemmStages *kOptimizedGemmStageBSize]
T lhs[kOptimizedGemmStages *kOptimizedGemmStageASize]
constexpr const T & operator[](int i) const
constexpr const T & get() const
std::array< T, kRegisterMatrixThreadTileRows *kRegisterMatrixThreadTileCols > values
std::array< T, kRegisterMatrixThreadTileCols > rhs
constexpr T & rhs_value()
constexpr T & lhs_value()
constexpr const T & lhs_value() const
std::array< T, kRegisterMatrixThreadTileRows > lhs
constexpr const T & rhs_value() const
static constexpr int kMaxSubgroups
T rhs[kRegisterMatrixRhsStages][kRegisterMatrixTileK *kRegisterMatrixTileBStride]
T lhs[kMaxSubgroups][kRegisterMatrixLhsStages][kRegisterMatrixSubgroupTileM *kRegisterMatrixTileAStride]
RegisterMatrixWorkspace< T > register_workspace
OptimizedGemmWorkspace< T > optimized_workspace