From 71bb8c8f3238508df7779928a364dff447f6024e Mon Sep 17 00:00:00 2001 From: Inbasekaran Date: Sat, 11 May 2024 10:35:16 +0530 Subject: [PATCH 1/2] feat: Add IsInf JIT emitter for ARM64 Incorporated code review feedback Added IsInf operation to the existing element-wise tests [CPU] [ARM] JIT IsInf: emitter fixes & tests --- .../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 + .../src/node_builders/eltwise.cpp | 1 + 10 files changed, 156 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 d08f41588d5d50..f106ba499186ed 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 @@ -540,6 +540,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 20f3a263ad2aaf..3c7a10eefa590a 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 @@ -293,6 +293,39 @@ class jit_mish_emitter : public jit_emitter { 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 1d950f7860c5fe..7eafb6e4a22bfa 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 @@ -26,6 +26,7 @@ bool JitEltwiseExecutor::isSupported( Algorithm::EltwiseEqual, Algorithm::EltwiseExp, 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 c2ccf3ec8fdf77..b219b61ecc2f4f 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 = { @@ -637,6 +648,7 @@ std::shared_ptr jit_uni_eltwise_generic::create_eltwise_emitte OV_CASE(Algorithm::EltwiseEqual, ov::intel_cpu::aarch64::jit_equal_emitter), OV_CASE(Algorithm::EltwiseExp, ov::intel_cpu::aarch64::jit_exp_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), @@ -804,6 +816,7 @@ std::set> eltwise_precision_helper::get_supported_pre OV_CASE(Algorithm::EltwiseEqual, jit_equal_emitter), OV_CASE(Algorithm::EltwiseExp, jit_exp_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 e01af364b075ab..08b2f1a7dd338b 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 @@ -158,6 +158,7 @@ std::string ActivationLayerCPUTest::getPrimitiveType(const utils::ActivationType (activation_type == utils::ActivationTypes::Elu) || (activation_type == utils::ActivationTypes::Exp) || (activation_type == utils::ActivationTypes::HSwish) || + (activation_type == utils::ActivationTypes::IsInf) || (activation_type == utils::ActivationTypes::HardSigmoid) || (activation_type == utils::ActivationTypes::Mish) || (activation_type == utils::ActivationTypes::Relu) || 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 1e0dd9eeac48c1..83b648779bbb49 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 853b71c9e36688..1390e7a6a00269 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 f9a24ef17cfb56..e0bf7bfec04349 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 548b235caca565..18bf6cd100ec67 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"); } diff --git a/src/tests/test_utils/common_test_utils/src/node_builders/eltwise.cpp b/src/tests/test_utils/common_test_utils/src/node_builders/eltwise.cpp index 262ceb30187137..335950982ee155 100644 --- a/src/tests/test_utils/common_test_utils/src/node_builders/eltwise.cpp +++ b/src/tests/test_utils/common_test_utils/src/node_builders/eltwise.cpp @@ -12,6 +12,7 @@ #include "openvino/op/divide.hpp" #include "openvino/op/erf.hpp" #include "openvino/op/floor_mod.hpp" +#include "openvino/op/is_inf.hpp" #include "openvino/op/mod.hpp" #include "openvino/op/multiply.hpp" #include "openvino/op/power.hpp" From 812fceb49b7c7dea2c9bea26750a844e4ffbce66 Mon Sep 17 00:00:00 2001 From: Inbasekaran Date: Sun, 9 Jun 2024 11:21:40 +0530 Subject: [PATCH 2/2] Refactor: Remove inc is_inf.hpp following code review feedback --- .../test_utils/common_test_utils/src/node_builders/eltwise.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tests/test_utils/common_test_utils/src/node_builders/eltwise.cpp b/src/tests/test_utils/common_test_utils/src/node_builders/eltwise.cpp index 335950982ee155..262ceb30187137 100644 --- a/src/tests/test_utils/common_test_utils/src/node_builders/eltwise.cpp +++ b/src/tests/test_utils/common_test_utils/src/node_builders/eltwise.cpp @@ -12,7 +12,6 @@ #include "openvino/op/divide.hpp" #include "openvino/op/erf.hpp" #include "openvino/op/floor_mod.hpp" -#include "openvino/op/is_inf.hpp" #include "openvino/op/mod.hpp" #include "openvino/op/multiply.hpp" #include "openvino/op/power.hpp"