#ifndef GPU_INTEL_COMPUTE_KERNEL_CTX_HPP
#define GPU_INTEL_COMPUTE_KERNEL_CTX_HPP
#include <cassert>
#include <map>
#include <set>
#include <sstream>
#include <string>
#include <type_traits>
#include <unordered_map>
#include "common/bit_cast.hpp"
#include "common/type_helpers.hpp"
#include "gpu/intel/primitive_attr.hpp"
#include "gpu/intel/utils.hpp"
namespace dnnl {
namespace impl {
namespace gpu {
namespace intel {
struct memory_desc_info_t;
namespace compute {
class kernel_ctx_t {
public:
kernel_ctx_t(const primitive_attr_t *attr = nullptr) {
set_default_options(attr);
set_default_macros(attr);
}
std::string options() const {
ostringstream_t oss;
for (auto &opt : option_set_)
oss << " " << opt;
if (use_int32_offset_) { oss << " -DUSE_INT32_OFFSET"; }
for (auto &int_var : int_var_map_) {
if (int_var.second == std::numeric_limits<int32_t>::min())
oss << " -D" << int_var.first << "=(-2147483647-1)";
else if (int_var.second == std::numeric_limits<int64_t>::min())
oss << " -D" << int_var.first << "=(-9223372036854775807L-1)";
else {
oss << " -D" << int_var.first << "=" << int_var.second;
if (int_var.second > INT_MAX || int_var.second < INT_MIN)
oss << "L";
}
}
for (auto &float_var : float_var_map_) {
oss << " -D" << float_var.first << "=as_float(0x" << std::hex
<< utils::bit_cast<uint32_t>(float_var.second) << ")";
}
return oss.str();
}
void register_buffer_size(const memory_desc_wrapper &mdw);
void register_buffer_size(const memory_desc_info_t &mdi);
void use_int32_offset(bool value) { use_int32_offset_ = value; }
void require_stateless_addressing(bool value) {
require_stateless_addressing_ = value;
}
bool require_stateless_addressing() const {
return require_stateless_addressing_;
}
void define_int(const char *variable, int64_t value) {
set_macro(variable, value, int_var_map_);
}
void define_int(const std::string &variable, int64_t value) {
define_int(variable.c_str(), value);
}
void define_float(const char *variable, float value) {
float_var_map_.insert({variable, value});
}
void add_option(const char *option) { option_set_.insert(option); }
void add_option(const std::string &option) { add_option(option.c_str()); }
bool has_macro(const char *name) const {
std::string opt_start = std::string("-D") + name + "=";
for (auto &opt : option_set_)
if (opt.find(opt_start) != std::string::npos) return true;
std::string var_name = name;
return int_var_map_.count(var_name) != 0
|| float_var_map_.count(var_name) != 0;
}
bool has_macro(const std::string &name) const {
return has_macro(name.c_str());
}
void set_data_type(data_type_t dt, bool with_punning = true) {
switch (dt) {
case data_type::bf16: define_int("DT_BF16", 1); break;
case data_type::f16: define_int("DT_F16", 1); break;
case data_type::f32: define_int("DT_F32", 1); break;
case data_type::f64: define_int("DT_F64", 1); break;
case data_type::s8: define_int("DT_S8", 1); break;
case data_type::u8: define_int("DT_U8", 1); break;
case data_type::f8_e4m3: define_int("DT_HF8", 1); break;
case data_type::f8_e5m2: define_int("DT_BF8", 1); break;
case data_type::f4_e2m1: define_int("DT_F4_E2M1", 1); break;
case data_type::f4_e3m0: define_int("DT_F4_E3M0", 1); break;
case data_type::s32: define_int("DT_S32", 1); break;
default: assert(!"unknown data type"); break;
}
define_int("WITH_PUNNING", with_punning);
}
std::string data_type() const {
if (int_var_map_.count("DT_F16") != 0) return "f16";
if (int_var_map_.count("DT_F32") != 0) return "f32";
if (int_var_map_.count("DT_F64") != 0) return "f64";
if (int_var_map_.count("DT_S8") != 0) return "s8";
return "";
}
void add_custom_header(
const std::string &header_name, std::string &&source) {
custom_headers_[header_name] = std::move(source);
}
const char *get_custom_header(const std::string &header_name) const {
auto iter = custom_headers_.find(header_name);
if (iter != custom_headers_.end()) return iter->second.c_str();
return nullptr;
}
bool has_custom_headers() const { return !custom_headers_.empty(); }
private:
void register_buffer_size(dim_t nelems, size_t size) {
if (nelems > INT32_MAX) use_int32_offset(false);
if (size > UINT32_MAX) require_stateless_addressing(true);
}
void set_default_options(const primitive_attr_t *attr) {
add_option("-cl-fp32-correctly-rounded-divide-sqrt");
if (attr && attr->gpu_attr_) {
auto *gpu_attr = utils::downcast<gpu_primitive_attr_t *>(
attr->gpu_attr_.get());
if (gpu_attr->threads_per_eu() == 4) {
add_option("-cl-intel-256-GRF-per-thread");
}
}
if (gpu_utils::dev_getenv("enable_check_assumptions", 0)) {
add_option("-DENABLE_CHECK_ASSUMPTIONS");
}
if (gpu_utils::dev_getenv("ocl_debug", 0)) {
add_option("-DOCL_DEBUG");
}
if (gpu_utils::dev_getenv("cl_opt_disable", 0)) {
add_option("-cl-opt-disable");
}
if (gpu_utils::dev_getenv("enable_ocl_werror", is_dev_mode()))
add_option("-Werror ");
}
void set_default_macros(const primitive_attr_t *attr) {
if (attr) { define_int("DETERMINISTIC", attr->deterministic_); }
}
template <typename T>
void set_macro(const char *variable, const T &value,
std::map<std::string, T> &var_map) {
gpu_assert(var_map.count(variable) == 0 || var_map[variable] == value)
<< "Error: macro " << variable
<< " is already set to a different value.\n Old value: "
<< var_map[variable] << "\n New value: " << value;
var_map.insert({variable, value});
}
std::map<std::string, int64_t> int_var_map_;
std::map<std::string, float> float_var_map_;
std::set<std::string> option_set_;
std::unordered_map<std::string, std::string> custom_headers_;
bool use_int32_offset_ = true;
bool require_stateless_addressing_ = false;
};
} } } } }
#endif