#include "gpu/intel/conv/jit_v2.hpp"
#include "common/utils.hpp"
#include "gpu/intel/conv/jit/v2/bridge.hpp"
#include "gpu/intel/conv/jit/v2/debug.hpp"
#include "gpu/intel/conv/jit/v2/plan_registry.hpp"
#include "gpu/intel/jit/ir/tensor_config.hpp"
#include "gpu/intel/logging.hpp"
namespace dnnl {
namespace impl {
namespace gpu {
namespace intel {
namespace conv {
namespace v2 {
using namespace jit;
using namespace jit::v2;
void maybe_init_layout(
memory_desc_t &md, const layout_tag_t &_tag, bool remove_a_dim) {
if (md.format_kind != format_kind::any) return;
auto layout = to_layout(_tag, md, remove_a_dim);
md = to_md(layout, md);
}
status_t init_default_layouts(pd_t *pd) {
auto &src_md = *const_cast<memory_desc_t *>(pd->invariant_src_md());
auto &dst_md = *const_cast<memory_desc_t *>(pd->invariant_dst_md());
if (src_md.format_kind == format_kind::any)
set_default_format(src_md, "axb");
if (dst_md.format_kind == format_kind::any)
set_default_format(dst_md, "axb");
return status::success;
}
status_t init_layouts(const kernel_desc_t &desc, pd_t *pd) {
auto &src_md = *const_cast<memory_desc_t *>(pd->invariant_src_md());
auto &wei_md = *const_cast<memory_desc_t *>(pd->invariant_wei_md());
auto &dst_md = *const_cast<memory_desc_t *>(pd->invariant_dst_md());
auto &bia_md = *const_cast<memory_desc_t *>(pd->invariant_bia_md());
maybe_init_layout(src_md, desc.src_tag, false);
maybe_init_layout(wei_md, desc.wei_tag, !pd->with_groups());
maybe_init_layout(dst_md, desc.dst_tag, false);
maybe_init_layout(bia_md, make_layout_tag(tensor_kind_t::bias, "a"), false);
return status::success;
}
void iter_md(const pd_t *pd,
const std::function<void(const memory_desc_t &)> &func) {
func(*pd->invariant_src_md());
func(*pd->invariant_wei_md());
func(*pd->invariant_dst_md());
func(*pd->invariant_bia_md());
auto &post_ops = pd->attr()->post_ops_;
for (int i = 0; i < post_ops.len(); i++) {
auto &e = post_ops.entry_[i];
if (e.is_binary()) func(e.binary.src1_desc);
}
}
bool has_large_buffers(const pd_t *pd) {
auto is_large = [](const memory_desc_t &md) {
memory_desc_wrapper mdw(md);
gpu_assert(!mdw.format_any());
return mdw.size() > size_t(std::numeric_limits<int32_t>::max());
};
bool has = false;
iter_md(pd, [&](const memory_desc_t &md) {
if (is_large(md)) has = true;
});
return has;
}
bool has_shifted_mds(const pd_t *pd) {
bool has = false;
iter_md(pd, [&](const memory_desc_t &md) {
if (md.offset0 != 0) has = true;
});
return has;
}
class gen_t {
public:
template <typename T>
static bool is_supported(T *pd, prop_kind_t prop) {
if (pd->is_bwd_d()
&& !(pd->KSW() == 1 && pd->KSH() == 1 && pd->KSD() == 1))
return false;
if (pd->is_bwd_d()
&& pd->diff_dst_md()->data_type
!= pd->diff_src_md()->data_type) {
return false;
}
using sm = primitive_attr_t::skip_mask_t;
auto skip_mask
= sm::post_ops | sm::sum_dt | sm::scales | sm::scales_data_type;
if (!pd->attr()->has_default_values(skip_mask)) return false;
if (pd->attr()->scales_.has_host_scalars()
|| pd->attr()->zero_points_.has_host_scalars())
return false;
return true;
}
template <typename T>
static status_t init_pd(T *pd, impl::engine_t *engine, prop_kind_t prop) {
if (!is_supported(pd, prop)) return status::unimplemented;
using intel::engine_t;
auto *intel_engine = utils::downcast<engine_t *>(engine);
if (!intel_engine->mayiuse_ngen_kernels()) return status::unimplemented;
if (!pd->set_default_alg_kind(alg_kind::convolution_direct))
return status::unimplemented;
CHECK(init_default_layouts(pd));
auto prb = to_problem(pd, engine);
kernel_desc_t _desc;
if (debug_t::init_kernel_desc(_desc)) {
_desc.set_missing();
_desc.spec.mode = specialization_mode_t::_default;
} else {
auto ®istry = const_plan_registry();
_desc = registry.find_best(prb, specialization_mode_t::_default);
if (_desc.is_empty()) {
gpu_info() << "Cannot find kernels that can fit the problem.";
return status::unimplemented;
}
}
_desc.fit_to(prb);
CHECK(init_layouts(_desc, pd));
CHECK(pd->attr_.set_default_formats(out_md(pd)));
if (has_large_buffers(pd)) return status::unimplemented;
if (has_shifted_mds(pd)) return status::unimplemented;
CHECK(_desc.set_attr(pd, pd->attr(), out_md(pd)));
if (!create_plan(_desc, prb)) {
gpu_info() << "Cannot create kernel descriptor.\n";
return status::runtime_error;
}
pd->init_plan = std::make_shared<primitive_init_plan_t>();
CHECK(_desc.init_primitive_plan(*pd->init_plan, prb, pd));
return status::success;
}
gen_t() = default;
template <typename T>
status_t init(T *primitive, impl::engine_t *engine) {
auto &init_plan = *primitive->pd()->init_plan;
CHECK(init_plan.create_exec_plan(exec_plan_, primitive, engine));
return status::success;
}
status_t execute(
const primitive_t *primitive, const exec_ctx_t &ctx) const {
return exec_plan_.execute(primitive, ctx);
}
private:
static const memory_desc_t *out_md(const pd_t *pd) {
if (pd->is_fwd()) return pd->dst_md();
if (pd->is_bwd_d()) return pd->diff_src_md();
if (pd->is_bwd_w()) return pd->diff_weights_md();
gpu_error_not_expected();
return nullptr;
}
primitive_exec_plan_t exec_plan_;
};
status_t gen_fwd_t::pd_t::init(impl::engine_t *engine) {
return gen_t::init_pd(this, engine, prop_kind::forward);
}
status_t gen_fwd_t::init(impl::engine_t *engine) {
impl_ = std::make_shared<gen_t>();
return impl_->init(this, engine);
}
status_t gen_fwd_t::execute(const exec_ctx_t &ctx) const {
return impl_->execute(this, ctx);
}
status_t gen_bwd_data_t::pd_t::init(impl::engine_t *engine) {
return gen_t::init_pd(this, engine, prop_kind::backward_data);
}
status_t gen_bwd_data_t::init(impl::engine_t *engine) {
impl_ = std::make_shared<gen_t>();
return impl_->init(this, engine);
}
status_t gen_bwd_data_t::execute(const exec_ctx_t &ctx) const {
return impl_->execute(this, ctx);
}
status_t gen_bwd_weights_t::pd_t::init(impl::engine_t *engine) {
return gen_t::init_pd(this, engine, prop_kind::backward_weights);
}
status_t gen_bwd_weights_t::init(impl::engine_t *engine) {
impl_ = std::make_shared<gen_t>();
return impl_->init(this, engine);
}
status_t gen_bwd_weights_t::execute(const exec_ctx_t &ctx) const {
return impl_->execute(this, ctx);
}
} } } } } }