#include "gpu/intel/binary/simple.hpp"
#include "gpu/intel/binary/config.hpp"
namespace dnnl {
namespace impl {
namespace gpu {
namespace intel {
namespace binary {
status_t simple_t::pd_t::init_conf(impl::engine_t *engine) {
const memory_desc_wrapper src0_d(src_md(0));
const memory_desc_wrapper src1_d(src_md(1));
const memory_desc_wrapper src2_d(src_md(2));
const memory_desc_wrapper dst_d(dst_md());
const int ndims = src0_d.ndims();
conf.src0_md_info = memory_desc_info_t::create(src0_d);
conf.src1_md_info = memory_desc_info_t::create(src1_d);
conf.dst_md_info = memory_desc_info_t::create(dst_d);
if (is_ternary_op()) {
conf.src2_md_info = memory_desc_info_t::create(src2_d);
conf.src2_data_type = src2_d.data_type();
} else {
conf.src2_md_info = memory_desc_info_t();
}
conf.src0_data_type = src0_d.data_type();
conf.src1_data_type = src1_d.data_type();
conf.dst_data_type = dst_d.data_type();
conf.ndims = ndims;
bool is_src0_bcasted = false;
for (int i = 0; i < MAX_NDIMS; ++i) {
conf.src0_bcast_dims[i] = i < ndims
? src0_d.dims()[i] == 1 && src0_d.dims()[i] != src1_d.dims()[i]
: 0;
is_src0_bcasted = is_src0_bcasted || conf.src0_bcast_dims[i];
conf.src1_bcast_dims[i] = i < ndims
? src1_d.dims()[i] == 1 && src0_d.dims()[i] != src1_d.dims()[i]
: 0;
if (is_ternary_op()) {
conf.src2_bcast_dims[i] = i < ndims
? (src2_d.dims()[i] == 1
&& src2_d.dims()[i] != dst_d.dims()[i])
: 0;
}
}
conf.alg = desc()->alg_kind;
conf.is_tensor_op = is_tensor_op();
conf.is_dense = dst_d.is_dense();
conf.same_src_dt = (src0_d.data_type() == src1_d.data_type());
conf.is_same_md = (src0_d == dst_d) && (src1_d == dst_d);
conf.attr_info = attr_info_t::create(attr());
conf.with_binary_post_op
= attr()->post_ops_.find(primitive_kind::binary) != -1;
int ic_block_sz = 1;
conf.use_unroll_16b = false;
conf.src0_unroll_16b = false;
auto &blk0 = src0_d.blocking_desc();
auto &blk1 = src1_d.blocking_desc();
auto &blkd = dst_d.blocking_desc();
bool is_16b_blk0 = (blk0.inner_nblks >= 1)
&& (blk0.inner_idxs[blk0.inner_nblks - 1] == 1)
&& (blk0.inner_blks[blk0.inner_nblks - 1] == 16);
bool is_16b_blk1 = (blk1.inner_nblks >= 1)
&& (blk1.inner_idxs[blk1.inner_nblks - 1] == 1)
&& (blk1.inner_blks[blk1.inner_nblks - 1] == 16);
bool is_16b_blkd = (blkd.inner_nblks >= 1)
&& (blkd.inner_idxs[blkd.inner_nblks - 1] == 1)
&& (blkd.inner_blks[blkd.inner_nblks - 1] == 16);
if (is_16b_blkd && !conf.is_tensor_op && !is_src0_bcasted) {
if (is_16b_blk0 && is_16b_blk1) {
ic_block_sz = 16;
conf.use_unroll_16b = true;
} else if (is_16b_blk0 && blk1.inner_nblks == 0) {
ic_block_sz = 16;
conf.src0_unroll_16b = true;
}
}
auto *intel_engine = utils::downcast<intel::engine_t *>(engine);
conf.dispatch = intel_engine->create_dispatch(dst_d.md_);
if (conf.is_tensor_op && conf.is_dense && conf.is_same_md
&& !conf.with_binary_post_op) {
conf.dispatch.define_dim("IDX", 0, dst_d.nelems());
} else {
for (int i = 0; i < MAX_NDIMS; ++i) {
if (i == 1 && (conf.use_unroll_16b || conf.src0_unroll_16b)) {
conf.dispatch.define_dim(utils::format("D%d", i),
nstl::min(i, ndims - 1),
i < ndims ? dst_d.padded_dims()[i] : 1, ic_block_sz);
} else {
conf.dispatch.define_dim(utils::format("D%d", i),
nstl::min(i, ndims - 1),
i < ndims ? dst_d.padded_dims()[i] : 1);
}
}
}
conf.dispatch.generate();
return status::success;
}
status_t simple_t::pd_t::init_kernel_ctx(
compute::kernel_ctx_t &kernel_ctx) const {
kernel_ctx.require_stateless_addressing(has_large_buffers());
kernel_ctx.define_int("BINARY_ALG", conf.alg);
kernel_ctx.define_int("IS_TERNARY", (conf.alg == alg_kind::binary_select));
kernel_ctx.set_data_type(conf.src0_data_type);
kernel_ctx.set_data_type(conf.src1_data_type);
kernel_ctx.set_data_type(conf.dst_data_type);
kernel_ctx.define_int("NDIMS", conf.ndims);
kernel_ctx.define_int("IS_PLAIN_LAYOUT", true);
kernel_ctx.define_int("IS_TENSOR_OP", conf.is_tensor_op);
kernel_ctx.define_int("IS_DENSE", conf.is_dense);
kernel_ctx.define_int("IS_SAME_MD", conf.is_same_md);
kernel_ctx.define_int("WITH_BINARY_POST_OP", conf.with_binary_post_op);
kernel_ctx.define_int("SAME_SRC_DT", conf.same_src_dt);
kernel_ctx.define_int("SRC0_BCAST_DIM0", conf.src0_bcast_dims[0]);
kernel_ctx.define_int("SRC0_BCAST_DIM1", conf.src0_bcast_dims[1]);
kernel_ctx.define_int("SRC0_BCAST_DIM2", conf.src0_bcast_dims[2]);
kernel_ctx.define_int("SRC0_BCAST_DIM3", conf.src0_bcast_dims[3]);
kernel_ctx.define_int("SRC0_BCAST_DIM4", conf.src0_bcast_dims[4]);
kernel_ctx.define_int("SRC0_BCAST_DIM5", conf.src0_bcast_dims[5]);
kernel_ctx.define_int("SRC1_BCAST_DIM0", conf.src1_bcast_dims[0]);
kernel_ctx.define_int("SRC1_BCAST_DIM1", conf.src1_bcast_dims[1]);
kernel_ctx.define_int("SRC1_BCAST_DIM2", conf.src1_bcast_dims[2]);
kernel_ctx.define_int("SRC1_BCAST_DIM3", conf.src1_bcast_dims[3]);
kernel_ctx.define_int("SRC1_BCAST_DIM4", conf.src1_bcast_dims[4]);
kernel_ctx.define_int("SRC1_BCAST_DIM5", conf.src1_bcast_dims[5]);
kernel_ctx.define_int("USE_UNROLL_16B", conf.use_unroll_16b);
kernel_ctx.define_int("SRC0_UNROLL_16B", conf.src0_unroll_16b);
kernel_ctx.define_int("SUB_GROUP_SIZE", 1);
def_memory_desc_info(kernel_ctx, conf.src0_md_info, "SRC0");
def_memory_desc_info(kernel_ctx, conf.src1_md_info, "SRC1");
def_memory_desc_info(kernel_ctx, conf.dst_md_info, "DST");
if (conf.alg == alg_kind::binary_select) {
kernel_ctx.define_int("SRC2_BCAST_DIM0", conf.src2_bcast_dims[0]);
kernel_ctx.define_int("SRC2_BCAST_DIM1", conf.src2_bcast_dims[1]);
kernel_ctx.define_int("SRC2_BCAST_DIM2", conf.src2_bcast_dims[2]);
kernel_ctx.define_int("SRC2_BCAST_DIM3", conf.src2_bcast_dims[3]);
kernel_ctx.define_int("SRC2_BCAST_DIM4", conf.src2_bcast_dims[4]);
kernel_ctx.define_int("SRC2_BCAST_DIM5", conf.src2_bcast_dims[5]);
def_memory_desc_info(kernel_ctx, conf.src2_md_info, "SRC2");
}
CHECK(def_attr_info(
kernel_ctx, conf.attr_info, attr()->post_ops_, *dst_md()));
def_dispatch(kernel_ctx, conf.dispatch);
return status::success;
}
status_t simple_t::execute_simple(const exec_ctx_t &ctx) const {
status_t status = status::success;
auto &src0 = CTX_IN_STORAGE(DNNL_ARG_SRC_0);
auto &src1 = CTX_IN_STORAGE(DNNL_ARG_SRC_1);
auto &dst = CTX_OUT_STORAGE(DNNL_ARG_DST);
CHECK(status);
const auto &conf = pd()->conf;
auto &src0_scale = CTX_IN_STORAGE(DNNL_ARG_SRC_0 | DNNL_ARG_ATTR_SCALES);
auto &src1_scale = CTX_IN_STORAGE(DNNL_ARG_SRC_1 | DNNL_ARG_ATTR_SCALES);
unsigned arg_idx = 0;
compute::kernel_arg_list_t arg_list;
arg_list.set(arg_idx++, src0);
arg_list.set(arg_idx++, src1);
if (pd()->is_ternary_op()) {
auto &src2 = CTX_IN_STORAGE(DNNL_ARG_SRC_2);
arg_list.set(arg_idx++, src2);
}
arg_list.set(arg_idx++, dst);
arg_idx = append_post_ops_to_arg_list(
ctx, arg_list, arg_idx, pd()->attr()->post_ops_, *pd()->dst_md());
arg_list.set(arg_idx++, src0_scale);
arg_list.set(arg_idx, src1_scale);
auto nd_range = conf.dispatch.nd_range();
status = parallel_for(ctx, nd_range, kernel_, arg_list);
return status;
}
} } } } }