#ifndef CPU_MATMUL_REF_GROUPED_GEMM_HPP
#define CPU_MATMUL_REF_GROUPED_GEMM_HPP
#include "oneapi/dnnl/dnnl_config.h"
#if DNNL_EXPERIMENTAL_GROUPED_MEMORY
#include "common/c_types_map.hpp"
#include "common/memory_desc_wrapper.hpp"
#include "common/primitive.hpp"
#include "common/type_helpers.hpp"
#include "common/utils.hpp"
#include "cpu/matmul/cpu_matmul_pd.hpp"
#include "cpu/primitive_attr_postops.hpp"
namespace dnnl {
namespace impl {
namespace cpu {
namespace matmul {
struct ref_grouped_t : public primitive_t {
struct pd_t : public cpu_matmul_pd_t {
using cpu_matmul_pd_t::cpu_matmul_pd_t;
DECLARE_COMMON_PD_T("ref_grouped:any", ref_grouped_t);
int wei_qmask_K() const { return (1 << 0) | (1 << 1); }
int wei_qmask_N() const { return (1 << 0) | (1 << 2); }
status_t init(engine_t *engine) {
using namespace data_type;
const auto src_type = src_md(0)->data_type;
const auto wei_type = weights_md(0)->data_type;
const auto dst_type = dst_md(0)->data_type;
memory_desc_wrapper src_d(src_md());
memory_desc_wrapper wei_d(weights_md(0));
memory_desc_wrapper dst_d(dst_md());
VDISPATCH_MATMUL(src_d.is_grouped_desc() && dst_d.is_grouped_desc(),
VERBOSE_UNSUPPORTED_SPARSE_CFG);
VDISPATCH_MATMUL(wei_d.is_blocking_desc() && wei_d.ndims() == 3,
VERBOSE_UNSUPPORTED_SPARSE_CFG);
const bool is_fp_src = utils::one_of(
src_type, f32, bf16, f16, f8_e5m2, f8_e4m3, f4_e2m1);
const bool is_fp_wei = utils::one_of(
wei_type, f32, bf16, f16, f8_e5m2, f8_e4m3, f4_e2m1);
const bool is_int_src = utils::one_of(src_type, u8, s8);
const bool is_int_wei = utils::one_of(wei_type, u8, s8, s4, u4);
VDISPATCH_MATMUL(is_fp_src || is_int_src, VERBOSE_UNSUPPORTED_DT);
VDISPATCH_MATMUL(is_fp_wei || is_int_wei, VERBOSE_UNSUPPORTED_DT);
VDISPATCH_MATMUL(utils::one_of(dst_type, f32, bf16, f16),
VERBOSE_UNSUPPORTED_DT);
VDISPATCH_MATMUL(IMPLICATION(is_int_src, is_int_wei),
VERBOSE_UNSUPPORTED_DT_CFG);
VDISPATCH_MATMUL(IMPLICATION(is_fp_src && is_int_wei,
!attr()->scales_.has_default_values(
DNNL_ARG_WEIGHTS)),
VERBOSE_UNSUPPORTED_DT_CFG);
VDISPATCH_MATMUL(IMPLICATION(is_fp_src && is_int_wei,
attr()->fpmath_.apply_to_int_),
VERBOSE_UNSUPPORTED_DT_CFG);
const auto &attr_scales = attr()->scales_;
if (!attr_scales.has_default_values(DNNL_ARG_SRC)) {
const int src_mask = attr_scales.get_mask(DNNL_ARG_SRC);
const int rowwise_mask = src_qmask_M();
const int blocked_mask = src_qmask_M() | src_qmask_K();
VDISPATCH_MATMUL(
src_mask == rowwise_mask || src_mask == blocked_mask,
VERBOSE_UNSUPPORTED_SCALES_CFG);
VDISPATCH_MATMUL(
utils::one_of(attr_scales.get_data_type(DNNL_ARG_SRC),
f32, bf16, f16, e8m0, f8_e4m3, f8_e5m2),
VERBOSE_UNSUPPORTED_SCALES_CFG);
if (!attr_scales.get(DNNL_ARG_SRC).has_default_groups()) {
VDISPATCH_MATMUL(is_int_src || is_fp_src,
VERBOSE_UNSUPPORTED_SCALES_CFG);
const auto gM = attr_scales.get_group(DNNL_ARG_SRC, -2);
VDISPATCH_MATMUL(gM == 1, VERBOSE_UNSUPPORTED_SCALES_CFG);
const auto gK = attr_scales.get_group(DNNL_ARG_SRC, -1);
VDISPATCH_MATMUL(gK > 1, VERBOSE_UNSUPPORTED_SCALES_CFG);
VDISPATCH_MATMUL(
K() % gK == 0, VERBOSE_UNSUPPORTED_SCALES_CFG);
}
}
if (!attr_scales.has_default_values(DNNL_ARG_WEIGHTS)) {
const int wei_mask = attr_scales.get_mask(DNNL_ARG_WEIGHTS);
const int colwise_mask = wei_qmask_N();
const int blocked_mask = wei_qmask_K() | wei_qmask_N();
VDISPATCH_MATMUL(
utils::one_of(
attr_scales.get_data_type(DNNL_ARG_WEIGHTS),
f32, bf16, f16, e8m0, f8_e4m3, f8_e5m2),
VERBOSE_UNSUPPORTED_SCALES_CFG);
VDISPATCH_MATMUL(
wei_mask == colwise_mask || wei_mask == blocked_mask,
VERBOSE_UNSUPPORTED_SCALES_CFG);
if (!attr_scales.get(DNNL_ARG_WEIGHTS).has_default_groups()) {
VDISPATCH_MATMUL(is_int_wei || is_fp_wei,
VERBOSE_UNSUPPORTED_SCALES_CFG);
const auto gK = attr_scales.get_group(DNNL_ARG_WEIGHTS, -2);
VDISPATCH_MATMUL(gK > 1, VERBOSE_UNSUPPORTED_SCALES_CFG);
VDISPATCH_MATMUL(
K() % gK == 0, VERBOSE_UNSUPPORTED_SCALES_CFG);
const auto gN = attr_scales.get_group(DNNL_ARG_WEIGHTS, -1);
VDISPATCH_MATMUL(gN == 1, VERBOSE_UNSUPPORTED_SCALES_CFG);
}
}
VDISPATCH_MATMUL(attr_scales.has_default_values(DNNL_ARG_DST),
VERBOSE_UNSUPPORTED_SCALES_CFG);
const auto &attr_zps = attr()->zero_points_;
VDISPATCH_MATMUL(attr_zps.has_default_values(DNNL_ARG_SRC),
VERBOSE_UNSUPPORTED_ZP_CFG);
VDISPATCH_MATMUL(attr_zps.has_default_values(DNNL_ARG_DST),
VERBOSE_UNSUPPORTED_ZP_CFG);
if (!attr_zps.has_default_values(DNNL_ARG_WEIGHTS)) {
VDISPATCH_MATMUL(is_int_wei, VERBOSE_UNSUPPORTED_ZP_CFG);
VDISPATCH_MATMUL(
utils::one_of(attr_zps.get_data_type(DNNL_ARG_WEIGHTS),
u8, s8, u4, s4, s32),
VERBOSE_UNSUPPORTED_ZP_CFG);
const int zp_mask = attr_zps.get_mask(DNNL_ARG_WEIGHTS);
const int colwise_mask = wei_qmask_N();
const int blocked_mask = wei_qmask_K() | wei_qmask_N();
VDISPATCH_MATMUL(
zp_mask == colwise_mask || zp_mask == blocked_mask,
VERBOSE_UNSUPPORTED_ZP_CFG);
if (!attr_zps.get(DNNL_ARG_WEIGHTS).has_default_groups()) {
const auto gK = attr_zps.get_group(DNNL_ARG_WEIGHTS, -2);
VDISPATCH_MATMUL(gK > 1, VERBOSE_UNSUPPORTED_ZP_CFG);
VDISPATCH_MATMUL(K() % gK == 0, VERBOSE_UNSUPPORTED_ZP_CFG);
const auto gN = attr_zps.get_group(DNNL_ARG_WEIGHTS, -1);
VDISPATCH_MATMUL(gN == 1, VERBOSE_UNSUPPORTED_ZP_CFG);
}
}
if (!attr_scales.has_default_values(DNNL_ARG_SRC)
&& !attr_scales.get(DNNL_ARG_SRC).has_default_groups()
&& !attr_scales.has_default_values(DNNL_ARG_WEIGHTS)
&& !attr_scales.get(DNNL_ARG_WEIGHTS)
.has_default_groups()) {
const auto src_gK = attr_scales.get_group(DNNL_ARG_SRC, -1);
const auto wei_gK = attr_scales.get_group(DNNL_ARG_WEIGHTS, -2);
VDISPATCH_MATMUL(src_gK % wei_gK == 0 || wei_gK % src_gK == 0,
VERBOSE_UNSUPPORTED_SCALES_CFG);
}
if (!attr_scales.has_default_values(DNNL_ARG_WEIGHTS)
&& !attr_zps.has_default_values(DNNL_ARG_WEIGHTS)) {
const auto scale_gK
= attr_scales.get_group(DNNL_ARG_WEIGHTS, -2);
const auto zp_gK = attr_zps.get_group(DNNL_ARG_WEIGHTS, -2);
VDISPATCH_MATMUL(scale_gK == zp_gK, VERBOSE_INCONSISTENT_DIM,
"wei_scale_group_k", (int)scale_gK, "wei_zp_group_k",
(int)zp_gK);
}
const auto &po = attr()->post_ops_;
bool po_ok = true;
for (int i = 0; i < po.len(); ++i) {
const auto &e = po.entry_[i];
po_ok = po_ok && e.is_binary()
&& e.binary.alg == alg_kind::binary_mul;
}
VDISPATCH_MATMUL(po_ok, VERBOSE_UNSUPPORTED_POSTOP);
VDISPATCH_MATMUL(attr_.post_ops_.set_default_formats(dst_md(0))
== status::success,
VERBOSE_UNSUPPORTED_POSTOP);
return status::success;
}
};
ref_grouped_t(const pd_t *apd) : primitive_t(apd) {}
status_t init(engine_t *engine) override {
ref_post_ops
= utils::make_unique<ref_post_ops_t>(pd()->attr()->post_ops_);
if (!ref_post_ops) return status::out_of_memory;
CHECK(ref_post_ops->init(pd()->dst_md()));
return status::success;
}
status_t execute(const exec_ctx_t &ctx) const override;
private:
const pd_t *pd() const { return (const pd_t *)primitive_t::pd().get(); }
std::unique_ptr<ref_post_ops_t> ref_post_ops;
};
} } } }
#endif #endif