55 BATCHLAS_KERNEL_TRACE_SCOPE(
"syrk_cuda_custom.triangular_tiles");
57 constexpr int TileM = kTriangularTile;
58 constexpr int TileN = kTriangularTile;
59 constexpr int TileK = kTriangularTileK;
60 constexpr int ThreadTile = 8;
61 constexpr int Band = ThreadTile / 2;
62 constexpr int LocalRows = TileM / ThreadTile;
63 constexpr int LocalCols = TileN / ThreadTile;
64 constexpr int Threads = LocalRows * LocalCols;
65 constexpr int AStride = TileM;
66 constexpr int BStride = TileN;
68 static_assert(TileM * TileK == 4 * Threads,
"staging assumes one packet per thread");
70 const int n =
static_cast<int>(C.
rows());
71 const int k = TransOperand ?
static_cast<int>(A.
rows()) :
static_cast<int>(A.
cols());
72 const int tile_count = triangular_tile_count(n);
74 const sycl::range<3> local(1, LocalRows, LocalCols);
75 const sycl::range<3> global(
static_cast<size_t>(A.
batch_size()),
76 static_cast<size_t>(tile_count * LocalRows),
77 static_cast<size_t>(LocalCols));
79 impl::check_group_count(*ctx, sycl::nd_range<3>(global, local));
80 ctx->submit([&](sycl::handler& h) {
81 sycl::local_accessor<T, 1> tile_a(sycl::range<1>(TileK * AStride), h);
82 sycl::local_accessor<T, 1> tile_b(sycl::range<1>(TileK * BStride), h);
86 const int lda = A.
ld();
87 const int ldc = C.
ld();
88 const int stride_a = A.
stride();
89 const int stride_c = C.
stride();
93 batchlas::impl::parallel_for<SyrkTriangularTilesKernel<T, TransOperand, AlignedFastPath>>(h,
94 sycl::nd_range<3>(global, local), [=](sycl::nd_item<3> item) {
95 const int bid =
static_cast<int>(item.get_group(0));
101 const int ty =
static_cast<int>(item.get_local_id(2));
102 const int tx =
static_cast<int>(item.get_local_id(1));
103 const int tid = tx * LocalRows + ty;
107 triangular_tile_decode(
static_cast<int>(item.get_group(1)), bi, bj);
108 const bool on_diagonal = bi == bj;
110 const int m0 = (lower ? bi : bj) * TileM;
111 const int n0 = (lower ? bj : bi) * TileN;
113 const T* Ab = a_ptr +
static_cast<std::ptrdiff_t
>(bid) * stride_a;
114 T* Cb = c_ptr +
static_cast<std::ptrdiff_t
>(bid) * stride_c;
116 T* sa = tile_a.template get_multi_ptr<sycl::access::decorated::no>().get();
117 T* sb = tile_b.template get_multi_ptr<sycl::access::decorated::no>().get();
119 T accum[ThreadTile][ThreadTile];
121 for (
int i = 0; i < ThreadTile; ++i) {
123 for (
int j = 0; j < ThreadTile; ++j) {
132 const int s_row = TransOperand ? tid / 2 : (tid % 32) * 4;
133 const int s_l = TransOperand ? (tid % 2) * 4 : tid / 32;
135 for (
int k0 = 0; k0 < k; k0 += TileK) {
136 if constexpr (AlignedFastPath) {
137 if constexpr (TransOperand) {
138 const TileVec4<T> va =
139 tile_vec4(Ab + (k0 + s_l) +
140 static_cast<std::ptrdiff_t
>(m0 + s_row) * lda);
141 const TileVec4<T> vb =
142 tile_vec4(Ab + (k0 + s_l) +
143 static_cast<std::ptrdiff_t
>(n0 + s_row) * lda);
145 for (
int i = 0; i < 4; ++i) {
146 sa[(s_l + i) * AStride + s_row] = va.v[i];
147 sb[(s_l + i) * BStride + s_row] = vb.v[i];
150 tile_vec4(&sa[s_l * AStride + s_row]) =
151 tile_vec4(Ab + (m0 + s_row) +
152 static_cast<std::ptrdiff_t
>(k0 + s_l) * lda);
153 tile_vec4(&sb[s_l * BStride + s_row]) =
154 tile_vec4(Ab + (n0 + s_row) +
155 static_cast<std::ptrdiff_t
>(k0 + s_l) * lda);
161 if constexpr (TransOperand) {
162 const int gm = m0 + s_row;
163 const int gn = n0 + s_row;
165 for (
int i = 0; i < 4; ++i) {
166 const int gk = k0 + s_l + i;
167 sa[(s_l + i) * AStride + s_row] =
169 ? Ab[gk +
static_cast<std::ptrdiff_t
>(gm) * lda]
171 sb[(s_l + i) * BStride + s_row] =
173 ? Ab[gk +
static_cast<std::ptrdiff_t
>(gn) * lda]
177 const int gk = k0 + s_l;
179 for (
int i = 0; i < 4; ++i) {
180 const int gm = m0 + s_row + i;
181 const int gn = n0 + s_row + i;
182 sa[s_l * AStride + s_row + i] =
184 ? Ab[gm +
static_cast<std::ptrdiff_t
>(gk) * lda]
186 sb[s_l * BStride + s_row + i] =
188 ? Ab[gn +
static_cast<std::ptrdiff_t
>(gk) * lda]
193 item.barrier(sycl::access::fence_space::local_space);
196 for (
int kk = 0; kk < TileK; ++kk) {
197 const TileVec4<T> a0 = tile_vec4(&sa[kk * AStride + ty * Band]);
198 const TileVec4<T> a1 = tile_vec4(&sa[kk * AStride + 64 + ty * Band]);
199 const TileVec4<T> b0 = tile_vec4(&sb[kk * BStride + tx * Band]);
200 const TileVec4<T> b1 = tile_vec4(&sb[kk * BStride + 64 + tx * Band]);
201 const T af[ThreadTile] = {a0.v[0], a0.v[1], a0.v[2], a0.v[3],
202 a1.v[0], a1.v[1], a1.v[2], a1.v[3]};
203 const T bf[ThreadTile] = {b0.v[0], b0.v[1], b0.v[2], b0.v[3],
204 b1.v[0], b1.v[1], b1.v[2], b1.v[3]};
206 for (
int i = 0; i < ThreadTile; ++i) {
208 for (
int j = 0; j < ThreadTile; ++j) {
209 accum[i][j] += af[i] * bf[j];
213 item.barrier(sycl::access::fence_space::local_space);
220 auto store_element = [&](
int row,
int col, T value) {
221 if (row >= n || col >= n) {
224 if (on_diagonal && (lower ? row < col : row > col)) {
227 T* p = &Cb[row +
static_cast<std::ptrdiff_t
>(col) * ldc];
228 *p = beta == T(0) ? alpha * value : alpha * value + beta * *p;
232 for (
int band = 0; band < 2; ++band) {
233 const int gm = m0 + band * 64 + ty * Band;
235 for (
int j = 0; j < ThreadTile; ++j) {
236 const int gn = n0 + (j < Band ? tx * Band + j : 64 + tx * Band + j - Band);
237 if constexpr (AlignedFastPath) {
239 T* p = &Cb[gm +
static_cast<std::ptrdiff_t
>(gn) * ldc];
243 for (
int i = 0; i < 4; ++i) {
244 out.v[i] = alpha * accum[band * Band + i][j];
247 const TileVec4<T> prior = tile_vec4(
const_cast<const T*
>(p));
249 for (
int i = 0; i < 4; ++i) {
250 out.v[i] = alpha * accum[band * Band + i][j] +
259 for (
int i = 0; i < 4; ++i) {
260 store_element(gm + i, gn, accum[band * Band + i][j]);