#ifndef GPU_INTEL_GEMM_XE_SYSTOLIC_COPY_KERNEL_HPP
#define GPU_INTEL_GEMM_XE_SYSTOLIC_COPY_KERNEL_HPP
#include "common/c_types_map.hpp"
#include "common/serialization.hpp"
#include "gpu/intel/compute/device_info.hpp"
#include "gpu/intel/compute/kernel.hpp"
#include "gpu/intel/engine.hpp"
namespace dnnl {
namespace impl {
namespace gpu {
namespace intel {
namespace gemm {
struct xe_systolic_copy_kernel_t {
status_t init(compute::gpu_arch_t arch, data_type_t dt, int unroll_n,
bool copyb, bool trans, bool sum = false, bool clear_sum = false,
bool require_stateless_addressing = true) {
*this = {};
arch_ = arch;
dt_ = dt;
unroll_n_ = unroll_n;
copyb_ = copyb;
trans_ = trans;
sum_ = sum;
clear_sum_ = clear_sum;
require_stateless_addressing_ = require_stateless_addressing;
return status::success;
}
status_t create_generator(const intel::engine_t &engine,
compute::kernel_bundle_t &bundle) const {
compute::kernel_ctx_t ctx;
CHECK(init_kernel_ctx(ctx));
return engine.create_kernel_bundle(bundle, {name()}, ctx);
}
status_t init_kernel_ctx(compute::kernel_ctx_t &kernel_ctx) const {
return init_kernel_ctx(kernel_ctx, arch_, dt_, unroll_n_, copyb_,
trans_, sum_, clear_sum_, require_stateless_addressing_);
}
static status_t init_kernel_ctx(compute::kernel_ctx_t &kernel_ctx,
compute::gpu_arch_t arch, data_type_t dt, int unroll_n, bool copyb,
bool trans, bool sum = false, bool clear_sum = false,
bool require_stateless_addressing = true) {
using arch_t = compute::gpu_arch_t;
auto dt_size = types::data_type_size(dt);
kernel_ctx.require_stateless_addressing(require_stateless_addressing);
if (dt_size == 1) kernel_ctx.add_option("-Dcl_intel_subgroups_char");
kernel_ctx.define_int("ELEMENT_SIZE", int(dt_size));
kernel_ctx.define_int("UNROLL_N", unroll_n);
kernel_ctx.define_int("COPY_A", int(!copyb));
kernel_ctx.define_int("COPY_B", int(copyb));
kernel_ctx.define_int("COPY_TRANS", int(trans));
kernel_ctx.define_int("COPY_SUM", int(sum));
kernel_ctx.define_int("COPY_CLEAR_SUM", int(clear_sum));
kernel_ctx.define_int("COPY_SIGNED", int(dt == data_type::s8));
kernel_ctx.add_option("-cl-strict-aliasing");
kernel_ctx.add_option(
"-cl-intel-256-GRF-per-thread"); if (utils::one_of(arch, arch_t::xe_hp, arch_t::xe_hpg))
kernel_ctx.add_option("-DCOPY_XE_HP");
if (utils::one_of(arch, arch_t::xe_hpc, arch_t::xe2, arch_t::xe3))
kernel_ctx.add_option("-DCOPY_XE_HPC");
return status::success;
}
const char *name() const { return name(arch_); }
static const char *name(compute::gpu_arch_t arch) {
using arch_t = compute::gpu_arch_t;
switch (arch) {
case arch_t::xe_hp:
case arch_t::xe_hpg: return "xe_hp_systolic_gemm_copy";
case arch_t::xe_hpc:
case arch_t::xe2:
case arch_t::xe3: return "xe_hpc_systolic_gemm_copy";
default: assert(!"Unsupported architecture"); return "";
}
}
static constexpr int unroll_k(size_t element_size) {
return 32 / int(element_size);
}
static constexpr int unroll_r(
compute::gpu_arch_t arch, size_t element_size, bool copyb) {
return !copyb ? ((arch >= compute::gpu_arch_t::xe_hpc) ? 64 : 32)
: unroll_k(element_size);
}
static constexpr int unroll_c(
size_t element_size, int unroll_n, bool copyb) {
return !copyb ? unroll_k(element_size) : unroll_n;
}
static constexpr int subgroup_size(compute::gpu_arch_t arch) {
return (arch >= compute::gpu_arch_t::xe_hpc) ? 16 : 8;
}
static constexpr int subgroup_size_clear_sum(compute::gpu_arch_t arch) {
return (arch >= compute::gpu_arch_t::xe_hpc) ? 16 : 8;
}
#if __cplusplus >= 202002L
bool operator==(const xe_systolic_copy_kernel_t &) const = default;
#endif
serialization_stream_t serialize() const {
DNNL_ASSERT_TRIVIALLY_SERIALIZABLE(xe_systolic_copy_kernel_t);
return serialization_stream_t(*this);
}
static xe_systolic_copy_kernel_t deserialize(
const serialization_stream_t &s) {
xe_systolic_copy_kernel_t t {};
deserializer_t d(s);
d.pop(t);
return t;
}
compute::gpu_arch_t arch_;
data_type_t dt_;
int unroll_n_;
bool copyb_;
bool trans_;
bool sum_;
bool clear_sum_;
bool require_stateless_addressing_;
uint8_t pad[3] = {};
};
} } } } }
#endif