#include "cpu/rv64/rvv_gemm_reorder.hpp"
#include "cpu/reorder/simple_reorder.hpp"
#include <cstdint>
#include <iostream>
#include <limits>
#include <unistd.h>
#include <riscv_vector.h>
namespace dnnl {
namespace impl {
namespace cpu {
namespace rv64 {
using namespace dnnl::impl::cpu::q10n;
status_t rvv_matrixA_reorder_t::pd_t::init(
engine_t *engine, engine_t *src_engine, engine_t *dst_engine) {
using namespace status;
using namespace format_tag;
status_t status = cpu_reorder_pd_t::init(engine, src_engine, dst_engine);
if (status != success) return status;
const memory_desc_wrapper id(src_md_), od(dst_md_);
const int ndims = id.ndims();
const auto type_i = id.data_type();
const auto type_o = od.data_type();
const auto in_strides = id.strides();
const auto out_strides = od.strides();
const bool is_row_major = ((in_strides[0] == out_strides[0])
&& (in_strides[1] == out_strides[1])
&& (out_strides[1] == 1))
? true
: false;
const bool dt_ok = true && utils::one_of(type_i, data_type::f32)
&& utils::one_of(type_o, data_type::u8, data_type::s8);
const bool args_ok = dt_ok && ndims == 2 && is_row_major;
if (!args_ok) return invalid_arguments;
init_scratchpad();
return status::success;
}
status_t rvv_matrixA_reorder_t::pd_t::create(reorder_pd_t **reorder_pd,
engine_t *engine, const primitive_attr_t *attr, engine_t *src_engine,
const memory_desc_t *src_md, engine_t *dst_engine,
const memory_desc_t *dst_md) {
auto _pd = make_unique_pd<pd_t>(
attr, src_engine->kind(), src_md, dst_engine->kind(), dst_md);
if (_pd == nullptr) return status::out_of_memory;
CHECK(_pd->init(engine, src_engine, dst_engine));
CHECK(_pd->init_scratchpad_md());
return safe_ptr_assign<reorder_pd_t>(*reorder_pd, _pd.release());
}
template <typename InputType, typename OutputType>
void kernel(InputType *inp, OutputType *out, int N, const float SrcScale,
const float DstScale, const int SrcZeroPoint, const int DstZeroPoint,
const float beta) {
constexpr int32_t MinimumValue = std::numeric_limits<OutputType>::min();
constexpr int32_t MaximumValue = std::numeric_limits<OutputType>::max();
while (N > 0) {
size_t vl = __riscv_vsetvl_e32m1(N);
vfloat32m1_t FloatVector = __riscv_vle32_v_f32m1(inp, vl);
FloatVector
= __riscv_vfsub_vf_f32m1(FloatVector, float(SrcZeroPoint), vl);
FloatVector = __riscv_vfmul_vf_f32m1(FloatVector, SrcScale, vl);
if (beta) {
vuint8mf4_t vec_out_u8 = __riscv_vle8_v_u8mf4((uint8_t *)out, vl);
vuint16mf2_t vec_out_u16
= __riscv_vwcvtu_x_x_v_u16mf2(vec_out_u8, vl);
vuint32m1_t vec_out_u32
= __riscv_vwcvtu_x_x_v_u32m1(vec_out_u16, vl);
vfloat32m1_t vec_out_f32
= __riscv_vfcvt_f_xu_v_f32m1(vec_out_u32, vl);
vfloat32m1_t BetaOut
= __riscv_vfmul_vf_f32m1(vec_out_f32, beta, vl);
FloatVector = __riscv_vfadd_vv_f32m1(FloatVector, BetaOut, vl);
}
FloatVector = __riscv_vfmul_vf_f32m1(FloatVector, DstScale, vl);
FloatVector = __riscv_vfcvt_f_x_v_f32m1(
__riscv_vfcvt_x_f_v_i32m1_rm(FloatVector, __RISCV_FRM_RNE, vl),
vl);
FloatVector
= __riscv_vfadd_vf_f32m1(FloatVector, float(DstZeroPoint), vl);
FloatVector
= __riscv_vfmax_vf_f32m1(FloatVector, float(MinimumValue), vl);
FloatVector
= __riscv_vfmin_vf_f32m1(FloatVector, float(MaximumValue), vl);
vuint32m1_t UIntegerVector
= __riscv_vfcvt_xu_f_v_u32m1(FloatVector, vl);
vuint16mf2_t UShortVector
= __riscv_vncvt_x_x_w_u16mf2(UIntegerVector, vl);
vuint8mf4_t UCharVector = __riscv_vncvt_x_x_w_u8mf4(UShortVector, vl);
__riscv_vse8_v_u8mf4((uint8_t *)out, UCharVector, vl);
out += vl;
inp += vl;
N -= vl;
}
}
status_t rvv_matrixA_reorder_t::execute_body(const exec_ctx_t &ctx) const {
using namespace utils;
const auto input = CTX_IN_MEM(const float *, DNNL_ARG_FROM);
auto output = CTX_OUT_MEM(unsigned char *, DNNL_ARG_TO);
const auto &scratchpad = ctx.get_scratchpad_grantor();
MAYBE_UNUSED(scratchpad);
const auto input_d = ctx.memory_mdw(DNNL_ARG_FROM, pd()->src_md());
DEFINE_ARG_SCALES_BUFFER_ATTR(pd()->attr(), src_scales, DNNL_ARG_FROM);
DEFINE_ARG_SCALES_BUFFER_ATTR(pd()->attr(), dst_scales_, DNNL_ARG_TO);
int src_scales_mask, dst_scales_mask;
CHECK(get_scales_mask(pd()->attr(), &src_scales_mask, &dst_scales_mask));
int scales_mask = std::max(src_scales_mask, dst_scales_mask);
MAYBE_UNUSED(scales_mask);
dim_t D_start, D_mask, D_rest;
pd()->get_D_values(input_d, scales_mask, &D_start, &D_mask, &D_rest);
const float *dst_scales = pd()->precompute_scales(
scratchpad, pd()->attr(), D_mask, dst_scales_);
const int32_t *src_zero_points = CTX_IN_MEM(
const int32_t *, DNNL_ARG_ATTR_ZERO_POINTS | DNNL_ARG_FROM);
int src_zp = src_zero_points ? src_zero_points[0] : 0;
const int32_t *dst_zero_points = CTX_IN_MEM(
const int32_t *, DNNL_ARG_ATTR_ZERO_POINTS | DNNL_ARG_TO);
int dst_zp = dst_zero_points ? dst_zero_points[0] : 0;
const float alpha = src_scales[0] * dst_scales[0];
MAYBE_UNUSED(alpha);
const float beta = pd()->beta();
const auto &dims = input_d.dims();
const auto in_strides = input_d.blocking_desc().strides;
const auto M = dims[0];
const auto K = dims[1];
dim_t M_b = 16;
dim_t K_b = 64;
K_b = std::min(K_b, K);
const dim_t num_M_blocks = (M + M_b - 1) / M_b;
const dim_t num_K_blocks = (K + K_b - 1) / K_b;
parallel_nd(num_M_blocks, num_K_blocks, [&](dim_t mb, dim_t kb) {
dim_t M_start = mb * M_b;
dim_t M_end = nstl::min(M_start + M_b, M);
dim_t K_start = kb * K_b;
dim_t K_end = nstl::min(K_start + K_b, K);
for (dim_t i = M_start; i < M_end; ++i) {
kernel<const float, unsigned char>(
input + i * in_strides[0] + K_start,
output + i * in_strides[0] + K_start, K_end - K_start,
src_scales[0], dst_scales[0], src_zp, dst_zp, beta);
}
});
return status::success;
}
} } } }