#include "graph/backend/dnnl/executables/reorder.hpp"
namespace dnnl {
namespace impl {
namespace graph {
namespace dnnl_impl {
void reorder_executable_t::execute(const stream &stream,
const std::unordered_map<int, memory> &args) const {
if (with_sum_) {
auto it_dst = args.find(DNNL_ARG_DST);
auto it_src = args.find(DNNL_GRAPH_ARG_POST_SRC);
if (it_dst == args.end() || it_src == args.end()) {
assert(!("cannot find the required memory"));
return;
}
const memory &psrc_mem = it_src->second;
const memory &dst_mem = it_dst->second;
if (psrc_mem.get_data_handle() != dst_mem.get_data_handle()) {
dnnl::reorder(psrc_mem, dst_mem)
.execute(stream, const_cast<memory &>(psrc_mem),
const_cast<memory &>(dst_mem));
}
}
prim_.execute(stream, args);
}
#ifdef DNNL_WITH_SYCL
std::optional<::sycl::event> reorder_executable_t::execute_sycl(
const stream &stream, const std::unordered_map<int, memory> &args,
const std::vector<::sycl::event> &deps) const {
auto sycl_deps = deps;
if (with_sum_) {
auto it_dst = args.find(DNNL_ARG_DST);
auto it_src = args.find(DNNL_GRAPH_ARG_POST_SRC);
if (it_dst == args.end() || it_src == args.end()) {
assert(!"cannot find memory for DNNL_ARG_POST_SRC or DNNL_ARG_DST");
return std::nullopt;
}
const memory &psrc_mem = it_src->second;
const memory &dst_mem = it_dst->second;
if (psrc_mem.get_data_handle() != dst_mem.get_data_handle()) {
auto prim = dnnl::reorder(psrc_mem, dst_mem);
auto e = dnnl::sycl_interop::execute(prim, stream,
{{DNNL_ARG_FROM, const_cast<memory &>(psrc_mem)},
{DNNL_ARG_TO, const_cast<memory &>(dst_mem)}},
sycl_deps);
sycl_deps = {e};
}
}
auto e = dnnl::sycl_interop::execute(prim_, stream, args, sycl_deps);
if (stream.get_engine().get_kind() == engine::kind::cpu) e.wait();
return e;
}
#endif
#if DNNL_GPU_RUNTIME == DNNL_RUNTIME_OCL
cl_event reorder_executable_t::execute_ocl(const stream &stream,
const std::unordered_map<int, memory> &args,
const std::vector<cl_event> &deps) const {
auto ocl_deps = deps;
if (with_sum_) {
auto it_dst = args.find(DNNL_ARG_DST);
auto it_src = args.find(DNNL_GRAPH_ARG_POST_SRC);
if (it_dst == args.end() || it_src == args.end()) {
assert(!("cannot find the required memory"));
return {};
}
const memory &psrc_mem = it_src->second;
const memory &dst_mem = it_dst->second;
if (psrc_mem.get_data_handle() != dst_mem.get_data_handle()) {
auto prim = dnnl::reorder(psrc_mem, dst_mem);
auto e = dnnl::ocl_interop::execute(prim, stream,
{{DNNL_ARG_FROM, const_cast<memory &>(psrc_mem)},
{DNNL_ARG_TO, const_cast<memory &>(dst_mem)}},
deps);
ocl_deps.assign(1, e);
}
}
auto e = dnnl::ocl_interop::execute(prim_, stream, args, ocl_deps);
return e;
}
#endif
reorder_executable_t::desc_t reorder_executable_t::create_desc(
std::shared_ptr<op_t> &op, const dnnl::engine &p_engine,
pd_cache_t &pd_cache, const fpmath_t &fpmath, bool use_block_layout) {
if (pd_cache.find(op.get()) != pd_cache.end()) {
auto pd = graph::utils::any_cast<dnnl::reorder::primitive_desc>(
pd_cache.at(op.get()));
return {pd, true};
}
dnnl::primitive_attr prm_attr;
if (op->has_attr(op_attr::fusion_info)) {
const fusion_info_t &fusion_info
= op->get_attr<fusion_info_t>(op_attr::fusion_info);
prm_attr = make_dnnl_primitive_attr(op, fusion_info);
}
const auto set_reorder_mask = [&op, &prm_attr](int mask) {
if (op->has_attr(op_attr::with_runtime_scales)
&& op->get_attr<bool>(op_attr::with_runtime_scales)) {
auto scale_dt = op->get_input_logical_tensor(1).data_type;
prm_attr.set_scales(DNNL_ARG_SRC, mask, {},
static_cast<dnnl::memory::data_type>(scale_dt));
} else if (op->has_attr(op_attr::scales)) {
assertm(false, "only support runtime arg scales.\n");
}
if (op->has_attr(op_attr::with_runtime_src_zps)
&& op->get_attr<bool>(op_attr::with_runtime_src_zps)) {
prm_attr.set_zero_points_mask(DNNL_ARG_FROM, mask);
} else if (op->has_attr(op_attr::src_zps)) {
assertm(false, "only support runtime src zero points.\n");
}
if (op->has_attr(op_attr::with_runtime_dst_zps)
&& op->get_attr<bool>(op_attr::with_runtime_dst_zps)) {
prm_attr.set_zero_points_mask(DNNL_ARG_TO, mask);
} else if (op->has_attr(op_attr::dst_zps)) {
assertm(false, "only support runtime dst zero points.\n");
}
};
if (op->has_attr(op_attr::qtype)) {
std::string qtype = op->get_attr<std::string>(op_attr::qtype);
int64_t axis = op->has_attr(op_attr::axis)
? op->get_attr<int64_t>(op_attr::axis)
: 1;
if (qtype == "per_group") {
const auto &scale_lt = op->get_input_logical_tensor(1);
const auto scales_data_type = scale_lt.data_type;
const auto &group_shape
= op->get_attr<std::vector<int64_t>>(op_attr::group_shape);
const auto ndims = group_shape.size();
const int mask = (1 << ndims) - 1;
const std::vector<int64_t> groups
= {group_shape[ndims - 2], group_shape[ndims - 1]};
prm_attr.set_scales(DNNL_ARG_FROM, mask, groups,
static_cast<dnnl::memory::data_type>(scales_data_type));
if (op->has_attr(op_attr::with_runtime_src_zps)
&& op->get_attr<bool>(op_attr::with_runtime_src_zps)) {
const auto &zps_lt = op->get_input_logical_tensor(2);
const auto zps_data_type = zps_lt.data_type;
prm_attr.set_zero_points(DNNL_ARG_FROM, mask, groups,
static_cast<dnnl::memory::data_type>(zps_data_type));
}
} else { int mask = 0;
if (qtype == "per_channel") { mask = 1 << axis; }
set_reorder_mask(mask);
}
}
prm_attr.set_scratchpad_mode(dnnl::scratchpad_mode::user);
auto in_md = make_dnnl_memory_desc(op->get_input_logical_tensor(0));
auto out_md = make_dnnl_memory_desc(op->get_output_logical_tensor(0));
auto pd = dnnl::reorder::primitive_desc(
p_engine, in_md, p_engine, out_md, prm_attr);
pd_cache.insert({op.get(), pd});
return {pd, false};
}
arg_indices_t reorder_executable_t::get_arg_indices(const op_t *op) {
arg_indices_t args;
size_t idx = 0;
args.insert({DNNL_ARG_FROM, {indices_t::type_t::input, idx++}});
const fusion_info_t &fusion_info = op->has_attr(op_attr::fusion_info)
? op->get_attr<fusion_info_t>(op_attr::fusion_info)
: fusion_info_t();
if ((op->has_attr(op_attr::with_runtime_scales)
&& op->get_attr<bool>(op_attr::with_runtime_scales))
|| fusion_info.with_runtime_scales(true, 0)) {
args.insert({DNNL_ARG_ATTR_SCALES | DNNL_ARG_SRC,
{indices_t::type_t::input, idx++}});
}
if ((op->has_attr(op_attr::with_runtime_src_zps)
&& op->get_attr<bool>(op_attr::with_runtime_src_zps))
|| fusion_info.with_runtime_zero_points(true, 0)) {
args.insert({DNNL_ARG_ATTR_ZERO_POINTS | DNNL_ARG_SRC,
{indices_t::type_t::input, idx++}});
}
get_arg_indices_for_post_ops(op, args, idx);
if (fusion_info.with_runtime_scales(false, 0)) {
args.insert({DNNL_ARG_ATTR_SCALES | DNNL_ARG_DST,
{indices_t::type_t::input, idx++}});
}
if ((op->has_attr(op_attr::with_runtime_dst_zps)
&& op->get_attr<bool>(op_attr::with_runtime_dst_zps))
|| fusion_info.with_runtime_zero_points(false, 0)) {
args.insert({DNNL_ARG_ATTR_ZERO_POINTS | DNNL_ARG_DST,
{indices_t::type_t::input, idx++}});
}
args.insert({DNNL_ARG_TO, {indices_t::type_t::output, 0}});
if (op->num_outputs() > 1) {
args.insert({DNNL_ARG_SCRATCHPAD, {indices_t::type_t::output, 1}});
}
return args;
}
} } } }