#include "cpu/ppc64/ppc64_gemm_reorder.hpp"
#include "cpu/reorder/simple_reorder.hpp"
#include <altivec.h>
#include <cstdint>
#include <iostream>
#include <unistd.h>
namespace dnnl {
namespace impl {
namespace cpu {
namespace ppc64 {
using namespace dnnl::impl::cpu::q10n;
typedef __vector signed long long vec_i64 __attribute__((aligned(8)));
typedef __vector short vec_i16 __attribute__((aligned(2)));
typedef __vector unsigned char vec_ut;
typedef __vector signed char vec_t;
typedef __vector signed short vec_short_t;
typedef __vector signed int vec_int_t;
typedef __vector float vec_float_t;
status_t ppc64_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 ppc64_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());
}
typedef __vector unsigned int VecUInt;
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();
__vector float SrcScaleVector = vec_splats(SrcScale);
__vector float DstScaleVector = vec_splats(DstScale);
__vector float MinimumValueVector = vec_splats(float(MinimumValue));
__vector float MaximumValueVector = vec_splats(float(MaximumValue));
__vector float SrcZeroPointVector = vec_splats(float(SrcZeroPoint));
__vector float DstZeroPointVector = vec_splats(float(DstZeroPoint));
while (N >= 16) {
auto FloatVector0 = vec_xl(0, inp);
auto FloatVector1 = vec_xl(0, inp + 4);
auto FloatVector2 = vec_xl(0, inp + 8);
auto FloatVector3 = vec_xl(0, inp + 12);
FloatVector0 = vec_sub(FloatVector0, SrcZeroPointVector);
FloatVector0 = vec_mul(FloatVector0, SrcScaleVector);
FloatVector1 = vec_sub(FloatVector1, SrcZeroPointVector);
FloatVector1 = vec_mul(FloatVector1, SrcScaleVector);
FloatVector2 = vec_sub(FloatVector2, SrcZeroPointVector);
FloatVector2 = vec_mul(FloatVector2, SrcScaleVector);
FloatVector3 = vec_sub(FloatVector3, SrcZeroPointVector);
FloatVector3 = vec_mul(FloatVector3, SrcScaleVector);
if (beta) {
FloatVector0[0] += beta * (float)out[0];
FloatVector0[1] += beta * (float)out[1];
FloatVector0[2] += beta * (float)out[2];
FloatVector0[3] += beta * (float)out[3];
FloatVector1[0] += beta * (float)out[4];
FloatVector1[1] += beta * (float)out[5];
FloatVector1[2] += beta * (float)out[6];
FloatVector1[3] += beta * (float)out[7];
FloatVector2[0] += beta * (float)out[8];
FloatVector2[1] += beta * (float)out[9];
FloatVector2[2] += beta * (float)out[10];
FloatVector2[3] += beta * (float)out[11];
FloatVector3[0] += beta * (float)out[12];
FloatVector3[1] += beta * (float)out[13];
FloatVector3[2] += beta * (float)out[14];
FloatVector3[3] += beta * (float)out[15];
}
FloatVector0 = vec_mul(FloatVector0, DstScaleVector);
FloatVector1 = vec_mul(FloatVector1, DstScaleVector);
FloatVector2 = vec_mul(FloatVector2, DstScaleVector);
FloatVector3 = vec_mul(FloatVector3, DstScaleVector);
FloatVector0 = vec_round(FloatVector0);
FloatVector1 = vec_round(FloatVector1);
FloatVector2 = vec_round(FloatVector2);
FloatVector3 = vec_round(FloatVector3);
FloatVector0 = vec_add(FloatVector0, DstZeroPointVector);
FloatVector1 = vec_add(FloatVector1, DstZeroPointVector);
FloatVector2 = vec_add(FloatVector2, DstZeroPointVector);
FloatVector3 = vec_add(FloatVector3, DstZeroPointVector);
FloatVector0 = vec_max(FloatVector0, MinimumValueVector);
FloatVector1 = vec_max(FloatVector1, MinimumValueVector);
FloatVector2 = vec_max(FloatVector2, MinimumValueVector);
FloatVector3 = vec_max(FloatVector3, MinimumValueVector);
FloatVector0 = vec_min(FloatVector0, MaximumValueVector);
FloatVector1 = vec_min(FloatVector1, MaximumValueVector);
FloatVector2 = vec_min(FloatVector2, MaximumValueVector);
FloatVector3 = vec_min(FloatVector3, MaximumValueVector);
VecUInt IntegerVector0 = vec_ctu(FloatVector0, 0);
VecUInt IntegerVector1 = vec_ctu(FloatVector1, 0);
VecUInt IntegerVector2 = vec_ctu(FloatVector2, 0);
VecUInt IntegerVector3 = vec_ctu(FloatVector3, 0);
auto ShortVector0 = vec_pack(IntegerVector0, IntegerVector1);
auto ShortVector1 = vec_pack(IntegerVector2, IntegerVector3);
auto CharVector = vec_pack(ShortVector0, ShortVector1);
vec_xst(CharVector, 0, (uint8_t *)out);
out += 16;
inp += 16;
N -= 16;
}
#ifdef __MMA__
while (N >= 4) {
auto FloatVector = vec_xl(0, inp);
FloatVector = vec_sub(FloatVector, SrcZeroPointVector);
FloatVector = vec_mul(FloatVector, SrcScaleVector);
if (beta) {
FloatVector[0] += beta * (float)out[0];
FloatVector[1] += beta * (float)out[1];
FloatVector[2] += beta * (float)out[2];
FloatVector[3] += beta * (float)out[3];
}
FloatVector = vec_mul(FloatVector, DstScaleVector);
FloatVector = vec_round(FloatVector);
FloatVector = vec_add(FloatVector, DstZeroPointVector);
FloatVector = vec_max(FloatVector, MinimumValueVector);
FloatVector = vec_min(FloatVector, MaximumValueVector);
auto IntegerVector = vec_ctu(FloatVector, 0);
auto ShortVector = vec_pack(IntegerVector, vec_splats((uint32_t)0));
auto CharVector = vec_pack(ShortVector, vec_splats((uint16_t)0));
vec_xst_len(CharVector, (uint8_t *)out, N);
out += 4;
inp += 4;
N -= 4;
}
if (N > 0) {
auto FloatVector = vec_xl_len(const_cast<float *>(inp), 4 * N);
FloatVector = vec_sub(FloatVector, SrcZeroPointVector);
FloatVector = vec_mul(FloatVector, SrcScaleVector);
if (beta) {
if (N == 1) { FloatVector[0] += beta * (float)out[0]; }
if (N == 2) {
FloatVector[0] += beta * (float)out[0];
FloatVector[1] += beta * (float)out[1];
}
if (N == 3) {
FloatVector[0] += beta * (float)out[0];
FloatVector[1] += beta * (float)out[1];
FloatVector[2] += beta * (float)out[2];
}
}
FloatVector = vec_mul(FloatVector, DstScaleVector);
FloatVector = vec_round(FloatVector);
FloatVector = vec_add(FloatVector, DstZeroPointVector);
FloatVector = vec_max(FloatVector, MinimumValueVector);
FloatVector = vec_min(FloatVector, MaximumValueVector);
auto IntegerVector = vec_ctu(FloatVector, 0);
auto ShortVector = vec_pack(IntegerVector, vec_splats((uint32_t)0));
auto CharVector = vec_pack(ShortVector, vec_splats((uint16_t)0));
vec_xst_len(CharVector, (uint8_t *)out, N);
}
#else
while (N > 0) {
float val = (*inp - SrcZeroPoint) * SrcScale;
if (beta) val += beta * *out;
val = val * DstScale + DstZeroPoint;
val = std::fmin(
std::fmax(val, float(MinimumValue)), float(MaximumValue));
*out = uint8_t(std::nearbyint(val));
inp++;
out++;
N -= 1;
}
#endif
}
status_t ppc64_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;
}
} } } }