#include "cpu/x64/rnn/jit_brgemm_transpose_single_row.hpp"
#include <cmath>
#include "cpu/rnn/rnn_utils.hpp"
namespace dnnl {
namespace impl {
namespace cpu {
namespace x64 {
jit_brgemm_transpose_single_row_t::jit_brgemm_transpose_single_row_t(
const int m_block)
: jit_generator_t(jit_name())
, m_block_(m_block)
, full_loop_iters_(m_block_ / (vmms_available_ * simd_w_))
, tail_(m_block_ % simd_w_)
, k_blocks_nb_(m_block_ / simd_w_) {}
void jit_brgemm_transpose_single_row_t::generate() {
preamble();
load_addresses();
compute_loop();
postamble();
}
#define PARAM_OFF(x) \
offsetof(jit_brgemm_transpose_single_row_t::call_params_t, x)
void jit_brgemm_transpose_single_row_t::load_addresses() {
mov(reg_src_, ptr[abi_param1 + PARAM_OFF(src)]);
mov(reg_dst_, ptr[abi_param1 + PARAM_OFF(dst)]);
}
#undef PARAM
void jit_brgemm_transpose_single_row_t::compute(
const dim_t unrolling, const bool is_tail) {
if (is_tail) {
mov(reg_tmp_.cvt32(), std::pow(2, tail_) - 1);
kmovd(tail_mask_, reg_tmp_.cvt32());
}
for (int k = unrolling - 1; k >= 0; k--) {
const auto read_vmm
= is_tail ? Xbyak::Zmm(k) | tail_mask_ | T_z : Xbyak::Zmm(k);
const auto src_off = k * simd_w_ * sizeof(bfloat16_t);
vpmovzxwd(read_vmm, ptr[reg_src_ + src_off]);
}
for (int k = unrolling - 1; k >= 0; k--) {
const auto store_vmm
= is_tail ? Xbyak::Zmm(k) | tail_mask_ : Xbyak::Zmm(k);
const auto dst_off = k * simd_w_ * sizeof(float);
uni_vmovups(ptr[reg_dst_ + dst_off], store_vmm);
}
}
void jit_brgemm_transpose_single_row_t::compute_loop() {
Xbyak::Label unroll_full_loop, loop_end;
if (full_loop_iters_ > 0) {
const auto loop_l_off = vmms_available_ * simd_w_;
const auto loop_src_off = loop_l_off * sizeof(bfloat16_t);
const auto loop_dst_off = loop_l_off * sizeof(float);
mov(reg_full_loop_, full_loop_iters_);
L(unroll_full_loop);
{
cmp(reg_full_loop_, 0);
je(loop_end, T_NEAR);
compute(vmms_available_, false);
add(reg_src_, loop_src_off);
add(reg_dst_, loop_dst_off);
dec(reg_full_loop_);
jmp(unroll_full_loop);
}
L(loop_end);
}
const int k_blocks_left = k_blocks_nb_ - full_loop_iters_ * vmms_available_;
if (k_blocks_left > 0) {
const auto off = k_blocks_left * simd_w_;
const auto src_off = off * sizeof(bfloat16_t);
const auto dst_off = off * sizeof(float);
compute(k_blocks_left, false);
add(reg_src_, src_off);
add(reg_dst_, dst_off);
}
if (tail_ > 0) compute(1, true);
}
#undef PARAM_OFF
} } } }