#ifndef GPU_INTEL_GEMM_JIT_GEN_KERNEL_HPP
#define GPU_INTEL_GEMM_JIT_GEN_KERNEL_HPP
#include "common/c_types_map.hpp"
#include "gemmstone/driver_info.hpp"
#include "gemmstone/kernel_catalog.hpp"
#include "gemmstone/kernel_evaluator.hpp"
#include "gemmstone/problem.hpp"
#include "gemmstone/strategy.hpp"
#include "gemmstone/type.hpp"
#include "gpu/intel/compute/device_info.hpp"
#include "gpu/intel/compute/kernel_arg_list.hpp"
#include "gpu/intel/gemm/jit/pd.hpp"
#include "gpu/intel/jit/generator_base.hpp"
#include "gpu/intel/kernel_cache.hpp"
namespace dnnl {
namespace impl {
namespace gpu {
namespace intel {
namespace gemm {
namespace jit {
bool enable_generator_dsl();
static inline gemmstone::Type convert_dnnl_to_kernel_type(data_type_t type) {
using gemmstone::Type;
switch (type) {
default: assert(!"Unknown type");
case data_type::f64: return Type::f64;
case data_type::f32: return Type::f32;
case data_type::f16: return Type::f16;
case data_type::bf16: return Type::bf16;
case data_type::f8_e5m2: return Type::bf8;
case data_type::f8_e4m3: return Type::hf8;
case data_type::e8m0: return Type::f8_e8m0;
case data_type::f4_e2m1: return Type::f4_e2m1;
case data_type::f4_e3m0: return Type::f4_e3m0;
case data_type::s32: return Type::s32;
case data_type::u8: return Type::u8;
case data_type::s8: return Type::s8;
case data_type::u4: return Type::u4;
case data_type::s4: return Type::s4;
case data_type::undef: return Type::invalid;
}
}
struct gen_desc_t {
friend struct gen_kernel_t;
const gemmstone::GEMMProblem *problem() const { return &problem_; }
const gemmstone::GEMMStrategy *strategy() const { return &strategy_; }
const gemmstone::CommonDriverInfo *driver_info() const {
return &driver_info_;
}
const gemmstone::EvaluateAuxOutput *aux_params() const {
return &aux_params_;
}
compute::scalar_type_t scalar_type() const;
status_t create_generator(
const intel::engine_t &engine, compute::kernel_t &kernel) const;
serialization_stream_t serialize() const {
return serialization_stream_t(problem_, strategy_);
}
compute::gpu_arch_t arch() const { return arch_; }
bool has_entry() { return entry_ != nullptr; }
const gemmstone::kcatalog::Entry &entry() const {
assert(entry_ != nullptr);
return *entry_;
}
void set_entry(const gemmstone::kcatalog::Entry *entry) { entry_ = entry; }
void set_problem(const gemmstone::GEMMProblem &problem) {
problem_ = problem;
}
void set_efficient_64b(bool efficient_64b) {
efficient_64b_ = efficient_64b;
}
protected:
compute::gpu_arch_t arch_;
ngen::HW hw_ = ngen::HW::Unknown;
int stepping_ = 0;
gemmstone::GEMMProblem problem_ = {};
gemmstone::GEMMStrategy strategy_;
const gemmstone::kcatalog::Entry *entry_ = nullptr;
gemmstone::EvaluateAuxOutput aux_params_;
gemmstone::CommonDriverInfo driver_info_;
bool efficient_64b_ = false;
int m_ = -1, n_ = -1, k_ = -1;
int eu_count_ = -1;
bool disable_systolic_ = false;
bool relaxed_acc_ = false;
status_t finalize(const char *tags);
void update_driver_info();
};
struct gen_nocopy_desc_t : public gen_desc_t {
enum compute_mode {
mode_default = 0,
mode_tf32 = 0x1,
mode_bf16x1 = 0x2,
mode_f16x1 = 0x4,
mode_w_decomp = 0x8,
mode_relaxed_acc = 0x10,
mode_strict = 0x20,
mode_deterministic = 0x8000
};
friend void set_mode(compute_mode &mode, compute_mode flag) {
mode = static_cast<compute_mode>(mode | flag);
}
std::vector<const gemmstone::kcatalog::Entry *> select_kernel(
compute::gpu_arch_t arch, int stepping, int eu_count,
bool has_systolic, bool is_integrated, compute_mode mode,
const gemmstone::GEMMProblem &problem, float alpha, float beta,
dim_t m, dim_t n, dim_t k, dim_t lda, dim_t ldb, dim_t ldc,
dim_t batch);
status_t finalize();
private:
std::string tags_;
gemmstone::EvaluateParams eval_params_;
gemmstone::Type Ts_;
gemmstone::Scalar beta_;
};
struct gen_xe_systolic_kernel_desc_t : public gen_desc_t {
status_t select_kernel(compute::gpu_arch_t arch, int stepping, int eu_count,
bool is_integrated, int batch_dims, bool packed_c, bool trans_co,
bool a_offset, bool b_offset, bool c_offset, bool bias, float alpha,
float beta, data_type_t a_type, data_type_t b_type,
data_type_t c_type, data_type_t ao_type, data_type_t bo_type,
data_type_t co_type, data_type_t acc_type, dim_t m, dim_t n,
dim_t k, dim_t batch, int unroll_m, int unroll_n, bool alt,
gpu_post_ops_t &&post_ops);
static void choose_unrolls(compute::gpu_arch_t arch, int eu_count,
data_type_t a_type, data_type_t b_type, data_type_t c_type, dim_t m,
dim_t n, dim_t k, dim_t batch, int &unroll_m, int &unroll_n,
bool &alt);
static int min_block_k(data_type_t a_type) { return 2048; }
};
struct gen_kernel_t : public intel::jit::generator_base_t {
explicit gen_kernel_t(const gen_desc_t &desc) : desc_(desc) {}
const char *kernel_name() const override { return "gemm_kernel"; }
status_t get_kernel(
compute::kernel_t &kernel, const intel::engine_t *engine) override;
const gen_desc_t *desc() const { return &desc_; }
protected:
const gen_desc_t &desc_;
ngen::NEOInterfaceHandler interface_ {ngen::HW::Unknown};
void init_interface();
void maybe_print_verbose();
};
} }
template <>
struct key_validator_t<gemm::jit::gen_desc_t> {
static bool is_valid(const gemm::jit::gen_desc_t &) { return true; }
};
template <>
struct key_validator_t<gemm::jit::gen_nocopy_desc_t> {
static bool is_valid(const gemm::jit::gen_nocopy_desc_t &derived) {
return key_validator_t<gemm::jit::gen_desc_t>::is_valid(derived);
}
};
template <>
struct key_validator_t<gemm::jit::gen_xe_systolic_kernel_desc_t> {
static bool is_valid(
const gemm::jit::gen_xe_systolic_kernel_desc_t &derived) {
return key_validator_t<gemm::jit::gen_desc_t>::is_valid(derived);
}
};
} } } }
#endif