#ifndef CPU_X64_LRN_JIT_UNI_LRN_KERNEL_HPP
#define CPU_X64_LRN_JIT_UNI_LRN_KERNEL_HPP
#include "common/c_types_map.hpp"
#include "common/type_helpers.hpp"
#include "cpu/x64/jit_generator.hpp"
#include "cpu/x64/utils/jit_io_helper.hpp"
namespace dnnl {
namespace impl {
namespace cpu {
namespace x64 {
struct bf16_emulation_t;
struct jit_args_fwd_t {
const void *src;
void *dst, *scratch, *bwd_intermediate_res;
};
struct jit_args_bwd_t {
const void *src, *diff_dst, *scratch, *bwd_intermediate_res;
void *diff_src;
};
struct nchw8c_across_t {
int H, W, version;
nchw8c_across_t(int h, int w, int v) : H(h), W(w), version(v) {}
nchw8c_across_t() : nchw8c_across_t(0, 0, 0) {}
};
struct within_config_t {
const int H, W, C, size;
const format_tag_t dat_tag;
within_config_t(int h, int w, int c, int s, format_tag_t dat_tag)
: H(h), W(w), C(c), size(s), dat_tag(dat_tag) {}
within_config_t() : within_config_t(0, 0, 0, 0, dnnl_format_tag_undef) {}
};
struct nchw_across_t {
int C, HW, tail;
nchw_across_t(int c, int hw, int t) : C(c), HW(hw), tail(t) {}
nchw_across_t() : nchw_across_t(0, 0, 0) {}
};
struct nhwc_across_t {
int C;
nhwc_across_t(int c) : C(c) {}
nhwc_across_t() : nhwc_across_t(0) {}
};
enum class lrn_config_t {
none = 0,
nchw8c_across,
within_config,
nchw_across,
nhwc_across,
};
template <class Derived>
class jit_uni_lrn_kernel_t;
template <template <cpu_isa_t isa, data_type_t d_type> class Derived,
cpu_isa_t isa, data_type_t d_type>
class jit_uni_lrn_kernel_t<Derived<isa, d_type>> : public jit_generator_t {
public:
jit_uni_lrn_kernel_t(const char *name = jit_name());
jit_uni_lrn_kernel_t(
const within_config_t &J, const char *name = jit_name());
~jit_uni_lrn_kernel_t() override;
DECLARE_CPU_JIT_AUX_FUNCTIONS(jit_uni_lrn_kernel_t);
static constexpr int VECTOR_LENGTH
= (cpu_isa_traits_t<(isa > sse41 ? isa : avx2)>::vlen
/ sizeof(float));
protected:
using Vmm = typename cpu_isa_traits_t<isa>::Vmm;
void load_constant(float constant, const Vmm &v_constant,
const Xbyak::Xmm &x_constant);
void within_loop(
const within_config_t &config, int max_reg_blocks, prop_kind_t pk);
void within_body_reg_blocked(int loop_count, int max_reg_block, int hoff,
int Hoff, int woff, int Woff, int stride, prop_kind_t pk);
const bool emulate_bfloat_ = false;
const Xbyak::Zmm bf16_emu_reserv_1_ = Xbyak::Zmm(28);
const Xbyak::Zmm bf16_emu_reserv_2_ = Xbyak::Zmm(29);
const Xbyak::Reg64 bf16_emu_scratch_ = this->rax;
const Xbyak::Zmm bf16_emu_reserv_3_ = Xbyak::Zmm(30);
const Xbyak::Zmm bf16_emu_reserv_4_ = Xbyak::Zmm(31);
std::unique_ptr<bf16_emulation_t> bf16_emu_;
const Xbyak::Reg64 h_ = this->r9;
const Xbyak::Reg64 w_ = this->r10;
const Xbyak::Reg64 imm_addr64_ = this->rbx;
const Xbyak::Reg64 reg_tmp_ = this->rsi;
static constexpr size_t simd_w_
= cpu_isa_traits_t<isa>::vlen / sizeof(float);
int single_pixel_offset_
= VECTOR_LENGTH * sizeof(typename prec_traits_t<d_type>::type);
io::jit_io_multi_dt_helper_t<Vmm> io_;
};
template <cpu_isa_t isa, data_type_t d_type>
class jit_uni_lrn_fwd_kernel_t
: public jit_uni_lrn_kernel_t<jit_uni_lrn_fwd_kernel_t<isa, d_type>> {
public:
DECLARE_CPU_JIT_AUX_FUNCTIONS(jit_uni_lrn_fwd_kernel_t)
jit_uni_lrn_fwd_kernel_t(
const within_config_t &J, float A, float K, prop_kind_t pk);
jit_uni_lrn_fwd_kernel_t(
const nchw8c_across_t &J, float A, float K, prop_kind_t pk);
jit_uni_lrn_fwd_kernel_t(
const nhwc_across_t &J, float A, float K, prop_kind_t pk);
jit_uni_lrn_fwd_kernel_t(
const nchw_across_t &J, float A, float K, prop_kind_t pk);
~jit_uni_lrn_fwd_kernel_t() override;
private:
using Base = jit_uni_lrn_kernel_t<jit_uni_lrn_fwd_kernel_t<isa, d_type>>;
void generate() override {
switch (config_) {
case lrn_config_t::within_config:
generate(this->within_config_);
return;
case lrn_config_t::nchw8c_across:
generate(this->nchw8c_across_);
return;
case lrn_config_t::nhwc_across:
generate(this->nhwc_across_);
return;
case lrn_config_t::nchw_across:
generate(this->nchw_across_);
return;
default: assert(!"Configuration not supported"); return;
}
}
void generate(const within_config_t &config);
void generate(const nchw8c_across_t &config);
void generate(const nhwc_across_t &config);
void generate(const nchw_across_t &config);
public:
using Base::VECTOR_LENGTH;
private:
friend Base;
using typename Base::Vmm;
void within_body(int hoff, int Hoff, int woff, int Woff, int stride,
prop_kind_t pk, int reg_block = 1, int single_pixel_offset = 0);
void nchw_body(int tail, int HW, prop_kind_t pk, Xbyak::Ymm ymask,
Xbyak::Ymm ya, Xbyak::Ymm yb, Xbyak::Ymm yc, Xbyak::Ymm yd,
Xbyak::Ymm ye, Xbyak::Ymm ysum);
void nchw_body_sse41(int tail, int HW, prop_kind_t pk, Xbyak::Xmm xe_lo,
Xbyak::Xmm xe_hi, Xbyak::Xmm xsum_lo, Xbyak::Xmm xsum_hi);
void nchw_tail_sse41(int tail, Xbyak::Reg64 reg_dst, Xbyak::Xmm xtail_lo,
Xbyak::Xmm xtail_hi);
void move_data_pointers(int pixel_count, prop_kind_t pk);
const Xbyak::Reg64 src_ = this->rax;
const Xbyak::Reg64 dst_ = this->r8;
const Xbyak::Reg64 scratch_ = this->r14;
const Xbyak::Reg64 bwd_intermediate_res_ = this->rdx;
const Xbyak::Reg64 store_addr_ = this->rbp;
const Xbyak::Xmm xalpha_ = this->xmm0;
const Xbyak::Xmm xk_ = this->xmm1;
const Xbyak::Ymm yk_ = this->ymm1;
const Vmm valpha_ = Vmm(0);
const Vmm vk_ = Vmm(1);
lrn_config_t config_;
const nchw8c_across_t nchw8c_across_;
const within_config_t within_config_;
const nchw_across_t nchw_across_;
const nhwc_across_t nhwc_across_;
float alpha_;
float k_;
prop_kind_t pk_;
static constexpr int stack_space_needed_ = 11 * 4 * sizeof(float) + 16;
};
template <cpu_isa_t isa, data_type_t d_type>
class jit_uni_lrn_bwd_kernel_t
: public jit_uni_lrn_kernel_t<jit_uni_lrn_bwd_kernel_t<isa, d_type>> {
public:
DECLARE_CPU_JIT_AUX_FUNCTIONS(jit_uni_lrn_bwd_kernel_t)
jit_uni_lrn_bwd_kernel_t(
const nchw8c_across_t &J, float A, float B, int use_h_parallel);
jit_uni_lrn_bwd_kernel_t(const within_config_t &J, float A, float B);
private:
using Base = jit_uni_lrn_kernel_t<jit_uni_lrn_bwd_kernel_t<isa, d_type>>;
void generate() override {
switch (config_) {
case lrn_config_t::nchw8c_across:
generate(this->nchw8c_across_);
return;
case lrn_config_t::within_config:
generate(this->within_config_);
return;
default: assert(!"Configuration not supported"); return;
}
}
void generate(const nchw8c_across_t &config);
void generate(const within_config_t &config);
public:
using Base::VECTOR_LENGTH;
private:
friend Base;
using typename Base::Vmm;
void within_body(int hoff, int Hoff, int woff, int Woff, int stride,
prop_kind_t pk, int reg_block = 1, int single_pixel_offset = 0);
void move_data_pointers(int pixel_count, prop_kind_t pk);
lrn_config_t config_;
const nchw8c_across_t nchw8c_across_;
const within_config_t within_config_;
prop_kind_t pk_ = prop_kind::backward;
float nalphabeta_;
int use_h_parallelizm_;
const Xbyak::Reg64 src_ = this->rax;
const Xbyak::Reg64 diffsrc_ = this->r13;
const Xbyak::Reg64 diffdst_ = this->r14;
const Xbyak::Reg64 scratch_ = this->r15;
const Xbyak::Reg64 bwd_intermediate_res_ = this->rdx;
const Xbyak::Xmm xnalphabeta_ = this->xmm0;
const Vmm vnalphabeta_ = Vmm(0);
};
} } } }
#endif