Skip to content

Commit

Permalink
[CPU] Bitwise operations
Browse files Browse the repository at this point in the history
  • Loading branch information
eshoguli committed Oct 13, 2023
1 parent 157041e commit 8141bae
Show file tree
Hide file tree
Showing 9 changed files with 175 additions and 10 deletions.
8 changes: 8 additions & 0 deletions src/plugins/intel_cpu/src/cpu_types.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ static const TypeToNameMap& get_type_to_name_tbl() {
{ "SoftSign", Type::Eltwise },
{ "Select", Type::Eltwise},
{ "Log", Type::Eltwise },
{ "BitwiseAnd", Type::Eltwise },
{ "BitwiseNot", Type::Eltwise },
{ "BitwiseOr", Type::Eltwise },
{ "BitwiseXor", Type::Eltwise },
{ "Reshape", Type::Reshape },
{ "Squeeze", Type::Reshape },
{ "Unsqueeze", Type::Reshape },
Expand Down Expand Up @@ -384,6 +388,10 @@ std::string algToString(const Algorithm alg) {
CASE(EltwiseErf);
CASE(EltwiseSoftSign);
CASE(EltwiseLog);
CASE(EltwiseBitwiseAnd);
CASE(EltwiseBitwiseNot);
CASE(EltwiseBitwiseOr);
CASE(EltwiseBitwiseXor);
CASE(FQCommon);
CASE(FQQuantization);
CASE(FQBinarization);
Expand Down
4 changes: 4 additions & 0 deletions src/plugins/intel_cpu/src/cpu_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ enum class Algorithm {
EltwiseErf,
EltwiseSoftSign,
EltwiseLog,
EltwiseBitwiseAnd,
EltwiseBitwiseNot,
EltwiseBitwiseOr,
EltwiseBitwiseXor,

// FakeQuantize algorithms
FQCommon,
Expand Down
46 changes: 46 additions & 0 deletions src/plugins/intel_cpu/src/emitters/x64/jit_eltwise_emitters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2243,5 +2243,51 @@ void jit_select_emitter::emit_isa(const std::vector<size_t> &in_vec_idxs, const
h->vblendmps(vmm_dst | k_mask, vmm_src1, vmm_src0);
}
}

/// LOGICAL_AND ///
jit_bitwise_and_emitter::jit_bitwise_and_emitter(x64::jit_generator *host, x64::cpu_isa_t host_isa, const std::shared_ptr<ov::Node>& node, Precision exec_prc)
: jit_emitter(host, host_isa, exec_prc) {
prepare_table();
}
jit_bitwise_and_emitter::jit_bitwise_and_emitter(x64::jit_generator *host, x64::cpu_isa_t host_isa, Precision exec_prc)
: jit_emitter(host, host_isa, exec_prc) {
prepare_table();
}

size_t jit_bitwise_and_emitter::get_inputs_num() const { return 2; }

std::set<std::vector<element::Type>> jit_bitwise_and_emitter::get_supported_precisions(const std::shared_ptr<ngraph::Node>& node) {
return {
{element::i8, element::i8},
{element::i16, element::i16},
{element::i32, element::i32},
{element::u8, element::u8},
{element::u16, element::u16},
{element::u32, element::u32}
};
}

void jit_bitwise_and_emitter::emit_impl(const std::vector<size_t>& in_vec_idxs, const std::vector<size_t>& out_vec_idxs) const {
if (host_isa_ == x64::sse41) {
emit_isa<x64::sse41>(in_vec_idxs, out_vec_idxs);
} else if (host_isa_ == x64::avx2) {
emit_isa<x64::avx2>(in_vec_idxs, out_vec_idxs);
} else if (host_isa_ == x64::avx512_core) {
emit_isa<x64::avx512_core>(in_vec_idxs, out_vec_idxs);
} else {
assert(!"unsupported isa");
}
}

template <x64::cpu_isa_t isa>
void jit_bitwise_and_emitter::emit_isa(const std::vector<size_t> &in_vec_idxs, const std::vector<size_t> &out_vec_idxs) const {
}

void jit_bitwise_and_emitter::register_table_entries() {
}

size_t jit_bitwise_and_emitter::aux_vecs_count() const {
return 3;
}
} // namespace intel_cpu
} // namespace ov
21 changes: 21 additions & 0 deletions src/plugins/intel_cpu/src/emitters/x64/jit_eltwise_emitters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,5 +669,26 @@ class jit_select_emitter : public jit_emitter {
template <dnnl::impl::cpu::x64::cpu_isa_t isa>
void emit_isa(const std::vector<size_t> &in_vec_idxs, const std::vector<size_t> &out_vec_idxs) const;
};

class jit_bitwise_and_emitter : public jit_emitter {
public:
jit_bitwise_and_emitter(dnnl::impl::cpu::x64::jit_generator* host, dnnl::impl::cpu::x64::cpu_isa_t host_isa,
InferenceEngine::Precision exec_prc = InferenceEngine::Precision::FP32);
jit_bitwise_and_emitter(dnnl::impl::cpu::x64::jit_generator* host, dnnl::impl::cpu::x64::cpu_isa_t host_isa, const std::shared_ptr<ov::Node>& n,
InferenceEngine::Precision exec_prc = InferenceEngine::Precision::FP32);

size_t get_inputs_num() const override;
static std::set<std::vector<element::Type>> get_supported_precisions(const std::shared_ptr<ngraph::Node>& node = nullptr);

private:
void emit_impl(const std::vector<size_t>& in_vec_idxs, const std::vector<size_t>& out_vec_idxs) const override;

template <dnnl::impl::cpu::x64::cpu_isa_t isa>
void emit_isa(const std::vector<size_t>& in_vec_idxs, const std::vector<size_t>& out_vec_idxs) const;

void register_table_entries() override;
size_t aux_vecs_count() const override;
};

} // namespace intel_cpu
} // namespace ov
50 changes: 41 additions & 9 deletions src/plugins/intel_cpu/src/nodes/eltwise.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

#include "ngraph/ngraph.hpp"
#include <ngraph/opsets/opset1.hpp>
#include <openvino/opsets/opset13.hpp>
#include "transformations/cpu_opset/common/op/power_static.hpp"
#include "transformations/cpu_opset/common/op/leaky_relu.hpp"
#include "transformations/cpu_opset/common/op/swish_cpu.hpp"
Expand Down Expand Up @@ -245,6 +246,10 @@ std::set<std::vector<element::Type>> eltwise_precision_helper::get_supported_pre
OV_CASE(Algorithm::EltwiseIsInf, jit_is_inf_emitter),
OV_CASE(Algorithm::EltwiseIsNaN, jit_is_nan_emitter),
OV_CASE(Algorithm::EltwiseSelect, jit_select_emitter));
//OV_CASE(Algorithm::EltwiseBitwiseAnd, jit_bitwise_and_emitter),
//OV_CASE(Algorithm::EltwiseBitwiseOr, jit_bitwise_and_emitter),
//OV_CASE(Algorithm::EltwiseBitwiseNot, jit_bitwise_and_emitter),
//OV_CASE(Algorithm::EltwiseBitwiseXor, jit_bitwise_and_emitter));

if (precisions.empty())
IE_THROW() << "Unsupported operation type for Eltwise emitter";
Expand Down Expand Up @@ -619,6 +624,10 @@ struct jit_uni_eltwise_generic : public jit_uni_eltwise_kernel, public jit_gener
OV_CASE(Algorithm::EltwiseIsInf, jit_is_inf_emitter),
OV_CASE(Algorithm::EltwiseIsNaN, jit_is_nan_emitter),
OV_CASE(Algorithm::EltwiseSelect, jit_select_emitter));
//OV_CASE(Algorithm::EltwiseBitwiseAnd, jit_bitwise_and_emitter),
//OV_CASE(Algorithm::EltwiseBitwiseOr, jit_bitwise_and_emitter),
//OV_CASE(Algorithm::EltwiseBitwiseNot, jit_bitwise_and_emitter),
//OV_CASE(Algorithm::EltwiseBitwiseXor, jit_bitwise_and_emitter));

if (!ctx.emitter)
IE_THROW() << "Unsupported operation type for Eltwise emitter";
Expand Down Expand Up @@ -717,7 +726,7 @@ struct jit_uni_eltwise_generic : public jit_uni_eltwise_kernel, public jit_gener
uni_vpmovzxbd(vmm_src, op);
break;
default:
assert(!"unknown src_prc");
IE_THROW() << "unknown src_prc: " << src_prc;
}

switch (dst_prc) {
Expand All @@ -730,7 +739,7 @@ struct jit_uni_eltwise_generic : public jit_uni_eltwise_kernel, public jit_gener
uni_vcvtps2dq(vmm_src, vmm_src);
break;
default:
assert(!"unknown dst_prc");
IE_THROW() << "unknown dst_prc: " << dst_prc;
}
}
}
Expand Down Expand Up @@ -765,7 +774,7 @@ struct jit_uni_eltwise_generic : public jit_uni_eltwise_kernel, public jit_gener
uni_vmovq(xmm_src, reg_tmp_64);
break;
default:
assert(!"unknown src_prc");
IE_THROW() << "unknown src_prc: " << src_prc;
}

switch (dst_prc) {
Expand All @@ -778,7 +787,7 @@ struct jit_uni_eltwise_generic : public jit_uni_eltwise_kernel, public jit_gener
uni_vcvtps2dq(xmm_src, xmm_src);
break;
default:
assert(!"unknown dst_prc");
IE_THROW() << "unknown dst_prc: " << dst_prc;
}
}

Expand All @@ -796,7 +805,7 @@ struct jit_uni_eltwise_generic : public jit_uni_eltwise_kernel, public jit_gener
uni_vcvtdq2ps(vmm_dst, vmm_dst);
break;
default:
assert(!"unknown src_prc");
IE_THROW() << "unknown src_prc: " << src_prc;
}

switch (dst_prc) {
Expand Down Expand Up @@ -868,7 +877,7 @@ struct jit_uni_eltwise_generic : public jit_uni_eltwise_kernel, public jit_gener
}
break;
default:
assert(!"unknown dst_prc");
IE_THROW() << "unknown dst_prc: " << dst_prc;
}
}

Expand All @@ -883,7 +892,7 @@ struct jit_uni_eltwise_generic : public jit_uni_eltwise_kernel, public jit_gener
uni_vcvtdq2ps(xmm_dst, xmm_dst);
break;
default:
assert(!"unknown src_prc");
IE_THROW() << "unknown src_prc: " << src_prc;
}

switch (dst_prc) {
Expand Down Expand Up @@ -923,7 +932,7 @@ struct jit_uni_eltwise_generic : public jit_uni_eltwise_kernel, public jit_gener
mov(op, reg_tmp_8);
break;
default:
assert(!"unknown dst_prc");
IE_THROW() << "unknown dst_prc: " << dst_prc;
}
}
};
Expand Down Expand Up @@ -1160,6 +1169,18 @@ const std::map<const ngraph::DiscreteTypeInfo, Eltwise::Initializer>& Eltwise::g
{ngraph::op::v0::Log::get_type_info_static(), [](const std::shared_ptr<ngraph::Node>& op, Eltwise& node) {
node.algorithm = Algorithm::EltwiseLog;
}},
{op::v13::BitwiseAnd::get_type_info_static(), [](const std::shared_ptr<ngraph::Node>& op, Eltwise& node) {
node.algorithm = Algorithm::EltwiseBitwiseAnd;
}},
{op::v13::BitwiseNot::get_type_info_static(), [](const std::shared_ptr<ngraph::Node>& op, Eltwise& node) {
node.algorithm = Algorithm::EltwiseBitwiseNot;
}},
{op::v13::BitwiseOr::get_type_info_static(), [](const std::shared_ptr<ngraph::Node>& op, Eltwise& node) {
node.algorithm = Algorithm::EltwiseBitwiseOr;
}},
{op::v13::BitwiseXor::get_type_info_static(), [](const std::shared_ptr<ngraph::Node>& op, Eltwise& node) {
node.algorithm = Algorithm::EltwiseBitwiseXor;
}},
};
return initializers;
}
Expand Down Expand Up @@ -1735,6 +1756,10 @@ class EltwiseRefExecutor : public Eltwise::IEltwiseExecutor {
break;
case Algorithm::EltwiseIsNaN: *dst_ptr_f = std::isnan(src_f[0]); break;
case Algorithm::EltwiseSelect: *dst_ptr_f = src_f[0] ? src_f[1] : src_f[2]; break;
case Algorithm::EltwiseBitwiseAnd: *dst_ptr_f = static_cast<uint64_t>(src_f[0]) & static_cast<uint64_t>(src_f[1]); break;
//case Algorithm::EltwiseBitwiseNot: *dst_ptr_f = ~src_f[0]; break;
//case Algorithm::EltwiseBitwiseOr: *dst_ptr_f = src_f[0] | src_f[1]; break;
//case Algorithm::EltwiseBitwiseXor: *dst_ptr_f = src_f[0] ^ src_f[1]; break;
default: IE_THROW() << "Unsupported operation type for Eltwise executor";
}
}
Expand Down Expand Up @@ -1885,6 +1910,12 @@ size_t Eltwise::getOpInputsNum() const {
case Algorithm::EltwiseMulAdd:
case Algorithm::EltwiseSelect:
return 3;
case Algorithm::EltwiseBitwiseAnd:
case Algorithm::EltwiseBitwiseOr:
case Algorithm::EltwiseBitwiseXor:
return 2;
case Algorithm::EltwiseBitwiseNot:
return 1;
default: IE_THROW() << "Unsupported operation for Eltwise node with name `" << getName() << "`.";
}
}
Expand Down Expand Up @@ -1926,7 +1957,8 @@ void Eltwise::initSupportedPrimitiveDescriptors() {
// if dim rank is greater than the maximum possible, we should use the reference execution
bool canUseOptimizedImpl = mayiuse(x64::sse41) && getInputShapeAtPort(0).getRank() <= MAX_ELTWISE_DIM_RANK;
// TODO: Add EltwiseLog algorithm support for JIT implementation
canUseOptimizedImpl &= !one_of(getAlgorithm(), Algorithm::EltwiseLog);
canUseOptimizedImpl &= !one_of(getAlgorithm(), Algorithm::EltwiseLog) && !one_of(getAlgorithm(), Algorithm::EltwiseBitwiseAnd);

bool canUseOptimizedShapeAgnosticImpl = isDynamicNode() && canUseOptimizedImpl;

if (!canUseOptimizedImpl && !fusedWith.empty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -219,5 +219,33 @@ const auto params_5D_dyn_param = ::testing::Combine(

INSTANTIATE_TEST_SUITE_P(smoke_CompareWithRefs_5D_MemOrder_dyn_param, EltwiseLayerCPUTest, params_5D_dyn_param, EltwiseLayerCPUTest::getTestCaseName);

static const std::vector<std::vector<ov::Shape>> bitwise_in_shapes_4D = {
{{1, 3, 4, 4}, {1, 3, 4, 4}},
{{1, 3, 4, 4}, {1, 3, 1, 1}},
};

// TODO: debug: for development only
const auto params_4D_bitwise = ::testing::Combine(
::testing::Combine(
::testing::ValuesIn(static_shapes_to_test_representation(bitwise_in_shapes_4D)),
::testing::ValuesIn({
ngraph::helpers::EltwiseTypes::BITWISE_AND,
ngraph::helpers::EltwiseTypes::BITWISE_NOT,
ngraph::helpers::EltwiseTypes::BITWISE_OR,
ngraph::helpers::EltwiseTypes::BITWISE_XOR
}),
::testing::ValuesIn(secondaryInputTypes()),
::testing::ValuesIn({ ov::test::utils::OpType::VECTOR }),
::testing::ValuesIn({ ElementType::boolean }),
::testing::Values(ov::element::boolean),
::testing::Values(ov::element::boolean),
::testing::Values(ov::test::utils::DEVICE_CPU),
::testing::ValuesIn(additional_config())),
::testing::ValuesIn(filterCPUSpecificParams(cpuParams_4D())),
::testing::Values(emptyFusingSpec),
::testing::Values(false));

INSTANTIATE_TEST_SUITE_P(smoke_CompareWithRefs_4D_Bitwise, EltwiseLayerCPUTest, params_4D_bitwise, EltwiseLayerCPUTest::getTestCaseName);

} // namespace Eltwise
} // namespace CPULayerTestsDefinitions
10 changes: 10 additions & 0 deletions src/tests/ov_helpers/ov_models/src/eltwise.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
#include "common_test_utils/test_enums.hpp"
#include "ov_models/utils/ov_helpers.hpp"

#include "openvino/opsets/opset13.hpp"

namespace ngraph {
namespace builder {

Expand All @@ -32,6 +34,14 @@ std::shared_ptr<ov::Node> makeEltwise(const ov::Output<Node>& in0,
return std::make_shared<ov::op::v1::Mod>(in0, in1);
case ov::test::utils::EltwiseTypes::ERF:
return std::make_shared<ov::op::v0::Erf>(in0);
case ngraph::helpers::EltwiseTypes::BITWISE_AND:
return std::make_shared<ov::op::v13::BitwiseAnd>(in0, in1);
case ngraph::helpers::EltwiseTypes::BITWISE_NOT:
return std::make_shared<ov::op::v13::BitwiseNot>(in0);
case ngraph::helpers::EltwiseTypes::BITWISE_OR:
return std::make_shared<ov::op::v13::BitwiseOr>(in0, in1);
case ngraph::helpers::EltwiseTypes::BITWISE_XOR:
return std::make_shared<ov::op::v13::BitwiseXor>(in0, in1);
default: {
throw std::runtime_error("Incorrect type of Eltwise operation");
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,11 @@ enum EltwiseTypes {
POWER,
FLOOR_MOD,
MOD,
ERF
ERF,
BITWISE_AND,
BITWISE_NOT,
BITWISE_OR,
BITWISE_XOR
};

enum SqueezeOpType {
Expand Down
12 changes: 12 additions & 0 deletions src/tests/test_utils/common_test_utils/src/test_enums.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,18 @@ std::ostream& operator<<(std::ostream& os, const ov::test::utils::EltwiseTypes t
case ov::test::utils::EltwiseTypes::ERF:
os << "Erf";
break;
case ov::test::utils::EltwiseTypes::BITWISE_AND:
os << "BitwiseAnd";
break;
case ov::test::utils::EltwiseTypes::BITWISE_NOT:
os << "BitwiseNot";
break;
case ov::test::utils::EltwiseTypes::BITWISE_OR:
os << "BitwiseOr";
break;
case ov::test::utils::EltwiseTypes::BITWISE_XOR:
os << "BitwiseXor";
break;
default:
throw std::runtime_error("NOT_SUPPORTED_OP_TYPE");
}
Expand Down

0 comments on commit 8141bae

Please sign in to comment.