#ifndef CPU_X64_RNN_JIT_UNI_LSTM_CELL_POSTGEMM_HPP
#define CPU_X64_RNN_JIT_UNI_LSTM_CELL_POSTGEMM_HPP
#include "common/utils.hpp"
#include "cpu/x64/jit_generator.hpp"
namespace dnnl {
namespace impl {
namespace cpu {
namespace x64 {
template <cpu_isa_t isa>
struct jit_uni_lstm_cell_postgemm_t {
jit_uni_lstm_cell_postgemm_t(
jit_generator_t *host, int tmp_id_begin, bool use_bf16_emu)
: host_(host)
, min_allowed_tmp_vmm_idx_(0)
, max_allowed_tmp_vmm_idx_(cpu_isa_traits_t<isa>::n_vregs - 1
- (is_superset(isa, avx512_core) && use_bf16_emu ? 4 : 0)) {
reset_tmp_vmm_idx_range(tmp_id_begin, max_allowed_tmp_vmm_idx_);
}
protected:
using injector_t = jit_uni_eltwise_injector_t<isa>;
using Vmm = typename cpu_isa_traits_t<isa>::Vmm;
const size_t vlen_ = cpu_isa_traits_t<isa>::vlen;
Vmm get_next_tmp_vmm() {
const Vmm vmm {current_tmp_id_++};
if (current_tmp_id_ > tmp_id_last_) reset_vmm_cnt();
return vmm;
}
Vmm maybe_get_next_tmp_vmm_for_below_avx2_isa() {
if (!this->avx2_available_) return get_next_tmp_vmm();
return Vmm(0); }
void reset_vmm_cnt() { current_tmp_id_ = tmp_id_first_; }
int get_min_allowed_tmp_vmm_allowed_idx() const {
return min_allowed_tmp_vmm_idx_;
}
int get_max_allowed_tmp_vmm_allowed_idx() const {
return max_allowed_tmp_vmm_idx_;
}
void reset_tmp_vmm_idx_range(int lower_idx, int upper_idx) {
assert(lower_idx >= get_min_allowed_tmp_vmm_allowed_idx()
&& upper_idx <= get_max_allowed_tmp_vmm_allowed_idx()
&& lower_idx <= upper_idx);
tmp_id_first_ = lower_idx;
tmp_id_last_ = upper_idx;
reset_vmm_cnt();
}
Xbyak::Xmm get_next_tmp_xmm() {
return Xbyak::Xmm(get_next_tmp_vmm().getIdx());
}
Vmm vmm_backup(const Vmm &vmm) {
auto tmp_vmm = vmm;
if (!this->avx2_available_) {
tmp_vmm = this->get_next_tmp_vmm();
host_->uni_vmovups(tmp_vmm, vmm);
}
return tmp_vmm;
}
Xbyak::Xmm xmm_backup(const Xbyak::Xmm &xmm) {
auto tmp_xmm = xmm;
if (!this->avx2_available_) {
tmp_xmm = this->get_next_tmp_xmm();
host_->uni_vmovss(tmp_xmm, xmm);
}
return tmp_xmm;
}
void vaddps_rhs_op_mem(
const Vmm &dst, const Vmm &lhs, const Xbyak::Address &rhs_addr) {
if (avx2_available_)
host_->uni_vaddps(dst, lhs, rhs_addr);
else {
const auto rhs = get_next_tmp_vmm();
host_->uni_vmovups(rhs, rhs_addr);
host_->uni_vaddps(dst, lhs, rhs);
}
}
void vfmadd231ps_rhs_op_mem(
const Vmm &dst, const Vmm &lhs, const Xbyak::Address &rhs_addr) {
if (avx2_available_)
host_->uni_vfmadd231ps(dst, lhs, rhs_addr);
else {
const auto tmp = get_next_tmp_vmm();
host_->uni_vmovups(tmp, rhs_addr);
const auto &rhs = lhs;
host_->uni_vfmadd231ps(dst, tmp, rhs);
}
}
void vmulps_rhs_op_mem(
const Vmm &dst, const Vmm &lhs, const Xbyak::Address &rhs_addr) {
if (avx2_available_)
host_->uni_vmulps(dst, lhs, rhs_addr);
else {
const auto rhs = get_next_tmp_vmm();
host_->uni_vmovups(rhs, rhs_addr);
host_->uni_vmulps(dst, lhs, rhs);
}
}
void vaddss_rhs_op_mem(const Xbyak::Xmm &dst, const Xbyak::Xmm &lhs,
const Xbyak::Address &rhs_addr) {
if (avx2_available_)
host_->uni_vaddss(dst, lhs, rhs_addr);
else {
const auto rhs = get_next_tmp_xmm();
host_->uni_vmovss(rhs, rhs_addr);
host_->uni_vaddss(dst, lhs, rhs);
}
}
void vfmadd231ss_rhs_op_mem(const Xbyak::Xmm &dst, const Xbyak::Xmm &lhs,
const Xbyak::Address &rhs_addr) {
if (avx2_available_)
host_->uni_vfmadd231ss(dst, lhs, rhs_addr);
else {
const auto tmp = get_next_tmp_xmm();
host_->uni_vmovss(tmp, rhs_addr);
const auto &rhs = lhs;
host_->uni_vfmadd231ss(dst, tmp, rhs);
}
}
void vmulss_rhs_op_mem(const Xbyak::Xmm &dst, const Xbyak::Xmm &lhs,
const Xbyak::Address &rhs_addr) {
if (avx2_available_)
host_->uni_vmulss(dst, lhs, rhs_addr);
else {
const auto rhs = get_next_tmp_xmm();
host_->uni_vmovss(rhs, rhs_addr);
host_->uni_vmulss(dst, lhs, rhs);
}
}
const bool avx2_available_ = is_superset(isa, avx2);
private:
jit_generator_t *host_;
const int min_allowed_tmp_vmm_idx_;
const int max_allowed_tmp_vmm_idx_;
int tmp_id_first_;
int current_tmp_id_;
int tmp_id_last_;
};
} } } }
#endif