60 BATCHLAS_KERNEL_TRACE_SCOPE(
"syr2k_cuda_custom.triangular_tiles");
62 constexpr int TileM = kTriangularTile;
63 constexpr int TileN = kTriangularTile;
64 constexpr int TileK = kTriangularTileK;
65 constexpr int ThreadTile = 8;
66 constexpr int Band = ThreadTile / 2;
67 constexpr int LocalRows = TileM / ThreadTile;
68 constexpr int LocalCols = TileN / ThreadTile;
69 constexpr int Threads = LocalRows * LocalCols;
70 constexpr int Stride = TileM;
72 static_assert(TileM * TileK == 4 * Threads,
"staging assumes one vector per thread");
74 const int n =
static_cast<int>(C.
rows());
75 const int k = TransOperand ?
static_cast<int>(A.
rows()) :
static_cast<int>(A.
cols());
76 const int tile_count = triangular_tile_count(n);
78 const sycl::range<3> local(1, LocalRows, LocalCols);
79 const sycl::range<3> global(
static_cast<size_t>(A.
batch_size()),
80 static_cast<size_t>(tile_count * LocalRows),
81 static_cast<size_t>(LocalCols));
83 impl::check_group_count(*ctx, sycl::nd_range<3>(global, local));
84 ctx->submit([&](sycl::handler& h) {
85 sycl::local_accessor<T, 1> tiles(sycl::range<1>(4 * TileK *
Stride), h);
90 const int lda = A.
ld();
91 const int ldb = B.
ld();
92 const int ldc = C.
ld();
93 const int stride_a = A.
stride();
94 const int stride_b = B.
stride();
95 const int stride_c = C.
stride();
99 batchlas::impl::parallel_for<Syr2kTriangularTilesKernel<T, TransOperand, AlignedFastPath>>(h,
100 sycl::nd_range<3>(global, local), [=](sycl::nd_item<3> item) {
101 const int bid =
static_cast<int>(item.get_group(0));
107 const int ty =
static_cast<int>(item.get_local_id(2));
108 const int tx =
static_cast<int>(item.get_local_id(1));
109 const int tid = tx * LocalRows + ty;
113 triangular_tile_decode(
static_cast<int>(item.get_group(1)), bi, bj);
114 const bool on_diagonal = bi == bj;
116 const int m0 = (lower ? bi : bj) * TileM;
117 const int n0 = (lower ? bj : bi) * TileN;
119 const T* Ab = a_ptr +
static_cast<std::ptrdiff_t
>(bid) * stride_a;
120 const T* Bb = b_ptr +
static_cast<std::ptrdiff_t
>(bid) * stride_b;
121 T* Cb = c_ptr +
static_cast<std::ptrdiff_t
>(bid) * stride_c;
123 T* shared = tiles.template get_multi_ptr<sycl::access::decorated::no>().get();
125 T* sbm = shared + TileK *
Stride;
126 T* san = on_diagonal ? sam : shared + 2 * TileK *
Stride;
127 T* sbn = on_diagonal ? sbm : shared + 3 * TileK *
Stride;
129 T accum[ThreadTile][ThreadTile];
131 for (
int i = 0; i < ThreadTile; ++i) {
133 for (
int j = 0; j < ThreadTile; ++j) {
142 const int s_row = TransOperand ? tid / 2 : (tid % 32) * 4;
143 const int s_l = TransOperand ? (tid % 2) * 4 : tid / 32;
145 for (
int k0 = 0; k0 < k; k0 += TileK) {
149 auto stage = [&](
const T* src,
int ld, T* dst,
int row0) {
150 if constexpr (TransOperand) {
151 const int row = row0 + s_row;
152 if constexpr (AlignedFastPath) {
153 const TileVec4<T> v =
154 tile_vec4(src + (k0 + s_l) +
155 static_cast<std::ptrdiff_t
>(row) * ld);
157 for (
int i = 0; i < 4; ++i) {
158 dst[(s_l + i) *
Stride + s_row] = v.v[i];
162 for (
int i = 0; i < 4; ++i) {
163 const int gk = k0 + s_l + i;
164 dst[(s_l + i) *
Stride + s_row] =
166 ? src[gk +
static_cast<std::ptrdiff_t
>(row) * ld]
171 const int gk = k0 + s_l;
172 if constexpr (AlignedFastPath) {
173 tile_vec4(&dst[s_l *
Stride + s_row]) =
174 tile_vec4(src + (row0 + s_row) +
175 static_cast<std::ptrdiff_t
>(gk) * ld);
178 for (
int i = 0; i < 4; ++i) {
179 const int row = row0 + s_row + i;
180 dst[s_l *
Stride + s_row + i] =
182 ? src[row +
static_cast<std::ptrdiff_t
>(gk) * ld]
189 stage(Ab, lda, sam, m0);
190 stage(Bb, ldb, sbm, m0);
192 stage(Ab, lda, san, n0);
193 stage(Bb, ldb, sbn, n0);
195 item.barrier(sycl::access::fence_space::local_space);
198 for (
int kk = 0; kk < TileK; ++kk) {
200 for (
int product = 0; product < 2; ++product) {
201 const T* srow = product == 0 ? sam : sbm;
202 const T* scol = product == 0 ? sbn : san;
203 const TileVec4<T> r0 = tile_vec4(&srow[kk *
Stride + ty * Band]);
204 const TileVec4<T> r1 = tile_vec4(&srow[kk *
Stride + 64 + ty * Band]);
205 const TileVec4<T> c0 = tile_vec4(&scol[kk *
Stride + tx * Band]);
206 const TileVec4<T> c1 = tile_vec4(&scol[kk *
Stride + 64 + tx * Band]);
207 const T rf[ThreadTile] = {r0.v[0], r0.v[1], r0.v[2], r0.v[3],
208 r1.v[0], r1.v[1], r1.v[2], r1.v[3]};
209 const T cf[ThreadTile] = {c0.v[0], c0.v[1], c0.v[2], c0.v[3],
210 c1.v[0], c1.v[1], c1.v[2], c1.v[3]};
212 for (
int i = 0; i < ThreadTile; ++i) {
214 for (
int j = 0; j < ThreadTile; ++j) {
215 accum[i][j] += rf[i] * cf[j];
220 item.barrier(sycl::access::fence_space::local_space);
227 auto store_element = [&](
int row,
int col, T value) {
228 if (row >= n || col >= n) {
231 if (on_diagonal && (lower ? row < col : row > col)) {
234 T* p = &Cb[row +
static_cast<std::ptrdiff_t
>(col) * ldc];
235 *p = beta == T(0) ? alpha * value : alpha * value + beta * *p;
239 for (
int band = 0; band < 2; ++band) {
240 const int gm = m0 + band * 64 + ty * Band;
242 for (
int j = 0; j < ThreadTile; ++j) {
243 const int gn = n0 + (j < Band ? tx * Band + j : 64 + tx * Band + j - Band);
244 if constexpr (AlignedFastPath) {
246 T* p = &Cb[gm +
static_cast<std::ptrdiff_t
>(gn) * ldc];
250 for (
int i = 0; i < 4; ++i) {
251 out.v[i] = alpha * accum[band * Band + i][j];
254 const TileVec4<T> prior = tile_vec4(
const_cast<const T*
>(p));
256 for (
int i = 0; i < 4; ++i) {
257 out.v[i] = alpha * accum[band * Band + i][j] +
266 for (
int i = 0; i < 4; ++i) {
267 store_element(gm + i, gn, accum[band * Band + i][j]);