50 BATCHLAS_KERNEL_TRACE_SCOPE(
"trmm_cuda_custom.triangular_tiles");
61 constexpr int ThreadRows = TileM / LocalRows;
62 constexpr int ThreadCols = TileN / LocalCols;
63 constexpr int Threads = LocalRows * LocalCols;
64 constexpr int SA = TileM;
65 constexpr int SB = TileN;
66 constexpr int PacksA = TileM / 4;
67 constexpr int PacksB = TileN / 4;
68 constexpr int BandsR = ThreadRows / 4;
69 constexpr int BandsC = ThreadCols / 4;
70 constexpr int BandSpanR = TileM / BandsR;
71 constexpr int BandSpanC = TileN / BandsC;
72 constexpr int PacketsA = TileK * PacksA;
73 constexpr int PacketsB = TileK * PacksB;
75 static_assert(ThreadRows % 4 == 0 && ThreadCols % 4 == 0,
"fragments are 4-wide bands");
76 static_assert(TileM % TileK == 0,
"the diagonal tile has to fall on a k boundary");
77 static_assert((PacksA & (PacksA - 1)) == 0 && (PacksB & (PacksB - 1)) == 0,
78 "the swizzle needs a power-of-two packet count");
80 const int m =
static_cast<int>(C.
rows());
81 const int n =
static_cast<int>(C.
cols());
83 const int tiles_m = (m + TileM - 1) / TileM;
84 const int tiles_n = (n + TileN - 1) / TileN;
89 const bool lower_eff = (uplo ==
Uplo::Lower) != transposed;
93 const sycl::range<3> local(1, 1,
static_cast<size_t>(Threads));
94 const sycl::range<3> global(
static_cast<size_t>(batch),
95 static_cast<size_t>(tiles_m * tiles_n),
96 static_cast<size_t>(Threads));
98 impl::check_group_count(*ctx, sycl::nd_range<3>(global, local));
99 ctx->submit([&](sycl::handler& h) {
100 sycl::local_accessor<T, 1> tile_a(sycl::range<1>(TileK * SA), h);
101 sycl::local_accessor<T, 1> tile_b(sycl::range<1>(TileK * SB), h);
106 const int lda = A.
ld();
107 const int ldb = B.
ld();
108 const int ldc = C.
ld();
109 const int stride_a = A.
stride();
110 const int stride_b = B.
stride();
111 const int stride_c = C.
stride();
113 batchlas::impl::parallel_for<TrmmTriangularTilesKernel<T, TileM>>(h,
114 sycl::nd_range<3>(global, local), [=](sycl::nd_item<3> item) {
115 const int bid =
static_cast<int>(item.get_group(0));
119 const int gid =
static_cast<int>(item.get_group(1));
120 const int tile_row = gid / tiles_n;
121 const int tile_col = gid % tiles_n;
122 const int m0 = tile_row * TileM;
123 const int n0 = tile_col * TileN;
125 const int tid =
static_cast<int>(item.get_local_id(2));
126 const int tr = tid % LocalRows;
127 const int tc = tid / LocalRows;
129 const T* Ab = a_ptr +
static_cast<std::ptrdiff_t
>(bid) * stride_a;
130 const T* Bb = b_ptr +
static_cast<std::ptrdiff_t
>(bid) * stride_b;
131 T* Cb = c_ptr +
static_cast<std::ptrdiff_t
>(bid) * stride_c;
132 T* sa = tile_a.template get_multi_ptr<sycl::access::decorated::no>().get();
133 T* sb = tile_b.template get_multi_ptr<sycl::access::decorated::no>().get();
135 auto swizzle_a = [](
int packet,
int pp) {
136 return packet ^ ((pp >> 2) & (PacksA - 1));
138 auto swizzle_b = [](
int packet,
int pp) {
139 return packet ^ ((pp >> 2) & (PacksB - 1));
142 T accum[ThreadRows][ThreadCols];
144 for (
int i = 0; i < ThreadRows; ++i) {
146 for (
int j = 0; j < ThreadCols; ++j) {
153 const int p_begin = lower_eff ? 0 : m0;
154 const int p_end = lower_eff ? sycl::min(m, m0 + TileM) : m;
156 for (
int p0 = p_begin; p0 < p_end; p0 += TileK) {
160 for (
int flat = tid; flat < PacketsA; flat += Threads) {
161 const int i = m0 + flat / (TileK / 4);
162 const int pp0 = (flat % (TileK / 4)) * 4;
163 const int ii = i - m0;
164 const int phys = (swizzle_a(ii >> 2, pp0) << 2) | (ii & 3);
166 for (
int e = 0; e < 4; ++e) {
167 const int p = p0 + pp0 + e;
169 if (i < m && p < m) {
176 : Ab[i +
static_cast<std::ptrdiff_t
>(i) * lda];
177 }
else if (lower_eff ? (p < i) : (p > i)) {
178 const T raw = Ab[p +
static_cast<std::ptrdiff_t
>(i) * lda];
182 sa[(pp0 + e) * SA + phys] = value;
186 for (
int flat = tid; flat < PacketsA; flat += Threads) {
187 const int pp = flat / PacksA;
188 const int ii0 = (flat % PacksA) * 4;
189 const int p = p0 + pp;
190 const int phys = swizzle_a(ii0 >> 2, pp) << 2;
194 for (
int e = 0; e < 4; ++e) {
195 const int i = m0 + ii0 + e;
197 if (i < m && p < m) {
201 : Ab[i +
static_cast<std::ptrdiff_t
>(i) * lda];
202 }
else if (lower_eff ? (p < i) : (p > i)) {
203 value = Ab[i +
static_cast<std::ptrdiff_t
>(p) * lda];
208 tile_store4(&sa[pp * SA + phys], packet);
215 for (
int flat = tid; flat < PacketsB; flat += Threads) {
216 const int col = flat / (TileK / 4);
217 const int pp0 = (flat % (TileK / 4)) * 4;
218 const int j = n0 + col;
219 const int phys = (swizzle_b(col >> 2, pp0) << 2) | (col & 3);
221 for (
int e = 0; e < 4; ++e) {
222 const int p = p0 + pp0 + e;
223 sb[(pp0 + e) * SB + phys] =
225 ? Bb[p +
static_cast<std::ptrdiff_t
>(j) * ldb]
229 item.barrier(sycl::access::fence_space::local_space);
232 for (
int p = 0; p < TileK; ++p) {
233 const T* rowa = &sa[p * SA];
234 const T* rowb = &sb[p * SB];
238 for (
int b = 0; b < BandsR; ++b) {
239 const TileVec4<T> v =
240 tile_load4(rowa + (swizzle_a(b * (BandSpanR / 4) + tr, p) << 2));
242 for (
int e = 0; e < 4; ++e) {
243 af[b * 4 + e] = v.v[e];
247 for (
int b = 0; b < BandsC; ++b) {
248 const TileVec4<T> v =
249 tile_load4(rowb + (swizzle_b(b * (BandSpanC / 4) + tc, p) << 2));
251 for (
int e = 0; e < 4; ++e) {
252 bf[b * 4 + e] = v.v[e];
256 for (
int i = 0; i < ThreadRows; ++i) {
258 for (
int j = 0; j < ThreadCols; ++j) {
259 accum[i][j] = accumulate(accum[i][j], af[i], bf[j]);
263 item.barrier(sycl::access::fence_space::local_space);
268 for (
int j = 0; j < ThreadCols; ++j) {
269 const int col = n0 + (j / 4) * BandSpanC + tc * 4 + (j % 4);
274 for (
int i = 0; i < ThreadRows; ++i) {
275 const int row = m0 + (i / 4) * BandSpanR + tr * 4 + (i % 4);
279 Cb[row +
static_cast<std::ptrdiff_t
>(col) * ldc] = alpha * accum[i][j];