From 9465604223fcd64aacebf5f0dcfc28e88b25e335 Mon Sep 17 00:00:00 2001 From: Inbasekaran Perumal Date: Mon, 10 Jun 2024 15:43:46 +0530 Subject: [PATCH] Implement IsInf JIT Emitter for ARM64 SIMD in OpenVINO (#24471) Hello maintainers, I've implemented the IsInf JIT emitter for the ARM64 SIMD platform, as outlined in the OpenVINO CPU plugin JIT emitters documentation. This PR addresses [#24419](https://github.com/openvinotoolkit/openvino/issues/24419). Please let me know if any further adjustments are needed. Thank you! --- .../plugin/aarch64/jit_eltwise_emitters.cpp | 99 +++++++++++++++++++ .../plugin/aarch64/jit_eltwise_emitters.hpp | 33 +++++++ .../nodes/executors/aarch64/jit_eltwise.cpp | 1 + .../aarch64/jit_uni_eltwise_generic.cpp | 13 +++ .../single_layer_tests/classes/activation.cpp | 1 + .../single_layer_tests/activation.cpp | 3 +- .../single_op/activation.hpp | 1 + .../include/common_test_utils/test_enums.hpp | 3 +- .../src/node_builders/activation.cpp | 3 + 9 files changed, 155 insertions(+), 2 deletions(-) diff --git a/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.cpp b/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.cpp index 1e35fe009cc..8953489de20 100644 --- a/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.cpp +++ b/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.cpp @@ -801,6 +801,105 @@ std::set> jit_hswish_emitter::get_supported_precision return {{element::f32}}; } +/// IS_INF /// + +jit_is_inf_emitter::jit_is_inf_emitter(dnnl::impl::cpu::aarch64::jit_generator* host, + dnnl::impl::cpu::aarch64::cpu_isa_t host_isa, + const std::shared_ptr& node) + : jit_emitter(host, host_isa, node, get_arithmetic_binary_exec_precision(node)) { + + auto isInf = ov::as_type_ptr(node); + if (isInf == nullptr) { + OV_CPU_JIT_EMITTER_THROW("Can't cast to ov::op::v10::IsInf"); + } + + const auto& attributes = isInf->get_attributes(); + detect_negative = attributes.detect_negative; + detect_positive = attributes.detect_positive; + + prepare_table(); +} + +jit_is_inf_emitter::jit_is_inf_emitter(dnnl::impl::cpu::aarch64::jit_generator* host, + dnnl::impl::cpu::aarch64::cpu_isa_t host_isa, + const bool detect_negative, + const bool detect_positive, + const ov::element::Type exec_prc) + : jit_emitter(host, host_isa, exec_prc), + detect_negative{detect_negative}, + detect_positive{detect_positive} { + prepare_table(); +} + +size_t jit_is_inf_emitter::get_inputs_count() const { + return 1; +} + +size_t jit_is_inf_emitter::get_aux_vecs_count() const { + return 1; +} + +size_t jit_is_inf_emitter::get_aux_gprs_count() const { + return 1; +} + +std::set> jit_is_inf_emitter::get_supported_precisions( + const std::shared_ptr& node) { + return {{element::f32}}; +} + +void jit_is_inf_emitter::emit_impl(const std::vector& in_vec_idxs, + const std::vector& out_vec_idxs) const { + if (host_isa_ == dnnl::impl::cpu::aarch64::asimd) { + emit_isa(in_vec_idxs, out_vec_idxs); + } else { + OV_CPU_JIT_EMITTER_THROW("Can't create jit eltwise kernel"); + } +} + +template +void jit_is_inf_emitter::emit_isa(const std::vector& in_vec_idxs, + const std::vector& out_vec_idxs) const { + OV_CPU_JIT_EMITTER_ASSERT(exec_prc_ == ov::element::f32, "unsupported precision: " + exec_prc_.to_string()); + + using TReg = typename dnnl::impl::cpu::aarch64::cpu_isa_traits::TReg; + const TReg src = TReg(in_vec_idxs[0]); + const TReg dst = TReg(out_vec_idxs[0]); + const TReg aux = TReg(aux_vec_idxs[0]); + + if (detect_negative || detect_positive) { + if (detect_positive) { + if (detect_negative) { + // If both positive and negative infinity detection is requested + // calculate the absolute value of 'src'. + h->fabs(src.s, src.s); + } + // Load 'aux' with positive infinity. + h->ld1r(aux.s, table_val2("inf")); + } else if (detect_negative) { + // Load 'aux' with negative infinity. + h->ld1r(aux.s, table_val2("inf_neg")); + } + // Compare elements of 'src' with 'aux'. + h->fcmeq(dst.s, src.s, aux.s); + // Sets elements in 'dst' to 1.0 where the comparison was true. + h->ld1r(aux.s, table_val2("one")); + h->and_(dst.b16, dst.b16, aux.b16); + + } else { + // If neither positive nor negative infinity detection is enabled, + // set 'dst' with zeros (a eor a is 0) + h->eor(dst.b16, dst.b16, dst.b16); + } +} + +void jit_is_inf_emitter::register_table_entries() { + // Registers constant values that comply with the IEEE 754 standard. + push_arg_entry_of("one", 0x3F800000, true); + push_arg_entry_of("inf", 0x7F800000, true); + push_arg_entry_of("inf_neg", 0xFF800000, true); +} + /// MAX /// jit_maximum_emitter::jit_maximum_emitter(dnnl::impl::cpu::aarch64::jit_generator* host, dnnl::impl::cpu::aarch64::cpu_isa_t host_isa, diff --git a/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.hpp b/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.hpp index 24fd1dde37e..ba107907d7b 100644 --- a/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.hpp +++ b/src/plugins/intel_cpu/src/emitters/plugin/aarch64/jit_eltwise_emitters.hpp @@ -378,6 +378,39 @@ private: void emit_isa(const std::vector &in_vec_idxs, const std::vector &out_vec_idxs) const; }; +class jit_is_inf_emitter : public jit_emitter { +public: + jit_is_inf_emitter(dnnl::impl::cpu::aarch64::jit_generator* host, + dnnl::impl::cpu::aarch64::cpu_isa_t host_isa, + const std::shared_ptr& node); + + jit_is_inf_emitter(dnnl::impl::cpu::aarch64::jit_generator* host, + dnnl::impl::cpu::aarch64::cpu_isa_t host_isa, + const bool detect_negative, + const bool detect_positive, + const ov::element::Type exec_prc = ov::element::f32); + + size_t get_inputs_count() const override; + + size_t get_aux_vecs_count() const override; + + size_t get_aux_gprs_count() const override; + + static std::set> get_supported_precisions( + const std::shared_ptr& node = nullptr); + +private: + void emit_impl(const std::vector& in_vec_idxs, const std::vector& out_vec_idxs) const override; + + template + void emit_isa(const std::vector& in_vec_idxs, const std::vector& out_vec_idxs) const; + + void register_table_entries() override; + + bool detect_negative; + bool detect_positive; +}; + class jit_mod_emitter : public jit_emitter { public: jit_mod_emitter(dnnl::impl::cpu::aarch64::jit_generator *host, diff --git a/src/plugins/intel_cpu/src/nodes/executors/aarch64/jit_eltwise.cpp b/src/plugins/intel_cpu/src/nodes/executors/aarch64/jit_eltwise.cpp index ac3674c9309..01cbb57f49a 100644 --- a/src/plugins/intel_cpu/src/nodes/executors/aarch64/jit_eltwise.cpp +++ b/src/plugins/intel_cpu/src/nodes/executors/aarch64/jit_eltwise.cpp @@ -29,6 +29,7 @@ bool JitEltwiseExecutor::isSupported( Algorithm::EltwiseGeluErf, Algorithm::EltwiseGeluTanh, Algorithm::EltwiseHswish, + Algorithm::EltwiseIsInf, Algorithm::EltwiseMaximum, Algorithm::EltwiseMinimum, Algorithm::EltwiseMish, diff --git a/src/plugins/intel_cpu/src/nodes/kernels/aarch64/jit_uni_eltwise_generic.cpp b/src/plugins/intel_cpu/src/nodes/kernels/aarch64/jit_uni_eltwise_generic.cpp index 10ae54d1fb7..1d0368b1a31 100644 --- a/src/plugins/intel_cpu/src/nodes/kernels/aarch64/jit_uni_eltwise_generic.cpp +++ b/src/plugins/intel_cpu/src/nodes/kernels/aarch64/jit_uni_eltwise_generic.cpp @@ -618,6 +618,17 @@ struct EltwiseEmitter { } }; +template<> +struct EltwiseEmitter { + void operator()(EltwiseEmitterContext& ctx) { + ctx.emitter = std::make_shared(ctx.host, + ctx.host_isa, + ctx.opData.alpha, + ctx.opData.beta, + ctx.exec_prc); + } +}; + template std::shared_ptr jit_uni_eltwise_generic::create_eltwise_emitter(const EltwiseData& data, const ov::element::Type& exec_prec) { EltwiseEmitterContext ctx = { @@ -638,6 +649,7 @@ std::shared_ptr jit_uni_eltwise_generic::create_eltwise_emitte OV_CASE(Algorithm::EltwiseExp, ov::intel_cpu::aarch64::jit_exp_emitter), OV_CASE(Algorithm::EltwiseFloor, ov::intel_cpu::aarch64::jit_floor_emitter), OV_CASE(Algorithm::EltwiseHswish, ov::intel_cpu::aarch64::jit_hswish_emitter), + OV_CASE(Algorithm::EltwiseIsInf, ov::intel_cpu::aarch64::jit_is_inf_emitter), OV_CASE(Algorithm::EltwiseMaximum, ov::intel_cpu::aarch64::jit_maximum_emitter), OV_CASE(Algorithm::EltwiseMinimum, ov::intel_cpu::aarch64::jit_minimum_emitter), OV_CASE(Algorithm::EltwiseMish, ov::intel_cpu::aarch64::jit_mish_emitter), @@ -810,6 +822,7 @@ std::set> eltwise_precision_helper::get_supported_pre OV_CASE(Algorithm::EltwiseGeluErf, jit_gelu_erf_emitter), OV_CASE(Algorithm::EltwiseGeluTanh, jit_gelu_tanh_emitter), OV_CASE(Algorithm::EltwiseHswish, jit_hswish_emitter), + OV_CASE(Algorithm::EltwiseIsInf, jit_is_inf_emitter), OV_CASE(Algorithm::EltwiseMaximum, jit_maximum_emitter), OV_CASE(Algorithm::EltwiseMinimum, jit_minimum_emitter), OV_CASE(Algorithm::EltwiseMish, jit_mish_emitter), diff --git a/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/classes/activation.cpp b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/classes/activation.cpp index 47f747afe60..b9bb07a3bb9 100644 --- a/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/classes/activation.cpp +++ b/src/plugins/intel_cpu/tests/functional/custom/single_layer_tests/classes/activation.cpp @@ -161,6 +161,7 @@ std::string ActivationLayerCPUTest::getPrimitiveType(const utils::ActivationType (activation_type == utils::ActivationTypes::Exp) || (activation_type == utils::ActivationTypes::Floor) || (activation_type == utils::ActivationTypes::HSwish) || + (activation_type == utils::ActivationTypes::IsInf) || (activation_type == utils::ActivationTypes::HardSigmoid) || (activation_type == utils::ActivationTypes::Mish) || (activation_type == utils::ActivationTypes::GeluErf) || diff --git a/src/plugins/intel_cpu/tests/functional/shared_tests_instances/single_layer_tests/activation.cpp b/src/plugins/intel_cpu/tests/functional/shared_tests_instances/single_layer_tests/activation.cpp index 1e0dd9eeac4..83b648779bb 100644 --- a/src/plugins/intel_cpu/tests/functional/shared_tests_instances/single_layer_tests/activation.cpp +++ b/src/plugins/intel_cpu/tests/functional/shared_tests_instances/single_layer_tests/activation.cpp @@ -54,7 +54,8 @@ const std::map>> activationTypes {ActivationTypes::RoundHalfAwayFromZero, {}}, {ActivationTypes::GeluErf, {}}, {ActivationTypes::GeluTanh, {}}, - {ActivationTypes::Swish, {{0.4f}}} + {ActivationTypes::Swish, {{0.4f}}}, + {ActivationTypes::IsInf, {}} }; // List of operations that should be tested also with integer precision diff --git a/src/tests/functional/shared_test_classes/include/shared_test_classes/single_op/activation.hpp b/src/tests/functional/shared_test_classes/include/shared_test_classes/single_op/activation.hpp index 853b71c9e36..1390e7a6a00 100644 --- a/src/tests/functional/shared_test_classes/include/shared_test_classes/single_op/activation.hpp +++ b/src/tests/functional/shared_test_classes/include/shared_test_classes/single_op/activation.hpp @@ -67,6 +67,7 @@ static std::map activationNames = { {ActivationTypes::GeluErf, "GeluErf"}, {ActivationTypes::GeluTanh, "GeluTanh"}, {ActivationTypes::SoftSign, "SoftSign"}, + {ActivationTypes::IsInf, "IsInf"}, }; typedef std::tuple< diff --git a/src/tests/test_utils/common_test_utils/include/common_test_utils/test_enums.hpp b/src/tests/test_utils/common_test_utils/include/common_test_utils/test_enums.hpp index f9a24ef17cf..e0bf7bfec04 100644 --- a/src/tests/test_utils/common_test_utils/include/common_test_utils/test_enums.hpp +++ b/src/tests/test_utils/common_test_utils/include/common_test_utils/test_enums.hpp @@ -121,7 +121,8 @@ enum ActivationTypes { RoundHalfAwayFromZero, GeluErf, GeluTanh, - SoftSign + SoftSign, + IsInf }; enum MinMaxOpType { diff --git a/src/tests/test_utils/common_test_utils/src/node_builders/activation.cpp b/src/tests/test_utils/common_test_utils/src/node_builders/activation.cpp index 548b235caca..18bf6cd100e 100644 --- a/src/tests/test_utils/common_test_utils/src/node_builders/activation.cpp +++ b/src/tests/test_utils/common_test_utils/src/node_builders/activation.cpp @@ -24,6 +24,7 @@ #include "openvino/op/hard_sigmoid.hpp" #include "openvino/op/hsigmoid.hpp" #include "openvino/op/hswish.hpp" +#include "openvino/op/is_inf.hpp" #include "openvino/op/log.hpp" #include "openvino/op/mish.hpp" #include "openvino/op/negative.hpp" @@ -144,6 +145,8 @@ std::shared_ptr make_activation(const ov::Output& in, return std::make_shared(in, ov::op::GeluApproximationMode::TANH); case ov::test::utils::ActivationTypes::SoftSign: return std::make_shared(in); + case ov::test::utils::ActivationTypes::IsInf: + return std::make_shared(in); default: OPENVINO_THROW("Can't create layer for this activation type"); }