group_blas_trmm.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 trmm(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 = operand.c.rows();
17 const int col_extent = operand.c.cols();
18 const int contract_extent = Tag::side == Side::Left ? operand.b.rows() : operand.b.cols();
19 constexpr bool effective_lower = Tag::trans == Transpose::NoTrans ? Tag::uplo == Uplo::Lower : Tag::uplo == Uplo::Upper;
20
21 if constexpr (Tag::side == Side::Left) {
22 for (int row_step = 0; row_step < row_extent; ++row_step) {
23 const int row = effective_lower ? (row_extent - 1 - row_step) : row_step;
24 for (int col = 0; col < col_extent; ++col) {
25 T partial{};
26 for (int k = local_id; k < contract_extent; k += local_size) {
27 partial += detail::triangular_matrix_entry<Tag>(a, row, k) * operand.b(k, col);
28 }
29 partial = detail::reduce_sum_group(group, partial);
30 if (detail::group_is_leader(group)) {
31 detail::write_matrix_output(operand, row, col, partial);
32 }
33 }
34 }
35 return;
36 }
37
38 for (int col_step = 0; col_step < col_extent; ++col_step) {
39 const int col = effective_lower ? col_step : (col_extent - 1 - col_step);
40 for (int row = 0; row < row_extent; ++row) {
41 T partial{};
42 for (int k = local_id; k < contract_extent; k += local_size) {
43 partial += operand.b(row, k) * detail::triangular_matrix_entry<Tag>(a, k, col);
44 }
45 partial = detail::reduce_sum_group(group, partial);
46 if (detail::group_is_leader(group)) {
47 detail::write_matrix_output(operand, row, col, partial);
48 }
49 }
50 }
51}
52
53} // namespace detail::generic
54
55namespace detail::subgroup {
56
57template <typename Item, typename T>
58inline constexpr void trmm(const Item& item,
61 TriangularTransform transform) {
62 const auto sg = item.get_sub_group();
63 const int sg_size = subgroup_size(item);
64 const int lane = subgroup_local_id(item);
65 const int sg_id = subgroup_group_id(item);
66 const int total_sg = subgroup_count(item);
67 const int row_extent = operand.c.rows();
68 const int col_extent = operand.c.cols();
69 const int contract_extent = transform.side == Side::Left ? operand.b.rows() : operand.b.cols();
70 const int tile_k = matrix_tile_k(contract_extent, sg_size, transform.side);
71 const int rows_per_sg = matrix_rows_per_subgroup(row_extent, total_sg, sg_size, contract_extent, transform.side);
72 const int col_tiles = (col_extent + sg_size - 1) / sg_size;
73 const int row_tiles = (row_extent + rows_per_sg - 1) / rows_per_sg;
74
75 for (int linear_tile = sg_id; linear_tile < row_tiles * col_tiles; linear_tile += total_sg) {
76 const int tile_row = linear_tile / col_tiles;
77 const int tile_col = linear_tile % col_tiles;
78 const int base_row = tile_row * rows_per_sg;
79 const int base_col = tile_col * sg_size;
80 const int col = base_col + lane;
81 std::array<T, detail::subgroup::kMaxMatrixRowsPerSubgroup> partials{};
82 std::array<int, detail::subgroup::kMaxMatrixRowsPerSubgroup> begins{};
83 std::array<int, detail::subgroup::kMaxMatrixRowsPerSubgroup> ends{};
84 const int col_begin = transform.side == Side::Right && col < col_extent ?
85 triangular_begin(col, contract_extent, transform, Side::Right) :
86 0;
87 const int col_end = transform.side == Side::Right && col < col_extent ?
88 triangular_end(col, contract_extent, transform, Side::Right) :
89 0;
90
91 if (transform.side == Side::Left) {
92 for (int row_offset = 0; row_offset < rows_per_sg; ++row_offset) {
93 const int row = base_row + row_offset;
94 if (row >= row_extent) {
95 continue;
96 }
97 begins[static_cast<std::size_t>(row_offset)] = triangular_begin(row, contract_extent, transform, Side::Left);
98 ends[static_cast<std::size_t>(row_offset)] = triangular_end(row, contract_extent, transform, Side::Left);
99 }
100 }
101
102 for (int k_base = 0; k_base < contract_extent; k_base += tile_k) {
103 const int tile_extent = std::min(tile_k, contract_extent - k_base);
104
105 if (transform.side == Side::Left) {
106 for (int tile_offset = 0; tile_offset < tile_extent; ++tile_offset) {
107 const int k = k_base + tile_offset;
108 const T b_value = col < col_extent ? operand.b(k, col) : T(0);
109 for (int row_offset = 0; row_offset < rows_per_sg; ++row_offset) {
110 const int row = base_row + row_offset;
111 if (row >= row_extent || col >= col_extent) {
112 continue;
113 }
114 if (k < begins[static_cast<std::size_t>(row_offset)] || k >= ends[static_cast<std::size_t>(row_offset)]) {
115 continue;
116 }
117 const T a_lane = lane == row_offset ? detail::triangular_matrix_entry(a, row, k, transform) : T(0);
118 const T a_value = batchlas::portable::select_from_group(sg, a_lane, static_cast<uint32_t>(row_offset));
119 partials[static_cast<std::size_t>(row_offset)] += a_value * b_value;
120 }
121 }
122 } else {
123 for (int tile_offset = 0; tile_offset < tile_extent; ++tile_offset) {
124 const int k = k_base + tile_offset;
125 if (k < col_begin || k >= col_end) {
126 continue;
127 }
128 const T a_value = col < col_extent ? detail::triangular_matrix_entry(a, k, col, transform) : T(0);
129 for (int row_offset = 0; row_offset < rows_per_sg; ++row_offset) {
130 const int row = base_row + row_offset;
131 const T b_lane = row < row_extent && lane == row_offset ? operand.b(row, k) : T(0);
132 const T b_value = batchlas::portable::select_from_group(sg, b_lane, static_cast<uint32_t>(row_offset));
133 if (row >= row_extent || col >= col_extent) {
134 continue;
135 }
136 partials[static_cast<std::size_t>(row_offset)] += b_value * a_value;
137 }
138 }
139 }
140 }
141
142 if (col < col_extent) {
143 for (int row_offset = 0; row_offset < rows_per_sg; ++row_offset) {
144 const int row = base_row + row_offset;
145 if (row >= row_extent) {
146 continue;
147 }
148 detail::write_matrix_output(operand, row, col, partials[static_cast<std::size_t>(row_offset)]);
149 }
150 }
151 }
152}
153
154template <typename Item, typename T>
155inline constexpr void trmm_register_tiled(const Item& item,
158 TriangularTransform transform,
159 RegisterMatrixWorkspace<T>* workspace) {
160 const int linear_tid = detail::item_local_linear_id(item);
161 const int subgroup_id = subgroup_group_id(item);
162 const int local_row = linear_tid / kRegisterMatrixLocalCols;
163 const int local_col = linear_tid % kRegisterMatrixLocalCols;
164 const int row_extent = operand.c.rows();
165 const int col_extent = operand.c.cols();
166 const int contract_extent = transform.side == Side::Left ? operand.b.rows() : operand.b.cols();
167 const int row_tiles = (row_extent + kRegisterMatrixTileM - 1) / kRegisterMatrixTileM;
168 const int col_tiles = (col_extent + kRegisterMatrixTileN - 1) / kRegisterMatrixTileN;
169 const int tile_row_start = matrix_tile_group_row(item);
170 const int tile_col_start = matrix_tile_group_col(item);
171 const int tile_row_stride = matrix_tile_group_row_stride(item);
172 const int tile_col_stride = matrix_tile_group_col_stride(item);
173 for (int tile_row = tile_row_start; tile_row < row_tiles; tile_row += tile_row_stride) {
174 for (int tile_col = tile_col_start; tile_col < col_tiles; tile_col += tile_col_stride) {
175 const int row_base = tile_row * kRegisterMatrixTileM + local_row * kRegisterMatrixThreadTileRows;
176 const int col_base = tile_col * kRegisterMatrixTileN + local_col * kRegisterMatrixThreadTileCols;
178 const int tile_contract_begin = triangular_tile_begin(tile_row * kRegisterMatrixTileM,
179 row_extent,
180 tile_col * kRegisterMatrixTileN,
181 col_extent,
182 contract_extent,
183 transform);
184 const int tile_contract_end = triangular_tile_end(tile_row * kRegisterMatrixTileM,
185 row_extent,
186 tile_col * kRegisterMatrixTileN,
187 col_extent,
188 contract_extent,
189 transform);
190
191 const int tile_count = std::max(0, (tile_contract_end - tile_contract_begin + kRegisterMatrixTileK - 1) / kRegisterMatrixTileK);
192 if (tile_count > 0) {
193 auto lhs_loader = [&](int tile_r, int global_k) {
194 const int global_row = tile_row * kRegisterMatrixTileM + tile_r;
195 if (global_row >= row_extent) {
196 return T(0);
197 }
198 return transform.side == Side::Left ?
199 detail::triangular_matrix_entry(a, global_row, global_k, transform) :
200 operand.b(global_row, global_k);
201 };
202 auto rhs_loader = [&](int tile_c, int global_k) {
203 const int global_col = tile_col * kRegisterMatrixTileN + tile_c;
204 if (global_col >= col_extent) {
205 return T(0);
206 }
207 return transform.side == Side::Left ?
208 operand.b(global_k, global_col) :
209 detail::triangular_matrix_entry(a, global_k, global_col, transform);
210 };
211
213 workspace,
214 linear_tid,
215 subgroup_id,
216 0,
217 0,
218 true,
219 true,
220 tile_contract_begin,
221 std::min(kRegisterMatrixTileK, tile_contract_end - tile_contract_begin),
222 lhs_loader,
223 rhs_loader);
224 sycl::group_barrier(item.get_group());
225
226 for (int tile_idx = 0; tile_idx < tile_count; ++tile_idx) {
227 const int next_tile_idx = tile_idx + 1;
228 const int current_k_base = tile_contract_begin + tile_idx * kRegisterMatrixTileK;
229 const int current_tile_extent = std::min(kRegisterMatrixTileK, tile_contract_end - current_k_base);
230 const int current_lhs_stage = register_matrix_lhs_stage(tile_idx);
231 const int current_rhs_stage = register_matrix_rhs_stage(tile_idx);
232
233 if (next_tile_idx < tile_count) {
234 const int next_k_base = tile_contract_begin + next_tile_idx * kRegisterMatrixTileK;
235 const int next_tile_extent = std::min(kRegisterMatrixTileK, tile_contract_end - next_k_base);
236 if constexpr (kRegisterMatrixRhsStages > 1) {
238 workspace,
239 linear_tid,
240 subgroup_id,
241 current_lhs_stage,
242 register_matrix_rhs_stage(next_tile_idx),
243 false,
245 next_k_base,
246 next_tile_extent,
247 lhs_loader,
248 rhs_loader);
249 }
250 }
251
253 workspace,
254 subgroup_id,
255 current_lhs_stage,
256 current_rhs_stage,
257 local_row,
258 local_col,
259 current_tile_extent,
260 accum);
261
262 if (next_tile_idx < tile_count) {
263 const int next_k_base = tile_contract_begin + next_tile_idx * kRegisterMatrixTileK;
264 const int next_tile_extent = std::min(kRegisterMatrixTileK, tile_contract_end - next_k_base);
265 if constexpr (kRegisterMatrixRhsStages == 1) {
266 sycl::group_barrier(item.get_group());
267 } else {
268 sycl::group_barrier(item.get_sub_group());
269 }
271 workspace,
272 linear_tid,
273 subgroup_id,
274 0,
275 kRegisterMatrixRhsStages == 1 ? 0 : register_matrix_rhs_stage(next_tile_idx),
276 true,
278 next_k_base,
279 next_tile_extent,
280 lhs_loader,
281 rhs_loader);
282 sycl::group_barrier(item.get_group());
283 }
284 }
285 }
286
287 write_register_matrix_tile(operand, row_base, col_base, row_extent, col_extent, accum);
288 }
289 }
290}
291
292} // namespace detail::subgroup
293
294namespace detail {
295
296template <typename Tag, DeviceBlasPolicy Policy, typename T>
297inline constexpr std::size_t trmm_workspace_elements(const DeviceBlasLaunchInfo& launch,
298 int row_extent,
299 int col_extent,
300 bool aliased = false) {
301 assert(row_extent >= 0 && col_extent >= 0 && "device::trmm workspace query expects non-negative matrix extents");
302 if (aliased || !detail::subgroup::is_nd_item_3d_launch(launch)) {
303 return 0;
304 }
305
306 const int contract_extent = Tag::side == Side::Left ? row_extent : col_extent;
307 if (detail::subgroup::can_use_matrix_register_fast_path<T>(launch, row_extent, col_extent, contract_extent, Policy)) {
309 }
310 return 0;
311}
312
313template <typename Tag, DeviceBlasPolicy Policy, typename Exec, typename T>
314inline constexpr void dispatch_trmm(const Exec& exec,
317 T* workspace = nullptr) {
318 const TriangularTransform transform{.side = Tag::side, .uplo = Tag::uplo, .trans = Tag::trans, .diag = Tag::diag};
319 validate_triangular_operand(a, operand, transform);
320 const bool aliased = detail::views_overlap(operand.b, operand.c);
321
322 if constexpr (detail::NdItemLike<Exec>) {
323 const int row_extent = operand.c.rows();
324 const int col_extent = operand.c.cols();
325 const int contract_extent = transform.side == Side::Left ? operand.b.rows() : operand.b.cols();
326 auto* register_workspace = workspace == nullptr ? nullptr : detail::workspace_ptr_cast<detail::subgroup::RegisterMatrixWorkspace<T>>(workspace);
327 if (!aliased && register_workspace != nullptr &&
328 detail::subgroup::can_use_matrix_register_fast_path<T>(exec, row_extent, col_extent, contract_extent, Policy) &&
329 std::same_as<std::remove_cvref_t<Exec>, sycl::nd_item<3>>) {
330 detail::subgroup::trmm_register_tiled(exec, a, operand, transform, register_workspace);
331 return;
332 }
333 if (!aliased && detail::subgroup::can_use_matrix_fast_path<T>(exec, row_extent, col_extent, contract_extent, Policy)) {
334 detail::subgroup::trmm(exec, a, operand, transform);
335 return;
336 }
337 }
338
339 generic::trmm<Tag>(exec, a, operand);
340}
341
342} // namespace detail
343
344/// @addtogroup api_device_blas
345/// @{
346
347/// @brief Triangular matrix-matrix product \f$ C := \alpha\,\mathrm{op}(A)\,B + \beta\,C \f$ (Left) or \f$ C := \alpha\,B\,\mathrm{op}(A) + \beta\,C \f$ (Right).
348///
349/// Unlike BLAS `trmm` it has a separate output and a `beta`. `B` and `C` may
350/// overlap: the generic path orders its traversal so no entry is overwritten
351/// before it is read, and overlap disables both fast paths. The fast paths
352/// (`float`, an `nd_item` executor; the register-tiled one also an
353/// `nd_item<3>`, 256 work-items and a workspace) are otherwise as for gemm().
354/// @tparam SideV side `A` multiplies from
355/// @tparam UploV stored triangle of `A`
356/// @tparam TransV op() applied to `A`
357/// @tparam DiagV `Unit`: the diagonal is taken as 1
358/// @tparam Group `sycl::group`, `sycl::sub_group` or an `nd_item`; every work-item must call
359/// @param group executor
360/// @param a single square triangular matrix, order `B.rows()` (Left) or `B.cols()` (Right)
361/// @param operand `B`, `C` (same shape as `B`), `alpha`, `beta`
362/// @param workspace local memory of trmm_workspace_elements() elements, or `nullptr`
363/// @pre `C` holds finite values even when `beta == 0`.
364/// @note On the generic path each `C` element is written by the group leader; barrier before other work-items read `C`.
365template <Side SideV = Side::Left,
366 Uplo UploV = Uplo::Upper,
368 Diag DiagV = Diag::NonUnit,
369 typename Group,
370 typename T>
371inline constexpr void trmm(const Group& group,
374 T* workspace = nullptr) {
376}
377
378/// @brief As trmm(), with an explicit DeviceBlasPolicy.
379template <DeviceBlasPolicy Policy,
380 Side SideV = Side::Left,
381 Uplo UploV = Uplo::Upper,
383 Diag DiagV = Diag::NonUnit,
384 typename Group,
385 typename T>
386inline constexpr void trmm(const Group& group,
389 T* workspace = nullptr) {
391}
392
393/// @brief Local memory, in elements of `T`, that trmm() can use for this launch and shape.
394///
395/// Nonzero only for an `nd_item<3>` launch description whose shape admits the
396/// register-tiled path. When the result is 0 pass `nullptr`.
397/// @trap `T` is the LAST template parameter here, after the four mode parameters,
398/// unlike every other `*_workspace_elements` and unlike the policy overload.
399/// @param launch description of the launch the call runs in
400/// @param row_extent rows of `C`
401/// @param col_extent columns of `C`
402/// @param aliased `B` and `C` overlap; the call then takes no staged path, so this returns 0
403/// @return element count, or 0 when no staged path applies
404/// @ingroup api_device_blas_lowlevel
405template <Side SideV = Side::Left,
406 Uplo UploV = Uplo::Upper,
408 Diag DiagV = Diag::NonUnit,
409 typename T>
410inline constexpr std::size_t trmm_workspace_elements(const DeviceBlasLaunchInfo& launch,
411 int row_extent,
412 int col_extent,
413 bool aliased = false) {
415}
416
417/// @brief Local memory, in elements of `T`, that trmm() can use under `Policy`; 0 means pass `nullptr`.
418/// @param launch description of the launch the call runs in
419/// @param row_extent rows of `C`
420/// @param col_extent columns of `C`
421/// @param aliased `B` and `C` overlap; the call then takes no staged path, so this returns 0
422/// @return element count, or 0 when no staged path applies
423/// @ingroup api_device_blas_lowlevel
424template <typename T,
426 Side SideV = Side::Left,
427 Uplo UploV = Uplo::Upper,
429 Diag DiagV = Diag::NonUnit>
430inline constexpr std::size_t trmm_workspace_elements(const DeviceBlasLaunchInfo& launch,
431 int row_extent,
432 int col_extent,
433 bool aliased = false) {
435}
436
437/// @brief As trmm(), with the operands passed separately instead of in an operand struct.
438template <Side SideV = Side::Left,
439 Uplo UploV = Uplo::Upper,
441 Diag DiagV = Diag::NonUnit,
442 typename Group,
443 typename T>
444inline constexpr void trmm(const Group& group,
448 T alpha = T(1),
449 T beta = T(0),
450 T* workspace = nullptr) {
451 trmm<SideV, UploV, TransV, DiagV>(group, a, make_matmat_operand(b, c, alpha, beta), workspace);
452}
453
454/// @brief As trmm(), with an explicit DeviceBlasPolicy and the operands passed separately.
455template <DeviceBlasPolicy Policy,
456 Side SideV = Side::Left,
457 Uplo UploV = Uplo::Upper,
459 Diag DiagV = Diag::NonUnit,
460 typename Group,
461 typename T>
462inline constexpr void trmm(const Group& group,
466 T alpha = T(1),
467 T beta = T(0),
468 T* workspace = nullptr) {
469 trmm<Policy, SideV, UploV, TransV, DiagV>(group, a, make_matmat_operand(b, c, alpha, beta), workspace);
470}
471
472/// @}
473
474} // namespace batchlas::device
Policy
Synchronous or asynchronous execution policy.
constexpr std::size_t trmm_workspace_elements(const DeviceBlasLaunchInfo &launch, int row_extent, int col_extent, bool aliased=false)
Local memory, in elements of T, that trmm() 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 trmm(const Group &group, const KernelMatrixView< T, MatrixFormat::Dense > &a, MatrixMatrixOperand< T > operand, T *workspace=nullptr)
Triangular matrix-matrix product (Left) or (Right).
@ 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
Diag
Whether a triangular operand's diagonal is read or assumed to be one.
Definition enums.hh:303
Uplo
Which triangle of a symmetric, Hermitian or triangular operand is referenced.
Definition enums.hh:287
Side
Side on which a special operand multiplies: op(A) * B or B * op(A).
Definition enums.hh:319
@ NoTrans
op(A) = A.
Definition enums.hh:172
@ NonUnit
The stored diagonal is used.
Definition enums.hh:304
@ Upper
The upper triangle (i <= j).
Definition enums.hh:288
@ Lower
The lower triangle (i >= j).
Definition enums.hh:289
@ Right
The special operand is on the right.
Definition enums.hh:321
@ 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 trmm(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 void trmm(const Item &item, const KernelMatrixView< T, MatrixFormat::Dense > &a, MatrixMatrixOperand< T > operand, TriangularTransform transform)
constexpr int triangular_begin(int index, int extent, TriangularTransform transform, Side side)
constexpr int triangular_end(int index, int extent, TriangularTransform transform, Side side)
constexpr int subgroup_group_id(const Item &item)
constexpr int matrix_tile_group_row(const Item &)
constexpr void trmm_register_tiled(const Item &item, const KernelMatrixView< T, MatrixFormat::Dense > &a, MatrixMatrixOperand< T > operand, TriangularTransform transform, RegisterMatrixWorkspace< T > *workspace)
constexpr int subgroup_size(const Item &item)
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 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 int triangular_tile_end(int row_base, int row_extent, int col_base, int col_extent, int contract_extent, TriangularTransform transform)
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 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 dispatch_trmm(const Exec &exec, const KernelMatrixView< T, MatrixFormat::Dense > &a, MatrixMatrixOperand< T > operand, T *workspace=nullptr)
constexpr std::size_t trmm_workspace_elements(const DeviceBlasLaunchInfo &launch, int row_extent, int col_extent, bool aliased=false)
constexpr bool views_overlap(const VectorView< T > &lhs, const VectorView< T > &rhs)
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 T triangular_matrix_entry(const KernelMatrixView< T, MatrixFormat::Dense > &a, int row, int col)
constexpr int group_local_linear_range(const Group &group)
constexpr Workspace * workspace_ptr_cast(T *workspace)
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 validate_triangular_operand(const KernelMatrixView< T, MatrixFormat::Dense > &a, const MatrixVectorOperand< T > &operand, TriangularTransform transform)
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 rows() const
Row count (the capacity on a heterogeneous batch).
Definition matrix.hh:219
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.
Operands of a matrix-matrix operation: .
KernelMatrixView< T, MatrixFormat::Dense > c
output matrix; read (scaled by beta) and overwritten
KernelMatrixView< T, MatrixFormat::Dense > b
second input matrix
Mode of a triangular product (trmv, trmm).
Side side
A multiplies from the left or the right