26#include <src/linalg-impl.hh>
27#include <src/sycl/kernel_attrs.hh>
29#include <sycl/sycl.hpp>
33template <
typename T,
bool AlignedFastPath,
bool StagedEpilogue>
38 return *
reinterpret_cast<const Vec4<T>*
>(__builtin_assume_aligned(p, 4 *
sizeof(T)));
43 return *
reinterpret_cast<Vec4<T>*
>(__builtin_assume_aligned(p, 4 *
sizeof(T)));
50#if defined(__SYCL_DEVICE_ONLY__) && defined(__NVPTX__)
51 if constexpr (std::is_same_v<T, float>) {
53 asm(
"ld.global.L2::128B.v4.f32 {%0, %1, %2, %3}, [%4];"
54 :
"=f"(r.x),
"=f"(r.y),
"=f"(r.z),
"=f"(r.w)
58#elif BATCHLAS_SYCL_IMPL_ACPP && defined(__x86_64__)
61 if constexpr (std::is_same_v<T, float>) {
62 if (sycl_impl::on_ptx()) {
63 unsigned x = 0, y = 0, z = 0, w = 0;
64 __acpp_if_target_sscp(
asm(
"ld.global.L2::128B.v4.b32 %{%0, %1, %2, %3%}, [%4];"
65 :
"=r"(x),
"=r"(y),
"=r"(z),
"=r"(w)
67 return Vec4<T>{__builtin_bit_cast(T, x), __builtin_bit_cast(T, y),
68 __builtin_bit_cast(T, z), __builtin_bit_cast(T, w)};
80#if defined(__SYCL_DEVICE_ONLY__) && defined(__NVPTX__)
81 if constexpr (std::is_same_v<T, float>) {
83 asm(
"ld.global.L2::128B.f32 %0, [%1];" :
"=f"(r) :
"l"(p));
86#elif BATCHLAS_SYCL_IMPL_ACPP && defined(__x86_64__)
87 if constexpr (std::is_same_v<T, float>) {
88 if (sycl_impl::on_ptx()) {
90 __acpp_if_target_sscp(
asm(
"ld.global.L2::128B.b32 %0, [%1];" :
"=r"(r) :
"l"(p));)
91 return __builtin_bit_cast(T, r);
103 constexpr int TileM = 128, TileN = 128, TileK = 8;
104 const auto m = A.
rows();
105 const auto k = A.
cols();
106 const auto n = B.
cols();
108 if (k < TileK || (m % TileM) != 0 || (n % TileN) != 0 || (k % TileK) != 0) {
114 auto aligned = [](
const T* p,
int ld,
int stride) {
115 return p !=
nullptr && (
reinterpret_cast<std::uintptr_t
>(p) % (4 *
sizeof(T))) == 0 &&
116 (ld % 4) == 0 && (stride % 4) == 0;
126template <
typename T,
bool AlignedFastPath,
bool StagedEpilogue>
135 static_assert(!StagedEpilogue || AlignedFastPath,
"the staged epilogue stores unpredicated");
147 void operator()(sycl::nd_item<3> item)
const {
148 const int bid =
static_cast<int>(item.get_group(0));
152 const int tid =
static_cast<int>(item.get_local_id(2));
153 const int lane = tid & 31, warp = tid >> 5;
154 const int ml = (lane & 1) | (((lane >> 2) & 3) << 1);
155 const int nl = ((lane >> 1) & 1) | (((lane >> 4) & 1) << 1);
156 const int mb = (warp & 1) * 64 + ml *
Band;
157 const int nb = (warp >> 1) * 32 + nl *
Band;
159 const int m0 =
static_cast<int>(item.get_group(1)) *
TileM;
160 const int n0 =
static_cast<int>(item.get_group(2)) *
TileN;
161 const T* Ab =
a_ptr +
static_cast<std::ptrdiff_t
>(bid) *
stride_a;
162 const T* Bb =
b_ptr +
static_cast<std::ptrdiff_t
>(bid) *
stride_b;
164 T* sa =
tile_a.template get_multi_ptr<sycl::access::decorated::no>().get();
165 T* sb =
tile_b.template get_multi_ptr<sycl::access::decorated::no>().get();
178 const int a_m = (tid % 32) * 4;
179 const int a_k = tid / 32;
180 const int b_k = (tid % 2) * 4;
181 const int b_n = tid / 2;
182 const T* ga = Ab + (m0 + a_m) +
static_cast<std::ptrdiff_t
>(a_k) *
lda;
183 const T* gb = Bb + b_k +
static_cast<std::ptrdiff_t
>(n0 + b_n) *
ldb;
186 auto gload = [&](
int k0) __attribute__((always_inline)) {
187 if constexpr (AlignedFastPath) {
188 ra =
vec4_ref(ga +
static_cast<std::ptrdiff_t
>(k0) *
lda);
192 const int gk_a = k0 + a_k;
193 const int gn_b = n0 + b_n;
195 for (
int i = 0; i < 4; ++i) {
196 const int gm = m0 + a_m + i;
197 ra[i] = (gm < m && gk_a < k) ? ga[static_cast<std::ptrdiff_t>(k0) *
lda + i] : T(0);
198 rb[i] = (k0 + b_k + i <
k && gn_b <
n) ?
load1_l2_line(gb + k0 + i) : T(0);
202 auto sstore = [&](
int buf) __attribute__((always_inline)) {
205 for (
int i = 0; i < 4; ++i) {
209 auto compute = [&](
int buf) __attribute__((always_inline)) {
213 for (
int kk = 0; kk <
TileK; ++kk) {
218 const T af[
ThreadTile] = {a0.x, a0.y, a0.z, a0.w, a1.x, a1.y, a1.z, a1.w};
219 const T bf[
ThreadTile] = {b0.x, b0.y, b0.z, b0.w, b1.x, b1.y, b1.z, b1.w};
224 accum[i][j] += af[i] * bf[j];
237 item.barrier(sycl::access::fence_space::local_space);
239 for (; s + 1 < slabs; s += 2) {
240 gload((s + 1) *
TileK);
243 item.barrier(sycl::access::fence_space::local_space);
244 const bool more = s + 2 < slabs;
245 if (more) gload((s + 2) *
TileK);
248 item.barrier(sycl::access::fence_space::local_space);
254 if constexpr (StagedEpilogue) {
258 const int tid2 =
static_cast<int>(item.get_local_id(2));
259 item.barrier(sycl::access::fence_space::local_space);
261 for (
int p = 0; p <
Band; ++p) {
263 for (
int half = 0; half < 2; ++half) {
264 const int slot = (nb >> 2) + half * (
BandN / 4);
266 for (
int band = 0; band < 2; ++band) {
269 for (
int i = 0; i < 4; ++i) {
270 v[i] = accum[band *
Band + i][p + half *
Band];
275 item.barrier(sycl::access::fence_space::local_space);
277 for (
int q = 0; q < 4; ++q) {
278 const int slot = (tid2 >> 5) * 4 + q;
279 const int row = (tid2 & 31) * 4;
280 T* dst = &Cb[m0 + row +
static_cast<std::ptrdiff_t
>(n0 + slot * 4 + p) *
ldc];
288 for (
int i = 0; i < 4; ++i) {
294 item.barrier(sycl::access::fence_space::local_space);
302 for (
int band = 0; band < 2; ++band) {
303 const int gm = m0 + band *
BandM + mb;
306 const int gn = n0 + (j <
Band ? nb + j :
BandN + nb + j -
Band);
307 if constexpr (AlignedFastPath) {
308 T* p = &Cb[gm +
static_cast<std::ptrdiff_t
>(gn) *
ldc];
312 for (
int i = 0; i < 4; ++i) {
313 out[i] =
alpha * accum[band *
Band + i][j];
318 for (
int i = 0; i < 4; ++i) {
328 for (
int i = 0; i < 4; ++i) {
329 const int row = gm + i;
333 T* p = &Cb[row +
static_cast<std::ptrdiff_t
>(gn) *
ldc];
335 beta == T(0) ? T(0) : *p);
343template <
typename T,
bool AlignedFastPath,
bool StagedEpilogue>
354 const int m =
static_cast<int>(A.
rows());
355 const int k =
static_cast<int>(A.
cols());
356 const int n =
static_cast<int>(B.
cols());
357 const int group_rows = (m + Body::TileM - 1) / Body::TileM;
358 const int group_cols = (n + Body::TileN - 1) / Body::TileN;
360 const sycl::range<3> local(1, 1, Body::Threads);
361 const sycl::range<3> global(
static_cast<size_t>(A.
batch_size()),
static_cast<size_t>(group_rows),
362 static_cast<size_t>(group_cols) * Body::Threads);
364 ctx->submit([&](sycl::handler& h) {
365 sycl::local_accessor<T, 1> tile_a(sycl::range<1>(Body::TileAElems), h);
366 sycl::local_accessor<T, 1> tile_b(sycl::range<1>(2 * Body::TileK * Body::BStride), h);
369 batchlas::impl::parallel_for<GemmRegister128x128Kernel<T, AlignedFastPath, StagedEpilogue>>(h,
370 sycl::nd_range<3>(global, local), body);
380template <
typename T,
bool AlignedFastPath = false>
388 if constexpr (AlignedFastPath) {
Non-owning view of a batch of matrices: the argument type of every entry point.
T * data_ptr() const
Base pointer of item 0.
int rows() const
Rows per item (the capacity on a heterogeneous batch).
int cols() const
Columns per item (the capacity on a heterogeneous batch).
int ld() const
Leading dimension: element distance between columns.
int stride() const
Batch stride: element distance between items.
int batch_size() const
Number of batch items.
constexpr int kStagedEpilogueMaxK
Vec4< T > load4_l2_line(const T *p)
const Vec4< T > & vec4_ref(const T *p)
Event launch_register_128x128_k8_leg(Queue &ctx, const MatrixView< T, MatrixFormat::Dense > &A, const MatrixView< T, MatrixFormat::Dense > &B, const MatrixView< T, MatrixFormat::Dense > &C, T alpha, T beta, const char *(*kernel_trace_name)(KernelVariant))
T load1_l2_line(const T *p)
T __attribute__((ext_vector_type(4))) Vec4
Event launch_register_128x128_k8(Queue &ctx, const MatrixView< T, MatrixFormat::Dense > &A, const MatrixView< T, MatrixFormat::Dense > &B, const MatrixView< T, MatrixFormat::Dense > &C, T alpha, T beta, const char *(*kernel_trace_name)(KernelVariant))
bool can_use_128x128_fast_path(const MatrixView< T, MatrixFormat::Dense > &A, const MatrixView< T, MatrixFormat::Dense > &B, const MatrixView< T, MatrixFormat::Dense > &C)
Completion handle of enqueued work, returned by every entry point.
Where BatchLAS work runs: a device, a backend, an ordered SYCL queue and a workspace arena.
Event get_event() const
An Event that completes after everything enqueued on this Queue so far.
static constexpr int kMinGroupsPerCu
static constexpr int TileK
static constexpr int AStride
static constexpr int TileN
static constexpr int Band
static constexpr int StageStride
static constexpr int BStride
static constexpr int Threads
sycl::local_accessor< T, 1 > tile_a
static constexpr int TileAElems
sycl::local_accessor< T, 1 > tile_b
static constexpr int TileM
static constexpr int BandN
static constexpr int ThreadTile
static constexpr int BandM
static T apply(T alpha, T beta, T accum, T prior)