diff options
author | Chunseok Lee <chunseok.lee@samsung.com> | 2020-07-30 11:32:26 +0900 |
---|---|---|
committer | Chunseok Lee <chunseok.lee@samsung.com> | 2020-07-30 11:32:26 +0900 |
commit | 05e0ec30a632339a8533082476f27bda31ccde16 (patch) | |
tree | 5f220ac83084fe133ffb08a6a17e99f9bb36ec1c /compiler/luci | |
parent | e2ef8438a24f7c56a0744eb579a6e293ee2fbf8e (diff) | |
download | nnfw-05e0ec30a632339a8533082476f27bda31ccde16.tar.gz nnfw-05e0ec30a632339a8533082476f27bda31ccde16.tar.bz2 nnfw-05e0ec30a632339a8533082476f27bda31ccde16.zip |
Imported Upstream version 1.7.0upstream/1.7.0
Diffstat (limited to 'compiler/luci')
475 files changed, 29882 insertions, 1907 deletions
diff --git a/compiler/luci/CMakeLists.txt b/compiler/luci/CMakeLists.txt index 387c22487..214a1bbf2 100644 --- a/compiler/luci/CMakeLists.txt +++ b/compiler/luci/CMakeLists.txt @@ -1,3 +1,4 @@ +add_subdirectory(env) add_subdirectory(log) add_subdirectory(lang) add_subdirectory(service) diff --git a/compiler/luci/env/CMakeLists.txt b/compiler/luci/env/CMakeLists.txt new file mode 100644 index 000000000..3d8387a47 --- /dev/null +++ b/compiler/luci/env/CMakeLists.txt @@ -0,0 +1,18 @@ +file(GLOB_RECURSE SOURCES "src/*.cpp") +file(GLOB_RECURSE TESTS "src/*.test.cpp") +list(REMOVE_ITEM SOURCES ${TESTS}) + +add_library(luci_env SHARED ${SOURCES}) +target_include_directories(luci_env PUBLIC include) +target_link_libraries(luci_env PRIVATE nncc_common) +install(TARGETS luci_env DESTINATION lib) + +if(NOT ENABLE_TEST) + return() +endif(NOT ENABLE_TEST) + +nnas_find_package(GTest REQUIRED) + +GTest_AddTest(luci_env_test ${TESTS}) +target_include_directories(luci_env_test PRIVATE src) +target_link_libraries(luci_env_test luci_env) diff --git a/compiler/luci/env/README.md b/compiler/luci/env/README.md new file mode 100644 index 000000000..cda007867 --- /dev/null +++ b/compiler/luci/env/README.md @@ -0,0 +1,3 @@ +# luci-env + +_luci-env_ provides user environment settings that control _luci_ diff --git a/compiler/luci/env/include/luci/UserSettings.h b/compiler/luci/env/include/luci/UserSettings.h new file mode 100644 index 000000000..bcfd16071 --- /dev/null +++ b/compiler/luci/env/include/luci/UserSettings.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_USER_SETTINGS__ +#define __LUCI_USER_SETTINGS__ + +// NOTE Revise the logic if we find a better way not using global status + +namespace luci +{ + +/** + * @brief UserSettings provides user settings by key-value + */ +struct UserSettings +{ + enum Key + { + Undefined, + MuteWarnings, + DisableValidation, + }; + + static UserSettings *settings(); + + virtual void set(const Key key, bool value) = 0; + virtual bool get(const Key key) const = 0; +}; + +} // namespace luci + +#endif // __LUCI_USER_SETTINGS__ diff --git a/compiler/luci/env/src/UserSettings.cpp b/compiler/luci/env/src/UserSettings.cpp new file mode 100644 index 000000000..27dec762d --- /dev/null +++ b/compiler/luci/env/src/UserSettings.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/UserSettings.h" + +#include <stdexcept> + +namespace luci +{ + +class UserSettingsImpl : public UserSettings +{ +public: + void set(const Key key, bool value) override; + bool get(const Key key) const override; + +private: + bool _MuteWarnings{false}; + bool _DisableValidation{false}; +}; + +void UserSettingsImpl::set(const Key key, bool value) +{ + switch (key) + { + case Key::MuteWarnings: + _MuteWarnings = value; + break; + case Key::DisableValidation: + _DisableValidation = value; + break; + default: + throw std::runtime_error("Invalid key in boolean set"); + break; + } +} + +bool UserSettingsImpl::get(const Key key) const +{ + switch (key) + { + case Key::MuteWarnings: + return _MuteWarnings; + case Key::DisableValidation: + return _DisableValidation; + default: + throw std::runtime_error("Invalid key in boolean get"); + break; + } + return false; +} + +} // namespace luci + +namespace luci +{ + +UserSettings *UserSettings::settings() +{ + static UserSettingsImpl _this; + return &_this; +} + +} // namespace luci diff --git a/compiler/luci/env/src/UserSettings.test.cpp b/compiler/luci/env/src/UserSettings.test.cpp new file mode 100644 index 000000000..8d9d1875b --- /dev/null +++ b/compiler/luci/env/src/UserSettings.test.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/UserSettings.h" + +#include <gtest/gtest.h> + +TEST(UserSettings, instance) +{ + auto settings = luci::UserSettings::settings(); + ASSERT_NE(nullptr, settings); + + auto s2 = luci::UserSettings::settings(); + ASSERT_EQ(s2, settings); +} + +TEST(UserSettings, MuteWarnings) +{ + auto settings = luci::UserSettings::settings(); + ASSERT_NE(nullptr, settings); + + settings->set(luci::UserSettings::Key::MuteWarnings, false); + ASSERT_FALSE(settings->get(luci::UserSettings::Key::MuteWarnings)); + + settings->set(luci::UserSettings::Key::MuteWarnings, true); + ASSERT_TRUE(settings->get(luci::UserSettings::Key::MuteWarnings)); +} + +TEST(UserSettings, DisableValidation) +{ + auto settings = luci::UserSettings::settings(); + ASSERT_NE(nullptr, settings); + + settings->set(luci::UserSettings::Key::DisableValidation, false); + ASSERT_FALSE(settings->get(luci::UserSettings::Key::DisableValidation)); + + settings->set(luci::UserSettings::Key::DisableValidation, true); + ASSERT_TRUE(settings->get(luci::UserSettings::Key::DisableValidation)); +} + +TEST(UserSettings, undefined_set_NEG) +{ + auto settings = luci::UserSettings::settings(); + ASSERT_NE(nullptr, settings); + + ASSERT_THROW(settings->set(luci::UserSettings::Key::Undefined, true), std::exception); +} + +TEST(UserSettings, undefined_get_NEG) +{ + auto settings = luci::UserSettings::settings(); + ASSERT_NE(nullptr, settings); + + ASSERT_THROW(settings->get(luci::UserSettings::Key::Undefined), std::exception); +} diff --git a/compiler/luci/export/CMakeLists.txt b/compiler/luci/export/CMakeLists.txt index e32eca366..fe4382ecd 100644 --- a/compiler/luci/export/CMakeLists.txt +++ b/compiler/luci/export/CMakeLists.txt @@ -10,6 +10,7 @@ target_link_libraries(luci_export PRIVATE luci_lang) target_link_libraries(luci_export PRIVATE luci_service) target_link_libraries(luci_export PRIVATE luci_pass) target_link_libraries(luci_export PRIVATE mio_circle) +target_link_libraries(luci_export PRIVATE luci_env) target_link_libraries(luci_export PRIVATE luci_log) target_link_libraries(luci_export PRIVATE luci_logex) target_link_libraries(luci_export PRIVATE nncc_common) diff --git a/compiler/luci/export/src/CircleExporterImpl.cpp b/compiler/luci/export/src/CircleExporterImpl.cpp index 81109ee62..860cebf6e 100644 --- a/compiler/luci/export/src/CircleExporterImpl.cpp +++ b/compiler/luci/export/src/CircleExporterImpl.cpp @@ -16,6 +16,7 @@ #include "CircleExporterImpl.h" #include "Optimize.h" +#include "TypeBridge.h" #include "CircleTensorExporter.h" #include "CircleOperationExporter.h" #include "CircleExporterUtils.h" @@ -36,11 +37,11 @@ luci::CircleInput *input_node(loco::Graph *g, const loco::GraphInputIndex &index { for (uint32_t n = 0; n < g->nodes()->size(); ++n) { - if (auto pull = dynamic_cast<luci::CircleInput *>(g->nodes()->at(n))) + if (auto input = dynamic_cast<luci::CircleInput *>(g->nodes()->at(n))) { - if (pull->indexed() && pull->index() == index) + if (input->indexed() && input->index() == index) { - return pull; + return input; } } } @@ -51,11 +52,11 @@ luci::CircleOutput *output_node(loco::Graph *g, const loco::GraphOutputIndex &in { for (uint32_t n = 0; n < g->nodes()->size(); ++n) { - if (auto push = dynamic_cast<luci::CircleOutput *>(g->nodes()->at(n))) + if (auto output = dynamic_cast<luci::CircleOutput *>(g->nodes()->at(n))) { - if (push->indexed() && push->index() == index) + if (output->indexed() && output->index() == index) { - return push; + return output; } } } @@ -80,6 +81,13 @@ void registerGraphOutputTensors(loco::Graph *graph, luci::SubGraphContext &ctx) assert(push != nullptr); auto node = push->from(); assert(node != nullptr); + + // Do not export CircleOutput when it's input is CircleOutputExclude + if (dynamic_cast<luci::CircleOutputExclude *>(push->from()) != nullptr) + { + continue; + } + ctx._outputs.push_back(luci::get_tensor_index(node)); } } @@ -93,8 +101,7 @@ using namespace circle; using namespace flatbuffers; Offset<Vector<Offset<OperatorCode>>> -encodeOperatorCodes(FlatBufferBuilder &builder, std::unordered_map<luci::OpCode, uint32_t> &opcodes, - std::unordered_map<luci::OpCode, std::string> &custom_opcodes) +encodeOperatorCodes(FlatBufferBuilder &builder, std::unordered_map<luci::OpCode, uint32_t> &opcodes) { std::vector<Offset<OperatorCode>> operator_codes_vec(opcodes.size()); for (auto it : opcodes) @@ -102,19 +109,15 @@ encodeOperatorCodes(FlatBufferBuilder &builder, std::unordered_map<luci::OpCode, uint32_t idx = it.second; if (it.first.opcode != BuiltinOperator_CUSTOM) { - operator_codes_vec[idx] = CreateOperatorCode(builder, it.first.opcode); + operator_codes_vec[idx] = CreateOperatorCode(builder, it.first.opcode, 0, it.first.version); } - else // custom op + else { - auto opCode = it.first; - auto custom_code = custom_opcodes.find(opCode); - if (custom_code == custom_opcodes.end()) - INTERNAL_EXN("Cannot find code for customop even though opcode is BuiltinOperator_CUSTOM"); - operator_codes_vec[idx] = - CreateOperatorCode(builder, it.first.opcode, builder.CreateString(custom_code->second)); + CreateOperatorCode(builder, it.first.opcode, builder.CreateString(it.first.custom_code)); } } + return builder.CreateVector(operator_codes_vec); } @@ -136,8 +139,9 @@ CircleExporterImpl::exportSubgraph(SerializedGraphData &gd) auto inputs = _builder.CreateVector(gd._inputs); auto outputs = _builder.CreateVector(gd._outputs); auto operators = _builder.CreateVector(gd._operators); + auto name = _builder.CreateString(gd._name); auto df = gd._data_format; - auto subgraph = CreateSubGraph(_builder, tensors, inputs, outputs, operators, df); + auto subgraph = CreateSubGraph(_builder, tensors, inputs, outputs, operators, name, df); return subgraph; } @@ -146,6 +150,9 @@ void CircleExporterImpl::exportGraph(loco::Graph *graph) // do graph optimization optimize(graph); + // copy shape/dtype inference data to CircleNode + copy_shape_dtype(graph); + _builder.Clear(); SerializedModelData md; @@ -154,6 +161,9 @@ void CircleExporterImpl::exportGraph(loco::Graph *graph) // This version is taken from comment in fbs constexpr uint32_t version = 0; + // set Subgraph name + gd._name = graph->name(); + // TODO set this value properly gd._data_format = circle::DataFormat::DataFormat_CHANNELS_LAST; @@ -170,8 +180,7 @@ void CircleExporterImpl::exportGraph(loco::Graph *graph) exportNodes(graph, _builder, md, gd); // encode operator codes - auto operator_codes = - encodeOperatorCodes(_builder, md._operator_codes, md._custom_operator_codes); + auto operator_codes = encodeOperatorCodes(_builder, md._operator_codes); // Subgraphs Offset<SubGraph> subgraph = exportSubgraph(gd); @@ -203,6 +212,9 @@ void CircleExporterImpl::exportModule(Module *module) _builder.Clear(); + // prepare model data + prepareModelData(_builder, md); + std::vector<flatbuffers::Offset<circle::SubGraph>> subgraph_vec; for (size_t g = 0; g < module->size(); ++g) @@ -211,8 +223,14 @@ void CircleExporterImpl::exportModule(Module *module) optimize(graph); + // copy shape/dtype inference data to CircleNode + copy_shape_dtype(graph); + SerializedGraphData gd; + // set Subgraph name + gd._name = graph->name(); + // TODO set this value properly gd._data_format = circle::DataFormat::DataFormat_CHANNELS_LAST; @@ -233,8 +251,7 @@ void CircleExporterImpl::exportModule(Module *module) auto subgraphs = _builder.CreateVector(std::vector<Offset<SubGraph>>{subgraph_vec}); // encode operator codes - auto operator_codes = - encodeOperatorCodes(_builder, md._operator_codes, md._custom_operator_codes); + auto operator_codes = encodeOperatorCodes(_builder, md._operator_codes); // Description std::string description_str = "nnpackage"; diff --git a/compiler/luci/export/src/CircleExporterUtils.cpp b/compiler/luci/export/src/CircleExporterUtils.cpp index 1272facb2..f097e71c5 100644 --- a/compiler/luci/export/src/CircleExporterUtils.cpp +++ b/compiler/luci/export/src/CircleExporterUtils.cpp @@ -70,28 +70,49 @@ circle::TensorType to_circle_tensortype(loco::DataType type) } } +circle::MirrorPadMode to_circle_mirrorpadmode(luci::MirrorPadMode mode) +{ + switch (mode) + { + case luci::MirrorPadMode::REFLECT: + return circle::MirrorPadMode::MirrorPadMode_REFLECT; + case luci::MirrorPadMode::SYMMETRIC: + return circle::MirrorPadMode::MirrorPadMode_SYMMETRIC; + default: + INTERNAL_EXN_V("trying to convert unsupported luci::MirrorPadMode", oops::to_uint32(mode)); + } +} + } // namespace luci namespace luci { -uint32_t SerializedModelData::registerBuiltinOpcode(circle::BuiltinOperator builtin_code) +uint32_t SerializedModelData::registerBuiltinOpcode(circle::BuiltinOperator builtin_code, + const int32_t op_version) { - auto it = _operator_codes.find(OpCode{builtin_code}); + assert(op_version > 0); + + auto it = _operator_codes.find(OpCode{builtin_code, "", op_version}); if (it != _operator_codes.end()) { return it->second; } auto idx = static_cast<uint32_t>(_operator_codes.size()); - _operator_codes.emplace(OpCode{builtin_code}, idx); + _operator_codes.emplace(OpCode{builtin_code, "", op_version}, idx); return idx; } -uint32_t SerializedModelData::registerCustomOpcode(const std::string &custom_op) +uint32_t SerializedModelData::registerCustomOpcode(const std::string &custom_code) { - circle::BuiltinOperator custom_code = circle::BuiltinOperator_CUSTOM; - auto idx = registerBuiltinOpcode(custom_code); - _custom_operator_codes.emplace(OpCode{custom_code}, custom_op); + const circle::BuiltinOperator builtin_code = circle::BuiltinOperator_CUSTOM; + auto it = _operator_codes.find(OpCode{builtin_code, custom_code}); + if (it != _operator_codes.end()) + { + return it->second; + } + auto idx = static_cast<uint32_t>(_operator_codes.size()); + _operator_codes.emplace(OpCode{builtin_code, custom_code}, idx); return idx; } diff --git a/compiler/luci/export/src/CircleExporterUtils.h b/compiler/luci/export/src/CircleExporterUtils.h index 6b970fd3c..f9ce6d2bf 100644 --- a/compiler/luci/export/src/CircleExporterUtils.h +++ b/compiler/luci/export/src/CircleExporterUtils.h @@ -31,6 +31,7 @@ namespace luci circle::ActivationFunctionType to_circle_actfunc(luci::FusedActFunc func); circle::TensorType to_circle_tensortype(loco::DataType type); +circle::MirrorPadMode to_circle_mirrorpadmode(luci::MirrorPadMode mode); } // namespace luci diff --git a/compiler/luci/export/src/CircleOperationExporter.cpp b/compiler/luci/export/src/CircleOperationExporter.cpp index ad9c7fd4b..3c01b676f 100644 --- a/compiler/luci/export/src/CircleOperationExporter.cpp +++ b/compiler/luci/export/src/CircleOperationExporter.cpp @@ -22,6 +22,8 @@ #include <luci/IR/CircleNodes.h> #include <luci/IR/CircleNodeVisitor.h> #include <luci/Service/CircleShapeInference.h> +#include <luci/UserSettings.h> +#include <luci/Log.h> #include <loco/IR/CanonicalNodeVisitor.h> #include <oops/InternalExn.h> @@ -49,42 +51,125 @@ public: public: void visit(luci::CircleAbs *) final; void visit(luci::CircleAdd *) final; + void visit(luci::CircleAddN *) final; void visit(luci::CircleArgMax *) final; + void visit(luci::CircleArgMin *) final; void visit(luci::CircleAveragePool2D *) final; + void visit(luci::CircleBatchMatMul *) final; void visit(luci::CircleBatchToSpaceND *) final; + void visit(luci::CircleCast *) final; + void visit(luci::CircleCeil *) final; void visit(luci::CircleConcatenation *) final; void visit(luci::CircleConst *) final{/* skip, everything is done in exportOpDefinedTensors */}; void visit(luci::CircleConv2D *) final; void visit(luci::CircleCos *) final; + void visit(luci::CircleCustom *) final; + void visit(luci::CircleDepthToSpace *) final; void visit(luci::CircleDepthwiseConv2D *) final; void visit(luci::CircleDiv *) final; - void visit(luci::CircleExp *) final; + void visit(luci::CircleElu *) final; void visit(luci::CircleEqual *) final; + void visit(luci::CircleExp *) final; + void visit(luci::CircleExpandDims *) final; + void visit(luci::CircleFill *) final; + void visit(luci::CircleFloor *) final; + void visit(luci::CircleFloorDiv *) final; + void visit(luci::CircleFloorMod *) final; void visit(luci::CircleFullyConnected *) final; + void visit(luci::CircleGather *) final; + void visit(luci::CircleGatherNd *) final; + void visit(luci::CircleGreater *) final; + void visit(luci::CircleGreaterEqual *) final; + void visit(luci::CircleIf *) final; + void visit(luci::CircleL2Normalize *) final; + void visit(luci::CircleL2Pool2D *) final; + void visit(luci::CircleLeakyRelu *) final; + void visit(luci::CircleLess *) final; + void visit(luci::CircleLessEqual *) final; + void visit(luci::CircleLocalResponseNormalization *) final; + void visit(luci::CircleLog *) final; + void visit(luci::CircleLogicalAnd *) final; void visit(luci::CircleLogicalNot *) final; void visit(luci::CircleLogicalOr *) final; + void visit(luci::CircleLogistic *) final; + void visit(luci::CircleLogSoftmax *) final; + void visit(luci::CircleMatrixDiag *) final; + void visit(luci::CircleMatrixSetDiag *) final; void visit(luci::CircleMaximum *) final; void visit(luci::CircleMaxPool2D *) final; void visit(luci::CircleMean *) final; + void visit(luci::CircleMinimum *) final; + void visit(luci::CircleMirrorPad *) final; void visit(luci::CircleMul *) final; + void visit(luci::CircleNeg *) final; + void visit(luci::CircleNotEqual *) final; + void visit(luci::CircleOneHot *) final; void visit(luci::CirclePack *) final; void visit(luci::CirclePad *) final; + void visit(luci::CirclePow *) final; + void visit(luci::CirclePRelu *) final; + void visit(luci::CircleRange *) final; + void visit(luci::CircleRank *) final; + void visit(luci::CircleReduceAny *) final; + void visit(luci::CircleReduceMax *) final; + void visit(luci::CircleReduceMin *) final; + void visit(luci::CircleReduceProd *) final; void visit(luci::CircleRelu *) final; void visit(luci::CircleRelu6 *) final; + void visit(luci::CircleReluN1To1 *) final; void visit(luci::CircleReshape *) final; + void visit(luci::CircleResizeBilinear *) final; + void visit(luci::CircleResizeNearestNeighbor *) final; + void visit(luci::CircleReverseSequence *) final; + void visit(luci::CircleReverseV2 *) final; + void visit(luci::CircleRound *) final; void visit(luci::CircleRsqrt *) final; + void visit(luci::CircleScatterNd *) final; + void visit(luci::CircleSegmentSum *) final; + void visit(luci::CircleSelect *) final; + void visit(luci::CircleSelectV2 *) final; + void visit(luci::CircleShape *) final; + void visit(luci::CircleSin *) final; + void visit(luci::CircleSlice *) final; void visit(luci::CircleSoftmax *) final; + void visit(luci::CircleSpaceToBatchND *) final; + void visit(luci::CircleSpaceToDepth *) final; + void visit(luci::CircleSparseToDense *) final; + void visit(luci::CircleSplit *) final; + void visit(luci::CircleSplitV *) final; void visit(luci::CircleSqrt *) final; + void visit(luci::CircleSquare *) final; void visit(luci::CircleSquaredDifference *) final; + void visit(luci::CircleSqueeze *) final; + void visit(luci::CircleStridedSlice *) final; void visit(luci::CircleSub *) final; - // TODO CircleTanh + void visit(luci::CircleSum *) final; + void visit(luci::CircleTanh *) final; + void visit(luci::CircleTile *) final; + void visit(luci::CircleTopKV2 *) final; void visit(luci::CircleTranspose *) final; void visit(luci::CircleTransposeConv *) final; + void visit(luci::CircleUnpack *) final; + void visit(luci::CircleWhere *) final; + void visit(luci::CircleWhile *) final; + void visit(luci::CircleZerosLike *) final; // Circle only + void visit(luci::CircleBCQFullyConnected *) final; + void visit(luci::CircleBCQGather *) final; void visit(luci::CircleInstanceNorm *) final; // Virtual void visit(luci::CircleInput *) final {} void visit(luci::CircleOutput *) final {} + void visit(luci::CircleOutputDummy *) final {} + void visit(luci::CircleOutputExclude *) final {} + // Virtual for multiple-outputs + void visit(luci::CircleCustomOut *) final {} + void visit(luci::CircleIfOut *) final {} + void visit(luci::CircleSplitOut *) final {} + void visit(luci::CircleSplitVOut *) final {} + void visit(luci::CircleTopKV2Out *) final {} + void visit(luci::CircleUnpackOut *) final {} + void visit(luci::CircleWhileOut *) final {} private: /** @@ -95,6 +180,17 @@ private: template <class CirclePool2D> void export_pool_2d(CirclePool2D *node, circle::BuiltinOperator builtin_op); + /** + * @brief export simple nodes + */ + void export_simple(loco::Node *node, circle::BuiltinOperator bop, circle::BuiltinOptions bot, + flatbuffers::Offset<void> options_offset); + + /** + * @brief export simple nodes having void options + */ + void export_simple(loco::Node *node, circle::BuiltinOperator bop); + private: FlatBufferBuilder &builder; SerializedModelData &md; @@ -105,11 +201,12 @@ template <class CirclePool2D> void OperationExporter::export_pool_2d(CirclePool2D *node, circle::BuiltinOperator builtin_op) { LUCI_ASSERT(builtin_op == circle::BuiltinOperator_MAX_POOL_2D || + builtin_op == circle::BuiltinOperator_L2_POOL_2D || builtin_op == circle::BuiltinOperator_AVERAGE_POOL_2D, - "Should be MaxPool or AvgPool"); + "Should be L2Pool, MaxPool or AvgPool"); LUCI_ASSERT(node->padding() != luci::Padding::UNDEFINED, "Padding is not set"); - uint32_t op_idx = md.registerBuiltinOpcode(builtin_op); + uint32_t op_idx = md.registerBuiltinOpcode(builtin_op, node->op_version()); std::vector<int32_t> inputs_vec{get_tensor_index(node->value())}; std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; auto inputs = builder.CreateVector(inputs_vec); @@ -125,54 +222,122 @@ void OperationExporter::export_pool_2d(CirclePool2D *node, circle::BuiltinOperat gd._operators.push_back(op_offset); } -void OperationExporter::visit(luci::CircleAbs *node) +void OperationExporter::export_simple(loco::Node *node, circle::BuiltinOperator bop, + circle::BuiltinOptions bot, + flatbuffers::Offset<void> options_offset) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_ABS); - std::vector<int32_t> inputs_vec{get_tensor_index(node->x())}; + uint32_t op_idx = + md.registerBuiltinOpcode(bop, loco::must_cast<luci::CircleNode *>(node)->op_version()); + std::vector<int32_t> inputs_vec; + std::vector<int32_t> outputs_vec{get_tensor_index(node)}; + for (uint32_t i = 0; i < node->arity(); ++i) + inputs_vec.push_back(get_tensor_index(node->arg(i))); + auto inputs = builder.CreateVector(inputs_vec); + auto outputs = builder.CreateVector(outputs_vec); + auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, bot, options_offset); + gd._operators.push_back(op_offset); +} + +void OperationExporter::export_simple(loco::Node *node, circle::BuiltinOperator bop) +{ + uint32_t op_idx = + md.registerBuiltinOpcode(bop, loco::must_cast<luci::CircleNode *>(node)->op_version()); + std::vector<int32_t> inputs_vec; std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; + for (uint32_t i = 0; i < node->arity(); ++i) + inputs_vec.push_back(get_tensor_index(node->arg(i))); auto inputs = builder.CreateVector(inputs_vec); auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateAbsOptions(builder); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_AbsOptions, options.Union()); + auto op_offset = CreateOperator(builder, op_idx, inputs, outputs); gd._operators.push_back(op_offset); } +void OperationExporter::visit(luci::CircleAbs *node) +{ + export_simple(node, circle::BuiltinOperator_ABS, circle::BuiltinOptions_AbsOptions, + CreateAbsOptions(builder).Union()); +} + void OperationExporter::visit(luci::CircleAdd *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_ADD); - std::vector<int32_t> inputs_vec{get_tensor_index(node->x()), get_tensor_index(node->y())}; + export_simple( + node, circle::BuiltinOperator_ADD, circle::BuiltinOptions_AddOptions, + CreateAddOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union()); +} + +void OperationExporter::visit(luci::CircleAddN *node) +{ + uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_ADD_N, node->op_version()); + std::vector<int32_t> inputs_vec; std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; + + for (uint32_t i = 0; i < node->arity(); ++i) + inputs_vec.push_back(get_tensor_index(node->inputs(i))); + auto inputs = builder.CreateVector(inputs_vec); auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateAddOptions(builder, to_circle_actfunc(node->fusedActivationFunction())); + auto options = CreateAddNOptions(builder); auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_AddOptions, options.Union()); + circle::BuiltinOptions_AddNOptions, options.Union()); gd._operators.push_back(op_offset); } void OperationExporter::visit(luci::CircleArgMax *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_ARG_MAX); - std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), - get_tensor_index(node->dimension())}; + export_simple(node, circle::BuiltinOperator_ARG_MAX, circle::BuiltinOptions_ArgMaxOptions, + CreateArgMaxOptions(builder, to_circle_tensortype(node->output_type())).Union()); +} + +void OperationExporter::visit(luci::CircleArgMin *node) +{ + export_simple(node, circle::BuiltinOperator_ARG_MIN, circle::BuiltinOptions_ArgMinOptions, + CreateArgMinOptions(builder, to_circle_tensortype(node->output_type())).Union()); +} + +void OperationExporter::visit(luci::CircleAveragePool2D *node) +{ + export_pool_2d<luci::CircleAveragePool2D>(node, circle::BuiltinOperator_AVERAGE_POOL_2D); +} + +void OperationExporter::visit(luci::CircleBatchMatMul *node) +{ + export_simple(node, circle::BuiltinOperator_BATCH_MATMUL, + circle::BuiltinOptions_BatchMatMulOptions, + CreateBatchMatMulOptions(builder, node->adj_x(), node->adj_y()).Union()); +} + +void OperationExporter::visit(luci::CircleCast *node) +{ + uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_CAST, node->op_version()); + std::vector<int32_t> inputs_vec{get_tensor_index(node->x())}; std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; auto inputs = builder.CreateVector(inputs_vec); auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateArgMaxOptions(builder, to_circle_tensortype(node->output_type())); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_ArgMaxOptions, options.Union()); + + flatbuffers::Offset<Operator> op_offset; + if (node->out_data_type() != loco::DataType::Unknown) + { + auto options = CreateCastOptions(builder, to_circle_tensortype(node->in_data_type()), + to_circle_tensortype(node->out_data_type())); + op_offset = CreateOperator(builder, op_idx, inputs, outputs, circle::BuiltinOptions_CastOptions, + options.Union()); + } + else + { + op_offset = CreateOperator(builder, op_idx, inputs, outputs); + } gd._operators.push_back(op_offset); } -void OperationExporter::visit(luci::CircleAveragePool2D *node) +void OperationExporter::visit(luci::CircleCeil *node) { - export_pool_2d<luci::CircleAveragePool2D>(node, circle::BuiltinOperator_AVERAGE_POOL_2D); + export_simple(node, circle::BuiltinOperator_CEIL); } void OperationExporter::visit(luci::CircleConcatenation *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_CONCATENATION); + uint32_t op_idx = + md.registerBuiltinOpcode(circle::BuiltinOperator_CONCATENATION, node->op_version()); std::vector<int32_t> inputs_vec; std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; @@ -190,169 +355,304 @@ void OperationExporter::visit(luci::CircleConcatenation *node) void OperationExporter::visit(luci::CircleBatchToSpaceND *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_BATCH_TO_SPACE_ND); - std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), - get_tensor_index(node->block_shape()), - get_tensor_index(node->crops())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateBatchToSpaceNDOptions(builder); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_BatchToSpaceNDOptions, options.Union()); - gd._operators.push_back(op_offset); + export_simple(node, circle::BuiltinOperator_BATCH_TO_SPACE_ND, + circle::BuiltinOptions_BatchToSpaceNDOptions, + CreateBatchToSpaceNDOptions(builder).Union()); } void OperationExporter::visit(luci::CircleConv2D *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_CONV_2D); - - // Make input, output and options for operator - std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), get_tensor_index(node->filter()), - get_tensor_index(node->bias())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - circle::Padding padding = getOpPadding(node->padding()); - auto options = CreateConv2DOptions(builder, padding, node->stride()->w(), node->stride()->h(), - to_circle_actfunc(node->fusedActivationFunction())); - - // Make CONV_2D operator - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_Conv2DOptions, options.Union()); - gd._operators.push_back(op_offset); + export_simple(node, circle::BuiltinOperator_CONV_2D, circle::BuiltinOptions_Conv2DOptions, + CreateConv2DOptions(builder, getOpPadding(node->padding()), node->stride()->w(), + node->stride()->h(), + to_circle_actfunc(node->fusedActivationFunction()), + node->dilation()->w(), node->dilation()->h()) + .Union()); } void OperationExporter::visit(luci::CircleCos *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_COS); + export_simple(node, circle::BuiltinOperator_COS, circle::BuiltinOptions_CosOptions, + CreateCosOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleCustom *node) +{ + auto custom_outputs = loco::succs(node); + + uint32_t op_idx = md.registerCustomOpcode(node->custom_code()); + std::vector<int32_t> inputs_vec; + std::vector<int32_t> outputs_vec; + + for (uint32_t index = 0; index < node->numInputs(); index++) + { + inputs_vec.push_back(get_tensor_index(node->inputs(index))); + } + for (uint32_t index = 0; index < custom_outputs.size(); index++) + { + // store in order of index + bool found = false; + for (auto out : custom_outputs) + { + auto custom_out = loco::must_cast<luci::CircleCustomOut *>(out); + if (custom_out->index() == static_cast<int32_t>(index)) + { + outputs_vec.push_back(get_tensor_index(custom_out)); + found = true; + break; + } + } + if (!found) + { + INTERNAL_EXN("Invalid Custom output"); + } + } - // Make input, output and options for operator - std::vector<int32_t> inputs_vec{get_tensor_index(node->x())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; auto inputs = builder.CreateVector(inputs_vec); auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateCosOptions(builder); - - // Make COS operator - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_CosOptions, options.Union()); + flatbuffers::Offset<flatbuffers::Vector<uint8_t>> circle_custom_options; + std::vector<uint8_t> custom_options_vec{node->custom_options().begin(), + node->custom_options().end()}; + circle_custom_options = builder.CreateVector(custom_options_vec); + auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, circle::BuiltinOptions_NONE, + flatbuffers::Offset<void>(), circle_custom_options); gd._operators.push_back(op_offset); } +void OperationExporter::visit(luci::CircleDepthToSpace *node) +{ + export_simple(node, circle::BuiltinOperator_DEPTH_TO_SPACE, + circle::BuiltinOptions_DepthToSpaceOptions, + CreateDepthToSpaceOptions(builder, node->block_size()).Union()); +} + void OperationExporter::visit(luci::CircleDepthwiseConv2D *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_DEPTHWISE_CONV_2D); + export_simple(node, circle::BuiltinOperator_DEPTHWISE_CONV_2D, + circle::BuiltinOptions_DepthwiseConv2DOptions, + CreateDepthwiseConv2DOptions(builder, getOpPadding(node->padding()), + node->stride()->w(), node->stride()->h(), + node->depthMultiplier(), + to_circle_actfunc(node->fusedActivationFunction()), + node->dilation()->w(), node->dilation()->h()) + .Union()); +} - // Make input, output and options for operator - std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), get_tensor_index(node->filter()), - get_tensor_index(node->bias())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - circle::Padding padding = getOpPadding(node->padding()); - auto options = CreateDepthwiseConv2DOptions(builder, padding, node->stride()->w(), - node->stride()->h(), node->depthMultiplier(), - to_circle_actfunc(node->fusedActivationFunction())); +void OperationExporter::visit(luci::CircleDiv *node) +{ + export_simple( + node, circle::BuiltinOperator_DIV, circle::BuiltinOptions_DivOptions, + CreateDivOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union()); +} - // Make DEPTHWISE_CONV_2D operator - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_DepthwiseConv2DOptions, options.Union()); - gd._operators.push_back(op_offset); +void OperationExporter::visit(luci::CircleElu *node) +{ + export_simple(node, circle::BuiltinOperator_ELU); } -void OperationExporter::visit(luci::CircleDiv *node) +void OperationExporter::visit(luci::CircleEqual *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_DIV); - std::vector<int32_t> inputs_vec{get_tensor_index(node->x()), get_tensor_index(node->y())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateDivOptions(builder, to_circle_actfunc(node->fusedActivationFunction())); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_DivOptions, options.Union()); - gd._operators.push_back(op_offset); + export_simple(node, circle::BuiltinOperator_EQUAL, circle::BuiltinOptions_EqualOptions, + CreateEqualOptions(builder).Union()); } void OperationExporter::visit(luci::CircleExp *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_EXP); - std::vector<int32_t> inputs_vec{get_tensor_index(node->x())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateAbsOptions(builder); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_ExpOptions, options.Union()); - gd._operators.push_back(op_offset); + export_simple(node, circle::BuiltinOperator_EXP, circle::BuiltinOptions_ExpOptions, + CreateExpOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleExpandDims *node) +{ + export_simple(node, circle::BuiltinOperator_EXPAND_DIMS, circle::BuiltinOptions_ExpandDimsOptions, + CreateExpandDimsOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleFill *node) +{ + export_simple(node, circle::BuiltinOperator_FILL, circle::BuiltinOptions_FillOptions, + CreateFillOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleFloor *node) +{ + export_simple(node, circle::BuiltinOperator_FLOOR); +} + +void OperationExporter::visit(luci::CircleFloorDiv *node) +{ + export_simple(node, circle::BuiltinOperator_FLOOR_DIV, circle::BuiltinOptions_FloorDivOptions, + CreateFloorDivOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleFloorMod *node) +{ + export_simple(node, circle::BuiltinOperator_FLOOR_MOD, circle::BuiltinOptions_FloorModOptions, + CreateFloorModOptions(builder).Union()); } void OperationExporter::visit(luci::CircleFullyConnected *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_FULLY_CONNECTED); + export_simple( + node, circle::BuiltinOperator_FULLY_CONNECTED, circle::BuiltinOptions_FullyConnectedOptions, + CreateFullyConnectedOptions(builder, to_circle_actfunc(node->fusedActivationFunction())) + .Union()); +} - // Make input, output and options for operator - std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), - get_tensor_index(node->weights()), - get_tensor_index(node->bias())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - auto options = - CreateFullyConnectedOptions(builder, to_circle_actfunc(node->fusedActivationFunction())); +void OperationExporter::visit(luci::CircleGather *node) +{ + export_simple(node, circle::BuiltinOperator_GATHER, circle::BuiltinOptions_GatherOptions, + CreateGatherOptions(builder, node->axis()).Union()); +} - // Make FULLY_CONNECTED operator - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_FullyConnectedOptions, options.Union()); - gd._operators.push_back(op_offset); +void OperationExporter::visit(luci::CircleGatherNd *node) +{ + export_simple(node, circle::BuiltinOperator_GATHER_ND, circle::BuiltinOptions_GatherNdOptions, + CreateGatherNdOptions(builder).Union()); } -void OperationExporter::visit(luci::CircleLogicalNot *node) +void OperationExporter::visit(luci::CircleGreater *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_LOGICAL_NOT); + export_simple(node, circle::BuiltinOperator_GREATER, circle::BuiltinOptions_GreaterOptions, + CreateGreaterOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleGreaterEqual *node) +{ + export_simple(node, circle::BuiltinOperator_GREATER_EQUAL, + circle::BuiltinOptions_GreaterEqualOptions, + CreateGreaterEqualOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleIf *node) +{ + auto if_outs = loco::succs(node); + assert(if_outs.size() == node->output_count()); + + uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_IF, node->op_version()); + std::vector<int32_t> inputs_vec; + std::vector<int32_t> outputs_vec; + + inputs_vec.push_back(get_tensor_index(node->cond())); + for (uint32_t idx = 0; idx < node->input_count(); ++idx) + inputs_vec.push_back(get_tensor_index(node->input(idx))); + + for (uint32_t idx = 0; idx < node->output_count(); ++idx) + { + // store in order of index + bool found = false; + for (auto out : if_outs) + { + auto if_out = loco::must_cast<luci::CircleIfOut *>(out); + if (if_out->index() == static_cast<int32_t>(idx)) + { + outputs_vec.push_back(get_tensor_index(if_out)); + found = true; + break; + } + } + if (!found) + { + INTERNAL_EXN("Invalid CircleIf output"); + } + } - // Make input, output and options for operator - std::vector<int32_t> inputs_vec{get_tensor_index(node->x())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; auto inputs = builder.CreateVector(inputs_vec); auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateLogicalNotOptions(builder); - - // Make LOGICAL_NOT operator + auto options = CreateIfOptions(builder, node->then_branch(), node->else_branch()); auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_LogicalNotOptions, options.Union()); + circle::BuiltinOptions_IfOptions, options.Union()); gd._operators.push_back(op_offset); } +void OperationExporter::visit(luci::CircleL2Normalize *node) +{ + export_simple( + node, circle::BuiltinOperator_L2_NORMALIZATION, circle::BuiltinOptions_L2NormOptions, + CreateL2NormOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union()); +} + +void OperationExporter::visit(luci::CircleL2Pool2D *node) +{ + export_pool_2d<luci::CircleL2Pool2D>(node, circle::BuiltinOperator_L2_POOL_2D); +} + +void OperationExporter::visit(luci::CircleLeakyRelu *node) +{ + export_simple(node, circle::BuiltinOperator_LEAKY_RELU, circle::BuiltinOptions_LeakyReluOptions, + CreateLeakyReluOptions(builder, node->alpha()).Union()); +} + +void OperationExporter::visit(luci::CircleLess *node) +{ + export_simple(node, circle::BuiltinOperator_LESS, circle::BuiltinOptions_LessOptions, + CreateLessOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleLessEqual *node) +{ + export_simple(node, circle::BuiltinOperator_LESS_EQUAL, circle::BuiltinOptions_LessEqualOptions, + CreateLessEqualOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleLocalResponseNormalization *node) +{ + export_simple(node, circle::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION, + circle::BuiltinOptions_LocalResponseNormalizationOptions, + CreateLocalResponseNormalizationOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleLog *node) +{ + export_simple(node, circle::BuiltinOperator_LOG); +} + +void OperationExporter::visit(luci::CircleLogicalAnd *node) +{ + export_simple(node, circle::BuiltinOperator_LOGICAL_AND, circle::BuiltinOptions_LogicalAndOptions, + CreateLogicalAndOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleLogicalNot *node) +{ + export_simple(node, circle::BuiltinOperator_LOGICAL_NOT, circle::BuiltinOptions_LogicalNotOptions, + CreateLogicalNotOptions(builder).Union()); +} + void OperationExporter::visit(luci::CircleLogicalOr *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_LOGICAL_OR); + export_simple(node, circle::BuiltinOperator_LOGICAL_OR, circle::BuiltinOptions_LogicalOrOptions, + CreateLogicalOrOptions(builder).Union()); +} - // Make input, output and options for operator - std::vector<int32_t> inputs_vec{get_tensor_index(node->x()), get_tensor_index(node->y())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateLogicalOrOptions(builder); +void OperationExporter::visit(luci::CircleLogistic *node) +{ + export_simple(node, circle::BuiltinOperator_LOGISTIC); +} - // Make LOGICAL_OR operator - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_LogicalOrOptions, options.Union()); - gd._operators.push_back(op_offset); +void OperationExporter::visit(luci::CircleLogSoftmax *node) +{ + export_simple(node, circle::BuiltinOperator_LOG_SOFTMAX, circle::BuiltinOptions_LogSoftmaxOptions, + CreateLogSoftmaxOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleMatrixDiag *node) +{ + export_simple(node, circle::BuiltinOperator_MATRIX_DIAG, circle::BuiltinOptions_MatrixDiagOptions, + CreateMatrixDiagOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleMatrixSetDiag *node) +{ + export_simple(node, circle::BuiltinOperator_MATRIX_SET_DIAG, + circle::BuiltinOptions_MatrixSetDiagOptions, + CreateMatrixSetDiagOptions(builder).Union()); } void OperationExporter::visit(luci::CircleMaximum *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_MAXIMUM); - std::vector<int32_t> inputs_vec{get_tensor_index(node->x()), get_tensor_index(node->y())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateMaximumMinimumOptions(builder); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_MaximumMinimumOptions, options.Union()); - gd._operators.push_back(op_offset); + export_simple(node, circle::BuiltinOperator_MAXIMUM, circle::BuiltinOptions_MaximumMinimumOptions, + CreateMaximumMinimumOptions(builder).Union()); } void OperationExporter::visit(luci::CircleMaxPool2D *node) @@ -362,259 +662,568 @@ void OperationExporter::visit(luci::CircleMaxPool2D *node) void OperationExporter::visit(luci::CircleMean *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_MEAN); - std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), - get_tensor_index(node->reduction_indices())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateReducerOptions(builder, node->keep_dims()); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_ReducerOptions, options.Union()); - gd._operators.push_back(op_offset); + export_simple(node, circle::BuiltinOperator_MEAN, circle::BuiltinOptions_ReducerOptions, + CreateReducerOptions(builder, node->keep_dims()).Union()); +} + +void OperationExporter::visit(luci::CircleMinimum *node) +{ + export_simple(node, circle::BuiltinOperator_MINIMUM, circle::BuiltinOptions_MaximumMinimumOptions, + CreateMaximumMinimumOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleMirrorPad *node) +{ + export_simple(node, circle::BuiltinOperator_MIRROR_PAD, circle::BuiltinOptions_MirrorPadOptions, + CreateMirrorPadOptions(builder, to_circle_mirrorpadmode(node->mode())).Union()); } void OperationExporter::visit(luci::CircleMul *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_MUL); - std::vector<int32_t> inputs_vec{get_tensor_index(node->x()), get_tensor_index(node->y())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateMulOptions(builder, to_circle_actfunc(node->fusedActivationFunction())); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_MulOptions, options.Union()); - gd._operators.push_back(op_offset); + export_simple( + node, circle::BuiltinOperator_MUL, circle::BuiltinOptions_MulOptions, + CreateMulOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union()); } -void OperationExporter::visit(luci::CirclePack *node) +void OperationExporter::visit(luci::CircleNeg *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_PACK); - std::vector<int32_t> inputs_vec; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; + export_simple(node, circle::BuiltinOperator_NEG, circle::BuiltinOptions_NegOptions, + CreateNegOptions(builder).Union()); +} - for (uint32_t i = 0; i < node->values_count(); ++i) - inputs_vec.push_back(get_tensor_index(node->values(i))); +void OperationExporter::visit(luci::CircleNotEqual *node) +{ + export_simple(node, circle::BuiltinOperator_NOT_EQUAL, circle::BuiltinOptions_NotEqualOptions, + CreateNotEqualOptions(builder).Union()); +} - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - auto options = CreatePackOptions(builder, node->values_count(), node->axis()); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_PackOptions, options.Union()); - gd._operators.push_back(op_offset); +void OperationExporter::visit(luci::CircleOneHot *node) +{ + export_simple(node, circle::BuiltinOperator_ONE_HOT, circle::BuiltinOptions_OneHotOptions, + CreateOneHotOptions(builder, node->axis()).Union()); +} + +void OperationExporter::visit(luci::CirclePack *node) +{ + export_simple(node, circle::BuiltinOperator_PACK, circle::BuiltinOptions_PackOptions, + CreatePackOptions(builder, node->values_count(), node->axis()).Union()); } void OperationExporter::visit(luci::CirclePad *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_PAD); - std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), - get_tensor_index(node->paddings())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - auto options = CreatePadOptions(builder); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_PadOptions, options.Union()); - gd._operators.push_back(op_offset); + export_simple(node, circle::BuiltinOperator_PAD, circle::BuiltinOptions_PadOptions, + CreatePadOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CirclePow *node) +{ + export_simple(node, circle::BuiltinOperator_POW, circle::BuiltinOptions_PowOptions, + CreatePowOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CirclePRelu *node) +{ + export_simple(node, circle::BuiltinOperator_PRELU); +} + +void OperationExporter::visit(luci::CircleRange *node) +{ + export_simple(node, circle::BuiltinOperator_RANGE, circle::BuiltinOptions_RangeOptions, + CreateRangeOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleRank *node) +{ + export_simple(node, circle::BuiltinOperator_RANK, circle::BuiltinOptions_RankOptions, + CreateRankOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleReduceAny *node) +{ + export_simple(node, circle::BuiltinOperator_REDUCE_ANY, circle::BuiltinOptions_ReducerOptions, + CreateReducerOptions(builder, node->keep_dims()).Union()); +} + +void OperationExporter::visit(luci::CircleReduceMax *node) +{ + export_simple(node, circle::BuiltinOperator_REDUCE_MAX, circle::BuiltinOptions_ReducerOptions, + CreateReducerOptions(builder, node->keep_dims()).Union()); +} + +void OperationExporter::visit(luci::CircleReduceMin *node) +{ + export_simple(node, circle::BuiltinOperator_REDUCE_MIN, circle::BuiltinOptions_ReducerOptions, + CreateReducerOptions(builder, node->keep_dims()).Union()); +} + +void OperationExporter::visit(luci::CircleReduceProd *node) +{ + export_simple(node, circle::BuiltinOperator_REDUCE_PROD, circle::BuiltinOptions_ReducerOptions, + CreateReducerOptions(builder, node->keep_dims()).Union()); } void OperationExporter::visit(luci::CircleRelu *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_RELU); - std::vector<int32_t> inputs_vec{get_tensor_index(node->features())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs); - gd._operators.push_back(op_offset); + export_simple(node, circle::BuiltinOperator_RELU); } void OperationExporter::visit(luci::CircleRelu6 *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_RELU6); - std::vector<int32_t> inputs_vec{get_tensor_index(node->features())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs); - gd._operators.push_back(op_offset); + export_simple(node, circle::BuiltinOperator_RELU6); } -void OperationExporter::visit(luci::CircleReshape *node) +void OperationExporter::visit(luci::CircleReluN1To1 *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_RESHAPE); - - // Create inputs and outputs. - std::vector<int32_t> inputs_vec{get_tensor_index(node->tensor()), - get_tensor_index(node->shape())}; - std::vector<int32_t> outputs_vec{get_tensor_index(node)}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); + export_simple(node, circle::BuiltinOperator_RELU_N1_TO_1); +} - // Create options. +void OperationExporter::visit(luci::CircleReshape *node) +{ auto new_shape = builder.CreateVector<int32_t>( node->newShape()->rank(), [node](size_t i) { return node->newShape()->dim(i); }); - auto options = CreateReshapeOptions(builder, new_shape); - // Create the operator. - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_ReshapeOptions, options.Union()); - gd._operators.push_back(op_offset); + export_simple(node, circle::BuiltinOperator_RESHAPE, circle::BuiltinOptions_ReshapeOptions, + CreateReshapeOptions(builder, new_shape).Union()); } -void OperationExporter::visit(luci::CircleRsqrt *node) +void OperationExporter::visit(luci::CircleResizeBilinear *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_RSQRT); - std::vector<int32_t> inputs_vec{get_tensor_index(node->x())}; + export_simple( + node, circle::BuiltinOperator_RESIZE_BILINEAR, circle::BuiltinOptions_ResizeBilinearOptions, + CreateResizeBilinearOptions(builder, node->align_corners(), node->half_pixel_centers()) + .Union()); +} + +void OperationExporter::visit(luci::CircleResizeNearestNeighbor *node) +{ + export_simple(node, circle::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR, + circle::BuiltinOptions_ResizeNearestNeighborOptions, + CreateResizeNearestNeighborOptions(builder, node->align_corners()).Union()); +} + +void OperationExporter::visit(luci::CircleReverseSequence *node) +{ + export_simple( + node, circle::BuiltinOperator_REVERSE_SEQUENCE, circle::BuiltinOptions_ReverseSequenceOptions, + CreateReverseSequenceOptions(builder, node->seq_axis(), node->batch_axis()).Union()); +} + +void OperationExporter::visit(luci::CircleReverseV2 *node) +{ + uint32_t op_idx = + md.registerBuiltinOpcode(circle::BuiltinOperator_REVERSE_V2, node->op_version()); + std::vector<int32_t> inputs_vec{get_tensor_index(node->tensor()), get_tensor_index(node->axis())}; std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; auto inputs = builder.CreateVector(inputs_vec); auto outputs = builder.CreateVector(outputs_vec); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs); + auto options = CreateReverseV2Options(builder); + auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, + circle::BuiltinOptions_ReverseSequenceOptions, options.Union()); gd._operators.push_back(op_offset); } +void OperationExporter::visit(luci::CircleRound *node) +{ + export_simple(node, circle::BuiltinOperator_ROUND); +} + +void OperationExporter::visit(luci::CircleRsqrt *node) +{ + export_simple(node, circle::BuiltinOperator_RSQRT); +} + +void OperationExporter::visit(luci::CircleScatterNd *node) +{ + export_simple(node, circle::BuiltinOperator_SCATTER_ND, circle::BuiltinOptions_ScatterNdOptions, + CreateScatterNdOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleSegmentSum *node) +{ + export_simple(node, circle::BuiltinOperator_SEGMENT_SUM, circle::BuiltinOptions_SegmentSumOptions, + CreateSegmentSumOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleSelect *node) +{ + export_simple(node, circle::BuiltinOperator_SELECT, circle::BuiltinOptions_SelectOptions, + CreateSelectOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleSelectV2 *node) +{ + export_simple(node, circle::BuiltinOperator_SELECT_V2, circle::BuiltinOptions_SelectV2Options, + CreateSelectV2Options(builder).Union()); +} + +void OperationExporter::visit(luci::CircleShape *node) +{ + export_simple(node, circle::BuiltinOperator_SHAPE, circle::BuiltinOptions_ShapeOptions, + CreateShapeOptions(builder, to_circle_tensortype(node->out_type())).Union()); +} + +void OperationExporter::visit(luci::CircleSin *node) +{ + export_simple(node, circle::BuiltinOperator_SIN); +} + +void OperationExporter::visit(luci::CircleSlice *node) +{ + export_simple(node, circle::BuiltinOperator_SLICE, circle::BuiltinOptions_SliceOptions, + CreateSliceOptions(builder).Union()); +} + void OperationExporter::visit(luci::CircleSoftmax *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SOFTMAX); - std::vector<int32_t> inputs_vec{get_tensor_index(node->logits())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; + export_simple(node, circle::BuiltinOperator_SOFTMAX, circle::BuiltinOptions_SoftmaxOptions, + CreateSoftmaxOptions(builder, node->beta()).Union()); +} + +void OperationExporter::visit(luci::CircleSpaceToBatchND *node) +{ + export_simple(node, circle::BuiltinOperator_SPACE_TO_BATCH_ND, + circle::BuiltinOptions_SpaceToBatchNDOptions, + CreateSpaceToBatchNDOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleSpaceToDepth *node) +{ + export_simple(node, circle::BuiltinOperator_SPACE_TO_DEPTH, + circle::BuiltinOptions_SpaceToDepthOptions, + CreateSpaceToDepthOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleSparseToDense *node) +{ + export_simple(node, circle::BuiltinOperator_SPARSE_TO_DENSE, + circle::BuiltinOptions_SparseToDenseOptions, + CreateSparseToDenseOptions(builder, node->validate_indices()).Union()); +} + +void OperationExporter::visit(luci::CircleSplit *node) +{ + auto split_outs = loco::succs(node); + assert(int32_t(split_outs.size()) == node->num_split()); + + uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SPLIT, node->op_version()); + // NOTE BuiltinOperator_SPLIT input is placed at second position + std::vector<int32_t> inputs_vec{get_tensor_index(node->split_dim()), + get_tensor_index(node->input())}; + std::vector<int32_t> outputs_vec; + + for (int32_t index = 0; index < node->num_split(); index++) + { + // store in order of index + bool found = false; + for (auto out : split_outs) + { + auto split_out = loco::must_cast<luci::CircleSplitOut *>(out); + if (split_out->index() == index) + { + outputs_vec.push_back(get_tensor_index(split_out)); + found = true; + break; + } + } + if (!found) + { + INTERNAL_EXN("Invalid Split output"); + } + } + auto inputs = builder.CreateVector(inputs_vec); auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateSoftmaxOptions(builder, node->beta()); + auto options = CreateSplitOptions(builder, node->num_split()); auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_SoftmaxOptions, options.Union()); + circle::BuiltinOptions_SplitOptions, options.Union()); gd._operators.push_back(op_offset); } -void OperationExporter::visit(luci::CircleSqrt *node) +void OperationExporter::visit(luci::CircleSplitV *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SQRT); - std::vector<int32_t> inputs_vec{get_tensor_index(node->x())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; + auto split_outs = loco::succs(node); + assert(int32_t(split_outs.size()) == node->num_split()); + + uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SPLIT_V, node->op_version()); + std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), + get_tensor_index(node->size_splits()), + get_tensor_index(node->split_dim())}; + std::vector<int32_t> outputs_vec; + + for (int32_t index = 0; index < node->num_split(); index++) + { + // store in order of index + bool found = false; + for (auto out : split_outs) + { + auto split_out = loco::must_cast<luci::CircleSplitVOut *>(out); + if (split_out->index() == index) + { + outputs_vec.push_back(get_tensor_index(split_out)); + found = true; + break; + } + } + if (!found) + { + INTERNAL_EXN("Invalid SplitV output"); + } + } + auto inputs = builder.CreateVector(inputs_vec); auto outputs = builder.CreateVector(outputs_vec); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs); + auto options = CreateSplitVOptions(builder, node->num_split()); + auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, + circle::BuiltinOptions_SplitVOptions, options.Union()); gd._operators.push_back(op_offset); } +void OperationExporter::visit(luci::CircleSqrt *node) +{ + export_simple(node, circle::BuiltinOperator_SQRT); +} + +void OperationExporter::visit(luci::CircleSquare *node) +{ + export_simple(node, circle::BuiltinOperator_SQUARE, circle::BuiltinOptions_SquareOptions, + CreateSquareOptions(builder).Union()); +} + void OperationExporter::visit(luci::CircleSquaredDifference *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SQUARED_DIFFERENCE); - std::vector<int32_t> inputs_vec{get_tensor_index(node->x()), get_tensor_index(node->y())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateSquaredDifferenceOptions(builder); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_SquaredDifferenceOptions, options.Union()); - gd._operators.push_back(op_offset); + export_simple(node, circle::BuiltinOperator_SQUARED_DIFFERENCE, + circle::BuiltinOptions_SquaredDifferenceOptions, + CreateSquaredDifferenceOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleSqueeze *node) +{ + auto squeeze_dims = builder.CreateVector<int32_t>(node->squeeze_dims()); + export_simple(node, circle::BuiltinOperator_SQUEEZE, circle::BuiltinOptions_SqueezeOptions, + CreateSqueezeOptions(builder, squeeze_dims).Union()); +} + +void OperationExporter::visit(luci::CircleStridedSlice *node) +{ + export_simple(node, circle::BuiltinOperator_STRIDED_SLICE, + circle::BuiltinOptions_StridedSliceOptions, + CreateStridedSliceOptions(builder, node->begin_mask(), node->end_mask(), + node->ellipsis_mask(), node->new_axis_mask(), + node->shrink_axis_mask()) + .Union()); } void OperationExporter::visit(luci::CircleSub *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SUB); - std::vector<int32_t> inputs_vec{get_tensor_index(node->x()), get_tensor_index(node->y())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; - auto inputs = builder.CreateVector(inputs_vec); - auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateSubOptions(builder, to_circle_actfunc(node->fusedActivationFunction())); - auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_SubOptions, options.Union()); - gd._operators.push_back(op_offset); + export_simple( + node, circle::BuiltinOperator_SUB, circle::BuiltinOptions_SubOptions, + CreateSubOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union()); } -// TODO CircleTanh +void OperationExporter::visit(luci::CircleSum *node) +{ + export_simple(node, circle::BuiltinOperator_SUM, circle::BuiltinOptions_ReducerOptions, + CreateReducerOptions(builder, node->keep_dims()).Union()); +} -void OperationExporter::visit(luci::CircleTranspose *node) +void OperationExporter::visit(luci::CircleTanh *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_TRANSPOSE); - std::vector<int32_t> inputs_vec{get_tensor_index(node->arg(0)), get_tensor_index(node->arg(1))}; - std::vector<int32_t> outputs_vec{get_tensor_index(node)}; + export_simple(node, circle::BuiltinOperator_TANH); +} + +void OperationExporter::visit(luci::CircleTile *node) +{ + export_simple(node, circle::BuiltinOperator_TILE, circle::BuiltinOptions_TileOptions, + CreateTileOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleTopKV2 *node) +{ + auto topkv2_outs = loco::succs(node); + int outs_count = int32_t(topkv2_outs.size()); + assert(outs_count == 2); + + uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_TOPK_V2, node->op_version()); + std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), get_tensor_index(node->k())}; + std::vector<int32_t> outputs_vec; + + for (int32_t index = 0; index < outs_count; index++) + { + // store in order of index + bool found = false; + for (auto out : topkv2_outs) + { + auto topkv2_out = loco::must_cast<luci::CircleTopKV2Out *>(out); + if (topkv2_out->index() == index) + { + outputs_vec.push_back(get_tensor_index(topkv2_out)); + found = true; + break; + } + } + if (!found) + { + INTERNAL_EXN("Invalid TopKV2 output"); + } + } auto inputs = builder.CreateVector(inputs_vec); auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateTransposeOptions(builder); - - auto op_offset = - CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions::BuiltinOptions_TransposeOptions, options.Union()); + auto options = CreateTopKV2Options(builder); + auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, + circle::BuiltinOptions_TopKV2Options, options.Union()); gd._operators.push_back(op_offset); } +void OperationExporter::visit(luci::CircleTranspose *node) +{ + export_simple(node, circle::BuiltinOperator_TRANSPOSE, circle::BuiltinOptions_TransposeOptions, + CreateTransposeOptions(builder).Union()); +} + void OperationExporter::visit(luci::CircleTransposeConv *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_TRANSPOSE_CONV); + export_simple(node, circle::BuiltinOperator_TRANSPOSE_CONV, + circle::BuiltinOptions_TransposeConvOptions, + CreateTransposeConvOptions(builder, getOpPadding(node->padding()), + node->stride()->w(), node->stride()->h()) + .Union()); +} + +void OperationExporter::visit(luci::CircleUnpack *node) +{ + LOGGER(l); + auto settings = luci::UserSettings::settings(); + + auto unpack_outs = loco::succs(node); + // NOTE real models may not use all of the outputs + if (static_cast<int32_t>(unpack_outs.size()) != node->num()) + { + if (settings->get(luci::UserSettings::Key::DisableValidation)) + { + WARN(l) << "Warning: export Unpack(" << node->name() << ") 'num' not same as outputs"; + } + else + assert(false); + } + + uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_UNPACK, node->op_version()); + std::vector<int32_t> inputs_vec{get_tensor_index(node->value())}; + std::vector<int32_t> outputs_vec; + + for (int32_t index = 0; index < node->num(); index++) + { + // store in order of index + bool found = false; + for (auto out : unpack_outs) + { + auto unpack_out = loco::must_cast<luci::CircleUnpackOut *>(out); + if (unpack_out->index() == index) + { + outputs_vec.push_back(get_tensor_index(unpack_out)); + found = true; + break; + } + } + // NOTE real models may not use all of the outputs + if (!found) + { + if (settings->get(luci::UserSettings::Key::DisableValidation)) + { + WARN(l) << "Warning: export Unpack(" << node->name() << ") output " << index << " not used"; + } + else + assert(false); + } + } - // Make input, output and options for operator - std::vector<int32_t> inputs_vec{get_tensor_index(node->inputSizes()), - get_tensor_index(node->filter()), - get_tensor_index(node->outBackprop())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; auto inputs = builder.CreateVector(inputs_vec); auto outputs = builder.CreateVector(outputs_vec); - circle::Padding padding = getOpPadding(node->padding()); - auto options = - CreateTransposeConvOptions(builder, padding, node->stride()->w(), node->stride()->h()); - - // Make TRANSPOSE_CONV operator + auto options = CreateUnpackOptions(builder, node->num(), node->axis()); auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_TransposeConvOptions, options.Union()); + circle::BuiltinOptions_UnpackOptions, options.Union()); gd._operators.push_back(op_offset); } -void OperationExporter::visit(luci::CircleInstanceNorm *node) +void OperationExporter::visit(luci::CircleWhere *node) { - uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_INSTANCE_NORM); - std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), get_tensor_index(node->gamma()), - get_tensor_index(node->beta())}; - std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))}; + export_simple(node, circle::BuiltinOperator_WHERE, circle::BuiltinOptions_WhereOptions, + CreateWhereOptions(builder).Union()); +} + +void OperationExporter::visit(luci::CircleWhile *node) +{ + auto while_outs = loco::succs(node); + assert(while_outs.size() == node->output_count()); + + uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_WHILE, node->op_version()); + std::vector<int32_t> inputs_vec; + std::vector<int32_t> outputs_vec; + + for (uint32_t idx = 0; idx < node->input_count(); ++idx) + inputs_vec.push_back(get_tensor_index(node->input(idx))); + + for (uint32_t idx = 0; idx < node->output_count(); ++idx) + { + // store in order of index + bool found = false; + for (auto out : while_outs) + { + auto while_out = loco::must_cast<luci::CircleWhileOut *>(out); + if (while_out->index() == static_cast<int32_t>(idx)) + { + outputs_vec.push_back(get_tensor_index(while_out)); + found = true; + break; + } + } + if (!found) + { + INTERNAL_EXN("Invalid CircleWhile output"); + } + } + auto inputs = builder.CreateVector(inputs_vec); auto outputs = builder.CreateVector(outputs_vec); - auto options = CreateInstanceNormOptions(builder, node->epsilon(), - to_circle_actfunc(node->fusedActivationFunction())); + auto options = CreateWhileOptions(builder, node->cond_branch(), node->body_branch()); auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, - circle::BuiltinOptions_InstanceNormOptions, options.Union()); + circle::BuiltinOptions_WhileOptions, options.Union()); gd._operators.push_back(op_offset); } -void OperationExporter::visit(luci::CircleEqual *node) +void OperationExporter::visit(luci::CircleZerosLike *node) { - uint32_t opcode_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_EQUAL); - std::vector<int32_t> inputs{get_tensor_index(node->x()), get_tensor_index(node->y())}; - std::vector<int32_t> outputs{get_tensor_index(node)}; - - auto fb_inputs = builder.CreateVector(inputs); - auto fb_outputs = builder.CreateVector(outputs); + export_simple(node, circle::BuiltinOperator_ZEROS_LIKE, circle::BuiltinOptions_ZerosLikeOptions, + CreateZerosLikeOptions(builder).Union()); +} - auto options = CreateEqualOptions(builder); +void OperationExporter::visit(luci::CircleBCQFullyConnected *node) +{ + export_simple(node, circle::BuiltinOperator_BCQ_FULLY_CONNECTED, + circle::BuiltinOptions_BCQFullyConnectedOptions, + CreateBCQFullyConnectedOptions(builder, node->weights_hidden_size(), + to_circle_actfunc(node->fusedActivationFunction())) + .Union()); +} - auto op_offset = CreateOperator(builder, opcode_idx, fb_inputs, fb_outputs, - circle::BuiltinOptions_EqualOptions, options.Union()); +void OperationExporter::visit(luci::CircleBCQGather *node) +{ + export_simple(node, circle::BuiltinOperator_BCQ_GATHER, circle::BuiltinOptions_BCQGatherOptions, + CreateBCQGatherOptions(builder, node->input_hidden_size(), node->axis()).Union()); +} - gd._operators.push_back(op_offset); +void OperationExporter::visit(luci::CircleInstanceNorm *node) +{ + export_simple(node, circle::BuiltinOperator_INSTANCE_NORM, + circle::BuiltinOptions_InstanceNormOptions, + CreateInstanceNormOptions(builder, node->epsilon(), + to_circle_actfunc(node->fusedActivationFunction())) + .Union()); } void exportNode(loco::Node *node, flatbuffers::FlatBufferBuilder &builder, SerializedModelData &md, SerializedGraphData &gd) { - // TODO Use explicit tagging to prevent possible mistake - auto isNoOp = [](loco::Node *node) { - // If there is only one input and the TensorIndex for the input is same - // as the TensorIndex of the output then this node is just a dummy node - if (node->arity() == 1) - { - assert(node->arg(0) != nullptr); - return get_tensor_index(node) == get_tensor_index(node->arg(0)); - } - return false; - }; - - if (isNoOp(node)) - { - // Skip if a given node is marked as NoOp (op with no effect) before - return; - } - if (auto circle_node = dynamic_cast<luci::CircleNode *>(node)) { OperationExporter exporter{builder, md, gd}; diff --git a/compiler/luci/export/src/CircleTensorExporter.cpp b/compiler/luci/export/src/CircleTensorExporter.cpp index ef9b9d7d9..5cad3920b 100644 --- a/compiler/luci/export/src/CircleTensorExporter.cpp +++ b/compiler/luci/export/src/CircleTensorExporter.cpp @@ -15,6 +15,7 @@ */ #include "CircleTensorExporter.h" +#include "TypeBridge.h" #include <luci/IR/CircleNodes.h> #include <luci/IR/CircleNodeVisitor.h> @@ -52,6 +53,9 @@ public: const ShapeDescription &shape(void) const { return _shape; } void shape(const ShapeDescription &shape) { _shape = shape; } + luci::ShapeStatus shape_status(void) const { return _shape_status; } + void shape_status(luci::ShapeStatus ss) { _shape_status = ss; } + public: luci::CircleConst *content(void) const { return _content; } void content(luci::CircleConst *c) { _content = c; } @@ -62,8 +66,9 @@ public: private: std::string _name; - circle::TensorType _dtype; - ShapeDescription _shape; + circle::TensorType _dtype{circle::TensorType_FLOAT32}; + ShapeDescription _shape{}; + luci::ShapeStatus _shape_status{luci::ShapeStatus::UNDEFINED}; luci::CircleConst *_content = nullptr; luci::CircleQuantParam *_quantparam = nullptr; @@ -76,30 +81,16 @@ struct NoOpDetector final : public luci::CircleNodeMutableVisitor<bool> // Input is Virtual but does produce a Tensor // Output is Virtual that does not produce any Tensor bool visit(luci::CircleOutput *) final { return true; } + bool visit(luci::CircleOutputExclude *) final { return true; } // Return false by default bool visit(luci::CircleNode *) final { return false; } }; -void allocateCircleTensor(CircleNode *node, CircleTensorContext &ctx) +void allocateCircleTensorInfo(CircleNode *node, CircleTensorContext &ctx) { LOGGER(l); - auto isNoOp = [](loco::Node *node) { - if (auto circle_node = dynamic_cast<luci::CircleNode *>(node)) - { - NoOpDetector d; - return circle_node->accept(&d); - } - return false; - }; - - if (isNoOp(node)) - { - set_tensor_index(node, get_tensor_index(node->arg(0))); - return; - } - auto tensor_index = static_cast<CircleTensorIndex>(ctx.size()); // TODO Use Graph-level metadata for Input & Output // auto tensor_name = "t_" + std::to_string(tensor_index); @@ -111,8 +102,10 @@ void allocateCircleTensor(CircleNode *node, CircleTensorContext &ctx) CircleTensoInfo tensor_info; tensor_info.name(tensor_name); - tensor_info.dtype(TypeInference::get(node)); - tensor_info.shape(ShapeInference::get(node)); + tensor_info.dtype(to_circle_tensortype(luci::node_dtype(node))); + if (node->shape_status() == ShapeStatus::VALID) + tensor_info.shape(to_shape_description(luci::node_shape(node))); + tensor_info.shape_status(node->shape_status()); tensor_info.content(dynamic_cast<luci::CircleConst *>(node)); tensor_info.quantparam(node->quantparam()); @@ -122,6 +115,108 @@ void allocateCircleTensor(CircleNode *node, CircleTensorContext &ctx) ctx.emplace_back(tensor_info); } +class MultiOutputDetector final : public luci::CircleNodeMutableVisitor<bool> +{ +public: + MultiOutputDetector(CircleTensorContext &ctx) : _ctx(ctx) {} + +private: + void store_outputs(luci::CircleNode *node, uint32_t count) + { + auto outs = loco::succs(node); + assert(outs.size() == count); + (void)count; // for unused variable error in release build + for (auto out : outs) + { + auto circle_out = loco::must_cast<luci::CircleNode *>(out); + allocateCircleTensorInfo(circle_out, _ctx); + } + set_tensor_index(node, -1); + } + +public: + bool visit(luci::CircleIfOut *) final { return true; } + bool visit(luci::CircleSplitOut *) final { return true; } + bool visit(luci::CircleSplitVOut *) final { return true; } + bool visit(luci::CircleTopKV2Out *) final { return true; } + bool visit(luci::CircleUnpackOut *) final { return true; } + bool visit(luci::CircleWhileOut *) final { return true; } + + bool visit(luci::CircleIf *node) final + { + store_outputs(node, node->output_count()); + return true; + } + + bool visit(luci::CircleSplit *node) final + { + store_outputs(node, uint32_t(node->num_split())); + return true; + } + + bool visit(luci::CircleSplitV *node) final + { + store_outputs(node, uint32_t(node->num_split())); + return true; + } + + bool visit(luci::CircleTopKV2 *node) final + { + store_outputs(node, 2); + return true; + } + + bool visit(luci::CircleUnpack *node) final + { + store_outputs(node, node->num()); + return true; + } + + bool visit(luci::CircleWhile *node) final + { + store_outputs(node, node->output_count()); + return true; + } + + // Return false by default + bool visit(luci::CircleNode *) final { return false; } + +private: + CircleTensorContext &_ctx; +}; + +void allocateCircleTensor(CircleNode *node, CircleTensorContext &ctx) +{ + if (node == nullptr) + throw std::runtime_error("allocateCIrcleTensor Failed : node is nullptr"); + + auto isNoOp = [](loco::Node *node) { + if (auto circle_node = dynamic_cast<luci::CircleNode *>(node)) + { + NoOpDetector d; + return circle_node->accept(&d); + } + return false; + }; + + if (isNoOp(node)) + { + set_tensor_index(node, -1); + return; + } + + // TODO revise this when loco supports multiple outputs + // NOTE this will store all virtual output tensors and skip for the real node + if (auto circle_node = dynamic_cast<luci::CircleNode *>(node)) + { + MultiOutputDetector d(ctx); + if (circle_node->accept(&d)) + return; + } + + allocateCircleTensorInfo(node, ctx); +} + } // namespace namespace @@ -166,18 +261,22 @@ flatbuffers::Offset<circle::Buffer> encodeOpBufferByDType(FlatBufferBuilder &bui template <> flatbuffers::Offset<circle::Buffer> encodeOpBuffer(FlatBufferBuilder &builder, luci::CircleConst *c) { - // TODO use switch - if (c->dtype() == loco::DataType::FLOAT32) + switch (c->dtype()) { - return encodeOpBufferByDType<loco::DataType::FLOAT32>(builder, c); - } - else if (c->dtype() == loco::DataType::S32) - { - return encodeOpBufferByDType<loco::DataType::S32>(builder, c); - } - else if (c->dtype() == loco::DataType::U8) - { - return encodeOpBufferByDType<loco::DataType::U8>(builder, c); + case loco::DataType::FLOAT32: + return encodeOpBufferByDType<loco::DataType::FLOAT32>(builder, c); + case loco::DataType::S16: + return encodeOpBufferByDType<loco::DataType::S16>(builder, c); + case loco::DataType::S32: + return encodeOpBufferByDType<loco::DataType::S32>(builder, c); + case loco::DataType::S64: + return encodeOpBufferByDType<loco::DataType::S64>(builder, c); + case loco::DataType::U8: + return encodeOpBufferByDType<loco::DataType::U8>(builder, c); + case loco::DataType::BOOL: + return encodeOpBufferByDType<loco::DataType::BOOL>(builder, c); + default: + break; } INTERNAL_EXN_V("Unsupported datatype", oops::to_uint32(c->dtype())); @@ -210,7 +309,9 @@ void exportOpDefinedTensor(const CircleTensoInfo &info, FlatBufferBuilder &build SerializedModelData &md, SerializedGraphData &gd) { // Create and register output tensor shape - auto shape_offset = encodeShape(builder, info.shape()); + flatbuffers::Offset<Vector<int32_t>> shape_offset; + if (info.shape_status() == ShapeStatus::VALID) + shape_offset = encodeShape(builder, info.shape()); // encode and register output tensor buffer auto buffer = @@ -249,9 +350,21 @@ void exportOpDefinedTensors(loco::Graph *g, FlatBufferBuilder &builder, Serializ { CircleTensorContext tensor_ctx; + // NOTE There may exist dangle CircleInput that is not visited with postorder_traversal() + // All dangle CircleOutput should be visited by postorder_traversal() + auto nodes = g->nodes(); + for (uint32_t n = 0; n < nodes->size(); ++n) + { + auto node = dynamic_cast<luci::CircleInput *>(nodes->at(n)); + if (node != nullptr) + allocateCircleTensor(node, tensor_ctx); + } + for (auto node : loco::postorder_traversal(loco::output_nodes(g))) { - CircleNode *circle_node = dynamic_cast<luci::CircleNode *>(node); + CircleNode *circle_node = loco::must_cast<luci::CircleNode *>(node); + if (dynamic_cast<const luci::CircleInput *>(circle_node) != nullptr) + continue; allocateCircleTensor(circle_node, tensor_ctx); } diff --git a/compiler/luci/export/src/ProgressReporter.cpp b/compiler/luci/export/src/ProgressReporter.cpp index ac9c3d9a8..216bd3f2a 100644 --- a/compiler/luci/export/src/ProgressReporter.cpp +++ b/compiler/luci/export/src/ProgressReporter.cpp @@ -49,36 +49,36 @@ namespace luci void ProgressReporter::notify(const logo::PhaseEventInfo<logo::PhaseEvent::PhaseBegin> *) { - LOGGER(prime); + LOGGER(l); - INFO(prime) << "=============================================================="; - INFO(prime) << "luci::PhaseRunner<" << to_str(strategy()) << ">"; - INFO(prime) << "Initial graph"; - INFO(prime) << fmt(graph()); + VERBOSE(l, 4) << "=============================================================="; + VERBOSE(l, 4) << "luci::PhaseRunner<" << to_str(strategy()) << ">"; + VERBOSE(l, 4) << "Initial graph"; + VERBOSE(l, 4) << fmt(graph()); } void ProgressReporter::notify(const logo::PhaseEventInfo<logo::PhaseEvent::PhaseEnd> *) { - LOGGER(prime); + LOGGER(l); - INFO(prime) << "luci::PhaseRunner<" << to_str(strategy()) << "> - done"; + VERBOSE(l, 4) << "luci::PhaseRunner<" << to_str(strategy()) << "> - done"; } void ProgressReporter::notify(const logo::PhaseEventInfo<logo::PhaseEvent::PassBegin> *info) { - LOGGER(prime); + LOGGER(l); - INFO(prime) << "--------------------------------------------------------------"; - INFO(prime) << "Before " << logo::pass_name(info->pass()); + VERBOSE(l, 4) << "--------------------------------------------------------------"; + VERBOSE(l, 4) << "Before " << logo::pass_name(info->pass()); } void ProgressReporter::notify(const logo::PhaseEventInfo<logo::PhaseEvent::PassEnd> *info) { - LOGGER(prime); + LOGGER(l); - INFO(prime) << "After " << logo::pass_name(info->pass()) - << " (changed: " << to_char(info->changed()) << ")"; - INFO(prime) << fmt(graph()); + VERBOSE(l, 4) << "After " << logo::pass_name(info->pass()) + << " (changed: " << to_char(info->changed()) << ")"; + VERBOSE(l, 4) << fmt(graph()); } } // namespace luci diff --git a/compiler/luci/export/src/SerializedData.h b/compiler/luci/export/src/SerializedData.h index 84249653c..251daa0ea 100644 --- a/compiler/luci/export/src/SerializedData.h +++ b/compiler/luci/export/src/SerializedData.h @@ -29,8 +29,20 @@ namespace luci struct OpCode { circle::BuiltinOperator opcode; - - bool operator==(const OpCode &rhs) const { return opcode == rhs.opcode; } + std::string custom_code{""}; + int32_t version = 1; + + bool operator==(const OpCode &rhs) const + { + if (opcode == circle::BuiltinOperator_CUSTOM) + { + return custom_code == rhs.custom_code; + } + else + { + return opcode == rhs.opcode; + } + } }; } // namespace luci @@ -53,11 +65,13 @@ namespace luci */ struct SubGraphContext { + /// @brief SubGraph name + std::string _name; /// @brief SubGraph input tensor id std::vector<int32_t> _inputs; /// @brief SubGraph output tensor id std::vector<int32_t> _outputs; - /// @DataFormat for SubGraph + /// @brief DataFormat for SubGraph circle::DataFormat _data_format{circle::DataFormat::DataFormat_CHANNELS_LAST}; }; @@ -68,7 +82,6 @@ struct SerializedModelData final SerializedModelData(const SerializedModelData &) = delete; std::unordered_map<OpCode, uint32_t> _operator_codes; - std::unordered_map<OpCode, std::string> _custom_operator_codes; std::vector<flatbuffers::Offset<circle::Buffer>> _buffers; /** @@ -76,7 +89,7 @@ struct SerializedModelData final * @param builtin_code * @return idx of opcode in table of opcodes (see schema) */ - uint32_t registerBuiltinOpcode(circle::BuiltinOperator builtin_code); + uint32_t registerBuiltinOpcode(circle::BuiltinOperator builtin_code, const int32_t op_version); uint32_t registerCustomOpcode(const std::string &custom_op); }; diff --git a/compiler/luci/export/src/TypeBridge.cpp b/compiler/luci/export/src/TypeBridge.cpp new file mode 100644 index 000000000..9ccd52376 --- /dev/null +++ b/compiler/luci/export/src/TypeBridge.cpp @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TypeBridge.h" + +#include "CircleExporterUtils.h" + +#include <luci/IR/CircleNodes.h> +#include <luci/IR/CircleNodeVisitor.h> +#include <luci/Service/CircleTypeInference.h> +#include <luci/Service/CircleShapeInference.h> + +#include <loco/Service/TypeInference.h> +#include <loco/Service/ShapeInference.h> + +namespace +{ + +/** + * @brief CopySelector will return condition of copy shape/type inference to node + */ +struct CopySelector final : public luci::CircleNodeVisitor<bool> +{ + // return false(don't copy) for nodes that provides shape/type from nature + bool visit(const luci::CircleInput *) final { return false; } + bool visit(const luci::CircleConst *) final { return false; } + + // default is copy attributes + bool visit(const luci::CircleNode *) { return true; } +}; + +} // namespace + +namespace luci +{ + +loco::TensorShape node_shape(CircleNode *node) +{ + loco::TensorShape shape; + + shape.rank(node->rank()); + for (uint32_t r = 0; r < node->rank(); ++r) + { + shape.dim(r) = loco::Dimension(node->dim(r).value()); + } + return shape; +} + +loco::DataType node_dtype(CircleNode *node) { return node->dtype(); } + +void copy_shape_dtype(loco::Graph *graph) +{ + /** + * @note We will iterate all the nodes in the graph to include dangle nodes + */ + auto nodes = graph->nodes(); + for (uint32_t n = 0; n < nodes->size(); ++n) + { + auto node = loco::must_cast<luci::CircleNode *>(nodes->at(n)); + + CopySelector cs; + if (node->accept(&cs)) + { + // NOTE not all nodes have infered shape/dtype: multiple outs may not be + // visited when outputs are not used + // TODO fix shape inference traversal + // NOTE when loco supports multiple outputs in nature this issue should be + // resolved also + + if (loco::dtype_known(node)) + { + node->dtype(loco::dtype_get(node)); + } + + if (loco::shape_known(node)) + { + auto shape = loco::shape_get(node).as<loco::TensorShape>(); + node->rank(shape.rank()); + for (uint32_t r = 0; r < shape.rank(); ++r) + { + node->dim(r) = loco::Dimension(shape.dim(r).value()); + } + + // ShapeStatus should be update only when the status was UNDEFINED + if (node->shape_status() == ShapeStatus::UNDEFINED) + node->shape_status(ShapeStatus::VALID); + } + } + } +} + +} // namespace luci diff --git a/compiler/luci/export/src/TypeBridge.h b/compiler/luci/export/src/TypeBridge.h new file mode 100644 index 000000000..a63fbce54 --- /dev/null +++ b/compiler/luci/export/src/TypeBridge.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __TYPE_BRIDGE_H__ +#define __TYPE_BRIDGE_H__ + +#include <luci/IR/CircleNode.h> + +#include <loco.h> + +namespace luci +{ + +/** + * @brief node_shape() will return loco::TensorShape of CircleNode + */ +loco::TensorShape node_shape(CircleNode *node); + +/** + * @brief node_dtype() will return loco::DataType of CircleNode + */ +loco::DataType node_dtype(CircleNode *node); + +/** + * @brief copy_shape_dtype() will copy shape and dtype inference data to CircleNode + */ +void copy_shape_dtype(loco::Graph *graph); + +} // namespace luci + +#endif // __TYPE_BRIDGE_H__ diff --git a/compiler/luci/import/CMakeLists.txt b/compiler/luci/import/CMakeLists.txt index bc9a9152a..2ae00b837 100644 --- a/compiler/luci/import/CMakeLists.txt +++ b/compiler/luci/import/CMakeLists.txt @@ -7,6 +7,7 @@ target_include_directories(luci_import PRIVATE src) target_include_directories(luci_import PUBLIC include) target_link_libraries(luci_import PUBLIC luci_lang) target_link_libraries(luci_import PUBLIC mio_circle) +target_link_libraries(luci_import PRIVATE luci_env) target_link_libraries(luci_import PRIVATE luci_log) target_link_libraries(luci_import PRIVATE luci_logex) target_link_libraries(luci_import PRIVATE nncc_common) diff --git a/compiler/luci/import/include/luci/Import/CircleReader.h b/compiler/luci/import/include/luci/Import/CircleReader.h index fcbe09ceb..3d85b9e35 100644 --- a/compiler/luci/import/include/luci/Import/CircleReader.h +++ b/compiler/luci/import/include/luci/Import/CircleReader.h @@ -21,6 +21,7 @@ #include <luci/IR/AttrFusedActFunc.h> #include <luci/IR/AttrPadding.h> +#include <luci/IR/CircleNode.h> #include <luci/IR/CircleQuantParam.h> #include <loco.h> @@ -42,9 +43,13 @@ const circle::QuantizationParametersT *tensor_quantization(const circle::TensorT loco::DataType luci_datatype(circle::TensorType type); FusedActFunc luci_actfunc(const circle::ActivationFunctionType type); Padding luci_padding(const circle::Padding padding); +MirrorPadMode luci_mirrorpad_mode(const circle::MirrorPadMode mode); std::unique_ptr<CircleQuantParam> luci_quantparam(const circle::QuantizationParametersT *quantization); +/// @brief Copy common tensor attributes such as name, type, etc. to node. +void copy_tensor_attributes(const circle::TensorT &tensor, CircleNode *node); + /** * @brief Loads Circle file and provides helpers to access attributes */ @@ -56,6 +61,9 @@ private: using CircleOperators_t = std::vector<std::unique_ptr<circle::OperatorT>>; using CircleOperatorCodes_t = std::vector<std::unique_ptr<circle::OperatorCodeT>>; + using CircleSubGraphsPtr_t = flatbuffers::Vector<flatbuffers::Offset<circle::SubGraph>>; + using CircleTensorsPtr_t = flatbuffers::Vector<flatbuffers::Offset<circle::Tensor>>; + public: CircleReader() = default; @@ -68,6 +76,8 @@ public: const std::vector<int32_t> &outputs() const { return _current_subgraph->outputs; } const std::string &name() const { return _current_subgraph->name; } + const CircleTensorsPtr_t *tensors_ptr() const { return _tensors_ptr; } + uint32_t num_subgraph() const { return _model->subgraphs.size(); } circle::BuiltinOperator builtin_code(const circle::OperatorT &op) const; @@ -80,6 +90,9 @@ public: private: std::unique_ptr<const circle::ModelT> _model; const circle::SubGraphT *_current_subgraph{nullptr}; + + const circle::Model *_model_ptr{nullptr}; + const CircleTensorsPtr_t *_tensors_ptr{nullptr}; }; } // namespace luci diff --git a/compiler/luci/import/include/luci/Import/GraphBuilder.h b/compiler/luci/import/include/luci/Import/GraphBuilder.h index 61f673fb6..548264dac 100644 --- a/compiler/luci/import/include/luci/Import/GraphBuilder.h +++ b/compiler/luci/import/include/luci/Import/GraphBuilder.h @@ -18,6 +18,7 @@ #define __LUCI_IMPORT_GRAPH_BUILDER_H__ #include "GraphBuilderContext.h" +#include "GraphBuilderBase.h" #include <mio/circle/schema_generated.h> @@ -25,25 +26,14 @@ namespace luci { /** - * @brief Interface of convert circle:: NodeDef to loco::Node (e.g., Conv2DGraphBuilder) + * @brief Base of general single output graph builder(e.g., Conv2DGraphBuilder) */ -class GraphBuilder +class GraphBuilder : public GraphBuilderBase { public: - struct ValidateArgs - { - ValidateArgs(const circle::OperatorT &o, const CircleReader &r) : op(o), reader(r) {} - - const circle::OperatorT &op; - const CircleReader &reader; - }; - -public: virtual ~GraphBuilder() = default; - virtual bool validate(const ValidateArgs &) const = 0; - - void build(const circle::OperatorT &op, GraphBuilderContext *context) const; + void build(const circle::OperatorT &op, GraphBuilderContext *context) const final; private: virtual CircleNode *build_node(const circle::OperatorT &op, diff --git a/compiler/luci/import/include/luci/Import/GraphBuilderBase.h b/compiler/luci/import/include/luci/Import/GraphBuilderBase.h new file mode 100644 index 000000000..a0cd008e0 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/GraphBuilderBase.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_GRAPH_BUILDER_BASE_H__ +#define __LUCI_IMPORT_GRAPH_BUILDER_BASE_H__ + +#include "GraphBuilderContext.h" + +#include <mio/circle/schema_generated.h> + +namespace luci +{ + +/** + * @brief Interface of convert circle::OperatorT to CircleNode + */ +struct GraphBuilderBase +{ + struct ValidateArgs + { + ValidateArgs(const circle::OperatorT &o, const CircleReader &r) : op(o), reader(r) {} + + const circle::OperatorT &op; + const CircleReader &reader; + }; + + virtual bool validate(const ValidateArgs &) const = 0; + virtual void build(const circle::OperatorT &op, GraphBuilderContext *context) const = 0; + + virtual ~GraphBuilderBase() = default; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_GRAPH_BUILDER_BASE_H__ diff --git a/compiler/luci/import/include/luci/Import/GraphBuilderContext.h b/compiler/luci/import/include/luci/Import/GraphBuilderContext.h index 8d464181d..72e237abc 100644 --- a/compiler/luci/import/include/luci/Import/GraphBuilderContext.h +++ b/compiler/luci/import/include/luci/Import/GraphBuilderContext.h @@ -24,6 +24,7 @@ #include <loco.h> #include <map> +#include <set> namespace luci { @@ -48,13 +49,29 @@ private: }; /** + * @brief Set of Tensor Index of outputs of operators + * including graph input nodes + */ +class IndexTensorOutputs +{ +public: + void enroll(TensorIndex idx); + + bool find(TensorIndex idx); + +private: + std::set<TensorIndex> _set; +}; + +/** * @brief Class to store context to build loco graph IR from TensorFlow */ class GraphBuilderContext { public: - GraphBuilderContext(loco::Graph *g, CircleReader *reader, IndexNodeFinder *nodefinder) - : _g(g), _reader(reader), _indexnodefinder(nodefinder) + GraphBuilderContext(loco::Graph *g, CircleReader *reader, IndexNodeFinder *nodefinder, + IndexTensorOutputs *tensoroutputs) + : _g(g), _reader(reader), _indexnodefinder(nodefinder), _indextensoroutputs(tensoroutputs) { // DO NOTHING } @@ -67,11 +84,13 @@ public: CircleReader *reader() { return _reader; } IndexNodeFinder *nodefinder() { return _indexnodefinder; } + IndexTensorOutputs *tensoroutputs() { return _indextensoroutputs; } private: loco::Graph *_g; CircleReader *_reader; IndexNodeFinder *_indexnodefinder; + IndexTensorOutputs *_indextensoroutputs; }; } // namespace luci diff --git a/compiler/luci/import/include/luci/Import/GraphBuilderRegistry.h b/compiler/luci/import/include/luci/Import/GraphBuilderRegistry.h index 99054e7b6..b8dc22fdd 100644 --- a/compiler/luci/import/include/luci/Import/GraphBuilderRegistry.h +++ b/compiler/luci/import/include/luci/Import/GraphBuilderRegistry.h @@ -17,7 +17,7 @@ #ifndef __LUCI_IMPORT_GRAPH_BUILDER_REGISTRY_H__ #define __LUCI_IMPORT_GRAPH_BUILDER_REGISTRY_H__ -#include "GraphBuilder.h" +#include "GraphBuilderBase.h" #include <map> @@ -31,11 +31,11 @@ struct GraphBuilderSource /** * @brief Returns registered GraphBuilder pointer for operator (nullptr if not present) */ - virtual const GraphBuilder *lookup(const circle::BuiltinOperator &op) const = 0; + virtual const GraphBuilderBase *lookup(const circle::BuiltinOperator &op) const = 0; }; /** - * @brief Class to return graph builder for TF nodes + * @brief Class to return graph builder for Circle nodes */ class GraphBuilderRegistry final : public GraphBuilderSource { @@ -53,7 +53,7 @@ public: * @brief Returns registered GraphBuilder pointer for operator or * nullptr if not registered */ - const GraphBuilder *lookup(const circle::BuiltinOperator &op) const final + const GraphBuilderBase *lookup(const circle::BuiltinOperator &op) const final { if (_builder_map.find(op) == _builder_map.end()) return (_parent == nullptr) ? nullptr : _parent->lookup(op); @@ -68,7 +68,7 @@ public: } public: - void add(const circle::BuiltinOperator op, std::unique_ptr<GraphBuilder> &&builder) + void add(const circle::BuiltinOperator op, std::unique_ptr<GraphBuilderBase> &&builder) { _builder_map[op] = std::move(builder); } @@ -77,7 +77,7 @@ private: const GraphBuilderSource *_parent = nullptr; private: - std::map<const circle::BuiltinOperator, std::unique_ptr<GraphBuilder>> _builder_map; + std::map<const circle::BuiltinOperator, std::unique_ptr<GraphBuilderBase>> _builder_map; }; } // namespace luci diff --git a/compiler/luci/import/include/luci/Import/Nodes.h b/compiler/luci/import/include/luci/Import/Nodes.h index 381d02b97..2719a5aec 100644 --- a/compiler/luci/import/include/luci/Import/Nodes.h +++ b/compiler/luci/import/include/luci/Import/Nodes.h @@ -19,30 +19,110 @@ #include "Nodes/CircleAbs.h" #include "Nodes/CircleAdd.h" +#include "Nodes/CircleAddN.h" #include "Nodes/CircleArgMax.h" +#include "Nodes/CircleArgMin.h" #include "Nodes/CircleAveragePool2D.h" +#include "Nodes/CircleBatchMatMul.h" #include "Nodes/CircleBatchToSpaceND.h" +#include "Nodes/CircleBCQFullyConnected.h" +#include "Nodes/CircleBCQGather.h" +#include "Nodes/CircleCast.h" +#include "Nodes/CircleCeil.h" #include "Nodes/CircleConcatenation.h" #include "Nodes/CircleConst.h" #include "Nodes/CircleConv2D.h" #include "Nodes/CircleCos.h" +#include "Nodes/CircleCustom.h" +#include "Nodes/CircleDepthToSpace.h" #include "Nodes/CircleDepthwiseConv2D.h" #include "Nodes/CircleDiv.h" +#include "Nodes/CircleElu.h" #include "Nodes/CircleEqual.h" #include "Nodes/CircleExp.h" +#include "Nodes/CircleExpandDims.h" +#include "Nodes/CircleFill.h" +#include "Nodes/CircleFloor.h" +#include "Nodes/CircleFloorDiv.h" +#include "Nodes/CircleFloorMod.h" #include "Nodes/CircleFullyConnected.h" +#include "Nodes/CircleGather.h" +#include "Nodes/CircleGatherNd.h" +#include "Nodes/CircleGreater.h" +#include "Nodes/CircleGreaterEqual.h" +#include "Nodes/CircleIf.h" +#include "Nodes/CircleInstanceNorm.h" +#include "Nodes/CircleL2Normalize.h" +#include "Nodes/CircleL2Pool2D.h" +#include "Nodes/CircleLeakyRelu.h" +#include "Nodes/CircleLess.h" +#include "Nodes/CircleLessEqual.h" +#include "Nodes/CircleLocalResponseNormalization.h" +#include "Nodes/CircleLog.h" +#include "Nodes/CircleLogicalAnd.h" #include "Nodes/CircleLogicalNot.h" #include "Nodes/CircleLogicalOr.h" +#include "Nodes/CircleLogistic.h" +#include "Nodes/CircleLogSoftmax.h" +#include "Nodes/CircleMatrixSetDiag.h" +#include "Nodes/CircleMaximum.h" #include "Nodes/CircleMaxPool2D.h" +#include "Nodes/CircleMatrixDiag.h" #include "Nodes/CircleMean.h" +#include "Nodes/CircleMinimum.h" +#include "Nodes/CircleMirrorPad.h" #include "Nodes/CircleMul.h" +#include "Nodes/CircleNeg.h" +#include "Nodes/CircleNotEqual.h" +#include "Nodes/CircleOneHot.h" #include "Nodes/CirclePack.h" #include "Nodes/CirclePad.h" +#include "Nodes/CirclePow.h" +#include "Nodes/CirclePRelu.h" +#include "Nodes/CircleRange.h" +#include "Nodes/CircleRank.h" +#include "Nodes/CircleReduceAny.h" +#include "Nodes/CircleReduceMax.h" +#include "Nodes/CircleReduceMin.h" +#include "Nodes/CircleReduceProd.h" #include "Nodes/CircleRelu.h" +#include "Nodes/CircleRelu6.h" +#include "Nodes/CircleReluN1To1.h" #include "Nodes/CircleReshape.h" +#include "Nodes/CircleResizeBilinear.h" +#include "Nodes/CircleResizeNearestNeighbor.h" +#include "Nodes/CircleReverseSequence.h" +#include "Nodes/CircleReverseV2.h" +#include "Nodes/CircleRound.h" #include "Nodes/CircleRsqrt.h" +#include "Nodes/CircleScatterNd.h" +#include "Nodes/CircleSegmentSum.h" +#include "Nodes/CircleSelect.h" +#include "Nodes/CircleSelectV2.h" +#include "Nodes/CircleShape.h" +#include "Nodes/CircleSin.h" +#include "Nodes/CircleSlice.h" #include "Nodes/CircleSoftmax.h" +#include "Nodes/CircleSpaceToBatchND.h" +#include "Nodes/CircleSpaceToDepth.h" +#include "Nodes/CircleSparseToDense.h" +#include "Nodes/CircleSplit.h" +#include "Nodes/CircleSplitV.h" +#include "Nodes/CircleSqrt.h" +#include "Nodes/CircleSquare.h" +#include "Nodes/CircleSquaredDifference.h" +#include "Nodes/CircleSqueeze.h" +#include "Nodes/CircleStridedSlice.h" #include "Nodes/CircleSub.h" +#include "Nodes/CircleSum.h" +#include "Nodes/CircleTanh.h" +#include "Nodes/CircleTile.h" +#include "Nodes/CircleTopKV2.h" #include "Nodes/CircleTranspose.h" +#include "Nodes/CircleTransposeConv.h" +#include "Nodes/CircleUnpack.h" +#include "Nodes/CircleWhere.h" +#include "Nodes/CircleWhile.h" +#include "Nodes/CircleZerosLike.h" #endif // __LUCI_IMPORT_NODES_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleAddN.h b/compiler/luci/import/include/luci/Import/Nodes/CircleAddN.h new file mode 100644 index 000000000..3ec6b2a45 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleAddN.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_ADD_N_H__ +#define __LUCI_IMPORT_OP_CIRCLE_ADD_N_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleAddNGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_ADD_N_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleArgMin.h b/compiler/luci/import/include/luci/Import/Nodes/CircleArgMin.h new file mode 100644 index 000000000..746f52837 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleArgMin.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_ARGMIN_H__ +#define __LUCI_IMPORT_OP_CIRCLE_ARGMIN_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleArgMinGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_ARGMIN_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleBCQFullyConnected.h b/compiler/luci/import/include/luci/Import/Nodes/CircleBCQFullyConnected.h new file mode 100644 index 000000000..be58acd8d --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleBCQFullyConnected.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_BCQFULLYCONNECTED_H__ +#define __LUCI_IMPORT_OP_CIRCLE_BCQFULLYCONNECTED_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleBCQFullyConnectedGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_BCQFULLYCONNECTED_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleBCQGather.h b/compiler/luci/import/include/luci/Import/Nodes/CircleBCQGather.h new file mode 100644 index 000000000..ff1c1f7e9 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleBCQGather.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_BCQGATHER_H__ +#define __LUCI_IMPORT_OP_CIRCLE_BCQGATHER_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleBCQGatherGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_BCQGATHER_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleBatchMatMul.h b/compiler/luci/import/include/luci/Import/Nodes/CircleBatchMatMul.h new file mode 100644 index 000000000..b46a8715c --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleBatchMatMul.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_BATCHMATMUL_H__ +#define __LUCI_IMPORT_OP_CIRCLE_BATCHMATMUL_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleBatchMatMulGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_BATCHMATMUL_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleCast.h b/compiler/luci/import/include/luci/Import/Nodes/CircleCast.h new file mode 100644 index 000000000..1cd850bc7 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleCast.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_CAST_H__ +#define __LUCI_IMPORT_OP_CIRCLE_CAST_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleCastGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_CAST_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleCeil.h b/compiler/luci/import/include/luci/Import/Nodes/CircleCeil.h new file mode 100644 index 000000000..f1bdf2397 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleCeil.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_CEIL_H__ +#define __LUCI_IMPORT_OP_CIRCLE_CEIL_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleCeilGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_CEIL_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleCustom.h b/compiler/luci/import/include/luci/Import/Nodes/CircleCustom.h new file mode 100644 index 000000000..65745be4b --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleCustom.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_CUSTOM_H__ +#define __LUCI_IMPORT_OP_CIRCLE_CUSTOM_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleCustomGraphBuilder : public GraphBuilderBase +{ +public: + bool validate(const ValidateArgs &args) const final; + + void build(const circle::OperatorT &op, GraphBuilderContext *context) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_CUSTOM_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleDepthToSpace.h b/compiler/luci/import/include/luci/Import/Nodes/CircleDepthToSpace.h new file mode 100644 index 000000000..a479cbd20 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleDepthToSpace.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_DEPTHTOSPACE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_DEPTHTOSPACE_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleDepthToSpaceGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_DEPTHTOSPACE_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleElu.h b/compiler/luci/import/include/luci/Import/Nodes/CircleElu.h new file mode 100644 index 000000000..2ec5642ce --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleElu.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_ELU_H__ +#define __LUCI_IMPORT_OP_CIRCLE_ELU_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleEluGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_ELU_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleExpandDims.h b/compiler/luci/import/include/luci/Import/Nodes/CircleExpandDims.h new file mode 100644 index 000000000..acbfe7aea --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleExpandDims.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_EXPAND_DIMS_H__ +#define __LUCI_IMPORT_OP_CIRCLE_EXPAND_DIMS_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleExpandDimsGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_EXPAND_DIMS_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleFill.h b/compiler/luci/import/include/luci/Import/Nodes/CircleFill.h new file mode 100644 index 000000000..3539dcd56 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleFill.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_FILL_H__ +#define __LUCI_IMPORT_OP_CIRCLE_FILL_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleFillGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_FILL_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleFloor.h b/compiler/luci/import/include/luci/Import/Nodes/CircleFloor.h new file mode 100644 index 000000000..057800865 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleFloor.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_FLOOR_H__ +#define __LUCI_IMPORT_OP_CIRCLE_FLOOR_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleFloorGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_FLOOR_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleFloorDiv.h b/compiler/luci/import/include/luci/Import/Nodes/CircleFloorDiv.h new file mode 100644 index 000000000..ddc2ab2ff --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleFloorDiv.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_FLOOR_DIV_H__ +#define __LUCI_IMPORT_OP_CIRCLE_FLOOR_DIV_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleFloorDivGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_FLOOR_DIV_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleFloorMod.h b/compiler/luci/import/include/luci/Import/Nodes/CircleFloorMod.h new file mode 100644 index 000000000..1d6aa87c2 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleFloorMod.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_FLOOR_MOD_H__ +#define __LUCI_IMPORT_OP_CIRCLE_FLOOR_MOD_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleFloorModGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_FLOOR_MOD_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleGather.h b/compiler/luci/import/include/luci/Import/Nodes/CircleGather.h new file mode 100644 index 000000000..0680c9451 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleGather.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_GATHER_H__ +#define __LUCI_IMPORT_OP_CIRCLE_GATHER_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleGatherGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_GATHER_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleGatherNd.h b/compiler/luci/import/include/luci/Import/Nodes/CircleGatherNd.h new file mode 100644 index 000000000..be96b7dbe --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleGatherNd.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_GATHER_ND_H__ +#define __LUCI_IMPORT_OP_CIRCLE_GATHER_ND_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleGatherNdGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_GATHER_ND_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleGreater.h b/compiler/luci/import/include/luci/Import/Nodes/CircleGreater.h new file mode 100644 index 000000000..87f0a8d83 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleGreater.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_GREATER_H__ +#define __LUCI_IMPORT_OP_CIRCLE_GREATER_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleGreaterGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_GREATER_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleGreaterEqual.h b/compiler/luci/import/include/luci/Import/Nodes/CircleGreaterEqual.h new file mode 100644 index 000000000..4d24314e9 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleGreaterEqual.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_GREATEREQUAL_H__ +#define __LUCI_IMPORT_OP_CIRCLE_GREATEREQUAL_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleGreaterEqualGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_GREATEREQUAL_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleIf.h b/compiler/luci/import/include/luci/Import/Nodes/CircleIf.h new file mode 100644 index 000000000..8faf09cae --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleIf.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_IF_H__ +#define __LUCI_IMPORT_OP_CIRCLE_IF_H__ + +#include "luci/Import/GraphBuilderBase.h" + +namespace luci +{ + +class CircleIfGraphBuilder : public GraphBuilderBase +{ +public: + bool validate(const ValidateArgs &args) const final; + + void build(const circle::OperatorT &op, GraphBuilderContext *context) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_IF_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleInstanceNorm.h b/compiler/luci/import/include/luci/Import/Nodes/CircleInstanceNorm.h new file mode 100644 index 000000000..5fd8f148a --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleInstanceNorm.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_INSTANCE_NORM_H__ +#define __LUCI_IMPORT_OP_CIRCLE_INSTANCE_NORM_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleInstanceNormGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_INSTANCE_NORM_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleL2Normalize.h b/compiler/luci/import/include/luci/Import/Nodes/CircleL2Normalize.h new file mode 100644 index 000000000..116605f09 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleL2Normalize.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_L2_NORMALIZE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_L2_NORMALIZE_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleL2NormalizeGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_L2_NORMALIZE_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleL2Pool2D.h b/compiler/luci/import/include/luci/Import/Nodes/CircleL2Pool2D.h new file mode 100644 index 000000000..2211c4751 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleL2Pool2D.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_L2_POOL2D_H__ +#define __LUCI_IMPORT_OP_CIRCLE_L2_POOL2D_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleL2Pool2DGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_L2_POOL2D_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLeakyRelu.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLeakyRelu.h new file mode 100644 index 000000000..b7fa41f25 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLeakyRelu.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_LEAKY_RELU_H__ +#define __LUCI_IMPORT_OP_CIRCLE_LEAKY_RELU_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleLeakyReluGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_LEAKY_RELU_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLess.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLess.h new file mode 100644 index 000000000..b93155bc4 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLess.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_LESS_H__ +#define __LUCI_IMPORT_OP_CIRCLE_LESS_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleLessGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_LESS_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLessEqual.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLessEqual.h new file mode 100644 index 000000000..e54a4cb8c --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLessEqual.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_LESS_EQUAL_H__ +#define __LUCI_IMPORT_OP_CIRCLE_LESS_EQUAL_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleLessEqualGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_LESS_EQUAL_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLocalResponseNormalization.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLocalResponseNormalization.h new file mode 100644 index 000000000..95e6ea880 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLocalResponseNormalization.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_LOCAL_RESPONSE_NORMALIZATION_H__ +#define __LUCI_IMPORT_OP_CIRCLE_LOCAL_RESPONSE_NORMALIZATION_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleLocalResponseNormalizationGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_LOCAL_RESPONSE_NORMALIZATION_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLog.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLog.h new file mode 100644 index 000000000..5b3321014 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLog.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_LOG_H__ +#define __LUCI_IMPORT_OP_CIRCLE_LOG_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleLogGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_LOG_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLogSoftmax.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLogSoftmax.h new file mode 100644 index 000000000..ef29833f5 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLogSoftmax.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_LOG_SOFTMAX_H__ +#define __LUCI_IMPORT_OP_CIRCLE_LOG_SOFTMAX_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleLogSoftmaxGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_LOG_SOFTMAX_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLogicalAnd.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLogicalAnd.h new file mode 100644 index 000000000..9336f4ac8 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLogicalAnd.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_LOGICALAND_H__ +#define __LUCI_IMPORT_OP_CIRCLE_LOGICALAND_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleLogicalAndGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_LOGICALAND_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleLogistic.h b/compiler/luci/import/include/luci/Import/Nodes/CircleLogistic.h new file mode 100644 index 000000000..67c6c1f1f --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleLogistic.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_LOGISTIC_H__ +#define __LUCI_IMPORT_OP_CIRCLE_LOGISTIC_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleLogisticGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_LOGISTIC_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleMatrixDiag.h b/compiler/luci/import/include/luci/Import/Nodes/CircleMatrixDiag.h new file mode 100644 index 000000000..e038c3e0a --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleMatrixDiag.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_MATRIX_DIAG_H__ +#define __LUCI_IMPORT_OP_CIRCLE_MATRIX_DIAG_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleMatrixDiagGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_MATRIX_DIAG_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleMatrixSetDiag.h b/compiler/luci/import/include/luci/Import/Nodes/CircleMatrixSetDiag.h new file mode 100644 index 000000000..a9ea0ac3d --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleMatrixSetDiag.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_MATRIX_SET_DIAG_H__ +#define __LUCI_IMPORT_OP_CIRCLE_MATRIX_SET_DIAG_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleMatrixSetDiagGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_MATRIX_SET_DIAG_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleMaximum.h b/compiler/luci/import/include/luci/Import/Nodes/CircleMaximum.h new file mode 100644 index 000000000..9705d3a36 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleMaximum.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_MAXIMUM_H__ +#define __LUCI_IMPORT_OP_CIRCLE_MAXIMUM_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleMaximumGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_MAXIMUM_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleMinimum.h b/compiler/luci/import/include/luci/Import/Nodes/CircleMinimum.h new file mode 100644 index 000000000..d9546ecf8 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleMinimum.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_MINIMUM_H__ +#define __LUCI_IMPORT_OP_CIRCLE_MINIMUM_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleMinimumGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_MINIMUM_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleMirrorPad.h b/compiler/luci/import/include/luci/Import/Nodes/CircleMirrorPad.h new file mode 100644 index 000000000..7f512cda7 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleMirrorPad.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_MIRROR_PAD_H__ +#define __LUCI_IMPORT_OP_CIRCLE_MIRROR_PAD_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleMirrorPadGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_MIRROR_PAD_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleNeg.h b/compiler/luci/import/include/luci/Import/Nodes/CircleNeg.h new file mode 100644 index 000000000..3d0bac19f --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleNeg.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_NEG_H__ +#define __LUCI_IMPORT_OP_CIRCLE_NEG_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleNegGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_NEG_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleNotEqual.h b/compiler/luci/import/include/luci/Import/Nodes/CircleNotEqual.h new file mode 100644 index 000000000..10c79b75e --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleNotEqual.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_NOTEQUAL_H__ +#define __LUCI_IMPORT_OP_CIRCLE_NOTEQUAL_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleNotEqualGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_NOTEQUAL_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleOneHot.h b/compiler/luci/import/include/luci/Import/Nodes/CircleOneHot.h new file mode 100644 index 000000000..8d9526d0e --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleOneHot.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_ONEHOT_H__ +#define __LUCI_IMPORT_OP_CIRCLE_ONEHOT_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleOneHotGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_ONEHOT_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CirclePRelu.h b/compiler/luci/import/include/luci/Import/Nodes/CirclePRelu.h new file mode 100644 index 000000000..822862cfd --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CirclePRelu.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_PRELU_H__ +#define __LUCI_IMPORT_OP_CIRCLE_PRELU_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CirclePReluGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_PRELU_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CirclePow.h b/compiler/luci/import/include/luci/Import/Nodes/CirclePow.h new file mode 100644 index 000000000..284aa9b89 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CirclePow.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_POW_H__ +#define __LUCI_IMPORT_OP_CIRCLE_POW_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CirclePowGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_POW_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleRange.h b/compiler/luci/import/include/luci/Import/Nodes/CircleRange.h new file mode 100644 index 000000000..bc63286b2 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleRange.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_RANGE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_RANGE_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleRangeGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_RANGE_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleRank.h b/compiler/luci/import/include/luci/Import/Nodes/CircleRank.h new file mode 100644 index 000000000..43a7fdb7b --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleRank.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_RANK_H__ +#define __LUCI_IMPORT_OP_CIRCLE_RANK_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleRankGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_RANK_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleReduceAny.h b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceAny.h new file mode 100644 index 000000000..5ee517999 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceAny.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_REDUCE_ANY_H__ +#define __LUCI_IMPORT_OP_CIRCLE_REDUCE_ANY_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleReduceAnyGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_REDUCE_ANY_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleReduceMax.h b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceMax.h new file mode 100644 index 000000000..0bc7021c1 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceMax.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_REDUCE_MAX_H__ +#define __LUCI_IMPORT_OP_CIRCLE_REDUCE_MAX_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleReduceMaxGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_REDUCE_MAX_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleReduceMin.h b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceMin.h new file mode 100644 index 000000000..0c05457f0 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceMin.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_REDUCE_MIN_H__ +#define __LUCI_IMPORT_OP_CIRCLE_REDUCE_MIN_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleReduceMinGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_REDUCE_MIN_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleReduceProd.h b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceProd.h new file mode 100644 index 000000000..446bc7866 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleReduceProd.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_REDUCE_PROD_H__ +#define __LUCI_IMPORT_OP_CIRCLE_REDUCE_PROD_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleReduceProdGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_REDUCE_PROD_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleRelu6.h b/compiler/luci/import/include/luci/Import/Nodes/CircleRelu6.h new file mode 100644 index 000000000..d17b4e200 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleRelu6.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_RELU6_H__ +#define __LUCI_IMPORT_OP_CIRCLE_RELU6_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleRelu6GraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_RELU6_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleReluN1To1.h b/compiler/luci/import/include/luci/Import/Nodes/CircleReluN1To1.h new file mode 100644 index 000000000..059431565 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleReluN1To1.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_RELU_N1_TO_1_H__ +#define __LUCI_IMPORT_OP_CIRCLE_RELU_N1_TO_1_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleReluN1To1GraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_RELU_N1_TO_1_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleResizeBilinear.h b/compiler/luci/import/include/luci/Import/Nodes/CircleResizeBilinear.h new file mode 100644 index 000000000..8c20ecc24 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleResizeBilinear.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_RESIZE_BILINEAR_H__ +#define __LUCI_IMPORT_OP_CIRCLE_RESIZE_BILINEAR_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleResizeBilinearGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_RESIZE_BILINEAR_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleResizeNearestNeighbor.h b/compiler/luci/import/include/luci/Import/Nodes/CircleResizeNearestNeighbor.h new file mode 100644 index 000000000..5b0647163 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleResizeNearestNeighbor.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_RESIZE_NEAREST_NEIGHBOR_H__ +#define __LUCI_IMPORT_OP_CIRCLE_RESIZE_NEAREST_NEIGHBOR_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleResizeNearestNeighborGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_RESIZE_NEAREST_NEIGHBOR_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleReverseSequence.h b/compiler/luci/import/include/luci/Import/Nodes/CircleReverseSequence.h new file mode 100644 index 000000000..cbeed3013 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleReverseSequence.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_REVERSE_SEQUENCE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_REVERSE_SEQUENCE_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleReverseSequenceGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_REVERSE_SEQUENCE_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleReverseV2.h b/compiler/luci/import/include/luci/Import/Nodes/CircleReverseV2.h new file mode 100644 index 000000000..f354298dd --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleReverseV2.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_REVERSE_V2_H__ +#define __LUCI_IMPORT_OP_CIRCLE_REVERSE_V2_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleReverseV2GraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_REVERSE_V2_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleRound.h b/compiler/luci/import/include/luci/Import/Nodes/CircleRound.h new file mode 100644 index 000000000..8b027d7ef --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleRound.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_ROUND_H__ +#define __LUCI_IMPORT_OP_CIRCLE_ROUND_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleRoundGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_ROUND_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleScatterNd.h b/compiler/luci/import/include/luci/Import/Nodes/CircleScatterNd.h new file mode 100644 index 000000000..8fa7a2f91 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleScatterNd.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SCATTER_ND_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SCATTER_ND_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleScatterNdGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SCATTER_ND_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSegmentSum.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSegmentSum.h new file mode 100644 index 000000000..7c33dee41 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSegmentSum.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SEGMENT_SUM_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SEGMENT_SUM_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleSegmentSumGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SEGMENT_SUM_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSelect.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSelect.h new file mode 100644 index 000000000..87bd1a7fe --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSelect.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SELECT_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SELECT_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleSelectGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SELECT_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSelectV2.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSelectV2.h new file mode 100644 index 000000000..28c73b087 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSelectV2.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SELECT_V2_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SELECT_V2_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleSelectV2GraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SELECT_V2_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleShape.h b/compiler/luci/import/include/luci/Import/Nodes/CircleShape.h new file mode 100644 index 000000000..3002084a5 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleShape.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SHAPE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SHAPE_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleShapeGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SHAPE_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSin.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSin.h new file mode 100644 index 000000000..605f5a5a0 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSin.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SIN_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SIN_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleSinGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SIN_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSlice.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSlice.h new file mode 100644 index 000000000..3bb4c51b7 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSlice.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SLICE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SLICE_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleSliceGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SLICE_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSpaceToBatchND.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSpaceToBatchND.h new file mode 100644 index 000000000..b8723098d --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSpaceToBatchND.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SPACETOBATCHND_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SPACETOBATCHND_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleSpaceToBatchNDGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SPACETOBATCHND_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSpaceToDepth.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSpaceToDepth.h new file mode 100644 index 000000000..75a54dd26 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSpaceToDepth.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SPACETODEPTH_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SPACETODEPTH_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleSpaceToDepthGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SPACETODEPTH_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSparseToDense.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSparseToDense.h new file mode 100644 index 000000000..baf240919 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSparseToDense.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SPARSETODENSE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SPARSETODENSE_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleSparseToDenseGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SPARSETODENSE_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSplit.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSplit.h new file mode 100644 index 000000000..3395e40fd --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSplit.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SPLIT_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SPLIT_H__ + +#include "luci/Import/GraphBuilderBase.h" + +namespace luci +{ + +class CircleSplitGraphBuilder : public GraphBuilderBase +{ +public: + bool validate(const ValidateArgs &args) const final; + + void build(const circle::OperatorT &op, GraphBuilderContext *context) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SPLIT_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSplitV.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSplitV.h new file mode 100644 index 000000000..3e53df362 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSplitV.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SPLIT_V_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SPLIT_V_H__ + +#include "luci/Import/GraphBuilderBase.h" + +namespace luci +{ + +class CircleSplitVGraphBuilder : public GraphBuilderBase +{ +public: + bool validate(const ValidateArgs &args) const final; + + void build(const circle::OperatorT &op, GraphBuilderContext *context) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SPLIT_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSqrt.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSqrt.h new file mode 100644 index 000000000..4fd79951c --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSqrt.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SQRT_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SQRT_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleSqrtGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SQRT_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSquare.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSquare.h new file mode 100644 index 000000000..3a1299102 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSquare.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SQUARE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SQUARE_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleSquareGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SQUARE_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSquaredDifference.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSquaredDifference.h new file mode 100644 index 000000000..95f08412b --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSquaredDifference.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SQUAREDDIFFERENCE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SQUAREDDIFFERENCE_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleSquaredDifferenceGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SQUAREDDIFFERENCE_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSqueeze.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSqueeze.h new file mode 100644 index 000000000..4f0dfb5ef --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSqueeze.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SQUEEZE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SQUEEZE_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleSqueezeGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SQUEEZE_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleStridedSlice.h b/compiler/luci/import/include/luci/Import/Nodes/CircleStridedSlice.h new file mode 100644 index 000000000..f535c3a61 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleStridedSlice.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_STRIDED_SLICE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_STRIDED_SLICE_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleStridedSliceGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_STRIDED_SLICE_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleSum.h b/compiler/luci/import/include/luci/Import/Nodes/CircleSum.h new file mode 100644 index 000000000..e65dd46ad --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleSum.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_SUM_H__ +#define __LUCI_IMPORT_OP_CIRCLE_SUM_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleSumGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_SUM_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleTanh.h b/compiler/luci/import/include/luci/Import/Nodes/CircleTanh.h new file mode 100644 index 000000000..b3795acba --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleTanh.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_TANH_H__ +#define __LUCI_IMPORT_OP_CIRCLE_TANH_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleTanhGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_TANH_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleTile.h b/compiler/luci/import/include/luci/Import/Nodes/CircleTile.h new file mode 100644 index 000000000..1da6cdbde --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleTile.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_TILE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_TILE_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleTileGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_TILE_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleTopKV2.h b/compiler/luci/import/include/luci/Import/Nodes/CircleTopKV2.h new file mode 100644 index 000000000..8ec3f3311 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleTopKV2.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_TOPK_V2_H__ +#define __LUCI_IMPORT_OP_CIRCLE_TOPK_V2_H__ + +#include "luci/Import/GraphBuilderBase.h" + +namespace luci +{ + +class CircleTopKV2GraphBuilder : public GraphBuilderBase +{ +public: + bool validate(const ValidateArgs &args) const final; + + void build(const circle::OperatorT &op, GraphBuilderContext *context) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_TOPK_V2_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleTransposeConv.h b/compiler/luci/import/include/luci/Import/Nodes/CircleTransposeConv.h new file mode 100644 index 000000000..2614d0d0d --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleTransposeConv.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_TRANSPOSE_CONV_H__ +#define __LUCI_IMPORT_OP_CIRCLE_TRANSPOSE_CONV_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleTransposeConvGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_TRANSPOSE_CONV_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleUnpack.h b/compiler/luci/import/include/luci/Import/Nodes/CircleUnpack.h new file mode 100644 index 000000000..f1a21de22 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleUnpack.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_UNPACK_H__ +#define __LUCI_IMPORT_OP_CIRCLE_UNPACK_H__ + +#include "luci/Import/GraphBuilderBase.h" + +namespace luci +{ + +class CircleUnpackGraphBuilder : public GraphBuilderBase +{ +public: + bool validate(const ValidateArgs &args) const final; + + void build(const circle::OperatorT &op, GraphBuilderContext *context) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_UNPACK_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleWhere.h b/compiler/luci/import/include/luci/Import/Nodes/CircleWhere.h new file mode 100644 index 000000000..72f98ef92 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleWhere.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_WHERE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_WHERE_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleWhereGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const override; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_WHERE_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleWhile.h b/compiler/luci/import/include/luci/Import/Nodes/CircleWhile.h new file mode 100644 index 000000000..68c56b3c6 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleWhile.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_WHILE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_WHILE_H__ + +#include "luci/Import/GraphBuilderBase.h" + +namespace luci +{ + +class CircleWhileGraphBuilder : public GraphBuilderBase +{ +public: + bool validate(const ValidateArgs &args) const final; + + void build(const circle::OperatorT &op, GraphBuilderContext *context) const final; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_WHILE_H__ diff --git a/compiler/luci/import/include/luci/Import/Nodes/CircleZerosLike.h b/compiler/luci/import/include/luci/Import/Nodes/CircleZerosLike.h new file mode 100644 index 000000000..2a3410379 --- /dev/null +++ b/compiler/luci/import/include/luci/Import/Nodes/CircleZerosLike.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IMPORT_OP_CIRCLE_ZEROS_LIKE_H__ +#define __LUCI_IMPORT_OP_CIRCLE_ZEROS_LIKE_H__ + +#include "luci/Import/GraphBuilder.h" + +namespace luci +{ + +class CircleZerosLikeGraphBuilder : public GraphBuilder +{ +public: + bool validate(const ValidateArgs &args) const final; + +private: + CircleNode *build_node(const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const override; +}; + +} // namespace luci + +#endif // __LUCI_IMPORT_OP_CIRCLE_ZEROS_LIKE_H__ diff --git a/compiler/luci/import/include/luci/Importer.h b/compiler/luci/import/include/luci/Importer.h index 246df9f27..f08ddcda7 100644 --- a/compiler/luci/import/include/luci/Importer.h +++ b/compiler/luci/import/include/luci/Importer.h @@ -51,4 +51,4 @@ private: } // namespace luci -#endif // __MOCO_IMPORTER_H__ +#endif // __LUCI_IMPORTER_H__ diff --git a/compiler/luci/import/src/CircleReader.cpp b/compiler/luci/import/src/CircleReader.cpp index ead0093b8..81e945dd1 100644 --- a/compiler/luci/import/src/CircleReader.cpp +++ b/compiler/luci/import/src/CircleReader.cpp @@ -136,6 +136,19 @@ Padding luci_padding(const circle::Padding padding) return Padding::UNDEFINED; } +MirrorPadMode luci_mirrorpad_mode(const circle::MirrorPadMode mode) +{ + switch (mode) + { + case circle::MirrorPadMode::MirrorPadMode_REFLECT: + return MirrorPadMode::REFLECT; + case circle::MirrorPadMode::MirrorPadMode_SYMMETRIC: + return MirrorPadMode::SYMMETRIC; + } + assert(false); + return MirrorPadMode::UNDEFINED; +} + std::unique_ptr<CircleQuantParam> luci_quantparam(const circle::QuantizationParametersT *quantization) { @@ -159,6 +172,27 @@ luci_quantparam(const circle::QuantizationParametersT *quantization) return nullptr; } +void copy_tensor_attributes(const circle::TensorT &tensor, CircleNode *node) +{ + node->name(tensor_name(tensor)); + node->dtype(luci_datatype(tensor.type)); + + std::vector<int32_t> dims = tensor.shape; // in NHWC + node->rank(dims.size()); + for (uint32_t r = 0; r < dims.size(); ++r) + { + node->dim(r) = loco::Dimension(dims[r]); + } + + const auto *quantization = tensor.quantization.get(); + if (quantization != nullptr) + { + auto quantparam = luci_quantparam(quantization); + if (quantparam) + node->quantparam(std::move(quantparam)); + } +} + circle::BuiltinOperator CircleReader::builtin_code(const circle::OperatorT &op) const { const auto &op_codes = opcodes(); @@ -192,6 +226,9 @@ bool CircleReader::parse(const circle::Model *model) _model.reset(model->UnPack()); + // for direct pointer access + _model_ptr = model; + return true; } @@ -205,6 +242,12 @@ bool CircleReader::select_subgraph(uint32_t sgindex) _current_subgraph = _model->subgraphs[sgindex].get(); + // for direct pointer access + auto subgraphs = _model_ptr->subgraphs(); + const circle::SubGraph *subgraph = (*subgraphs)[sgindex]; + + _tensors_ptr = subgraph->tensors(); + return true; } diff --git a/compiler/luci/import/src/GraphBuilder.cpp b/compiler/luci/import/src/GraphBuilder.cpp index e0ec9ded5..80a9f986a 100644 --- a/compiler/luci/import/src/GraphBuilder.cpp +++ b/compiler/luci/import/src/GraphBuilder.cpp @@ -16,21 +16,39 @@ #include "luci/Import/GraphBuilder.h" +#include <luci/Log.h> + namespace luci { void GraphBuilder::build(const circle::OperatorT &op, GraphBuilderContext *context) const { + LOGGER(l); + assert(context != nullptr); const std::vector<int32_t> &inputs = op.inputs; const std::vector<int32_t> &outputs = op.outputs; const auto &tensors = context->reader()->tensors(); + const auto &opcodes = context->reader()->opcodes(); + auto tensors_ptr = context->reader()->tensors_ptr(); + assert(tensors_ptr != nullptr); std::vector<CircleNode *> input_nodes; for (const int32_t input_tensor_index : inputs) { - input_nodes.push_back(context->nodefinder()->node(input_tensor_index)); + if (input_tensor_index >= 0) + { + auto input = context->nodefinder()->node(input_tensor_index); + if (input == nullptr) + INFO(l) << "[luci] Warning: input node is null " << input_tensor_index << std::endl; + input_nodes.push_back(input); + } + else + { + // If there is no tensor, insert CircleOutputExclude. + input_nodes.push_back(context->graph()->nodes()->create<luci::CircleOutputExclude>()); + } } CircleNode *node = build_node(op, input_nodes, context->graph()); @@ -39,16 +57,15 @@ void GraphBuilder::build(const circle::OperatorT &op, GraphBuilderContext *conte assert(outputs.size() == 1); { const circle::TensorT &output_tensor = *tensors[outputs[0]]; + copy_tensor_attributes(output_tensor, node); + // mark shape_status + if (tensors_ptr->Get(outputs[0])->shape() == nullptr) + node->shape_status(ShapeStatus::NOSHAPE); + else + node->shape_status(ShapeStatus::VALID); - node->name(tensor_name(output_tensor)); - - auto quantization = tensor_quantization(output_tensor); - if (quantization) - { - auto quantparam = luci_quantparam(quantization); - if (quantparam) - node->quantparam(std::move(quantparam)); - } + // mark operator version + node->op_version(opcodes[op.opcode_index].get()->version); } // Register node's only output. diff --git a/compiler/luci/import/src/GraphBuilderContext.cpp b/compiler/luci/import/src/GraphBuilderContext.cpp index a5162ce83..21adfa7e2 100644 --- a/compiler/luci/import/src/GraphBuilderContext.cpp +++ b/compiler/luci/import/src/GraphBuilderContext.cpp @@ -25,10 +25,12 @@ namespace luci void IndexNodeFinder::enroll(TensorIndex idx, CircleNode *node) { - if (_table.find(idx) != _table.end()) + auto iter = _table.find(idx); + if (iter != _table.end()) { LOGGER(l); - INFO(l) << "[luci] NodeFinder SKIP (" << idx << ") " << node << std::endl; + INFO(l) << "[luci] NodeFinder SKIP (" << idx << ") " << node << ":" << node->name() + << " existing: " << iter->second << ":" << iter->second->name() << std::endl; return; } @@ -39,9 +41,22 @@ CircleNode *IndexNodeFinder::node(TensorIndex idx) const { MapIndexNode_t::const_iterator iter = _table.find(idx); - assert(iter != _table.end() && iter->second != nullptr); + // dangle output node may exist that are not enrolled + return (iter != _table.end()) ? iter->second : nullptr; +} - return iter->second; +void IndexTensorOutputs::enroll(TensorIndex idx) +{ + auto iter = _set.find(idx); + if (iter != _set.end()) + { + LOGGER(l); + INFO(l) << "[luci] TensorOutputs SKIP (" << idx << ") existing" << std::endl; + return; + } + _set.insert(idx); } +bool IndexTensorOutputs::find(TensorIndex idx) { return (_set.find(idx) != _set.end()); } + } // namespace luci diff --git a/compiler/luci/import/src/GraphBuilderRegistry.cpp b/compiler/luci/import/src/GraphBuilderRegistry.cpp index 929b71a7d..d29557f74 100644 --- a/compiler/luci/import/src/GraphBuilderRegistry.cpp +++ b/compiler/luci/import/src/GraphBuilderRegistry.cpp @@ -27,137 +27,140 @@ GraphBuilderRegistry::GraphBuilderRegistry() { #define CIRCLE_NODE(OPCODE, CLASS) add(circle::BuiltinOperator_##OPCODE, std::make_unique<CLASS>()); - CIRCLE_NODE(ABS, CircleAbsGraphBuilder); // 101 - CIRCLE_NODE(ADD, CircleAddGraphBuilder); // 0 - CIRCLE_NODE(ARG_MAX, CircleArgMaxGraphBuilder); // 56 - CIRCLE_NODE(AVERAGE_POOL_2D, CircleAveragePool2DGraphBuilder); // 1 - CIRCLE_NODE(BATCH_TO_SPACE_ND, CircleBatchToSpaceNDGraphBuilder); // 37 - CIRCLE_NODE(CONCATENATION, CircleConcatenationGraphBuilder); // 2 - CIRCLE_NODE(CONV_2D, CircleConv2DGraphBuilder); // 3 - CIRCLE_NODE(COS, CircleCosGraphBuilder); // 108 - CIRCLE_NODE(DEPTHWISE_CONV_2D, CircleDepthwiseConv2DGraphBuilder); // 4 - CIRCLE_NODE(DIV, CircleDivGraphBuilder); // 42 - CIRCLE_NODE(EQUAL, CircleEqualGraphBuilder); // 71 - CIRCLE_NODE(EXP, CircleExpGraphBuilder); // 47 - CIRCLE_NODE(FULLY_CONNECTED, CircleFullyConnectedGraphBuilder); // 9 - CIRCLE_NODE(LOGICAL_NOT, CircleLogicalNotGraphBuilder); // 87 - CIRCLE_NODE(LOGICAL_OR, CircleLogicalOrGraphBuilder); // 84 - CIRCLE_NODE(MAX_POOL_2D, CircleMaxPool2DGraphBuilder); // 17 - CIRCLE_NODE(MEAN, CircleMeanGraphBuilder); // 40 - CIRCLE_NODE(MUL, CircleMulGraphBuilder); // 18 - CIRCLE_NODE(PACK, CirclePackGraphBuilder); // 83 - CIRCLE_NODE(PAD, CirclePadGraphBuilder); // 34 - CIRCLE_NODE(RELU, CircleReluGraphBuilder); // 19 - CIRCLE_NODE(RESHAPE, CircleReshapeGraphBuilder); // 22 - CIRCLE_NODE(RSQRT, CircleRsqrtGraphBuilder); // 76 - CIRCLE_NODE(SOFTMAX, CircleSoftmaxGraphBuilder); // 25 - CIRCLE_NODE(SUB, CircleSubGraphBuilder); // 41 - CIRCLE_NODE(TRANSPOSE, CircleTransposeGraphBuilder); // 39 + CIRCLE_NODE(ABS, CircleAbsGraphBuilder); // 101 + CIRCLE_NODE(ADD, CircleAddGraphBuilder); // 0 + CIRCLE_NODE(ADD_N, CircleAddNGraphBuilder); // 106 + CIRCLE_NODE(ARG_MAX, CircleArgMaxGraphBuilder); // 56 + CIRCLE_NODE(ARG_MIN, CircleArgMinGraphBuilder); // 79 + CIRCLE_NODE(AVERAGE_POOL_2D, CircleAveragePool2DGraphBuilder); // 1 + CIRCLE_NODE(BATCH_MATMUL, CircleBatchMatMulGraphBuilder); // 126 + CIRCLE_NODE(BATCH_TO_SPACE_ND, CircleBatchToSpaceNDGraphBuilder); // 37 + CIRCLE_NODE(BCQ_FULLY_CONNECTED, CircleBCQFullyConnectedGraphBuilder); // 253 + CIRCLE_NODE(BCQ_GATHER, CircleBCQGatherGraphBuilder); // 252 + CIRCLE_NODE(CAST, CircleCastGraphBuilder); // 53 + CIRCLE_NODE(CEIL, CircleCeilGraphBuilder); // 104 + CIRCLE_NODE(CUSTOM, CircleCustomGraphBuilder); // 32 + CIRCLE_NODE(CONCATENATION, CircleConcatenationGraphBuilder); // 2 + CIRCLE_NODE(CONV_2D, CircleConv2DGraphBuilder); // 3 + CIRCLE_NODE(COS, CircleCosGraphBuilder); // 108 + CIRCLE_NODE(DEPTH_TO_SPACE, CircleDepthToSpaceGraphBuilder); // 5 + CIRCLE_NODE(DEPTHWISE_CONV_2D, CircleDepthwiseConv2DGraphBuilder); // 4 + CIRCLE_NODE(DIV, CircleDivGraphBuilder); // 42 + CIRCLE_NODE(ELU, CircleEluGraphBuilder); // 111 + CIRCLE_NODE(EQUAL, CircleEqualGraphBuilder); // 71 + CIRCLE_NODE(EXP, CircleExpGraphBuilder); // 47 + CIRCLE_NODE(EXPAND_DIMS, CircleExpandDimsGraphBuilder); // 70 + CIRCLE_NODE(FILL, CircleFillGraphBuilder); // 94 + CIRCLE_NODE(FLOOR, CircleFloorGraphBuilder); // 8 + CIRCLE_NODE(FLOOR_DIV, CircleFloorDivGraphBuilder); // 90 + CIRCLE_NODE(FLOOR_MOD, CircleFloorModGraphBuilder); // 95 + CIRCLE_NODE(FULLY_CONNECTED, CircleFullyConnectedGraphBuilder); // 9 + CIRCLE_NODE(GATHER, CircleGatherGraphBuilder); // 36 + CIRCLE_NODE(GATHER_ND, CircleGatherNdGraphBuilder); // 107 + CIRCLE_NODE(GREATER, CircleGreaterGraphBuilder); // 61 + CIRCLE_NODE(GREATER_EQUAL, CircleGreaterEqualGraphBuilder); // 62 + CIRCLE_NODE(IF, CircleIfGraphBuilder); // 118 + CIRCLE_NODE(INSTANCE_NORM, CircleInstanceNormGraphBuilder); // 254 + CIRCLE_NODE(L2_NORMALIZATION, CircleL2NormalizeGraphBuilder); // 11 + CIRCLE_NODE(L2_POOL_2D, CircleL2Pool2DGraphBuilder); // 12 + CIRCLE_NODE(LEAKY_RELU, CircleLeakyReluGraphBuilder); // 98, + CIRCLE_NODE(LESS, CircleLessGraphBuilder); // 58 + CIRCLE_NODE(LESS_EQUAL, CircleLessEqualGraphBuilder); // 63 + CIRCLE_NODE(LOCAL_RESPONSE_NORMALIZATION, CircleLocalResponseNormalizationGraphBuilder); // 13 + CIRCLE_NODE(LOG, CircleLogGraphBuilder); // 73 + CIRCLE_NODE(LOGICAL_AND, CircleLogicalAndGraphBuilder); // 86 + CIRCLE_NODE(LOGICAL_NOT, CircleLogicalNotGraphBuilder); // 87 + CIRCLE_NODE(LOGICAL_OR, CircleLogicalOrGraphBuilder); // 84 + CIRCLE_NODE(LOGISTIC, CircleLogisticGraphBuilder); // 14 + CIRCLE_NODE(LOG_SOFTMAX, CircleLogSoftmaxGraphBuilder); // 50 + CIRCLE_NODE(MATRIX_DIAG, CircleMatrixDiagGraphBuilder); // 113 + CIRCLE_NODE(MATRIX_SET_DIAG, CircleMatrixSetDiagGraphBuilder); // 115 + CIRCLE_NODE(MAXIMUM, CircleMaximumGraphBuilder); // 55 + CIRCLE_NODE(MAX_POOL_2D, CircleMaxPool2DGraphBuilder); // 17 + CIRCLE_NODE(MEAN, CircleMeanGraphBuilder); // 40 + CIRCLE_NODE(MINIMUM, CircleMinimumGraphBuilder); // 57 + CIRCLE_NODE(MIRROR_PAD, CircleMirrorPadGraphBuilder); // 100 + CIRCLE_NODE(MUL, CircleMulGraphBuilder); // 18 + CIRCLE_NODE(NEG, CircleNegGraphBuilder); // 59 + CIRCLE_NODE(NOT_EQUAL, CircleNotEqualGraphBuilder); // 72 + CIRCLE_NODE(ONE_HOT, CircleOneHotGraphBuilder); // 85 + CIRCLE_NODE(PACK, CirclePackGraphBuilder); // 83 + CIRCLE_NODE(PAD, CirclePadGraphBuilder); // 34 + CIRCLE_NODE(POW, CirclePowGraphBuilder); // 78 + CIRCLE_NODE(PRELU, CirclePReluGraphBuilder); // 54, + CIRCLE_NODE(RANGE, CircleRangeGraphBuilder); // 96 + CIRCLE_NODE(RANK, CircleRankGraphBuilder); // 110 + CIRCLE_NODE(REDUCE_ANY, CircleReduceAnyGraphBuilder); // 91 + CIRCLE_NODE(REDUCE_MAX, CircleReduceMaxGraphBuilder); // 82 + CIRCLE_NODE(REDUCE_MIN, CircleReduceMinGraphBuilder); // 89 + CIRCLE_NODE(REDUCE_PROD, CircleReduceProdGraphBuilder); // 81 + CIRCLE_NODE(RELU, CircleReluGraphBuilder); // 19 + CIRCLE_NODE(RELU6, CircleRelu6GraphBuilder); // 21 + CIRCLE_NODE(RELU_N1_TO_1, CircleReluN1To1GraphBuilder); // 20 + CIRCLE_NODE(RESHAPE, CircleReshapeGraphBuilder); // 22 + CIRCLE_NODE(RESIZE_BILINEAR, CircleResizeBilinearGraphBuilder); // 23 + CIRCLE_NODE(RESIZE_NEAREST_NEIGHBOR, CircleResizeNearestNeighborGraphBuilder); // 97 + CIRCLE_NODE(REVERSE_SEQUENCE, CircleReverseSequenceGraphBuilder); // 112 + CIRCLE_NODE(REVERSE_V2, CircleReverseV2GraphBuilder); // 105 + CIRCLE_NODE(ROUND, CircleRoundGraphBuilder); // 116 + CIRCLE_NODE(RSQRT, CircleRsqrtGraphBuilder); // 76 + CIRCLE_NODE(SCATTER_ND, CircleScatterNdGraphBuilder); // 122 + CIRCLE_NODE(SEGMENT_SUM, CircleSegmentSumGraphBuilder); // 125 + CIRCLE_NODE(SELECT, CircleSelectGraphBuilder); // 64 + CIRCLE_NODE(SELECT_V2, CircleSelectV2GraphBuilder); // 123 + CIRCLE_NODE(SHAPE, CircleShapeGraphBuilder); // 77 + CIRCLE_NODE(SIN, CircleSinGraphBuilder); // 66 + CIRCLE_NODE(SLICE, CircleSliceGraphBuilder); // 65 + CIRCLE_NODE(SOFTMAX, CircleSoftmaxGraphBuilder); // 25 + CIRCLE_NODE(SPACE_TO_BATCH_ND, CircleSpaceToBatchNDGraphBuilder); // 38 + CIRCLE_NODE(SPACE_TO_DEPTH, CircleSpaceToDepthGraphBuilder); // 26 + CIRCLE_NODE(SPARSE_TO_DENSE, CircleSparseToDenseGraphBuilder); // 68 + CIRCLE_NODE(SPLIT, CircleSplitGraphBuilder); // 49 + CIRCLE_NODE(SPLIT_V, CircleSplitVGraphBuilder); // 102 + CIRCLE_NODE(SQRT, CircleSqrtGraphBuilder); // 75 + CIRCLE_NODE(SQUARE, CircleSquareGraphBuilder); // 92 + CIRCLE_NODE(SQUARED_DIFFERENCE, CircleSquaredDifferenceGraphBuilder); // 99 + CIRCLE_NODE(SQUEEZE, CircleSqueezeGraphBuilder); // 43 + CIRCLE_NODE(STRIDED_SLICE, CircleStridedSliceGraphBuilder); // 45 + CIRCLE_NODE(SUB, CircleSubGraphBuilder); // 41 + CIRCLE_NODE(SUM, CircleSumGraphBuilder); // 74 + CIRCLE_NODE(TANH, CircleTanhGraphBuilder); // 28 + CIRCLE_NODE(TILE, CircleTileGraphBuilder); // 69 + CIRCLE_NODE(TOPK_V2, CircleTopKV2GraphBuilder); // 48 + CIRCLE_NODE(TRANSPOSE, CircleTransposeGraphBuilder); // 39 + CIRCLE_NODE(TRANSPOSE_CONV, CircleTransposeConvGraphBuilder); // 67 + CIRCLE_NODE(UNPACK, CircleUnpackGraphBuilder); // 88 + CIRCLE_NODE(WHERE, CircleWhereGraphBuilder); // 109 + CIRCLE_NODE(WHILE, CircleWhileGraphBuilder); // 119 + CIRCLE_NODE(ZEROS_LIKE, CircleZerosLikeGraphBuilder); // 93 #undef CIRCLE_NODE // BuiltinOperator_DEQUANTIZE = 6, // BuiltinOperator_EMBEDDING_LOOKUP = 7, - // BuiltinOperator_FLOOR = 8, // BuiltinOperator_HASHTABLE_LOOKUP = 10, - // BuiltinOperator_L2_NORMALIZATION = 11, - // BuiltinOperator_L2_POOL_2D = 12, - // BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION = 13, - // BuiltinOperator_LOGISTIC = 14, // BuiltinOperator_LSH_PROJECTION = 15, // BuiltinOperator_LSTM = 16, - // BuiltinOperator_RELU_N1_TO_1 = 20, - // BuiltinOperator_RELU6 = 21, - // BuiltinOperator_RESIZE_BILINEAR = 23, // BuiltinOperator_RNN = 24, - // BuiltinOperator_SPACE_TO_DEPTH = 26, // BuiltinOperator_SVDF = 27, - // BuiltinOperator_TANH = 28, // BuiltinOperator_CONCAT_EMBEDDINGS = 29, // BuiltinOperator_SKIP_GRAM = 30, // BuiltinOperator_CALL = 31, - // BuiltinOperator_CUSTOM = 32, // BuiltinOperator_EMBEDDING_LOOKUP_SPARSE = 33, // BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_RNN = 35, - // BuiltinOperator_GATHER = 36, - // BuiltinOperator_SPACE_TO_BATCH_ND = 38, - // BuiltinOperator_SQUEEZE = 43, // BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM = 44, - // BuiltinOperator_STRIDED_SLICE = 45, // BuiltinOperator_BIDIRECTIONAL_SEQUENCE_RNN = 46, - // BuiltinOperator_TOPK_V2 = 48, - // BuiltinOperator_SPLIT = 49, - // BuiltinOperator_LOG_SOFTMAX = 50, // BuiltinOperator_DELEGATE = 51, // BuiltinOperator_BIDIRECTIONAL_SEQUENCE_LSTM = 52, - // BuiltinOperator_CAST = 53, - // BuiltinOperator_PRELU = 54, - // BuiltinOperator_MAXIMUM = 55, // BuiltinOperator_ARG_MAX = 56, - // BuiltinOperator_MINIMUM = 57, - // BuiltinOperator_LESS = 58, - // BuiltinOperator_NEG = 59, // BuiltinOperator_PADV2 = 60, - // BuiltinOperator_GREATER = 61, - // BuiltinOperator_GREATER_EQUAL = 62, - // BuiltinOperator_LESS_EQUAL = 63, - // BuiltinOperator_SELECT = 64, - // BuiltinOperator_SLICE = 65, - // BuiltinOperator_SIN = 66, - // BuiltinOperator_TRANSPOSE_CONV = 67, - // BuiltinOperator_SPARSE_TO_DENSE = 68, - // BuiltinOperator_TILE = 69, - // BuiltinOperator_EXPAND_DIMS = 70, - // BuiltinOperator_NOT_EQUAL = 72, - // BuiltinOperator_LOG = 73, - // BuiltinOperator_SUM = 74, - // BuiltinOperator_SQRT = 75, - // BuiltinOperator_SHAPE = 77, - // BuiltinOperator_POW = 78, - // BuiltinOperator_ARG_MIN = 79, // BuiltinOperator_FAKE_QUANT = 80, - // BuiltinOperator_REDUCE_PROD = 81, - // BuiltinOperator_REDUCE_MAX = 82, - // BuiltinOperator_ONE_HOT = 85, - // BuiltinOperator_LOGICAL_AND = 86, - // BuiltinOperator_UNPACK = 88, - // BuiltinOperator_REDUCE_MIN = 89, - // BuiltinOperator_FLOOR_DIV = 90, - // BuiltinOperator_REDUCE_ANY = 91, - // BuiltinOperator_SQUARE = 92, - // BuiltinOperator_ZEROS_LIKE = 93, - // BuiltinOperator_FILL = 94, - // BuiltinOperator_FLOOR_MOD = 95, - // BuiltinOperator_RANGE = 96, - // BuiltinOperator_RESIZE_NEAREST_NEIGHBOR = 97, - // BuiltinOperator_LEAKY_RELU = 98, - // BuiltinOperator_SQUARED_DIFFERENCE = 99, - // BuiltinOperator_MIRROR_PAD = 100, - // BuiltinOperator_SPLIT_V = 102, // BuiltinOperator_UNIQUE = 103, - // BuiltinOperator_CEIL = 104, - // BuiltinOperator_REVERSE_V2 = 105, - // BuiltinOperator_ADD_N = 106, - // BuiltinOperator_GATHER_ND = 107, - // BuiltinOperator_WHERE = 109, - // BuiltinOperator_RANK = 110, - // BuiltinOperator_ELU = 111, - // BuiltinOperator_REVERSE_SEQUENCE = 112, - // BuiltinOperator_MATRIX_DIAG = 113, // BuiltinOperator_QUANTIZE = 114, - // BuiltinOperator_MATRIX_SET_DIAG = 115, - // BuiltinOperator_ROUND = 116, // BuiltinOperator_HARD_SWISH = 117, - // BuiltinOperator_IF = 118, - // BuiltinOperator_WHILE = 119, // BuiltinOperator_NON_MAX_SUPPRESSION_V4 = 120, // BuiltinOperator_NON_MAX_SUPPRESSION_V5 = 121, - // BuiltinOperator_SCATTER_ND = 122, - // BuiltinOperator_SELECT_V2 = 123, // BuiltinOperator_DENSIFY = 124, - // BuiltinOperator_SEGMENT_SUM = 125, - // BuiltinOperator_BATCH_MATMUL = 126, - // BuiltinOperator_INSTANCE_NORM = 254, } } // namespace luci diff --git a/compiler/luci/import/src/Importer.cpp b/compiler/luci/import/src/Importer.cpp index 964c47633..ab89f3587 100644 --- a/compiler/luci/import/src/Importer.cpp +++ b/compiler/luci/import/src/Importer.cpp @@ -15,6 +15,7 @@ */ #include "luci/Importer.h" +#include "PostImport.h" #include "luci/Import/GraphBuilder.h" #include "luci/Import/GraphBuilderContext.h" @@ -27,6 +28,7 @@ #include <luci/Log.h> #include <luci/LogHelper.h> +#include <oops/InternalExn.h> #include <oops/UserExn.h> #include <memory> @@ -40,11 +42,28 @@ void convert_graph(const luci::GraphBuilderSource &source, luci::CircleReader &r LOGGER(l); auto nodefinder = std::make_unique<luci::IndexNodeFinder>(); + auto tensoroutputs = std::make_unique<luci::IndexTensorOutputs>(); - luci::GraphBuilderContext gb_context(graph, &reader, nodefinder.get()); + luci::GraphBuilderContext gb_context(graph, &reader, nodefinder.get(), tensoroutputs.get()); const auto &operators = reader.operators(); const auto &tensors = reader.tensors(); + auto tensors_ptr = reader.tensors_ptr(); + assert(tensors_ptr != nullptr); + + // build a cache to identify if a tensor is output of an operator + // if this is set, we should not create a CircleConst for this tensor + for (uint32_t i = 0; i < operators.size(); ++i) + { + const circle::OperatorT &op = *operators[i]; + const auto &outputs = op.outputs; + + for (uint32_t j = 0; j < outputs.size(); ++j) + { + auto tidx = outputs[j]; + tensoroutputs->enroll(tidx); + } + } // graph inputs; there are no input nodes in TFlite but just Tensors // creating virtual input nodes will make possible to connect nodes that uses them @@ -55,51 +74,43 @@ void convert_graph(const luci::GraphBuilderSource &source, luci::CircleReader &r assert(input_node != nullptr); const circle::TensorT &tensor = *tensors[input]; - auto tname = luci::tensor_name(tensor); - input_node->name(tname); - auto quantization = luci::tensor_quantization(tensor); - if (quantization) - { - auto quantparam = luci::luci_quantparam(quantization); - if (quantparam.get()) - input_node->quantparam(std::move(quantparam)); - } + luci::copy_tensor_attributes(tensor, input_node); + if (tensors_ptr->Get(input)->shape() == nullptr) + input_node->shape_status(luci::ShapeStatus::NOSHAPE); + else + input_node->shape_status(luci::ShapeStatus::VALID); INFO(l) << "[luci] NodeFinder INPUT(" << input << ") = " << input_node << std::endl; nodefinder->enroll(input, input_node); - // Shape of Input - const std::vector<int32_t> &input_dims = tensor.shape; // in NHWC - input_node->rank(input_dims.size()); - for (uint32_t r = 0; r < input_dims.size(); ++r) - input_node->dim(r) = loco::Dimension(input_dims[r]); - - // Data type of Input - auto dtype = luci::luci_datatype(tensor.type); - input_node->dtype(dtype); + // input_node is also an output to a tensor + tensoroutputs->enroll(input); // Name auto graph_input = graph->inputs()->create(); - graph_input->name(tname); + graph_input->name(input_node->name()); // Set GraphInputOutputIndex for graph input_node->index(graph_input->index()); // Data type - graph_input->dtype(dtype); + graph_input->dtype(input_node->dtype()); + + // Shape of GraphInput + auto input_shape = std::make_unique<loco::TensorShape>(); + const std::vector<int32_t> &input_dims = tensor.shape; // in NHWC + input_shape->rank(input_dims.size()); + for (uint32_t r = 0; r < input_dims.size(); ++r) + input_shape->dim(r) = loco::Dimension(input_dims[r]); + graph_input->shape(std::move(input_shape)); } // Create CircleConst nodes for constant tensors. - const auto &buffers = reader.buffers(); for (uint32_t i = 0; i < tensors.size(); ++i) { - const circle::TensorT &tensor = *tensors[i]; - const std::vector<uint8_t> &buffer = buffers[tensor.buffer]->data; - if (!buffer.empty()) - { - luci::CircleConst *const_node = luci::create_circleconst(&gb_context, i); + luci::CircleConst *const_node = luci::create_circleconst(&gb_context, i); + if (const_node != nullptr) nodefinder->enroll(i, const_node); - } } // Import the operators. @@ -130,18 +141,38 @@ void convert_graph(const luci::GraphBuilderSource &source, luci::CircleReader &r // graph outputs for (auto output : reader.outputs()) { + const circle::TensorT &tensor = *tensors[output]; + auto output_node = graph->nodes()->create<luci::CircleOutput>(); assert(output_node != nullptr); - output_node->from(nodefinder->node(output)); + auto output_from = nodefinder->node(output); + if (output_from != nullptr) + output_node->from(output_from); + else + { + // NOTE loco::Graph requires all input node(s) to a node should exist. + // Here, CircleOutput needs an input node. + // We add a dummy node to make it happy. + auto output_dummy = graph->nodes()->create<luci::CircleOutputDummy>(); + assert(output_dummy != nullptr); + output_node->from(output_dummy); + + luci::copy_tensor_attributes(tensor, output_dummy); + if (tensors_ptr->Get(output)->shape() == nullptr) + output_dummy->shape_status(luci::ShapeStatus::NOSHAPE); + else + output_dummy->shape_status(luci::ShapeStatus::VALID); + } INFO(l) << "[luci] NodeFinder OUTPUT(" << output << ") = " << output_node << std::endl; // set the graph output name and node object - const circle::TensorT &tensor = *tensors[output]; auto graph_output = graph->outputs()->create(); std::string tname = luci::tensor_name(tensor); graph_output->name("output_" + tname); + luci::copy_tensor_attributes(tensor, output_node); + // Set GraphInputOutputIndex for graph output_node->index(graph_output->index()); @@ -195,8 +226,10 @@ std::unique_ptr<loco::Graph> Importer::import(const circle::Model *model) const if (!reader.parse(model)) return nullptr; - // TODO support multiple subgraph when Circle supports - assert(reader.num_subgraph() == 1); + if (reader.num_subgraph() != 1) + { + INTERNAL_EXN("Use 'importModule()' for multiple subgraphs"); + } if (!reader.select_subgraph(0)) return nullptr; @@ -204,11 +237,14 @@ std::unique_ptr<loco::Graph> Importer::import(const circle::Model *model) const convert_graph(*source_ptr, reader, graph.get()); LOGGER(l); - INFO(l) << fmt(graph.get()); + VERBOSE(l, 3) << "--- graph dump begin -------------------------------------------"; + VERBOSE(l, 3) << "Name: " << graph->name(); + VERBOSE(l, 3) << fmt(graph.get()); + VERBOSE(l, 3) << "--- graph dump end ---------------------------------------------"; assert(loco::valid(graph.get(), std::make_unique<ValidateCollector>())); - return std::move(graph); + return graph; } std::unique_ptr<Module> Importer::importModule(const circle::Model *model) const @@ -240,14 +276,19 @@ std::unique_ptr<Module> Importer::importModule(const circle::Model *model) const convert_graph(*source_ptr, reader, graph.get()); LOGGER(l); - INFO(l) << fmt(graph.get()); + VERBOSE(l, 3) << "--- graph dump begin -------------------------------------------"; + VERBOSE(l, 3) << "Name: " << graph->name(); + VERBOSE(l, 3) << fmt(graph.get()); + VERBOSE(l, 3) << "--- graph dump end ---------------------------------------------"; assert(loco::valid(graph.get(), std::make_unique<ValidateCollector>())); module->add(std::move(graph)); } - return std::move(module); + post_import_graph(module.get(), reader); + + return module; } } // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleAddN.cpp b/compiler/luci/import/src/Nodes/CircleAddN.cpp new file mode 100644 index 000000000..2f1716e62 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleAddN.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleAddN.h" + +#include <luci/IR/Nodes/CircleAdd.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleAddNGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() < 1) + return false; + + if (args.op.outputs.size() != 1) + return false; + + return true; +} + +CircleNode *CircleAddNGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleAddN>(inputs.size()); + for (uint32_t i = 0; i < inputs.size(); ++i) + { + node->inputs(i, inputs[i]); + } + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleArgMin.cpp b/compiler/luci/import/src/Nodes/CircleArgMin.cpp new file mode 100644 index 000000000..4d85bbff0 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleArgMin.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleArgMin.h" + +#include <luci/IR/Nodes/CircleArgMin.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleArgMinGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 2) + return false; + + return true; +} + +CircleNode *CircleArgMinGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleArgMin>(); + node->input(inputs[0]); + node->dimension(inputs[1]); + + const auto *options = op.builtin_options.AsArgMinOptions(); + node->output_type(luci_datatype(options->output_type)); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleBCQFullyConnected.cpp b/compiler/luci/import/src/Nodes/CircleBCQFullyConnected.cpp new file mode 100644 index 000000000..7cc077ed6 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleBCQFullyConnected.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleBCQFullyConnected.h" + +#include <luci/IR/Nodes/CircleBCQFullyConnected.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleBCQFullyConnectedGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 5) + return false; + + return true; +} + +CircleNode *CircleBCQFullyConnectedGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleBCQFullyConnected>(); + + node->input(inputs[0]); + node->weights_scales(inputs[1]); + node->weights_binary(inputs[2]); + node->bias(inputs[3]); + node->weights_clusters(inputs[4]); + + // TODO Find and move to appropriate place for setting optional input + if (auto bias = dynamic_cast<luci::CircleOutputExclude *>(node->bias())) + { + // bias is not used for type inference, but node itself should have a type + bias->dtype(loco::DataType::FLOAT32); + + // bias is not used for shape inference + } + + const auto *options = op.builtin_options.AsBCQFullyConnectedOptions(); + node->weights_hidden_size(options->weights_hidden_size); + node->fusedActivationFunction(luci_actfunc(options->fused_activation_function)); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleBCQGather.cpp b/compiler/luci/import/src/Nodes/CircleBCQGather.cpp new file mode 100644 index 000000000..c6d2ab559 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleBCQGather.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleBCQGather.h" + +#include <luci/IR/Nodes/CircleBCQGather.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleBCQGatherGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 4) + return false; + + return true; +} + +CircleNode *CircleBCQGatherGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleBCQGather>(); + + node->input_scales(inputs[0]); + node->input_binary(inputs[1]); + node->indices(inputs[2]); + node->input_clusters(inputs[3]); + + const auto *options = op.builtin_options.AsBCQGatherOptions(); + node->input_hidden_size(options->input_hidden_size); + node->axis(options->axis); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleBatchMatMul.cpp b/compiler/luci/import/src/Nodes/CircleBatchMatMul.cpp new file mode 100644 index 000000000..6026b2a72 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleBatchMatMul.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleBatchMatMul.h" + +#include <luci/IR/Nodes/CircleBatchMatMul.h> + +namespace luci +{ + +bool CircleBatchMatMulGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 2) + return false; + + return true; +} + +CircleNode *CircleBatchMatMulGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleBatchMatMul>(); + node->x(inputs[0]); + node->y(inputs[1]); + + const auto *options = op.builtin_options.AsBatchMatMulOptions(); + node->adj_x(options->adjoint_lhs); + node->adj_y(options->adjoint_rhs); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleCast.cpp b/compiler/luci/import/src/Nodes/CircleCast.cpp new file mode 100644 index 000000000..a4d09b505 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleCast.cpp @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleCast.h" + +#include <luci/IR/Nodes/CircleCast.h> + +#include <luci/UserSettings.h> +#include <luci/Log.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleCastGraphBuilder::validate(const ValidateArgs &args) const +{ + LOGGER(l); + + auto settings = luci::UserSettings::settings(); + + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + if (inputs.size() != 1) + return false; + if (outputs.size() != 1) + return false; + + // NOTE real models do have type mismatch + const auto *options = args.op.builtin_options.AsCastOptions(); + if (options != nullptr) + { + const auto &tensors = args.reader.tensors(); + const circle::TensorT &output_tensor = *tensors[outputs[0]]; + auto name = tensor_name(output_tensor); + + const auto &tensor_in = tensors.at(inputs[0]); + if (tensor_in->type != options->in_data_type) + { + if (settings->get(luci::UserSettings::Key::DisableValidation)) + { + WARN(l) << "Warning: import Cast(" << name << ") dtype mismatch"; + } + else + return false; + } + const auto &tensor_out = tensors.at(outputs[0]); + if (tensor_out->type != options->out_data_type) + { + if (settings->get(luci::UserSettings::Key::DisableValidation)) + { + WARN(l) << "Warning: import Cast(" << name << ") dtype mismatch"; + } + else + return false; + } + } + + return true; +} + +CircleNode *CircleCastGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleCast>(); + node->x(inputs[0]); + + const auto *options = op.builtin_options.AsCastOptions(); + if (options != nullptr) + { + node->in_data_type(luci_datatype(options->in_data_type)); + node->out_data_type(luci_datatype(options->out_data_type)); + } + else + { + node->in_data_type(inputs[0]->dtype()); + node->out_data_type(loco::DataType::Unknown); + // type inference should use node->dtype() for Unknown + // export should use BuiltinOptions_NONE for Unknown + } + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleCeil.cpp b/compiler/luci/import/src/Nodes/CircleCeil.cpp new file mode 100644 index 000000000..d3d6cd945 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleCeil.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleCeil.h" + +#include <luci/IR/Nodes/CircleCeil.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleCeilGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + if (inputs.size() != 1) + return false; + if (outputs.size() != 1) + return false; + + // TODO dtype check + + return true; +} + +CircleNode *CircleCeilGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleCeil>(); + node->x(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleConst.cpp b/compiler/luci/import/src/Nodes/CircleConst.cpp index 1d798983b..7131dc115 100644 --- a/compiler/luci/import/src/Nodes/CircleConst.cpp +++ b/compiler/luci/import/src/Nodes/CircleConst.cpp @@ -24,6 +24,24 @@ #include <cassert> +namespace +{ + +std::ostream &operator<<(std::ostream &os, const std::vector<int32_t> &vect) +{ + uint32_t seq = 0; + for (auto &v : vect) + { + if (seq) + os << ", "; + os << v; + seq++; + } + return os; +} + +} // namespace + namespace luci { @@ -53,55 +71,73 @@ CircleConst *create_circleconst(GraphBuilderContext *context, int32_t tensor_ind auto graph = context->graph(); auto reader = context->reader(); const auto &tensors = reader->tensors(); - - // (1) create CircleConst - auto const_node = graph->nodes()->create<CircleConst>(); const circle::TensorT &const_tensor = *tensors[tensor_index]; - const_node->name(tensor_name(const_tensor)); - auto quantization = luci::tensor_quantization(const_tensor); - if (quantization) + + const std::vector<uint8_t> &buffer = reader->buffers()[const_tensor.buffer]->data; + std::vector<int32_t> const_dims = const_tensor.shape; // in NHWC + if (const_dims.size() == 0 && buffer.empty()) { - auto quantparam = luci::luci_quantparam(quantization); - if (quantparam.get()) - const_node->quantparam(std::move(quantparam)); + // unknown shape tensor + return nullptr; } - INFO(l) << "[luci] NodeFinder const_node(" << tensor_index << ") -> " << const_node << std::endl; - - // (2) set data_type to CircleConst - const_node->dtype(luci_datatype(const_tensor.type)); + // if tensor_index is used as output to some other operator, this is not a constant + auto tensoroutputs = context->tensoroutputs(); + if (tensoroutputs->find(tensor_index)) + { + // other operator output tensor + return nullptr; + } - // (3) set shape to CicleConst - std::vector<int32_t> const_dims = const_tensor.shape; // in NHWC - const_node->rank(const_dims.size()); uint32_t num_elements = 1; for (uint32_t r = 0; r < const_dims.size(); ++r) { - const_node->dim(r) = loco::Dimension(const_dims[r]); num_elements = num_elements * const_dims[r]; } - // (4) constant values from circle buffer - const std::vector<uint8_t> &buffer = reader->buffers()[const_tensor.buffer]->data; - if (buffer.empty()) - throw oops::UserExn("Empty buffer"); - - switch (luci_datatype(const_tensor.type)) + if (buffer.empty() && num_elements > 0) { - case loco::DataType::FLOAT32: - copy_data<loco::DataType::FLOAT32>(buffer, num_elements, const_node); - break; - - case loco::DataType::U8: - copy_data<loco::DataType::U8>(buffer, num_elements, const_node); - break; - - case loco::DataType::S32: - copy_data<loco::DataType::S32>(buffer, num_elements, const_node); - break; + // normal empty tensor + return nullptr; + } - default: - throw oops::UserExn("Unsupported tensor type", circle::EnumNameTensorType(const_tensor.type)); + auto const_node = graph->nodes()->create<CircleConst>(); + copy_tensor_attributes(const_tensor, const_node); + const_node->shape_status(luci::ShapeStatus::VALID); + INFO(l) << "[luci] NodeFinder const_node(" << tensor_index << ") -> " << const_node << " " + << const_dims << std::endl; + if (num_elements > 0) + { + switch (luci_datatype(const_tensor.type)) + { + case loco::DataType::FLOAT32: + copy_data<loco::DataType::FLOAT32>(buffer, num_elements, const_node); + break; + + case loco::DataType::U8: + copy_data<loco::DataType::U8>(buffer, num_elements, const_node); + break; + + case loco::DataType::S16: + copy_data<loco::DataType::S16>(buffer, num_elements, const_node); + break; + + case loco::DataType::S32: + copy_data<loco::DataType::S32>(buffer, num_elements, const_node); + break; + + case loco::DataType::S64: + copy_data<loco::DataType::S64>(buffer, num_elements, const_node); + break; + + case loco::DataType::BOOL: + copy_data<loco::DataType::BOOL>(buffer, num_elements, const_node); + break; + + default: + throw oops::UserExn("Unsupported tensor type", + circle::EnumNameTensorType(const_tensor.type)); + } } return const_node; diff --git a/compiler/luci/import/src/Nodes/CircleConv2D.cpp b/compiler/luci/import/src/Nodes/CircleConv2D.cpp index ec9dce0d2..42c5c265a 100644 --- a/compiler/luci/import/src/Nodes/CircleConv2D.cpp +++ b/compiler/luci/import/src/Nodes/CircleConv2D.cpp @@ -50,7 +50,8 @@ CircleNode *CircleConv2DGraphBuilder::build_node(const circle::OperatorT &op, node->stride()->w(options->stride_w); node->stride()->h(options->stride_h); node->fusedActivationFunction(luci_actfunc(options->fused_activation_function)); - // FIXME Check dilation_w_factor, dilation_h_factor. + node->dilation()->w(options->dilation_w_factor); + node->dilation()->h(options->dilation_h_factor); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleCustom.cpp b/compiler/luci/import/src/Nodes/CircleCustom.cpp new file mode 100644 index 000000000..d541ee87b --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleCustom.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleCustom.h" + +#include <loco.h> + +namespace luci +{ + +bool CircleCustomGraphBuilder::validate(const ValidateArgs &) const +{ + // DO NOTHING + return true; +} + +void CircleCustomGraphBuilder::build(const circle::OperatorT &op, + GraphBuilderContext *context) const +{ + assert(context != nullptr); + + auto graph = context->graph(); + + const std::vector<int32_t> &inputs = op.inputs; + const std::vector<int32_t> &outputs = op.outputs; + const auto &tensors = context->reader()->tensors(); + auto tensors_ptr = context->reader()->tensors_ptr(); + assert(tensors_ptr != nullptr); + + // Create CircleCustom + const auto &opcodes = context->reader()->opcodes(); + const uint32_t opcode_index = op.opcode_index; + const circle::OperatorCodeT &opcode = *opcodes[opcode_index]; + + auto *node = graph->nodes()->create<CircleCustom>(inputs.size()); + uint32_t input_idx = 0; + for (const int32_t input_tensor_index : inputs) + { + node->inputs(input_idx++, context->nodefinder()->node(input_tensor_index)); + } + node->custom_options(std::vector<uint8_t>{op.custom_options.begin(), op.custom_options.end()}); + node->custom_code(opcode.custom_code); + // Operator version of custom is always 1, so do nothing + + uint32_t output_count = outputs.size(); + + assert(output_count > 0); + { + // Let's use attributes from output 0 for this node + const circle::TensorT &output_tensor = *tensors[outputs[0]]; + node->name(tensor_name(output_tensor)); + node->dtype(luci_datatype(output_tensor.type)); + } + + // Create virtual outputs of Custom + for (uint32_t n = 0; n < output_count; ++n) + { + const circle::TensorT &output_tensor = *tensors[outputs[n]]; + + auto *nodeout = graph->nodes()->create<CircleCustomOut>(); + copy_tensor_attributes(output_tensor, nodeout); + // mark shape_status + if (tensors_ptr->Get(outputs[n])->shape() == nullptr) + nodeout->shape_status(ShapeStatus::NOSHAPE); + else + nodeout->shape_status(ShapeStatus::VALID); + + nodeout->input(node); + nodeout->index(n); + + context->nodefinder()->enroll(outputs[n], nodeout); + } +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleDepthToSpace.cpp b/compiler/luci/import/src/Nodes/CircleDepthToSpace.cpp new file mode 100644 index 000000000..827b63468 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleDepthToSpace.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleDepthToSpace.h" + +#include <luci/IR/Nodes/CircleDepthToSpace.h> + +#include <loco.h> + +#include <cassert> + +namespace luci +{ + +bool CircleDepthToSpaceGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + const auto *options = args.op.builtin_options.AsDepthToSpaceOptions(); + + if (inputs.size() != 1) + return false; + + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + + if (tensors[outputs[0]]->type != tensors[inputs[0]]->type) + { + return false; + } + + if (options->block_size < 2) + return false; + + return true; +} + +CircleNode *CircleDepthToSpaceGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleDepthToSpace>(); + node->input(inputs[0]); + + const auto *options = op.builtin_options.AsDepthToSpaceOptions(); + node->block_size(options->block_size); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleDepthwiseConv2D.cpp b/compiler/luci/import/src/Nodes/CircleDepthwiseConv2D.cpp index c6d3b1f1e..2b13f9ebb 100644 --- a/compiler/luci/import/src/Nodes/CircleDepthwiseConv2D.cpp +++ b/compiler/luci/import/src/Nodes/CircleDepthwiseConv2D.cpp @@ -52,7 +52,8 @@ CircleNode *CircleDepthwiseConv2DGraphBuilder::build_node(const circle::Operator node->stride()->h(options->stride_h); node->depthMultiplier(options->depth_multiplier); node->fusedActivationFunction(luci_actfunc(options->fused_activation_function)); - // FIXME Check dilation_w_factor, dilation_h_factor. + node->dilation()->w(options->dilation_w_factor); + node->dilation()->h(options->dilation_h_factor); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleElu.cpp b/compiler/luci/import/src/Nodes/CircleElu.cpp new file mode 100644 index 000000000..37a290cb1 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleElu.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleElu.h" + +#include <luci/IR/Nodes/CircleElu.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleEluGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 1) + return false; + + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + + switch (tensor->type) + { + case circle::TensorType_FLOAT32: + break; + default: + return false; + } + + if (tensors[outputs[0]]->type != tensor->type) + return false; + + return true; +} + +CircleNode *CircleEluGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleElu>(); + node->features(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleExp.cpp b/compiler/luci/import/src/Nodes/CircleExp.cpp index 44fc93d09..a32851458 100644 --- a/compiler/luci/import/src/Nodes/CircleExp.cpp +++ b/compiler/luci/import/src/Nodes/CircleExp.cpp @@ -16,7 +16,7 @@ #include "luci/Import/Nodes/CircleExp.h" -#include <luci/IR/Nodes/CircleAbs.h> +#include <luci/IR/Nodes/CircleExp.h> #include <loco.h> @@ -50,7 +50,7 @@ CircleNode *CircleExpGraphBuilder::build_node(const circle::OperatorT &, const std::vector<CircleNode *> &inputs, loco::Graph *graph) const { - auto *node = graph->nodes()->create<CircleAbs>(); + auto *node = graph->nodes()->create<CircleExp>(); node->x(inputs[0]); return node; diff --git a/compiler/luci/import/src/Nodes/CircleExpandDims.cpp b/compiler/luci/import/src/Nodes/CircleExpandDims.cpp new file mode 100644 index 000000000..1cef67a83 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleExpandDims.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleExpandDims.h" + +#include <luci/IR/Nodes/CircleExpandDims.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleExpandDimsGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + + if (inputs.size() != 2) + { + return false; + } + + const auto &tensors = args.reader.tensors(); + + return tensors[inputs[1]]->type == circle::TensorType_INT32; +} + +CircleNode *CircleExpandDimsGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleExpandDims>(); + node->input(inputs[0]); + node->axis(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleFill.cpp b/compiler/luci/import/src/Nodes/CircleFill.cpp new file mode 100644 index 000000000..6c3d3a247 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleFill.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleFill.h" + +#include <luci/IR/Nodes/CircleFill.h> + +namespace luci +{ + +bool CircleFillGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 2) + return false; + + if (args.op.outputs.size() != 1) + return false; + + return true; +} + +CircleNode *CircleFillGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleFill>(); + node->dims(inputs[0]); + node->value(inputs[1]); + + const auto *options = op.builtin_options.AsFillOptions(); + (void)options; + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleFloor.cpp b/compiler/luci/import/src/Nodes/CircleFloor.cpp new file mode 100644 index 000000000..302a9eae3 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleFloor.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleFloor.h" + +#include <luci/IR/Nodes/CircleFloor.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleFloorGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + if (inputs.size() != 1) + return false; + if (outputs.size() != 1) + return false; + + // TODO dtype check + + return true; +} + +CircleNode *CircleFloorGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleFloor>(); + node->x(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleFloorDiv.cpp b/compiler/luci/import/src/Nodes/CircleFloorDiv.cpp new file mode 100644 index 000000000..875197890 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleFloorDiv.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleFloorDiv.h" + +#include <luci/IR/Nodes/CircleFloorDiv.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleFloorDivGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + { + return false; + } + + if (outputs.size() != 1) + { + return false; + } + + const auto &tensors = args.reader.tensors(); + const auto &tensor_in_0 = tensors.at(inputs[0]); + const auto &tensor_in_1 = tensors.at(inputs[1]); + const auto &tensor_out = tensors.at(outputs[0]); + + if (tensor_in_0->type != tensor_in_1->type) + return false; + + if (tensor_out->type != tensor_in_1->type) + { + return false; + } + + return true; +} + +CircleNode *CircleFloorDivGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleFloorDiv>(); + node->x(inputs[0]); + node->y(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleFloorMod.cpp b/compiler/luci/import/src/Nodes/CircleFloorMod.cpp new file mode 100644 index 000000000..3ccdce0cd --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleFloorMod.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleFloorMod.h" + +#include <luci/IR/Nodes/CircleFloorMod.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleFloorModGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + if (inputs.size() != 2) + return false; + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor_in_0 = tensors.at(inputs[0]); + const auto &tensor_in_1 = tensors.at(inputs[1]); + if (tensor_in_0->type != tensor_in_1->type) + return false; + + // TODO dtype check + + return true; +} + +CircleNode *CircleFloorModGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleFloorMod>(); + node->x(inputs[0]); + node->y(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleFullyConnected.cpp b/compiler/luci/import/src/Nodes/CircleFullyConnected.cpp index 8f74fe9ce..8937e78f1 100644 --- a/compiler/luci/import/src/Nodes/CircleFullyConnected.cpp +++ b/compiler/luci/import/src/Nodes/CircleFullyConnected.cpp @@ -17,6 +17,7 @@ #include "luci/Import/Nodes/CircleFullyConnected.h" #include <luci/IR/Nodes/CircleFullyConnected.h> +#include <luci/IR/Nodes/CircleOutput.h> #include <loco.h> #include <oops/UserExn.h> @@ -39,7 +40,16 @@ CircleNode *CircleFullyConnectedGraphBuilder::build_node(const circle::OperatorT auto *node = graph->nodes()->create<CircleFullyConnected>(); node->input(inputs[0]); node->weights(inputs[1]); - node->bias(inputs[2]); + node->bias(inputs[2]); // bias is optional + + // TODO Find and move to appropriate place for setting optional input + if (auto bias = dynamic_cast<luci::CircleOutputExclude *>(node->bias())) + { + // bias is not used for type inference, but node itself should have a type + bias->dtype(loco::DataType::FLOAT32); + + // bias is not used for shape inference + } const auto *options = op.builtin_options.AsFullyConnectedOptions(); node->fusedActivationFunction(luci_actfunc(options->fused_activation_function)); diff --git a/compiler/luci/import/src/Nodes/CircleGather.cpp b/compiler/luci/import/src/Nodes/CircleGather.cpp new file mode 100644 index 000000000..1caa05ec2 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleGather.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleGather.h" + +#include <luci/IR/Nodes/CircleGather.h> + +#include <loco.h> +#include <oops/UserExn.h> + +namespace luci +{ + +bool CircleGatherGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + const auto *options = args.op.builtin_options.AsGatherOptions(); + + int32_t axis = options->axis; + + if (inputs.size() != 2) + return false; + + if (outputs.size() != 1) + return false; + + if (axis < 0) + axis += inputs.size(); + + if (axis < 0) + return false; + + // TODO do indices type check + // TODO do axis check when shape information is given + + return true; +} + +CircleNode *CircleGatherGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleGather>(); + + node->params(inputs[0]); + node->indices(inputs[1]); + + const auto *options = op.builtin_options.AsGatherOptions(); + node->axis(options->axis); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleGatherNd.cpp b/compiler/luci/import/src/Nodes/CircleGatherNd.cpp new file mode 100644 index 000000000..621d4ae92 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleGatherNd.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleGatherNd.h" + +#include <luci/IR/Nodes/CircleGatherNd.h> + +#include <loco.h> +#include <oops/UserExn.h> +#include <mio/circle/schema_generated.h> + +namespace luci +{ + +bool CircleGatherNdGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + return false; + + if (outputs.size() != 1) + return false; + + auto &indices_tensor = args.reader.tensors()[inputs[1]]; + + if (!(indices_tensor->type == circle::TensorType::TensorType_INT32 || + indices_tensor->type == circle::TensorType::TensorType_INT64)) + { + return false; + } + + return true; +} + +CircleNode *CircleGatherNdGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleGatherNd>(); + + node->params(inputs[0]); + node->indices(inputs[1]); + + // GatherNd options empty + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleGreater.cpp b/compiler/luci/import/src/Nodes/CircleGreater.cpp new file mode 100644 index 000000000..88107589c --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleGreater.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleGreater.h" + +#include <luci/IR/Nodes/CircleGreater.h> + +#include <luci/UserSettings.h> +#include <luci/Log.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleGreaterGraphBuilder::validate(const ValidateArgs &args) const +{ + LOGGER(l); + + auto settings = luci::UserSettings::settings(); + + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + return false; + + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + + if (tensors[inputs[0]]->type != tensors[inputs[1]]->type) + return false; + + // NOTE: real models do have output dtype NOT BOOL + if (tensors[outputs[0]]->type != circle::TensorType_BOOL) + { + if (settings->get(luci::UserSettings::Key::DisableValidation)) + { + const circle::TensorT &output_tensor = *tensors[outputs[0]]; + auto name = tensor_name(output_tensor); + WARN(l) << "Warning: import Greater(" << name << ") output dtype is not boolean"; + } + else + return false; + } + + return true; +} + +CircleNode *CircleGreaterGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleGreater>(); + node->x(inputs[0]); + node->y(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleGreaterEqual.cpp b/compiler/luci/import/src/Nodes/CircleGreaterEqual.cpp new file mode 100644 index 000000000..dff1510c5 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleGreaterEqual.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleGreaterEqual.h" + +#include <luci/IR/Nodes/CircleGreaterEqual.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleGreaterEqualGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + { + return false; + } + + if (outputs.size() != 1) + { + return false; + } + + const auto &tensors = args.reader.tensors(); + + if (tensors[inputs[0]]->type != tensors[inputs[1]]->type) + { + return false; + } + + return tensors[outputs[0]]->type == circle::TensorType::TensorType_BOOL; +} + +CircleNode *CircleGreaterEqualGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleGreaterEqual>(); + node->x(inputs[0]); + node->y(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleIf.cpp b/compiler/luci/import/src/Nodes/CircleIf.cpp new file mode 100644 index 000000000..d6090640d --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleIf.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleIf.h" + +#include <luci/IR/Nodes/CircleIf.h> +#include <luci/IR/Nodes/CircleIfOut.h> + +#include <loco.h> +#include <oops/UserExn.h> + +namespace luci +{ + +bool CircleIfGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto *options = args.op.builtin_options.AsIfOptions(); + + if (inputs.size() < 2) // cond + input + return false; + if (args.op.outputs.size() < 1) // output + return false; + + auto num_graphs = static_cast<int32_t>(args.reader.num_subgraph()); + if (options->then_subgraph_index >= num_graphs) + return false; + if (options->else_subgraph_index >= num_graphs) + return false; + + // input 0 should be BOOL type + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + if (tensor->type != circle::TensorType_BOOL) + return false; + + const auto &shape = tensor->shape; + if (shape.size() != 1 && shape.size() != 0) + return false; + + return true; +} + +/** + * @brief If Node builder + * + * @note Current loco does not provide multiple outputs + * We will create multiple CircleIfOut nodes to emulate this + * For two outputs that may look like this + * + * --- CircleIf --- Node --- + * \- Node --- + * + * will be created like this + * + * --- CircleIf --- CircleIfOut --- Node --- + * \- CircleIfOut --- Node --- + */ + +void CircleIfGraphBuilder::build(const circle::OperatorT &op, GraphBuilderContext *context) const +{ + assert(context != nullptr); + + auto graph = context->graph(); + + const std::vector<int32_t> &inputs = op.inputs; + const std::vector<int32_t> &outputs = op.outputs; + const auto &tensors = context->reader()->tensors(); + const auto &opcodes = context->reader()->opcodes(); + auto tensors_ptr = context->reader()->tensors_ptr(); + assert(tensors_ptr != nullptr); + + std::vector<CircleNode *> input_nodes; + for (const int32_t input_tensor_index : inputs) + { + input_nodes.push_back(context->nodefinder()->node(input_tensor_index)); + } + + uint32_t input_count = inputs.size() - 1; + uint32_t output_count = outputs.size(); + + // Create CircleIf + CircleIf *node = graph->nodes()->create<CircleIf>(input_count, output_count); + + node->cond(input_nodes[0]); + for (uint32_t idx = 0; idx < input_count; ++idx) + { + node->input(idx, input_nodes[idx + 1]); + } + + const auto *options = op.builtin_options.AsIfOptions(); + node->then_branch(options->then_subgraph_index); + node->else_branch(options->else_subgraph_index); + + assert(outputs.size() > 0); + { + // Lets use name of output 0 as If name + const circle::TensorT &output_tensor = *tensors[outputs[0]]; + node->name(tensor_name(output_tensor)); + node->op_version(opcodes[op.opcode_index].get()->version); + + // NOTE We don't set quantization for If itself but to virtual outputs + } + + // Create virtual outputs of If + for (uint32_t n = 0; n < output_count; ++n) + { + const circle::TensorT &output_tensor = *tensors[outputs[n]]; + + auto *nodeout = graph->nodes()->create<CircleIfOut>(); + copy_tensor_attributes(output_tensor, nodeout); + // mark shape_status + if (tensors_ptr->Get(outputs[n])->shape() == nullptr) + nodeout->shape_status(ShapeStatus::NOSHAPE); + else + nodeout->shape_status(ShapeStatus::VALID); + + nodeout->input(node); + nodeout->index(n); + + context->nodefinder()->enroll(outputs[n], nodeout); + } +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleInstanceNorm.cpp b/compiler/luci/import/src/Nodes/CircleInstanceNorm.cpp new file mode 100644 index 000000000..b95c54c89 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleInstanceNorm.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleInstanceNorm.h" + +#include <luci/IR/Nodes/CircleInstanceNorm.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleInstanceNormGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 3) + return false; + + // TODO check dtypes + + return true; +} + +CircleNode *CircleInstanceNormGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleInstanceNorm>(); + node->input(inputs[0]); + node->gamma(inputs[1]); + node->beta(inputs[2]); + + const auto *options = op.builtin_options.AsInstanceNormOptions(); + node->epsilon(options->epsilon); + node->fusedActivationFunction(luci_actfunc(options->fused_activation_function)); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleL2Normalize.cpp b/compiler/luci/import/src/Nodes/CircleL2Normalize.cpp new file mode 100644 index 000000000..fe10a8572 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleL2Normalize.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleL2Normalize.h" + +#include <luci/IR/Nodes/CircleL2Normalize.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleL2NormalizeGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 1) + { + return false; + } + + if (outputs.size() != 1) + { + return false; + } + + return true; +} + +CircleNode *CircleL2NormalizeGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleL2Normalize>(); + node->x(inputs[0]); + const auto *options = op.builtin_options.AsL2NormOptions(); + node->fusedActivationFunction(luci_actfunc(options->fused_activation_function)); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleL2Pool2D.cpp b/compiler/luci/import/src/Nodes/CircleL2Pool2D.cpp new file mode 100644 index 000000000..023206695 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleL2Pool2D.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleL2Pool2D.h" + +#include <luci/IR/Nodes/CircleL2Pool2D.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleL2Pool2DGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 1) + return false; + + // TODO check dtypes + + return true; +} + +CircleNode *CircleL2Pool2DGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleL2Pool2D>(); + node->value(inputs[0]); + + const auto *options = op.builtin_options.AsPool2DOptions(); + node->padding(luci_padding(options->padding)); + node->stride()->w(options->stride_w); + node->stride()->h(options->stride_h); + node->filter()->w(options->filter_width); + node->filter()->h(options->filter_height); + node->fusedActivationFunction(luci_actfunc(options->fused_activation_function)); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleLeakyRelu.cpp b/compiler/luci/import/src/Nodes/CircleLeakyRelu.cpp new file mode 100644 index 000000000..4957ceae0 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleLeakyRelu.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleLeakyRelu.h" + +#include <luci/IR/Nodes/CircleLeakyRelu.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleLeakyReluGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 1) + return false; + + if (args.op.outputs.size() != 1) + return false; + + return true; +} + +CircleNode *CircleLeakyReluGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleLeakyRelu>(); + node->features(inputs[0]); + + const auto *options = op.builtin_options.AsLeakyReluOptions(); + node->alpha(options->alpha); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleLess.cpp b/compiler/luci/import/src/Nodes/CircleLess.cpp new file mode 100644 index 000000000..40ad28c6e --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleLess.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleLess.h" + +#include <luci/IR/Nodes/CircleLess.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleLessGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + { + return false; + } + + if (outputs.size() != 1) + { + return false; + } + + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + + switch (tensor->type) + { + case circle::TensorType_FLOAT32: + case circle::TensorType_FLOAT64: + case circle::TensorType_INT32: + case circle::TensorType_UINT8: + case circle::TensorType_INT16: + case circle::TensorType_INT8: + case circle::TensorType_INT64: + case circle::TensorType_FLOAT16: + break; + default: + return false; + } + + if (tensors[inputs[1]]->type != tensor->type) + { + return false; + } + + return tensors[outputs[0]]->type == circle::TensorType_BOOL; +} + +CircleNode *CircleLessGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleLess>(); + node->x(inputs[0]); + node->y(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleLessEqual.cpp b/compiler/luci/import/src/Nodes/CircleLessEqual.cpp new file mode 100644 index 000000000..13e995069 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleLessEqual.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleLessEqual.h" + +#include <luci/IR/Nodes/CircleLessEqual.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleLessEqualGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + { + return false; + } + + if (outputs.size() != 1) + { + return false; + } + + const auto &tensors = args.reader.tensors(); + + if (tensors[inputs[0]]->type != tensors[inputs[1]]->type) + { + return false; + } + + return tensors[outputs[0]]->type == circle::TensorType::TensorType_BOOL; +} + +CircleNode *CircleLessEqualGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleLessEqual>(); + node->x(inputs[0]); + node->y(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleLocalResponseNormalization.cpp b/compiler/luci/import/src/Nodes/CircleLocalResponseNormalization.cpp new file mode 100644 index 000000000..7b1f0db56 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleLocalResponseNormalization.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleLocalResponseNormalization.h" + +#include <luci/IR/Nodes/CircleLocalResponseNormalization.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleLocalResponseNormalizationGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 1) + return false; + + // TODO do attribute checks + + return true; +} + +CircleNode *CircleLocalResponseNormalizationGraphBuilder::build_node( + const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleLocalResponseNormalization>(); + node->input(inputs[0]); + + const auto *options = op.builtin_options.AsLocalResponseNormalizationOptions(); + node->radius(options->radius); + node->bias(options->bias); + node->alpha(options->alpha); + node->beta(options->beta); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleLog.cpp b/compiler/luci/import/src/Nodes/CircleLog.cpp new file mode 100644 index 000000000..21408327d --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleLog.cpp @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleLog.h" + +#include <luci/IR/Nodes/CircleLog.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleLogGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + if (inputs.size() != 1) + return false; + if (args.op.outputs.size() != 1) + return false; + + // input type check + // Must be one of bfloat16, half, float32, float64, complex64, complex128. + // Currently circle supports half(float16), float32, float64, complex64. + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + switch (tensor->type) + { + case circle::TensorType_FLOAT16: + case circle::TensorType_FLOAT32: + case circle::TensorType_FLOAT64: + case circle::TensorType_COMPLEX64: + break; + default: + return false; + } + + return true; +} + +CircleNode *CircleLogGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleLog>(); + node->x(inputs[0]); + + // No options for Log + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleLogSoftmax.cpp b/compiler/luci/import/src/Nodes/CircleLogSoftmax.cpp new file mode 100644 index 000000000..e738c4a0c --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleLogSoftmax.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleLogSoftmax.h" + +#include <luci/IR/Nodes/CircleLogSoftmax.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleLogSoftmaxGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 1) + return false; + + // TODO do attribute checks + + return true; +} + +CircleNode *CircleLogSoftmaxGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleLogSoftmax>(); + node->logits(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleLogicalAnd.cpp b/compiler/luci/import/src/Nodes/CircleLogicalAnd.cpp new file mode 100644 index 000000000..8509dbaf3 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleLogicalAnd.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleLogicalAnd.h" + +#include <luci/IR/Nodes/CircleLogicalAnd.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleLogicalAndGraphBuilder::validate(const ValidateArgs &args) const +{ + // Only BOOL type is allowed for inputs + const auto &inputs = args.op.inputs; + if (inputs.size() != 2) + return false; + + const auto &tensors = args.reader.tensors(); + for (auto input : inputs) + { + const auto &tensor = tensors.at(input); + if (tensor->type != circle::TensorType::TensorType_BOOL) + return false; + } + + return true; +} + +CircleNode *CircleLogicalAndGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleLogicalAnd>(); + node->x(inputs[0]); + node->y(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleLogistic.cpp b/compiler/luci/import/src/Nodes/CircleLogistic.cpp new file mode 100644 index 000000000..85e7e55b2 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleLogistic.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleLogistic.h" + +#include <luci/IR/Nodes/CircleLogistic.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleLogisticGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + if (inputs.size() != 1) + return false; + const auto &outputs = args.op.outputs; + if (outputs.size() != 1) + return false; + + // Must be one of the following types + // float16, float32, float64, complex64, or complex128 + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + switch (tensor->type) + { + case circle::TensorType_FLOAT16: + case circle::TensorType_FLOAT32: + case circle::TensorType_FLOAT64: + case circle::TensorType_COMPLEX64: + break; + default: + return false; + } + + if (tensors.at(inputs[0])->type != tensors.at(outputs[0])->type) + return false; + + return true; +} + +CircleNode *CircleLogisticGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleLogistic>(); + node->x(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleMatrixDiag.cpp b/compiler/luci/import/src/Nodes/CircleMatrixDiag.cpp new file mode 100644 index 000000000..f4ae03c58 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleMatrixDiag.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleMatrixDiag.h" + +#include <luci/IR/Nodes/CircleMatrixDiag.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleMatrixDiagGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 1) + return false; + + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + + if (tensors[outputs[0]]->type != tensor->type) + return false; + + return true; +} + +CircleNode *CircleMatrixDiagGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleMatrixDiag>(); + node->diagonal(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleMatrixSetDiag.cpp b/compiler/luci/import/src/Nodes/CircleMatrixSetDiag.cpp new file mode 100644 index 000000000..d6f6aee33 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleMatrixSetDiag.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleMatrixSetDiag.h" + +#include <luci/IR/Nodes/CircleMatrixSetDiag.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleMatrixSetDiagGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + return false; + + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + + if (tensors[outputs[0]]->type != tensor->type) + return false; + + return true; +} + +CircleNode *CircleMatrixSetDiagGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleMatrixSetDiag>(); + node->input(inputs[0]); + node->diagonal(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleMaximum.cpp b/compiler/luci/import/src/Nodes/CircleMaximum.cpp new file mode 100644 index 000000000..6ca7e4079 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleMaximum.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleMaximum.h" + +#include <luci/IR/Nodes/CircleMaximum.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleMaximumGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + return false; + + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + + switch (tensor->type) + { + case circle::TensorType_FLOAT16: + case circle::TensorType_FLOAT32: + case circle::TensorType_FLOAT64: + case circle::TensorType_INT32: + case circle::TensorType_INT64: + break; + default: + return false; + } + + if (tensors[inputs[1]]->type != tensor->type) + return false; + + if (tensors[outputs[0]]->type != tensor->type) + return false; + + return true; +} + +CircleNode *CircleMaximumGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleMaximum>(); + node->x(inputs[0]); + node->y(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleMinimum.cpp b/compiler/luci/import/src/Nodes/CircleMinimum.cpp new file mode 100644 index 000000000..b770f365f --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleMinimum.cpp @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleMinimum.h" + +#include <luci/IR/Nodes/CircleMinimum.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleMinimumGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + return false; + + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + + switch (tensor->type) + { + case circle::TensorType_FLOAT16: + case circle::TensorType_FLOAT32: + case circle::TensorType_FLOAT64: + case circle::TensorType_INT32: + case circle::TensorType_INT64: + break; + default: + return false; + } + + if (tensors[inputs[1]]->type != tensor->type) + return false; + + if (tensors[outputs[0]]->type != tensor->type) + return false; + + return true; +} + +CircleNode *CircleMinimumGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleMinimum>(); + node->x(inputs[0]); + node->y(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleMirrorPad.cpp b/compiler/luci/import/src/Nodes/CircleMirrorPad.cpp new file mode 100644 index 000000000..41b5e5d80 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleMirrorPad.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleMirrorPad.h" + +#include <luci/IR/Nodes/CircleMirrorPad.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleMirrorPadGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 2) + return false; + + // TODO check others + + return true; +} + +CircleNode *CircleMirrorPadGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleMirrorPad>(); + node->input(inputs[0]); + node->paddings(inputs[1]); + + const auto *options = op.builtin_options.AsMirrorPadOptions(); + node->mode(luci_mirrorpad_mode(options->mode)); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleNeg.cpp b/compiler/luci/import/src/Nodes/CircleNeg.cpp new file mode 100644 index 000000000..3d3079ca2 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleNeg.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleNeg.h" + +#include <luci/IR/Nodes/CircleNeg.h> + +#include <loco.h> + +namespace luci +{ +bool CircleNegGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 1) + return false; + + // TODO Support type check + return true; +} + +CircleNode *CircleNegGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleNeg>(); + node->x(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleNotEqual.cpp b/compiler/luci/import/src/Nodes/CircleNotEqual.cpp new file mode 100644 index 000000000..5b04856db --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleNotEqual.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleNotEqual.h" + +#include <luci/IR/Nodes/CircleNotEqual.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleNotEqualGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + { + return false; + } + + if (outputs.size() != 1) + { + return false; + } + + const auto &tensors = args.reader.tensors(); + + if (tensors[inputs[0]]->type != tensors[inputs[1]]->type) + { + return false; + } + + return tensors[outputs[0]]->type == circle::TensorType::TensorType_BOOL; +} + +CircleNode *CircleNotEqualGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleNotEqual>(); + node->x(inputs[0]); + node->y(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleOneHot.cpp b/compiler/luci/import/src/Nodes/CircleOneHot.cpp new file mode 100644 index 000000000..9fdbfa84d --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleOneHot.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleOneHot.h" + +#include <luci/IR/Nodes/CircleOneHot.h> + +#include <loco.h> +#include <oops/UserExn.h> + +namespace luci +{ + +bool CircleOneHotGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + const auto *options = args.op.builtin_options.AsOneHotOptions(); + + // Only 4 Input come refered from + if (inputs.size() != 4) + return false; + + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &indices = tensors.at(inputs[0]); + const auto &depth = tensors.at(inputs[1]); + const auto &on_value = tensors.at(inputs[2]); + const auto &off_value = tensors.at(inputs[3]); + + if (options->axis < -1 || options->axis > static_cast<int32_t>(indices->shape.size())) + return false; + if (depth->shape.size() != 0) + return false; + if (on_value->shape.size() != 0) + return false; + if (off_value->shape.size() != 0) + return false; + if (on_value->type != off_value->type) + return false; + + return true; +} + +CircleNode *CircleOneHotGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleOneHot>(); + + node->indices(inputs[0]); + node->depth(inputs[1]); + node->on_value(inputs[2]); + node->off_value(inputs[3]); + + const auto *options = op.builtin_options.AsOneHotOptions(); + node->axis(options->axis); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CirclePRelu.cpp b/compiler/luci/import/src/Nodes/CirclePRelu.cpp new file mode 100644 index 000000000..0d87cd423 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CirclePRelu.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CirclePRelu.h" + +#include <luci/IR/Nodes/CirclePRelu.h> + +#include <loco.h> + +namespace luci +{ + +bool CirclePReluGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 2) + return false; + + if (args.op.outputs.size() != 1) + return false; + + return true; +} + +CircleNode *CirclePReluGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CirclePRelu>(); + node->input(inputs[0]); + node->alpha(inputs[1]); + + // PRelu options are empty + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CirclePow.cpp b/compiler/luci/import/src/Nodes/CirclePow.cpp new file mode 100644 index 000000000..ff9833165 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CirclePow.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CirclePow.h" + +#include <luci/IR/Nodes/CirclePow.h> + +#include <loco.h> + +namespace luci +{ + +bool CirclePowGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 2) + return false; + + if (args.op.outputs.size() != 1) + return false; + + return true; +} + +CircleNode *CirclePowGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CirclePow>(); + node->x(inputs[0]); + node->y(inputs[1]); + + // Pow options are empty + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleRange.cpp b/compiler/luci/import/src/Nodes/CircleRange.cpp new file mode 100644 index 000000000..c21191605 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleRange.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleRange.h" + +#include <luci/IR/Nodes/CircleRange.h> + +#include <loco.h> + +namespace luci +{ +bool CircleRangeGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 3) + return false; + + // TODO Support type check + return true; +} + +CircleNode *CircleRangeGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleRange>(); + node->start(inputs[0]); + node->limit(inputs[1]); + node->delta(inputs[2]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleRank.cpp b/compiler/luci/import/src/Nodes/CircleRank.cpp new file mode 100644 index 000000000..705ae0120 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleRank.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleRank.h" + +#include <luci/IR/Nodes/CircleRank.h> + +#include <loco.h> + +namespace luci +{ +bool CircleRankGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 1) + return false; + + if (args.op.outputs.size() != 1) + return false; + + return true; +} + +CircleNode *CircleRankGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleRank>(); + node->input(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleReduceAny.cpp b/compiler/luci/import/src/Nodes/CircleReduceAny.cpp new file mode 100644 index 000000000..030c5304c --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleReduceAny.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleReduceAny.h" + +#include <luci/IR/Nodes/CircleReduceAny.h> + +namespace luci +{ + +bool CircleReduceAnyGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + if (inputs.size() != 2) + return false; + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor_0 = tensors.at(inputs[0]); + const auto &tensor_1 = tensors.at(inputs[1]); + const auto &tensor_o = tensors.at(outputs[0]); + + if (tensor_0->type != circle::TensorType_BOOL) + return false; + if (tensor_o->type != circle::TensorType_BOOL) + return false; + + switch (tensor_1->type) + { + case circle::TensorType_INT32: + case circle::TensorType_INT64: + break; + default: + return false; + } + + return true; +} + +CircleNode *CircleReduceAnyGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleReduceAny>(); + node->input(inputs[0]); + node->reduction_indices(inputs[1]); + + const auto *options = op.builtin_options.AsReducerOptions(); + node->keep_dims(options->keep_dims); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleReduceMax.cpp b/compiler/luci/import/src/Nodes/CircleReduceMax.cpp new file mode 100644 index 000000000..8ca8e2e34 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleReduceMax.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleReduceMax.h" + +#include <luci/IR/Nodes/CircleReduceMax.h> + +namespace luci +{ + +bool CircleReduceMaxGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + return false; + + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor_axis = tensors.at(inputs[1]); + + switch (tensor_axis->type) + { + case circle::TensorType_INT32: + case circle::TensorType_INT64: + break; + default: + return false; + } + + return true; +} + +CircleNode *CircleReduceMaxGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleReduceMax>(); + node->input(inputs[0]); + node->reduction_indices(inputs[1]); + + const auto *options = op.builtin_options.AsReducerOptions(); + node->keep_dims(options->keep_dims); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleReduceMin.cpp b/compiler/luci/import/src/Nodes/CircleReduceMin.cpp new file mode 100644 index 000000000..3020c3778 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleReduceMin.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleReduceMin.h" + +#include <luci/IR/Nodes/CircleReduceMin.h> + +namespace luci +{ + +bool CircleReduceMinGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + return false; + + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor_axis = tensors.at(inputs[1]); + + switch (tensor_axis->type) + { + case circle::TensorType_INT32: + case circle::TensorType_INT64: + break; + default: + return false; + } + + return true; +} + +CircleNode *CircleReduceMinGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleReduceMin>(); + node->input(inputs[0]); + node->reduction_indices(inputs[1]); + + const auto *options = op.builtin_options.AsReducerOptions(); + node->keep_dims(options->keep_dims); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleReduceProd.cpp b/compiler/luci/import/src/Nodes/CircleReduceProd.cpp new file mode 100644 index 000000000..2bb43f6ce --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleReduceProd.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleReduceProd.h" + +#include <luci/IR/Nodes/CircleReduceProd.h> + +namespace luci +{ + +bool CircleReduceProdGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + if (inputs.size() != 2) + return false; + if (args.op.outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor_1 = tensors.at(inputs[1]); + + // TODO check input types + + // Check for reduction_indices types + switch (tensor_1->type) + { + case circle::TensorType_INT32: + case circle::TensorType_INT64: + break; + default: + return false; + } + + return true; +} + +CircleNode *CircleReduceProdGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleReduceProd>(); + node->input(inputs[0]); + node->reduction_indices(inputs[1]); + + const auto *options = op.builtin_options.AsReducerOptions(); + node->keep_dims(options->keep_dims); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleRelu6.cpp b/compiler/luci/import/src/Nodes/CircleRelu6.cpp new file mode 100644 index 000000000..5b443993b --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleRelu6.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleRelu6.h" + +#include <luci/IR/Nodes/CircleRelu6.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleRelu6GraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 1) + return false; + + if (args.op.outputs.size() != 1) + return false; + + return true; +} + +CircleNode *CircleRelu6GraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleRelu6>(); + node->features(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleReluN1To1.cpp b/compiler/luci/import/src/Nodes/CircleReluN1To1.cpp new file mode 100644 index 000000000..edf662fb9 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleReluN1To1.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleReluN1To1.h" + +#include <luci/IR/Nodes/CircleReluN1To1.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleReluN1To1GraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 1) + return false; + + if (args.op.outputs.size() != 1) + return false; + + // TODO check dtypes + + return true; +} + +CircleNode *CircleReluN1To1GraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleReluN1To1>(); + node->features(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleReshape.cpp b/compiler/luci/import/src/Nodes/CircleReshape.cpp index c83f143a6..f72c152b1 100644 --- a/compiler/luci/import/src/Nodes/CircleReshape.cpp +++ b/compiler/luci/import/src/Nodes/CircleReshape.cpp @@ -66,7 +66,14 @@ CircleNode *CircleReshapeGraphBuilder::build_node(const circle::OperatorT &op, if (shape_node == nullptr) { const auto *options = op.builtin_options.AsReshapeOptions(); - shape_node = create_shape_node(options->new_shape, graph); + if (options != nullptr) + shape_node = create_shape_node(options->new_shape, graph); + else + { + shape_node = graph->nodes()->create<CircleOutputDummy>(); + shape_node->dtype(loco::DataType::S32); + shape_node->rank(0); + } } auto *node = graph->nodes()->create<CircleReshape>(); @@ -74,7 +81,8 @@ CircleNode *CircleReshapeGraphBuilder::build_node(const circle::OperatorT &op, node->shape(shape_node); const auto *options = op.builtin_options.AsReshapeOptions(); - setup_shape_attribute(options->new_shape, node); + if (options) + setup_shape_attribute(options->new_shape, node); return node; } diff --git a/compiler/luci/import/src/Nodes/CircleResizeBilinear.cpp b/compiler/luci/import/src/Nodes/CircleResizeBilinear.cpp new file mode 100644 index 000000000..6128f1b86 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleResizeBilinear.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleResizeBilinear.h" + +#include <luci/IR/Nodes/CircleConst.h> +#include <luci/IR/Nodes/CircleResizeBilinear.h> + +namespace luci +{ + +bool CircleResizeBilinearGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 2) + return false; + + if (args.op.outputs.size() != 1) + return false; + + return true; +} + +CircleNode *CircleResizeBilinearGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleResizeBilinear>(); + node->input(inputs[0]); + node->size(inputs[1]); + + const auto *options = op.builtin_options.AsResizeBilinearOptions(); + node->align_corners(options->align_corners); + node->half_pixel_centers(options->half_pixel_centers); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleResizeNearestNeighbor.cpp b/compiler/luci/import/src/Nodes/CircleResizeNearestNeighbor.cpp new file mode 100644 index 000000000..a1f1ef0ff --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleResizeNearestNeighbor.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleResizeNearestNeighbor.h" + +#include <luci/IR/Nodes/CircleConst.h> +#include <luci/IR/Nodes/CircleResizeNearestNeighbor.h> + +namespace luci +{ + +bool CircleResizeNearestNeighborGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 2) + return false; + + if (args.op.outputs.size() != 1) + return false; + + return true; +} + +CircleNode *CircleResizeNearestNeighborGraphBuilder::build_node( + const circle::OperatorT &op, const std::vector<CircleNode *> &inputs, loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleResizeNearestNeighbor>(); + node->input(inputs[0]); + node->size(inputs[1]); + + const auto *options = op.builtin_options.AsResizeNearestNeighborOptions(); + node->align_corners(options->align_corners); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleReverseSequence.cpp b/compiler/luci/import/src/Nodes/CircleReverseSequence.cpp new file mode 100644 index 000000000..72d3b153d --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleReverseSequence.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleReverseSequence.h" + +#include <luci/IR/Nodes/CircleReverseSequence.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleReverseSequenceGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + return false; + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor_in = tensors.at(inputs[0]); + const auto &tensor_lengths = tensors.at(inputs[1]); + const auto &tensor_out = tensors.at(outputs[0]); + + switch (tensor_lengths->type) + { + case circle::TensorType_INT32: + case circle::TensorType_INT64: + break; + default: + return false; + } + + if (tensor_in->type != tensor_out->type) + return false; + + return true; +} + +CircleNode *CircleReverseSequenceGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleReverseSequence>(); + node->input(inputs[0]); + node->seq_lengths(inputs[1]); + + const auto *options = op.builtin_options.AsReverseSequenceOptions(); + node->seq_axis(options->seq_dim); + node->batch_axis(options->batch_dim); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleReverseV2.cpp b/compiler/luci/import/src/Nodes/CircleReverseV2.cpp new file mode 100644 index 000000000..cd18128a7 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleReverseV2.cpp @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleReverseV2.h" + +#include <luci/IR/Nodes/CircleReverseV2.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleReverseV2GraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + return false; + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor_in = tensors.at(inputs[0]); + const auto &tensor_axis = tensors.at(inputs[1]); + const auto &tensor_out = tensors.at(outputs[0]); + + switch (tensor_axis->type) + { + case circle::TensorType_INT32: + case circle::TensorType_INT64: + break; + default: + return false; + } + + if (tensor_out->type != tensor_in->type) + return false; + + return true; +} + +CircleNode *CircleReverseV2GraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleReverseV2>(); + node->tensor(inputs[0]); + node->axis(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleRound.cpp b/compiler/luci/import/src/Nodes/CircleRound.cpp new file mode 100644 index 000000000..896489521 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleRound.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleRound.h" + +#include <luci/IR/Nodes/CircleRound.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleRoundGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 1) + return false; + if (outputs.size() != 1) + return false; + + // Must be one of the following types + // bfloat16, half (float16), float32, float64, complex64, complex128 + // Currently, circle supports float16, float32, complex64 + const auto &tensors = args.reader.tensors(); + const auto &tensor_in = tensors.at(inputs[0]); + const auto &tensor_out = tensors.at(outputs[0]); + + switch (tensor_in->type) + { + case circle::TensorType_FLOAT16: + case circle::TensorType_FLOAT32: + case circle::TensorType_FLOAT64: + case circle::TensorType_INT32: + case circle::TensorType_INT64: + break; + default: + return false; + } + + if (tensor_out->type != tensor_in->type) + return false; + + return true; +} + +CircleNode *CircleRoundGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleRound>(); + node->x(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleScatterNd.cpp b/compiler/luci/import/src/Nodes/CircleScatterNd.cpp new file mode 100644 index 000000000..adcaa0030 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleScatterNd.cpp @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleScatterNd.h" + +#include <luci/IR/Nodes/CircleScatterNd.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleScatterNdGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + if (inputs.size() != 3) + return false; + + // indices must have the same type as shape + const auto &tensors = args.reader.tensors(); + + if (tensors[inputs[0]]->type != tensors[inputs[2]]->type) + return false; + + // indices must be either int32 or int64 + if (tensors[inputs[0]]->type != circle::TensorType_INT32 && + tensors[inputs[0]]->type != circle::TensorType_INT64) + return false; + + return true; +} + +CircleNode *CircleScatterNdGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleScatterNd>(); + node->indices(inputs[0]); + node->updates(inputs[1]); + node->shape(inputs[2]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSegmentSum.cpp b/compiler/luci/import/src/Nodes/CircleSegmentSum.cpp new file mode 100644 index 000000000..1122bdca3 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSegmentSum.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSegmentSum.h" + +#include <luci/IR/Nodes/CircleSegmentSum.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleSegmentSumGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + if (inputs.size() != 2) + return false; + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor_in = tensors.at(inputs[0]); + const auto &tensor_out = tensors.at(outputs[0]); + const auto &tensor_ids = tensors.at(inputs[1]); + + switch (tensor_ids->type) + { + case circle::TensorType_INT32: + case circle::TensorType_INT64: + break; + default: + return false; + } + + if (tensor_out->type != tensor_in->type) + { + return false; + } + + return true; +} + +CircleNode *CircleSegmentSumGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleSegmentSum>(); + node->input(inputs[0]); + node->segment_ids(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSelect.cpp b/compiler/luci/import/src/Nodes/CircleSelect.cpp new file mode 100644 index 000000000..ff94212c3 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSelect.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSelect.h" + +#include <luci/IR/Nodes/CircleSelect.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleSelectGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + if (inputs.size() != 3) + return false; + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + if (tensor->type != circle::TensorType_BOOL) + return false; + // TODO check dtypes for input 1, 2 + + return true; +} + +CircleNode *CircleSelectGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleSelect>(); + node->condition(inputs[0]); + node->t(inputs[1]); + node->e(inputs[2]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSelectV2.cpp b/compiler/luci/import/src/Nodes/CircleSelectV2.cpp new file mode 100644 index 000000000..78b2e6459 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSelectV2.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSelectV2.h" + +#include <luci/IR/Nodes/CircleSelectV2.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleSelectV2GraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + if (inputs.size() != 3) + return false; + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &condition = tensors.at(inputs[0]); + if (condition->type != circle::TensorType_BOOL) + return false; + + const auto &t = tensors.at(inputs[1]); + const auto &e = tensors.at(inputs[2]); + if (t->type != e->type) + return false; + + return true; +} + +CircleNode *CircleSelectV2GraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleSelectV2>(); + node->condition(inputs[0]); + node->t(inputs[1]); + node->e(inputs[2]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleShape.cpp b/compiler/luci/import/src/Nodes/CircleShape.cpp new file mode 100644 index 000000000..864b5eb51 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleShape.cpp @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleShape.h" + +#include <luci/IR/Nodes/CircleShape.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleShapeGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + if (inputs.size() != 1) + return false; + if (outputs.size() != 1) + return false; + + // TODO check shape, dtype + + return true; +} + +CircleNode *CircleShapeGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleShape>(); + node->input(inputs[0]); + + const auto *options = op.builtin_options.AsShapeOptions(); + node->out_type(luci_datatype(options->out_type)); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSin.cpp b/compiler/luci/import/src/Nodes/CircleSin.cpp new file mode 100644 index 000000000..61d60c78f --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSin.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSin.h" + +#include <luci/IR/Nodes/CircleSin.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleSinGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + if (inputs.size() != 1) + return false; + if (args.op.outputs.size() != 1) + return false; + + // input type check + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + switch (tensor->type) + { + case circle::TensorType_FLOAT16: + case circle::TensorType_FLOAT32: + case circle::TensorType_FLOAT64: + break; + // TODO support TensorType_COMPLEX64, complex128, bfloat16 + default: + return false; + } + + return true; +} + +CircleNode *CircleSinGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleSin>(); + node->x(inputs[0]); + + // No options for Sin + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSlice.cpp b/compiler/luci/import/src/Nodes/CircleSlice.cpp new file mode 100644 index 000000000..313c35599 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSlice.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSlice.h" + +#include <luci/IR/Nodes/CircleSlice.h> + +#include <loco.h> + +#include <cassert> + +namespace luci +{ + +bool CircleSliceGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 3) + return false; + if (args.op.outputs.size() != 1) + return false; + + // TODO check shapes and types + + return true; +} + +CircleNode *CircleSliceGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleSlice>(); + node->input(inputs[0]); + node->begin(inputs[1]); + node->size(inputs[2]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSpaceToBatchND.cpp b/compiler/luci/import/src/Nodes/CircleSpaceToBatchND.cpp new file mode 100644 index 000000000..f1361fb11 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSpaceToBatchND.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSpaceToBatchND.h" + +#include <luci/IR/Nodes/CircleSpaceToBatchND.h> + +#include <loco.h> + +#include <cassert> + +namespace luci +{ + +bool CircleSpaceToBatchNDGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + if (inputs.size() != 3) + return false; + + // input 1 and 2 should have INT32/INT64 type + const auto &tensors = args.reader.tensors(); + const auto &tensor_1 = tensors.at(inputs[1]); + switch (tensor_1->type) + { + case circle::TensorType_INT32: + case circle::TensorType_INT64: + break; + default: + return false; + } + const auto &tensor_2 = tensors.at(inputs[2]); + switch (tensor_2->type) + { + case circle::TensorType_INT32: + case circle::TensorType_INT64: + break; + default: + return false; + } + + // Only support input shape dimension 3 and 4 only + const auto &tensor_0 = tensors.at(inputs[0]); + const auto t_0_s = tensor_0->shape.size(); + if (t_0_s != 3 && t_0_s != 4) + return false; + + // TODO check input shape + + return true; +} + +CircleNode *CircleSpaceToBatchNDGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleSpaceToBatchND>(); + node->input(inputs[0]); + node->block_shape(inputs[1]); + node->paddings(inputs[2]); + + // No options for SpaceToBatchND + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSpaceToDepth.cpp b/compiler/luci/import/src/Nodes/CircleSpaceToDepth.cpp new file mode 100644 index 000000000..b612c9a9a --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSpaceToDepth.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSpaceToDepth.h" + +#include <luci/IR/Nodes/CircleSpaceToDepth.h> + +#include <loco.h> + +#include <cassert> + +namespace luci +{ + +bool CircleSpaceToDepthGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + if (inputs.size() != 1) + return false; + + // TODO do attribute checks + + return true; +} + +CircleNode *CircleSpaceToDepthGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleSpaceToDepth>(); + node->input(inputs[0]); + + const auto *options = op.builtin_options.AsSpaceToDepthOptions(); + node->block_size(options->block_size); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSparseToDense.cpp b/compiler/luci/import/src/Nodes/CircleSparseToDense.cpp new file mode 100644 index 000000000..bfe790fc1 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSparseToDense.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSparseToDense.h" + +#include <luci/IR/Nodes/CircleSparseToDense.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleSparseToDenseGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 4) + return false; + + return true; +} + +CircleNode *CircleSparseToDenseGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleSparseToDense>(); + node->indices(inputs[0]); + node->output_shape(inputs[1]); + node->values(inputs[2]); + node->default_value(inputs[3]); + + const auto *options = op.builtin_options.AsSparseToDenseOptions(); + node->validate_indices(options->validate_indices); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSplit.cpp b/compiler/luci/import/src/Nodes/CircleSplit.cpp new file mode 100644 index 000000000..07b6cc939 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSplit.cpp @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSplit.h" + +#include <luci/IR/Nodes/CircleSplit.h> +#include <luci/IR/Nodes/CircleSplitOut.h> + +#include <loco.h> +#include <oops/UserExn.h> + +namespace luci +{ + +bool CircleSplitGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + const auto *options = args.op.builtin_options.AsSplitOptions(); + + if (inputs.size() != 2) + return false; + + if (static_cast<int32_t>(outputs.size()) != options->num_splits) + return false; + + // TODO check types + + return true; +} + +/** + * @brief Split Node builder + * + * @note Current loco does not provide multiple outputs + * We will create multiple CircleSplitOut nodes to emulate this + * For two outputs that may look like this + * + * --- CircleSplit --- FullyConnected --- + * \- FullyConnected --- + * + * will be created like this + * + * --- CircleSplit --- CircleSplitOut --- FullyConnected --- + * \- CircleSplitOut --- FullyConnected --- + */ + +void CircleSplitGraphBuilder::build(const circle::OperatorT &op, GraphBuilderContext *context) const +{ + assert(context != nullptr); + + auto graph = context->graph(); + + const std::vector<int32_t> &inputs = op.inputs; + const std::vector<int32_t> &outputs = op.outputs; + const auto &tensors = context->reader()->tensors(); + const auto &opcodes = context->reader()->opcodes(); + auto tensors_ptr = context->reader()->tensors_ptr(); + assert(tensors_ptr != nullptr); + + std::vector<CircleNode *> input_nodes; + for (const int32_t input_tensor_index : inputs) + { + input_nodes.push_back(context->nodefinder()->node(input_tensor_index)); + } + + // Create CircleSplit + auto node = graph->nodes()->create<CircleSplit>(); + node->split_dim(input_nodes[0]); + node->input(input_nodes[1]); + + const auto *options = op.builtin_options.AsSplitOptions(); + node->num_split(options->num_splits); + + assert(outputs.size() > 0); + assert(int32_t(outputs.size()) == options->num_splits); + { + // Let's use name of output 0 as Split name + const circle::TensorT &output_tensor = *tensors[outputs[0]]; + node->name(tensor_name(output_tensor)); + node->op_version(opcodes[op.opcode_index].get()->version); + + // NOTE We don't set quantization for Split itself but to virtual outputs + } + + // Create virtual outputs of Split + for (int32_t n = 0; n < options->num_splits; ++n) + { + const circle::TensorT &output_tensor = *tensors[outputs[n]]; + + auto *nodeout = graph->nodes()->create<CircleSplitOut>(); + copy_tensor_attributes(output_tensor, nodeout); + // mark shape_status + if (tensors_ptr->Get(outputs[n])->shape() == nullptr) + nodeout->shape_status(ShapeStatus::NOSHAPE); + else + nodeout->shape_status(ShapeStatus::VALID); + + nodeout->input(node); + nodeout->index(n); + + context->nodefinder()->enroll(outputs[n], nodeout); + } +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSplitV.cpp b/compiler/luci/import/src/Nodes/CircleSplitV.cpp new file mode 100644 index 000000000..7c6e83e17 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSplitV.cpp @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSplitV.h" + +#include <luci/IR/Nodes/CircleSplitV.h> +#include <luci/IR/Nodes/CircleSplitVOut.h> + +#include <loco.h> +#include <oops/UserExn.h> + +namespace luci +{ + +bool CircleSplitVGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + const auto *options = args.op.builtin_options.AsSplitVOptions(); + + if (inputs.size() != 3) + return false; + + if (static_cast<int32_t>(outputs.size()) != options->num_splits) + return false; + + // TODO check types + + return true; +} + +/** + * @brief SplitV Node builder + * + * @note Current loco does not provide multiple outputs + * We will create multiple CircleSplitVOut nodes to emulate this + * For two outputs that may look like this + * + * --- CircleSplitV --- FullyConnected --- + * \- FullyConnected --- + * + * will be created like this + * + * --- CircleSplitV --- CircleSplitVOut --- FullyConnected --- + * \- CircleSplitVOut --- FullyConnected --- + */ + +void CircleSplitVGraphBuilder::build(const circle::OperatorT &op, + GraphBuilderContext *context) const +{ + assert(context != nullptr); + + auto graph = context->graph(); + + const std::vector<int32_t> &inputs = op.inputs; + const std::vector<int32_t> &outputs = op.outputs; + const auto &tensors = context->reader()->tensors(); + const auto &opcodes = context->reader()->opcodes(); + auto tensors_ptr = context->reader()->tensors_ptr(); + assert(tensors_ptr != nullptr); + + std::vector<CircleNode *> input_nodes; + for (const int32_t input_tensor_index : inputs) + { + input_nodes.push_back(context->nodefinder()->node(input_tensor_index)); + } + + // Create CircleSplitV + auto node = graph->nodes()->create<CircleSplitV>(); + node->input(input_nodes[0]); + node->size_splits(input_nodes[1]); + node->split_dim(input_nodes[2]); + + const auto *options = op.builtin_options.AsSplitVOptions(); + node->num_split(options->num_splits); + + assert(outputs.size() > 0); + assert(int32_t(outputs.size()) == options->num_splits); + { + // Let's use name of output 0 as Split name + const circle::TensorT &output_tensor = *tensors[outputs[0]]; + node->name(tensor_name(output_tensor)); + node->op_version(opcodes[op.opcode_index].get()->version); + + // NOTE We don't set quantization for Split itself but to virtual outputs + } + + // Create virtual outputs of Split + for (int32_t n = 0; n < options->num_splits; ++n) + { + const circle::TensorT &output_tensor = *tensors[outputs[n]]; + + auto *nodeout = graph->nodes()->create<CircleSplitVOut>(); + copy_tensor_attributes(output_tensor, nodeout); + // mark shape_status + if (tensors_ptr->Get(outputs[n])->shape() == nullptr) + nodeout->shape_status(ShapeStatus::NOSHAPE); + else + nodeout->shape_status(ShapeStatus::VALID); + + nodeout->input(node); + nodeout->index(n); + + context->nodefinder()->enroll(outputs[n], nodeout); + } +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSqrt.cpp b/compiler/luci/import/src/Nodes/CircleSqrt.cpp new file mode 100644 index 000000000..8a90f6691 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSqrt.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSqrt.h" + +#include <luci/IR/Nodes/CircleSqrt.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleSqrtGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 1) + return false; + + return true; +} + +CircleNode *CircleSqrtGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleSqrt>(); + node->x(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSquare.cpp b/compiler/luci/import/src/Nodes/CircleSquare.cpp new file mode 100644 index 000000000..8398548b6 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSquare.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSquare.h" + +#include <luci/IR/Nodes/CircleSquare.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleSquareGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + if (inputs.size() != 1) + return false; + + // Must be one of the following types + // bfloat16, half (float16), float32, float64, complex64, complex128 + // Currently, circle supports float16, float32, complex64 + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + switch (tensor->type) + { + case circle::TensorType_INT32: + case circle::TensorType_INT64: + case circle::TensorType_FLOAT16: + case circle::TensorType_FLOAT32: + case circle::TensorType_FLOAT64: + case circle::TensorType_COMPLEX64: + break; + default: + return false; + } + + return true; +} + +CircleNode *CircleSquareGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleSquare>(); + node->x(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSquaredDifference.cpp b/compiler/luci/import/src/Nodes/CircleSquaredDifference.cpp new file mode 100644 index 000000000..93ce959e2 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSquaredDifference.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSquaredDifference.h" + +#include <luci/IR/Nodes/CircleSquaredDifference.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleSquaredDifferenceGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + return false; + + if (outputs.size() != 1) + return false; + + // Inputs must be one of the following types + // bfloat16, half(float16), float32, float64, int32, int64, complex64, complex128 + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + switch (tensor->type) + { + case circle::TensorType_FLOAT16: + case circle::TensorType_FLOAT32: + case circle::TensorType_FLOAT64: + case circle::TensorType_INT32: + case circle::TensorType_INT64: + case circle::TensorType_COMPLEX64: + break; + // TODO support bfloat16, complex128 + default: + return false; + } + + // Input types must match + if (tensors.at(inputs[0])->type != tensors.at(inputs[1])->type) + return false; + + // Input and output types must match + if (tensors.at(inputs[0])->type != tensors.at(outputs[0])->type) + return false; + + return true; +} + +CircleNode *CircleSquaredDifferenceGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleSquaredDifference>(); + node->x(inputs[0]); + node->y(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSqueeze.cpp b/compiler/luci/import/src/Nodes/CircleSqueeze.cpp new file mode 100644 index 000000000..a5252d0bb --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSqueeze.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSqueeze.h" + +#include <luci/IR/Nodes/CircleConst.h> +#include <luci/IR/Nodes/CircleSqueeze.h> + +namespace luci +{ + +bool CircleSqueezeGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 1) + return false; + + if (args.op.outputs.size() != 1) + return false; + + return true; +} + +CircleNode *CircleSqueezeGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleSqueeze>(); + node->input(inputs[0]); + + const auto *options = op.builtin_options.AsSqueezeOptions(); + assert(options); + + node->squeeze_dims(options->squeeze_dims); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleStridedSlice.cpp b/compiler/luci/import/src/Nodes/CircleStridedSlice.cpp new file mode 100644 index 000000000..95e446704 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleStridedSlice.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleStridedSlice.h" + +#include <luci/IR/Nodes/CircleStridedSlice.h> + +#include <loco.h> + +#include <cassert> + +namespace luci +{ + +bool CircleStridedSliceGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 4) + return false; + if (args.op.outputs.size() != 1) + return false; + + // TODO check shapes and types + + return true; +} + +CircleNode *CircleStridedSliceGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleStridedSlice>(); + node->input(inputs[0]); + node->begin(inputs[1]); + node->end(inputs[2]); + node->strides(inputs[3]); + + const auto *options = op.builtin_options.AsStridedSliceOptions(); + node->begin_mask(options->begin_mask); + node->end_mask(options->end_mask); + node->ellipsis_mask(options->ellipsis_mask); + node->new_axis_mask(options->new_axis_mask); + node->shrink_axis_mask(options->shrink_axis_mask); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleSum.cpp b/compiler/luci/import/src/Nodes/CircleSum.cpp new file mode 100644 index 000000000..b4865de59 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleSum.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleSum.h" + +#include <luci/IR/Nodes/CircleSum.h> + +namespace luci +{ + +bool CircleSumGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 2) + return false; + + return true; +} + +CircleNode *CircleSumGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleSum>(); + node->input(inputs[0]); + node->reduction_indices(inputs[1]); + + const auto *options = op.builtin_options.AsReducerOptions(); + node->keep_dims(options->keep_dims); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleTanh.cpp b/compiler/luci/import/src/Nodes/CircleTanh.cpp new file mode 100644 index 000000000..8986378c4 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleTanh.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleTanh.h" + +#include <luci/IR/Nodes/CircleTanh.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleTanhGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + if (inputs.size() != 1) + return false; + + // Must be one of the following types + // bfloat16, half (float16), float32, float64, complex64, complex128 + // Currently, circle supports float16, float32, complex64 + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + switch (tensor->type) + { + case circle::TensorType_FLOAT16: + case circle::TensorType_FLOAT32: + case circle::TensorType_COMPLEX64: + break; + default: + return false; + } + + return true; +} + +CircleNode *CircleTanhGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleTanh>(); + node->x(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleTile.cpp b/compiler/luci/import/src/Nodes/CircleTile.cpp new file mode 100644 index 000000000..91054ce7f --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleTile.cpp @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleTile.h" + +#include <luci/IR/Nodes/CircleTile.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleTileGraphBuilder::validate(const ValidateArgs &args) const +{ + auto inputs = args.op.inputs; + auto outputs = args.op.outputs; + + if (inputs.size() != 2) + return false; + + if (outputs.size() != 1) + return false; + + // Multiples (inputs[1]) must be one of the following types + // int32, int64 + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[1]); + switch (tensor->type) + { + case circle::TensorType_INT32: + case circle::TensorType_INT64: + break; + default: + return false; + } + + // Type of input and output must be the same + if (tensors.at(inputs[0])->type != tensors.at(outputs[0])->type) + return false; + + return true; +} + +CircleNode *CircleTileGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleTile>(); + node->input(inputs[0]); + node->multiples(inputs[1]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleTopKV2.cpp b/compiler/luci/import/src/Nodes/CircleTopKV2.cpp new file mode 100644 index 000000000..5c1051c43 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleTopKV2.cpp @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleTopKV2.h" + +#include <luci/IR/Nodes/CircleTopKV2.h> +#include <luci/IR/Nodes/CircleTopKV2Out.h> + +#include <loco.h> +#include <oops/UserExn.h> + +namespace luci +{ + +bool CircleTopKV2GraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 2) + return false; + if (outputs.size() != 2) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[1]); + if (tensor->type != circle::TensorType_INT32) + return false; + + return true; +} + +/** + * @brief TopKV2 Node builder + * + * @note Current loco does not provide multiple outputs + * We will create multiple CircleTopKV2Out nodes to emulate this + * For two outputs that may look like this + * + * --- CircleTopKV2--- FullyConnected --- + * \- FullyConnected --- + * + * will be created like this + * + * --- CircleTopKV2 --- CircleTopKV2Out --- FullyConnected --- + * \- CircleTopKV2Out --- FullyConnected --- + */ + +void CircleTopKV2GraphBuilder::build(const circle::OperatorT &op, + GraphBuilderContext *context) const +{ + assert(context != nullptr); + + auto graph = context->graph(); + + const std::vector<int32_t> &inputs = op.inputs; + const std::vector<int32_t> &outputs = op.outputs; + const auto &tensors = context->reader()->tensors(); + const auto &opcodes = context->reader()->opcodes(); + auto tensors_ptr = context->reader()->tensors_ptr(); + assert(tensors_ptr != nullptr); + + std::vector<CircleNode *> input_nodes; + for (const int32_t input_tensor_index : inputs) + { + input_nodes.push_back(context->nodefinder()->node(input_tensor_index)); + } + + // Create CircleTopKV2 + auto node = graph->nodes()->create<CircleTopKV2>(); + node->input(input_nodes[0]); + node->k(input_nodes[1]); + + assert(outputs.size() == 2); + { + // Let's use name of output 0 as TopKV2 name + const circle::TensorT &output_tensor = *tensors[outputs[0]]; + node->name(tensor_name(output_tensor)); + node->op_version(opcodes[op.opcode_index].get()->version); + + // NOTE We don't set quantization for TopKV2 itself but to virtual outputs + } + + // Create virtual outputs of TopKV2 + for (size_t n = 0; n < outputs.size(); ++n) + { + const circle::TensorT &output_tensor = *tensors[outputs[n]]; + + auto *nodeout = graph->nodes()->create<CircleTopKV2Out>(); + copy_tensor_attributes(output_tensor, nodeout); + // mark shape_status + if (tensors_ptr->Get(outputs[n])->shape() == nullptr) + nodeout->shape_status(ShapeStatus::NOSHAPE); + else + nodeout->shape_status(ShapeStatus::VALID); + + nodeout->input(node); + nodeout->index(n); + + context->nodefinder()->enroll(outputs[n], nodeout); + } +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleTransposeConv.cpp b/compiler/luci/import/src/Nodes/CircleTransposeConv.cpp new file mode 100644 index 000000000..7bdf46daa --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleTransposeConv.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleTransposeConv.h" + +#include <luci/IR/Nodes/CircleTransposeConv.h> + +#include <loco.h> + +#include <cassert> + +namespace luci +{ + +bool CircleTransposeConvGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 3) + return false; + + return true; +} + +CircleNode *CircleTransposeConvGraphBuilder::build_node(const circle::OperatorT &op, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleTransposeConv>(); + + node->inputSizes(inputs[0]); + node->filter(inputs[1]); + node->outBackprop(inputs[2]); + + const auto *options = op.builtin_options.AsTransposeConvOptions(); + node->padding(luci_padding(options->padding)); + node->stride()->w(options->stride_w); + node->stride()->h(options->stride_h); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleUnpack.cpp b/compiler/luci/import/src/Nodes/CircleUnpack.cpp new file mode 100644 index 000000000..c4282e24f --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleUnpack.cpp @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleUnpack.h" + +#include <luci/IR/Nodes/CircleUnpack.h> +#include <luci/IR/Nodes/CircleUnpackOut.h> + +#include <luci/UserSettings.h> +#include <luci/Log.h> + +#include <loco.h> +#include <oops/UserExn.h> + +namespace luci +{ + +bool CircleUnpackGraphBuilder::validate(const ValidateArgs &args) const +{ + LOGGER(l); + + auto settings = luci::UserSettings::settings(); + + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + const auto *options = args.op.builtin_options.AsUnpackOptions(); + + if (inputs.size() != 1) + return false; + + // NOTE real models may have mismatch + if (static_cast<int32_t>(outputs.size()) != options->num) + { + if (settings->get(luci::UserSettings::Key::DisableValidation)) + { + const auto &tensors = args.reader.tensors(); + const circle::TensorT &output_tensor = *tensors[outputs[0]]; + auto name = tensor_name(output_tensor); + WARN(l) << "Warning: import Unpack(" << name << ") 'num' is not same as outputs used"; + } + else + return false; + } + + if (options->num < 0) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor = tensors.at(inputs[0]); + const auto &shape = tensor->shape; + auto shape_size = static_cast<int32_t>(shape.size()); + if (shape_size > 0) + { + // NOTE for unknown shape, shape_size is 0 + if (options->axis < -shape_size || options->axis >= shape_size) + return false; + } + + return true; +} + +/** + * @brief Unpack Node builder + * + * @note Current loco does not provide multiple outputs + * We will create multiple CircleUnpackOut nodes to emulate this + * For two outputs that may look like this + * + * --- CircleUnpack --- FullyConnected --- + * \- FullyConnected --- + * + * will be created like this + * + * --- CircleUnpack --- CircleUnpackOut --- FullyConnected --- + * \- CircleUnpackOut --- FullyConnected --- + */ + +void CircleUnpackGraphBuilder::build(const circle::OperatorT &op, + GraphBuilderContext *context) const +{ + assert(context != nullptr); + + auto graph = context->graph(); + + const std::vector<int32_t> &inputs = op.inputs; + const std::vector<int32_t> &outputs = op.outputs; + const auto &tensors = context->reader()->tensors(); + const auto &opcodes = context->reader()->opcodes(); + auto tensors_ptr = context->reader()->tensors_ptr(); + assert(tensors_ptr != nullptr); + + // NOTE Unpack has only one input so running a loop is not necessary + // This is provided as a reference for other Ops as a reference + std::vector<CircleNode *> input_nodes; + for (const int32_t input_tensor_index : inputs) + { + input_nodes.push_back(context->nodefinder()->node(input_tensor_index)); + } + + // Create CircleUnpack + CircleUnpack *node = graph->nodes()->create<CircleUnpack>(); + node->value(input_nodes[0]); + + const auto *options = op.builtin_options.AsUnpackOptions(); + node->num(options->num); + node->axis(options->axis); + + assert(outputs.size() > 0); + { + // Let's use name of output 0 as Unpack name + const circle::TensorT &output_tensor = *tensors[outputs[0]]; + node->name(tensor_name(output_tensor)); + node->op_version(opcodes[op.opcode_index].get()->version); + + // NOTE We don't set quantization for Unpack itself but to virtual outputs + } + + // Create virtual outputs of Unpack + for (int32_t n = 0; n < options->num; ++n) + { + const circle::TensorT &output_tensor = *tensors[outputs[n]]; + + auto *nodeout = graph->nodes()->create<CircleUnpackOut>(); + copy_tensor_attributes(output_tensor, nodeout); + // mark shape_status + if (tensors_ptr->Get(outputs[n])->shape() == nullptr) + nodeout->shape_status(ShapeStatus::NOSHAPE); + else + nodeout->shape_status(ShapeStatus::VALID); + + nodeout->input(node); + nodeout->index(n); + + context->nodefinder()->enroll(outputs[n], nodeout); + } +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleWhere.cpp b/compiler/luci/import/src/Nodes/CircleWhere.cpp new file mode 100644 index 000000000..a13c4d6c9 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleWhere.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleWhere.h" + +#include <luci/IR/Nodes/CircleWhere.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleWhereGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto &outputs = args.op.outputs; + + if (inputs.size() != 1) + return false; + + if (outputs.size() != 1) + return false; + + const auto &tensors = args.reader.tensors(); + const auto &tensor_condition = tensors.at(inputs[0]); + const auto &tensor_out = tensors.at(outputs[0]); + + if (tensor_condition->type != circle::TensorType_BOOL) + return false; + + if (tensor_out->type != circle::TensorType_INT64) + return false; + + return true; +} + +CircleNode *CircleWhereGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleWhere>(); + node->condition(inputs[0]); + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleWhile.cpp b/compiler/luci/import/src/Nodes/CircleWhile.cpp new file mode 100644 index 000000000..aead25071 --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleWhile.cpp @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleWhile.h" + +#include <luci/IR/Nodes/CircleWhile.h> +#include <luci/IR/Nodes/CircleWhileOut.h> + +#include <loco.h> +#include <oops/UserExn.h> + +namespace luci +{ + +bool CircleWhileGraphBuilder::validate(const ValidateArgs &args) const +{ + const auto &inputs = args.op.inputs; + const auto *options = args.op.builtin_options.AsWhileOptions(); + + if (inputs.size() != args.op.outputs.size()) + return false; + + auto num_graphs = static_cast<int32_t>(args.reader.num_subgraph()); + if (options->cond_subgraph_index >= num_graphs) + return false; + if (options->body_subgraph_index >= num_graphs) + return false; + + return true; +} + +/** + * @brief While Node builder + * + * @note Current loco does not provide multiple outputs + * We will create multiple CircleWhileOut nodes to emulate this + * For two outputs that may look like this + * + * --- CircleWhile --- Node --- + * \- Node --- + * + * will be created like this + * + * --- CircleWhile --- CircleWhileOut --- Node --- + * \- CircleWhileOut --- Node --- + */ + +void CircleWhileGraphBuilder::build(const circle::OperatorT &op, GraphBuilderContext *context) const +{ + assert(context != nullptr); + + auto graph = context->graph(); + + const std::vector<int32_t> &inputs = op.inputs; + const std::vector<int32_t> &outputs = op.outputs; + const auto &tensors = context->reader()->tensors(); + const auto &opcodes = context->reader()->opcodes(); + + std::vector<CircleNode *> input_nodes; + for (const int32_t input_tensor_index : inputs) + { + auto input_node = context->nodefinder()->node(input_tensor_index); + assert(input_node != nullptr); + input_nodes.push_back(input_node); + } + + uint32_t input_count = inputs.size(); + uint32_t output_count = outputs.size(); + + // Create CircleWhile + CircleWhile *node = graph->nodes()->create<CircleWhile>(input_count, output_count); + + for (uint32_t idx = 0; idx < input_count; ++idx) + { + node->input(idx, input_nodes[idx]); + } + + const auto *options = op.builtin_options.AsWhileOptions(); + node->cond_branch(options->cond_subgraph_index); + node->body_branch(options->body_subgraph_index); + + assert(outputs.size() > 0); + { + // Lets use name of output 0 as While name + const circle::TensorT &output_tensor = *tensors[outputs[0]]; + node->name(tensor_name(output_tensor)); + node->op_version(opcodes[op.opcode_index].get()->version); + + // NOTE We don't set quantization for While itself but to virtual outputs + } + + // Create virtual outputs of While + for (uint32_t n = 0; n < output_count; ++n) + { + const circle::TensorT &output_tensor = *tensors[outputs[n]]; + + auto *nodeout = graph->nodes()->create<CircleWhileOut>(); + + nodeout->input(node); + nodeout->index(n); + + copy_tensor_attributes(output_tensor, nodeout); + + // Note: leave shape_status to UNKNOWN to run shape inference + + context->nodefinder()->enroll(outputs[n], nodeout); + } +} + +} // namespace luci diff --git a/compiler/luci/import/src/Nodes/CircleZerosLike.cpp b/compiler/luci/import/src/Nodes/CircleZerosLike.cpp new file mode 100644 index 000000000..4362925cd --- /dev/null +++ b/compiler/luci/import/src/Nodes/CircleZerosLike.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Import/Nodes/CircleZerosLike.h" + +#include <luci/IR/Nodes/CircleZerosLike.h> + +#include <loco.h> + +namespace luci +{ + +bool CircleZerosLikeGraphBuilder::validate(const ValidateArgs &args) const +{ + if (args.op.inputs.size() != 1) + return false; + + if (args.op.outputs.size() != 1) + return false; + + return true; +} + +CircleNode *CircleZerosLikeGraphBuilder::build_node(const circle::OperatorT &, + const std::vector<CircleNode *> &inputs, + loco::Graph *graph) const +{ + auto *node = graph->nodes()->create<CircleZerosLike>(); + node->input(inputs[0]); + + // ZerosLikeOptinos are empty + + return node; +} + +} // namespace luci diff --git a/compiler/luci/import/src/PostImport.cpp b/compiler/luci/import/src/PostImport.cpp new file mode 100644 index 000000000..f436b48e8 --- /dev/null +++ b/compiler/luci/import/src/PostImport.cpp @@ -0,0 +1,354 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "PostImport.h" + +#include "luci/Import/CircleReader.h" + +#include <luci/IR/CircleNodes.h> +#include <luci/IR/CircleDialect.h> +#include <luci/IR/CircleNodeVisitor.h> +#include <luci/Log.h> + +#include <loco.h> +#include <oops/InternalExn.h> + +namespace +{ + +/** + * @brief FixInterGraphNodes will fix inter graph connections for each Nodes + */ +class FixInterGraphNodes final : public luci::CircleNodeMutableVisitor<void> +{ +public: + FixInterGraphNodes(const luci::Module *m, const luci::CircleReader &r) : _module(m), _reader(r) {} + + /** + * @note This will set Graph* to every CircleIf nodes 'else' and 'then' + */ + void visit(luci::CircleIf *node) final + { + LOGGER(l); + INFO(l) << "CircleIf " << node->name() << std::endl; + + auto then_branch = node->then_branch(); + auto else_branch = node->else_branch(); + auto num_graphs = static_cast<int32_t>(_module->size()); + (void)num_graphs; + + assert(num_graphs > 0); + assert(then_branch >= 0 && then_branch < num_graphs); + assert(else_branch >= 0 && else_branch < num_graphs); + + auto then_graph = _module->graph(then_branch); + auto else_graph = _module->graph(else_branch); + assert(then_graph != nullptr); + assert(else_graph != nullptr); + + node->then_graph(then_graph); + node->else_graph(else_graph); + } + + void visit(luci::CircleWhile *node) final + { + LOGGER(l); + INFO(l) << "CircleWhile " << node->name() << std::endl; + + auto cond_branch = node->cond_branch(); + auto body_branch = node->body_branch(); + auto num_graphs = static_cast<int32_t>(_module->size()); + (void)num_graphs; + + assert(num_graphs > 0); + assert(cond_branch >= 0 && cond_branch < num_graphs); + assert(body_branch >= 0 && body_branch < num_graphs); + + auto cond_graph = _module->graph(cond_branch); + auto body_graph = _module->graph(body_branch); + assert(cond_graph != nullptr); + assert(body_graph != nullptr); + + node->cond_graph(cond_graph); + node->body_graph(body_graph); + } + + void visit(luci::CircleNode *) final + { + // DO NOTHING + } + +private: + const luci::Module *_module; + const luci::CircleReader &_reader; +}; + +/** + * @brief FixInterGraph will fix inter graph connections + */ +class FixInterGraph final +{ +public: + void run(loco::Graph *g, const luci::Module *m, const luci::CircleReader &r) + { + for (auto node : loco::postorder_traversal(loco::output_nodes(g))) + { + if (recognize(node->dialect())) + { + auto cn = loco::must_cast<luci::CircleNode *>(node); + + fix(cn, m, r); + } + } + } + +private: + bool recognize(const loco::Dialect *dialect) { return (dialect == luci::CircleDialect::get()); } + + void fix(luci::CircleNode *node, const luci::Module *module, const luci::CircleReader &reader) + { + FixInterGraphNodes fix(module, reader); + node->accept(&fix); + } +}; + +} // namespace + +namespace +{ +/** + * @brief ValidateNodeProp will validate inter graph connections for each Nodes + */ +class ValidateNodeProp final : public luci::CircleNodeMutableVisitor<void> +{ +public: + ValidateNodeProp(const luci::Module *m, const luci::CircleReader &r) : _module(m), _reader(r) {} + + /** + * @note Validate CircleIf node 'else' and 'then' graph input/output count + * shape and type + */ + void visit(luci::CircleIf *node) final + { + LOGGER(l); + INFO(l) << "CircleIf " << node->name() << std::endl; + + auto then_graph = node->then_graph(); + auto else_graph = node->else_graph(); + assert(then_graph != nullptr); + assert(else_graph != nullptr); + + // TODO support for differnt shape; but how? + // NODE Shape/Type inference assume below conditions + + // Check both "then" and "else" subgraph outputs are same in count + auto then_outputs = loco::output_nodes(then_graph); // CircleOutput nodes + auto else_outputs = loco::output_nodes(else_graph); + if (then_outputs.size() != else_outputs.size()) + { + INTERNAL_EXN("CircleIf THEN and ELSE Graph are not same in size"); + } + + // check outputs have same shape and dtype + auto then_graph_outputs = then_graph->outputs(); // loco::GraphOutput items + auto else_graph_outputs = else_graph->outputs(); + for (size_t idx = 0; idx < then_outputs.size(); ++idx) + { + auto then_out = loco::must_cast<luci::CircleOutput *>(then_outputs.at(idx)); + auto else_out = loco::must_cast<luci::CircleOutput *>(else_outputs.at(idx)); + + auto then_graph_output = then_graph_outputs->at(then_out->index()); + auto else_graph_output = else_graph_outputs->at(else_out->index()); + if (!(*then_graph_output->shape() == *else_graph_output->shape())) + { + INTERNAL_EXN_V("CircleIf THEN and ELSE Graph Output shape mismatch ", idx); + } + if (then_graph_output->dtype() != else_graph_output->dtype()) + { + INTERNAL_EXN_V("CircleIf THEN and ELSE Graph Output type mismatch ", idx); + } + } + } + + /** + * @note Validate CircleWhile node 'cond' and 'body' graph input/output count + * shape and type + */ + void visit(luci::CircleWhile *node) final + { + LOGGER(l); + INFO(l) << "CircleWhile " << node->name() << std::endl; + + auto cond_graph = node->cond_graph(); + auto body_graph = node->body_graph(); + assert(cond_graph != nullptr); + assert(body_graph != nullptr); + + // Check input of "cond" and input/output of "body" subgraph have the same size + auto cond_inputs = loco::input_nodes(cond_graph); + auto cond_outputs = loco::output_nodes(cond_graph); + auto body_inputs = loco::input_nodes(body_graph); + auto body_outputs = loco::output_nodes(body_graph); + if (cond_inputs.size() != body_outputs.size()) + { + INTERNAL_EXN("CircleWhile COND input and BODY output have different sizes"); + } + if (cond_inputs.size() != body_inputs.size()) + { + INTERNAL_EXN("CircleWhile COND input and BODY input have different sizes"); + } + if (cond_outputs.size() != 1) + { + INTERNAL_EXN("CircleWhile COND output must have size 1"); + } + auto cond_out = loco::must_cast<luci::CircleOutput *>(cond_outputs.at(0)); + if (cond_out->dtype() != loco::DataType::BOOL) + { + INTERNAL_EXN("CircleWhile COND output must have bool type"); + } + + // input of "cond" and input/output of "body" subgraph must have the same shape and type + // First we compare input of "cond" with input of "body" + auto cond_graph_inputs = cond_graph->inputs(); + auto body_graph_inputs = body_graph->inputs(); + for (size_t idx = 0; idx < cond_inputs.size(); ++idx) + { + auto cond_in = loco::must_cast<luci::CircleInput *>(cond_inputs.at(idx)); + auto body_in = loco::must_cast<luci::CircleInput *>(body_inputs.at(idx)); + + auto cond_graph_input = cond_graph_inputs->at(cond_in->index()); + auto body_graph_input = body_graph_inputs->at(body_in->index()); + if ((cond_in->rank() != body_in->rank())) + { + INTERNAL_EXN_V("CircleWhile COND input and BODY input shape mismatch ", idx); + } + if (cond_in->rank() > 0 && body_in->rank() > 0) + { + if (!(*cond_graph_input->shape() == *body_graph_input->shape())) + { + INTERNAL_EXN_V("CircleWhile COND input and BODY input shape mismatch ", idx); + } + } + if (cond_in->dtype() != body_in->dtype()) + { + INTERNAL_EXN_V("CircleWhile COND input and BODY input type mismatch ", idx); + } + } + + // Next we compare input of "cond" with output of "body" + auto body_graph_outputs = body_graph->outputs(); + for (size_t idx = 0; idx < cond_inputs.size(); ++idx) + { + auto cond_in = loco::must_cast<luci::CircleInput *>(cond_inputs.at(idx)); + auto body_out = loco::must_cast<luci::CircleOutput *>(body_outputs.at(idx)); + + auto cond_graph_input = cond_graph_inputs->at(cond_in->index()); + auto body_graph_output = body_graph_outputs->at(body_out->index()); + if ((cond_in->rank() != body_out->rank())) + { + INTERNAL_EXN_V("CircleWhile COND input and BODY output shape mismatch ", idx); + } + if (cond_in->rank() > 0 && body_out->rank() > 0) + { + if (!(*cond_graph_input->shape() == *body_graph_output->shape())) + { + INTERNAL_EXN_V("CircleWhile COND input and BODY output shape mismatch ", idx); + } + } + if (cond_in->dtype() != body_out->dtype()) + { + INTERNAL_EXN_V("CircleWhile COND input and BODY output type mismatch ", idx); + } + } + } + + void visit(luci::CircleNode *) final + { + // DO NOTHING + } + +private: + const luci::Module *_module; + const luci::CircleReader &_reader; +}; + +/** + * @brief ValidateGraphProp will validate inter graph node properties + */ +class ValidateGraphProp final +{ +public: + void run(loco::Graph *g, const luci::Module *m, const luci::CircleReader &r) + { + for (auto node : loco::postorder_traversal(loco::output_nodes(g))) + { + if (recognize(node->dialect())) + { + auto cn = loco::must_cast<luci::CircleNode *>(node); + + eval(cn, m, r); + } + } + } + +private: + bool recognize(const loco::Dialect *dialect) { return (dialect == luci::CircleDialect::get()); } + + void eval(luci::CircleNode *node, const luci::Module *module, const luci::CircleReader &reader) + { + ValidateNodeProp val(module, reader); + node->accept(&val); + } +}; + +} // namespace + +namespace luci +{ + +/** + * @brief Do post import actions + */ +void post_import_graph(luci::Module *module, const luci::CircleReader &reader) +{ + LOGGER(l); + + auto count = module->size(); + + for (size_t s = 0; s < count; ++s) + { + auto g = module->graph(s); + assert(g != nullptr); + + INFO(l) << "--- FixInterGraph " << g->name() << "-------------------------"; + FixInterGraph fix; + fix.run(g, module, reader); + } + + for (size_t s = 0; s < count; ++s) + { + auto g = module->graph(s); + assert(g != nullptr); + + INFO(l) << "--- ValidateGraphProp " << g->name() << "---------------------"; + ValidateGraphProp prop; + prop.run(g, module, reader); + } + + INFO(l) << "--- post_import_graph done -------------------------------------"; +} + +} // namespace luci diff --git a/compiler/luci/import/src/PostImport.h b/compiler/luci/import/src/PostImport.h new file mode 100644 index 000000000..c719c588a --- /dev/null +++ b/compiler/luci/import/src/PostImport.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_POST_IMPORT_H__ +#define __LUCI_POST_IMPORT_H__ + +#include "luci/Import/CircleReader.h" + +#include "luci/IR/Module.h" + +namespace luci +{ + +/** + * @brief Do post import actions + */ +void post_import_graph(luci::Module *module, const luci::CircleReader &reader); + +} // namespace luci + +#endif // __LUCI_POST_IMPORT_H__ diff --git a/compiler/luci/lang/CMakeLists.txt b/compiler/luci/lang/CMakeLists.txt index 564e777fb..32d0a890d 100644 --- a/compiler/luci/lang/CMakeLists.txt +++ b/compiler/luci/lang/CMakeLists.txt @@ -7,6 +7,7 @@ target_include_directories(luci_lang PRIVATE src) target_include_directories(luci_lang PUBLIC include) target_link_libraries(luci_lang PUBLIC loco) target_link_libraries(luci_lang PUBLIC oops) +target_link_libraries(luci_lang PRIVATE logo) target_link_libraries(luci_lang PRIVATE nncc_common) install(TARGETS luci_lang DESTINATION lib) @@ -20,3 +21,4 @@ nnas_find_package(GTest REQUIRED) GTest_AddTest(luci_lang_test ${TESTS}) target_include_directories(luci_lang_test PRIVATE src) target_link_libraries(luci_lang_test luci_lang) +target_link_libraries(luci_lang_test logo) diff --git a/compiler/luci/lang/include/luci/IR/AttrDilation.h b/compiler/luci/lang/include/luci/IR/AttrDilation.h new file mode 100644 index 000000000..c2b28d77d --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/AttrDilation.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_ATTRDILATION_H__ +#define __LUCI_IR_ATTRDILATION_H__ + +#include <stdint.h> + +namespace luci +{ + +class Dilation final +{ +public: + Dilation() : _w(1), _h(1) {} + + int32_t w() const { return _w; } + void w(int32_t w) { _w = w; } + + int32_t h() const { return _h; } + void h(int32_t h) { _h = h; } + +private: + int32_t _w; + int32_t _h; +}; + +} // namespace luci + +#endif // __LUCI_IR_ATTRDILATION_H__ diff --git a/compiler/luci/lang/include/luci/IR/AttrMirrorPadMode.h b/compiler/luci/lang/include/luci/IR/AttrMirrorPadMode.h new file mode 100644 index 000000000..7ca9d5d99 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/AttrMirrorPadMode.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_ATTR_MIRROR_PAD_MODE_H__ +#define __LUCI_IR_ATTR_MIRROR_PAD_MODE_H__ + +namespace luci +{ + +enum class MirrorPadMode +{ + UNDEFINED, // This is not defined by Circle. This was added to prevent programming error. + + REFLECT, + SYMMETRIC, +}; + +} // namespace luci + +#endif // __LUCI_IR_ATTR_MIRROR_PAD_MODE_H__ diff --git a/compiler/luci/lang/include/luci/IR/CircleNodeDecl.h b/compiler/luci/lang/include/luci/IR/CircleNodeDecl.h index b87bdf9d0..967103e3c 100644 --- a/compiler/luci/lang/include/luci/IR/CircleNodeDecl.h +++ b/compiler/luci/lang/include/luci/IR/CircleNodeDecl.h @@ -17,8 +17,10 @@ #ifndef __LUCI_IR_CIRCLENODEDECL_H__ #define __LUCI_IR_CIRCLENODEDECL_H__ -#include <loco/IR/Node.h> #include <loco/IR/Dialect.h> +#include <loco/IR/Node.h> +#include <loco/IR/NodeMixins.h> +#include <luci/IR/PropertyShapeStatus.h> #include "CircleOpcode.h" #include "CircleNodeVisitor.forward.h" @@ -31,7 +33,9 @@ namespace luci using NodeName = std::string; -struct CircleNode : public loco::Node +struct CircleNode : public loco::Node, + public loco::NodeMixin<loco::NodeTrait::DataType>, + public loco::NodeMixin<loco::NodeTrait::TensorShape> { virtual ~CircleNode() = default; @@ -50,9 +54,17 @@ struct CircleNode : public loco::Node _quantparam = std::move(quantparam); } + ShapeStatus shape_status(void) const { return _shape_status; } + void shape_status(ShapeStatus ss) { _shape_status = ss; } + + int32_t op_version(void) const { return _op_version; } + void op_version(int32_t op_version) { _op_version = op_version; } + private: NodeName _name; std::unique_ptr<CircleQuantParam> _quantparam; + ShapeStatus _shape_status{ShapeStatus::UNDEFINED}; + int32_t _op_version = 1; }; template <CircleOpcode Code> struct CircleNodeImpl : public CircleNode diff --git a/compiler/luci/lang/include/luci/IR/CircleNodeImpl.h b/compiler/luci/lang/include/luci/IR/CircleNodeImpl.h index bdcfc9c9d..a6b9488db 100644 --- a/compiler/luci/lang/include/luci/IR/CircleNodeImpl.h +++ b/compiler/luci/lang/include/luci/IR/CircleNodeImpl.h @@ -18,7 +18,6 @@ #define __LUCI_IR_CIRCLENODEIMPL_H__ #include "CircleNodes.h" -#include "CircleNodeVisitor.h" #include <oops/InternalExn.h> diff --git a/compiler/luci/lang/include/luci/IR/CircleNodes.h b/compiler/luci/lang/include/luci/IR/CircleNodes.h index cc822842b..3b31149b2 100644 --- a/compiler/luci/lang/include/luci/IR/CircleNodes.h +++ b/compiler/luci/lang/include/luci/IR/CircleNodes.h @@ -19,42 +19,124 @@ #include "Nodes/CircleAbs.h" #include "Nodes/CircleAdd.h" +#include "Nodes/CircleAddN.h" #include "Nodes/CircleArgMax.h" +#include "Nodes/CircleArgMin.h" #include "Nodes/CircleAveragePool2D.h" +#include "Nodes/CircleBatchMatMul.h" #include "Nodes/CircleBatchToSpaceND.h" +#include "Nodes/CircleCast.h" +#include "Nodes/CircleCeil.h" #include "Nodes/CircleConcatenation.h" #include "Nodes/CircleConst.h" #include "Nodes/CircleConv2D.h" #include "Nodes/CircleCos.h" +#include "Nodes/CircleCustom.h" +#include "Nodes/CircleDepthToSpace.h" #include "Nodes/CircleDepthwiseConv2D.h" #include "Nodes/CircleDiv.h" +#include "Nodes/CircleElu.h" #include "Nodes/CircleEqual.h" #include "Nodes/CircleExp.h" +#include "Nodes/CircleExpandDims.h" +#include "Nodes/CircleFill.h" +#include "Nodes/CircleFloor.h" +#include "Nodes/CircleFloorDiv.h" +#include "Nodes/CircleFloorMod.h" #include "Nodes/CircleFullyConnected.h" #include "Nodes/CircleGather.h" +#include "Nodes/CircleGatherNd.h" +#include "Nodes/CircleGreater.h" +#include "Nodes/CircleGreaterEqual.h" +#include "Nodes/CircleIf.h" +#include "Nodes/CircleL2Normalize.h" +#include "Nodes/CircleL2Pool2D.h" +#include "Nodes/CircleLeakyRelu.h" +#include "Nodes/CircleLess.h" +#include "Nodes/CircleLessEqual.h" +#include "Nodes/CircleLocalResponseNormalization.h" +#include "Nodes/CircleLog.h" +#include "Nodes/CircleLogicalAnd.h" #include "Nodes/CircleLogicalNot.h" #include "Nodes/CircleLogicalOr.h" +#include "Nodes/CircleLogistic.h" +#include "Nodes/CircleLogSoftmax.h" +#include "Nodes/CircleMatrixDiag.h" +#include "Nodes/CircleMatrixSetDiag.h" #include "Nodes/CircleMaximum.h" #include "Nodes/CircleMaxPool2D.h" #include "Nodes/CircleMean.h" +#include "Nodes/CircleMinimum.h" +#include "Nodes/CircleMirrorPad.h" #include "Nodes/CircleMul.h" +#include "Nodes/CircleNeg.h" +#include "Nodes/CircleNotEqual.h" +#include "Nodes/CircleOneHot.h" #include "Nodes/CirclePack.h" #include "Nodes/CirclePad.h" -#include "Nodes/CircleRelu6.h" +#include "Nodes/CirclePow.h" +#include "Nodes/CirclePRelu.h" +#include "Nodes/CircleRange.h" +#include "Nodes/CircleRank.h" +#include "Nodes/CircleReduceAny.h" +#include "Nodes/CircleReduceMax.h" +#include "Nodes/CircleReduceMin.h" +#include "Nodes/CircleReduceProd.h" #include "Nodes/CircleRelu.h" +#include "Nodes/CircleRelu6.h" +#include "Nodes/CircleReluN1To1.h" #include "Nodes/CircleReshape.h" +#include "Nodes/CircleResizeBilinear.h" +#include "Nodes/CircleResizeNearestNeighbor.h" +#include "Nodes/CircleReverseSequence.h" +#include "Nodes/CircleReverseV2.h" +#include "Nodes/CircleRound.h" #include "Nodes/CircleRsqrt.h" +#include "Nodes/CircleScatterNd.h" +#include "Nodes/CircleSegmentSum.h" +#include "Nodes/CircleSelect.h" +#include "Nodes/CircleSelectV2.h" +#include "Nodes/CircleShape.h" +#include "Nodes/CircleSin.h" +#include "Nodes/CircleSlice.h" #include "Nodes/CircleSoftmax.h" +#include "Nodes/CircleSpaceToBatchND.h" +#include "Nodes/CircleSpaceToDepth.h" +#include "Nodes/CircleSparseToDense.h" +#include "Nodes/CircleSplit.h" +#include "Nodes/CircleSplitV.h" #include "Nodes/CircleSqrt.h" +#include "Nodes/CircleSquare.h" #include "Nodes/CircleSquaredDifference.h" +#include "Nodes/CircleSqueeze.h" +#include "Nodes/CircleStridedSlice.h" #include "Nodes/CircleSub.h" -#include "Nodes/CircleTransposeConv.h" +#include "Nodes/CircleSum.h" +#include "Nodes/CircleTanh.h" +#include "Nodes/CircleTile.h" +#include "Nodes/CircleTopKV2.h" #include "Nodes/CircleTranspose.h" +#include "Nodes/CircleTransposeConv.h" +#include "Nodes/CircleUnpack.h" +#include "Nodes/CircleWhere.h" +#include "Nodes/CircleWhile.h" +#include "Nodes/CircleZerosLike.h" // Circle only +#include "Nodes/CircleBCQFullyConnected.h" +#include "Nodes/CircleBCQGather.h" #include "Nodes/CircleInstanceNorm.h" // Virtual nodes #include "Nodes/CircleInput.h" #include "Nodes/CircleOutput.h" +#include "Nodes/CircleCustomOut.h" +#include "Nodes/CircleIfOut.h" +#include "Nodes/CircleUnpackOut.h" +#include "Nodes/CircleSplitOut.h" +#include "Nodes/CircleSplitVOut.h" +#include "Nodes/CircleTopKV2Out.h" +#include "Nodes/CircleWhileOut.h" + +#include <loco/IR/Graph.h> namespace luci { @@ -68,6 +150,18 @@ namespace luci */ void set_new_shape(CircleReshape *node, int32_t *base, uint32_t size); +/// @brief Link GraphOutput with CircleOutput node +void link(loco::GraphOutput *, CircleOutput *); + +/// @brief Link GraphInput with CircleInput node +void link(loco::GraphInput *, CircleInput *); + +/// @brief Find a CircleOutput node with a given output index +CircleOutput *output_node(loco::Graph *g, const loco::GraphOutputIndex &index); + +/// @brief Find a Pull node with a given input index +CircleInput *input_node(loco::Graph *g, const loco::GraphInputIndex &index); + } // namespace luci #endif // __LUCI_IR_CIRCLENODES_H__ diff --git a/compiler/luci/lang/include/luci/IR/CircleNodes.lst b/compiler/luci/lang/include/luci/IR/CircleNodes.lst index ca3f7fb0f..488dcfb89 100644 --- a/compiler/luci/lang/include/luci/IR/CircleNodes.lst +++ b/compiler/luci/lang/include/luci/IR/CircleNodes.lst @@ -13,40 +13,121 @@ CIRCLE_NODE(ABS, luci::CircleAbs) CIRCLE_NODE(ADD, luci::CircleAdd) +CIRCLE_NODE(ADD_N, luci::CircleAddN) CIRCLE_NODE(ARG_MAX, luci::CircleArgMax) +CIRCLE_NODE(ARG_MIN, luci::CircleArgMin) CIRCLE_NODE(AVERAGE_POOL_2D, luci::CircleAveragePool2D) CIRCLE_NODE(BATCH_TO_SPACE_ND, luci::CircleBatchToSpaceND) +CIRCLE_NODE(BATCHMATMUL, luci::CircleBatchMatMul) +CIRCLE_NODE(CAST, luci::CircleCast) +CIRCLE_NODE(CEIL, luci::CircleCeil) CIRCLE_NODE(CONCATENATION, luci::CircleConcatenation) CIRCLE_NODE(CONST, luci::CircleConst) CIRCLE_NODE(CONV_2D, luci::CircleConv2D) CIRCLE_NODE(COS, luci::CircleCos) +CIRCLE_NODE(CUSTOM, luci::CircleCustom) +CIRCLE_NODE(DEPTH_TO_SPACE, luci::CircleDepthToSpace) CIRCLE_NODE(DEPTHWISE_CONV_2D, luci::CircleDepthwiseConv2D) CIRCLE_NODE(DIV, luci::CircleDiv) +CIRCLE_NODE(ELU, luci::CircleElu) CIRCLE_NODE(EQUAL, luci::CircleEqual) CIRCLE_NODE(EXP, luci::CircleExp) +CIRCLE_NODE(EXPAND_DIMS, luci::CircleExpandDims) +CIRCLE_NODE(FILL, luci::CircleFill) +CIRCLE_NODE(FLOOR, luci::CircleFloor) +CIRCLE_NODE(FLOOR_DIV, luci::CircleFloorDiv) +CIRCLE_NODE(FLOOR_MOD, luci::CircleFloorMod) CIRCLE_NODE(FULLY_CONNECTED, luci::CircleFullyConnected) CIRCLE_NODE(GATHER, luci::CircleGather) +CIRCLE_NODE(GATHER_ND, luci::CircleGatherNd) +CIRCLE_NODE(GREATER, luci::CircleGreater) +CIRCLE_NODE(GREATER_EQUAL, luci::CircleGreaterEqual) +CIRCLE_NODE(IF, luci::CircleIf) +CIRCLE_NODE(L2_NORMALIZATION, luci::CircleL2Normalize) +CIRCLE_NODE(L2_POOL_2D, luci::CircleL2Pool2D) +CIRCLE_NODE(LEAKY_RELU, luci::CircleLeakyRelu) +CIRCLE_NODE(LESS, luci::CircleLess) +CIRCLE_NODE(LESS_EQUAL, luci::CircleLessEqual) +CIRCLE_NODE(LOCAL_RESPONSE_NORMALIZATION, luci::CircleLocalResponseNormalization) +CIRCLE_NODE(LOG, luci::CircleLog) +CIRCLE_NODE(LOGICAL_AND, luci::CircleLogicalAnd) CIRCLE_NODE(LOGICAL_NOT, luci::CircleLogicalNot) CIRCLE_NODE(LOGICAL_OR, luci::CircleLogicalOr) -CIRCLE_NODE(MAXIMUM, luci::CircleMaximum) +CIRCLE_NODE(LOGISTIC, luci::CircleLogistic) +CIRCLE_NODE(LOG_SOFTMAX, luci::CircleLogSoftmax) +CIRCLE_NODE(MATRIX_DIAG, luci::CircleMatrixDiag) CIRCLE_NODE(MAX_POOL_2D, luci::CircleMaxPool2D) +CIRCLE_NODE(MATRIX_SET_DIAG, luci::CircleMatrixSetDiag) +CIRCLE_NODE(MAXIMUM, luci::CircleMaximum) CIRCLE_NODE(MEAN, luci::CircleMean) +CIRCLE_NODE(MINIMUM, luci::CircleMinimum) +CIRCLE_NODE(MIRROR_PAD, luci::CircleMirrorPad) CIRCLE_NODE(MUL, luci::CircleMul) +CIRCLE_NODE(NEG, luci::CircleNeg) +CIRCLE_NODE(NOT_EQUAL, luci::CircleNotEqual) +CIRCLE_NODE(ONE_HOT, luci::CircleOneHot) CIRCLE_NODE(PACK, luci::CirclePack) CIRCLE_NODE(PAD, luci::CirclePad) +CIRCLE_NODE(POW, luci::CirclePow) +CIRCLE_NODE(PRELU, luci::CirclePRelu) +CIRCLE_NODE(RANGE, luci::CircleRange) +CIRCLE_NODE(RANK, luci::CircleRank) +CIRCLE_NODE(REDUCE_ANY, luci::CircleReduceAny) +CIRCLE_NODE(REDUCE_MAX, luci::CircleReduceMax) +CIRCLE_NODE(REDUCE_MIN, luci::CircleReduceMin) +CIRCLE_NODE(REDUCE_PROD, luci::CircleReduceProd) CIRCLE_NODE(RELU, luci::CircleRelu) CIRCLE_NODE(RELU6, luci::CircleRelu6) +CIRCLE_NODE(RELU_N1_TO_1, luci::CircleReluN1To1) CIRCLE_NODE(RESHAPE, luci::CircleReshape) +CIRCLE_NODE(RESIZE_BILINEAR, luci::CircleResizeBilinear) +CIRCLE_NODE(RESIZE_NEAREST_NEIGHBOR, luci::CircleResizeNearestNeighbor) +CIRCLE_NODE(REVERSE_SEQUENCE, luci::CircleReverseSequence) +CIRCLE_NODE(REVERSE_V2, luci::CircleReverseV2) +CIRCLE_NODE(ROUND, luci::CircleRound) CIRCLE_NODE(RSQRT, luci::CircleRsqrt) +CIRCLE_NODE(SCATTER_ND, luci::CircleScatterNd) +CIRCLE_NODE(SEGMENT_SUM, luci::CircleSegmentSum) +CIRCLE_NODE(SELECT, luci::CircleSelect) +CIRCLE_NODE(SELECT_V2, luci::CircleSelectV2) +CIRCLE_NODE(SHAPE, luci::CircleShape) +CIRCLE_NODE(SIN, luci::CircleSin) +CIRCLE_NODE(SLICE, luci::CircleSlice) CIRCLE_NODE(SOFTMAX, luci::CircleSoftmax) +CIRCLE_NODE(SPACE_TO_BATCH_ND, luci::CircleSpaceToBatchND) +CIRCLE_NODE(SPACE_TO_DEPTH, luci::CircleSpaceToDepth) +CIRCLE_NODE(SPARSE_TO_DENSE, luci::CircleSparseToDense) +CIRCLE_NODE(SPLIT, luci::CircleSplit) +CIRCLE_NODE(SPLIT_V, luci::CircleSplitV) CIRCLE_NODE(SQRT, luci::CircleSqrt) +CIRCLE_NODE(SQUARE, luci::CircleSquare) CIRCLE_NODE(SQUARED_DIFFERENCE, luci::CircleSquaredDifference) +CIRCLE_NODE(SQUEEZE, luci::CircleSqueeze) +CIRCLE_NODE(STRIDED_SLICE, luci::CircleStridedSlice) CIRCLE_NODE(SUB, luci::CircleSub) -// TODO TFLTanh +CIRCLE_NODE(SUM, luci::CircleSum) +CIRCLE_NODE(TANH, luci::CircleTanh) +CIRCLE_NODE(TILE, luci::CircleTile) +CIRCLE_NODE(TOPK_V2, luci::CircleTopKV2) CIRCLE_NODE(TRANSPOSE, luci::CircleTranspose) CIRCLE_NODE(TRANSPOSE_CONV, luci::CircleTransposeConv) +CIRCLE_NODE(UNPACK, luci::CircleUnpack) +CIRCLE_NODE(WHERE, luci::CircleWhere) +CIRCLE_NODE(WHILE, luci::CircleWhile) +CIRCLE_NODE(ZEROS_LIKE, luci::CircleZerosLike) // Circle Only +CIRCLE_NODE(BCQ_FULLY_CONNECTED, luci::CircleBCQFullyConnected) +CIRCLE_NODE(BCQ_GATHER, luci::CircleBCQGather) CIRCLE_NODE(INSTANCE_NORM, luci::CircleInstanceNorm) // Virtual node(s) CIRCLE_NODE(CIRCLEINPUT, luci::CircleInput) CIRCLE_NODE(CIRCLEOUTPUT, luci::CircleOutput) +CIRCLE_NODE(CIRCLEOUTPUTDUMMY, luci::CircleOutputDummy) +CIRCLE_NODE(CIRCLEOUTPUTEXCLUDE, luci::CircleOutputExclude) +CIRCLE_NODE(CIRCLECUSTOMOUT, luci::CircleCustomOut) +CIRCLE_NODE(CIRCLEIFOUT, luci::CircleIfOut) +CIRCLE_NODE(CIRCLESPLITOUT, luci::CircleSplitOut) +CIRCLE_NODE(CIRCLESPLITVOUT, luci::CircleSplitVOut) +CIRCLE_NODE(CIRCLETOPKV2OUT, luci::CircleTopKV2Out) +CIRCLE_NODE(CIRCLEUNPACKOUT, luci::CircleUnpackOut) +CIRCLE_NODE(CIRCLEWHILEOUT, luci::CircleWhileOut) diff --git a/compiler/luci/lang/include/luci/IR/LuciNodeMixins.h b/compiler/luci/lang/include/luci/IR/LuciNodeMixins.h index b18ac5dc4..c1bb0db11 100644 --- a/compiler/luci/lang/include/luci/IR/LuciNodeMixins.h +++ b/compiler/luci/lang/include/luci/IR/LuciNodeMixins.h @@ -22,6 +22,8 @@ #include <loco/IR/Node.h> #include <loco/IR/NodeMixins.h> +#include <vector> + namespace luci { @@ -70,6 +72,7 @@ template <unsigned N, typename Base> class FixedArityNode : public Base public: FixedArityNode() { + _args.resize(N); for (uint32_t n = 0; n < N; ++n) { _args[n] = std::make_unique<loco::Use>(this); @@ -96,7 +99,7 @@ protected: loco::Use *at(unsigned n) const { return _args.at(n).get(); } private: - std::array<std::unique_ptr<loco::Use>, N> _args; + std::vector<std::unique_ptr<loco::Use>> _args{}; }; } // namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleAddN.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleAddN.h new file mode 100644 index 000000000..6ba4a96bc --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleAddN.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCEL_ADD_N_H__ +#define __LUCI_IR_CIRCEL_ADD_N_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/VariadicArityNode.h" + +namespace luci +{ + +/** + * @brief ADD_N in Circle + */ +class CircleAddN final : public VariadicArityNode<CircleNodeImpl<CircleOpcode::ADD_N>> +{ +public: + CircleAddN(uint32_t arity) : VariadicArityNode<CircleNodeImpl<CircleOpcode::ADD_N>>(arity) + { + assert(arity >= 1); + } + +public: + Node *inputs(uint32_t index) const { return at(index)->node(); } + void inputs(uint32_t index, Node *node) { at(index)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCEL_ADD_N_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleArgMin.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleArgMin.h new file mode 100644 index 000000000..8cb561983 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleArgMin.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCELARGMIN_H__ +#define __LUCI_IR_CIRCELARGMIN_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief ARG_Min in Circle + */ +class CircleArgMin final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::ARG_MIN>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *dimension(void) const { return at(1)->node(); } + void dimension(loco::Node *node) { at(1)->node(node); } + +public: + loco::DataType output_type(void) const { return _output_type; } + void output_type(loco::DataType ot) { _output_type = ot; } + +private: + loco::DataType _output_type{loco::DataType::S64}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCELARGMIN_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleBCQFullyConnected.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleBCQFullyConnected.h new file mode 100644 index 000000000..7d12d593a --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleBCQFullyConnected.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLEBCQFULLYCONNECTED_H__ +#define __LUCI_IR_CIRCLEBCQFULLYCONNECTED_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/AttrFusedActFunc.h" +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief BCQ_FULLY_CONNECTED in Circle + */ +class CircleBCQFullyConnected final + : public FixedArityNode<5, CircleNodeImpl<CircleOpcode::BCQ_FULLY_CONNECTED>>, + public LuciNodeMixin<LuciNodeTrait::FusedActFunc>, + public LuciNodeMixin<LuciNodeTrait::Bias> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *weights_scales(void) const { return at(1)->node(); } + void weights_scales(loco::Node *node) { at(1)->node(node); } + + loco::Node *weights_binary(void) const { return at(2)->node(); } + void weights_binary(loco::Node *node) { at(2)->node(node); } + + loco::Node *bias(void) const override { return at(3)->node(); } + void bias(loco::Node *node) override { at(3)->node(node); } + + loco::Node *weights_clusters(void) const { return at(4)->node(); } + void weights_clusters(loco::Node *node) { at(4)->node(node); } + +public: + int32_t weights_hidden_size(void) const { return _weights_hidden_size; } + void weights_hidden_size(int32_t weights_hidden_size) + { + _weights_hidden_size = weights_hidden_size; + } + +private: + int32_t _weights_hidden_size = 0; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLEBCQFULLYCONNECTED_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleBCQGather.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleBCQGather.h new file mode 100644 index 000000000..f7638261d --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleBCQGather.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLEBCQGATHER_H__ +#define __LUCI_IR_CIRCLEBCQGATHER_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief BCQ_GATHER in Circle + */ +class CircleBCQGather final : public FixedArityNode<4, CircleNodeImpl<CircleOpcode::BCQ_GATHER>> +{ +public: + loco::Node *input_scales(void) const { return at(0)->node(); } + void input_scales(loco::Node *node) { at(0)->node(node); } + + loco::Node *input_binary(void) const { return at(1)->node(); } + void input_binary(loco::Node *node) { at(1)->node(node); } + + loco::Node *indices(void) const { return at(2)->node(); } + void indices(loco::Node *node) { at(2)->node(node); } + + loco::Node *input_clusters(void) const { return at(3)->node(); } + void input_clusters(loco::Node *node) { at(3)->node(node); } + +public: + int32_t axis(void) const { return _axis; } + void axis(int32_t axis) { _axis = axis; } + + int32_t input_hidden_size(void) const { return _input_hidden_size; } + void input_hidden_size(int32_t input_hidden_size) { _input_hidden_size = input_hidden_size; } + +private: + int32_t _axis = 0; + int32_t _input_hidden_size = 0; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLEBCQGATHER_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleBatchMatMul.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleBatchMatMul.h new file mode 100644 index 000000000..19999924e --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleBatchMatMul.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCELBATCHMATMUL_H__ +#define __LUCI_IR_CIRCELBATCHMATMUL_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief BATCHMATMUL in Circle + */ +class CircleBatchMatMul final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::BATCHMATMUL>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } + + loco::Node *y(void) const { return at(1)->node(); } + void y(loco::Node *node) { at(1)->node(node); } + +public: + bool adj_x(void) const { return _adj_x; } + void adj_x(bool arg) { _adj_x = arg; } + + bool adj_y(void) const { return _adj_y; } + void adj_y(bool arg) { _adj_y = arg; } + +private: + bool _adj_x = false; + bool _adj_y = false; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCELBATCHMATMUL_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleCast.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleCast.h new file mode 100644 index 000000000..9a89d0b2b --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleCast.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCELECAST_H__ +#define __LUCI_IR_CIRCELECAST_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief CAST in Circle + */ +class CircleCast final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CAST>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } + +public: + loco::DataType in_data_type(void) const { return _in_data_type; } + void in_data_type(loco::DataType it) { _in_data_type = it; } + + loco::DataType out_data_type(void) const { return _out_data_type; } + void out_data_type(loco::DataType ot) { _out_data_type = ot; } + +private: + loco::DataType _in_data_type{loco::DataType::FLOAT32}; + loco::DataType _out_data_type{loco::DataType::FLOAT32}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCELECAST_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleCeil.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleCeil.h new file mode 100644 index 000000000..8a8715dcf --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleCeil.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_CEIL_H__ +#define __LUCI_IR_CIRCLE_CEIL_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief CEIL in Circle + */ +class CircleCeil final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CEIL>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_CEIL_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleConcatenation.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleConcatenation.h index 8a6778a2f..dea1a4613 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleConcatenation.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleConcatenation.h @@ -64,7 +64,7 @@ public: void axis(int32_t axis) { _axis = axis; } private: - int32_t _axis; + int32_t _axis{0}; }; } // namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h index 089836eb9..fc671746f 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleConst.h @@ -20,7 +20,6 @@ #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" -#include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" #include <loco/IR/DataTypeTraits.h> @@ -32,9 +31,7 @@ namespace luci * @brief Class to build tensor data * @note This will not be exported as a specific op */ -class CircleConst final : public FixedArityNode<0, CircleNodeImpl<CircleOpcode::CONST>>, - public loco::NodeMixin<loco::NodeTrait::DataType>, - public loco::NodeMixin<loco::NodeTrait::TensorShape> +class CircleConst final : public FixedArityNode<0, CircleNodeImpl<CircleOpcode::CONST>> { public: CircleConst() = default; diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleConv2D.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleConv2D.h index 54318e65c..13657cee4 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleConv2D.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleConv2D.h @@ -22,6 +22,7 @@ #include "luci/IR/AttrPadding.h" #include "luci/IR/AttrStride.h" +#include "luci/IR/AttrDilation.h" #include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" @@ -52,9 +53,13 @@ public: const Stride *stride(void) const { return &_stride; } Stride *stride(void) { return &_stride; } + const Dilation *dilation(void) const { return &_dilation; } + Dilation *dilation(void) { return &_dilation; } + private: Padding _padding = Padding::UNDEFINED; Stride _stride; + Dilation _dilation; }; } // namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleCustom.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleCustom.h new file mode 100644 index 000000000..6c722b766 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleCustom.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLECUSTOM_H__ +#define __LUCI_IR_CIRCLECUSTOM_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/VariadicArityNode.h" + +namespace luci +{ + +/** + * @brief CUSTOM in Circle + */ +class CircleCustom final : public VariadicArityNode<CircleNodeImpl<CircleOpcode::CUSTOM>> +{ +public: + CircleCustom(uint32_t arity) : VariadicArityNode<CircleNodeImpl<CircleOpcode::CUSTOM>>(arity) + { + // TODO Support when arity is 0 + assert(arity >= 1); + } + +public: + uint32_t numInputs(void) const { return arity(); } + +public: + Node *inputs(uint32_t index) const { return at(index)->node(); } + void inputs(uint32_t index, Node *node) { at(index)->node(node); } + + const std::vector<uint8_t> &custom_options(void) const { return _custom_options; } + void custom_options(const std::vector<uint8_t> &custom_options) + { + _custom_options = custom_options; + } + + const std::string &custom_code(void) const { return _custom_code; } + void custom_code(const std::string &custom_code) { _custom_code = custom_code; } + +private: + std::vector<uint8_t> _custom_options; + std::string _custom_code; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLECUSTOM_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleCustomOut.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleCustomOut.h new file mode 100644 index 000000000..36b8e4aed --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleCustomOut.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_CUSTOMOUT_H__ +#define __LUCI_IR_CIRCLE_CUSTOMOUT_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief Virtual CIRCLECUSTOMOUT in Circle + */ +class CircleCustomOut final + : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLECUSTOMOUT>> +{ +public: + CircleCustomOut() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + int32_t index(void) const { return _index; } + void index(int32_t index) { _index = index; } + +private: + int32_t _index{-1}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_CUSTOMOUT_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleDepthToSpace.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleDepthToSpace.h new file mode 100644 index 000000000..e19282b97 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleDepthToSpace.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_DEPTHTOSPACE_H__ +#define __LUCI_IR_CIRCLE_DEPTHTOSPACE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief DEPTH_TO_SPACE in Circle + */ +class CircleDepthToSpace final + : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::DEPTH_TO_SPACE>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + int block_size(void) const { return _block_size; } + void block_size(int block_size) { _block_size = block_size; } + +private: + int _block_size{0}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_DEPTHTOSPACE_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleDepthwiseConv2D.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleDepthwiseConv2D.h index 15ee62ba7..eb058cec1 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleDepthwiseConv2D.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleDepthwiseConv2D.h @@ -20,6 +20,7 @@ #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" +#include "luci/IR/AttrDilation.h" #include "luci/IR/AttrFilter.h" #include "luci/IR/AttrPadding.h" #include "luci/IR/AttrStride.h" @@ -57,10 +58,14 @@ public: int32_t depthMultiplier(void) const { return _depth_multiplier; } void depthMultiplier(int32_t arg) { _depth_multiplier = arg; } + const Dilation *dilation(void) const { return &_dilation; } + Dilation *dilation(void) { return &_dilation; } + private: Padding _padding = Padding::UNDEFINED; Stride _stride; int32_t _depth_multiplier = 0; + Dilation _dilation; }; } // namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleElu.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleElu.h new file mode 100644 index 000000000..fbb2f3533 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleElu.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLEELU_H__ +#define __LUCI_IR_CIRCLEELU_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief ELU in Circle + */ +class CircleElu final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::ELU>> +{ +public: + CircleElu() = default; + +public: + loco::Node *features(void) const { return at(0)->node(); } + void features(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLEELU_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleExpandDims.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleExpandDims.h new file mode 100644 index 000000000..f70219614 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleExpandDims.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLEEXPAND_DIMS_H__ +#define __LUCI_IR_CIRCLEEXPAND_DIMS_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief EXPAND_DIMS in Circle + */ +class CircleExpandDims final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::EXPAND_DIMS>> +{ +public: + CircleExpandDims() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *axis(void) const { return at(1)->node(); } + void axis(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLEEXPAND_DIMS_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleFill.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleFill.h new file mode 100644 index 000000000..bfc65274a --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleFill.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCEFILL_H__ +#define __LUCI_IR_CIRCEFILL_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief FILL in Circle + */ +class CircleFill final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::FILL>> +{ +public: + loco::Node *dims(void) const { return at(0)->node(); } + void dims(loco::Node *node) { at(0)->node(node); } + + loco::Node *value(void) const { return at(1)->node(); } + void value(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCEFILL_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleFloor.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleFloor.h new file mode 100644 index 000000000..7e10547b6 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleFloor.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_FLOOR_H__ +#define __LUCI_IR_CIRCLE_FLOOR_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief FLOOR in Circle + */ +class CircleFloor final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::FLOOR>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_FLOOR_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleFloorDiv.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleFloorDiv.h new file mode 100644 index 000000000..ba9db010c --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleFloorDiv.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_FLOOR_DIV_H__ +#define __LUCI_IR_CIRCLE_FLOOR_DIV_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief FLOOR_DIV in Circle + */ +class CircleFloorDiv final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::FLOOR_DIV>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } + + loco::Node *y(void) const { return at(1)->node(); } + void y(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_FLOOR_DIV_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleFloorMod.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleFloorMod.h new file mode 100644 index 000000000..4d13717a0 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleFloorMod.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_FLOOR_MOD_H__ +#define __LUCI_IR_CIRCLE_FLOOR_MOD_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief FLOOR_MOD in Circle + */ +class CircleFloorMod final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::FLOOR_MOD>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } + + loco::Node *y(void) const { return at(1)->node(); } + void y(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_FLOOR_MOD_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleGather.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleGather.h index 489596c04..1e8c4982a 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleGather.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleGather.h @@ -20,7 +20,6 @@ #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" -#include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" namespace luci @@ -32,11 +31,11 @@ namespace luci class CircleGather final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::GATHER>> { public: - loco::Node *input(void) const { return at(0)->node(); } - void input(loco::Node *node) { at(0)->node(node); } + loco::Node *params(void) const { return at(0)->node(); } + void params(loco::Node *node) { at(0)->node(node); } - loco::Node *positions(void) const { return at(1)->node(); } - void positions(loco::Node *node) { at(1)->node(node); } + loco::Node *indices(void) const { return at(1)->node(); } + void indices(loco::Node *node) { at(1)->node(node); } public: int32_t axis(void) const { return _axis; } diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleGatherNd.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleGatherNd.h new file mode 100644 index 000000000..3423a8216 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleGatherNd.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLEGATHER_ND_H__ +#define __LUCI_IR_CIRCLEGATHER_ND_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief GATHER_ND in Circle + */ +class CircleGatherNd final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::GATHER_ND>> +{ +public: + loco::Node *params(void) const { return at(0)->node(); } + void params(loco::Node *node) { at(0)->node(node); } + + loco::Node *indices(void) const { return at(1)->node(); } + void indices(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLEGATHER_ND_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleGreater.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleGreater.h new file mode 100644 index 000000000..040a4e338 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleGreater.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_GREATER_H__ +#define __LUCI_IR_CIRCLE_GREATER_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief Greater in Circle + */ +class CircleGreater final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::GREATER>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } + + loco::Node *y(void) const { return at(1)->node(); } + void y(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_GREATER_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleGreaterEqual.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleGreaterEqual.h new file mode 100644 index 000000000..82bdab212 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleGreaterEqual.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_GREATEREQUAL_H__ +#define __LUCI_IR_CIRCLE_GREATEREQUAL_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief GREATER EQUAL in Circle + */ +class CircleGreaterEqual final + : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::GREATER_EQUAL>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } + + loco::Node *y(void) const { return at(1)->node(); } + void y(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_GREATEREQUAL_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleIf.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleIf.h new file mode 100644 index 000000000..2f9eac211 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleIf.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_IF_H__ +#define __LUCI_IR_CIRCLE_IF_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/VariadicArityNode.h" + +#include <cassert> + +namespace luci +{ + +/** + * @brief IF in Circle + */ +class CircleIf final : public VariadicArityNode<CircleNodeImpl<CircleOpcode::IF>> +{ +public: + CircleIf(uint32_t arity, uint32_t out) + : VariadicArityNode<CircleNodeImpl<CircleOpcode::IF>>(arity + 1), _output_count(out) + { + assert(arity > 0); + assert(out > 0); + } + +public: + uint32_t input_count(void) const { return arity() - 1; } + uint32_t output_count(void) const { return _output_count; } + +public: + Node *cond(void) const { return at(0)->node(); } + void cond(Node *node) { at(0)->node(node); } + + Node *input(uint32_t index) const { return at(index + 1)->node(); } + void input(uint32_t index, Node *node) { at(index + 1)->node(node); } + +public: + int32_t then_branch(void) const { return _then_branch; } + void then_branch(int32_t then_branch) { _then_branch = then_branch; } + + int32_t else_branch(void) const { return _else_branch; } + void else_branch(int32_t else_branch) { _else_branch = else_branch; } + +public: + loco::Graph *then_graph(void) const { return _then_graph; } + void then_graph(loco::Graph *then_graph) { _then_graph = then_graph; } + + loco::Graph *else_graph(void) const { return _else_graph; } + void else_graph(loco::Graph *else_graph) { _else_graph = else_graph; } + +private: + uint32_t _output_count{0}; + int32_t _then_branch{-1}; + int32_t _else_branch{-1}; + + loco::Graph *_then_graph{nullptr}; + loco::Graph *_else_graph{nullptr}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_IF_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleIfOut.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleIfOut.h new file mode 100644 index 000000000..3654e943b --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleIfOut.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_IFOUT_H__ +#define __LUCI_IR_CIRCLE_IFOUT_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief Virtual CIRCLEIFOUT in Circle + */ +class CircleIfOut final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLEIFOUT>> +{ +public: + CircleIfOut() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + int32_t index(void) const { return _index; } + void index(int32_t index) { _index = index; } + +private: + int32_t _index{-1}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_IFOUT_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleInput.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleInput.h index 2c4d60253..4a7d36a4e 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleInput.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleInput.h @@ -20,7 +20,6 @@ #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" -#include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" #include <loco/IR/DataTypeTraits.h> @@ -33,9 +32,7 @@ namespace luci * @brief CircleNode used for Input of the Graph * @note This will not be exported as a specific op */ -class CircleInput final : public FixedArityNode<0, CircleNodeImpl<CircleOpcode::CIRCLEINPUT>>, - public loco::NodeMixin<loco::NodeTrait::DataType>, - public loco::NodeMixin<loco::NodeTrait::TensorShape> +class CircleInput final : public FixedArityNode<0, CircleNodeImpl<CircleOpcode::CIRCLEINPUT>> { public: CircleInput() = default; diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleL2Normalize.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleL2Normalize.h new file mode 100644 index 000000000..efa932d95 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleL2Normalize.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCEL2NORMALIZE_H__ +#define __LUCI_IR_CIRCEL2NORMALIZE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/AttrFusedActFunc.h" +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief L2_NORMALIZATION in Circle + */ +class CircleL2Normalize final + : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::L2_NORMALIZATION>>, + public LuciNodeMixin<LuciNodeTrait::FusedActFunc> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCEL2NORMALIZE_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleL2Pool2D.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleL2Pool2D.h new file mode 100644 index 000000000..7c76ee5d0 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleL2Pool2D.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_L2_POOL2D_H__ +#define __LUCI_IR_CIRCLE_L2_POOL2D_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/AttrFilter.h" +#include "luci/IR/AttrPadding.h" +#include "luci/IR/AttrStride.h" +#include "luci/IR/AttrFusedActFunc.h" +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief L2_POOL_2D in Circle + */ +class CircleL2Pool2D final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::L2_POOL_2D>>, + public LuciNodeMixin<LuciNodeTrait::FusedActFunc> +{ +public: + CircleL2Pool2D() : _padding(Padding::UNDEFINED) { /* empty */} + +public: + loco::Node *value(void) const { return at(0)->node(); } + void value(loco::Node *node) { at(0)->node(node); } + + Padding padding() const { return _padding; } + void padding(Padding padding) { _padding = padding; } + + const Filter *filter(void) const { return &_filter; } + Filter *filter(void) { return &_filter; } + + const Stride *stride(void) const { return &_stride; } + Stride *stride(void) { return &_stride; } + +private: + Padding _padding; + Stride _stride; + Filter _filter; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_L2_POOL2D_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLeakyRelu.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLeakyRelu.h new file mode 100644 index 000000000..d6ac97fc0 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLeakyRelu.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_LEAKY_RELU_H__ +#define __LUCI_IR_CIRCLE_LEAKY_RELU_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief LEAKY_RELU in Circle + */ +class CircleLeakyRelu final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::LEAKY_RELU>> +{ +public: + CircleLeakyRelu() = default; + +public: + loco::Node *features(void) const { return at(0)->node(); } + void features(loco::Node *node) { at(0)->node(node); } + + float alpha() const { return _alpha; } + void alpha(float alpha) { _alpha = alpha; } + +private: + float _alpha = 0.2f; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_LEAKY_RELU_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLess.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLess.h new file mode 100644 index 000000000..cd6cf1872 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLess.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_LESS_H__ +#define __LUCI_IR_CIRCLE_LESS_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief LESS in Circle + */ +class CircleLess final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::LESS>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } + + loco::Node *y(void) const { return at(1)->node(); } + void y(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_LESS_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLessEqual.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLessEqual.h new file mode 100644 index 000000000..4c7c6a49b --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLessEqual.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_LESSEQUAL_H__ +#define __LUCI_IR_CIRCLE_LESSEQUAL_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief LESS_EQUAL in Circle + */ +class CircleLessEqual final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::LESS_EQUAL>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } + + loco::Node *y(void) const { return at(1)->node(); } + void y(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_LESSEQUAL_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLocalResponseNormalization.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLocalResponseNormalization.h new file mode 100644 index 000000000..8ad2b40fd --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLocalResponseNormalization.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLELOCAL_RESPONSE_NORMALIZATION_H__ +#define __LUCI_IR_CIRCLELOCAL_RESPONSE_NORMALIZATION_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief LOCAL_RESPONSE_NORMALIZATION in Circle + */ +class CircleLocalResponseNormalization final + : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::LOCAL_RESPONSE_NORMALIZATION>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + int32_t radius(void) const { return _radius; } + void radius(int32_t radius) { _radius = radius; } + + float bias(void) const { return _bias; } + void bias(float bias) { _bias = bias; } + + float alpha(void) const { return _alpha; } + void alpha(float alpha) { _alpha = alpha; } + + float beta(void) const { return _beta; } + void beta(float beta) { _beta = beta; } + +private: + int32_t _radius{5}; + float _bias{1.0f}; + float _alpha{1.0f}; + float _beta{0.5f}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLELOCAL_RESPONSE_NORMALIZATION_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLog.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLog.h new file mode 100644 index 000000000..aeb13fed9 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLog.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_LOG_H__ +#define __LUCI_IR_CIRCLE_LOG_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief LOG in Circle + */ +class CircleLog final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::LOG>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_LOG_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLogSoftmax.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLogSoftmax.h new file mode 100644 index 000000000..5dfd2c1f9 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLogSoftmax.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_LOG_SOFTMAX_H__ +#define __LUCI_IR_CIRCLE_LOG_SOFTMAX_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief LOG_SOFTMAX in Circle + */ +class CircleLogSoftmax final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::LOG_SOFTMAX>> +{ +public: + loco::Node *logits(void) const { return at(0)->node(); } + void logits(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_LOG_SOFTMAX_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLogicalAnd.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLogicalAnd.h new file mode 100644 index 000000000..975f6dbc7 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLogicalAnd.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_LOGICALAND_H__ +#define __LUCI_IR_CIRCLE_LOGICALAND_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief LOGICAL_AND in Circle + */ +class CircleLogicalAnd final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::LOGICAL_AND>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } + + loco::Node *y(void) const { return at(1)->node(); } + void y(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_LOGICALAND_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleLogistic.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleLogistic.h new file mode 100644 index 000000000..8328cb328 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleLogistic.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_LOGISTIC_H__ +#define __LUCI_IR_CIRCLE_LOGISTIC_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief LOGISTIC in Circle + */ +class CircleLogistic final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::LOGISTIC>> +{ +public: + CircleLogistic() = default; + +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_LOGISTIC_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleMatrixDiag.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleMatrixDiag.h new file mode 100644 index 000000000..dca6538c3 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleMatrixDiag.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLEMATRIXDIAG_H__ +#define __LUCI_IR_CIRCLEMATRIXDIAG_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief MATRIX_DIAG in Circle + */ +class CircleMatrixDiag final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::MATRIX_DIAG>> +{ +public: + loco::Node *diagonal(void) const { return at(0)->node(); } + void diagonal(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLEMATRIXDIAG_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleMatrixSetDiag.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleMatrixSetDiag.h new file mode 100644 index 000000000..c1f5f3023 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleMatrixSetDiag.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLEMATRIXSETDIAG_H__ +#define __LUCI_IR_CIRCLEMATRIXSETDIAG_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief MATRIX_SET_DIAG in Circle + */ +class CircleMatrixSetDiag final + : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::MATRIX_SET_DIAG>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *diagonal(void) const { return at(1)->node(); } + void diagonal(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLEMATRIXSETDIAG_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleMaximum.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleMaximum.h index cf7305e3a..6f789bc14 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleMaximum.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleMaximum.h @@ -20,7 +20,6 @@ #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" -#include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleMean.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleMean.h index 6fd791450..7f8aeb5aa 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleMean.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleMean.h @@ -20,7 +20,6 @@ #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" -#include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleMinimum.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleMinimum.h new file mode 100644 index 000000000..79d5a6f17 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleMinimum.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLEMINIMUM_H__ +#define __LUCI_IR_CIRCLEMINIMUM_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief MINIMUM in Circle + */ +class CircleMinimum final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::MINIMUM>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } + + loco::Node *y(void) const { return at(1)->node(); } + void y(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLEMINIMUM_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleMirrorPad.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleMirrorPad.h new file mode 100644 index 000000000..68db8f6f3 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleMirrorPad.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_MIRRORPAD_H__ +#define __LUCI_IR_CIRCLE_MIRRORPAD_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" +#include "luci/IR/AttrMirrorPadMode.h" + +namespace luci +{ + +/** + * @brief MIRROR_PAD in Circle + */ +class CircleMirrorPad final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::MIRROR_PAD>> +{ +public: + CircleMirrorPad() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *paddings(void) const { return at(1)->node(); } + void paddings(loco::Node *node) { at(1)->node(node); } + +public: + MirrorPadMode mode(void) const { return _mode; } + void mode(MirrorPadMode mode) { _mode = mode; } + +private: + MirrorPadMode _mode{MirrorPadMode::REFLECT}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_MIRRORPAD_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleNeg.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleNeg.h new file mode 100644 index 000000000..4149ac4a7 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleNeg.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLENEG_H__ +#define __LUCI_IR_CIRCLENEG_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief NEG in Circle + */ +class CircleNeg final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::NEG>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLENEG_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleNotEqual.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleNotEqual.h new file mode 100644 index 000000000..cca7a5e22 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleNotEqual.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_NOTEQUAL_H__ +#define __LUCI_IR_CIRCLE_NOTEQUAL_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief NOT EQUAL in Circle + */ +class CircleNotEqual final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::NOT_EQUAL>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } + + loco::Node *y(void) const { return at(1)->node(); } + void y(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_NOTEQUAL_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleOneHot.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleOneHot.h new file mode 100644 index 000000000..665e01d48 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleOneHot.h @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLEONEHOT_H__ +#define __LUCI_IR_CIRCLEONEHOT_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief ONEHOT in Circle + */ +class CircleOneHot final : public FixedArityNode<4, CircleNodeImpl<CircleOpcode::ONE_HOT>> +{ +public: + loco::Node *indices(void) const { return at(0)->node(); } + void indices(loco::Node *node) { at(0)->node(node); } + + loco::Node *depth(void) const { return at(1)->node(); } + void depth(loco::Node *node) { at(1)->node(node); } + + loco::Node *on_value(void) const { return at(2)->node(); } + void on_value(loco::Node *node) { at(2)->node(node); } + + loco::Node *off_value(void) const { return at(3)->node(); } + void off_value(loco::Node *node) { at(3)->node(node); } + +public: + int32_t axis(void) const { return _axis; } + void axis(int32_t axis) { _axis = axis; } + +private: + int32_t _axis = -1; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLEONEHOT_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleOutput.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleOutput.h index c65317ad1..67e55f1a1 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleOutput.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleOutput.h @@ -20,7 +20,6 @@ #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" -#include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" #include <loco/IR/GraphOutputIndex.h> @@ -50,6 +49,27 @@ private: int64_t _index = -1; // Uninitialized }; +/** + * @brief Temporary DummyNode used with dangle CircleNode + */ +// TODO remove CircleOutputDummy +class CircleOutputDummy final + : public FixedArityNode<0, CircleNodeImpl<CircleOpcode::CIRCLEOUTPUTDUMMY>> +{ +public: + CircleOutputDummy() = default; +}; + +/** + * @brief CircleOutputExclude is used to specifying not exported nodes + */ +class CircleOutputExclude final + : public FixedArityNode<0, CircleNodeImpl<CircleOpcode::CIRCLEOUTPUTEXCLUDE>> +{ +public: + CircleOutputExclude() = default; +}; + } // namespace luci #endif // __LUCI_IR_CIRCLEOUTPUT_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CirclePRelu.h b/compiler/luci/lang/include/luci/IR/Nodes/CirclePRelu.h new file mode 100644 index 000000000..693777512 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CirclePRelu.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_PRELU_H__ +#define __LUCI_IR_PRELU_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief PRelu in Circle + */ +class CirclePRelu final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::PRELU>> +{ +public: + CirclePRelu() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *alpha(void) const { return at(1)->node(); } + void alpha(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_PRELU_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CirclePow.h b/compiler/luci/lang/include/luci/IR/Nodes/CirclePow.h new file mode 100644 index 000000000..006e3dd86 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CirclePow.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_POW_H__ +#define __LUCI_IR_POW_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief POW in Circle + */ +class CirclePow final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::POW>> +{ +public: + CirclePow() = default; + +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } + + loco::Node *y(void) const { return at(1)->node(); } + void y(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_POW_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleRange.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleRange.h new file mode 100644 index 000000000..977a37a52 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleRange.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLERANGE_H__ +#define __LUCI_IR_CIRCLERANGE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief RANGE in Circle + */ +class CircleRange final : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::RANGE>> +{ +public: + loco::Node *start(void) const { return at(0)->node(); } + void start(loco::Node *node) { at(0)->node(node); } + + loco::Node *limit(void) const { return at(1)->node(); } + void limit(loco::Node *node) { at(1)->node(node); } + + loco::Node *delta(void) const { return at(2)->node(); } + void delta(loco::Node *node) { at(2)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLERANGE_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleRank.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleRank.h new file mode 100644 index 000000000..ba6d67f69 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleRank.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLERANK_H__ +#define __LUCI_IR_CIRCLERANK_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief RANK in Circle + */ +class CircleRank final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::RANK>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLERANK_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceAny.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceAny.h new file mode 100644 index 000000000..0456be863 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceAny.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_REDUCE_ANY_H__ +#define __LUCI_IR_CIRCLE_REDUCE_ANY_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief REDUCE_ANY in Circle + */ +class CircleReduceAny final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::REDUCE_ANY>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *reduction_indices(void) const { return at(1)->node(); } + void reduction_indices(loco::Node *node) { at(1)->node(node); } + +public: + bool keep_dims(void) const { return _keep_dims; } + void keep_dims(bool keep_dims) { _keep_dims = keep_dims; } + +private: + bool _keep_dims = false; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_REDUCE_ANY_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceMax.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceMax.h new file mode 100644 index 000000000..925c977e5 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceMax.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_REDUCE_MAX_H__ +#define __LUCI_IR_CIRCLE_REDUCE_MAX_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief REDUCE_MAX in Circle + */ +class CircleReduceMax final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::REDUCE_MAX>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *reduction_indices(void) const { return at(1)->node(); } + void reduction_indices(loco::Node *node) { at(1)->node(node); } + +public: + bool keep_dims(void) const { return _keep_dims; } + void keep_dims(bool keep_dims) { _keep_dims = keep_dims; } + +private: + bool _keep_dims = false; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_REDUCE_MAX_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceMin.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceMin.h new file mode 100644 index 000000000..fd789ae5e --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceMin.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_REDUCE_MIN_H__ +#define __LUCI_IR_CIRCLE_REDUCE_MIN_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief REDUCE_MIN in Circle + */ +class CircleReduceMin final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::REDUCE_MIN>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *reduction_indices(void) const { return at(1)->node(); } + void reduction_indices(loco::Node *node) { at(1)->node(node); } + +public: + bool keep_dims(void) const { return _keep_dims; } + void keep_dims(bool keep_dims) { _keep_dims = keep_dims; } + +private: + bool _keep_dims = false; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_REDUCE_MIN_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceProd.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceProd.h new file mode 100644 index 000000000..b7d226255 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReduceProd.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_REDUCE_PROD_H__ +#define __LUCI_IR_CIRCLE_REDUCE_PROD_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief REDUCE_PROD in Circle + */ +class CircleReduceProd final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::REDUCE_PROD>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *reduction_indices(void) const { return at(1)->node(); } + void reduction_indices(loco::Node *node) { at(1)->node(node); } + +public: + bool keep_dims(void) const { return _keep_dims; } + void keep_dims(bool keep_dims) { _keep_dims = keep_dims; } + +private: + bool _keep_dims = false; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_REDUCE_PROD_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu.h index afb2c667a..91272d2bf 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu.h @@ -20,7 +20,6 @@ #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" -#include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu6.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu6.h index b313a5557..b4274ded9 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu6.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleRelu6.h @@ -20,7 +20,6 @@ #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" -#include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReluN1To1.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReluN1To1.h new file mode 100644 index 000000000..a5c5710c2 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReluN1To1.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_RELU_N1_TO_1_H__ +#define __LUCI_IR_CIRCLE_RELU_N1_TO_1_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief RELU_N1_TO_1 in Circle + */ +class CircleReluN1To1 final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::RELU_N1_TO_1>> +{ +public: + CircleReluN1To1() = default; + +public: + loco::Node *features(void) const { return at(0)->node(); } + void features(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_RELU_N1_TO_1_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReshape.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReshape.h index a3a2a3f31..b13144f7e 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleReshape.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReshape.h @@ -20,7 +20,6 @@ #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" -#include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" namespace luci @@ -38,8 +37,8 @@ public: loco::Node *tensor(void) const { return at(0)->node(); } void tensor(loco::Node *node) { at(0)->node(node); } - // TODO Make this input optional. That is, loco system does not emit error - // with this input being null + // NOTE shape is optional and can be CircleConst or any other type + // and also can be CircleOutputDummy when reshape option does not exist loco::Node *shape(void) const { return at(1)->node(); } void shape(loco::Node *node) { at(1)->node(node); } diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleResizeBilinear.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleResizeBilinear.h new file mode 100644 index 000000000..3c8223338 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleResizeBilinear.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLERESIZE_BILINEAR_H__ +#define __LUCI_IR_CIRCLERESIZE_BILINEAR_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief RESIZE_BILINEAR in Circle + */ +class CircleResizeBilinear final + : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::RESIZE_BILINEAR>> +{ +public: + CircleResizeBilinear() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *size(void) const { return at(1)->node(); } + void size(loco::Node *node) { at(1)->node(node); } + + bool align_corners() const { return _align_corners; } + void align_corners(bool value) { _align_corners = value; } + + bool half_pixel_centers() const { return _half_pixel_centers; } + void half_pixel_centers(bool value) { _half_pixel_centers = value; } + +private: + bool _align_corners = false; + bool _half_pixel_centers = false; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLERESIZE_BILINEAR_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleResizeNearestNeighbor.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleResizeNearestNeighbor.h new file mode 100644 index 000000000..dc32ebee7 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleResizeNearestNeighbor.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLERESSIZE_NEAREST_NEIGHBOR_H__ +#define __LUCI_IR_CIRCLERESSIZE_NEAREST_NEIGHBOR_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief RESIZE_NEAREST_NEIGHBOR in Circle + */ +class CircleResizeNearestNeighbor final + : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::RESIZE_NEAREST_NEIGHBOR>> +{ +public: + CircleResizeNearestNeighbor() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *size(void) const { return at(1)->node(); } + void size(loco::Node *node) { at(1)->node(node); } + + bool align_corners() const { return _align_corners; } + void align_corners(bool value) { _align_corners = value; } + +private: + bool _align_corners = false; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLERESSIZE_NEAREST_NEIGHBOR_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReverseSequence.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReverseSequence.h new file mode 100644 index 000000000..b0766dd3e --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReverseSequence.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLEREVERSESEQUENCE_H__ +#define __LUCI_IR_CIRCLEREVERSESEQUENCE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief REVERSE_SEQUENCE in Circle + */ +class CircleReverseSequence final + : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::REVERSE_SEQUENCE>> +{ +public: + CircleReverseSequence() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *seq_lengths(void) const { return at(1)->node(); } + void seq_lengths(loco::Node *node) { at(1)->node(node); } + +public: + int seq_axis(void) const { return _seq_axis; } + void seq_axis(int seq_axis) { _seq_axis = seq_axis; } + + int batch_axis(void) const { return _batch_axis; } + void batch_axis(int batch_axis) { _batch_axis = batch_axis; } + +private: + int _seq_axis{0}; + int _batch_axis{0}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLEREVERSESEQUENCE_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleReverseV2.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleReverseV2.h new file mode 100644 index 000000000..71d9f65aa --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleReverseV2.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLEREVERSE_V2_H__ +#define __LUCI_IR_CIRCLEREVERSE_V2_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief ReverseV2 in Circle + */ +class CircleReverseV2 final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::REVERSE_V2>> +{ +public: + loco::Node *tensor(void) const { return at(0)->node(); } + void tensor(loco::Node *node) { at(0)->node(node); } + + loco::Node *axis(void) const { return at(1)->node(); } + void axis(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLEREVERSE_V2_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleRound.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleRound.h new file mode 100644 index 000000000..30296ce9e --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleRound.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLEROUND_H__ +#define __LUCI_IR_CIRCLEROUND_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief ROUND in Circle + */ +class CircleRound final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::ROUND>> +{ +public: + CircleRound() = default; + +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLEROUND_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleRsqrt.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleRsqrt.h index 44d22ef22..873397bce 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleRsqrt.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleRsqrt.h @@ -20,7 +20,6 @@ #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" -#include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleScatterNd.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleScatterNd.h new file mode 100644 index 000000000..9f93a0a80 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleScatterNd.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLESCATTER_ND_H__ +#define __LUCI_IR_CIRCLESCATTER_ND_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SCATTER_ND in Circle + */ +class CircleScatterNd final : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::SCATTER_ND>> +{ +public: + loco::Node *indices(void) const { return at(0)->node(); } + void indices(loco::Node *node) { at(0)->node(node); } + + loco::Node *updates(void) const { return at(1)->node(); } + void updates(loco::Node *node) { at(1)->node(node); } + + loco::Node *shape(void) const { return at(2)->node(); } + void shape(loco::Node *node) { at(2)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLESCATTER_ND_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSegmentSum.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSegmentSum.h new file mode 100644 index 000000000..416d617b2 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSegmentSum.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_SEGMENT_SUM_H__ +#define __LUCI_IR_CIRCLE_SEGMENT_SUM_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SEGMENT_SUM in Circle + */ +class CircleSegmentSum final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::SEGMENT_SUM>> +{ +public: + CircleSegmentSum() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *segment_ids(void) const { return at(1)->node(); } + void segment_ids(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_SEGMENT_SUM_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSelect.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSelect.h new file mode 100644 index 000000000..727647168 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSelect.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_SELECT_H__ +#define __LUCI_IR_CIRCLE_SELECT_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SELECT in Circle + */ +class CircleSelect final : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::SELECT>> +{ +public: + CircleSelect() = default; + +public: + loco::Node *condition(void) const { return at(0)->node(); } + void condition(loco::Node *node) { at(0)->node(node); } + + loco::Node *t(void) const { return at(1)->node(); } + void t(loco::Node *node) { at(1)->node(node); } + + loco::Node *e(void) const { return at(2)->node(); } + void e(loco::Node *node) { at(2)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_SELECT_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSelectV2.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSelectV2.h new file mode 100644 index 000000000..7ac3c0524 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSelectV2.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_SELECT_V2_H__ +#define __LUCI_IR_CIRCLE_SELECT_V2_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SELECT_V2 in Circle + */ +class CircleSelectV2 final : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::SELECT_V2>> +{ +public: + CircleSelectV2() = default; + +public: + loco::Node *condition(void) const { return at(0)->node(); } + void condition(loco::Node *node) { at(0)->node(node); } + + loco::Node *t(void) const { return at(1)->node(); } + void t(loco::Node *node) { at(1)->node(node); } + + loco::Node *e(void) const { return at(2)->node(); } + void e(loco::Node *node) { at(2)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_SELECT_V2_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleShape.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleShape.h new file mode 100644 index 000000000..ff20ce684 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleShape.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_SHAPE_H__ +#define __LUCI_IR_CIRCLE_SHAPE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SHAPE in Circle + */ +class CircleShape final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::SHAPE>> +{ +public: + CircleShape() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + loco::DataType out_type(void) const { return _out_type; } + void out_type(loco::DataType ot) { _out_type = ot; } + +private: + loco::DataType _out_type{loco::DataType::S32}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_SHAPE_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSin.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSin.h new file mode 100644 index 000000000..5624db253 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSin.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_SIN_H__ +#define __LUCI_IR_CIRCLE_SIN_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SIN in Circle + */ +class CircleSin final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::SIN>> +{ +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_SIN_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSlice.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSlice.h new file mode 100644 index 000000000..a2113643d --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSlice.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_SLICE_H__ +#define __LUCI_IR_SLICE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SLICE in Circle + */ +class CircleSlice final : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::SLICE>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *begin(void) const { return at(1)->node(); } + void begin(loco::Node *node) { at(1)->node(node); } + + loco::Node *size(void) const { return at(2)->node(); } + void size(loco::Node *node) { at(2)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_SLICE_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSoftmax.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSoftmax.h index 4ea3c4b0e..7166a329b 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleSoftmax.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSoftmax.h @@ -39,7 +39,7 @@ public: void beta(float beta) { _beta = beta; } private: - float _beta; + float _beta{0.0f}; }; } // namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSpaceToBatchND.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSpaceToBatchND.h new file mode 100644 index 000000000..042ebffcd --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSpaceToBatchND.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_SPACETOBATCHND_H__ +#define __LUCI_IR_CIRCLE_SPACETOBATCHND_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SPACE_TO_BATCH_ND in Circle + */ +class CircleSpaceToBatchND final + : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::SPACE_TO_BATCH_ND>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *block_shape(void) const { return at(1)->node(); } + void block_shape(loco::Node *node) { at(1)->node(node); } + + loco::Node *paddings(void) const { return at(2)->node(); } + void paddings(loco::Node *node) { at(2)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_SPACETOBATCHND_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSpaceToDepth.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSpaceToDepth.h new file mode 100644 index 000000000..420a4cb96 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSpaceToDepth.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_SPACETODEPTH_H__ +#define __LUCI_IR_CIRCLE_SPACETODEPTH_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SPACE_TO_DEPTH in Circle + */ +class CircleSpaceToDepth final + : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::SPACE_TO_DEPTH>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + int block_size(void) const { return _block_size; } + void block_size(int block_size) { _block_size = block_size; } + +private: + int _block_size{0}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_SPACETODEPTH_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSparseToDense.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSparseToDense.h new file mode 100644 index 000000000..9f5051317 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSparseToDense.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCELSPARSETODENSE_H__ +#define __LUCI_IR_CIRCELSPARSETODENSE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SPARSE_TO_DENSE in Circle + */ +class CircleSparseToDense final + : public FixedArityNode<4, CircleNodeImpl<CircleOpcode::SPARSE_TO_DENSE>> +{ +public: + loco::Node *indices(void) const { return at(0)->node(); } + void indices(loco::Node *node) { at(0)->node(node); } + + loco::Node *output_shape(void) const { return at(1)->node(); } + void output_shape(loco::Node *node) { at(1)->node(node); } + + loco::Node *values(void) const { return at(2)->node(); } + void values(loco::Node *node) { at(2)->node(node); } + + loco::Node *default_value(void) const { return at(3)->node(); } + void default_value(loco::Node *node) { at(3)->node(node); } + +public: + bool validate_indices(void) const { return _validate_indices; } + void validate_indices(bool validate_indices) { _validate_indices = validate_indices; } + +private: + bool _validate_indices{true}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCELSPARSETODENSE_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSplit.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplit.h new file mode 100644 index 000000000..0eda19501 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplit.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_SPLIT_H__ +#define __LUCI_IR_CIRCLE_SPLIT_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SPLIT in Circle + */ +class CircleSplit final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::SPLIT>> +{ +public: + loco::Node *split_dim(void) const { return at(0)->node(); } + void split_dim(loco::Node *node) { at(0)->node(node); } + + loco::Node *input(void) const { return at(1)->node(); } + void input(loco::Node *node) { at(1)->node(node); } + +public: + // NOTE it is num_split() not num_splits() as we follow TF name + int32_t num_split(void) const { return _num_split; } + void num_split(int32_t num_split) { _num_split = num_split; } + +private: + int32_t _num_split{0}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_SPLIT_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitOut.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitOut.h new file mode 100644 index 000000000..6bf4a9fef --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitOut.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_SPLITOUT_H__ +#define __LUCI_IR_CIRCLE_SPLITOUT_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief Virtual CIRCLESPLITOUT in Circle + */ +class CircleSplitOut final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLESPLITOUT>> +{ +public: + CircleSplitOut() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + int32_t index(void) const { return _index; } + void index(int32_t index) { _index = index; } + +private: + int32_t _index{-1}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_SPLITOUT_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitV.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitV.h new file mode 100644 index 000000000..1b7d55534 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitV.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_SPLIT_V_H__ +#define __LUCI_IR_CIRCLE_SPLIT_V_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SPLIT_V in Circle + */ +class CircleSplitV final : public FixedArityNode<3, CircleNodeImpl<CircleOpcode::SPLIT_V>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *size_splits(void) const { return at(1)->node(); } + void size_splits(loco::Node *node) { at(1)->node(node); } + + loco::Node *split_dim(void) const { return at(2)->node(); } + void split_dim(loco::Node *node) { at(2)->node(node); } + +public: + // NOTE it is num_split() not num_splits() as we follow TF name + int32_t num_split(void) const { return _num_split; } + void num_split(int32_t num_split) { _num_split = num_split; } + +private: + int32_t _num_split{0}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_SPLIT_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitVOut.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitVOut.h new file mode 100644 index 000000000..d3b2f1e5a --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSplitVOut.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_SPLITVOUT_H__ +#define __LUCI_IR_CIRCLE_SPLITVOUT_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief Virtual CIRCLESPLITVOUT in Circle + */ +class CircleSplitVOut final + : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLESPLITVOUT>> +{ +public: + CircleSplitVOut() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + int32_t index(void) const { return _index; } + void index(int32_t index) { _index = index; } + +private: + int32_t _index{-1}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_SPLITVOUT_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSqrt.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSqrt.h index bc1f39d90..c96ca8498 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleSqrt.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSqrt.h @@ -20,7 +20,6 @@ #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" -#include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSquare.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSquare.h new file mode 100644 index 000000000..a29edfe82 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSquare.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLESQUARE_H__ +#define __LUCI_IR_CIRCLESQUARE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SQUARE in Circle + */ +class CircleSquare final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::SQUARE>> +{ +public: + CircleSquare() = default; + +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLESQUARE_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSquaredDifference.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSquaredDifference.h index ff337dfbe..b5b39f920 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleSquaredDifference.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSquaredDifference.h @@ -20,7 +20,6 @@ #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" -#include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSqueeze.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSqueeze.h new file mode 100644 index 000000000..f175f1411 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSqueeze.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLESQUEEZE_H__ +#define __LUCI_IR_CIRCLESQUEEZE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SQUEEZE in Circle + */ +class CircleSqueeze final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::SQUEEZE>> +{ +public: + CircleSqueeze() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + const std::vector<int32_t> &squeeze_dims() const { return _squeeze_dims; } + void squeeze_dims(const std::vector<int32_t> &squeeze_dims) { _squeeze_dims = squeeze_dims; }; + +private: + std::vector<int32_t> _squeeze_dims{}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLESQUEEZE_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleStridedSlice.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleStridedSlice.h new file mode 100644 index 000000000..98799fec1 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleStridedSlice.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_STRIDEDSLICE_H__ +#define __LUCI_IR_STRIDEDSLICE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief STRIDED_SLICE in Circle + */ +class CircleStridedSlice final + : public FixedArityNode<4, CircleNodeImpl<CircleOpcode::STRIDED_SLICE>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *begin(void) const { return at(1)->node(); } + void begin(loco::Node *node) { at(1)->node(node); } + + loco::Node *end(void) const { return at(2)->node(); } + void end(loco::Node *node) { at(2)->node(node); } + + loco::Node *strides(void) const { return at(3)->node(); } + void strides(loco::Node *node) { at(3)->node(node); } + +public: + int32_t begin_mask() const { return _begin_mask; } + void begin_mask(int32_t mask) { _begin_mask = mask; } + + int32_t end_mask() const { return _end_mask; } + void end_mask(int32_t mask) { _end_mask = mask; } + + int32_t ellipsis_mask() const { return _ellipsis_mask; } + void ellipsis_mask(int32_t mask) { _ellipsis_mask = mask; } + + int32_t new_axis_mask() const { return _new_axis_mask; } + void new_axis_mask(int32_t mask) { _new_axis_mask = mask; } + + int32_t shrink_axis_mask() const { return _shrink_axis_mask; } + void shrink_axis_mask(int32_t mask) { _shrink_axis_mask = mask; } + +private: + int32_t _begin_mask{0}; + int32_t _end_mask{0}; + int32_t _ellipsis_mask{0}; + int32_t _new_axis_mask{0}; + int32_t _shrink_axis_mask{0}; +}; + +} // namespace luci + +#endif // __LUCI_IR_STRIDEDSLICE_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleSum.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleSum.h new file mode 100644 index 000000000..21faa76fe --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleSum.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLESUM_H__ +#define __LUCI_IR_CIRCLESUM_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief SUM in Circle + */ +class CircleSum final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::SUM>> +{ +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *reduction_indices(void) const { return at(1)->node(); } + void reduction_indices(loco::Node *node) { at(1)->node(node); } + +public: + bool keep_dims(void) const { return _keep_dims; } + void keep_dims(bool keep_dims) { _keep_dims = keep_dims; } + +private: + bool _keep_dims = false; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLESUM_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleTanh.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleTanh.h new file mode 100644 index 000000000..f7444921f --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleTanh.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLETANH_H__ +#define __LUCI_IR_CIRCLETANH_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief TANH in Circle + */ +class CircleTanh final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::TANH>> +{ +public: + CircleTanh() = default; + +public: + loco::Node *x(void) const { return at(0)->node(); } + void x(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLETANH_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleTile.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleTile.h new file mode 100644 index 000000000..96e1f69c6 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleTile.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLETILE_H__ +#define __LUCI_IR_CIRCLETILE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief TILE in Circle + */ +class CircleTile final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::TILE>> +{ +public: + CircleTile() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *multiples(void) const { return at(1)->node(); } + void multiples(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLETILE_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleTopKV2.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleTopKV2.h new file mode 100644 index 000000000..3b2b5abb7 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleTopKV2.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_TOPK_V2_H__ +#define __LUCI_IR_CIRCLE_TOPK_V2_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief TOPK_V2 in Circle + */ +class CircleTopKV2 final : public FixedArityNode<2, CircleNodeImpl<CircleOpcode::TOPK_V2>> +{ +public: + CircleTopKV2() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + + loco::Node *k(void) const { return at(1)->node(); } + void k(loco::Node *node) { at(1)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_TOPK_V2_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleTopKV2Out.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleTopKV2Out.h new file mode 100644 index 000000000..5a6dd0c02 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleTopKV2Out.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_TOPK_V2_OUT_H__ +#define __LUCI_IR_CIRCLE_TOPK_V2_OUT_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief Virtual CIRCLETOPKV2OUT in Circle + */ +class CircleTopKV2Out final + : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLETOPKV2OUT>> +{ +public: + CircleTopKV2Out() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + int32_t index(void) const { return _index; } + void index(int32_t index) { _index = index; } + +private: + int32_t _index{-1}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_TOPK_V2_OUT_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleTranspose.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleTranspose.h index 198b56afd..095cd6746 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleTranspose.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleTranspose.h @@ -20,7 +20,6 @@ #include "luci/IR/CircleNodeDecl.h" #include "luci/IR/CircleOpcode.h" -#include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" namespace luci diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleTransposeConv.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleTransposeConv.h index 54a0d010c..fc638d49f 100644 --- a/compiler/luci/lang/include/luci/IR/Nodes/CircleTransposeConv.h +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleTransposeConv.h @@ -22,7 +22,6 @@ #include "luci/IR/AttrPadding.h" #include "luci/IR/AttrStride.h" -#include "luci/IR/AttrFusedActFunc.h" #include "luci/IR/LuciNodeMixins.h" namespace luci @@ -55,7 +54,7 @@ public: Stride *stride(void) { return &_stride; } private: - Padding _padding; + Padding _padding{Padding::UNDEFINED}; Stride _stride; }; diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleUnpack.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleUnpack.h new file mode 100644 index 000000000..cb91d7e6a --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleUnpack.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_UNPACK_H__ +#define __LUCI_IR_CIRCLE_UNPACK_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief UNPACK in Circle + */ +class CircleUnpack final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::UNPACK>> +{ +public: + CircleUnpack() = default; + +public: + loco::Node *value(void) const { return at(0)->node(); } + void value(loco::Node *node) { at(0)->node(node); } + +public: + int32_t num(void) const { return _num; } + void num(int32_t num) { _num = num; } + + int32_t axis(void) const { return _axis; } + void axis(int32_t axis) { _axis = axis; } + +private: + int32_t _num{0}; + int32_t _axis{0}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_UNPACK_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleUnpackOut.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleUnpackOut.h new file mode 100644 index 000000000..6f24578a1 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleUnpackOut.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_UNPACKOUT_H__ +#define __LUCI_IR_CIRCLE_UNPACKOUT_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief Virtual CIRCLEUNPACKOUT in Circle + */ +class CircleUnpackOut final + : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLEUNPACKOUT>> +{ +public: + CircleUnpackOut() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + int32_t index(void) const { return _index; } + void index(int32_t index) { _index = index; } + +private: + int32_t _index{0}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_UNPACKOUT_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleWhere.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleWhere.h new file mode 100644 index 000000000..51eda3d6e --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleWhere.h @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_WHERE_H__ +#define __LUCI_IR_CIRCLE_WHERE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +#include <cassert> + +namespace luci +{ + +/** + * @brief WHERE in Circle + */ +class CircleWhere final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::WHERE>> +{ +public: + CircleWhere() = default; + +public: + loco::Node *condition() const { return at(0)->node(); } + void condition(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_WHERE_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleWhile.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleWhile.h new file mode 100644 index 000000000..40ec96414 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleWhile.h @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_WHILE_H__ +#define __LUCI_IR_CIRCLE_WHILE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/VariadicArityNode.h" + +#include <cassert> + +namespace luci +{ + +/** + * @brief WHILE in Circle + */ +class CircleWhile final : public VariadicArityNode<CircleNodeImpl<CircleOpcode::WHILE>> +{ +public: + CircleWhile(uint32_t arity, uint32_t out) + : VariadicArityNode<CircleNodeImpl<CircleOpcode::WHILE>>(arity), _output_count(out) + { + assert(arity > 0); + assert(out > 0); + + // input and output must have the same size + assert(arity == out); + } + +public: + uint32_t input_count(void) const { return arity(); } + uint32_t output_count(void) const { return _output_count; } + +public: + Node *input(uint32_t index) const { return at(index)->node(); } + void input(uint32_t index, Node *node) { at(index)->node(node); } + +public: + int32_t cond_branch(void) const { return _cond_branch; } + void cond_branch(int32_t cond_branch) { _cond_branch = cond_branch; } + + int32_t body_branch(void) const { return _body_branch; } + void body_branch(int32_t body_branch) { _body_branch = body_branch; } + +public: + loco::Graph *cond_graph(void) const { return _cond_graph; } + void cond_graph(loco::Graph *cond_graph) { _cond_graph = cond_graph; } + + loco::Graph *body_graph(void) const { return _body_graph; } + void body_graph(loco::Graph *body_graph) { _body_graph = body_graph; } + +private: + uint32_t _output_count{0}; + int32_t _cond_branch{-1}; + int32_t _body_branch{-1}; + + loco::Graph *_cond_graph{nullptr}; + loco::Graph *_body_graph{nullptr}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_WHILE_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleWhileOut.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleWhileOut.h new file mode 100644 index 000000000..cdf617848 --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleWhileOut.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_WHILEOUT_H__ +#define __LUCI_IR_CIRCLE_WHILEOUT_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief Virtual CIRCLEWHILEOUT in Circle + */ +class CircleWhileOut final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::CIRCLEWHILEOUT>> +{ +public: + CircleWhileOut() = default; + +public: + loco::Node *input(void) const { return at(0)->node(); } + void input(loco::Node *node) { at(0)->node(node); } + +public: + int32_t index(void) const { return _index; } + void index(int32_t index) { _index = index; } + +private: + int32_t _index{-1}; +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_WHILEOUT_H__ diff --git a/compiler/luci/lang/include/luci/IR/Nodes/CircleZerosLike.h b/compiler/luci/lang/include/luci/IR/Nodes/CircleZerosLike.h new file mode 100644 index 000000000..d3b6d272a --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/Nodes/CircleZerosLike.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_CIRCLE_ZEROS_LIKE_H__ +#define __LUCI_IR_CIRCLE_ZEROS_LIKE_H__ + +#include "luci/IR/CircleNodeDecl.h" +#include "luci/IR/CircleOpcode.h" + +#include "luci/IR/LuciNodeMixins.h" + +namespace luci +{ + +/** + * @brief ZEROS_LIKE in Circle + */ +class CircleZerosLike final : public FixedArityNode<1, CircleNodeImpl<CircleOpcode::ZEROS_LIKE>> +{ +public: + CircleZerosLike() = default; + +public: + /// @brief Get the input node + loco::Node *input(void) const { return at(0)->node(); } + + /// @brief Set the input node + void input(loco::Node *node) { at(0)->node(node); } +}; + +} // namespace luci + +#endif // __LUCI_IR_CIRCLE_ZEROS_LIKE_H__ diff --git a/compiler/luci/lang/include/luci/IR/PropertyShapeStatus.h b/compiler/luci/lang/include/luci/IR/PropertyShapeStatus.h new file mode 100644 index 000000000..179a8ab3c --- /dev/null +++ b/compiler/luci/lang/include/luci/IR/PropertyShapeStatus.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_IR_PROPERTY_SHAPE_STATUS_H__ +#define __LUCI_IR_PROPERTY_SHAPE_STATUS_H__ + +namespace luci +{ + +/** + * @brief ShapeStatus is to remember circle node shape status. + * @note This is not an attribute from the file but inner status of a node. + * Shape with [] is scalar but sometimes it acts as dynamic shape. + */ +enum class ShapeStatus +{ + UNDEFINED, // Shape status is undefined + + NOSHAPE, // shape is unknown; to distinguish from scalar + VALID, // shape is valid +}; + +} // namespace luci + +#endif // __LUCI_IR_PROPERTY_SHAPE_STATUS_H__ diff --git a/compiler/luci/lang/include/luci/IR/VariadicArityNode.h b/compiler/luci/lang/include/luci/IR/VariadicArityNode.h index a4814ee48..e83d90978 100644 --- a/compiler/luci/lang/include/luci/IR/VariadicArityNode.h +++ b/compiler/luci/lang/include/luci/IR/VariadicArityNode.h @@ -46,11 +46,7 @@ public: public: uint32_t arity(void) const final { return _args.size(); } - loco::Node *arg(uint32_t n) const final - { - assert(n < _args.size()); - return _args.at(n)->node(); - } + loco::Node *arg(uint32_t n) const final { return _args.at(n)->node(); } void drop(void) final { @@ -62,11 +58,7 @@ public: protected: // This API allows inherited classes to access "_args" field. - loco::Use *at(uint32_t n) const - { - assert(n < _args.size()); - return _args.at(n).get(); - } + loco::Use *at(uint32_t n) const { return _args.at(n).get(); } private: std::vector<std::unique_ptr<loco::Use>> _args; diff --git a/compiler/luci/lang/src/CircleDialect.cpp b/compiler/luci/lang/src/CircleDialect.cpp index e1c925de4..42ca3c917 100644 --- a/compiler/luci/lang/src/CircleDialect.cpp +++ b/compiler/luci/lang/src/CircleDialect.cpp @@ -22,6 +22,8 @@ #include <loco/IR/GraphInputIndex.h> #include <loco/IR/GraphOutputIndex.h> +#include "DeadNodeQueryService.h" + #include <cassert> #include <memory> @@ -42,8 +44,7 @@ struct GiiQueryServiceImpl final : public loco::GraphInputIndexQueryService loco::GraphOutputIndex index(const loco::Node *node) const final { assert(associated(node)); - auto circleinput = dynamic_cast<const luci::CircleInput *>(node); - assert(circleinput != nullptr); + auto circleinput = loco::must_cast<const luci::CircleInput *>(node); return circleinput->index(); } }; @@ -62,8 +63,7 @@ struct GoiQueryServiceImpl final : public loco::GraphOutputIndexQueryService loco::GraphOutputIndex index(const loco::Node *node) const final { assert(associated(node)); - auto circleoutput = dynamic_cast<const luci::CircleOutput *>(node); - assert(circleoutput != nullptr); + auto circleoutput = loco::must_cast<const luci::CircleOutput *>(node); return circleoutput->index(); } }; @@ -77,6 +77,7 @@ CircleDialect::CircleDialect() { service<loco::GraphInputIndexQueryService>(std::make_unique<GiiQueryServiceImpl>()); service<loco::GraphOutputIndexQueryService>(std::make_unique<GoiQueryServiceImpl>()); + service<logo::DeadNodeQueryService>(std::make_unique<DeadNodeQueryServiceImpl>()); } loco::Dialect *CircleDialect::get(void) diff --git a/compiler/luci/lang/src/CircleDialect.test.cpp b/compiler/luci/lang/src/CircleDialect.test.cpp index 78221f199..a09c105ec 100644 --- a/compiler/luci/lang/src/CircleDialect.test.cpp +++ b/compiler/luci/lang/src/CircleDialect.test.cpp @@ -15,6 +15,10 @@ */ #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodes.h" + +#include <loco.h> +#include <logo/DeadNodeQueryService.h> #include <gtest/gtest.h> @@ -25,10 +29,59 @@ TEST(CircleDialectTest, get_P) // get() SHOULD return a valid(non-null) pointer ASSERT_NE(d, nullptr); // The return value SHOULD be stable across multiple invocations - ASSERT_EQ(d, luci::CircleDialect::get()); + ASSERT_EQ(luci::CircleDialect::get(), d); } -TEST(CircleDialectTest, get_N) +TEST(CircleDialectTest, check_if_dead_node_service) { - // TBD + /** + * [CircleInput1] [CircleInput2] [CircleInput3] + * \ / (dangling input) + * \ / + * [CircleAdd] [CircleBatchMatMul] + * | (dangling node) + * | + * [CircleOutput1] [CircleOutput2] + * (dangling output) + */ + auto g = loco::make_graph(); + + auto graph_input1 = g->inputs()->create(); + auto circle_input1 = g->nodes()->create<luci::CircleInput>(); + circle_input1->index(graph_input1->index()); + + auto graph_input2 = g->inputs()->create(); + auto circle_input2 = g->nodes()->create<luci::CircleInput>(); + circle_input2->index(graph_input2->index()); + + // dangling output + auto graph_input3 = g->inputs()->create(); + auto dangling_input = g->nodes()->create<luci::CircleInput>(); + dangling_input->index(graph_input3->index()); + + auto active_node = g->nodes()->create<luci::CircleAdd>(); + active_node->x(circle_input1); + active_node->y(circle_input2); + + auto dangling_node = g->nodes()->create<luci::CircleBatchMatMul>(); + + auto graph_output1 = g->outputs()->create(); + auto circle_output1 = g->nodes()->create<luci::CircleOutput>(); + circle_output1->index(graph_output1->index()); + circle_output1->from(active_node); + + // dangling output + auto graph_output2 = g->outputs()->create(); + auto circle_output2 = g->nodes()->create<luci::CircleOutput>(); + circle_output2->index(graph_output2->index()); + + auto service = active_node->dialect()->service<logo::DeadNodeQueryService>(); + + ASSERT_TRUE(service->isDeadNode(dangling_node)); + ASSERT_FALSE(service->isDeadNode(dangling_input)); + ASSERT_FALSE(service->isDeadNode(active_node)); + ASSERT_FALSE(service->isDeadNode(circle_input1)); + ASSERT_FALSE(service->isDeadNode(circle_input2)); + ASSERT_FALSE(service->isDeadNode(circle_output1)); + ASSERT_FALSE(service->isDeadNode(circle_output2)); } diff --git a/compiler/luci/lang/src/CircleNodeShapeDtype.test.cpp b/compiler/luci/lang/src/CircleNodeShapeDtype.test.cpp new file mode 100644 index 000000000..61eab4b77 --- /dev/null +++ b/compiler/luci/lang/src/CircleNodeShapeDtype.test.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/CircleNodes.h" + +#include <gtest/gtest.h> + +TEST(CircleNodeShapeDTypeTest, constructor) +{ + luci::CircleAdd node; + + ASSERT_EQ(loco::DataType::Unknown, node.dtype()); + ASSERT_EQ(0, node.rank()); +} + +TEST(CircleNodeShapeDTypeTest, values) +{ + luci::CircleAdd node; + + node.dtype(loco::DataType::FLOAT32); + ASSERT_EQ(loco::DataType::FLOAT32, node.dtype()); + + node.rank(4); + ASSERT_EQ(4, node.rank()); + ASSERT_FALSE(node.dim(0).known()); + + node.dim(0) = loco::Dimension(1); + ASSERT_TRUE(node.dim(0).known()); + ASSERT_EQ(1, node.dim(0).value()); +} + +TEST(CircleNodeShapeDTypeTest, values_NEG) +{ + luci::CircleAdd node; + + node.rank(4); + EXPECT_ANY_THROW(node.dim(100).known()); + EXPECT_ANY_THROW(node.dim(100) = loco::Dimension(1)); +} diff --git a/compiler/luci/lang/src/CircleNodes.cpp b/compiler/luci/lang/src/CircleNodes.cpp index 76ff7ec5a..c77c06861 100644 --- a/compiler/luci/lang/src/CircleNodes.cpp +++ b/compiler/luci/lang/src/CircleNodes.cpp @@ -37,6 +37,7 @@ void set_new_shape(CircleReshape *node, int32_t *base, uint32_t size) const_shape_node->dim(0) = size; const_shape_node->dtype(S32); const_shape_node->size<S32>(size); + const_shape_node->shape_status(luci::ShapeStatus::VALID); for (uint32_t axis = 0; axis < size; ++axis) const_shape_node->at<S32>(axis) = base[axis]; node->shape(const_shape_node); @@ -47,4 +48,38 @@ void set_new_shape(CircleReshape *node, int32_t *base, uint32_t size) node->newShape()->dim(axis) = base[axis]; } +void link(loco::GraphOutput *output, CircleOutput *node) { node->index(output->index()); } + +CircleOutput *output_node(loco::Graph *g, const loco::GraphOutputIndex &index) +{ + for (uint32_t n = 0; n < g->nodes()->size(); ++n) + { + if (auto output = dynamic_cast<CircleOutput *>(g->nodes()->at(n))) + { + if (output->indexed() && output->index() == index) + { + return output; + } + } + } + return nullptr; +} + +void link(loco::GraphInput *input, CircleInput *node) { node->index(input->index()); } + +CircleInput *input_node(loco::Graph *g, const loco::GraphInputIndex &index) +{ + for (uint32_t n = 0; n < g->nodes()->size(); ++n) + { + if (auto input = dynamic_cast<CircleInput *>(g->nodes()->at(n))) + { + if (input->indexed() && input->index() == index) + { + return input; + } + } + } + return nullptr; +} + } // namespace luci diff --git a/compiler/luci/lang/src/DeadNodeQueryService.cpp b/compiler/luci/lang/src/DeadNodeQueryService.cpp new file mode 100644 index 000000000..a22574c94 --- /dev/null +++ b/compiler/luci/lang/src/DeadNodeQueryService.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "DeadNodeQueryService.h" + +#include "luci/IR/CircleNodeVisitor.h" + +#include <loco/IR/Graph.h> + +namespace luci +{ + +struct VirtualOutputDetector final : public luci::CircleNodeMutableVisitor<bool> +{ + bool visit(luci::CircleIfOut *) final { return true; } + bool visit(luci::CircleSplitOut *) final { return true; } + bool visit(luci::CircleSplitVOut *) final { return true; } + bool visit(luci::CircleTopKV2Out *) final { return true; } + bool visit(luci::CircleUnpackOut *) final { return true; } + bool visit(luci::CircleWhileOut *) final { return true; } + // TODO add more nodes that multi output virtual nodes + + // default is false + bool visit(luci::CircleNode *) final { return false; } +}; + +bool DeadNodeQueryServiceImpl::isDeadNode(loco::Node *node) +{ + auto g = node->graph(); + auto input_nodes_vec = loco::input_nodes(g); + auto output_nodes_vec = loco::output_nodes(g); + + auto input_nodes = std::set<loco::Node *>(input_nodes_vec.begin(), input_nodes_vec.end()); + auto output_nodes = std::set<loco::Node *>(output_nodes_vec.begin(), output_nodes_vec.end()); + auto active_nodes = loco::active_nodes(output_nodes_vec); + + if (active_nodes.find(node) != active_nodes.end()) + return false; + // input and output nodes are not dead node even if it is not active. + if (input_nodes.find(node) != input_nodes.end()) + return false; + + // if node is one of virtual mulitple outputs, we need to ask the real node + if (auto circle_node = dynamic_cast<luci::CircleNode *>(node)) + { + VirtualOutputDetector d; + if (circle_node->accept(&d)) + { + assert(node->arity() == 1); + loco::Node *real_node = node->arg(0); + if (active_nodes.find(real_node) != active_nodes.end()) + return false; + if (input_nodes.find(real_node) != input_nodes.end()) + return false; + } + } + + return true; +} + +} // namespace luci diff --git a/compiler/luci/lang/src/DeadNodeQueryService.h b/compiler/luci/lang/src/DeadNodeQueryService.h new file mode 100644 index 000000000..d10696667 --- /dev/null +++ b/compiler/luci/lang/src/DeadNodeQueryService.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_LANG_DEADNODEQUERYSERVICE_H__ +#define __LUCI_LANG_DEADNODEQUERYSERVICE_H__ + +#include <logo/DeadNodeQueryService.h> + +#include <loco/IR/Node.h> + +namespace luci +{ + +struct DeadNodeQueryServiceImpl final : public logo::DeadNodeQueryService +{ + bool isDeadNode(loco::Node *node) final; +}; + +} // namespace luci + +#endif // __LUCI_LANG_DEADNODEQUERYSERVICE_H__ diff --git a/compiler/luci/lang/src/Module.cpp b/compiler/luci/lang/src/Module.cpp index e52d897a5..80ef61910 100644 --- a/compiler/luci/lang/src/Module.cpp +++ b/compiler/luci/lang/src/Module.cpp @@ -43,4 +43,4 @@ loco::Graph *Module::graph(size_t idx) const std::unique_ptr<Module> make_module(void) { return std::make_unique<Module>(); } -} // namespace loco +} // namespace luci diff --git a/compiler/luci/lang/src/Module.test.cpp b/compiler/luci/lang/src/Module.test.cpp index f60319944..26bf073be 100644 --- a/compiler/luci/lang/src/Module.test.cpp +++ b/compiler/luci/lang/src/Module.test.cpp @@ -33,8 +33,8 @@ TEST(ModuleTest, add) m->add(std::move(g)); - ASSERT_EQ(m->graph(), g_ptr); - ASSERT_EQ(m->graph(0), g_ptr); + ASSERT_EQ(g_ptr, m->graph()); + ASSERT_EQ(g_ptr, m->graph(0)); } TEST(ModuleTest, add_more) @@ -51,11 +51,11 @@ TEST(ModuleTest, add_more) m->add(std::move(g2)); m->add(std::move(g3)); - ASSERT_EQ(m->size(), 3); - ASSERT_EQ(m->graph(), g1_ptr); - ASSERT_EQ(m->graph(0), g1_ptr); - ASSERT_EQ(m->graph(1), g2_ptr); - ASSERT_EQ(m->graph(2), g3_ptr); + ASSERT_EQ(3, m->size()); + ASSERT_EQ(g1_ptr, m->graph()); + ASSERT_EQ(g1_ptr, m->graph(0)); + ASSERT_EQ(g2_ptr, m->graph(1)); + ASSERT_EQ(g3_ptr, m->graph(2)); } TEST(ModuleTest, add_nullptr_NEG) diff --git a/compiler/luci/lang/src/Nodes/CircleAbs.test.cpp b/compiler/luci/lang/src/Nodes/CircleAbs.test.cpp index 847f1500b..f97becba8 100644 --- a/compiler/luci/lang/src/Nodes/CircleAbs.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleAbs.test.cpp @@ -17,15 +17,78 @@ #include "luci/IR/Nodes/CircleAbs.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> +#include <memory> + TEST(CircleAbsTest, constructor) { luci::CircleAbs abs_node; - ASSERT_EQ(abs_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(abs_node.opcode(), luci::CircleOpcode::ABS); + ASSERT_EQ(luci::CircleDialect::get(), abs_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::ABS, abs_node.opcode()); + + ASSERT_EQ(nullptr, abs_node.x()); +} + +TEST(CircleAbsTest, common_NEG) +{ + luci::CircleAbs abs_node; + + abs_node.name("name"); + ASSERT_EQ("name", abs_node.name()); + + auto q = std::make_unique<luci::CircleQuantParam>(); + abs_node.quantparam(std::move(q)); + ASSERT_NE(nullptr, abs_node.quantparam()); + + ASSERT_EQ(luci::ShapeStatus::UNDEFINED, abs_node.shape_status()); + abs_node.shape_status(luci::ShapeStatus::NOSHAPE); + ASSERT_NE(luci::ShapeStatus::UNDEFINED, abs_node.shape_status()); +} + +TEST(CircleAbsTest, input_NEG) +{ + luci::CircleAbs abs_node; + luci::CircleAbs node; + + abs_node.x(&node); + ASSERT_NE(nullptr, abs_node.x()); + + abs_node.x(nullptr); + ASSERT_EQ(nullptr, abs_node.x()); +} + +TEST(CircleAbsTest, arity_NEG) +{ + luci::CircleAbs abs_node; + + ASSERT_NO_THROW(abs_node.arg(0)); + ASSERT_THROW(abs_node.arg(1), std::out_of_range); +} + +TEST(CircleAbsTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleAbs abs_node; + + TestVisitor tv; + ASSERT_THROW(abs_node.accept(&tv), std::exception); +} + +TEST(CircleAbsTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleAbs abs_node; - ASSERT_EQ(abs_node.x(), nullptr); + TestVisitor tv; + ASSERT_THROW(abs_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleAdd.test.cpp b/compiler/luci/lang/src/Nodes/CircleAdd.test.cpp index a7701963d..382faa5ef 100644 --- a/compiler/luci/lang/src/Nodes/CircleAdd.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleAdd.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleAdd.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,9 +25,57 @@ TEST(CircleAddTest, constructor_P) { luci::CircleAdd add_node; - ASSERT_EQ(add_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(add_node.opcode(), luci::CircleOpcode::ADD); + ASSERT_EQ(luci::CircleDialect::get(), add_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::ADD, add_node.opcode()); - ASSERT_EQ(add_node.x(), nullptr); - ASSERT_EQ(add_node.y(), nullptr); + ASSERT_EQ(nullptr, add_node.x()); + ASSERT_EQ(nullptr, add_node.y()); +} + +TEST(CircleAddTest, input_NEG) +{ + luci::CircleAdd add_node; + luci::CircleAdd node; + + add_node.x(&node); + add_node.y(&node); + ASSERT_NE(nullptr, add_node.x()); + ASSERT_NE(nullptr, add_node.y()); + + add_node.x(nullptr); + add_node.y(nullptr); + ASSERT_EQ(nullptr, add_node.x()); + ASSERT_EQ(nullptr, add_node.y()); +} + +TEST(CircleAddTest, arity_NEG) +{ + luci::CircleAdd add_node; + + ASSERT_NO_THROW(add_node.arg(1)); + ASSERT_THROW(add_node.arg(2), std::out_of_range); +} + +TEST(CircleAddTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleAdd add_node; + + TestVisitor tv; + ASSERT_THROW(add_node.accept(&tv), std::exception); +} + +TEST(CircleAddTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleAdd add_node; + + TestVisitor tv; + ASSERT_THROW(add_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleAddN.test.cpp b/compiler/luci/lang/src/Nodes/CircleAddN.test.cpp new file mode 100644 index 000000000..399d8cb82 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleAddN.test.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleAddN.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleAddNTest, constructor) +{ + luci::CircleAddN add_node(3); + + ASSERT_EQ(luci::CircleDialect::get(), add_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::ADD_N, add_node.opcode()); + + ASSERT_EQ(nullptr, add_node.inputs(0)); + ASSERT_EQ(nullptr, add_node.inputs(1)); + ASSERT_EQ(nullptr, add_node.inputs(2)); +} + +TEST(CircleAddNTest, input_NEG) +{ + luci::CircleAddN add_node(3); + luci::CircleAddN node(2); + + add_node.inputs(0, &node); + add_node.inputs(1, &node); + add_node.inputs(2, &node); + ASSERT_NE(nullptr, add_node.inputs(0)); + ASSERT_NE(nullptr, add_node.inputs(1)); + ASSERT_NE(nullptr, add_node.inputs(2)); + + add_node.inputs(0, nullptr); + add_node.inputs(1, nullptr); + add_node.inputs(2, nullptr); + ASSERT_EQ(nullptr, add_node.inputs(0)); + ASSERT_EQ(nullptr, add_node.inputs(1)); + ASSERT_EQ(nullptr, add_node.inputs(2)); +} + +TEST(CircleAddNTest, arity_NEG) +{ + luci::CircleAddN add_node(3); + luci::CircleAddN node(2); + + ASSERT_NO_THROW(add_node.inputs(2, &node)); + ASSERT_NO_THROW(add_node.inputs(2, nullptr)); + ASSERT_THROW(add_node.inputs(3, &node), std::out_of_range); + + ASSERT_NO_THROW(add_node.arg(2)); + ASSERT_THROW(add_node.arg(3), std::out_of_range); +} + +TEST(CircleAddNTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleAddN add_node(2); + + TestVisitor tv; + ASSERT_THROW(add_node.accept(&tv), std::exception); +} + +TEST(CircleAddNTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleAddN add_node(2); + + TestVisitor tv; + ASSERT_THROW(add_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleArgMax.test.cpp b/compiler/luci/lang/src/Nodes/CircleArgMax.test.cpp index 6b2cff11c..375a74c20 100644 --- a/compiler/luci/lang/src/Nodes/CircleArgMax.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleArgMax.test.cpp @@ -17,16 +17,65 @@ #include "luci/IR/Nodes/CircleArgMax.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> TEST(CircleArgMaxTest, constructor_P) { - luci::CircleArgMax add_node; + luci::CircleArgMax argmax_node; - ASSERT_EQ(add_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(add_node.opcode(), luci::CircleOpcode::ARG_MAX); + ASSERT_EQ(luci::CircleDialect::get(), argmax_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::ARG_MAX, argmax_node.opcode()); - ASSERT_EQ(add_node.input(), nullptr); - ASSERT_EQ(add_node.dimension(), nullptr); + ASSERT_EQ(nullptr, argmax_node.input()); + ASSERT_EQ(nullptr, argmax_node.dimension()); +} + +TEST(CircleArgMaxTest, input_NEG) +{ + luci::CircleArgMax argmax_node; + luci::CircleArgMax node; + + argmax_node.input(&node); + argmax_node.dimension(&node); + ASSERT_NE(nullptr, argmax_node.input()); + ASSERT_NE(nullptr, argmax_node.dimension()); + + argmax_node.input(nullptr); + argmax_node.dimension(nullptr); + ASSERT_EQ(nullptr, argmax_node.input()); + ASSERT_EQ(nullptr, argmax_node.dimension()); +} + +TEST(CircleArgMaxTest, arity_NEG) +{ + luci::CircleArgMax argmax_node; + + ASSERT_NO_THROW(argmax_node.arg(1)); + ASSERT_THROW(argmax_node.arg(2), std::out_of_range); +} + +TEST(CircleArgMaxTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleArgMax argmax_node; + + TestVisitor tv; + ASSERT_THROW(argmax_node.accept(&tv), std::exception); +} + +TEST(CircleArgMaxTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleArgMax argmax_node; + + TestVisitor tv; + ASSERT_THROW(argmax_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleArgMin.test.cpp b/compiler/luci/lang/src/Nodes/CircleArgMin.test.cpp new file mode 100644 index 000000000..6607bf82f --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleArgMin.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleArgMin.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleArgMinTest, constructor_P) +{ + luci::CircleArgMin argmin_node; + + ASSERT_EQ(luci::CircleDialect::get(), argmin_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::ARG_MIN, argmin_node.opcode()); + + ASSERT_EQ(nullptr, argmin_node.input()); + ASSERT_EQ(nullptr, argmin_node.dimension()); +} + +TEST(CircleArgMinTest, input_NEG) +{ + luci::CircleArgMin argmin_node; + luci::CircleArgMin node; + + argmin_node.input(&node); + argmin_node.dimension(&node); + ASSERT_NE(nullptr, argmin_node.input()); + ASSERT_NE(nullptr, argmin_node.dimension()); + + argmin_node.input(nullptr); + argmin_node.dimension(nullptr); + ASSERT_EQ(nullptr, argmin_node.input()); + ASSERT_EQ(nullptr, argmin_node.dimension()); +} + +TEST(CircleArgMinTest, arity_NEG) +{ + luci::CircleArgMin argmin_node; + + ASSERT_NO_THROW(argmin_node.arg(1)); + ASSERT_THROW(argmin_node.arg(2), std::out_of_range); +} + +TEST(CircleArgMinTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleArgMin argmin_node; + + TestVisitor tv; + ASSERT_THROW(argmin_node.accept(&tv), std::exception); +} + +TEST(CircleArgMinTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleArgMin argmin_node; + + TestVisitor tv; + ASSERT_THROW(argmin_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleAveragePool2D.test.cpp b/compiler/luci/lang/src/Nodes/CircleAveragePool2D.test.cpp new file mode 100644 index 000000000..fc7265cf0 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleAveragePool2D.test.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleAveragePool2D.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleAveragePool2DTest, constructor_P) +{ + luci::CircleAveragePool2D average_pool_2d_node; + + ASSERT_EQ(luci::CircleDialect::get(), average_pool_2d_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::AVERAGE_POOL_2D, average_pool_2d_node.opcode()); + + ASSERT_EQ(nullptr, average_pool_2d_node.value()); + ASSERT_EQ(luci::Padding::UNDEFINED, average_pool_2d_node.padding()); + ASSERT_EQ(1, average_pool_2d_node.filter()->h()); + ASSERT_EQ(1, average_pool_2d_node.filter()->w()); + ASSERT_EQ(1, average_pool_2d_node.stride()->h()); + ASSERT_EQ(1, average_pool_2d_node.stride()->w()); +} + +TEST(CircleAveragePool2DTest, input_NEG) +{ + luci::CircleAveragePool2D avgpool_node; + luci::CircleAveragePool2D node; + + avgpool_node.value(&node); + ASSERT_NE(nullptr, avgpool_node.value()); + + avgpool_node.value(nullptr); + ASSERT_EQ(nullptr, avgpool_node.value()); + + avgpool_node.filter()->h(2); + avgpool_node.filter()->w(2); + avgpool_node.stride()->h(2); + avgpool_node.stride()->w(2); + ASSERT_NE(1, avgpool_node.filter()->h()); + ASSERT_NE(1, avgpool_node.filter()->w()); + ASSERT_NE(1, avgpool_node.stride()->h()); + ASSERT_NE(1, avgpool_node.stride()->w()); +} + +TEST(CircleAveragePool2DTest, arity_NEG) +{ + luci::CircleAveragePool2D avgpool_node; + + ASSERT_NO_THROW(avgpool_node.arg(0)); + ASSERT_THROW(avgpool_node.arg(1), std::out_of_range); +} + +TEST(CircleAveragePool2DTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleAveragePool2D avgpool_node; + + TestVisitor tv; + ASSERT_THROW(avgpool_node.accept(&tv), std::exception); +} + +TEST(CircleAveragePool2DTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleAveragePool2D avgpool_node; + + TestVisitor tv; + ASSERT_THROW(avgpool_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleBCQFullyConnected.test.cpp b/compiler/luci/lang/src/Nodes/CircleBCQFullyConnected.test.cpp new file mode 100644 index 000000000..35c9ab95b --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleBCQFullyConnected.test.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleBCQFullyConnected.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleBCQFullyConnectedTest, constructor) +{ + luci::CircleBCQFullyConnected bcq_FC_node; + + ASSERT_EQ(luci::CircleDialect::get(), bcq_FC_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::BCQ_FULLY_CONNECTED, bcq_FC_node.opcode()); + + ASSERT_EQ(nullptr, bcq_FC_node.input()); + ASSERT_EQ(nullptr, bcq_FC_node.weights_scales()); + ASSERT_EQ(nullptr, bcq_FC_node.weights_binary()); + ASSERT_EQ(nullptr, bcq_FC_node.bias()); + ASSERT_EQ(nullptr, bcq_FC_node.weights_clusters()); + + ASSERT_EQ(luci::FusedActFunc::UNDEFINED, bcq_FC_node.fusedActivationFunction()); + ASSERT_EQ(0, bcq_FC_node.weights_hidden_size()); +} diff --git a/compiler/luci/lang/src/Nodes/CircleBCQGather.test.cpp b/compiler/luci/lang/src/Nodes/CircleBCQGather.test.cpp new file mode 100644 index 000000000..c187a9033 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleBCQGather.test.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleBCQGather.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleBCQGatherTest, constructor) +{ + luci::CircleBCQGather bcq_gather_node; + + ASSERT_EQ(luci::CircleDialect::get(), bcq_gather_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::BCQ_GATHER, bcq_gather_node.opcode()); + + ASSERT_EQ(nullptr, bcq_gather_node.input_scales()); + ASSERT_EQ(nullptr, bcq_gather_node.input_binary()); + ASSERT_EQ(nullptr, bcq_gather_node.indices()); + ASSERT_EQ(nullptr, bcq_gather_node.input_clusters()); + + ASSERT_EQ(0, bcq_gather_node.axis()); + ASSERT_EQ(0, bcq_gather_node.input_hidden_size()); +} diff --git a/compiler/luci/lang/src/Nodes/CircleBatchMatMul.test.cpp b/compiler/luci/lang/src/Nodes/CircleBatchMatMul.test.cpp new file mode 100644 index 000000000..d7712c8dd --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleBatchMatMul.test.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleBatchMatMul.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleBatchMatMulTest, constructor) +{ + luci::CircleBatchMatMul batchmatmul_node; + + ASSERT_EQ(luci::CircleDialect::get(), batchmatmul_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::BATCHMATMUL, batchmatmul_node.opcode()); + + ASSERT_EQ(nullptr, batchmatmul_node.x()); + ASSERT_EQ(nullptr, batchmatmul_node.y()); + + ASSERT_FALSE(batchmatmul_node.adj_x()); + ASSERT_FALSE(batchmatmul_node.adj_y()); +} + +TEST(CircleBatchMatMulTest, input_NEG) +{ + luci::CircleBatchMatMul batchmatmul_node; + luci::CircleBatchMatMul node; + + batchmatmul_node.x(&node); + batchmatmul_node.y(&node); + ASSERT_NE(nullptr, batchmatmul_node.x()); + ASSERT_NE(nullptr, batchmatmul_node.y()); + + batchmatmul_node.x(nullptr); + batchmatmul_node.y(nullptr); + ASSERT_EQ(nullptr, batchmatmul_node.x()); + ASSERT_EQ(nullptr, batchmatmul_node.y()); +} + +TEST(CircleBatchMatMulTest, arity_NEG) +{ + luci::CircleBatchMatMul batchmatmul_node; + + ASSERT_NO_THROW(batchmatmul_node.arg(1)); + ASSERT_THROW(batchmatmul_node.arg(2), std::out_of_range); +} + +TEST(CircleBatchMatMulTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleBatchMatMul batchmatmul_node; + + TestVisitor tv; + ASSERT_THROW(batchmatmul_node.accept(&tv), std::exception); +} + +TEST(CircleBatchMatMulTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleBatchMatMul batchmatmul_node; + + TestVisitor tv; + ASSERT_THROW(batchmatmul_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleBatchToSpaceND.test.cpp b/compiler/luci/lang/src/Nodes/CircleBatchToSpaceND.test.cpp index e995718a1..0374fe008 100644 --- a/compiler/luci/lang/src/Nodes/CircleBatchToSpaceND.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleBatchToSpaceND.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleBatchToSpaceND.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,10 +25,62 @@ TEST(CircleBatchToSpaceNDTest, constructor) { luci::CircleBatchToSpaceND bts_node; - ASSERT_EQ(bts_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(bts_node.opcode(), luci::CircleOpcode::BATCH_TO_SPACE_ND); + ASSERT_EQ(luci::CircleDialect::get(), bts_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::BATCH_TO_SPACE_ND, bts_node.opcode()); - ASSERT_EQ(bts_node.input(), nullptr); - ASSERT_EQ(bts_node.block_shape(), nullptr); - ASSERT_EQ(bts_node.crops(), nullptr); + ASSERT_EQ(nullptr, bts_node.input()); + ASSERT_EQ(nullptr, bts_node.block_shape()); + ASSERT_EQ(nullptr, bts_node.crops()); +} + +TEST(CircleBatchToSpaceNDTest, input_NEG) +{ + luci::CircleBatchToSpaceND bts_node; + luci::CircleBatchToSpaceND node; + + bts_node.input(&node); + bts_node.block_shape(&node); + bts_node.crops(&node); + ASSERT_NE(nullptr, bts_node.input()); + ASSERT_NE(nullptr, bts_node.block_shape()); + ASSERT_NE(nullptr, bts_node.crops()); + + bts_node.input(nullptr); + bts_node.block_shape(nullptr); + bts_node.crops(nullptr); + ASSERT_EQ(nullptr, bts_node.input()); + ASSERT_EQ(nullptr, bts_node.block_shape()); + ASSERT_EQ(nullptr, bts_node.crops()); +} + +TEST(CircleBatchToSpaceNDTest, arity_NEG) +{ + luci::CircleBatchToSpaceND bts_node; + + ASSERT_NO_THROW(bts_node.arg(2)); + ASSERT_THROW(bts_node.arg(3), std::out_of_range); +} + +TEST(CircleBatchToSpaceNDTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleBatchToSpaceND bts_node; + + TestVisitor tv; + ASSERT_THROW(bts_node.accept(&tv), std::exception); +} + +TEST(CircleBatchToSpaceNDTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleBatchToSpaceND bts_node; + + TestVisitor tv; + ASSERT_THROW(bts_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleCast.test.cpp b/compiler/luci/lang/src/Nodes/CircleCast.test.cpp new file mode 100644 index 000000000..b58bf96f9 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleCast.test.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleCast.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleCastTest, constructor) +{ + luci::CircleCast cast_node; + + ASSERT_EQ(luci::CircleDialect::get(), cast_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::CAST, cast_node.opcode()); + + ASSERT_EQ(nullptr, cast_node.x()); + ASSERT_EQ(loco::DataType::FLOAT32, cast_node.in_data_type()); + ASSERT_EQ(loco::DataType::FLOAT32, cast_node.out_data_type()); +} + +TEST(CircleCastTest, input_NEG) +{ + luci::CircleCast cast_node; + luci::CircleCast node; + + cast_node.x(&node); + ASSERT_NE(nullptr, cast_node.x()); + + cast_node.x(nullptr); + ASSERT_EQ(nullptr, cast_node.x()); +} + +TEST(CircleCastTest, arity_NEG) +{ + luci::CircleCast cast_node; + + ASSERT_NO_THROW(cast_node.arg(0)); + ASSERT_THROW(cast_node.arg(1), std::out_of_range); +} + +TEST(CircleCastTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleCast cast_node; + + TestVisitor tv; + ASSERT_THROW(cast_node.accept(&tv), std::exception); +} + +TEST(CircleCastTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleCast cast_node; + + TestVisitor tv; + ASSERT_THROW(cast_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleCeil.test.cpp b/compiler/luci/lang/src/Nodes/CircleCeil.test.cpp new file mode 100644 index 000000000..efac614b2 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleCeil.test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleCeil.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleCeilTest, constructor) +{ + luci::CircleCeil ceil_node; + + ASSERT_EQ(luci::CircleDialect::get(), ceil_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::CEIL, ceil_node.opcode()); + + ASSERT_EQ(nullptr, ceil_node.x()); +} + +TEST(CircleCeilTest, input_NEG) +{ + luci::CircleCeil ceil_node; + luci::CircleCeil node; + + ceil_node.x(&node); + ASSERT_NE(nullptr, ceil_node.x()); + + ceil_node.x(nullptr); + ASSERT_EQ(nullptr, ceil_node.x()); +} + +TEST(CircleCeilTest, arity_NEG) +{ + luci::CircleCeil ceil_node; + + ASSERT_NO_THROW(ceil_node.arg(0)); + ASSERT_THROW(ceil_node.arg(1), std::out_of_range); +} + +TEST(CircleCeilTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleCeil ceil_node; + + TestVisitor tv; + ASSERT_THROW(ceil_node.accept(&tv), std::exception); +} + +TEST(CircleCeilTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleCeil ceil_node; + + TestVisitor tv; + ASSERT_THROW(ceil_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleConcatenation.test.cpp b/compiler/luci/lang/src/Nodes/CircleConcatenation.test.cpp index 7167682b2..9f219a386 100644 --- a/compiler/luci/lang/src/Nodes/CircleConcatenation.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleConcatenation.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleConcatenation.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,12 +25,60 @@ TEST(CircleConcatenationTest, constructor_P) { luci::CircleConcatenation concat_node(3); - ASSERT_EQ(concat_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(concat_node.opcode(), luci::CircleOpcode::CONCATENATION); + ASSERT_EQ(luci::CircleDialect::get(), concat_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::CONCATENATION, concat_node.opcode()); - ASSERT_EQ(concat_node.numValues(), 3); - ASSERT_EQ(concat_node.values(0), nullptr); - ASSERT_EQ(concat_node.values(1), nullptr); - ASSERT_EQ(concat_node.values(2), nullptr); - ASSERT_EQ(concat_node.fusedActivationFunction(), luci::FusedActFunc::UNDEFINED); + ASSERT_EQ(3, concat_node.numValues()); + ASSERT_EQ(nullptr, concat_node.values(0)); + ASSERT_EQ(nullptr, concat_node.values(1)); + ASSERT_EQ(nullptr, concat_node.values(2)); + ASSERT_EQ(luci::FusedActFunc::UNDEFINED, concat_node.fusedActivationFunction()); +} + +TEST(CircleConcatenationTest, input_NEG) +{ + luci::CircleConcatenation concat_node(2); + luci::CircleConcatenation node(2); + + concat_node.values(0, &node); + concat_node.values(1, &node); + ASSERT_NE(nullptr, concat_node.values(0)); + ASSERT_NE(nullptr, concat_node.values(1)); + + concat_node.values(0, nullptr); + concat_node.values(1, nullptr); + ASSERT_EQ(nullptr, concat_node.values(0)); + ASSERT_EQ(nullptr, concat_node.values(1)); +} + +TEST(CircleConcatenationTest, arity_NEG) +{ + luci::CircleConcatenation concat_node(5); + + ASSERT_NO_THROW(concat_node.arg(4)); + ASSERT_THROW(concat_node.arg(5), std::out_of_range); +} + +TEST(CircleConcatenationTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleConcatenation concat_node(2); + + TestVisitor tv; + ASSERT_THROW(concat_node.accept(&tv), std::exception); +} + +TEST(CircleConcatenationTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleConcatenation concat_node(2); + + TestVisitor tv; + ASSERT_THROW(concat_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleConst.cpp b/compiler/luci/lang/src/Nodes/CircleConst.cpp index 1c46884d8..17ff853eb 100644 --- a/compiler/luci/lang/src/Nodes/CircleConst.cpp +++ b/compiler/luci/lang/src/Nodes/CircleConst.cpp @@ -70,9 +70,12 @@ template <loco::DataType DT> typename loco::DataTypeImpl<DT>::Type &CircleConst: template const typename loco::DataTypeImpl<DT>::Type &CircleConst::scalar<DT>(void) const; \ template typename loco::DataTypeImpl<DT>::Type &CircleConst::scalar<DT>(void); +INSTANTIATE(loco::DataType::S64); INSTANTIATE(loco::DataType::S32); +INSTANTIATE(loco::DataType::S16); INSTANTIATE(loco::DataType::FLOAT32); INSTANTIATE(loco::DataType::U8); +INSTANTIATE(loco::DataType::BOOL); #undef INSTANTIATE diff --git a/compiler/luci/lang/src/Nodes/CircleConv2D.test.cpp b/compiler/luci/lang/src/Nodes/CircleConv2D.test.cpp index 7931c7eba..7fcc71d6e 100644 --- a/compiler/luci/lang/src/Nodes/CircleConv2D.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleConv2D.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleConv2D.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,10 +25,84 @@ TEST(CircleConv2Dest, constructor_P) { luci::CircleConv2D conv2d_node; - ASSERT_EQ(conv2d_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(conv2d_node.opcode(), luci::CircleOpcode::CONV_2D); + ASSERT_EQ(luci::CircleDialect::get(), conv2d_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::CONV_2D, conv2d_node.opcode()); - ASSERT_EQ(conv2d_node.input(), nullptr); - ASSERT_EQ(conv2d_node.filter(), nullptr); - ASSERT_EQ(conv2d_node.bias(), nullptr); + ASSERT_EQ(nullptr, conv2d_node.input()); + ASSERT_EQ(nullptr, conv2d_node.filter()); + ASSERT_EQ(nullptr, conv2d_node.bias()); + ASSERT_EQ(luci::Padding::UNDEFINED, conv2d_node.padding()); + ASSERT_EQ(1, conv2d_node.stride()->h()); + ASSERT_EQ(1, conv2d_node.stride()->w()); + ASSERT_EQ(1, conv2d_node.dilation()->h()); + ASSERT_EQ(1, conv2d_node.dilation()->w()); + ASSERT_EQ(luci::FusedActFunc::UNDEFINED, conv2d_node.fusedActivationFunction()); +} + +TEST(CircleConv2Dest, input_NEG) +{ + luci::CircleConv2D conv2d_node; + luci::CircleConv2D node; + + conv2d_node.input(&node); + conv2d_node.filter(&node); + conv2d_node.bias(&node); + ASSERT_NE(nullptr, conv2d_node.input()); + ASSERT_NE(nullptr, conv2d_node.filter()); + ASSERT_NE(nullptr, conv2d_node.bias()); + + conv2d_node.input(nullptr); + conv2d_node.filter(nullptr); + conv2d_node.bias(nullptr); + ASSERT_EQ(nullptr, conv2d_node.input()); + ASSERT_EQ(nullptr, conv2d_node.filter()); + ASSERT_EQ(nullptr, conv2d_node.bias()); + + conv2d_node.padding(luci::Padding::SAME); + ASSERT_NE(luci::Padding::UNDEFINED, conv2d_node.padding()); + + conv2d_node.stride()->h(2); + conv2d_node.stride()->w(2); + ASSERT_EQ(2, conv2d_node.stride()->h()); + ASSERT_EQ(2, conv2d_node.stride()->w()); + + conv2d_node.dilation()->h(2); + conv2d_node.dilation()->w(2); + ASSERT_EQ(2, conv2d_node.dilation()->h()); + ASSERT_EQ(2, conv2d_node.dilation()->w()); + + conv2d_node.fusedActivationFunction(luci::FusedActFunc::RELU); + ASSERT_NE(luci::FusedActFunc::UNDEFINED, conv2d_node.fusedActivationFunction()); +} + +TEST(CircleConv2Dest, arity_NEG) +{ + luci::CircleConv2D conv2d_node; + + ASSERT_NO_THROW(conv2d_node.arg(2)); + ASSERT_THROW(conv2d_node.arg(3), std::out_of_range); +} + +TEST(CircleConv2Dest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleConv2D conv2d_node; + + TestVisitor tv; + ASSERT_THROW(conv2d_node.accept(&tv), std::exception); +} + +TEST(CircleConv2Dest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleConv2D conv2d_node; + + TestVisitor tv; + ASSERT_THROW(conv2d_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleCos.test.cpp b/compiler/luci/lang/src/Nodes/CircleCos.test.cpp index 34c2cfdf0..55438d37f 100644 --- a/compiler/luci/lang/src/Nodes/CircleCos.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleCos.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleCos.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,8 +25,52 @@ TEST(CircleCosTest, constructor_P) { luci::CircleCos cos_node; - ASSERT_EQ(cos_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(cos_node.opcode(), luci::CircleOpcode::COS); + ASSERT_EQ(luci::CircleDialect::get(), cos_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::COS, cos_node.opcode()); - ASSERT_EQ(cos_node.x(), nullptr); + ASSERT_EQ(nullptr, cos_node.x()); +} + +TEST(CircleCosTest, input_NEG) +{ + luci::CircleCos cos_node; + luci::CircleCos node; + + cos_node.x(&node); + ASSERT_NE(nullptr, cos_node.x()); + + cos_node.x(nullptr); + ASSERT_EQ(nullptr, cos_node.x()); +} + +TEST(CircleCosTest, arity_NEG) +{ + luci::CircleCos cos_node; + + ASSERT_NO_THROW(cos_node.arg(0)); + ASSERT_THROW(cos_node.arg(1), std::out_of_range); +} + +TEST(CircleCosTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleCos cos_node; + + TestVisitor tv; + ASSERT_THROW(cos_node.accept(&tv), std::exception); +} + +TEST(CircleCosTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleCos cos_node; + + TestVisitor tv; + ASSERT_THROW(cos_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleCustom.test.cpp b/compiler/luci/lang/src/Nodes/CircleCustom.test.cpp new file mode 100644 index 000000000..74ea82c6c --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleCustom.test.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleCustom.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleCustomTest, constructor) +{ + luci::CircleCustom custom_node(2); + + ASSERT_EQ(luci::CircleDialect::get(), custom_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::CUSTOM, custom_node.opcode()); + + ASSERT_EQ(2, custom_node.arity()); + ASSERT_EQ(nullptr, custom_node.arg(0)); + ASSERT_EQ(nullptr, custom_node.arg(1)); + + ASSERT_EQ(2, custom_node.numInputs()); + ASSERT_EQ(0, custom_node.custom_code().size()); +} + +TEST(CircleCustomTest, constructor_NEG) { ASSERT_DEBUG_DEATH(luci::CircleCustom{0}, ""); } + +TEST(CircleCustomTest, invalidIndex_NEG) +{ + luci::CircleCustom custom_node(2); + + EXPECT_ANY_THROW(custom_node.arg(5)); +} diff --git a/compiler/luci/lang/src/Nodes/CircleCustomOut.test.cpp b/compiler/luci/lang/src/Nodes/CircleCustomOut.test.cpp new file mode 100644 index 000000000..8b63f97b1 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleCustomOut.test.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleCustomOut.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleCustomOutTest, constructor) +{ + luci::CircleCustomOut customout_node; + + ASSERT_EQ(luci::CircleDialect::get(), customout_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::CIRCLECUSTOMOUT, customout_node.opcode()); + + ASSERT_EQ(nullptr, customout_node.input()); + ASSERT_EQ(-1, customout_node.index()); +} diff --git a/compiler/luci/lang/src/Nodes/CircleDepthToSpace.test.cpp b/compiler/luci/lang/src/Nodes/CircleDepthToSpace.test.cpp new file mode 100644 index 000000000..9e3bbb7b7 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleDepthToSpace.test.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleDepthToSpace.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleDepthToSpaceTest, constructor_P) +{ + luci::CircleDepthToSpace std_node; + + ASSERT_EQ(luci::CircleDialect::get(), std_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::DEPTH_TO_SPACE, std_node.opcode()); + + ASSERT_EQ(nullptr, std_node.input()); + ASSERT_EQ(0, std_node.block_size()); +} + +TEST(CircleDepthToSpaceTest, input_NEG) +{ + luci::CircleDepthToSpace std_node; + luci::CircleDepthToSpace node; + + std_node.input(&node); + ASSERT_NE(nullptr, std_node.input()); + + std_node.input(nullptr); + ASSERT_EQ(nullptr, std_node.input()); + + std_node.block_size(2); + ASSERT_EQ(2, std_node.block_size()); +} + +TEST(CircleDepthToSpaceTest, arity_NEG) +{ + luci::CircleDepthToSpace std_node; + + ASSERT_NO_THROW(std_node.arg(0)); + ASSERT_THROW(std_node.arg(1), std::out_of_range); +} + +TEST(CircleDepthToSpaceTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleDepthToSpace std_node; + + TestVisitor tv; + ASSERT_THROW(std_node.accept(&tv), std::exception); +} + +TEST(CircleDepthToSpaceTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleDepthToSpace std_node; + + TestVisitor tv; + ASSERT_THROW(std_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleDepthwiseConv2D.test.cpp b/compiler/luci/lang/src/Nodes/CircleDepthwiseConv2D.test.cpp index bbc1ea543..5761775e5 100644 --- a/compiler/luci/lang/src/Nodes/CircleDepthwiseConv2D.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleDepthwiseConv2D.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleDepthwiseConv2D.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,15 +25,85 @@ TEST(CircleDepthwiseConv2DTest, constructor_P) { luci::CircleDepthwiseConv2D dw_conv2d_node; - ASSERT_EQ(dw_conv2d_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(dw_conv2d_node.opcode(), luci::CircleOpcode::DEPTHWISE_CONV_2D); - - ASSERT_EQ(dw_conv2d_node.input(), nullptr); - ASSERT_EQ(dw_conv2d_node.filter(), nullptr); - ASSERT_EQ(dw_conv2d_node.bias(), nullptr); - ASSERT_EQ(dw_conv2d_node.padding(), luci::Padding::UNDEFINED); - ASSERT_EQ(dw_conv2d_node.stride()->h(), 1); - ASSERT_EQ(dw_conv2d_node.stride()->w(), 1); - ASSERT_EQ(dw_conv2d_node.depthMultiplier(), 0); - ASSERT_EQ(dw_conv2d_node.fusedActivationFunction(), luci::FusedActFunc::UNDEFINED); + ASSERT_EQ(luci::CircleDialect::get(), dw_conv2d_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::DEPTHWISE_CONV_2D, dw_conv2d_node.opcode()); + + ASSERT_EQ(nullptr, dw_conv2d_node.input()); + ASSERT_EQ(nullptr, dw_conv2d_node.filter()); + ASSERT_EQ(nullptr, dw_conv2d_node.bias()); + ASSERT_EQ(luci::Padding::UNDEFINED, dw_conv2d_node.padding()); + ASSERT_EQ(1, dw_conv2d_node.stride()->h()); + ASSERT_EQ(1, dw_conv2d_node.stride()->w()); + ASSERT_EQ(1, dw_conv2d_node.dilation()->h()); + ASSERT_EQ(1, dw_conv2d_node.dilation()->w()); + ASSERT_EQ(0, dw_conv2d_node.depthMultiplier()); + ASSERT_EQ(luci::FusedActFunc::UNDEFINED, dw_conv2d_node.fusedActivationFunction()); +} + +TEST(CircleDepthwiseConv2DTest, input_NEG) +{ + luci::CircleDepthwiseConv2D dw_conv2d_node; + luci::CircleDepthwiseConv2D node; + + dw_conv2d_node.input(&node); + dw_conv2d_node.filter(&node); + dw_conv2d_node.bias(&node); + ASSERT_NE(nullptr, dw_conv2d_node.input()); + ASSERT_NE(nullptr, dw_conv2d_node.filter()); + ASSERT_NE(nullptr, dw_conv2d_node.bias()); + + dw_conv2d_node.input(nullptr); + dw_conv2d_node.filter(nullptr); + dw_conv2d_node.bias(nullptr); + ASSERT_EQ(nullptr, dw_conv2d_node.input()); + ASSERT_EQ(nullptr, dw_conv2d_node.filter()); + ASSERT_EQ(nullptr, dw_conv2d_node.bias()); + + dw_conv2d_node.padding(luci::Padding::SAME); + ASSERT_NE(luci::Padding::UNDEFINED, dw_conv2d_node.padding()); + + dw_conv2d_node.stride()->h(2); + dw_conv2d_node.stride()->w(2); + ASSERT_EQ(2, dw_conv2d_node.stride()->h()); + ASSERT_EQ(2, dw_conv2d_node.stride()->w()); + + dw_conv2d_node.dilation()->h(2); + dw_conv2d_node.dilation()->w(2); + ASSERT_EQ(2, dw_conv2d_node.dilation()->h()); + ASSERT_EQ(2, dw_conv2d_node.dilation()->w()); + + dw_conv2d_node.fusedActivationFunction(luci::FusedActFunc::RELU); + ASSERT_NE(luci::FusedActFunc::UNDEFINED, dw_conv2d_node.fusedActivationFunction()); +} + +TEST(CircleDepthwiseConv2DTest, arity_NEG) +{ + luci::CircleDepthwiseConv2D dw_conv2d_node; + + ASSERT_NO_THROW(dw_conv2d_node.arg(2)); + ASSERT_THROW(dw_conv2d_node.arg(3), std::out_of_range); +} + +TEST(CircleDepthwiseConv2DTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleDepthwiseConv2D dw_conv2d_node; + + TestVisitor tv; + ASSERT_THROW(dw_conv2d_node.accept(&tv), std::exception); +} + +TEST(CircleDepthwiseConv2DTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleDepthwiseConv2D dw_conv2d_node; + + TestVisitor tv; + ASSERT_THROW(dw_conv2d_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleDiv.test.cpp b/compiler/luci/lang/src/Nodes/CircleDiv.test.cpp index e950cc6be..d0b632ca9 100644 --- a/compiler/luci/lang/src/Nodes/CircleDiv.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleDiv.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleDiv.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,9 +25,57 @@ TEST(CircleDivTest, constructor_P) { luci::CircleDiv div_node; - ASSERT_EQ(div_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(div_node.opcode(), luci::CircleOpcode::DIV); + ASSERT_EQ(luci::CircleDialect::get(), div_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::DIV, div_node.opcode()); - ASSERT_EQ(div_node.x(), nullptr); - ASSERT_EQ(div_node.y(), nullptr); + ASSERT_EQ(nullptr, div_node.x()); + ASSERT_EQ(nullptr, div_node.y()); +} + +TEST(CircleDivTest, input_NEG) +{ + luci::CircleDiv div_node; + luci::CircleDiv node; + + div_node.x(&node); + div_node.y(&node); + ASSERT_NE(nullptr, div_node.x()); + ASSERT_NE(nullptr, div_node.y()); + + div_node.x(nullptr); + div_node.y(nullptr); + ASSERT_EQ(nullptr, div_node.x()); + ASSERT_EQ(nullptr, div_node.y()); +} + +TEST(CircleDivTest, arity_NEG) +{ + luci::CircleDiv div_node; + + ASSERT_NO_THROW(div_node.arg(1)); + ASSERT_THROW(div_node.arg(2), std::out_of_range); +} + +TEST(CircleDivTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleDiv div_node; + + TestVisitor tv; + ASSERT_THROW(div_node.accept(&tv), std::exception); +} + +TEST(CircleDivTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleDiv div_node; + + TestVisitor tv; + ASSERT_THROW(div_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleElu.test.cpp b/compiler/luci/lang/src/Nodes/CircleElu.test.cpp new file mode 100644 index 000000000..2a044d75b --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleElu.test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleElu.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleEluTest, constructor_P) +{ + luci::CircleElu elu_node; + + ASSERT_EQ(luci::CircleDialect::get(), elu_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::ELU, elu_node.opcode()); + + ASSERT_EQ(nullptr, elu_node.features()); +} + +TEST(CircleEluTest, input_NEG) +{ + luci::CircleElu elu_node; + luci::CircleElu node; + + elu_node.features(&node); + ASSERT_NE(nullptr, elu_node.features()); + + elu_node.features(nullptr); + ASSERT_EQ(nullptr, elu_node.features()); +} + +TEST(CircleEluTest, arity_NEG) +{ + luci::CircleElu elu_node; + + ASSERT_NO_THROW(elu_node.arg(0)); + ASSERT_THROW(elu_node.arg(1), std::out_of_range); +} + +TEST(CircleEluTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleElu elu_node; + + TestVisitor tv; + ASSERT_THROW(elu_node.accept(&tv), std::exception); +} + +TEST(CircleEluTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleElu elu_node; + + TestVisitor tv; + ASSERT_THROW(elu_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleEqual.test.cpp b/compiler/luci/lang/src/Nodes/CircleEqual.test.cpp index e2757f094..2ae15290d 100644 --- a/compiler/luci/lang/src/Nodes/CircleEqual.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleEqual.test.cpp @@ -17,16 +17,65 @@ #include "luci/IR/Nodes/CircleEqual.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> TEST(CircleEqualTest, constructor_P) { - luci::CircleEqual or_node; + luci::CircleEqual equ_node; - ASSERT_EQ(or_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(or_node.opcode(), luci::CircleOpcode::EQUAL); + ASSERT_EQ(luci::CircleDialect::get(), equ_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::EQUAL, equ_node.opcode()); - ASSERT_EQ(or_node.x(), nullptr); - ASSERT_EQ(or_node.y(), nullptr); + ASSERT_EQ(nullptr, equ_node.x()); + ASSERT_EQ(nullptr, equ_node.y()); +} + +TEST(CircleEqualTest, input_NEG) +{ + luci::CircleEqual equ_node; + luci::CircleEqual node; + + equ_node.x(&node); + equ_node.y(&node); + ASSERT_NE(nullptr, equ_node.x()); + ASSERT_NE(nullptr, equ_node.y()); + + equ_node.x(nullptr); + equ_node.y(nullptr); + ASSERT_EQ(nullptr, equ_node.x()); + ASSERT_EQ(nullptr, equ_node.y()); +} + +TEST(CircleEqualTest, arity_NEG) +{ + luci::CircleEqual equ_node; + + ASSERT_NO_THROW(equ_node.arg(1)); + ASSERT_THROW(equ_node.arg(2), std::out_of_range); +} + +TEST(CircleEqualTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleEqual equ_node; + + TestVisitor tv; + ASSERT_THROW(equ_node.accept(&tv), std::exception); +} + +TEST(CircleEqualTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleEqual equ_node; + + TestVisitor tv; + ASSERT_THROW(equ_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleExp.test.cpp b/compiler/luci/lang/src/Nodes/CircleExp.test.cpp index db10d0b03..5ca90e90f 100644 --- a/compiler/luci/lang/src/Nodes/CircleExp.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleExp.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleExp.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,8 +25,52 @@ TEST(CircleExpTest, constructor) { luci::CircleExp exp_node; - ASSERT_EQ(exp_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(exp_node.opcode(), luci::CircleOpcode::EXP); + ASSERT_EQ(luci::CircleDialect::get(), exp_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::EXP, exp_node.opcode()); - ASSERT_EQ(exp_node.x(), nullptr); + ASSERT_EQ(nullptr, exp_node.x()); +} + +TEST(CircleExpTest, input_NEG) +{ + luci::CircleExp exp_node; + luci::CircleExp node; + + exp_node.x(&node); + ASSERT_NE(nullptr, exp_node.x()); + + exp_node.x(nullptr); + ASSERT_EQ(nullptr, exp_node.x()); +} + +TEST(CircleExpTest, arity_NEG) +{ + luci::CircleExp exp_node; + + ASSERT_NO_THROW(exp_node.arg(0)); + ASSERT_THROW(exp_node.arg(1), std::out_of_range); +} + +TEST(CircleExpTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleExp exp_node; + + TestVisitor tv; + ASSERT_THROW(exp_node.accept(&tv), std::exception); +} + +TEST(CircleExpTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleExp exp_node; + + TestVisitor tv; + ASSERT_THROW(exp_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleExpandDims.test.cpp b/compiler/luci/lang/src/Nodes/CircleExpandDims.test.cpp new file mode 100644 index 000000000..754ef01f9 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleExpandDims.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleExpandDims.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleExpandDimsTest, constructor_P) +{ + luci::CircleExpandDims expand_dims; + + ASSERT_EQ(luci::CircleDialect::get(), expand_dims.dialect()); + ASSERT_EQ(luci::CircleOpcode::EXPAND_DIMS, expand_dims.opcode()); + + ASSERT_EQ(nullptr, expand_dims.input()); + ASSERT_EQ(nullptr, expand_dims.axis()); +} + +TEST(CircleExpandDimsTest, input_NEG) +{ + luci::CircleExpandDims expand_dims; + luci::CircleExpandDims node; + + expand_dims.input(&node); + expand_dims.axis(&node); + ASSERT_NE(nullptr, expand_dims.input()); + ASSERT_NE(nullptr, expand_dims.axis()); + + expand_dims.input(nullptr); + expand_dims.axis(nullptr); + ASSERT_EQ(nullptr, expand_dims.input()); + ASSERT_EQ(nullptr, expand_dims.axis()); +} + +TEST(CircleExpandDimsTest, arity_NEG) +{ + luci::CircleExpandDims expand_dims; + + ASSERT_NO_THROW(expand_dims.arg(1)); + ASSERT_THROW(expand_dims.arg(2), std::out_of_range); +} + +TEST(CircleExpandDimsTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleExpandDims expand_dims; + + TestVisitor tv; + ASSERT_THROW(expand_dims.accept(&tv), std::exception); +} + +TEST(CircleExpandDimsTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleExpandDims expand_dims; + + TestVisitor tv; + ASSERT_THROW(expand_dims.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleFill.test.cpp b/compiler/luci/lang/src/Nodes/CircleFill.test.cpp new file mode 100644 index 000000000..4555da1cb --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleFill.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleFill.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleFillTest, constructor_P) +{ + luci::CircleFill fill; + + ASSERT_EQ(fill.dialect(), luci::CircleDialect::get()); + ASSERT_EQ(fill.opcode(), luci::CircleOpcode::FILL); + + ASSERT_EQ(nullptr, fill.dims()); + ASSERT_EQ(nullptr, fill.value()); +} + +TEST(CircleFillTest, input_NEG) +{ + luci::CircleFill fill_node; + luci::CircleFill node; + + fill_node.dims(&node); + fill_node.value(&node); + ASSERT_NE(nullptr, fill_node.dims()); + ASSERT_NE(nullptr, fill_node.value()); + + fill_node.dims(nullptr); + fill_node.value(nullptr); + ASSERT_EQ(nullptr, fill_node.dims()); + ASSERT_EQ(nullptr, fill_node.value()); +} + +TEST(CircleFillTest, arity_NEG) +{ + luci::CircleFill fill_node; + + ASSERT_NO_THROW(fill_node.arg(1)); + ASSERT_THROW(fill_node.arg(2), std::out_of_range); +} + +TEST(CircleFillTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleFill fill_node; + + TestVisitor tv; + ASSERT_THROW(fill_node.accept(&tv), std::exception); +} + +TEST(CircleFillTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleFill fill_node; + + TestVisitor tv; + ASSERT_THROW(fill_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleFloor.test.cpp b/compiler/luci/lang/src/Nodes/CircleFloor.test.cpp new file mode 100644 index 000000000..38d38a0da --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleFloor.test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleFloor.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleFloorTest, constructor) +{ + luci::CircleFloor floor_node; + + ASSERT_EQ(luci::CircleDialect::get(), floor_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::FLOOR, floor_node.opcode()); + + ASSERT_EQ(nullptr, floor_node.x()); +} + +TEST(CircleFloorTest, input_NEG) +{ + luci::CircleFloor floor_node; + luci::CircleFloor node; + + floor_node.x(&node); + ASSERT_NE(nullptr, floor_node.x()); + + floor_node.x(nullptr); + ASSERT_EQ(nullptr, floor_node.x()); +} + +TEST(CircleFloorTest, arity_NEG) +{ + luci::CircleFloor floor_node; + + ASSERT_NO_THROW(floor_node.arg(0)); + ASSERT_THROW(floor_node.arg(1), std::out_of_range); +} + +TEST(CircleFloorTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleFloor floor_node; + + TestVisitor tv; + ASSERT_THROW(floor_node.accept(&tv), std::exception); +} + +TEST(CircleFloorTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleFloor floor_node; + + TestVisitor tv; + ASSERT_THROW(floor_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleFloorDiv.test.cpp b/compiler/luci/lang/src/Nodes/CircleFloorDiv.test.cpp new file mode 100644 index 000000000..6c52eee73 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleFloorDiv.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleFloorDiv.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleFloorDivTest, constructor_P) +{ + luci::CircleFloorDiv floordiv_node; + + ASSERT_EQ(luci::CircleDialect::get(), floordiv_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::FLOOR_DIV, floordiv_node.opcode()); + + ASSERT_EQ(nullptr, floordiv_node.x()); + ASSERT_EQ(nullptr, floordiv_node.y()); +} + +TEST(CircleFloorDivTest, input_NEG) +{ + luci::CircleFloorDiv floordiv_node; + luci::CircleFloorDiv node; + + floordiv_node.x(&node); + floordiv_node.y(&node); + ASSERT_NE(nullptr, floordiv_node.x()); + ASSERT_NE(nullptr, floordiv_node.y()); + + floordiv_node.x(nullptr); + floordiv_node.y(nullptr); + ASSERT_EQ(nullptr, floordiv_node.x()); + ASSERT_EQ(nullptr, floordiv_node.y()); +} + +TEST(CircleFloorDivTest, arity_NEG) +{ + luci::CircleFloorDiv floordiv_node; + + ASSERT_NO_THROW(floordiv_node.arg(1)); + ASSERT_THROW(floordiv_node.arg(2), std::out_of_range); +} + +TEST(CircleFloorDivTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleFloorDiv floordiv_node; + + TestVisitor tv; + ASSERT_THROW(floordiv_node.accept(&tv), std::exception); +} + +TEST(CircleFloorDivTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleFloorDiv floordiv_node; + + TestVisitor tv; + ASSERT_THROW(floordiv_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleFloorMod.test.cpp b/compiler/luci/lang/src/Nodes/CircleFloorMod.test.cpp new file mode 100644 index 000000000..c3fa187f2 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleFloorMod.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleFloorMod.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleFloorModTest, constructor) +{ + luci::CircleFloorMod floormod_node; + + ASSERT_EQ(luci::CircleDialect::get(), floormod_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::FLOOR_MOD, floormod_node.opcode()); + + ASSERT_EQ(nullptr, floormod_node.x()); + ASSERT_EQ(nullptr, floormod_node.y()); +} + +TEST(CircleFloorModTest, input_NEG) +{ + luci::CircleFloorMod floormod_node; + luci::CircleFloorMod node; + + floormod_node.x(&node); + floormod_node.y(&node); + ASSERT_NE(nullptr, floormod_node.x()); + ASSERT_NE(nullptr, floormod_node.y()); + + floormod_node.x(nullptr); + floormod_node.y(nullptr); + ASSERT_EQ(nullptr, floormod_node.x()); + ASSERT_EQ(nullptr, floormod_node.y()); +} + +TEST(CircleFloorModTest, arity_NEG) +{ + luci::CircleFloorMod floormod_node; + + ASSERT_NO_THROW(floormod_node.arg(1)); + ASSERT_THROW(floormod_node.arg(2), std::out_of_range); +} + +TEST(CircleFloorModTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleFloorMod floormod_node; + + TestVisitor tv; + ASSERT_THROW(floormod_node.accept(&tv), std::exception); +} + +TEST(CircleFloorModTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleFloorMod floormod_node; + + TestVisitor tv; + ASSERT_THROW(floormod_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleFullyConnected.test.cpp b/compiler/luci/lang/src/Nodes/CircleFullyConnected.test.cpp index 994dcd239..bb0e3c51b 100644 --- a/compiler/luci/lang/src/Nodes/CircleFullyConnected.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleFullyConnected.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleFullyConnected.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,11 +25,66 @@ TEST(CircleFullyConnectedTest, constructor) { luci::CircleFullyConnected fc_node; - ASSERT_EQ(fc_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(fc_node.opcode(), luci::CircleOpcode::FULLY_CONNECTED); + ASSERT_EQ(luci::CircleDialect::get(), fc_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::FULLY_CONNECTED, fc_node.opcode()); - ASSERT_EQ(fc_node.input(), nullptr); - ASSERT_EQ(fc_node.weights(), nullptr); - ASSERT_EQ(fc_node.bias(), nullptr); - ASSERT_EQ(fc_node.fusedActivationFunction(), luci::FusedActFunc::UNDEFINED); + ASSERT_EQ(nullptr, fc_node.input()); + ASSERT_EQ(nullptr, fc_node.weights()); + ASSERT_EQ(nullptr, fc_node.bias()); + ASSERT_EQ(luci::FusedActFunc::UNDEFINED, fc_node.fusedActivationFunction()); +} + +TEST(CircleFullyConnectedTest, input_NEG) +{ + luci::CircleFullyConnected fc_node; + luci::CircleFullyConnected node; + + fc_node.input(&node); + fc_node.weights(&node); + fc_node.bias(&node); + ASSERT_NE(nullptr, fc_node.input()); + ASSERT_NE(nullptr, fc_node.weights()); + ASSERT_NE(nullptr, fc_node.bias()); + + fc_node.input(nullptr); + fc_node.weights(nullptr); + fc_node.bias(nullptr); + ASSERT_EQ(nullptr, fc_node.input()); + ASSERT_EQ(nullptr, fc_node.weights()); + ASSERT_EQ(nullptr, fc_node.bias()); + + fc_node.fusedActivationFunction(luci::FusedActFunc::RELU); + ASSERT_NE(luci::FusedActFunc::UNDEFINED, fc_node.fusedActivationFunction()); +} + +TEST(CircleFullyConnectedTest, arity_NEG) +{ + luci::CircleFullyConnected fc_node; + + ASSERT_NO_THROW(fc_node.arg(2)); + ASSERT_THROW(fc_node.arg(3), std::out_of_range); +} + +TEST(CircleFullyConnectedTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleFullyConnected fc_node; + + TestVisitor tv; + ASSERT_THROW(fc_node.accept(&tv), std::exception); +} + +TEST(CircleFullyConnectedTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleFullyConnected fc_node; + + TestVisitor tv; + ASSERT_THROW(fc_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleGather.test.cpp b/compiler/luci/lang/src/Nodes/CircleGather.test.cpp index 4eace9a02..5194d6bdd 100644 --- a/compiler/luci/lang/src/Nodes/CircleGather.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleGather.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleGather.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,10 +25,61 @@ TEST(CircleGatherTest, constructor) { luci::CircleGather gather_node; - ASSERT_EQ(gather_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(gather_node.opcode(), luci::CircleOpcode::GATHER); + ASSERT_EQ(luci::CircleDialect::get(), gather_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::GATHER, gather_node.opcode()); - ASSERT_EQ(gather_node.input(), nullptr); - ASSERT_EQ(gather_node.positions(), nullptr); - ASSERT_EQ(gather_node.axis(), 0); + ASSERT_EQ(nullptr, gather_node.params()); + ASSERT_EQ(nullptr, gather_node.indices()); + ASSERT_EQ(0, gather_node.axis()); +} + +TEST(CircleGatherTest, input_NEG) +{ + luci::CircleGather gather_node; + luci::CircleGather node; + + gather_node.params(&node); + gather_node.indices(&node); + ASSERT_NE(nullptr, gather_node.params()); + ASSERT_NE(nullptr, gather_node.indices()); + + gather_node.params(nullptr); + gather_node.indices(nullptr); + ASSERT_EQ(nullptr, gather_node.params()); + ASSERT_EQ(nullptr, gather_node.indices()); + + gather_node.axis(1); + ASSERT_NE(0, gather_node.axis()); +} + +TEST(CircleGatherTest, arity_NEG) +{ + luci::CircleGather gather_node; + + ASSERT_NO_THROW(gather_node.arg(1)); + ASSERT_THROW(gather_node.arg(2), std::out_of_range); +} + +TEST(CircleGatherTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleGather gather_node; + + TestVisitor tv; + ASSERT_THROW(gather_node.accept(&tv), std::exception); +} + +TEST(CircleGatherTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleGather gather_node; + + TestVisitor tv; + ASSERT_THROW(gather_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleGatherNd.test.cpp b/compiler/luci/lang/src/Nodes/CircleGatherNd.test.cpp new file mode 100644 index 000000000..1402e6e45 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleGatherNd.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleGatherNd.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleGatherNdTest, constructor) +{ + luci::CircleGatherNd gather_nd_node; + + ASSERT_EQ(luci::CircleDialect::get(), gather_nd_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::GATHER_ND, gather_nd_node.opcode()); + + ASSERT_EQ(nullptr, gather_nd_node.params()); + ASSERT_EQ(nullptr, gather_nd_node.indices()); +} + +TEST(CircleGatherNdTest, input_NEG) +{ + luci::CircleGatherNd gather_nd_node; + luci::CircleGatherNd node; + + gather_nd_node.params(&node); + gather_nd_node.indices(&node); + ASSERT_NE(nullptr, gather_nd_node.params()); + ASSERT_NE(nullptr, gather_nd_node.indices()); + + gather_nd_node.params(nullptr); + gather_nd_node.indices(nullptr); + ASSERT_EQ(nullptr, gather_nd_node.params()); + ASSERT_EQ(nullptr, gather_nd_node.indices()); +} + +TEST(CircleGatherNdTest, arity_NEG) +{ + luci::CircleGatherNd gather_nd_node; + + ASSERT_NO_THROW(gather_nd_node.arg(1)); + ASSERT_THROW(gather_nd_node.arg(2), std::out_of_range); +} + +TEST(CircleGatherNdTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleGatherNd gather_nd_node; + + TestVisitor tv; + ASSERT_THROW(gather_nd_node.accept(&tv), std::exception); +} + +TEST(CircleGatherNdTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleGatherNd gather_nd_node; + + TestVisitor tv; + ASSERT_THROW(gather_nd_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleGreater.test.cpp b/compiler/luci/lang/src/Nodes/CircleGreater.test.cpp new file mode 100644 index 000000000..9a2b5f9f9 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleGreater.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleGreater.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleGreaterTest, constructor_P) +{ + luci::CircleGreater greater_node; + + ASSERT_EQ(luci::CircleDialect::get(), greater_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::GREATER, greater_node.opcode()); + + ASSERT_EQ(nullptr, greater_node.x()); + ASSERT_EQ(nullptr, greater_node.y()); +} + +TEST(CircleGreaterTest, input_NEG) +{ + luci::CircleGreater greater_node; + luci::CircleGreater node; + + greater_node.x(&node); + greater_node.y(&node); + ASSERT_NE(nullptr, greater_node.x()); + ASSERT_NE(nullptr, greater_node.y()); + + greater_node.x(nullptr); + greater_node.y(nullptr); + ASSERT_EQ(nullptr, greater_node.x()); + ASSERT_EQ(nullptr, greater_node.y()); +} + +TEST(CircleGreaterTest, arity_NEG) +{ + luci::CircleGreater greater_node; + + ASSERT_NO_THROW(greater_node.arg(1)); + ASSERT_THROW(greater_node.arg(2), std::out_of_range); +} + +TEST(CircleGreaterTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleGreater greater_node; + + TestVisitor tv; + ASSERT_THROW(greater_node.accept(&tv), std::exception); +} + +TEST(CircleGreaterTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleGreater greater_node; + + TestVisitor tv; + ASSERT_THROW(greater_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleGreaterEqual.test.cpp b/compiler/luci/lang/src/Nodes/CircleGreaterEqual.test.cpp new file mode 100644 index 000000000..51c22b707 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleGreaterEqual.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleGreaterEqual.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleGreaterEqualTest, constructor_P) +{ + luci::CircleGreaterEqual greater_equal_node; + + ASSERT_EQ(luci::CircleDialect::get(), greater_equal_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::GREATER_EQUAL, greater_equal_node.opcode()); + + ASSERT_EQ(nullptr, greater_equal_node.x()); + ASSERT_EQ(nullptr, greater_equal_node.y()); +} + +TEST(CircleGreaterEqualTest, input_NEG) +{ + luci::CircleGreaterEqual greater_equal_node; + luci::CircleGreaterEqual node; + + greater_equal_node.x(&node); + greater_equal_node.y(&node); + ASSERT_NE(nullptr, greater_equal_node.x()); + ASSERT_NE(nullptr, greater_equal_node.y()); + + greater_equal_node.x(nullptr); + greater_equal_node.y(nullptr); + ASSERT_EQ(nullptr, greater_equal_node.x()); + ASSERT_EQ(nullptr, greater_equal_node.y()); +} + +TEST(CircleGreaterEqualTest, arity_NEG) +{ + luci::CircleGreaterEqual greater_equal_node; + + ASSERT_NO_THROW(greater_equal_node.arg(1)); + ASSERT_THROW(greater_equal_node.arg(2), std::out_of_range); +} + +TEST(CircleGreaterEqualTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleGreaterEqual greater_equal_node; + + TestVisitor tv; + ASSERT_THROW(greater_equal_node.accept(&tv), std::exception); +} + +TEST(CircleGreaterEqualTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleGreaterEqual greater_equal_node; + + TestVisitor tv; + ASSERT_THROW(greater_equal_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleIf.test.cpp b/compiler/luci/lang/src/Nodes/CircleIf.test.cpp new file mode 100644 index 000000000..e3c8c9f60 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleIf.test.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleIf.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleIfTest, constructor) +{ + luci::CircleIf if_node(2, 2); + + ASSERT_EQ(luci::CircleDialect::get(), if_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::IF, if_node.opcode()); + + ASSERT_EQ(2, if_node.input_count()); + ASSERT_EQ(2, if_node.output_count()); + + ASSERT_EQ(nullptr, if_node.input(0)); + ASSERT_EQ(nullptr, if_node.input(1)); + + ASSERT_EQ(-1, if_node.then_branch()); + ASSERT_EQ(-1, if_node.else_branch()); +} + +TEST(CircleIfTestDeath, invalid_arity_NEG) +{ + ASSERT_DEBUG_DEATH(luci::CircleIf very_long_name_if_node(0, 1), ""); +} + +TEST(CircleIfTestDeath, invalid_output_count_NEG) +{ + ASSERT_DEBUG_DEATH(luci::CircleIf if_node(2, 0), ""); +} + +TEST(CircleIfTestDeath, invalid_input_get_index_NEG) +{ + luci::CircleIf if_node(2, 2); + + EXPECT_ANY_THROW(if_node.input(100)); +} + +TEST(CircleIfTestDeath, invalid_input_set_index_NEG) +{ + luci::CircleIf if_node(2, 2); + + EXPECT_ANY_THROW(if_node.input(100, nullptr)); +} + +TEST(CircleIfTestDeath, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleIf if_node(2, 2); + + TestVisitor tv; + ASSERT_THROW(if_node.accept(&tv), std::exception); +} + +TEST(CircleIfTestDeath, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleIf if_node(2, 2); + + TestVisitor tv; + ASSERT_THROW(if_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleIfOut.test.cpp b/compiler/luci/lang/src/Nodes/CircleIfOut.test.cpp new file mode 100644 index 000000000..5154b6b28 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleIfOut.test.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleIfOut.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleIfOutTest, constructor) +{ + luci::CircleIfOut ifout_node; + + ASSERT_EQ(luci::CircleDialect::get(), ifout_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::CIRCLEIFOUT, ifout_node.opcode()); + + ASSERT_EQ(nullptr, ifout_node.input()); + ASSERT_EQ(-1, ifout_node.index()); +} diff --git a/compiler/luci/lang/src/Nodes/CircleInstanceNorm.test.cpp b/compiler/luci/lang/src/Nodes/CircleInstanceNorm.test.cpp index b87e81791..88a5b8c6c 100644 --- a/compiler/luci/lang/src/Nodes/CircleInstanceNorm.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleInstanceNorm.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleInstanceNorm.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,12 +25,67 @@ TEST(CircleInstanceNormTest, constructor) { luci::CircleInstanceNorm instance_norm; - ASSERT_EQ(instance_norm.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(instance_norm.opcode(), luci::CircleOpcode::INSTANCE_NORM); + ASSERT_EQ(luci::CircleDialect::get(), instance_norm.dialect()); + ASSERT_EQ(luci::CircleOpcode::INSTANCE_NORM, instance_norm.opcode()); - ASSERT_EQ(instance_norm.input(), nullptr); - ASSERT_EQ(instance_norm.gamma(), nullptr); - ASSERT_EQ(instance_norm.beta(), nullptr); + ASSERT_EQ(nullptr, instance_norm.input()); + ASSERT_EQ(nullptr, instance_norm.gamma()); + ASSERT_EQ(nullptr, instance_norm.beta()); ASSERT_FLOAT_EQ(instance_norm.epsilon(), 1e-05); - ASSERT_EQ(instance_norm.fusedActivationFunction(), luci::FusedActFunc::UNDEFINED); + ASSERT_EQ(luci::FusedActFunc::UNDEFINED, instance_norm.fusedActivationFunction()); +} + +TEST(CircleInstanceNormTest, input_NEG) +{ + luci::CircleInstanceNorm instance_norm; + luci::CircleInstanceNorm node; + + instance_norm.input(&node); + instance_norm.gamma(&node); + instance_norm.beta(&node); + ASSERT_NE(nullptr, instance_norm.input()); + ASSERT_NE(nullptr, instance_norm.gamma()); + ASSERT_NE(nullptr, instance_norm.beta()); + + instance_norm.input(nullptr); + instance_norm.gamma(nullptr); + instance_norm.beta(nullptr); + ASSERT_EQ(nullptr, instance_norm.input()); + ASSERT_EQ(nullptr, instance_norm.gamma()); + ASSERT_EQ(nullptr, instance_norm.beta()); + + instance_norm.fusedActivationFunction(luci::FusedActFunc::RELU); + ASSERT_NE(luci::FusedActFunc::UNDEFINED, instance_norm.fusedActivationFunction()); +} + +TEST(CircleInstanceNormTest, arity_NEG) +{ + luci::CircleInstanceNorm instance_norm; + + ASSERT_NO_THROW(instance_norm.arg(2)); + ASSERT_THROW(instance_norm.arg(3), std::out_of_range); +} + +TEST(CircleInstanceNormTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleInstanceNorm instance_norm; + + TestVisitor tv; + ASSERT_THROW(instance_norm.accept(&tv), std::exception); +} + +TEST(CircleInstanceNormTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleInstanceNorm instance_norm; + + TestVisitor tv; + ASSERT_THROW(instance_norm.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleL2Pool2D.test.cpp b/compiler/luci/lang/src/Nodes/CircleL2Pool2D.test.cpp new file mode 100644 index 000000000..cb779efa5 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleL2Pool2D.test.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleL2Pool2D.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleL2Pool2DTest, constructor) +{ + luci::CircleL2Pool2D l2pool2d_node; + + ASSERT_EQ(luci::CircleDialect::get(), l2pool2d_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::L2_POOL_2D, l2pool2d_node.opcode()); + + ASSERT_EQ(nullptr, l2pool2d_node.value()); + ASSERT_EQ(1, l2pool2d_node.filter()->h()); + ASSERT_EQ(1, l2pool2d_node.filter()->w()); + ASSERT_EQ(1, l2pool2d_node.stride()->h()); + ASSERT_EQ(1, l2pool2d_node.stride()->w()); + ASSERT_EQ(luci::FusedActFunc::UNDEFINED, l2pool2d_node.fusedActivationFunction()); +} + +TEST(CircleL2Pool2DTest, input_NEG) +{ + luci::CircleL2Pool2D l2pool2d_node; + luci::CircleL2Pool2D node; + + l2pool2d_node.value(&node); + ASSERT_NE(nullptr, l2pool2d_node.value()); + + l2pool2d_node.value(nullptr); + ASSERT_EQ(nullptr, l2pool2d_node.value()); + + l2pool2d_node.stride()->h(2); + l2pool2d_node.stride()->w(2); + ASSERT_EQ(2, l2pool2d_node.stride()->h()); + ASSERT_EQ(2, l2pool2d_node.stride()->w()); + + l2pool2d_node.filter()->h(2); + l2pool2d_node.filter()->w(2); + ASSERT_EQ(2, l2pool2d_node.filter()->h()); + ASSERT_EQ(2, l2pool2d_node.filter()->w()); + + l2pool2d_node.fusedActivationFunction(luci::FusedActFunc::RELU); + ASSERT_NE(luci::FusedActFunc::UNDEFINED, l2pool2d_node.fusedActivationFunction()); +} + +TEST(CircleL2Pool2DTest, arity_NEG) +{ + luci::CircleL2Pool2D l2pool2d_node; + + ASSERT_NO_THROW(l2pool2d_node.arg(0)); + ASSERT_THROW(l2pool2d_node.arg(1), std::out_of_range); +} + +TEST(CircleL2Pool2DTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleL2Pool2D l2pool2d_node; + + TestVisitor tv; + ASSERT_THROW(l2pool2d_node.accept(&tv), std::exception); +} + +TEST(CircleL2Pool2DTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleL2Pool2D l2pool2d_node; + + TestVisitor tv; + ASSERT_THROW(l2pool2d_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleLeakyRelu.test.cpp b/compiler/luci/lang/src/Nodes/CircleLeakyRelu.test.cpp new file mode 100644 index 000000000..bacb444da --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleLeakyRelu.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleLeakyRelu.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleLeakyReluTest, constructor) +{ + luci::CircleLeakyRelu relu_node; + + ASSERT_EQ(luci::CircleDialect::get(), relu_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::LEAKY_RELU, relu_node.opcode()); + + ASSERT_EQ(nullptr, relu_node.features()); + + ASSERT_EQ(0.2f, relu_node.alpha()); +} + +TEST(CircleLeakyReluTest, input_NEG) +{ + luci::CircleLeakyRelu relu_node; + luci::CircleLeakyRelu node; + + relu_node.features(&node); + ASSERT_NE(nullptr, relu_node.features()); + + relu_node.features(nullptr); + ASSERT_EQ(nullptr, relu_node.features()); + + relu_node.alpha(1.2f); + ASSERT_NE(0.2f, relu_node.alpha()); +} + +TEST(CircleLeakyReluTest, arity_NEG) +{ + luci::CircleLeakyRelu relu_node; + + ASSERT_NO_THROW(relu_node.arg(0)); + ASSERT_THROW(relu_node.arg(1), std::out_of_range); +} + +TEST(CircleLeakyReluTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleLeakyRelu relu_node; + + TestVisitor tv; + ASSERT_THROW(relu_node.accept(&tv), std::exception); +} + +TEST(CircleLeakyReluTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleLeakyRelu relu_node; + + TestVisitor tv; + ASSERT_THROW(relu_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleLess.test.cpp b/compiler/luci/lang/src/Nodes/CircleLess.test.cpp new file mode 100644 index 000000000..ec454dfb5 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleLess.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleLess.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleLessTest, constructor_P) +{ + luci::CircleLess less_node; + + ASSERT_EQ(luci::CircleDialect::get(), less_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::LESS, less_node.opcode()); + + ASSERT_EQ(nullptr, less_node.x()); + ASSERT_EQ(nullptr, less_node.y()); +} + +TEST(CircleLessTest, input_NEG) +{ + luci::CircleLess less_node; + luci::CircleLess node; + + less_node.x(&node); + less_node.y(&node); + ASSERT_NE(nullptr, less_node.x()); + ASSERT_NE(nullptr, less_node.y()); + + less_node.x(nullptr); + less_node.y(nullptr); + ASSERT_EQ(nullptr, less_node.x()); + ASSERT_EQ(nullptr, less_node.y()); +} + +TEST(CircleLessTest, arity_NEG) +{ + luci::CircleLess less_node; + + ASSERT_NO_THROW(less_node.arg(1)); + ASSERT_THROW(less_node.arg(2), std::out_of_range); +} + +TEST(CircleLessTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleLess less_node; + + TestVisitor tv; + ASSERT_THROW(less_node.accept(&tv), std::exception); +} + +TEST(CircleLessTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleLess less_node; + + TestVisitor tv; + ASSERT_THROW(less_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleLessEqual.test.cpp b/compiler/luci/lang/src/Nodes/CircleLessEqual.test.cpp new file mode 100644 index 000000000..baa9202ae --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleLessEqual.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleLessEqual.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleLessEqualTest, constructor_P) +{ + luci::CircleLessEqual less_equal_node; + + ASSERT_EQ(luci::CircleDialect::get(), less_equal_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::LESS_EQUAL, less_equal_node.opcode()); + + ASSERT_EQ(nullptr, less_equal_node.x()); + ASSERT_EQ(nullptr, less_equal_node.y()); +} + +TEST(CircleLessEqualTest, input_NEG) +{ + luci::CircleLessEqual less_equal_node; + luci::CircleLessEqual node; + + less_equal_node.x(&node); + less_equal_node.y(&node); + ASSERT_NE(nullptr, less_equal_node.x()); + ASSERT_NE(nullptr, less_equal_node.y()); + + less_equal_node.x(nullptr); + less_equal_node.y(nullptr); + ASSERT_EQ(nullptr, less_equal_node.x()); + ASSERT_EQ(nullptr, less_equal_node.y()); +} + +TEST(CircleLessEqualTest, arity_NEG) +{ + luci::CircleLessEqual less_equal_node; + + ASSERT_NO_THROW(less_equal_node.arg(1)); + ASSERT_THROW(less_equal_node.arg(2), std::out_of_range); +} + +TEST(CircleLessEqualTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleLessEqual less_equal_node; + + TestVisitor tv; + ASSERT_THROW(less_equal_node.accept(&tv), std::exception); +} + +TEST(CircleLessEqualTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleLessEqual less_equal_node; + + TestVisitor tv; + ASSERT_THROW(less_equal_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleLocalResponseNormalization.test.cpp b/compiler/luci/lang/src/Nodes/CircleLocalResponseNormalization.test.cpp new file mode 100644 index 000000000..1b1bf67bd --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleLocalResponseNormalization.test.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleLocalResponseNormalization.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleLocalResponseNormalizationTest, constructor_P) +{ + luci::CircleLocalResponseNormalization local_response_normalization_node; + + ASSERT_EQ(luci::CircleDialect::get(), local_response_normalization_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::LOCAL_RESPONSE_NORMALIZATION, + local_response_normalization_node.opcode()); + + ASSERT_EQ(nullptr, local_response_normalization_node.input()); + ASSERT_EQ(5, local_response_normalization_node.radius()); + ASSERT_EQ(1.0f, local_response_normalization_node.bias()); + ASSERT_EQ(1.0f, local_response_normalization_node.alpha()); + ASSERT_EQ(0.5f, local_response_normalization_node.beta()); +} + +TEST(CircleLocalResponseNormalizationTest, input_NEG) +{ + luci::CircleLocalResponseNormalization local_response_normalization_node; + luci::CircleLocalResponseNormalization node; + + local_response_normalization_node.input(&node); + ASSERT_NE(nullptr, local_response_normalization_node.input()); + + local_response_normalization_node.input(nullptr); + ASSERT_EQ(nullptr, local_response_normalization_node.input()); + + local_response_normalization_node.radius(100); + local_response_normalization_node.bias(100.0f); + local_response_normalization_node.alpha(100.0f); + local_response_normalization_node.beta(100.0f); + ASSERT_NE(5, local_response_normalization_node.radius()); + ASSERT_NE(1.0f, local_response_normalization_node.bias()); + ASSERT_NE(1.0f, local_response_normalization_node.alpha()); + ASSERT_NE(0.5f, local_response_normalization_node.beta()); +} + +TEST(CircleLocalResponseNormalizationTest, arity_NEG) +{ + luci::CircleLocalResponseNormalization local_response_normalization_node; + + ASSERT_NO_THROW(local_response_normalization_node.arg(0)); + ASSERT_THROW(local_response_normalization_node.arg(1), std::out_of_range); +} + +TEST(CircleLocalResponseNormalizationTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleLocalResponseNormalization local_response_normalization_node; + + TestVisitor tv; + ASSERT_THROW(local_response_normalization_node.accept(&tv), std::exception); +} + +TEST(CircleLocalResponseNormalizationTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleLocalResponseNormalization local_response_normalization_node; + + TestVisitor tv; + ASSERT_THROW(local_response_normalization_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleLog.test.cpp b/compiler/luci/lang/src/Nodes/CircleLog.test.cpp new file mode 100644 index 000000000..0bb9ee76e --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleLog.test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleLog.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleLogTest, constructor) +{ + luci::CircleLog log_node; + + ASSERT_EQ(luci::CircleDialect::get(), log_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::LOG, log_node.opcode()); + + ASSERT_EQ(nullptr, log_node.x()); +} + +TEST(CircleLogTest, input_NEG) +{ + luci::CircleLog log_node; + luci::CircleLog node; + + log_node.x(&node); + ASSERT_NE(nullptr, log_node.x()); + + log_node.x(nullptr); + ASSERT_EQ(nullptr, log_node.x()); +} + +TEST(CircleLogTest, arity_NEG) +{ + luci::CircleLog log_node; + + ASSERT_NO_THROW(log_node.arg(0)); + ASSERT_THROW(log_node.arg(1), std::out_of_range); +} + +TEST(CircleLogTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleLog log_node; + + TestVisitor tv; + ASSERT_THROW(log_node.accept(&tv), std::exception); +} + +TEST(CircleLogTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleLog log_node; + + TestVisitor tv; + ASSERT_THROW(log_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleLogSoftmax.test.cpp b/compiler/luci/lang/src/Nodes/CircleLogSoftmax.test.cpp new file mode 100644 index 000000000..70977ae4f --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleLogSoftmax.test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleLogSoftmax.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleLogSoftmaxTest, constructor) +{ + luci::CircleLogSoftmax log_softmax_node; + + ASSERT_EQ(luci::CircleDialect::get(), log_softmax_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::LOG_SOFTMAX, log_softmax_node.opcode()); + + ASSERT_EQ(nullptr, log_softmax_node.logits()); +} + +TEST(CircleLogSoftmaxTest, input_NEG) +{ + luci::CircleLogSoftmax log_softmax_node; + luci::CircleLogSoftmax node; + + log_softmax_node.logits(&node); + ASSERT_NE(nullptr, log_softmax_node.logits()); + + log_softmax_node.logits(nullptr); + ASSERT_EQ(nullptr, log_softmax_node.logits()); +} + +TEST(CircleLogSoftmaxTest, arity_NEG) +{ + luci::CircleLogSoftmax log_softmax_node; + + ASSERT_NO_THROW(log_softmax_node.arg(0)); + ASSERT_THROW(log_softmax_node.arg(1), std::out_of_range); +} + +TEST(CircleLogSoftmaxTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleLogSoftmax log_softmax_node; + + TestVisitor tv; + ASSERT_THROW(log_softmax_node.accept(&tv), std::exception); +} + +TEST(CircleLogSoftmaxTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleLogSoftmax log_softmax_node; + + TestVisitor tv; + ASSERT_THROW(log_softmax_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleLogicalAnd.test.cpp b/compiler/luci/lang/src/Nodes/CircleLogicalAnd.test.cpp new file mode 100644 index 000000000..db378f022 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleLogicalAnd.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleLogicalAnd.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleLogicalAndTest, constructor_P) +{ + luci::CircleLogicalAnd and_node; + + ASSERT_EQ(luci::CircleDialect::get(), and_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::LOGICAL_AND, and_node.opcode()); + + ASSERT_EQ(nullptr, and_node.x()); + ASSERT_EQ(nullptr, and_node.y()); +} + +TEST(CircleLogicalAndTest, input_NEG) +{ + luci::CircleLogicalAnd and_node; + luci::CircleLogicalAnd node; + + and_node.x(&node); + and_node.y(&node); + ASSERT_NE(nullptr, and_node.x()); + ASSERT_NE(nullptr, and_node.y()); + + and_node.x(nullptr); + and_node.y(nullptr); + ASSERT_EQ(nullptr, and_node.x()); + ASSERT_EQ(nullptr, and_node.y()); +} + +TEST(CircleLogicalAndTest, arity_NEG) +{ + luci::CircleLogicalAnd and_node; + + ASSERT_NO_THROW(and_node.arg(1)); + ASSERT_THROW(and_node.arg(2), std::out_of_range); +} + +TEST(CircleLogicalAndTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleLogicalAnd and_node; + + TestVisitor tv; + ASSERT_THROW(and_node.accept(&tv), std::exception); +} + +TEST(CircleLogicalAndTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleLogicalAnd and_node; + + TestVisitor tv; + ASSERT_THROW(and_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleLogicalNot.test.cpp b/compiler/luci/lang/src/Nodes/CircleLogicalNot.test.cpp index 360dd4711..0c2c02938 100644 --- a/compiler/luci/lang/src/Nodes/CircleLogicalNot.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleLogicalNot.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleLogicalNot.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,8 +25,52 @@ TEST(CircleLogicalNotTest, constructor_P) { luci::CircleLogicalNot not_node; - ASSERT_EQ(not_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(not_node.opcode(), luci::CircleOpcode::LOGICAL_NOT); + ASSERT_EQ(luci::CircleDialect::get(), not_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::LOGICAL_NOT, not_node.opcode()); - ASSERT_EQ(not_node.x(), nullptr); + ASSERT_EQ(nullptr, not_node.x()); +} + +TEST(CircleLogicalNotTest, input_NEG) +{ + luci::CircleLogicalNot not_node; + luci::CircleLogicalNot node; + + not_node.x(&node); + ASSERT_NE(nullptr, not_node.x()); + + not_node.x(nullptr); + ASSERT_EQ(nullptr, not_node.x()); +} + +TEST(CircleLogicalNotTest, arity_NEG) +{ + luci::CircleLogicalNot not_node; + + ASSERT_NO_THROW(not_node.arg(0)); + ASSERT_THROW(not_node.arg(1), std::out_of_range); +} + +TEST(CircleLogicalNotTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleLogicalNot not_node; + + TestVisitor tv; + ASSERT_THROW(not_node.accept(&tv), std::exception); +} + +TEST(CircleLogicalNotTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleLogicalNot not_node; + + TestVisitor tv; + ASSERT_THROW(not_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleLogicalOr.test.cpp b/compiler/luci/lang/src/Nodes/CircleLogicalOr.test.cpp index 039db4afc..a08b863c7 100644 --- a/compiler/luci/lang/src/Nodes/CircleLogicalOr.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleLogicalOr.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleLogicalOr.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,9 +25,57 @@ TEST(CircleLogicalOrTest, constructor_P) { luci::CircleLogicalOr or_node; - ASSERT_EQ(or_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(or_node.opcode(), luci::CircleOpcode::LOGICAL_OR); + ASSERT_EQ(luci::CircleDialect::get(), or_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::LOGICAL_OR, or_node.opcode()); - ASSERT_EQ(or_node.x(), nullptr); - ASSERT_EQ(or_node.y(), nullptr); + ASSERT_EQ(nullptr, or_node.x()); + ASSERT_EQ(nullptr, or_node.y()); +} + +TEST(CircleLogicalOrTest, input_NEG) +{ + luci::CircleLogicalOr or_node; + luci::CircleLogicalOr node; + + or_node.x(&node); + or_node.y(&node); + ASSERT_NE(nullptr, or_node.x()); + ASSERT_NE(nullptr, or_node.y()); + + or_node.x(nullptr); + or_node.y(nullptr); + ASSERT_EQ(nullptr, or_node.x()); + ASSERT_EQ(nullptr, or_node.y()); +} + +TEST(CircleLogicalOrTest, arity_NEG) +{ + luci::CircleLogicalOr or_node; + + ASSERT_NO_THROW(or_node.arg(1)); + ASSERT_THROW(or_node.arg(2), std::out_of_range); +} + +TEST(CircleLogicalOrTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleLogicalOr or_node; + + TestVisitor tv; + ASSERT_THROW(or_node.accept(&tv), std::exception); +} + +TEST(CircleLogicalOrTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleLogicalOr or_node; + + TestVisitor tv; + ASSERT_THROW(or_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleLogistic.test.cpp b/compiler/luci/lang/src/Nodes/CircleLogistic.test.cpp new file mode 100644 index 000000000..18efd869d --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleLogistic.test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleLogistic.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleLogisticTest, constructor) +{ + luci::CircleLogistic logistic_node; + + ASSERT_EQ(luci::CircleDialect::get(), logistic_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::LOGISTIC, logistic_node.opcode()); + + ASSERT_EQ(nullptr, logistic_node.x()); +} + +TEST(CircleLogisticTest, input_NEG) +{ + luci::CircleLogistic logistic_node; + luci::CircleLogistic node; + + logistic_node.x(&node); + ASSERT_NE(nullptr, logistic_node.x()); + + logistic_node.x(nullptr); + ASSERT_EQ(nullptr, logistic_node.x()); +} + +TEST(CircleLogisticTest, arity_NEG) +{ + luci::CircleLogistic logistic_node; + + ASSERT_NO_THROW(logistic_node.arg(0)); + ASSERT_THROW(logistic_node.arg(1), std::out_of_range); +} + +TEST(CircleLogisticTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleLogistic logistic_node; + + TestVisitor tv; + ASSERT_THROW(logistic_node.accept(&tv), std::exception); +} + +TEST(CircleLogisticTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleLogistic logistic_node; + + TestVisitor tv; + ASSERT_THROW(logistic_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleMatrixDiag.test.cpp b/compiler/luci/lang/src/Nodes/CircleMatrixDiag.test.cpp new file mode 100644 index 000000000..9209cf1a4 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleMatrixDiag.test.cpp @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleMatrixDiag.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleMatrixDiagTest, constructor_P) +{ + luci::CircleMatrixDiag matrix_diag_node; + + ASSERT_EQ(luci::CircleDialect::get(), matrix_diag_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::MATRIX_DIAG, matrix_diag_node.opcode()); + + ASSERT_EQ(nullptr, matrix_diag_node.diagonal()); +} + +TEST(CircleMatrixDiagTest, input_NEG) +{ + luci::CircleMatrixDiag matrix_diag_node; + luci::CircleMatrixDiag node; + + matrix_diag_node.diagonal(&node); + + ASSERT_NE(nullptr, matrix_diag_node.diagonal()); + + matrix_diag_node.diagonal(nullptr); + + ASSERT_EQ(nullptr, matrix_diag_node.diagonal()); +} + +TEST(CircleMatrixDiagTest, arity_NEG) +{ + luci::CircleMatrixDiag matrix_diag_node; + + ASSERT_NO_THROW(matrix_diag_node.arg(0)); + ASSERT_THROW(matrix_diag_node.arg(1), std::out_of_range); +} + +TEST(CircleMatrixDiagTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleMatrixDiag matrix_diag_node; + + TestVisitor tv; + ASSERT_THROW(matrix_diag_node.accept(&tv), std::exception); +} + +TEST(CircleMatrixDiagTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleMatrixDiag matrix_diag_node; + + TestVisitor tv; + ASSERT_THROW(matrix_diag_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleMatrixSetDiag.test.cpp b/compiler/luci/lang/src/Nodes/CircleMatrixSetDiag.test.cpp new file mode 100644 index 000000000..9dea9852e --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleMatrixSetDiag.test.cpp @@ -0,0 +1,84 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleMatrixSetDiag.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleMatrixSetDiagTest, constructor_P) +{ + luci::CircleMatrixSetDiag matrix_set_diag_node; + + ASSERT_EQ(luci::CircleDialect::get(), matrix_set_diag_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::MATRIX_SET_DIAG, matrix_set_diag_node.opcode()); + + ASSERT_EQ(nullptr, matrix_set_diag_node.input()); + ASSERT_EQ(nullptr, matrix_set_diag_node.diagonal()); +} + +TEST(CircleMatrixSetDiagTest, input_NEG) +{ + luci::CircleMatrixSetDiag matrix_set_diag_node; + luci::CircleMatrixSetDiag node; + + matrix_set_diag_node.input(&node); + matrix_set_diag_node.diagonal(&node); + + ASSERT_NE(nullptr, matrix_set_diag_node.input()); + ASSERT_NE(nullptr, matrix_set_diag_node.diagonal()); + + matrix_set_diag_node.input(nullptr); + matrix_set_diag_node.diagonal(nullptr); + + ASSERT_EQ(nullptr, matrix_set_diag_node.input()); + ASSERT_EQ(nullptr, matrix_set_diag_node.diagonal()); +} + +TEST(CircleMatrixSetDiagTest, arity_NEG) +{ + luci::CircleMatrixSetDiag matrix_set_diag_node; + + ASSERT_NO_THROW(matrix_set_diag_node.arg(0)); + ASSERT_NO_THROW(matrix_set_diag_node.arg(1)); + ASSERT_THROW(matrix_set_diag_node.arg(2), std::out_of_range); +} + +TEST(CircleMatrixSetDiagTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleMatrixSetDiag matrix_set_diag_node; + + TestVisitor tv; + ASSERT_THROW(matrix_set_diag_node.accept(&tv), std::exception); +} + +TEST(CircleMatrixSetDiagTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleMatrixSetDiag matrix_set_diag_node; + + TestVisitor tv; + ASSERT_THROW(matrix_set_diag_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleMaxPool2D.test.cpp b/compiler/luci/lang/src/Nodes/CircleMaxPool2D.test.cpp index 874ecec0e..cb6c016e3 100644 --- a/compiler/luci/lang/src/Nodes/CircleMaxPool2D.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleMaxPool2D.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleMaxPool2D.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,10 +25,66 @@ TEST(CircleMaxPool2DTest, constructor_P) { luci::CircleMaxPool2D maxpool2d_node; - ASSERT_EQ(maxpool2d_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(maxpool2d_node.opcode(), luci::CircleOpcode::MAX_POOL_2D); + ASSERT_EQ(luci::CircleDialect::get(), maxpool2d_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::MAX_POOL_2D, maxpool2d_node.opcode()); - ASSERT_EQ(maxpool2d_node.value(), nullptr); - ASSERT_NE(maxpool2d_node.filter(), nullptr); - ASSERT_NE(maxpool2d_node.stride(), nullptr); + ASSERT_EQ(nullptr, maxpool2d_node.value()); + ASSERT_EQ(luci::Padding::UNDEFINED, maxpool2d_node.padding()); + ASSERT_EQ(1, maxpool2d_node.filter()->h()); + ASSERT_EQ(1, maxpool2d_node.filter()->w()); + ASSERT_EQ(1, maxpool2d_node.stride()->h()); + ASSERT_EQ(1, maxpool2d_node.stride()->w()); +} + +TEST(CircleMaxPool2DTest, input_NEG) +{ + luci::CircleMaxPool2D maxpool2d_node; + luci::CircleMaxPool2D node; + + maxpool2d_node.value(&node); + ASSERT_NE(nullptr, maxpool2d_node.value()); + + maxpool2d_node.value(nullptr); + ASSERT_EQ(nullptr, maxpool2d_node.value()); + + maxpool2d_node.filter()->h(2); + maxpool2d_node.filter()->w(2); + maxpool2d_node.stride()->h(2); + maxpool2d_node.stride()->w(2); + ASSERT_NE(1, maxpool2d_node.filter()->h()); + ASSERT_NE(1, maxpool2d_node.filter()->w()); + ASSERT_NE(1, maxpool2d_node.stride()->h()); + ASSERT_NE(1, maxpool2d_node.stride()->w()); +} + +TEST(CircleMaxPool2DTest, arity_NEG) +{ + luci::CircleMaxPool2D maxpool2d_node; + + ASSERT_NO_THROW(maxpool2d_node.arg(0)); + ASSERT_THROW(maxpool2d_node.arg(1), std::out_of_range); +} + +TEST(CircleMaxPool2DTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleMaxPool2D maxpool2d_node; + + TestVisitor tv; + ASSERT_THROW(maxpool2d_node.accept(&tv), std::exception); +} + +TEST(CircleMaxPool2DTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleMaxPool2D maxpool2d_node; + + TestVisitor tv; + ASSERT_THROW(maxpool2d_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleMaximum.test.cpp b/compiler/luci/lang/src/Nodes/CircleMaximum.test.cpp index efe62f11a..3fc6f1114 100644 --- a/compiler/luci/lang/src/Nodes/CircleMaximum.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleMaximum.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleMaximum.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,9 +25,57 @@ TEST(CircleMaximumTest, constructor_P) { luci::CircleMaximum max_node; - ASSERT_EQ(max_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(max_node.opcode(), luci::CircleOpcode::MAXIMUM); + ASSERT_EQ(luci::CircleDialect::get(), max_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::MAXIMUM, max_node.opcode()); - ASSERT_EQ(max_node.x(), nullptr); - ASSERT_EQ(max_node.y(), nullptr); + ASSERT_EQ(nullptr, max_node.x()); + ASSERT_EQ(nullptr, max_node.y()); +} + +TEST(CircleMaximumTest, input_NEG) +{ + luci::CircleMaximum max_node; + luci::CircleMaximum node; + + max_node.x(&node); + max_node.y(&node); + ASSERT_NE(nullptr, max_node.x()); + ASSERT_NE(nullptr, max_node.y()); + + max_node.x(nullptr); + max_node.y(nullptr); + ASSERT_EQ(nullptr, max_node.x()); + ASSERT_EQ(nullptr, max_node.y()); +} + +TEST(CircleMaximumTest, arity_NEG) +{ + luci::CircleMaximum max_node; + + ASSERT_NO_THROW(max_node.arg(1)); + ASSERT_THROW(max_node.arg(2), std::out_of_range); +} + +TEST(CircleMaximumTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleMaximum max_node; + + TestVisitor tv; + ASSERT_THROW(max_node.accept(&tv), std::exception); +} + +TEST(CircleMaximumTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleMaximum max_node; + + TestVisitor tv; + ASSERT_THROW(max_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleMean.test.cpp b/compiler/luci/lang/src/Nodes/CircleMean.test.cpp new file mode 100644 index 000000000..743063968 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleMean.test.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleMean.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleMeanTest, constructor) +{ + luci::CircleMean mean_node; + + ASSERT_EQ(luci::CircleDialect::get(), mean_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::MEAN, mean_node.opcode()); + + ASSERT_EQ(nullptr, mean_node.input()); + ASSERT_EQ(nullptr, mean_node.reduction_indices()); + + ASSERT_FALSE(mean_node.keep_dims()); +} + +TEST(CircleMeanTest, input_NEG) +{ + luci::CircleMean mean_node; + luci::CircleMean node; + + mean_node.input(&node); + mean_node.reduction_indices(&node); + ASSERT_NE(nullptr, mean_node.input()); + ASSERT_NE(nullptr, mean_node.reduction_indices()); + + mean_node.input(nullptr); + mean_node.reduction_indices(nullptr); + ASSERT_EQ(nullptr, mean_node.input()); + ASSERT_EQ(nullptr, mean_node.reduction_indices()); + + mean_node.keep_dims(true); + ASSERT_TRUE(mean_node.keep_dims()); +} + +TEST(CircleMeanTest, arity_NEG) +{ + luci::CircleMean mean_node; + + ASSERT_NO_THROW(mean_node.arg(1)); + ASSERT_THROW(mean_node.arg(2), std::out_of_range); +} + +TEST(CircleMeanTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleMean mean_node; + + TestVisitor tv; + ASSERT_THROW(mean_node.accept(&tv), std::exception); +} + +TEST(CircleMeanTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleMean mean_node; + + TestVisitor tv; + ASSERT_THROW(mean_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleMinimum.test.cpp b/compiler/luci/lang/src/Nodes/CircleMinimum.test.cpp new file mode 100644 index 000000000..19fe69fb7 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleMinimum.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleMinimum.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleMinimumTest, constructor_P) +{ + luci::CircleMinimum min_node; + + ASSERT_EQ(luci::CircleDialect::get(), min_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::MINIMUM, min_node.opcode()); + + ASSERT_EQ(nullptr, min_node.x()); + ASSERT_EQ(nullptr, min_node.y()); +} + +TEST(CircleMinimumTest, input_NEG) +{ + luci::CircleMinimum min_node; + luci::CircleMinimum node; + + min_node.x(&node); + min_node.y(&node); + ASSERT_NE(nullptr, min_node.x()); + ASSERT_NE(nullptr, min_node.y()); + + min_node.x(nullptr); + min_node.y(nullptr); + ASSERT_EQ(nullptr, min_node.x()); + ASSERT_EQ(nullptr, min_node.y()); +} + +TEST(CircleMinimumTest, arity_NEG) +{ + luci::CircleMinimum min_node; + + ASSERT_NO_THROW(min_node.arg(1)); + ASSERT_THROW(min_node.arg(2), std::out_of_range); +} + +TEST(CircleMinimumTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleMinimum min_node; + + TestVisitor tv; + ASSERT_THROW(min_node.accept(&tv), std::exception); +} + +TEST(CircleMinimumTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleMinimum min_node; + + TestVisitor tv; + ASSERT_THROW(min_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleMirrorPad.test.cpp b/compiler/luci/lang/src/Nodes/CircleMirrorPad.test.cpp new file mode 100644 index 000000000..9ba6bf58a --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleMirrorPad.test.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleMirrorPad.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleMirrorPadTest, constructor_P) +{ + luci::CircleMirrorPad pad_node; + + ASSERT_EQ(luci::CircleDialect::get(), pad_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::MIRROR_PAD, pad_node.opcode()); + + ASSERT_EQ(nullptr, pad_node.input()); + ASSERT_EQ(nullptr, pad_node.paddings()); + + ASSERT_EQ(luci::MirrorPadMode::REFLECT, pad_node.mode()); +} + +TEST(CircleMirrorPadTest, input_NEG) +{ + luci::CircleMirrorPad pad_node; + luci::CircleMirrorPad node; + + pad_node.input(&node); + pad_node.paddings(&node); + ASSERT_NE(nullptr, pad_node.input()); + ASSERT_NE(nullptr, pad_node.paddings()); + + pad_node.input(nullptr); + pad_node.paddings(nullptr); + ASSERT_EQ(nullptr, pad_node.input()); + ASSERT_EQ(nullptr, pad_node.paddings()); + + pad_node.mode(luci::MirrorPadMode::SYMMETRIC); + ASSERT_NE(luci::MirrorPadMode::REFLECT, pad_node.mode()); +} + +TEST(CircleMirrorPadTest, arity_NEG) +{ + luci::CircleMirrorPad pad_node; + + ASSERT_NO_THROW(pad_node.arg(1)); + ASSERT_THROW(pad_node.arg(2), std::out_of_range); +} + +TEST(CircleMirrorPadTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleMirrorPad pad_node; + + TestVisitor tv; + ASSERT_THROW(pad_node.accept(&tv), std::exception); +} + +TEST(CircleMirrorPadTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleMirrorPad pad_node; + + TestVisitor tv; + ASSERT_THROW(pad_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleMul.test.cpp b/compiler/luci/lang/src/Nodes/CircleMul.test.cpp index f9eca42f9..3c26d08ca 100644 --- a/compiler/luci/lang/src/Nodes/CircleMul.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleMul.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleMul.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,9 +25,57 @@ TEST(CircleMulTest, constructor_P) { luci::CircleMul mul_node; - ASSERT_EQ(mul_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(mul_node.opcode(), luci::CircleOpcode::MUL); + ASSERT_EQ(luci::CircleDialect::get(), mul_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::MUL, mul_node.opcode()); - ASSERT_EQ(mul_node.x(), nullptr); - ASSERT_EQ(mul_node.y(), nullptr); + ASSERT_EQ(nullptr, mul_node.x()); + ASSERT_EQ(nullptr, mul_node.y()); +} + +TEST(CircleMulTest, input_NEG) +{ + luci::CircleMul mul_node; + luci::CircleMul node; + + mul_node.x(&node); + mul_node.y(&node); + ASSERT_NE(nullptr, mul_node.x()); + ASSERT_NE(nullptr, mul_node.y()); + + mul_node.x(nullptr); + mul_node.y(nullptr); + ASSERT_EQ(nullptr, mul_node.x()); + ASSERT_EQ(nullptr, mul_node.y()); +} + +TEST(CircleMulTest, arity_NEG) +{ + luci::CircleMul mul_node; + + ASSERT_NO_THROW(mul_node.arg(1)); + ASSERT_THROW(mul_node.arg(2), std::out_of_range); +} + +TEST(CircleMulTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleMul mul_node; + + TestVisitor tv; + ASSERT_THROW(mul_node.accept(&tv), std::exception); +} + +TEST(CircleMulTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleMul mul_node; + + TestVisitor tv; + ASSERT_THROW(mul_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleNeg.test.cpp b/compiler/luci/lang/src/Nodes/CircleNeg.test.cpp new file mode 100644 index 000000000..4bcfa48a6 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleNeg.test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleNeg.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleNegTest, constructor) +{ + luci::CircleNeg neg_node; + + ASSERT_EQ(luci::CircleDialect::get(), neg_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::NEG, neg_node.opcode()); + + ASSERT_EQ(nullptr, neg_node.x()); +} + +TEST(CircleNegTest, input_NEG) +{ + luci::CircleNeg neg_node; + luci::CircleNeg node; + + neg_node.x(&node); + ASSERT_NE(nullptr, neg_node.x()); + + neg_node.x(nullptr); + ASSERT_EQ(nullptr, neg_node.x()); +} + +TEST(CircleNegTest, arity_NEG) +{ + luci::CircleNeg neg_node; + + ASSERT_NO_THROW(neg_node.arg(0)); + ASSERT_THROW(neg_node.arg(1), std::out_of_range); +} + +TEST(CircleNegTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleNeg neg_node; + + TestVisitor tv; + ASSERT_THROW(neg_node.accept(&tv), std::exception); +} + +TEST(CircleNegTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleNeg neg_node; + + TestVisitor tv; + ASSERT_THROW(neg_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleNotEqual.test.cpp b/compiler/luci/lang/src/Nodes/CircleNotEqual.test.cpp new file mode 100644 index 000000000..e464a7b96 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleNotEqual.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleNotEqual.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleNotEqualTest, constructor_P) +{ + luci::CircleNotEqual not_equal_node; + + ASSERT_EQ(luci::CircleDialect::get(), not_equal_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::NOT_EQUAL, not_equal_node.opcode()); + + ASSERT_EQ(nullptr, not_equal_node.x()); + ASSERT_EQ(nullptr, not_equal_node.y()); +} + +TEST(CircleNotEqualTest, input_NEG) +{ + luci::CircleNotEqual not_equal_node; + luci::CircleNotEqual node; + + not_equal_node.x(&node); + not_equal_node.y(&node); + ASSERT_NE(nullptr, not_equal_node.x()); + ASSERT_NE(nullptr, not_equal_node.y()); + + not_equal_node.x(nullptr); + not_equal_node.y(nullptr); + ASSERT_EQ(nullptr, not_equal_node.x()); + ASSERT_EQ(nullptr, not_equal_node.y()); +} + +TEST(CircleNotEqualTest, arity_NEG) +{ + luci::CircleNotEqual not_equal_node; + + ASSERT_NO_THROW(not_equal_node.arg(1)); + ASSERT_THROW(not_equal_node.arg(2), std::out_of_range); +} + +TEST(CircleNotEqualTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleNotEqual not_equal_node; + + TestVisitor tv; + ASSERT_THROW(not_equal_node.accept(&tv), std::exception); +} + +TEST(CircleNotEqualTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleNotEqual not_equal_node; + + TestVisitor tv; + ASSERT_THROW(not_equal_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleOneHot.test.cpp b/compiler/luci/lang/src/Nodes/CircleOneHot.test.cpp new file mode 100644 index 000000000..18e1045cc --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleOneHot.test.cpp @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleOneHot.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleOneHotTest, constructor) +{ + luci::CircleOneHot one_hot_node; + + ASSERT_EQ(luci::CircleDialect::get(), one_hot_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::ONE_HOT, one_hot_node.opcode()); + + ASSERT_EQ(nullptr, one_hot_node.indices()); + ASSERT_EQ(nullptr, one_hot_node.depth()); + ASSERT_EQ(nullptr, one_hot_node.on_value()); + ASSERT_EQ(nullptr, one_hot_node.off_value()); + ASSERT_EQ(-1, one_hot_node.axis()); +} + +TEST(CircleOneHotTest, input_NEG) +{ + luci::CircleOneHot one_hot_node; + luci::CircleOneHot node; + + one_hot_node.indices(&node); + one_hot_node.depth(&node); + one_hot_node.on_value(&node); + one_hot_node.off_value(&node); + ASSERT_NE(nullptr, one_hot_node.indices()); + ASSERT_NE(nullptr, one_hot_node.depth()); + ASSERT_NE(nullptr, one_hot_node.on_value()); + ASSERT_NE(nullptr, one_hot_node.off_value()); + + one_hot_node.indices(nullptr); + one_hot_node.depth(nullptr); + one_hot_node.on_value(nullptr); + one_hot_node.off_value(nullptr); + ASSERT_EQ(nullptr, one_hot_node.indices()); + ASSERT_EQ(nullptr, one_hot_node.depth()); + ASSERT_EQ(nullptr, one_hot_node.on_value()); + ASSERT_EQ(nullptr, one_hot_node.off_value()); + + one_hot_node.axis(1); + ASSERT_NE(-1, one_hot_node.axis()); +} + +TEST(CircleOneHotTest, arity_NEG) +{ + luci::CircleOneHot one_hot_node; + + ASSERT_NO_THROW(one_hot_node.arg(3)); + ASSERT_THROW(one_hot_node.arg(4), std::out_of_range); +} + +TEST(CircleOneHotTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleOneHot one_hot_node; + + TestVisitor tv; + ASSERT_THROW(one_hot_node.accept(&tv), std::exception); +} + +TEST(CircleOneHotTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleOneHot one_hot_node; + + TestVisitor tv; + ASSERT_THROW(one_hot_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CirclePRelu.test.cpp b/compiler/luci/lang/src/Nodes/CirclePRelu.test.cpp new file mode 100644 index 000000000..8355c6d97 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CirclePRelu.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CirclePRelu.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CirclePReluTest, constructor_P) +{ + luci::CirclePRelu prelu_node; + + ASSERT_EQ(luci::CircleDialect::get(), prelu_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::PRELU, prelu_node.opcode()); + + ASSERT_EQ(nullptr, prelu_node.input()); + ASSERT_EQ(nullptr, prelu_node.alpha()); +} + +TEST(CirclePReluTest, input_NEG) +{ + luci::CirclePRelu prelu_node; + luci::CirclePRelu node; + + prelu_node.input(&node); + prelu_node.alpha(&node); + ASSERT_NE(nullptr, prelu_node.input()); + ASSERT_NE(nullptr, prelu_node.alpha()); + + prelu_node.input(nullptr); + prelu_node.alpha(nullptr); + ASSERT_EQ(nullptr, prelu_node.input()); + ASSERT_EQ(nullptr, prelu_node.alpha()); +} + +TEST(CirclePReluTest, arity_NEG) +{ + luci::CirclePRelu prelu_node; + + ASSERT_NO_THROW(prelu_node.arg(1)); + ASSERT_THROW(prelu_node.arg(2), std::out_of_range); +} + +TEST(CirclePReluTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CirclePRelu prelu_node; + + TestVisitor tv; + ASSERT_THROW(prelu_node.accept(&tv), std::exception); +} + +TEST(CirclePReluTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CirclePRelu prelu_node; + + TestVisitor tv; + ASSERT_THROW(prelu_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CirclePack.test.cpp b/compiler/luci/lang/src/Nodes/CirclePack.test.cpp index 5c9a96f7c..5e64f0d89 100644 --- a/compiler/luci/lang/src/Nodes/CirclePack.test.cpp +++ b/compiler/luci/lang/src/Nodes/CirclePack.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CirclePack.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,12 +25,60 @@ TEST(CirclePackTest, constructor) { luci::CirclePack pack_node(3); - ASSERT_EQ(pack_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(pack_node.opcode(), luci::CircleOpcode::PACK); + ASSERT_EQ(luci::CircleDialect::get(), pack_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::PACK, pack_node.opcode()); - ASSERT_EQ(pack_node.axis(), 0); - ASSERT_EQ(pack_node.values_count(), 3); - ASSERT_EQ(pack_node.values(0), nullptr); - ASSERT_EQ(pack_node.values(1), nullptr); - ASSERT_EQ(pack_node.values(2), nullptr); + ASSERT_EQ(0, pack_node.axis()); + ASSERT_EQ(3, pack_node.values_count()); + ASSERT_EQ(nullptr, pack_node.values(0)); + ASSERT_EQ(nullptr, pack_node.values(1)); + ASSERT_EQ(nullptr, pack_node.values(2)); +} + +TEST(CirclePackTest, input_NEG) +{ + luci::CirclePack pack_node(2); + luci::CirclePack node(2); + + pack_node.values(0, &node); + pack_node.values(1, &node); + ASSERT_NE(nullptr, pack_node.values(0)); + ASSERT_NE(nullptr, pack_node.values(1)); + + pack_node.values(0, nullptr); + pack_node.values(1, nullptr); + ASSERT_EQ(nullptr, pack_node.values(0)); + ASSERT_EQ(nullptr, pack_node.values(1)); +} + +TEST(CirclePackTest, arity_NEG) +{ + luci::CirclePack pack_node(5); + + ASSERT_NO_THROW(pack_node.arg(4)); + ASSERT_THROW(pack_node.arg(5), std::out_of_range); +} + +TEST(CirclePackTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CirclePack pack_node(2); + + TestVisitor tv; + ASSERT_THROW(pack_node.accept(&tv), std::exception); +} + +TEST(CirclePackTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CirclePack pack_node(2); + + TestVisitor tv; + ASSERT_THROW(pack_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CirclePad.test.cpp b/compiler/luci/lang/src/Nodes/CirclePad.test.cpp index 3a23fa0f0..12c66b7ea 100644 --- a/compiler/luci/lang/src/Nodes/CirclePad.test.cpp +++ b/compiler/luci/lang/src/Nodes/CirclePad.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CirclePad.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,9 +25,57 @@ TEST(CirclePadTest, constructor_P) { luci::CirclePad pad_node; - ASSERT_EQ(pad_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(pad_node.opcode(), luci::CircleOpcode::PAD); + ASSERT_EQ(luci::CircleDialect::get(), pad_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::PAD, pad_node.opcode()); - ASSERT_EQ(pad_node.input(), nullptr); - ASSERT_EQ(pad_node.paddings(), nullptr); + ASSERT_EQ(nullptr, pad_node.input()); + ASSERT_EQ(nullptr, pad_node.paddings()); +} + +TEST(CirclePadTest, input_NEG) +{ + luci::CirclePad pad_node; + luci::CirclePad node; + + pad_node.input(&node); + pad_node.paddings(&node); + ASSERT_NE(nullptr, pad_node.input()); + ASSERT_NE(nullptr, pad_node.paddings()); + + pad_node.input(nullptr); + pad_node.paddings(nullptr); + ASSERT_EQ(nullptr, pad_node.input()); + ASSERT_EQ(nullptr, pad_node.paddings()); +} + +TEST(CirclePadTest, arity_NEG) +{ + luci::CirclePad pad_node; + + ASSERT_NO_THROW(pad_node.arg(1)); + ASSERT_THROW(pad_node.arg(2), std::out_of_range); +} + +TEST(CirclePadTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CirclePad pad_node; + + TestVisitor tv; + ASSERT_THROW(pad_node.accept(&tv), std::exception); +} + +TEST(CirclePadTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CirclePad pad_node; + + TestVisitor tv; + ASSERT_THROW(pad_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CirclePow.test.cpp b/compiler/luci/lang/src/Nodes/CirclePow.test.cpp new file mode 100644 index 000000000..67ba0882b --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CirclePow.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CirclePow.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CirclePowTest, constructor_P) +{ + luci::CirclePow pow_node; + + ASSERT_EQ(luci::CircleDialect::get(), pow_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::POW, pow_node.opcode()); + + ASSERT_EQ(nullptr, pow_node.x()); + ASSERT_EQ(nullptr, pow_node.y()); +} + +TEST(CirclePowTest, input_NEG) +{ + luci::CirclePow pow_node; + luci::CirclePow node; + + pow_node.x(&node); + pow_node.y(&node); + ASSERT_NE(nullptr, pow_node.x()); + ASSERT_NE(nullptr, pow_node.y()); + + pow_node.x(nullptr); + pow_node.y(nullptr); + ASSERT_EQ(nullptr, pow_node.x()); + ASSERT_EQ(nullptr, pow_node.y()); +} + +TEST(CirclePowTest, arity_NEG) +{ + luci::CirclePow pow_node; + + ASSERT_NO_THROW(pow_node.arg(1)); + ASSERT_THROW(pow_node.arg(2), std::out_of_range); +} + +TEST(CirclePowTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CirclePow pow_node; + + TestVisitor tv; + ASSERT_THROW(pow_node.accept(&tv), std::exception); +} + +TEST(CirclePowTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CirclePow pow_node; + + TestVisitor tv; + ASSERT_THROW(pow_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleRange.test.cpp b/compiler/luci/lang/src/Nodes/CircleRange.test.cpp new file mode 100644 index 000000000..dd54dfd6e --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleRange.test.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleRange.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleRangeTest, constructor) +{ + luci::CircleRange range_node; + + ASSERT_EQ(luci::CircleDialect::get(), range_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::RANGE, range_node.opcode()); + + ASSERT_EQ(nullptr, range_node.start()); + ASSERT_EQ(nullptr, range_node.limit()); + ASSERT_EQ(nullptr, range_node.delta()); +} + +TEST(CircleRangeTest, input_NEG) +{ + luci::CircleRange range_node; + luci::CircleRange node; + + range_node.start(&node); + range_node.limit(&node); + range_node.delta(&node); + ASSERT_NE(nullptr, range_node.start()); + ASSERT_NE(nullptr, range_node.limit()); + ASSERT_NE(nullptr, range_node.delta()); + + range_node.start(nullptr); + range_node.limit(nullptr); + range_node.delta(nullptr); + ASSERT_EQ(nullptr, range_node.start()); + ASSERT_EQ(nullptr, range_node.limit()); + ASSERT_EQ(nullptr, range_node.delta()); +} + +TEST(CircleRangeTest, arity_NEG) +{ + luci::CircleRange range_node; + + ASSERT_NO_THROW(range_node.arg(2)); + ASSERT_THROW(range_node.arg(3), std::out_of_range); +} + +TEST(CircleRangeTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleRange range_node; + + TestVisitor tv; + ASSERT_THROW(range_node.accept(&tv), std::exception); +} + +TEST(CircleRangeTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleRange range_node; + + TestVisitor tv; + ASSERT_THROW(range_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleRank.test.cpp b/compiler/luci/lang/src/Nodes/CircleRank.test.cpp new file mode 100644 index 000000000..e64eae235 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleRank.test.cpp @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleRank.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleRankTest, constructor_P) +{ + luci::CircleRank rank_node; + + ASSERT_EQ(luci::CircleDialect::get(), rank_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::RANK, rank_node.opcode()); + + ASSERT_EQ(nullptr, rank_node.input()); +} diff --git a/compiler/luci/lang/src/Nodes/CircleReduceAny.test.cpp b/compiler/luci/lang/src/Nodes/CircleReduceAny.test.cpp new file mode 100644 index 000000000..cd5c6b746 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleReduceAny.test.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleReduceAny.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleReduceAnyTest, constructor) +{ + luci::CircleReduceAny reduce_any_node; + + ASSERT_EQ(luci::CircleDialect::get(), reduce_any_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::REDUCE_ANY, reduce_any_node.opcode()); + + ASSERT_EQ(nullptr, reduce_any_node.input()); + ASSERT_EQ(nullptr, reduce_any_node.reduction_indices()); + + ASSERT_FALSE(reduce_any_node.keep_dims()); +} + +TEST(CircleReduceAnyTest, input_NEG) +{ + luci::CircleReduceAny reduce_any_node; + luci::CircleReduceAny node; + + reduce_any_node.input(&node); + reduce_any_node.reduction_indices(&node); + ASSERT_NE(nullptr, reduce_any_node.input()); + ASSERT_NE(nullptr, reduce_any_node.reduction_indices()); + + reduce_any_node.input(nullptr); + reduce_any_node.reduction_indices(nullptr); + ASSERT_EQ(nullptr, reduce_any_node.input()); + ASSERT_EQ(nullptr, reduce_any_node.reduction_indices()); + + reduce_any_node.keep_dims(true); + ASSERT_TRUE(reduce_any_node.keep_dims()); +} + +TEST(CircleReduceAnyTest, arity_NEG) +{ + luci::CircleReduceAny reduce_any_node; + + ASSERT_NO_THROW(reduce_any_node.arg(1)); + ASSERT_THROW(reduce_any_node.arg(2), std::out_of_range); +} + +TEST(CircleReduceAnyTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleReduceAny reduce_any_node; + + TestVisitor tv; + ASSERT_THROW(reduce_any_node.accept(&tv), std::exception); +} + +TEST(CircleReduceAnyTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleReduceAny reduce_any_node; + + TestVisitor tv; + ASSERT_THROW(reduce_any_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleReduceMax.test.cpp b/compiler/luci/lang/src/Nodes/CircleReduceMax.test.cpp new file mode 100644 index 000000000..bdd1818e0 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleReduceMax.test.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleReduceMax.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleReduceMaxTest, constructor_P) +{ + luci::CircleReduceMax reduce_max_node; + + ASSERT_EQ(luci::CircleDialect::get(), reduce_max_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::REDUCE_MAX, reduce_max_node.opcode()); + + ASSERT_EQ(nullptr, reduce_max_node.input()); + ASSERT_EQ(nullptr, reduce_max_node.reduction_indices()); + + ASSERT_FALSE(reduce_max_node.keep_dims()); +} + +TEST(CircleReduceMaxTest, input_NEG) +{ + luci::CircleReduceMax reduce_max_node; + luci::CircleReduceMax node; + + reduce_max_node.input(&node); + reduce_max_node.reduction_indices(&node); + ASSERT_NE(nullptr, reduce_max_node.input()); + ASSERT_NE(nullptr, reduce_max_node.reduction_indices()); + + reduce_max_node.input(nullptr); + reduce_max_node.reduction_indices(nullptr); + ASSERT_EQ(nullptr, reduce_max_node.input()); + ASSERT_EQ(nullptr, reduce_max_node.reduction_indices()); + + reduce_max_node.keep_dims(true); + ASSERT_TRUE(reduce_max_node.keep_dims()); +} + +TEST(CircleReduceMaxTest, arity_NEG) +{ + luci::CircleReduceMax reduce_max_node; + + ASSERT_NO_THROW(reduce_max_node.arg(1)); + ASSERT_THROW(reduce_max_node.arg(2), std::out_of_range); +} + +TEST(CircleReduceMaxTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleReduceMax reduce_max_node; + + TestVisitor tv; + ASSERT_THROW(reduce_max_node.accept(&tv), std::exception); +} + +TEST(CircleReduceMaxTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleReduceMax reduce_max_node; + + TestVisitor tv; + ASSERT_THROW(reduce_max_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleReduceMin.test.cpp b/compiler/luci/lang/src/Nodes/CircleReduceMin.test.cpp new file mode 100644 index 000000000..ba99ae648 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleReduceMin.test.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleReduceMin.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleReduceMinTest, constructor_P) +{ + luci::CircleReduceMin reduce_min_node; + + ASSERT_EQ(luci::CircleDialect::get(), reduce_min_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::REDUCE_MIN, reduce_min_node.opcode()); + + ASSERT_EQ(nullptr, reduce_min_node.input()); + ASSERT_EQ(nullptr, reduce_min_node.reduction_indices()); + + ASSERT_FALSE(reduce_min_node.keep_dims()); +} + +TEST(CircleReduceMinTest, input_NEG) +{ + luci::CircleReduceMin reduce_min_node; + luci::CircleReduceMin node; + + reduce_min_node.input(&node); + reduce_min_node.reduction_indices(&node); + ASSERT_NE(nullptr, reduce_min_node.input()); + ASSERT_NE(nullptr, reduce_min_node.reduction_indices()); + + reduce_min_node.input(nullptr); + reduce_min_node.reduction_indices(nullptr); + ASSERT_EQ(nullptr, reduce_min_node.input()); + ASSERT_EQ(nullptr, reduce_min_node.reduction_indices()); + + reduce_min_node.keep_dims(true); + ASSERT_TRUE(reduce_min_node.keep_dims()); +} + +TEST(CircleReduceMinTest, arity_NEG) +{ + luci::CircleReduceMin reduce_min_node; + + ASSERT_NO_THROW(reduce_min_node.arg(1)); + ASSERT_THROW(reduce_min_node.arg(2), std::out_of_range); +} + +TEST(CircleReduceMinTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleReduceMin reduce_min_node; + + TestVisitor tv; + ASSERT_THROW(reduce_min_node.accept(&tv), std::exception); +} + +TEST(CircleReduceMinTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleReduceMin reduce_min_node; + + TestVisitor tv; + ASSERT_THROW(reduce_min_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleReduceProd.test.cpp b/compiler/luci/lang/src/Nodes/CircleReduceProd.test.cpp new file mode 100644 index 000000000..f60b2905b --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleReduceProd.test.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleReduceProd.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleReduceProdTest, constructor) +{ + luci::CircleReduceProd reduce_prod_node; + + ASSERT_EQ(luci::CircleDialect::get(), reduce_prod_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::REDUCE_PROD, reduce_prod_node.opcode()); + + ASSERT_EQ(nullptr, reduce_prod_node.input()); + ASSERT_EQ(nullptr, reduce_prod_node.reduction_indices()); + + ASSERT_FALSE(reduce_prod_node.keep_dims()); +} + +TEST(CircleReduceProdTest, input_NEG) +{ + luci::CircleReduceProd reduce_prod_node; + luci::CircleReduceProd node; + + reduce_prod_node.input(&node); + reduce_prod_node.reduction_indices(&node); + ASSERT_NE(nullptr, reduce_prod_node.input()); + ASSERT_NE(nullptr, reduce_prod_node.reduction_indices()); + + reduce_prod_node.input(nullptr); + reduce_prod_node.reduction_indices(nullptr); + ASSERT_EQ(nullptr, reduce_prod_node.input()); + ASSERT_EQ(nullptr, reduce_prod_node.reduction_indices()); + + reduce_prod_node.keep_dims(true); + ASSERT_TRUE(reduce_prod_node.keep_dims()); +} + +TEST(CircleReduceProdTest, arity_NEG) +{ + luci::CircleReduceProd reduce_prod_node; + + ASSERT_NO_THROW(reduce_prod_node.arg(1)); + ASSERT_THROW(reduce_prod_node.arg(2), std::out_of_range); +} + +TEST(CircleReduceProdTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleReduceProd reduce_prod_node; + + TestVisitor tv; + ASSERT_THROW(reduce_prod_node.accept(&tv), std::exception); +} + +TEST(CircleReduceProdTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleReduceProd reduce_prod_node; + + TestVisitor tv; + ASSERT_THROW(reduce_prod_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleRelu.test.cpp b/compiler/luci/lang/src/Nodes/CircleRelu.test.cpp index 19ea88aa6..35796509c 100644 --- a/compiler/luci/lang/src/Nodes/CircleRelu.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleRelu.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleRelu.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,8 +25,52 @@ TEST(CircleReluTest, constructor_P) { luci::CircleRelu relu_node; - ASSERT_EQ(relu_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(relu_node.opcode(), luci::CircleOpcode::RELU); + ASSERT_EQ(luci::CircleDialect::get(), relu_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::RELU, relu_node.opcode()); - ASSERT_EQ(relu_node.features(), nullptr); + ASSERT_EQ(nullptr, relu_node.features()); +} + +TEST(CircleReluTest, input_NEG) +{ + luci::CircleRelu relu_node; + luci::CircleRelu node; + + relu_node.features(&node); + ASSERT_NE(nullptr, relu_node.features()); + + relu_node.features(nullptr); + ASSERT_EQ(nullptr, relu_node.features()); +} + +TEST(CircleReluTest, arity_NEG) +{ + luci::CircleRelu relu_node; + + ASSERT_NO_THROW(relu_node.arg(0)); + ASSERT_THROW(relu_node.arg(1), std::out_of_range); +} + +TEST(CircleReluTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleRelu relu_node; + + TestVisitor tv; + ASSERT_THROW(relu_node.accept(&tv), std::exception); +} + +TEST(CircleReluTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleRelu relu_node; + + TestVisitor tv; + ASSERT_THROW(relu_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleRelu6.test.cpp b/compiler/luci/lang/src/Nodes/CircleRelu6.test.cpp index 74bf2e86a..647a5d7ba 100644 --- a/compiler/luci/lang/src/Nodes/CircleRelu6.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleRelu6.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleRelu6.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,8 +25,52 @@ TEST(CircleRelu6Test, constructor_P) { luci::CircleRelu6 relu6_node; - ASSERT_EQ(relu6_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(relu6_node.opcode(), luci::CircleOpcode::RELU6); + ASSERT_EQ(luci::CircleDialect::get(), relu6_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::RELU6, relu6_node.opcode()); - ASSERT_EQ(relu6_node.features(), nullptr); + ASSERT_EQ(nullptr, relu6_node.features()); +} + +TEST(CircleRelu6Test, input_NEG) +{ + luci::CircleRelu6 relu6_node; + luci::CircleRelu6 node; + + relu6_node.features(&node); + ASSERT_NE(nullptr, relu6_node.features()); + + relu6_node.features(nullptr); + ASSERT_EQ(nullptr, relu6_node.features()); +} + +TEST(CircleRelu6Test, arity_NEG) +{ + luci::CircleRelu6 relu6_node; + + ASSERT_NO_THROW(relu6_node.arg(0)); + ASSERT_THROW(relu6_node.arg(1), std::out_of_range); +} + +TEST(CircleRelu6Test, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleRelu6 relu6_node; + + TestVisitor tv; + ASSERT_THROW(relu6_node.accept(&tv), std::exception); +} + +TEST(CircleRelu6Test, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleRelu6 relu6_node; + + TestVisitor tv; + ASSERT_THROW(relu6_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleReluN1To1.test.cpp b/compiler/luci/lang/src/Nodes/CircleReluN1To1.test.cpp new file mode 100644 index 000000000..8de84ac42 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleReluN1To1.test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleReluN1To1.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleReluN1To1Test, constructor) +{ + luci::CircleReluN1To1 relu_node; + + ASSERT_EQ(luci::CircleDialect::get(), relu_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::RELU_N1_TO_1, relu_node.opcode()); + + ASSERT_EQ(nullptr, relu_node.features()); +} + +TEST(CircleReluN1To1Test, input_NEG) +{ + luci::CircleReluN1To1 relu_node; + luci::CircleReluN1To1 node; + + relu_node.features(&node); + ASSERT_NE(nullptr, relu_node.features()); + + relu_node.features(nullptr); + ASSERT_EQ(nullptr, relu_node.features()); +} + +TEST(CircleReluN1To1Test, arity_NEG) +{ + luci::CircleReluN1To1 relu_node; + + ASSERT_NO_THROW(relu_node.arg(0)); + ASSERT_THROW(relu_node.arg(1), std::out_of_range); +} + +TEST(CircleReluN1To1Test, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleReluN1To1 relu_node; + + TestVisitor tv; + ASSERT_THROW(relu_node.accept(&tv), std::exception); +} + +TEST(CircleReluN1To1Test, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleReluN1To1 relu_node; + + TestVisitor tv; + ASSERT_THROW(relu_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleReshape.test.cpp b/compiler/luci/lang/src/Nodes/CircleReshape.test.cpp index 7bc2d32a4..236fde28b 100644 --- a/compiler/luci/lang/src/Nodes/CircleReshape.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleReshape.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleReshape.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,12 +25,12 @@ TEST(CircleReshapeTest, constructor_P) { luci::CircleReshape reshape; - ASSERT_EQ(reshape.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(reshape.opcode(), luci::CircleOpcode::RESHAPE); + ASSERT_EQ(luci::CircleDialect::get(), reshape.dialect()); + ASSERT_EQ(luci::CircleOpcode::RESHAPE, reshape.opcode()); - ASSERT_EQ(reshape.tensor(), nullptr); - ASSERT_EQ(reshape.shape(), nullptr); - ASSERT_EQ(reshape.newShape()->rank(), 0); + ASSERT_EQ(nullptr, reshape.tensor()); + ASSERT_EQ(nullptr, reshape.shape()); + ASSERT_EQ(0, reshape.newShape()->rank()); } TEST(CircleReshapeTest, alloc_new_shape_P) @@ -37,12 +38,60 @@ TEST(CircleReshapeTest, alloc_new_shape_P) luci::CircleReshape reshape; reshape.newShape()->rank(2); - ASSERT_EQ(reshape.newShape()->rank(), 2); + ASSERT_EQ(2, reshape.newShape()->rank()); reshape.newShape()->dim(0) = 0; reshape.newShape()->dim(1) = 1; auto &const_reshape = const_cast<const luci::CircleReshape &>(reshape); - ASSERT_EQ(const_reshape.newShape()->dim(0), 0); - ASSERT_EQ(const_reshape.newShape()->dim(1), 1); + ASSERT_EQ(0, const_reshape.newShape()->dim(0)); + ASSERT_EQ(1, const_reshape.newShape()->dim(1)); +} + +TEST(CircleReshapeTest, input_NEG) +{ + luci::CircleReshape reshape_node; + luci::CircleReshape node; + + reshape_node.tensor(&node); + reshape_node.shape(&node); + ASSERT_NE(nullptr, reshape_node.tensor()); + ASSERT_NE(nullptr, reshape_node.shape()); + + reshape_node.tensor(nullptr); + reshape_node.shape(nullptr); + ASSERT_EQ(nullptr, reshape_node.tensor()); + ASSERT_EQ(nullptr, reshape_node.shape()); +} + +TEST(CircleReshapeTest, arity_NEG) +{ + luci::CircleReshape reshape_node; + + ASSERT_NO_THROW(reshape_node.arg(1)); + ASSERT_THROW(reshape_node.arg(2), std::out_of_range); +} + +TEST(CircleReshapeTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleReshape reshape_node; + + TestVisitor tv; + ASSERT_THROW(reshape_node.accept(&tv), std::exception); +} + +TEST(CircleReshapeTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleReshape reshape_node; + + TestVisitor tv; + ASSERT_THROW(reshape_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleResizeBilinear.test.cpp b/compiler/luci/lang/src/Nodes/CircleResizeBilinear.test.cpp new file mode 100644 index 000000000..a1481a640 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleResizeBilinear.test.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleResizeBilinear.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleResizeBilinearTest, constructor) +{ + luci::CircleResizeBilinear resize; + + ASSERT_EQ(luci::CircleDialect::get(), resize.dialect()); + ASSERT_EQ(luci::CircleOpcode::RESIZE_BILINEAR, resize.opcode()); + + ASSERT_EQ(nullptr, resize.input()); + ASSERT_EQ(nullptr, resize.size()); + ASSERT_FALSE(resize.align_corners()); + ASSERT_FALSE(resize.half_pixel_centers()); +} + +TEST(CircleResizeBilinearTest, input_NEG) +{ + luci::CircleResizeBilinear resize_node; + luci::CircleResizeBilinear node; + + resize_node.input(&node); + resize_node.size(&node); + ASSERT_NE(nullptr, resize_node.input()); + ASSERT_NE(nullptr, resize_node.size()); + + resize_node.input(nullptr); + resize_node.size(nullptr); + ASSERT_EQ(nullptr, resize_node.input()); + ASSERT_EQ(nullptr, resize_node.size()); + + resize_node.align_corners(true); + ASSERT_TRUE(resize_node.align_corners()); + resize_node.half_pixel_centers(true); + ASSERT_TRUE(resize_node.half_pixel_centers()); +} + +TEST(CircleResizeBilinearTest, arity_NEG) +{ + luci::CircleResizeBilinear resize_node; + + ASSERT_NO_THROW(resize_node.arg(1)); + ASSERT_THROW(resize_node.arg(2), std::out_of_range); +} + +TEST(CircleResizeBilinearTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleResizeBilinear resize_node; + + TestVisitor tv; + ASSERT_THROW(resize_node.accept(&tv), std::exception); +} + +TEST(CircleResizeBilinearTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleResizeBilinear resize_node; + + TestVisitor tv; + ASSERT_THROW(resize_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleResizeNearestNeighbor.test.cpp b/compiler/luci/lang/src/Nodes/CircleResizeNearestNeighbor.test.cpp new file mode 100644 index 000000000..00e0ae9ea --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleResizeNearestNeighbor.test.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleResizeNearestNeighbor.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleResizeNearestNeightborTest, constructor) +{ + luci::CircleResizeNearestNeighbor resize; + + ASSERT_EQ(luci::CircleDialect::get(), resize.dialect()); + ASSERT_EQ(luci::CircleOpcode::RESIZE_NEAREST_NEIGHBOR, resize.opcode()); + + ASSERT_EQ(nullptr, resize.input()); + ASSERT_EQ(nullptr, resize.size()); + ASSERT_FALSE(resize.align_corners()); +} + +TEST(CircleResizeNearestNeightborTest, input_NEG) +{ + luci::CircleResizeNearestNeighbor resize_node; + luci::CircleResizeNearestNeighbor node; + + resize_node.input(&node); + resize_node.size(&node); + ASSERT_NE(nullptr, resize_node.input()); + ASSERT_NE(nullptr, resize_node.size()); + + resize_node.input(nullptr); + resize_node.size(nullptr); + ASSERT_EQ(nullptr, resize_node.input()); + ASSERT_EQ(nullptr, resize_node.size()); + + resize_node.align_corners(true); + ASSERT_TRUE(resize_node.align_corners()); +} + +TEST(CircleResizeNearestNeightborTest, arity_NEG) +{ + luci::CircleResizeNearestNeighbor resize_node; + + ASSERT_NO_THROW(resize_node.arg(1)); + ASSERT_THROW(resize_node.arg(2), std::out_of_range); +} + +TEST(CircleResizeNearestNeightborTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleResizeNearestNeighbor resize_node; + + TestVisitor tv; + ASSERT_THROW(resize_node.accept(&tv), std::exception); +} + +TEST(CircleResizeNearestNeightborTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleResizeNearestNeighbor resize_node; + + TestVisitor tv; + ASSERT_THROW(resize_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleReverseSequence.test.cpp b/compiler/luci/lang/src/Nodes/CircleReverseSequence.test.cpp new file mode 100644 index 000000000..b1cc6d6d6 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleReverseSequence.test.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleReverseSequence.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleReverseSequenceTest, constructor_P) +{ + luci::CircleReverseSequence std_node; + + ASSERT_EQ(luci::CircleDialect::get(), std_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::REVERSE_SEQUENCE, std_node.opcode()); + + ASSERT_EQ(nullptr, std_node.input()); + ASSERT_EQ(nullptr, std_node.seq_lengths()); + + ASSERT_EQ(0, std_node.seq_axis()); + ASSERT_EQ(0, std_node.batch_axis()); +} diff --git a/compiler/luci/lang/src/Nodes/CircleReverseV2.test.cpp b/compiler/luci/lang/src/Nodes/CircleReverseV2.test.cpp new file mode 100644 index 000000000..cc568e81a --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleReverseV2.test.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleReverseV2.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleReverseV2, constructor_P) +{ + luci::CircleReverseV2 std_node; + + ASSERT_EQ(luci::CircleDialect::get(), std_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::REVERSE_V2, std_node.opcode()); + + ASSERT_EQ(nullptr, std_node.tensor()); + ASSERT_EQ(nullptr, std_node.axis()); +} diff --git a/compiler/luci/lang/src/Nodes/CircleRound.test.cpp b/compiler/luci/lang/src/Nodes/CircleRound.test.cpp new file mode 100644 index 000000000..2f4518daf --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleRound.test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleRound.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleRoundTest, constructor_P) +{ + luci::CircleRound round_node; + + ASSERT_EQ(luci::CircleDialect::get(), round_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::ROUND, round_node.opcode()); + + ASSERT_EQ(nullptr, round_node.x()); +} + +TEST(CircleRoundTest, input_NEG) +{ + luci::CircleRound round_node; + luci::CircleRound node; + + round_node.x(&node); + ASSERT_NE(nullptr, round_node.x()); + + round_node.x(nullptr); + ASSERT_EQ(nullptr, round_node.x()); +} + +TEST(CircleRoundTest, arity_NEG) +{ + luci::CircleRound round_node; + + ASSERT_NO_THROW(round_node.arg(0)); + ASSERT_THROW(round_node.arg(1), std::out_of_range); +} + +TEST(CircleRoundTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleRound round_node; + + TestVisitor tv; + ASSERT_THROW(round_node.accept(&tv), std::exception); +} + +TEST(CircleRoundTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleRound round_node; + + TestVisitor tv; + ASSERT_THROW(round_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleRsqrt.test.cpp b/compiler/luci/lang/src/Nodes/CircleRsqrt.test.cpp index 51f6bab36..d038979c1 100644 --- a/compiler/luci/lang/src/Nodes/CircleRsqrt.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleRsqrt.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleRsqrt.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,8 +25,52 @@ TEST(CircleRsqrtTest, constructor) { luci::CircleRsqrt rsqrt_node; - ASSERT_EQ(rsqrt_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(rsqrt_node.opcode(), luci::CircleOpcode::RSQRT); + ASSERT_EQ(luci::CircleDialect::get(), rsqrt_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::RSQRT, rsqrt_node.opcode()); - ASSERT_EQ(rsqrt_node.x(), nullptr); + ASSERT_EQ(nullptr, rsqrt_node.x()); +} + +TEST(CircleRsqrtTest, input_NEG) +{ + luci::CircleRsqrt rsqrt_node; + luci::CircleRsqrt node; + + rsqrt_node.x(&node); + ASSERT_NE(nullptr, rsqrt_node.x()); + + rsqrt_node.x(nullptr); + ASSERT_EQ(nullptr, rsqrt_node.x()); +} + +TEST(CircleRsqrtTest, arity_NEG) +{ + luci::CircleRsqrt rsqrt_node; + + ASSERT_NO_THROW(rsqrt_node.arg(0)); + ASSERT_THROW(rsqrt_node.arg(1), std::out_of_range); +} + +TEST(CircleRsqrtTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleRsqrt rsqrt_node; + + TestVisitor tv; + ASSERT_THROW(rsqrt_node.accept(&tv), std::exception); +} + +TEST(CircleRsqrtTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleRsqrt rsqrt_node; + + TestVisitor tv; + ASSERT_THROW(rsqrt_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleScatterNd.test.cpp b/compiler/luci/lang/src/Nodes/CircleScatterNd.test.cpp new file mode 100644 index 000000000..165f26b44 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleScatterNd.test.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleScatterNd.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleScatterNdTest, constructor_P) +{ + luci::CircleScatterNd scatter_nd_node; + + ASSERT_EQ(luci::CircleDialect::get(), scatter_nd_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SCATTER_ND, scatter_nd_node.opcode()); + + ASSERT_EQ(nullptr, scatter_nd_node.indices()); + ASSERT_EQ(nullptr, scatter_nd_node.updates()); + ASSERT_EQ(nullptr, scatter_nd_node.shape()); +} + +TEST(CircleScatterNdTest, input_NEG) +{ + luci::CircleScatterNd scatter_nd_node; + luci::CircleScatterNd node; + + scatter_nd_node.indices(&node); + scatter_nd_node.updates(&node); + scatter_nd_node.shape(&node); + ASSERT_NE(nullptr, scatter_nd_node.indices()); + ASSERT_NE(nullptr, scatter_nd_node.updates()); + ASSERT_NE(nullptr, scatter_nd_node.shape()); + + scatter_nd_node.indices(nullptr); + scatter_nd_node.updates(nullptr); + scatter_nd_node.shape(nullptr); + ASSERT_EQ(nullptr, scatter_nd_node.indices()); + ASSERT_EQ(nullptr, scatter_nd_node.updates()); + ASSERT_EQ(nullptr, scatter_nd_node.shape()); +} + +TEST(CircleScatterNdTest, arity_NEG) +{ + luci::CircleScatterNd scatter_nd_node; + + ASSERT_NO_THROW(scatter_nd_node.arg(2)); + ASSERT_THROW(scatter_nd_node.arg(3), std::out_of_range); +} + +TEST(CircleScatterNdTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleScatterNd scatter_nd_node; + + TestVisitor tv; + ASSERT_THROW(scatter_nd_node.accept(&tv), std::exception); +} + +TEST(CircleScatterNdTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleScatterNd scatter_nd_node; + + TestVisitor tv; + ASSERT_THROW(scatter_nd_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSegmentSum.test.cpp b/compiler/luci/lang/src/Nodes/CircleSegmentSum.test.cpp new file mode 100644 index 000000000..90469b7e2 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSegmentSum.test.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSegmentSum.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleSegmentSumTest, constructor) +{ + luci::CircleSegmentSum segment_sum_node; + + ASSERT_EQ(luci::CircleDialect::get(), segment_sum_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SEGMENT_SUM, segment_sum_node.opcode()); + + ASSERT_EQ(nullptr, segment_sum_node.input()); + ASSERT_EQ(nullptr, segment_sum_node.segment_ids()); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSelect.test.cpp b/compiler/luci/lang/src/Nodes/CircleSelect.test.cpp new file mode 100644 index 000000000..7eeb538af --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSelect.test.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSelect.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleSelectTest, constructor) +{ + luci::CircleSelect select_node; + + ASSERT_EQ(luci::CircleDialect::get(), select_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SELECT, select_node.opcode()); + + ASSERT_EQ(nullptr, select_node.condition()); + ASSERT_EQ(nullptr, select_node.t()); + ASSERT_EQ(nullptr, select_node.e()); +} + +TEST(CircleSelectTest, input_NEG) +{ + luci::CircleSelect select_node; + luci::CircleSelect node; + + select_node.condition(&node); + select_node.t(&node); + select_node.e(&node); + ASSERT_NE(nullptr, select_node.condition()); + ASSERT_NE(nullptr, select_node.t()); + ASSERT_NE(nullptr, select_node.e()); + + select_node.condition(nullptr); + select_node.t(nullptr); + select_node.e(nullptr); + ASSERT_EQ(nullptr, select_node.condition()); + ASSERT_EQ(nullptr, select_node.t()); + ASSERT_EQ(nullptr, select_node.e()); +} + +TEST(CircleSelectTest, arity_NEG) +{ + luci::CircleSelect select_node; + + ASSERT_NO_THROW(select_node.arg(2)); + ASSERT_THROW(select_node.arg(3), std::out_of_range); +} + +TEST(CircleSelectTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSelect select_node; + + TestVisitor tv; + ASSERT_THROW(select_node.accept(&tv), std::exception); +} + +TEST(CircleSelectTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSelect select_node; + + TestVisitor tv; + ASSERT_THROW(select_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSelectV2.test.cpp b/compiler/luci/lang/src/Nodes/CircleSelectV2.test.cpp new file mode 100644 index 000000000..eea5fb83f --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSelectV2.test.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSelectV2.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleSelectV2Test, constructor) +{ + luci::CircleSelectV2 select_node; + + ASSERT_EQ(luci::CircleDialect::get(), select_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SELECT_V2, select_node.opcode()); + + ASSERT_EQ(nullptr, select_node.condition()); + ASSERT_EQ(nullptr, select_node.t()); + ASSERT_EQ(nullptr, select_node.e()); +} + +TEST(CircleSelectV2Test, input_NEG) +{ + luci::CircleSelectV2 select_v2_node; + luci::CircleSelectV2 node; + + select_v2_node.condition(&node); + select_v2_node.t(&node); + select_v2_node.e(&node); + ASSERT_NE(nullptr, select_v2_node.condition()); + ASSERT_NE(nullptr, select_v2_node.t()); + ASSERT_NE(nullptr, select_v2_node.e()); + + select_v2_node.condition(nullptr); + select_v2_node.t(nullptr); + select_v2_node.e(nullptr); + ASSERT_EQ(nullptr, select_v2_node.condition()); + ASSERT_EQ(nullptr, select_v2_node.t()); + ASSERT_EQ(nullptr, select_v2_node.e()); +} + +TEST(CircleSelectV2Test, arity_NEG) +{ + luci::CircleSelectV2 select_v2_node; + + ASSERT_NO_THROW(select_v2_node.arg(2)); + ASSERT_THROW(select_v2_node.arg(3), std::out_of_range); +} + +TEST(CircleSelectV2Test, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSelectV2 select_v2_node; + + TestVisitor tv; + ASSERT_THROW(select_v2_node.accept(&tv), std::exception); +} + +TEST(CircleSelectV2Test, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSelectV2 select_v2_node; + + TestVisitor tv; + ASSERT_THROW(select_v2_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleShape.test.cpp b/compiler/luci/lang/src/Nodes/CircleShape.test.cpp new file mode 100644 index 000000000..18271d2b2 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleShape.test.cpp @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleShape.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleShapeTest, constructor) +{ + luci::CircleShape shape_node; + + ASSERT_EQ(luci::CircleDialect::get(), shape_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SHAPE, shape_node.opcode()); + + ASSERT_EQ(nullptr, shape_node.input()); + ASSERT_EQ(loco::DataType::S32, shape_node.out_type()); +} + +TEST(CircleShapeTest, input_NEG) +{ + luci::CircleShape shape_node; + luci::CircleShape node; + + shape_node.input(&node); + ASSERT_NE(nullptr, shape_node.input()); + + shape_node.input(nullptr); + ASSERT_EQ(nullptr, shape_node.input()); + + shape_node.out_type(loco::DataType::U8); + ASSERT_NE(loco::DataType::S32, shape_node.out_type()); +} + +TEST(CircleShapeTest, arity_NEG) +{ + luci::CircleShape shape_node; + + ASSERT_NO_THROW(shape_node.arg(0)); + ASSERT_THROW(shape_node.arg(1), std::out_of_range); +} + +TEST(CircleShapeTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleShape shape_node; + + TestVisitor tv; + ASSERT_THROW(shape_node.accept(&tv), std::exception); +} + +TEST(CircleShapeTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleShape shape_node; + + TestVisitor tv; + ASSERT_THROW(shape_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSin.test.cpp b/compiler/luci/lang/src/Nodes/CircleSin.test.cpp new file mode 100644 index 000000000..e01932d4f --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSin.test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSin.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleSinTest, constructor) +{ + luci::CircleSin sin_node; + + ASSERT_EQ(luci::CircleDialect::get(), sin_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SIN, sin_node.opcode()); + + ASSERT_EQ(nullptr, sin_node.x()); +} + +TEST(CircleSinTest, input_NEG) +{ + luci::CircleSin sin_node; + luci::CircleSin node; + + sin_node.x(&node); + ASSERT_NE(nullptr, sin_node.x()); + + sin_node.x(nullptr); + ASSERT_EQ(nullptr, sin_node.x()); +} + +TEST(CircleSinTest, arity_NEG) +{ + luci::CircleSin sin_node; + + ASSERT_NO_THROW(sin_node.arg(0)); + ASSERT_THROW(sin_node.arg(1), std::out_of_range); +} + +TEST(CircleSinTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSin sin_node; + + TestVisitor tv; + ASSERT_THROW(sin_node.accept(&tv), std::exception); +} + +TEST(CircleSinTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSin sin_node; + + TestVisitor tv; + ASSERT_THROW(sin_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSlice.test.cpp b/compiler/luci/lang/src/Nodes/CircleSlice.test.cpp new file mode 100644 index 000000000..5563a34b9 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSlice.test.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSlice.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleSliceTest, constructor) +{ + luci::CircleSlice s_node; + + ASSERT_EQ(luci::CircleDialect::get(), s_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SLICE, s_node.opcode()); + + ASSERT_EQ(nullptr, s_node.input()); + ASSERT_EQ(nullptr, s_node.begin()); + ASSERT_EQ(nullptr, s_node.size()); +} + +TEST(CircleSliceTest, input_NEG) +{ + luci::CircleSlice s_node; + luci::CircleSlice node; + + s_node.input(&node); + s_node.begin(&node); + s_node.size(&node); + ASSERT_NE(nullptr, s_node.input()); + ASSERT_NE(nullptr, s_node.begin()); + ASSERT_NE(nullptr, s_node.size()); + + s_node.input(nullptr); + s_node.begin(nullptr); + s_node.size(nullptr); + ASSERT_EQ(nullptr, s_node.input()); + ASSERT_EQ(nullptr, s_node.begin()); + ASSERT_EQ(nullptr, s_node.size()); +} + +TEST(CircleSliceTest, arity_NEG) +{ + luci::CircleSlice s_node; + + ASSERT_NO_THROW(s_node.arg(2)); + ASSERT_THROW(s_node.arg(3), std::out_of_range); +} + +TEST(CircleSliceTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSlice s_node; + + TestVisitor tv; + ASSERT_THROW(s_node.accept(&tv), std::exception); +} + +TEST(CircleSliceTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSlice s_node; + + TestVisitor tv; + ASSERT_THROW(s_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSoftmax.test.cpp b/compiler/luci/lang/src/Nodes/CircleSoftmax.test.cpp index 7e994490c..b15c009f2 100644 --- a/compiler/luci/lang/src/Nodes/CircleSoftmax.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleSoftmax.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleSoftmax.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,8 +25,52 @@ TEST(CircleSoftmaxTest, constructor_P) { luci::CircleSoftmax softmax_node; - ASSERT_EQ(softmax_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(softmax_node.opcode(), luci::CircleOpcode::SOFTMAX); + ASSERT_EQ(luci::CircleDialect::get(), softmax_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SOFTMAX, softmax_node.opcode()); - ASSERT_EQ(softmax_node.logits(), nullptr); + ASSERT_EQ(nullptr, softmax_node.logits()); +} + +TEST(CircleSoftmaxTest, input_NEG) +{ + luci::CircleSoftmax softmax_node; + luci::CircleSoftmax node; + + softmax_node.logits(&node); + ASSERT_NE(nullptr, softmax_node.logits()); + + softmax_node.logits(nullptr); + ASSERT_EQ(nullptr, softmax_node.logits()); +} + +TEST(CircleSoftmaxTest, arity_NEG) +{ + luci::CircleSoftmax softmax_node; + + ASSERT_NO_THROW(softmax_node.arg(0)); + ASSERT_THROW(softmax_node.arg(1), std::out_of_range); +} + +TEST(CircleSoftmaxTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSoftmax softmax_node; + + TestVisitor tv; + ASSERT_THROW(softmax_node.accept(&tv), std::exception); +} + +TEST(CircleSoftmaxTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSoftmax softmax_node; + + TestVisitor tv; + ASSERT_THROW(softmax_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleSpaceToBatchND.test.cpp b/compiler/luci/lang/src/Nodes/CircleSpaceToBatchND.test.cpp new file mode 100644 index 000000000..8b4ac8f2b --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSpaceToBatchND.test.cpp @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSpaceToBatchND.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleSpaceToBatchNDTest, constructor) +{ + luci::CircleSpaceToBatchND stb_node; + + ASSERT_EQ(luci::CircleDialect::get(), stb_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SPACE_TO_BATCH_ND, stb_node.opcode()); + + ASSERT_EQ(nullptr, stb_node.input()); + ASSERT_EQ(nullptr, stb_node.block_shape()); + ASSERT_EQ(nullptr, stb_node.paddings()); +} + +TEST(CircleSpaceToBatchNDTest, input_NEG) +{ + luci::CircleSpaceToBatchND stb_node; + luci::CircleSpaceToBatchND node; + + stb_node.input(&node); + stb_node.block_shape(&node); + stb_node.paddings(&node); + ASSERT_NE(nullptr, stb_node.input()); + ASSERT_NE(nullptr, stb_node.block_shape()); + ASSERT_NE(nullptr, stb_node.paddings()); + + stb_node.input(nullptr); + stb_node.block_shape(nullptr); + stb_node.paddings(nullptr); + ASSERT_EQ(nullptr, stb_node.input()); + ASSERT_EQ(nullptr, stb_node.block_shape()); + ASSERT_EQ(nullptr, stb_node.paddings()); +} + +TEST(CircleSpaceToBatchNDTest, arity_NEG) +{ + luci::CircleSpaceToBatchND stb_node; + + ASSERT_NO_THROW(stb_node.arg(2)); + ASSERT_THROW(stb_node.arg(3), std::out_of_range); +} + +TEST(CircleSpaceToBatchNDTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSpaceToBatchND stb_node; + + TestVisitor tv; + ASSERT_THROW(stb_node.accept(&tv), std::exception); +} + +TEST(CircleSpaceToBatchNDTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSpaceToBatchND stb_node; + + TestVisitor tv; + ASSERT_THROW(stb_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSpaceToDepth.test.cpp b/compiler/luci/lang/src/Nodes/CircleSpaceToDepth.test.cpp new file mode 100644 index 000000000..d49a2ce85 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSpaceToDepth.test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSpaceToDepth.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleSpaceToDepthTest, constructor) +{ + luci::CircleSpaceToDepth std_node; + + ASSERT_EQ(luci::CircleDialect::get(), std_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SPACE_TO_DEPTH, std_node.opcode()); + + ASSERT_EQ(nullptr, std_node.input()); +} + +TEST(CircleSpaceToDepthTest, input_NEG) +{ + luci::CircleSpaceToDepth std_node; + luci::CircleSpaceToDepth node; + + std_node.input(&node); + ASSERT_NE(nullptr, std_node.input()); + + std_node.input(nullptr); + ASSERT_EQ(nullptr, std_node.input()); +} + +TEST(CircleSpaceToDepthTest, arity_NEG) +{ + luci::CircleSpaceToDepth std_node; + + ASSERT_NO_THROW(std_node.arg(0)); + ASSERT_THROW(std_node.arg(1), std::out_of_range); +} + +TEST(CircleSpaceToDepthTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSpaceToDepth std_node; + + TestVisitor tv; + ASSERT_THROW(std_node.accept(&tv), std::exception); +} + +TEST(CircleSpaceToDepthTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSpaceToDepth std_node; + + TestVisitor tv; + ASSERT_THROW(std_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSparseToDense.test.cpp b/compiler/luci/lang/src/Nodes/CircleSparseToDense.test.cpp new file mode 100644 index 000000000..de3cf6e9a --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSparseToDense.test.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSparseToDense.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleSparseToDenseTest, constructor) +{ + luci::CircleSparseToDense stb_node; + + ASSERT_EQ(luci::CircleDialect::get(), stb_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SPARSE_TO_DENSE, stb_node.opcode()); + + ASSERT_EQ(nullptr, stb_node.indices()); + ASSERT_EQ(nullptr, stb_node.output_shape()); + ASSERT_EQ(nullptr, stb_node.values()); + ASSERT_EQ(nullptr, stb_node.default_value()); + + ASSERT_EQ(true, stb_node.validate_indices()); +} + +TEST(CircleSparseToDenseTest, input_NEG) +{ + luci::CircleSparseToDense stb_node; + luci::CircleSparseToDense node; + + stb_node.indices(&node); + stb_node.output_shape(&node); + stb_node.values(&node); + stb_node.default_value(&node); + ASSERT_NE(nullptr, stb_node.indices()); + ASSERT_NE(nullptr, stb_node.output_shape()); + ASSERT_NE(nullptr, stb_node.values()); + ASSERT_NE(nullptr, stb_node.default_value()); + + stb_node.indices(nullptr); + stb_node.output_shape(nullptr); + stb_node.values(nullptr); + stb_node.default_value(nullptr); + ASSERT_EQ(nullptr, stb_node.indices()); + ASSERT_EQ(nullptr, stb_node.output_shape()); + ASSERT_EQ(nullptr, stb_node.values()); + ASSERT_EQ(nullptr, stb_node.default_value()); +} + +TEST(CircleSparseToDenseTest, arity_NEG) +{ + luci::CircleSparseToDense stb_node; + + ASSERT_NO_THROW(stb_node.arg(3)); + ASSERT_THROW(stb_node.arg(4), std::out_of_range); +} + +TEST(CircleSparseToDenseTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSparseToDense stb_node; + + TestVisitor tv; + ASSERT_THROW(stb_node.accept(&tv), std::exception); +} + +TEST(CircleSparseToDenseTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSparseToDense stb_node; + + TestVisitor tv; + ASSERT_THROW(stb_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSplit.test.cpp b/compiler/luci/lang/src/Nodes/CircleSplit.test.cpp new file mode 100644 index 000000000..acf8c4410 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSplit.test.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSplit.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleSplitTest, constructor) +{ + luci::CircleSplit split_node; + + ASSERT_EQ(luci::CircleDialect::get(), split_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SPLIT, split_node.opcode()); + + ASSERT_EQ(nullptr, split_node.input()); + ASSERT_EQ(nullptr, split_node.split_dim()); + ASSERT_EQ(0, split_node.num_split()); +} + +TEST(CircleSplitTest, input_NEG) +{ + luci::CircleSplit split_node; + luci::CircleSplit node; + + split_node.input(&node); + split_node.split_dim(&node); + ASSERT_NE(nullptr, split_node.input()); + ASSERT_NE(nullptr, split_node.split_dim()); + + split_node.input(nullptr); + split_node.split_dim(nullptr); + ASSERT_EQ(nullptr, split_node.input()); + ASSERT_EQ(nullptr, split_node.split_dim()); + + split_node.num_split(100); + ASSERT_NE(0, split_node.num_split()); +} + +TEST(CircleSplitTest, arity_NEG) +{ + luci::CircleSplit split_node; + + ASSERT_NO_THROW(split_node.arg(1)); + ASSERT_THROW(split_node.arg(2), std::out_of_range); +} + +TEST(CircleSplitTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSplit split_node; + + TestVisitor tv; + ASSERT_THROW(split_node.accept(&tv), std::exception); +} + +TEST(CircleSplitTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSplit split_node; + + TestVisitor tv; + ASSERT_THROW(split_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSplitOut.test.cpp b/compiler/luci/lang/src/Nodes/CircleSplitOut.test.cpp new file mode 100644 index 000000000..e93715825 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSplitOut.test.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSplitOut.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleSplitOutTest, constructor) +{ + luci::CircleSplitOut vout_node; + + ASSERT_EQ(luci::CircleDialect::get(), vout_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::CIRCLESPLITOUT, vout_node.opcode()); + + ASSERT_EQ(nullptr, vout_node.input()); + ASSERT_EQ(-1, vout_node.index()); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSplitV.test.cpp b/compiler/luci/lang/src/Nodes/CircleSplitV.test.cpp new file mode 100644 index 000000000..1f01608a3 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSplitV.test.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSplitV.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleSplitVTest, constructor) +{ + luci::CircleSplitV splitv_node; + + ASSERT_EQ(luci::CircleDialect::get(), splitv_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SPLIT_V, splitv_node.opcode()); + + ASSERT_EQ(nullptr, splitv_node.input()); + ASSERT_EQ(nullptr, splitv_node.size_splits()); + ASSERT_EQ(nullptr, splitv_node.split_dim()); + ASSERT_EQ(0, splitv_node.num_split()); +} + +TEST(CircleSplitVTest, input_NEG) +{ + luci::CircleSplitV splitv_node; + luci::CircleSplitV node; + + splitv_node.input(&node); + splitv_node.size_splits(&node); + splitv_node.split_dim(&node); + ASSERT_NE(nullptr, splitv_node.input()); + ASSERT_NE(nullptr, splitv_node.size_splits()); + ASSERT_NE(nullptr, splitv_node.split_dim()); + + splitv_node.input(nullptr); + splitv_node.size_splits(nullptr); + splitv_node.split_dim(nullptr); + ASSERT_EQ(nullptr, splitv_node.input()); + ASSERT_EQ(nullptr, splitv_node.size_splits()); + ASSERT_EQ(nullptr, splitv_node.split_dim()); + + splitv_node.num_split(100); + ASSERT_NE(0, splitv_node.num_split()); +} + +TEST(CircleSplitVTest, arity_NEG) +{ + luci::CircleSplitV splitv_node; + + ASSERT_NO_THROW(splitv_node.arg(2)); + ASSERT_THROW(splitv_node.arg(3), std::out_of_range); +} + +TEST(CircleSplitVTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSplitV splitv_node; + + TestVisitor tv; + ASSERT_THROW(splitv_node.accept(&tv), std::exception); +} + +TEST(CircleSplitVTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSplitV splitv_node; + + TestVisitor tv; + ASSERT_THROW(splitv_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSplitVOut.test.cpp b/compiler/luci/lang/src/Nodes/CircleSplitVOut.test.cpp new file mode 100644 index 000000000..2a4fe3267 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSplitVOut.test.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSplitVOut.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleSplitVOutTest, constructor) +{ + luci::CircleSplitVOut vout_node; + + ASSERT_EQ(luci::CircleDialect::get(), vout_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::CIRCLESPLITVOUT, vout_node.opcode()); + + ASSERT_EQ(nullptr, vout_node.input()); + ASSERT_EQ(-1, vout_node.index()); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSqrt.test.cpp b/compiler/luci/lang/src/Nodes/CircleSqrt.test.cpp index 6cfb3bc94..f4222fd67 100644 --- a/compiler/luci/lang/src/Nodes/CircleSqrt.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleSqrt.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleSqrt.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,8 +25,52 @@ TEST(CircleSqrtTest, constructor_P) { luci::CircleSqrt sqrt_node; - ASSERT_EQ(sqrt_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(sqrt_node.opcode(), luci::CircleOpcode::SQRT); + ASSERT_EQ(luci::CircleDialect::get(), sqrt_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SQRT, sqrt_node.opcode()); - ASSERT_EQ(sqrt_node.x(), nullptr); + ASSERT_EQ(nullptr, sqrt_node.x()); +} + +TEST(CircleSqrtTest, input_NEG) +{ + luci::CircleSqrt sqrt_node; + luci::CircleSqrt node; + + sqrt_node.x(&node); + ASSERT_NE(nullptr, sqrt_node.x()); + + sqrt_node.x(nullptr); + ASSERT_EQ(nullptr, sqrt_node.x()); +} + +TEST(CircleSqrtTest, arity_NEG) +{ + luci::CircleSqrt sqrt_node; + + ASSERT_NO_THROW(sqrt_node.arg(0)); + ASSERT_THROW(sqrt_node.arg(1), std::out_of_range); +} + +TEST(CircleSqrtTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSqrt sqrt_node; + + TestVisitor tv; + ASSERT_THROW(sqrt_node.accept(&tv), std::exception); +} + +TEST(CircleSqrtTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSqrt sqrt_node; + + TestVisitor tv; + ASSERT_THROW(sqrt_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleSquare.test.cpp b/compiler/luci/lang/src/Nodes/CircleSquare.test.cpp new file mode 100644 index 000000000..3b0a86eed --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSquare.test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSquare.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleSquareTest, constructor_P) +{ + luci::CircleSquare square_node; + + ASSERT_EQ(luci::CircleDialect::get(), square_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SQUARE, square_node.opcode()); + + ASSERT_EQ(nullptr, square_node.x()); +} + +TEST(CircleSquareTest, input_NEG) +{ + luci::CircleSquare square_node; + luci::CircleSquare node; + + square_node.x(&node); + ASSERT_NE(nullptr, square_node.x()); + + square_node.x(nullptr); + ASSERT_EQ(nullptr, square_node.x()); +} + +TEST(CircleSquareTest, arity_NEG) +{ + luci::CircleSquare square_node; + + ASSERT_NO_THROW(square_node.arg(0)); + ASSERT_THROW(square_node.arg(1), std::out_of_range); +} + +TEST(CircleSquareTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSquare square_node; + + TestVisitor tv; + ASSERT_THROW(square_node.accept(&tv), std::exception); +} + +TEST(CircleSquareTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSquare square_node; + + TestVisitor tv; + ASSERT_THROW(square_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSquaredDifference.test.cpp b/compiler/luci/lang/src/Nodes/CircleSquaredDifference.test.cpp index 71df189b9..ea632218b 100644 --- a/compiler/luci/lang/src/Nodes/CircleSquaredDifference.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleSquaredDifference.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleSquaredDifference.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,9 +25,57 @@ TEST(CircleSquaredDifferenceTest, constructor_P) { luci::CircleSquaredDifference sd_node; - ASSERT_EQ(sd_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(sd_node.opcode(), luci::CircleOpcode::SQUARED_DIFFERENCE); + ASSERT_EQ(luci::CircleDialect::get(), sd_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SQUARED_DIFFERENCE, sd_node.opcode()); - ASSERT_EQ(sd_node.x(), nullptr); - ASSERT_EQ(sd_node.y(), nullptr); + ASSERT_EQ(nullptr, sd_node.x()); + ASSERT_EQ(nullptr, sd_node.y()); +} + +TEST(CircleSquaredDifferenceTest, input_NEG) +{ + luci::CircleSquaredDifference sd_node; + luci::CircleSquaredDifference node; + + sd_node.x(&node); + sd_node.y(&node); + ASSERT_NE(nullptr, sd_node.x()); + ASSERT_NE(nullptr, sd_node.y()); + + sd_node.x(nullptr); + sd_node.y(nullptr); + ASSERT_EQ(nullptr, sd_node.x()); + ASSERT_EQ(nullptr, sd_node.y()); +} + +TEST(CircleSquaredDifferenceTest, arity_NEG) +{ + luci::CircleSquaredDifference sd_node; + + ASSERT_NO_THROW(sd_node.arg(1)); + ASSERT_THROW(sd_node.arg(2), std::out_of_range); +} + +TEST(CircleSquaredDifferenceTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSquaredDifference sd_node; + + TestVisitor tv; + ASSERT_THROW(sd_node.accept(&tv), std::exception); +} + +TEST(CircleSquaredDifferenceTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSquaredDifference sd_node; + + TestVisitor tv; + ASSERT_THROW(sd_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleSqueeze.test.cpp b/compiler/luci/lang/src/Nodes/CircleSqueeze.test.cpp new file mode 100644 index 000000000..6dc3d03cd --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSqueeze.test.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSqueeze.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleSqueezeTest, constructor_P) +{ + luci::CircleSqueeze squeeze; + + ASSERT_EQ(luci::CircleDialect::get(), squeeze.dialect()); + ASSERT_EQ(luci::CircleOpcode::SQUEEZE, squeeze.opcode()); + + ASSERT_EQ(nullptr, squeeze.input()); + ASSERT_EQ(0, squeeze.squeeze_dims().size()); +} + +TEST(CircleSqueezeTest, squeeze_dims) +{ + luci::CircleSqueeze squeeze; + + squeeze.squeeze_dims({1, 2}); + + ASSERT_EQ(1, squeeze.squeeze_dims().at(0)); + ASSERT_EQ(2, squeeze.squeeze_dims().at(1)); +} + +TEST(CircleSqueezeTest, input_NEG) +{ + luci::CircleSqueeze squeeze_node; + luci::CircleSqueeze node; + + squeeze_node.input(&node); + ASSERT_NE(nullptr, squeeze_node.input()); + + squeeze_node.input(nullptr); + ASSERT_EQ(nullptr, squeeze_node.input()); +} + +TEST(CircleSqueezeTest, arity_NEG) +{ + luci::CircleSqueeze squeeze_node; + + ASSERT_NO_THROW(squeeze_node.arg(0)); + ASSERT_THROW(squeeze_node.arg(1), std::out_of_range); +} + +TEST(CircleSqueezeTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSqueeze squeeze_node; + + TestVisitor tv; + ASSERT_THROW(squeeze_node.accept(&tv), std::exception); +} + +TEST(CircleSqueezeTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSqueeze squeeze_node; + + TestVisitor tv; + ASSERT_THROW(squeeze_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleStridedSlice.test.cpp b/compiler/luci/lang/src/Nodes/CircleStridedSlice.test.cpp new file mode 100644 index 000000000..1982e7b38 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleStridedSlice.test.cpp @@ -0,0 +1,108 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleStridedSlice.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleStridedSliceTest, constructor) +{ + luci::CircleStridedSlice ss_node; + + ASSERT_EQ(luci::CircleDialect::get(), ss_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::STRIDED_SLICE, ss_node.opcode()); + + ASSERT_EQ(nullptr, ss_node.input()); + ASSERT_EQ(nullptr, ss_node.begin()); + ASSERT_EQ(nullptr, ss_node.end()); + ASSERT_EQ(nullptr, ss_node.strides()); + + ASSERT_EQ(0, ss_node.begin_mask()); + ASSERT_EQ(0, ss_node.end_mask()); + ASSERT_EQ(0, ss_node.ellipsis_mask()); + ASSERT_EQ(0, ss_node.new_axis_mask()); + ASSERT_EQ(0, ss_node.shrink_axis_mask()); +} + +TEST(CircleStridedSliceTest, input_NEG) +{ + luci::CircleStridedSlice ss_node; + luci::CircleStridedSlice node; + + ss_node.input(&node); + ss_node.begin(&node); + ss_node.end(&node); + ss_node.strides(&node); + ASSERT_NE(nullptr, ss_node.input()); + ASSERT_NE(nullptr, ss_node.begin()); + ASSERT_NE(nullptr, ss_node.end()); + ASSERT_NE(nullptr, ss_node.strides()); + + ss_node.input(nullptr); + ss_node.begin(nullptr); + ss_node.end(nullptr); + ss_node.strides(nullptr); + ASSERT_EQ(nullptr, ss_node.input()); + ASSERT_EQ(nullptr, ss_node.begin()); + ASSERT_EQ(nullptr, ss_node.end()); + ASSERT_EQ(nullptr, ss_node.strides()); + + ss_node.begin_mask(1); + ss_node.end_mask(1); + ss_node.ellipsis_mask(1); + ss_node.new_axis_mask(1); + ss_node.shrink_axis_mask(1); + ASSERT_NE(0, ss_node.begin_mask()); + ASSERT_NE(0, ss_node.end_mask()); + ASSERT_NE(0, ss_node.ellipsis_mask()); + ASSERT_NE(0, ss_node.new_axis_mask()); + ASSERT_NE(0, ss_node.shrink_axis_mask()); +} + +TEST(CircleStridedSliceTest, arity_NEG) +{ + luci::CircleStridedSlice ss_node; + + ASSERT_NO_THROW(ss_node.arg(3)); + ASSERT_THROW(ss_node.arg(4), std::out_of_range); +} + +TEST(CircleStridedSliceTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleStridedSlice ss_node; + + TestVisitor tv; + ASSERT_THROW(ss_node.accept(&tv), std::exception); +} + +TEST(CircleStridedSliceTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleStridedSlice ss_node; + + TestVisitor tv; + ASSERT_THROW(ss_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleSub.test.cpp b/compiler/luci/lang/src/Nodes/CircleSub.test.cpp index ebb29446a..92c674bd0 100644 --- a/compiler/luci/lang/src/Nodes/CircleSub.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleSub.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleSub.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,9 +25,57 @@ TEST(CircleSubTest, constructor_P) { luci::CircleSub sub_node; - ASSERT_EQ(sub_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(sub_node.opcode(), luci::CircleOpcode::SUB); + ASSERT_EQ(luci::CircleDialect::get(), sub_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SUB, sub_node.opcode()); - ASSERT_EQ(sub_node.x(), nullptr); - ASSERT_EQ(sub_node.y(), nullptr); + ASSERT_EQ(nullptr, sub_node.x()); + ASSERT_EQ(nullptr, sub_node.y()); +} + +TEST(CircleSubTest, input_NEG) +{ + luci::CircleSub sub_node; + luci::CircleSub node; + + sub_node.x(&node); + sub_node.y(&node); + ASSERT_NE(nullptr, sub_node.x()); + ASSERT_NE(nullptr, sub_node.y()); + + sub_node.x(nullptr); + sub_node.y(nullptr); + ASSERT_EQ(nullptr, sub_node.x()); + ASSERT_EQ(nullptr, sub_node.y()); +} + +TEST(CircleSubTest, arity_NEG) +{ + luci::CircleSub sub_node; + + ASSERT_NO_THROW(sub_node.arg(1)); + ASSERT_THROW(sub_node.arg(2), std::out_of_range); +} + +TEST(CircleSubTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSub sub_node; + + TestVisitor tv; + ASSERT_THROW(sub_node.accept(&tv), std::exception); +} + +TEST(CircleSubTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSub sub_node; + + TestVisitor tv; + ASSERT_THROW(sub_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleSum.test.cpp b/compiler/luci/lang/src/Nodes/CircleSum.test.cpp new file mode 100644 index 000000000..84b51d671 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleSum.test.cpp @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleSum.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleSumTest, constructor_P) +{ + luci::CircleSum sum_node; + + ASSERT_EQ(luci::CircleDialect::get(), sum_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::SUM, sum_node.opcode()); + + ASSERT_EQ(nullptr, sum_node.input()); + ASSERT_EQ(nullptr, sum_node.reduction_indices()); + ASSERT_EQ(false, sum_node.keep_dims()); +} + +TEST(CircleSumTest, input_NEG) +{ + luci::CircleSum sum_node; + luci::CircleSum node; + + sum_node.input(&node); + sum_node.reduction_indices(&node); + ASSERT_NE(nullptr, sum_node.input()); + ASSERT_NE(nullptr, sum_node.reduction_indices()); + + sum_node.input(nullptr); + sum_node.reduction_indices(nullptr); + ASSERT_EQ(nullptr, sum_node.input()); + ASSERT_EQ(nullptr, sum_node.reduction_indices()); + + sum_node.keep_dims(true); + ASSERT_TRUE(sum_node.keep_dims()); +} + +TEST(CircleSumTest, arity_NEG) +{ + luci::CircleSum sum_node; + + ASSERT_NO_THROW(sum_node.arg(1)); + ASSERT_THROW(sum_node.arg(2), std::out_of_range); +} + +TEST(CircleSumTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleSum sum_node; + + TestVisitor tv; + ASSERT_THROW(sum_node.accept(&tv), std::exception); +} + +TEST(CircleSumTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleSum sum_node; + + TestVisitor tv; + ASSERT_THROW(sum_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleTanh.test.cpp b/compiler/luci/lang/src/Nodes/CircleTanh.test.cpp new file mode 100644 index 000000000..257ecb24d --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleTanh.test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleTanh.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleTanhTest, constructor) +{ + luci::CircleTanh tanh_node; + + ASSERT_EQ(luci::CircleDialect::get(), tanh_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::TANH, tanh_node.opcode()); + + ASSERT_EQ(nullptr, tanh_node.x()); +} + +TEST(CircleTanhTest, input_NEG) +{ + luci::CircleTanh neg_node; + luci::CircleTanh node; + + neg_node.x(&node); + ASSERT_NE(nullptr, neg_node.x()); + + neg_node.x(nullptr); + ASSERT_EQ(nullptr, neg_node.x()); +} + +TEST(CircleTanhTest, arity_NEG) +{ + luci::CircleTanh neg_node; + + ASSERT_NO_THROW(neg_node.arg(0)); + ASSERT_THROW(neg_node.arg(1), std::out_of_range); +} + +TEST(CircleTanhTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleTanh neg_node; + + TestVisitor tv; + ASSERT_THROW(neg_node.accept(&tv), std::exception); +} + +TEST(CircleTanhTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleTanh neg_node; + + TestVisitor tv; + ASSERT_THROW(neg_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleTile.test.cpp b/compiler/luci/lang/src/Nodes/CircleTile.test.cpp new file mode 100644 index 000000000..1695165cc --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleTile.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleTile.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleTileTest, constructor) +{ + luci::CircleTile tile_node; + + ASSERT_EQ(luci::CircleDialect::get(), tile_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::TILE, tile_node.opcode()); + + ASSERT_EQ(nullptr, tile_node.input()); + ASSERT_EQ(nullptr, tile_node.multiples()); +} + +TEST(CircleTileTest, input_NEG) +{ + luci::CircleTile tile_node; + luci::CircleTile node; + + tile_node.input(&node); + tile_node.multiples(&node); + ASSERT_NE(nullptr, tile_node.input()); + ASSERT_NE(nullptr, tile_node.multiples()); + + tile_node.input(nullptr); + tile_node.multiples(nullptr); + ASSERT_EQ(nullptr, tile_node.input()); + ASSERT_EQ(nullptr, tile_node.multiples()); +} + +TEST(CircleTileTest, arity_NEG) +{ + luci::CircleTile tile_node; + + ASSERT_NO_THROW(tile_node.arg(1)); + ASSERT_THROW(tile_node.arg(2), std::out_of_range); +} + +TEST(CircleTileTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleTile tile_node; + + TestVisitor tv; + ASSERT_THROW(tile_node.accept(&tv), std::exception); +} + +TEST(CircleTileTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleTile tile_node; + + TestVisitor tv; + ASSERT_THROW(tile_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleTopKV2.test.cpp b/compiler/luci/lang/src/Nodes/CircleTopKV2.test.cpp new file mode 100644 index 000000000..31478d3af --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleTopKV2.test.cpp @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleTopKV2.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleTopKV2Test, constructor) +{ + luci::CircleTopKV2 topkv2_node; + + ASSERT_EQ(luci::CircleDialect::get(), topkv2_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::TOPK_V2, topkv2_node.opcode()); + + ASSERT_EQ(nullptr, topkv2_node.input()); + ASSERT_EQ(nullptr, topkv2_node.k()); +} + +TEST(CircleTopKV2Test, input_NEG) +{ + luci::CircleTopKV2 topkv2_node; + luci::CircleTopKV2 node; + + topkv2_node.input(&node); + topkv2_node.k(&node); + ASSERT_NE(nullptr, topkv2_node.input()); + ASSERT_NE(nullptr, topkv2_node.k()); + + topkv2_node.input(nullptr); + topkv2_node.k(nullptr); + ASSERT_EQ(nullptr, topkv2_node.input()); + ASSERT_EQ(nullptr, topkv2_node.k()); +} + +TEST(CircleTopKV2Test, arity_NEG) +{ + luci::CircleTopKV2 topkv2_node; + + ASSERT_NO_THROW(topkv2_node.arg(1)); + ASSERT_THROW(topkv2_node.arg(2), std::out_of_range); +} + +TEST(CircleTopKV2Test, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleTopKV2 topkv2_node; + + TestVisitor tv; + ASSERT_THROW(topkv2_node.accept(&tv), std::exception); +} + +TEST(CircleTopKV2Test, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleTopKV2 topkv2_node; + + TestVisitor tv; + ASSERT_THROW(topkv2_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleTopKV2Out.test.cpp b/compiler/luci/lang/src/Nodes/CircleTopKV2Out.test.cpp new file mode 100644 index 000000000..d0835a27d --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleTopKV2Out.test.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleTopKV2Out.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleTopKV2OutTest, constructor) +{ + luci::CircleTopKV2Out topout_node; + + ASSERT_EQ(luci::CircleDialect::get(), topout_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::CIRCLETOPKV2OUT, topout_node.opcode()); + + ASSERT_EQ(nullptr, topout_node.input()); + ASSERT_EQ(-1, topout_node.index()); +} diff --git a/compiler/luci/lang/src/Nodes/CircleTranspose.test.cpp b/compiler/luci/lang/src/Nodes/CircleTranspose.test.cpp index 7233869e6..f4db3f37b 100644 --- a/compiler/luci/lang/src/Nodes/CircleTranspose.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleTranspose.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleTranspose.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,9 +25,57 @@ TEST(CircleTransposeTest, constructor_P) { luci::CircleTranspose tr_node; - ASSERT_EQ(tr_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(tr_node.opcode(), luci::CircleOpcode::TRANSPOSE); + ASSERT_EQ(luci::CircleDialect::get(), tr_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::TRANSPOSE, tr_node.opcode()); - ASSERT_EQ(tr_node.a(), nullptr); - ASSERT_EQ(tr_node.perm(), nullptr); + ASSERT_EQ(nullptr, tr_node.a()); + ASSERT_EQ(nullptr, tr_node.perm()); +} + +TEST(CircleTransposeTest, input_NEG) +{ + luci::CircleTranspose tr_node; + luci::CircleTranspose node; + + tr_node.a(&node); + tr_node.perm(&node); + ASSERT_NE(nullptr, tr_node.a()); + ASSERT_NE(nullptr, tr_node.perm()); + + tr_node.a(nullptr); + tr_node.perm(nullptr); + ASSERT_EQ(nullptr, tr_node.a()); + ASSERT_EQ(nullptr, tr_node.perm()); +} + +TEST(CircleTransposeTest, arity_NEG) +{ + luci::CircleTranspose tr_node; + + ASSERT_NO_THROW(tr_node.arg(1)); + ASSERT_THROW(tr_node.arg(2), std::out_of_range); +} + +TEST(CircleTransposeTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleTranspose tr_node; + + TestVisitor tv; + ASSERT_THROW(tr_node.accept(&tv), std::exception); +} + +TEST(CircleTransposeTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleTranspose tr_node; + + TestVisitor tv; + ASSERT_THROW(tr_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleTransposeConv.test.cpp b/compiler/luci/lang/src/Nodes/CircleTransposeConv.test.cpp index 9615082d9..429169744 100644 --- a/compiler/luci/lang/src/Nodes/CircleTransposeConv.test.cpp +++ b/compiler/luci/lang/src/Nodes/CircleTransposeConv.test.cpp @@ -17,6 +17,7 @@ #include "luci/IR/Nodes/CircleTransposeConv.h" #include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" #include <gtest/gtest.h> @@ -24,10 +25,74 @@ TEST(CircleTransposeConvTest, constructor_P) { luci::CircleTransposeConv trc_node; - ASSERT_EQ(trc_node.dialect(), luci::CircleDialect::get()); - ASSERT_EQ(trc_node.opcode(), luci::CircleOpcode::TRANSPOSE_CONV); + ASSERT_EQ(luci::CircleDialect::get(), trc_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::TRANSPOSE_CONV, trc_node.opcode()); - ASSERT_EQ(trc_node.inputSizes(), nullptr); - ASSERT_EQ(trc_node.filter(), nullptr); - ASSERT_EQ(trc_node.outBackprop(), nullptr); + ASSERT_EQ(nullptr, trc_node.inputSizes()); + ASSERT_EQ(nullptr, trc_node.filter()); + ASSERT_EQ(nullptr, trc_node.outBackprop()); + + ASSERT_EQ(luci::Padding::UNDEFINED, trc_node.padding()); + ASSERT_EQ(1, trc_node.stride()->h()); + ASSERT_EQ(1, trc_node.stride()->w()); +} + +TEST(CircleTransposeConvTest, input_NEG) +{ + luci::CircleTransposeConv trc_node; + luci::CircleTransposeConv node; + + trc_node.inputSizes(&node); + trc_node.filter(&node); + trc_node.outBackprop(&node); + ASSERT_NE(nullptr, trc_node.inputSizes()); + ASSERT_NE(nullptr, trc_node.filter()); + ASSERT_NE(nullptr, trc_node.outBackprop()); + + trc_node.inputSizes(nullptr); + trc_node.filter(nullptr); + trc_node.outBackprop(nullptr); + ASSERT_EQ(nullptr, trc_node.inputSizes()); + ASSERT_EQ(nullptr, trc_node.filter()); + ASSERT_EQ(nullptr, trc_node.outBackprop()); + + trc_node.padding(luci::Padding::SAME); + ASSERT_NE(luci::Padding::UNDEFINED, trc_node.padding()); + + trc_node.stride()->h(2); + trc_node.stride()->w(2); + ASSERT_EQ(2, trc_node.stride()->h()); + ASSERT_EQ(2, trc_node.stride()->w()); +} + +TEST(CircleTransposeConvTest, arity_NEG) +{ + luci::CircleTransposeConv trc_node; + + ASSERT_NO_THROW(trc_node.arg(2)); + ASSERT_THROW(trc_node.arg(3), std::out_of_range); +} + +TEST(CircleTransposeConvTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleTransposeConv trc_node; + + TestVisitor tv; + ASSERT_THROW(trc_node.accept(&tv), std::exception); +} + +TEST(CircleTransposeConvTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleTransposeConv trc_node; + + TestVisitor tv; + ASSERT_THROW(trc_node.accept(&tv), std::exception); } diff --git a/compiler/luci/lang/src/Nodes/CircleUnpack.test.cpp b/compiler/luci/lang/src/Nodes/CircleUnpack.test.cpp new file mode 100644 index 000000000..4323028e4 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleUnpack.test.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleUnpack.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleUnpackTest, constructor) +{ + luci::CircleUnpack unpack_node; + + ASSERT_EQ(luci::CircleDialect::get(), unpack_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::UNPACK, unpack_node.opcode()); + + ASSERT_EQ(nullptr, unpack_node.value()); + ASSERT_EQ(0, unpack_node.num()); + ASSERT_EQ(0, unpack_node.axis()); +} + +TEST(CircleUnpackTest, input_NEG) +{ + luci::CircleUnpack unpack_node; + luci::CircleUnpack node; + + unpack_node.value(&node); + ASSERT_NE(nullptr, unpack_node.value()); + + unpack_node.value(nullptr); + ASSERT_EQ(nullptr, unpack_node.value()); + + unpack_node.num(1); + unpack_node.axis(1); + ASSERT_NE(0, unpack_node.num()); + ASSERT_NE(0, unpack_node.axis()); +} + +TEST(CircleUnpackTest, arity_NEG) +{ + luci::CircleUnpack unpack_node; + + ASSERT_NO_THROW(unpack_node.arg(0)); + ASSERT_THROW(unpack_node.arg(1), std::out_of_range); +} + +TEST(CircleUnpackTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleUnpack unpack_node; + + TestVisitor tv; + ASSERT_THROW(unpack_node.accept(&tv), std::exception); +} + +TEST(CircleUnpackTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleUnpack unpack_node; + + TestVisitor tv; + ASSERT_THROW(unpack_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleUnpackOut.test.cpp b/compiler/luci/lang/src/Nodes/CircleUnpackOut.test.cpp new file mode 100644 index 000000000..7b8a41bf7 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleUnpackOut.test.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleUnpackOut.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleUnpackOutTest, constructor) +{ + luci::CircleUnpackOut unpackout_node; + + ASSERT_EQ(luci::CircleDialect::get(), unpackout_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::CIRCLEUNPACKOUT, unpackout_node.opcode()); + + ASSERT_EQ(nullptr, unpackout_node.input()); + ASSERT_EQ(0, unpackout_node.index()); +} diff --git a/compiler/luci/lang/src/Nodes/CircleWhere.test.cpp b/compiler/luci/lang/src/Nodes/CircleWhere.test.cpp new file mode 100644 index 000000000..287eda460 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleWhere.test.cpp @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleWhere.h" +#include "luci/IR/Nodes/CircleInput.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleWhereTest, constructor_P) +{ + luci::CircleWhere where_node; + + ASSERT_EQ(luci::CircleDialect::get(), where_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::WHERE, where_node.opcode()); + + ASSERT_EQ(1, where_node.arity()); + ASSERT_EQ(nullptr, where_node.condition()); +} diff --git a/compiler/luci/lang/src/Nodes/CircleWhile.test.cpp b/compiler/luci/lang/src/Nodes/CircleWhile.test.cpp new file mode 100644 index 000000000..19290c0a2 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleWhile.test.cpp @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleWhile.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleWhileTest, constructor) +{ + luci::CircleWhile while_node(2, 2); + + ASSERT_EQ(luci::CircleDialect::get(), while_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::WHILE, while_node.opcode()); + + ASSERT_EQ(2, while_node.input_count()); + ASSERT_EQ(2, while_node.output_count()); + + ASSERT_EQ(nullptr, while_node.input(0)); + ASSERT_EQ(nullptr, while_node.input(1)); + + ASSERT_EQ(-1, while_node.cond_branch()); + ASSERT_EQ(-1, while_node.body_branch()); +} + +TEST(CircleWhileTestDeath, invalid_arity_NEG) +{ + ASSERT_DEBUG_DEATH(luci::CircleWhile very_long_name_while_node(0, 1), ""); +} + +TEST(CircleWhileTestDeath, invalid_output_count_NEG) +{ + ASSERT_DEBUG_DEATH(luci::CircleWhile while_node(2, 0), ""); +} + +TEST(CircleWhileTestDeath, invalid_input_get_index_NEG) +{ + luci::CircleWhile while_node(2, 2); + + EXPECT_ANY_THROW(while_node.input(100)); +} + +TEST(CircleWhileTestDeath, invalid_input_set_index_NEG) +{ + luci::CircleWhile while_node(2, 2); + + EXPECT_ANY_THROW(while_node.input(100, nullptr)); +} + +TEST(CircleWhileTestDeath, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleWhile while_node(2, 2); + + TestVisitor tv; + ASSERT_THROW(while_node.accept(&tv), std::exception); +} + +TEST(CircleWhileTestDeath, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleWhile while_node(2, 2); + + TestVisitor tv; + ASSERT_THROW(while_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/lang/src/Nodes/CircleWhileOut.test.cpp b/compiler/luci/lang/src/Nodes/CircleWhileOut.test.cpp new file mode 100644 index 000000000..1800e4098 --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleWhileOut.test.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleWhileOut.h" + +#include "luci/IR/CircleDialect.h" + +#include <gtest/gtest.h> + +TEST(CircleWhileOutTest, constructor) +{ + luci::CircleWhileOut whileout_node; + + ASSERT_EQ(luci::CircleDialect::get(), whileout_node.dialect()); + ASSERT_EQ(luci::CircleOpcode::CIRCLEWHILEOUT, whileout_node.opcode()); + + ASSERT_EQ(nullptr, whileout_node.input()); + ASSERT_EQ(-1, whileout_node.index()); +} diff --git a/compiler/luci/lang/src/Nodes/CircleZerosLike.test.cpp b/compiler/luci/lang/src/Nodes/CircleZerosLike.test.cpp new file mode 100644 index 000000000..3368c8e3f --- /dev/null +++ b/compiler/luci/lang/src/Nodes/CircleZerosLike.test.cpp @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/IR/Nodes/CircleZerosLike.h" + +#include "luci/IR/CircleDialect.h" +#include "luci/IR/CircleNodeVisitor.h" + +#include <gtest/gtest.h> + +TEST(CircleZerosLikeTest, constructor_P) +{ + luci::CircleZerosLike node; + + ASSERT_EQ(luci::CircleDialect::get(), node.dialect()); + ASSERT_EQ(luci::CircleOpcode::ZEROS_LIKE, node.opcode()); + + ASSERT_EQ(nullptr, node.input()); +} + +TEST(CircleZerosLikeTest, input_NEG) +{ + luci::CircleZerosLike zeros_node; + luci::CircleZerosLike node; + + zeros_node.input(&node); + ASSERT_NE(nullptr, zeros_node.input()); + + zeros_node.input(nullptr); + ASSERT_EQ(nullptr, zeros_node.input()); +} + +TEST(CircleZerosLikeTest, arity_NEG) +{ + luci::CircleZerosLike zeros_node; + + ASSERT_NO_THROW(zeros_node.arg(0)); + ASSERT_THROW(zeros_node.arg(1), std::out_of_range); +} + +TEST(CircleZerosLikeTest, visit_mutable_NEG) +{ + struct TestVisitor final : public luci::CircleNodeMutableVisitor<void> + { + }; + + luci::CircleZerosLike zeros_node; + + TestVisitor tv; + ASSERT_THROW(zeros_node.accept(&tv), std::exception); +} + +TEST(CircleZerosLikeTest, visit_NEG) +{ + struct TestVisitor final : public luci::CircleNodeVisitor<void> + { + }; + + luci::CircleZerosLike zeros_node; + + TestVisitor tv; + ASSERT_THROW(zeros_node.accept(&tv), std::exception); +} diff --git a/compiler/luci/log/CMakeLists.txt b/compiler/luci/log/CMakeLists.txt index af2e7a768..5e822871b 100644 --- a/compiler/luci/log/CMakeLists.txt +++ b/compiler/luci/log/CMakeLists.txt @@ -6,4 +6,5 @@ target_include_directories(luci_log PUBLIC include) target_link_libraries(luci_log PUBLIC hermes) target_link_libraries(luci_log PRIVATE hermes_std) target_link_libraries(luci_log PRIVATE nncc_common) +target_link_libraries(luci_log PRIVATE luci_env) install(TARGETS luci_log DESTINATION lib) diff --git a/compiler/luci/log/include/luci/Log.h b/compiler/luci/log/include/luci/Log.h index 51299a082..e148810d8 100644 --- a/compiler/luci/log/include/luci/Log.h +++ b/compiler/luci/log/include/luci/Log.h @@ -35,7 +35,7 @@ public: /** * @brief Logger Configuration * - * Users are able to turn logging on/off via MOCO_LOG environment variable. + * Users are able to turn logging on/off via LUCI_LOG environment variable. */ class LoggerConfig final : public hermes::Config { @@ -47,7 +47,9 @@ public: void configure(const Logger *, hermes::Source::Setting &) const; private: - bool _enabled; + bool _show_warn = true; + bool _show_info = false; + int _show_verbose = 0; }; } // namespace luci @@ -64,8 +66,10 @@ private: */ #define LOGGER(name) ::luci::Logger name{::luci::LoggingContext::get()}; -// TODO Support FATAL, ERROR, WARN, and VERBOSE +// TODO Support FATAL, ERROR #define INFO(name) HERMES_INFO(name) +#define WARN(name) HERMES_WARN(name) +#define VERBOSE(name, lv) HERMES_VERBOSE(name, lv) // WARNING! // diff --git a/compiler/luci/log/src/Log.cpp b/compiler/luci/log/src/Log.cpp index 7e1634009..c26bf307b 100644 --- a/compiler/luci/log/src/Log.cpp +++ b/compiler/luci/log/src/Log.cpp @@ -16,6 +16,8 @@ #include "luci/Log.h" +#include <luci/UserSettings.h> + #include <cassert> #include <cstdlib> #include <iostream> @@ -36,6 +38,11 @@ template <> bool safecast<bool>(const char *s, const bool &value) return (s == nullptr) ? value : (std::stoi(s) != 0); } +template <> int safecast<int>(const char *s, const int &value) +{ + return (s == nullptr) ? value : std::stoi(s); +} + } // namespace // @@ -57,8 +64,16 @@ namespace luci LoggerConfig::LoggerConfig() { - // Turn on logging if LUCI_LOG is set as non-zero value - _enabled = safecast<bool>(std::getenv("LUCI_LOG"), false); + auto settings = luci::UserSettings::settings(); + + _show_warn = !settings->get(luci::UserSettings::Key::MuteWarnings); + + // Turn on info logging if LUCI_LOG is set as non-zero value + _show_info = safecast<bool>(std::getenv("LUCI_LOG"), false); + + // Turn on verbose logging if LUCI_LOG is set to some level + // VERBOSE(l, 1) will be visible with LUCI_LOG=2 and VERBOSE(l, 2) with LUCI_LOG=3 and so on + _show_verbose = safecast<int>(std::getenv("LUCI_LOG"), 0); } void LoggerConfig::configure(const hermes::Source *source, hermes::Source::Setting &setting) const @@ -72,15 +87,24 @@ void LoggerConfig::configure(const hermes::Source *source, hermes::Source::Setti void LoggerConfig::configure(const Logger *, hermes::Source::Setting &setting) const { - if (_enabled) + setting.filter(hermes::SeverityCategory::FATAL).reject_all(); + setting.filter(hermes::SeverityCategory::ERROR).reject_all(); + setting.filter(hermes::SeverityCategory::WARN).reject_all(); + setting.filter(hermes::SeverityCategory::INFO).reject_all(); + setting.filter(hermes::SeverityCategory::VERBOSE).reject_all(); + + // TODO enable FATAL and ERROR + if (_show_warn) + { + setting.filter(hermes::SeverityCategory::WARN).accept_all(); + } + if (_show_info) { - // Enable all catagories - setting.accept_all(); + setting.filter(hermes::SeverityCategory::INFO).accept_all(); } - else + if (_show_verbose) { - // Disable all catagories - setting.reject_all(); + setting.filter(hermes::SeverityCategory::VERBOSE).accept_upto(_show_verbose); } } diff --git a/compiler/luci/logex/src/FormattedGraph.cpp b/compiler/luci/logex/src/FormattedGraph.cpp index 894ebc151..4725ee3df 100644 --- a/compiler/luci/logex/src/FormattedGraph.cpp +++ b/compiler/luci/logex/src/FormattedGraph.cpp @@ -78,6 +78,8 @@ const char *to_str(loco::DataType type) } } +const char *to_str(bool value) { return value ? "true" : "false"; } + const char *to_str(luci::FusedActFunc fused) { switch (fused) @@ -108,6 +110,19 @@ const char *to_str(luci::Padding padding) } } +const char *to_str(luci::MirrorPadMode mode) +{ + switch (mode) + { + case luci::MirrorPadMode::REFLECT: + return "REFLECT"; + case luci::MirrorPadMode::SYMMETRIC: + return "SYMMETRIC"; + default: + return "Error"; + } +} + std::string to_str(const luci::Stride *stride) { return pepper::str(stride->h(), ",", stride->w()); @@ -180,43 +195,187 @@ private: #define IMPLEMENT(CLASS) bool summary(const CLASS *, locop::NodeSummary &) const final; IMPLEMENT(luci::CircleAbs) IMPLEMENT(luci::CircleAdd) + IMPLEMENT(luci::CircleAddN) IMPLEMENT(luci::CircleArgMax) + IMPLEMENT(luci::CircleArgMin) IMPLEMENT(luci::CircleAveragePool2D) + IMPLEMENT(luci::CircleBatchMatMul) IMPLEMENT(luci::CircleBatchToSpaceND) + IMPLEMENT(luci::CircleCast) + IMPLEMENT(luci::CircleCeil) IMPLEMENT(luci::CircleConcatenation) IMPLEMENT(luci::CircleConst) IMPLEMENT(luci::CircleConv2D) IMPLEMENT(luci::CircleCos) + IMPLEMENT(luci::CircleCustom) + IMPLEMENT(luci::CircleDepthToSpace) IMPLEMENT(luci::CircleDepthwiseConv2D) IMPLEMENT(luci::CircleDiv) + IMPLEMENT(luci::CircleElu) IMPLEMENT(luci::CircleExp) + IMPLEMENT(luci::CircleExpandDims) + IMPLEMENT(luci::CircleFill) + IMPLEMENT(luci::CircleFloor) + IMPLEMENT(luci::CircleFloorDiv) + IMPLEMENT(luci::CircleFloorMod) IMPLEMENT(luci::CircleFullyConnected) + IMPLEMENT(luci::CircleGather) + IMPLEMENT(luci::CircleGatherNd) + IMPLEMENT(luci::CircleGreater) + IMPLEMENT(luci::CircleGreaterEqual) + IMPLEMENT(luci::CircleIf) + IMPLEMENT(luci::CircleL2Normalize) + IMPLEMENT(luci::CircleLeakyRelu) + IMPLEMENT(luci::CircleLess) + IMPLEMENT(luci::CircleLessEqual) + IMPLEMENT(luci::CircleLocalResponseNormalization) + IMPLEMENT(luci::CircleLog) + IMPLEMENT(luci::CircleLogicalAnd) IMPLEMENT(luci::CircleLogicalNot) IMPLEMENT(luci::CircleLogicalOr) + IMPLEMENT(luci::CircleLogistic) + IMPLEMENT(luci::CircleLogSoftmax) + IMPLEMENT(luci::CircleMatrixDiag) + IMPLEMENT(luci::CircleMatrixSetDiag) IMPLEMENT(luci::CircleMaximum) IMPLEMENT(luci::CircleMaxPool2D) IMPLEMENT(luci::CircleMean) + IMPLEMENT(luci::CircleMinimum) + IMPLEMENT(luci::CircleMirrorPad) IMPLEMENT(luci::CircleMul) + IMPLEMENT(luci::CircleNeg) + IMPLEMENT(luci::CircleNotEqual) + IMPLEMENT(luci::CircleOneHot) IMPLEMENT(luci::CirclePack) IMPLEMENT(luci::CirclePad) + IMPLEMENT(luci::CirclePow) + IMPLEMENT(luci::CirclePRelu) + IMPLEMENT(luci::CircleRange) + IMPLEMENT(luci::CircleRank) + IMPLEMENT(luci::CircleReduceAny) + IMPLEMENT(luci::CircleReduceMax) + IMPLEMENT(luci::CircleReduceMin) + IMPLEMENT(luci::CircleReduceProd) IMPLEMENT(luci::CircleRelu) IMPLEMENT(luci::CircleRelu6) + IMPLEMENT(luci::CircleReluN1To1) IMPLEMENT(luci::CircleReshape) + IMPLEMENT(luci::CircleResizeBilinear) + IMPLEMENT(luci::CircleResizeNearestNeighbor) + IMPLEMENT(luci::CircleReverseSequence) + IMPLEMENT(luci::CircleReverseV2) + IMPLEMENT(luci::CircleRound) IMPLEMENT(luci::CircleRsqrt) + IMPLEMENT(luci::CircleScatterNd) + IMPLEMENT(luci::CircleSegmentSum) + IMPLEMENT(luci::CircleSelect) + IMPLEMENT(luci::CircleSelectV2) + IMPLEMENT(luci::CircleShape) + IMPLEMENT(luci::CircleSin) + IMPLEMENT(luci::CircleSlice) IMPLEMENT(luci::CircleSoftmax) + IMPLEMENT(luci::CircleSpaceToBatchND) + IMPLEMENT(luci::CircleSpaceToDepth) + IMPLEMENT(luci::CircleSparseToDense) + IMPLEMENT(luci::CircleSplit) + IMPLEMENT(luci::CircleSplitV) IMPLEMENT(luci::CircleSqrt) + IMPLEMENT(luci::CircleSquare) IMPLEMENT(luci::CircleSquaredDifference) + IMPLEMENT(luci::CircleSqueeze) + IMPLEMENT(luci::CircleStridedSlice) IMPLEMENT(luci::CircleSub) + IMPLEMENT(luci::CircleSum) + IMPLEMENT(luci::CircleTanh) + IMPLEMENT(luci::CircleTile) + IMPLEMENT(luci::CircleTopKV2) IMPLEMENT(luci::CircleTranspose) IMPLEMENT(luci::CircleTransposeConv) + IMPLEMENT(luci::CircleUnpack) + IMPLEMENT(luci::CircleWhere) + IMPLEMENT(luci::CircleWhile) + IMPLEMENT(luci::CircleZerosLike) // Circle Only + IMPLEMENT(luci::CircleBCQFullyConnected) + IMPLEMENT(luci::CircleBCQGather) IMPLEMENT(luci::CircleInstanceNorm) // Virtual nodes IMPLEMENT(luci::CircleInput) IMPLEMENT(luci::CircleOutput) + IMPLEMENT(luci::CircleIfOut) + IMPLEMENT(luci::CircleSplitOut) + IMPLEMENT(luci::CircleSplitVOut) + IMPLEMENT(luci::CircleTopKV2Out) + IMPLEMENT(luci::CircleUnpackOut) + IMPLEMENT(luci::CircleWhileOut) #undef IMPLEMENT }; +template <class CIRCLENODE> +bool use_x(const locop::SymbolTable *tbl, const CIRCLENODE *node, locop::NodeSummary &s) +{ + s.args().append("x", tbl->lookup(node->x())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +template <class CIRCLENODE> +bool use_input(const locop::SymbolTable *tbl, const CIRCLENODE *node, locop::NodeSummary &s) +{ + s.args().append("input", tbl->lookup(node->input())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +template <class CIRCLENODE> +bool use_features(const locop::SymbolTable *tbl, const CIRCLENODE *node, locop::NodeSummary &s) +{ + s.args().append("features", tbl->lookup(node->features())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +template <class CIRCLENODE> +bool use_xy(const locop::SymbolTable *tbl, const CIRCLENODE *node, locop::NodeSummary &s) +{ + s.args().append("x", tbl->lookup(node->x())); + s.args().append("y", tbl->lookup(node->y())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +template <class CIRCLENODE> +bool use_xy_act(const locop::SymbolTable *tbl, const CIRCLENODE *node, locop::NodeSummary &s) +{ + assert(node->fusedActivationFunction() != luci::FusedActFunc::UNDEFINED); + + s.args().append("x", tbl->lookup(node->x())); + s.args().append("y", tbl->lookup(node->y())); + s.args().append("fused_activation_function", to_str(node->fusedActivationFunction())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +template <class CIRCLENODE> +bool use_reducer(const locop::SymbolTable *tbl, const CIRCLENODE *node, locop::NodeSummary &s) +{ + s.args().append("input", tbl->lookup(node->input())); + s.args().append("reduction_indices", tbl->lookup(node->reduction_indices())); + s.args().append("keep_dims", node->keep_dims() ? "true" : "false"); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +template <class CIRCLENODE> +bool use_ido(const locop::SymbolTable *tbl, const CIRCLENODE *node, locop::NodeSummary &s) +{ + s.args().append("input", tbl->lookup(node->input())); + s.args().append("dimension", tbl->lookup(node->dimension())); + s.args().append("output_type", to_str(node->output_type())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + bool CircleNodeSummaryBuilderBase::build(const loco::Node *node, locop::NodeSummary &s) const { if (node->dialect() != luci::CircleDialect::get()) @@ -236,29 +395,31 @@ bool CircleNodeSummaryBuilderBase::build(const loco::Node *node, locop::NodeSumm bool CircleNodeSummaryBuilder::summary(const luci::CircleAbs *node, locop::NodeSummary &s) const { - s.args().append("x", tbl()->lookup(node->x())); - s.state(locop::NodeSummary::State::Complete); - return true; + return use_x(tbl(), node, s); } bool CircleNodeSummaryBuilder::summary(const luci::CircleAdd *node, locop::NodeSummary &s) const { - assert(node->fusedActivationFunction() != luci::FusedActFunc::UNDEFINED); + return use_xy_act(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleAddN *node, locop::NodeSummary &s) const +{ + for (uint32_t i = 0; i < node->arity(); ++i) + s.args().append("inputs", tbl()->lookup(node->inputs(i))); - s.args().append("x", tbl()->lookup(node->x())); - s.args().append("y", tbl()->lookup(node->y())); - s.args().append("fused_activation_function", to_str(node->fusedActivationFunction())); s.state(locop::NodeSummary::State::Complete); return true; } bool CircleNodeSummaryBuilder::summary(const luci::CircleArgMax *node, locop::NodeSummary &s) const { - s.args().append("input", tbl()->lookup(node->input())); - s.args().append("dimension", tbl()->lookup(node->dimension())); - s.args().append("output_type", to_str(node->output_type())); - s.state(locop::NodeSummary::State::Complete); - return true; + return use_ido(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleArgMin *node, locop::NodeSummary &s) const +{ + return use_ido(tbl(), node, s); } bool CircleNodeSummaryBuilder::summary(const luci::CircleAveragePool2D *node, @@ -277,6 +438,17 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleAveragePool2D *node, return true; } +bool CircleNodeSummaryBuilder::summary(const luci::CircleBatchMatMul *node, + locop::NodeSummary &s) const +{ + s.args().append("x", tbl()->lookup(node->x())); + s.args().append("y", tbl()->lookup(node->y())); + s.args().append("adj_x", to_str(node->adj_x())); + s.args().append("adj_y", to_str(node->adj_y())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + bool CircleNodeSummaryBuilder::summary(const luci::CircleBatchToSpaceND *node, locop::NodeSummary &s) const { @@ -289,6 +461,20 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleBatchToSpaceND *node, return true; } +bool CircleNodeSummaryBuilder::summary(const luci::CircleCast *node, locop::NodeSummary &s) const +{ + s.args().append("x", tbl()->lookup(node->x())); + s.args().append("in_data_type", to_str(node->in_data_type())); + s.args().append("out_data_type", to_str(node->out_data_type())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleCeil *node, locop::NodeSummary &s) const +{ + return use_x(tbl(), node, s); +} + bool CircleNodeSummaryBuilder::summary(const luci::CircleConcatenation *node, locop::NodeSummary &s) const { @@ -318,6 +504,8 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleConv2D *node, locop::No s.args().append("bias", tbl()->lookup(node->bias())); s.args().append("stride(h,w)", to_str(node->stride())); + s.args().append("dilation(h,w)", to_str(node->dilation())); + s.args().append("padding", to_str(node->padding())); s.args().append("fused", to_str(node->fusedActivationFunction())); @@ -328,8 +516,28 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleConv2D *node, locop::No bool CircleNodeSummaryBuilder::summary(const luci::CircleCos *node, locop::NodeSummary &s) const { - s.args().append("x", tbl()->lookup(node->x())); + return use_x(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleCustom *node, locop::NodeSummary &s) const +{ + for (uint32_t i = 0; i < node->numInputs(); i++) + { + s.args().append("input" + std::to_string(i), tbl()->lookup(node->inputs(i))); + } + s.args().append("custom_code", node->custom_code()); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleDepthToSpace *node, + locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("block_size", std::to_string(node->block_size())); + s.state(locop::NodeSummary::State::Complete); + return true; } @@ -344,6 +552,7 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleDepthwiseConv2D *node, s.args().append("bias", tbl()->lookup(node->bias())); s.args().append("stride(h,w)", to_str(node->stride())); + s.args().append("dilation(h,w)", to_str(node->dilation())); s.args().append("padding", to_str(node->padding())); s.args().append("depthMultiplier", std::to_string(node->depthMultiplier())); s.args().append("fused", to_str(node->fusedActivationFunction())); @@ -355,15 +564,49 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleDepthwiseConv2D *node, bool CircleNodeSummaryBuilder::summary(const luci::CircleDiv *node, locop::NodeSummary &s) const { - s.args().append("x", tbl()->lookup(node->x())); - s.args().append("y", tbl()->lookup(node->y())); + return use_xy(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleElu *node, locop::NodeSummary &s) const +{ + return use_features(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleExp *node, locop::NodeSummary &s) const +{ + return use_x(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleExpandDims *node, + locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("axis", tbl()->lookup(node->axis())); s.state(locop::NodeSummary::State::Complete); return true; } -bool CircleNodeSummaryBuilder::summary(const luci::CircleExp *node, locop::NodeSummary &s) const +bool CircleNodeSummaryBuilder::summary(const luci::CircleFloor *node, locop::NodeSummary &s) const { - s.args().append("x", tbl()->lookup(node->x())); + return use_x(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleFloorDiv *node, + locop::NodeSummary &s) const +{ + return use_xy(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleFloorMod *node, + locop::NodeSummary &s) const +{ + return use_xy(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleFill *node, locop::NodeSummary &s) const +{ + s.args().append("dims", tbl()->lookup(node->dims())); + s.args().append("value", tbl()->lookup(node->value())); s.state(locop::NodeSummary::State::Complete); return true; } @@ -383,31 +626,157 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleFullyConnected *node, return true; } -bool CircleNodeSummaryBuilder::summary(const luci::CircleLogicalNot *node, +bool CircleNodeSummaryBuilder::summary(const luci::CircleGather *node, locop::NodeSummary &s) const +{ + s.args().append("params", tbl()->lookup(node->params())); + s.args().append("indices", tbl()->lookup(node->indices())); + s.args().append("axis", pepper::str(node->axis())); + + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleGatherNd *node, + locop::NodeSummary &s) const +{ + s.args().append("params", tbl()->lookup(node->params())); + s.args().append("indices", tbl()->lookup(node->indices())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleGreater *node, locop::NodeSummary &s) const +{ + return use_xy(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleGreaterEqual *node, + locop::NodeSummary &s) const +{ + return use_xy(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleIf *node, locop::NodeSummary &s) const +{ + s.args().append("cond", tbl()->lookup(node->cond())); + for (uint32_t i = 0; i < node->input_count(); ++i) + s.args().append("input", tbl()->lookup(node->input(i))); + + if (node->then_graph() != nullptr) + s.args().append("then_graph", node->then_graph()->name()); + else + s.args().append("then_branch", pepper::str(node->then_branch())); + + if (node->else_graph() != nullptr) + s.args().append("else_graph", node->else_graph()->name()); + else + s.args().append("else_branch", pepper::str(node->else_branch())); + + s.state(locop::NodeSummary::State::Complete); + + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleL2Normalize *node, locop::NodeSummary &s) const { s.args().append("x", tbl()->lookup(node->x())); + s.args().append("fused_activation_function", to_str(node->fusedActivationFunction())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleLess *node, locop::NodeSummary &s) const +{ + return use_xy(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleLessEqual *node, + locop::NodeSummary &s) const +{ + return use_xy(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleLeakyRelu *node, + locop::NodeSummary &s) const +{ + s.args().append("features", tbl()->lookup(node->features())); + s.args().append("alpha", std::to_string(node->alpha())); s.state(locop::NodeSummary::State::Complete); return true; } +bool CircleNodeSummaryBuilder::summary(const luci::CircleLocalResponseNormalization *node, + locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("radius", pepper::str(node->radius())); + s.args().append("bias", pepper::str(node->bias())); + s.args().append("alpha", pepper::str(node->alpha())); + s.args().append("beta", pepper::str(node->beta())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleLog *node, locop::NodeSummary &s) const +{ + return use_x(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleLogicalAnd *node, + locop::NodeSummary &s) const +{ + return use_xy(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleLogicalNot *node, + locop::NodeSummary &s) const +{ + return use_x(tbl(), node, s); +} + bool CircleNodeSummaryBuilder::summary(const luci::CircleLogicalOr *node, locop::NodeSummary &s) const { - s.args().append("x", tbl()->lookup(node->x())); - s.args().append("y", tbl()->lookup(node->y())); + return use_xy(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleLogistic *node, + locop::NodeSummary &s) const +{ + return use_x(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleLogSoftmax *node, + locop::NodeSummary &s) const +{ + s.args().append("logits", tbl()->lookup(node->logits())); s.state(locop::NodeSummary::State::Complete); return true; } -bool CircleNodeSummaryBuilder::summary(const luci::CircleMaximum *node, locop::NodeSummary &s) const +bool CircleNodeSummaryBuilder::summary(const luci::CircleMatrixDiag *node, + locop::NodeSummary &s) const { - s.args().append("x", tbl()->lookup(node->x())); - s.args().append("y", tbl()->lookup(node->y())); + s.args().append("diagonal", tbl()->lookup(node->diagonal())); s.state(locop::NodeSummary::State::Complete); return true; } +bool CircleNodeSummaryBuilder::summary(const luci::CircleMatrixSetDiag *node, + locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("diagonal", tbl()->lookup(node->diagonal())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleMaximum *node, locop::NodeSummary &s) const +{ + return use_xy(tbl(), node, s); +} + bool CircleNodeSummaryBuilder::summary(const luci::CircleMaxPool2D *node, locop::NodeSummary &s) const { @@ -426,20 +795,48 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleMaxPool2D *node, bool CircleNodeSummaryBuilder::summary(const luci::CircleMean *node, locop::NodeSummary &s) const { + return use_reducer(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleMinimum *node, locop::NodeSummary &s) const +{ + return use_xy(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleMirrorPad *node, + locop::NodeSummary &s) const +{ s.args().append("input", tbl()->lookup(node->input())); - s.args().append("reduction_indices", tbl()->lookup(node->reduction_indices())); - s.args().append("keep_dims", node->keep_dims() ? "true" : "false"); + s.args().append("paddings", tbl()->lookup(node->paddings())); + s.args().append("mode", to_str(node->mode())); s.state(locop::NodeSummary::State::Complete); return true; } bool CircleNodeSummaryBuilder::summary(const luci::CircleMul *node, locop::NodeSummary &s) const { - assert(node->fusedActivationFunction() != luci::FusedActFunc::UNDEFINED); + return use_xy_act(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleNeg *node, locop::NodeSummary &s) const +{ + return use_x(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleNotEqual *node, + locop::NodeSummary &s) const +{ + return use_xy(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleOneHot *node, locop::NodeSummary &s) const +{ + s.args().append("indices", tbl()->lookup(node->indices())); + s.args().append("depth", tbl()->lookup(node->depth())); + s.args().append("on_value", tbl()->lookup(node->on_value())); + s.args().append("off_value", tbl()->lookup(node->off_value())); + s.args().append("axis", pepper::str(node->axis())); - s.args().append("x", tbl()->lookup(node->x())); - s.args().append("y", tbl()->lookup(node->y())); - s.args().append("fused_activation_function", to_str(node->fusedActivationFunction())); s.state(locop::NodeSummary::State::Complete); return true; } @@ -462,20 +859,74 @@ bool CircleNodeSummaryBuilder::summary(const luci::CirclePad *node, locop::NodeS return true; } -bool CircleNodeSummaryBuilder::summary(const luci::CircleRelu *node, locop::NodeSummary &s) const +bool CircleNodeSummaryBuilder::summary(const luci::CirclePow *node, locop::NodeSummary &s) const { - s.args().append("features", tbl()->lookup(node->features())); + return use_xy(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CirclePRelu *node, locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("alpha", tbl()->lookup(node->alpha())); s.state(locop::NodeSummary::State::Complete); return true; } -bool CircleNodeSummaryBuilder::summary(const luci::CircleRelu6 *node, locop::NodeSummary &s) const +bool CircleNodeSummaryBuilder::summary(const luci::CircleRange *node, locop::NodeSummary &s) const { - s.args().append("features", tbl()->lookup(node->features())); + s.args().append("start", tbl()->lookup(node->start())); + s.args().append("limit", tbl()->lookup(node->limit())); + s.args().append("delta", tbl()->lookup(node->delta())); + s.state(locop::NodeSummary::State::Complete); return true; } +bool CircleNodeSummaryBuilder::summary(const luci::CircleRank *node, locop::NodeSummary &s) const +{ + return use_input(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleReduceAny *node, + locop::NodeSummary &s) const +{ + return use_reducer(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleReduceMax *node, + locop::NodeSummary &s) const +{ + return use_reducer(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleReduceMin *node, + locop::NodeSummary &s) const +{ + return use_reducer(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleReduceProd *node, + locop::NodeSummary &s) const +{ + return use_reducer(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleRelu *node, locop::NodeSummary &s) const +{ + return use_features(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleRelu6 *node, locop::NodeSummary &s) const +{ + return use_features(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleReluN1To1 *node, + locop::NodeSummary &s) const +{ + return use_features(tbl(), node, s); +} + bool CircleNodeSummaryBuilder::summary(const luci::CircleReshape *node, locop::NodeSummary &s) const { s.args().append("tensor", tbl()->lookup(node->tensor())); @@ -485,9 +936,113 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleReshape *node, locop::N return true; } +bool CircleNodeSummaryBuilder::summary(const luci::CircleResizeBilinear *node, + locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("size", tbl()->lookup(node->size())); + s.args().append("align_corners", node->align_corners() ? "true" : "false"); + s.args().append("half_pixel_centers", node->half_pixel_centers() ? "true" : "false"); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleResizeNearestNeighbor *node, + locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("size", tbl()->lookup(node->size())); + s.args().append("align_corners", node->align_corners() ? "true" : "false"); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleReverseSequence *node, + locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("seq_lengths", tbl()->lookup(node->seq_lengths())); + s.args().append("seq_axis", std::to_string(node->seq_axis())); + s.args().append("batch_axis", std::to_string(node->batch_axis())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleReverseV2 *node, + locop::NodeSummary &s) const +{ + s.args().append("tensor", tbl()->lookup(node->tensor())); + s.args().append("axis", tbl()->lookup(node->axis())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleRound *node, locop::NodeSummary &s) const +{ + return use_x(tbl(), node, s); +} + bool CircleNodeSummaryBuilder::summary(const luci::CircleRsqrt *node, locop::NodeSummary &s) const { - s.args().append("x", tbl()->lookup(node->x())); + return use_x(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleScatterNd *node, + locop::NodeSummary &s) const +{ + s.args().append("indices", tbl()->lookup(node->indices())); + s.args().append("updates", tbl()->lookup(node->updates())); + s.args().append("shape", tbl()->lookup(node->shape())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleSegmentSum *node, + locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("segment_ids", tbl()->lookup(node->segment_ids())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleSelect *node, locop::NodeSummary &s) const +{ + s.args().append("condition", tbl()->lookup(node->condition())); + s.args().append("t", tbl()->lookup(node->t())); + s.args().append("e", tbl()->lookup(node->e())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleSelectV2 *node, + locop::NodeSummary &s) const +{ + s.args().append("condition", tbl()->lookup(node->condition())); + s.args().append("t", tbl()->lookup(node->t())); + s.args().append("e", tbl()->lookup(node->e())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleShape *node, locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("out_type", to_str(node->out_type())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleSin *node, locop::NodeSummary &s) const +{ + return use_x(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleSlice *node, locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("begin", tbl()->lookup(node->begin())); + s.args().append("size", tbl()->lookup(node->size())); s.state(locop::NodeSummary::State::Complete); return true; } @@ -500,31 +1055,151 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleSoftmax *node, locop::N return true; } -bool CircleNodeSummaryBuilder::summary(const luci::CircleSqrt *node, locop::NodeSummary &s) const +bool CircleNodeSummaryBuilder::summary(const luci::CircleSpaceToBatchND *node, + locop::NodeSummary &s) const { - s.args().append("x", tbl()->lookup(node->x())); + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("block_shape", tbl()->lookup(node->block_shape())); + s.args().append("paddings", tbl()->lookup(node->paddings())); + s.state(locop::NodeSummary::State::Complete); + return true; } +bool CircleNodeSummaryBuilder::summary(const luci::CircleSpaceToDepth *node, + locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("block_size", pepper::str(node->block_size())); + + s.state(locop::NodeSummary::State::Complete); + + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleSparseToDense *node, + locop::NodeSummary &s) const +{ + s.args().append("indices", tbl()->lookup(node->indices())); + s.args().append("output_shape", tbl()->lookup(node->output_shape())); + s.args().append("values", tbl()->lookup(node->values())); + s.args().append("default_value", tbl()->lookup(node->default_value())); + + s.args().append("Validate_indices", pepper::str(node->validate_indices())); + + s.state(locop::NodeSummary::State::Complete); + + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleSplit *node, locop::NodeSummary &s) const +{ + s.args().append("split_dim", tbl()->lookup(node->split_dim())); + s.args().append("input", tbl()->lookup(node->input())); + + s.args().append("num_split", pepper::str(node->num_split())); + + s.state(locop::NodeSummary::State::Complete); + + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleSplitV *node, locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("size_splits", tbl()->lookup(node->size_splits())); + s.args().append("split_dim", tbl()->lookup(node->split_dim())); + + s.args().append("num_split", pepper::str(node->num_split())); + + s.state(locop::NodeSummary::State::Complete); + + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleSqrt *node, locop::NodeSummary &s) const +{ + return use_x(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleSquare *node, locop::NodeSummary &s) const +{ + return use_x(tbl(), node, s); +} + bool CircleNodeSummaryBuilder::summary(const luci::CircleSquaredDifference *node, locop::NodeSummary &s) const { - s.args().append("x", tbl()->lookup(node->x())); - s.args().append("y", tbl()->lookup(node->y())); + return use_xy(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleSqueeze *node, locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + + std::stringstream ss{"("}; + for (size_t i = 0; i < node->squeeze_dims().size(); ++i) + { + if (i != 0) + ss << ", "; + ss << node->squeeze_dims()[i]; + } + ss << ")"; + + s.args().append("squeeze_dims", ss.str()); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleStridedSlice *node, + locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("begin", tbl()->lookup(node->begin())); + s.args().append("end", tbl()->lookup(node->end())); + s.args().append("strides", tbl()->lookup(node->strides())); + + s.args().append("begin_mask", pepper::str(node->begin_mask())); + s.args().append("end_mask", pepper::str(node->end_mask())); + s.args().append("ellipsis_mask", pepper::str(node->ellipsis_mask())); + s.args().append("new_axis_mask", pepper::str(node->new_axis_mask())); + s.args().append("shrink_axis_mask", pepper::str(node->shrink_axis_mask())); + s.state(locop::NodeSummary::State::Complete); return true; } bool CircleNodeSummaryBuilder::summary(const luci::CircleSub *node, locop::NodeSummary &s) const { - s.args().append("x", tbl()->lookup(node->x())); - s.args().append("y", tbl()->lookup(node->y())); + return use_xy(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleSum *node, locop::NodeSummary &s) const +{ + return use_reducer(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleTanh *node, locop::NodeSummary &s) const +{ + return use_x(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleTile *node, locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("multiples", tbl()->lookup(node->multiples())); s.state(locop::NodeSummary::State::Complete); return true; } -// TODO TFLTanh +bool CircleNodeSummaryBuilder::summary(const luci::CircleTopKV2 *node, locop::NodeSummary &s) const +{ + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("k", tbl()->lookup(node->k())); + s.state(locop::NodeSummary::State::Complete); + return true; +} bool CircleNodeSummaryBuilder::summary(const luci::CircleTranspose *node, locop::NodeSummary &s) const @@ -552,6 +1227,97 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleTransposeConv *node, return true; } +bool CircleNodeSummaryBuilder::summary(const luci::CircleUnpack *node, locop::NodeSummary &s) const +{ + s.args().append("value", tbl()->lookup(node->value())); + + s.args().append("num", pepper::str(node->num())); + s.args().append("axis", pepper::str(node->axis())); + + s.state(locop::NodeSummary::State::Complete); + + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleWhere *node, locop::NodeSummary &s) const +{ + s.args().append("condition", tbl()->lookup(node->condition())); + s.state(locop::NodeSummary::State::Complete); + + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleWhile *node, locop::NodeSummary &s) const +{ + for (uint32_t i = 0; i < node->input_count(); ++i) + s.args().append("input", tbl()->lookup(node->input(i))); + + if (node->cond_graph() != nullptr) + s.args().append("cond_graph", node->cond_graph()->name()); + else + s.args().append("cond_branch", pepper::str(node->cond_branch())); + + if (node->body_graph() != nullptr) + s.args().append("body_graph", node->body_graph()->name()); + else + s.args().append("body_branch", pepper::str(node->body_branch())); + + s.state(locop::NodeSummary::State::Complete); + + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleZerosLike *node, + locop::NodeSummary &s) const +{ + return use_input(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleSplitOut *node, + locop::NodeSummary &s) const +{ + return use_input(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleSplitVOut *node, + locop::NodeSummary &s) const +{ + return use_input(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleTopKV2Out *node, + locop::NodeSummary &s) const +{ + s.args().append("topkv2", tbl()->lookup(node->input())); + s.state(locop::NodeSummary::State::Complete); + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleUnpackOut *node, + locop::NodeSummary &s) const +{ + s.args().append("unpack", tbl()->lookup(node->input())); + + s.state(locop::NodeSummary::State::Complete); + + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleIfOut *node, locop::NodeSummary &s) const +{ + return use_input(tbl(), node, s); +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleWhileOut *node, + locop::NodeSummary &s) const +{ + s.args().append("while", tbl()->lookup(node->input())); + + s.state(locop::NodeSummary::State::Complete); + + return true; +} + bool CircleNodeSummaryBuilder::summary(const luci::CircleInput *, locop::NodeSummary &s) const { s.state(locop::NodeSummary::State::Complete); @@ -566,6 +1332,40 @@ bool CircleNodeSummaryBuilder::summary(const luci::CircleOutput *node, locop::No return true; } +bool CircleNodeSummaryBuilder::summary(const luci::CircleBCQFullyConnected *node, + locop::NodeSummary &s) const +{ + assert(node->fusedActivationFunction() != luci::FusedActFunc::UNDEFINED); + + s.args().append("input", tbl()->lookup(node->input())); + s.args().append("weights_scales", tbl()->lookup(node->weights_scales())); + s.args().append("weights_binary", tbl()->lookup(node->weights_binary())); + s.args().append("bias", tbl()->lookup(node->bias())); + s.args().append("weights_clusters", tbl()->lookup(node->weights_clusters())); + + s.args().append("fused", to_str(node->fusedActivationFunction())); + s.args().append("weights_hidden_size", pepper::str(node->weights_hidden_size())); + + s.state(locop::NodeSummary::State::Complete); + + return true; +} + +bool CircleNodeSummaryBuilder::summary(const luci::CircleBCQGather *node, + locop::NodeSummary &s) const +{ + s.args().append("input_scales", tbl()->lookup(node->input_scales())); + s.args().append("input_binary", tbl()->lookup(node->input_binary())); + s.args().append("indices", tbl()->lookup(node->indices())); + s.args().append("input_clusters", tbl()->lookup(node->input_clusters())); + + s.args().append("axis", pepper::str(node->axis())); + s.args().append("input_hidden_size", pepper::str(node->input_hidden_size())); + + s.state(locop::NodeSummary::State::Complete); + return true; +} + bool CircleNodeSummaryBuilder::summary(const luci::CircleInstanceNorm *node, locop::NodeSummary &s) const { @@ -603,4 +1403,4 @@ bool NodeSummaryBuilder::build(const loco::Node *node, locop::NodeSummary &s) co return false; } -} // namespace exo +} // namespace luci diff --git a/compiler/luci/pass/CMakeLists.txt b/compiler/luci/pass/CMakeLists.txt index 93130ce60..2c5fb3407 100644 --- a/compiler/luci/pass/CMakeLists.txt +++ b/compiler/luci/pass/CMakeLists.txt @@ -1,6 +1,6 @@ file(GLOB_RECURSE SOURCES "src/*.cpp") -#file(GLOB_RECURSE TESTS "src/*.test.cpp") -#list(REMOVE_ITEM SOURCES ${TESTS}) +file(GLOB_RECURSE TESTS "src/*.test.cpp") +list(REMOVE_ITEM SOURCES ${TESTS}) add_library(luci_pass SHARED ${SOURCES}) target_include_directories(luci_pass PRIVATE src) @@ -16,14 +16,14 @@ target_link_libraries(luci_pass PRIVATE nncc_common) target_link_libraries(luci_pass PRIVATE oops) install(TARGETS luci_pass DESTINATION lib) -# TODO enable for tests -#if(NOT ENABLE_TEST) -# return() -#endif(NOT ENABLE_TEST) -# -#nnas_find_package(GTest REQUIRED) -# -#GTest_AddTest(luci_pass_test ${TESTS}) -#target_include_directories(luci_pass_test PRIVATE src) -#target_link_libraries(luci_pass_test luci_pass) +if(NOT ENABLE_TEST) + return() +endif(NOT ENABLE_TEST) + +nnas_find_package(GTest REQUIRED) + +GTest_AddTest(luci_pass_test ${TESTS}) +target_include_directories(luci_pass_test PRIVATE src) +target_link_libraries(luci_pass_test luci_pass) +target_link_libraries(luci_pass_test luci_lang) #target_link_libraries(luci_pass_test oops) diff --git a/compiler/luci/pass/include/luci/CircleOptimizer.h b/compiler/luci/pass/include/luci/CircleOptimizer.h index a969cca85..312749f83 100644 --- a/compiler/luci/pass/include/luci/CircleOptimizer.h +++ b/compiler/luci/pass/include/luci/CircleOptimizer.h @@ -32,11 +32,28 @@ public: { enum Algorithm { + FuseBCQ, FuseInstanceNorm, + ResolveCustomOpAdd, + ResolveCustomOpBatchMatMul, + ResolveCustomOpMatMul, + QuantizeDequantizeWeights, + QuantizeWithMinMax, }; + enum AlgorithmParameters + { + Quantize_input_dtype, + Quantize_output_dtype, + Quantize_granularity // layer-wise or channel-wise + }; + + virtual ~Options() = default; + virtual void enable(Algorithm) = 0; virtual bool query(Algorithm) = 0; + virtual void param(AlgorithmParameters, const std::string &) = 0; + virtual const std::string param(AlgorithmParameters) const = 0; }; public: @@ -46,6 +63,8 @@ public: public: void optimize(loco::Graph *) const; + void quantize(loco::Graph *) const; + private: std::unique_ptr<Options> _options; }; diff --git a/compiler/luci/pass/include/luci/Pass/FuseBCQPass.h b/compiler/luci/pass/include/luci/Pass/FuseBCQPass.h new file mode 100644 index 000000000..4404a9fc9 --- /dev/null +++ b/compiler/luci/pass/include/luci/Pass/FuseBCQPass.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_FUSE_BCQ_PASS_H__ +#define __LUCI_FUSE_BCQ_PASS_H__ + +#include <logo/Pass.h> + +namespace luci +{ + +/** + * @brief Class to fuse certain pattern of subgraph into CircleBCQFullyConnected or CircleBCQGather + * + */ +struct FuseBCQPass final : public logo::Pass +{ + const char *name(void) const final { return "luci::FuseBCQPass"; } + + bool run(loco::Graph *g) final; +}; + +} // namespace luci + +#endif // __LUCI_FUSE_BCQ_PASS_H__ diff --git a/compiler/luci/pass/include/luci/Pass/QuantizationParameters.h b/compiler/luci/pass/include/luci/Pass/QuantizationParameters.h new file mode 100644 index 000000000..5c9cd427f --- /dev/null +++ b/compiler/luci/pass/include/luci/Pass/QuantizationParameters.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_QUANTIZATION_PARAMETERS_H__ +#define __LUCI_QUANTIZATION_PARAMETERS_H__ + +namespace luci +{ + +enum QuantizationGranularity +{ + LayerWise = 0, + ChannelWise = 1, +}; + +} // namespace luci + +#endif // __LUCI_QUANTIZATION_PARAMETERS_H__ diff --git a/compiler/luci/pass/include/luci/Pass/QuantizeDequantizeWeightsPass.h b/compiler/luci/pass/include/luci/Pass/QuantizeDequantizeWeightsPass.h new file mode 100644 index 000000000..713b88f9d --- /dev/null +++ b/compiler/luci/pass/include/luci/Pass/QuantizeDequantizeWeightsPass.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_QUANTIZE_DEQUANTIZE_WEIGHTS_PASS_H__ +#define __LUCI_QUANTIZE_DEQUANTIZE_WEIGHTS_PASS_H__ + +#include <loco.h> + +#include <logo/Pass.h> + +#include <luci/Pass/QuantizationParameters.h> + +namespace luci +{ + +/** + * @brief Pass to quantize weights + */ +class QuantizeDequantizeWeightsPass : public logo::Pass +{ +public: + QuantizeDequantizeWeightsPass(loco::DataType input_dtype, loco::DataType output_dtype, + QuantizationGranularity granularity) + : _input_dtype{input_dtype}, _output_dtype{output_dtype}, _granularity{granularity} + { + // DO NOTHING + } + virtual const char *name(void) const { return "luci::QuantizeDequantizeWeightsPass"; } + +public: + bool run(loco::Graph *graph); + +private: + loco::DataType _input_dtype; + loco::DataType _output_dtype; + QuantizationGranularity _granularity; +}; + +} // namespace luci + +#endif //__LUCI_QUANTIZE_DEQUANTIZE_WEIGHTS_PASS_H__ diff --git a/compiler/luci/pass/include/luci/Pass/QuantizeWithMinMaxPass.h b/compiler/luci/pass/include/luci/Pass/QuantizeWithMinMaxPass.h new file mode 100644 index 000000000..bb0d0ff40 --- /dev/null +++ b/compiler/luci/pass/include/luci/Pass/QuantizeWithMinMaxPass.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_QUANTIZE_WITH_MINMAX_PASS_H__ +#define __LUCI_QUANTIZE_WITH_MINMAX_PASS_H__ + +#include <loco.h> + +#include <logo/Pass.h> + +#include <luci/Pass/QuantizationParameters.h> + +namespace luci +{ + +/** + * @brief Pass to quantize activation, weights, and bias + */ +class QuantizeWithMinMaxPass : public logo::Pass +{ +public: + QuantizeWithMinMaxPass(loco::DataType input_dtype, loco::DataType output_dtype, + QuantizationGranularity granularity) + : _input_dtype{input_dtype}, _output_dtype{output_dtype}, _granularity{granularity} + { + // DO NOTHING + } + virtual const char *name(void) const { return "luci::QuantizeWithMinMaxPass"; } + +public: + bool run(loco::Graph *graph); + +private: + loco::DataType _input_dtype; + loco::DataType _output_dtype; + QuantizationGranularity _granularity; +}; + +} // namespace luci + +#endif //__LUCI_QUANTIZE_WITH_MINMAX_PASS_H__ diff --git a/compiler/luci/pass/include/luci/Pass/ResolveCustomOpAddPass.h b/compiler/luci/pass/include/luci/Pass/ResolveCustomOpAddPass.h new file mode 100644 index 000000000..35a335028 --- /dev/null +++ b/compiler/luci/pass/include/luci/Pass/ResolveCustomOpAddPass.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_RESOLVE_CUSTOM_OP_ADD_PASS_H__ +#define __LUCI_RESOLVE_CUSTOM_OP_ADD_PASS_H__ + +#include <logo/Pass.h> + +namespace luci +{ + +/** + * @brief Class to resolve certain custom op of subgraph into add op in circle schema. + */ +struct ResolveCustomOpAddPass final : public logo::Pass +{ + const char *name(void) const final { return "luci::ResolveCustomOpAddPass"; } + + bool run(loco::Graph *g) final; +}; + +} // namespace luci + +#endif // __LUCI_RESOLVE_CUSTOM_OP_ADD_PASS_H__ diff --git a/compiler/luci/pass/include/luci/Pass/ResolveCustomOpBatchMatMulPass.h b/compiler/luci/pass/include/luci/Pass/ResolveCustomOpBatchMatMulPass.h new file mode 100644 index 000000000..7c48c8d16 --- /dev/null +++ b/compiler/luci/pass/include/luci/Pass/ResolveCustomOpBatchMatMulPass.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_RESOLVE_CUSTOM_OP_BATCHMATMUL_PASS_H__ +#define __LUCI_RESOLVE_CUSTOM_OP_BATCHMATMUL_PASS_H__ + +#include <logo/Pass.h> + +namespace luci +{ + +/** + * @brief Class to resolve certain custom op of subgraph into batchmatmul op in circle schema. + */ +struct ResolveCustomOpBatchMatMulPass final : public logo::Pass +{ + const char *name(void) const final { return "luci::ResolveCustomOpBatchMatMulPass"; } + + bool run(loco::Graph *g) final; +}; + +} // namespace luci + +#endif // __LUCI_RESOLVE_CUSTOM_OP_BATCHMATMUL_PASS_H__ diff --git a/compiler/luci/pass/include/luci/Pass/ResolveCustomOpMatMulPass.h b/compiler/luci/pass/include/luci/Pass/ResolveCustomOpMatMulPass.h new file mode 100644 index 000000000..701deba91 --- /dev/null +++ b/compiler/luci/pass/include/luci/Pass/ResolveCustomOpMatMulPass.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_RESOLVE_CUSTOM_OP_MATMUL_PASS_H__ +#define __LUCI_RESOLVE_CUSTOM_OP_MATMUL_PASS_H__ + +#include <logo/Pass.h> + +namespace luci +{ + +/** + * @brief Class to resolve certain custom op of subgraph into matmul op in circle schema. + */ +struct ResolveCustomOpMatMulPass final : public logo::Pass +{ + const char *name(void) const final { return "luci::ResolveCustomOpMatMulPass"; } + + bool run(loco::Graph *g) final; +}; + +} // namespace luci + +#endif // __LUCI_RESOLVE_CUSTOM_OP_MATMUL_PASS_H__ diff --git a/compiler/luci/pass/src/CircleOptimizer.cpp b/compiler/luci/pass/src/CircleOptimizer.cpp index dcb05a0b5..90fbe9009 100644 --- a/compiler/luci/pass/src/CircleOptimizer.cpp +++ b/compiler/luci/pass/src/CircleOptimizer.cpp @@ -16,16 +16,23 @@ #include "luci/CircleOptimizer.h" +#include "luci/Pass/FuseBCQPass.h" #include "luci/Pass/FuseInstanceNormPass.h" +#include "luci/Pass/ResolveCustomOpAddPass.h" +#include "luci/Pass/ResolveCustomOpBatchMatMulPass.h" +#include "luci/Pass/ResolveCustomOpMatMulPass.h" +#include "luci/Pass/QuantizeWithMinMaxPass.h" +#include "luci/Pass/QuantizeDequantizeWeightsPass.h" // TODO add more passes #include "luci/Pass/ShapeInferencePass.h" #include "luci/Pass/TypeInferencePass.h" // logo passes -#include <logo/RemoveDeadNodePass.h> +#include <logo/RemoveDeadNodeWithQueryPass.h> #include "ProgressReporter.h" +#include "CircleOptimizerUtils.h" #include <logo/Phase.h> @@ -36,18 +43,39 @@ namespace using namespace luci; -class OptimizeOptionsImpl : public luci::CircleOptimizer::Options +class OptimizeOptionsImpl final : public luci::CircleOptimizer::Options { public: void enable(Algorithm) final; + void param(AlgorithmParameters, const std::string &) final; + const std::string param(AlgorithmParameters) const final; bool query(Algorithm) final; private: std::vector<Algorithm> _algorithms; + std::map<AlgorithmParameters, const std::string> _algorithm_params; }; void OptimizeOptionsImpl::enable(Algorithm algo) { _algorithms.push_back(algo); } +void OptimizeOptionsImpl::param(AlgorithmParameters param, const std::string &str) +{ + _algorithm_params.insert(std::pair<AlgorithmParameters, const std::string>(param, str)); +} + +const std::string OptimizeOptionsImpl::param(AlgorithmParameters param) const +{ + auto param_str = _algorithm_params.find(param); + if (param_str != _algorithm_params.end()) + { + return param_str->second; + } + else + { + return std::string(); + } +} + bool OptimizeOptionsImpl::query(Algorithm algo) { std::vector<Algorithm>::iterator it = std::find(_algorithms.begin(), _algorithms.end(), algo); @@ -77,14 +105,31 @@ void CircleOptimizer::optimize(loco::Graph *g) const logo::Phase phase; /* TRANSFORM DECLARATION BEGIN */ + if (_options->query(Options::Algorithm::ResolveCustomOpAdd)) + { + phase.emplace_back(std::make_unique<luci::ResolveCustomOpAddPass>()); + } + if (_options->query(Options::Algorithm::ResolveCustomOpBatchMatMul)) + { + phase.emplace_back(std::make_unique<luci::ResolveCustomOpBatchMatMulPass>()); + } + if (_options->query(Options::Algorithm::ResolveCustomOpMatMul)) + { + phase.emplace_back(std::make_unique<luci::ResolveCustomOpMatMulPass>()); + } if (_options->query(Options::Algorithm::FuseInstanceNorm)) { phase.emplace_back(std::make_unique<FuseInstanceNormPass>()); } + if (_options->query(Options::Algorithm::FuseBCQ)) + { + phase.emplace_back(std::make_unique<FuseBCQPass>()); + } + // Shape inference is needed for added nodes doing above transformations phase.emplace_back(std::make_unique<luci::ShapeInferencePass>()); phase.emplace_back(std::make_unique<luci::TypeInferencePass>()); - phase.emplace_back(std::make_unique<logo::RemoveDeadNodePass>()); + phase.emplace_back(std::make_unique<logo::RemoveDeadNodeWithQueryPass>()); /* TRANSFORM DECLARATION END */ ProgressReporter prog(g, logo::PhaseStrategy::Saturate); @@ -93,4 +138,74 @@ void CircleOptimizer::optimize(loco::Graph *g) const phase_runner.run(phase); } +void CircleOptimizer::quantize(loco::Graph *g) const +{ + // Fake quantization of weights + if (_options->query(Options::Algorithm::QuantizeDequantizeWeights)) + { + static const std::vector<std::string> fakeq_supported_input_dtype{"float32"}; + static const std::vector<std::string> fakeq_supported_output_dtype{"uint8"}; + static const std::vector<std::string> fakeq_supported_granularity{"layer"}; + + auto input_dtype = _options->param(Options::AlgorithmParameters::Quantize_input_dtype); + auto output_dtype = _options->param(Options::AlgorithmParameters::Quantize_output_dtype); + auto granularity = _options->param(Options::AlgorithmParameters::Quantize_granularity); + + if (!in_array(to_lower_case(input_dtype), fakeq_supported_input_dtype)) + throw std::runtime_error("Unsupported input type. List of supported input type: " + + to_string(fakeq_supported_input_dtype)); + + if (!in_array(to_lower_case(output_dtype), fakeq_supported_output_dtype)) + throw std::runtime_error("Unsupported output type. List of supported output type: " + + to_string(fakeq_supported_output_dtype)); + + if (!in_array(to_lower_case(granularity), fakeq_supported_granularity)) + throw std::runtime_error("Unsupported granularity. List of supported granularity: " + + to_string(fakeq_supported_granularity)); + + luci::QuantizeDequantizeWeightsPass fake_quantizer( + str_to_dtype(input_dtype), str_to_dtype(output_dtype), str_to_granularity(granularity)); + fake_quantizer.run(g); + } + + // Actual quantization of weights, bias, and activation + if (_options->query(Options::Algorithm::QuantizeWithMinMax)) + { + static const std::vector<std::string> qwmm_supported_input_dtype{"float32"}; + static const std::vector<std::string> qwmm_supported_output_dtype{"uint8"}; + static const std::vector<std::string> qwmm_supported_granularity{"layer"}; + + auto input_dtype = _options->param(Options::AlgorithmParameters::Quantize_input_dtype); + auto output_dtype = _options->param(Options::AlgorithmParameters::Quantize_output_dtype); + auto granularity = _options->param(Options::AlgorithmParameters::Quantize_granularity); + + if (!in_array(to_lower_case(input_dtype), qwmm_supported_input_dtype)) + throw std::runtime_error("Unsupported input type. List of supported input types: " + + to_string(qwmm_supported_input_dtype)); + + if (!in_array(to_lower_case(output_dtype), qwmm_supported_output_dtype)) + throw std::runtime_error("Unsupported output type. List of supported output types: " + + to_string(qwmm_supported_output_dtype)); + + if (!in_array(to_lower_case(granularity), qwmm_supported_granularity)) + throw std::runtime_error("Unsupported granularity. List of supported granularity: " + + to_string(qwmm_supported_granularity)); + + luci::QuantizeWithMinMaxPass quantizer(str_to_dtype(input_dtype), str_to_dtype(output_dtype), + str_to_granularity(granularity)); + quantizer.run(g); + } + + logo::Phase phase; + + // Do Shape/Type inference + phase.emplace_back(std::make_unique<luci::ShapeInferencePass>()); + phase.emplace_back(std::make_unique<luci::TypeInferencePass>()); + + ProgressReporter prog(g, logo::PhaseStrategy::Saturate); + logo::PhaseRunner<logo::PhaseStrategy::Saturate> phase_runner{g}; + phase_runner.attach(&prog); + phase_runner.run(phase); +} + } // namespace luci diff --git a/compiler/luci/pass/src/CircleOptimizerUtils.cpp b/compiler/luci/pass/src/CircleOptimizerUtils.cpp new file mode 100644 index 000000000..ffc372392 --- /dev/null +++ b/compiler/luci/pass/src/CircleOptimizerUtils.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "CircleOptimizerUtils.h" + +namespace luci +{ + +bool in_array(const std::string &str, const std::vector<std::string> &array) +{ + return std::find(array.begin(), array.end(), str) != array.end(); +} + +std::string to_string(const std::vector<std::string> &strings) +{ + assert(!strings.empty()); + + std::string res; + for (unsigned int i = 0; i < strings.size() - 1; i++) + res += strings[i] + ", "; + + res += strings[strings.size() - 1]; + return res; +} + +std::string to_lower_case(std::string s) +{ + std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return std::tolower(c); }); + return s; +} + +loco::DataType str_to_dtype(const std::string &str) +{ + if (to_lower_case(str).compare("uint8") == 0) + return loco::DataType::U8; + if (to_lower_case(str).compare("uint16") == 0) + return loco::DataType::U16; + if (to_lower_case(str).compare("uint32") == 0) + return loco::DataType::U32; + if (to_lower_case(str).compare("uint64") == 0) + return loco::DataType::U64; + + if (to_lower_case(str).compare("int8") == 0) + return loco::DataType::S8; + if (to_lower_case(str).compare("int16") == 0) + return loco::DataType::S16; + if (to_lower_case(str).compare("int32") == 0) + return loco::DataType::S32; + if (to_lower_case(str).compare("int64") == 0) + return loco::DataType::S64; + + if (to_lower_case(str).compare("float16") == 0) + return loco::DataType::FLOAT16; + if (to_lower_case(str).compare("float32") == 0) + return loco::DataType::FLOAT32; + if (to_lower_case(str).compare("float64") == 0) + return loco::DataType::FLOAT64; + + if (to_lower_case(str).compare("bool") == 0) + return loco::DataType::BOOL; + + return loco::DataType::Unknown; +} + +QuantizationGranularity str_to_granularity(const std::string &str) +{ + if (to_lower_case(str).compare("layer") == 0) + return QuantizationGranularity::LayerWise; + + if (to_lower_case(str).compare("channel") == 0) + return QuantizationGranularity::ChannelWise; + + throw std::runtime_error("Quantization granularity must be either 'layer' or 'channel'"); +} + +} // namespace luci diff --git a/compiler/luci/pass/src/CircleOptimizerUtils.h b/compiler/luci/pass/src/CircleOptimizerUtils.h new file mode 100644 index 000000000..7e577a05f --- /dev/null +++ b/compiler/luci/pass/src/CircleOptimizerUtils.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_CIRCLE_OPTIMIZER_UTILS_H__ +#define __LUCI_CIRCLE_OPTIMIZER_UTILS_H__ + +#include "luci/Pass/QuantizeDequantizeWeightsPass.h" +#include "luci/Pass/QuantizeWithMinMaxPass.h" + +#include <loco.h> + +#include <algorithm> + +namespace luci +{ + +bool in_array(const std::string &, const std::vector<std::string> &); + +std::string to_string(const std::vector<std::string> &); + +std::string to_lower_case(std::string); + +loco::DataType str_to_dtype(const std::string &); + +QuantizationGranularity str_to_granularity(const std::string &); + +} // namespace luci + +#endif // __LUCI_CIRCLE_OPTIMIZER_UTILS_H__ diff --git a/compiler/luci/pass/src/FuseBCQPass.cpp b/compiler/luci/pass/src/FuseBCQPass.cpp new file mode 100644 index 000000000..b81db8827 --- /dev/null +++ b/compiler/luci/pass/src/FuseBCQPass.cpp @@ -0,0 +1,405 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Pass/FuseBCQPass.h" + +#include <luci/IR/CircleNodes.h> + +#include <cassert> +#include <string> +#include <set> + +namespace +{ + +/** + * @brief Circle nodes including BCQ information and a circle node to which BCQ will be applied + * are connected with their name. And their names include common prefix. + * However, after pb file is converted to tflite file, some nodes' name are changed. + * Thus this function will return original common prefix. + * + * @note All the re-naming rule of TFLite converter is not figured out. + * Therefore, if new naming rule is detected, this function should be updated. + */ +const std::string node_name_prefix(luci::NodeName node_name) +{ + std::string prefix = node_name; + + if (prefix.find("ReadVariableOp/resource/") != std::string::npos) + { + const auto start_index = prefix.find("ReadVariableOp/resource/"); + + const auto left_prefix = prefix.substr(0, start_index); + const auto right_prefix = prefix.substr(start_index + 24); + + prefix = left_prefix + right_prefix; + } + + if (prefix.find("Tensordot/") != std::string::npos) + { + const auto index = prefix.find("Tensordot/"); + prefix = prefix.substr(0, index - 1); + } + else if (prefix.find("kernel/") != std::string::npos) + { + const auto index = prefix.find("kernel/"); + prefix = prefix.substr(0, index - 1); + } + else if (prefix.find("/bcqinfo_") != std::string::npos) + { + const auto index = prefix.find("/bcqinfo_"); + prefix = prefix.substr(0, index); + } + + return prefix; +} + +} // namespace + +namespace +{ + +class BCQConverter final +{ +public: + void add_BCQ_info_node(luci::CircleConst *node) + { + const auto node_name = node->name(); + const auto prefix = node_name_prefix(node_name); + + // If bcqinfo_* nodes are held by Reshape operation, + // shape of bcqinfo_* nodes are copied to `shape` input of Reshape operation. + // Then the name becomes bcqinfo_*_copy_shape. + // We should prevent this node not to added to bcq information. + if (node_name.find("_copy_shape") != std::string::npos) + return; + + if (node_name.find("bcqinfo_do_w_x") != std::string::npos) + _do_w_x[prefix] = node; + else if (node_name.find("bcqinfo_alpha") != std::string::npos) + _alpha[prefix] = node; + else if (node_name.find("bcqinfo_packed_binary_code") != std::string::npos) + _packed_binary_code[prefix] = node; + else if (node_name.find("bcqinfo_number_of_clusters") != std::string::npos) + _number_of_clusters[prefix] = node; + else if (node_name.find("bcqinfo_size_of_clusters") != std::string::npos) + _size_of_clusters[prefix] = node; + else if (node_name.find("bcqinfo_qbits_of_clusters") != std::string::npos) + _qbits_of_clusters[prefix] = node; + else if (node_name.find("bcqinfo_dequant_weight") != std::string::npos) + _dequant_weight[prefix] = node; + } + + bool has_BCQ_info(luci::CircleConst *node) + { + const auto prefix = node_name_prefix(node->name()); + bool has_info = true; + + has_info &= (_do_w_x.find(prefix) != _do_w_x.end()); + has_info &= (_alpha.find(prefix) != _alpha.end()); + has_info &= (_packed_binary_code.find(prefix) != _packed_binary_code.end()); + has_info &= (_number_of_clusters.find(prefix) != _number_of_clusters.end()); + has_info &= (_size_of_clusters.find(prefix) != _size_of_clusters.end()); + has_info &= (_qbits_of_clusters.find(prefix) != _qbits_of_clusters.end()); + // bcqinfo_dequant_weight is just for validation, so not always exists. + + return has_info; + } + + bool do_w_x(luci::CircleConst *node) + { + const auto prefix = node_name_prefix(node->name()); + + if (_do_w_x[prefix]->dtype() == loco::DataType::S32) + return _do_w_x[prefix]->at<loco::DataType::S32>(0) == 1; + else if (_do_w_x[prefix]->dtype() == loco::DataType::BOOL) + return _do_w_x[prefix]->at<loco::DataType::BOOL>(0); + else + throw std::runtime_error("do_w_x should be int or bool"); + } + + luci::CircleConst *get_alpha(luci::CircleConst *node) + { + const auto prefix = node_name_prefix(node->name()); + return _alpha[prefix]; + } + + luci::CircleConst *get_packed_binary_code(luci::CircleConst *node) + { + const auto prefix = node_name_prefix(node->name()); + return _packed_binary_code[prefix]; + } + + luci::CircleConst *get_number_of_clusters(luci::CircleConst *node) + { + const auto prefix = node_name_prefix(node->name()); + return _number_of_clusters[prefix]; + } + + luci::CircleConst *get_size_of_clusters(luci::CircleConst *node) + { + const auto prefix = node_name_prefix(node->name()); + return _size_of_clusters[prefix]; + } + + luci::CircleConst *get_qbits_of_clusters(luci::CircleConst *node) + { + const auto prefix = node_name_prefix(node->name()); + return _qbits_of_clusters[prefix]; + } + + luci::CircleConst *packed_clusters(luci::CircleConst *node) + { + auto graph = node->graph(); + auto qbits_of_clusters = get_qbits_of_clusters(node); + auto size_of_clusters = get_size_of_clusters(node); + const auto number_of_clusters = get_number_of_clusters(node)->at<loco::DataType::S32>(0); + + auto packed_clusters = graph->nodes()->create<luci::CircleConst>(); + packed_clusters->dtype(loco::DataType::S32); + packed_clusters->size<loco::DataType::S32>(number_of_clusters * 2); + packed_clusters->rank(2); + packed_clusters->dim(0) = number_of_clusters; + packed_clusters->dim(1) = 2; + packed_clusters->shape_status(luci::ShapeStatus::VALID); + + for (int i = 0; i < number_of_clusters; ++i) + { + packed_clusters->at<loco::DataType::S32>(i * 2) = + qbits_of_clusters->at<loco::DataType::S32>(i); + packed_clusters->at<loco::DataType::S32>(i * 2 + 1) = + size_of_clusters->at<loco::DataType::S32>(i); + } + + return packed_clusters; + } + + /** + * @brief Exclude BCQ information nodes which are used for fusing BCQ operations + * from graph output by using CircleOutputExclude + */ + void clear_BCQ_nodes() + { + auto createNoOp = [](luci::CircleNode *circle_node) { + auto graph = circle_node->graph(); + auto noOp = graph->nodes()->create<luci::CircleOutputExclude>(); + + if (circle_node->shape_status() == luci::ShapeStatus::VALID) + { + noOp->dtype(circle_node->dtype()); + noOp->rank(circle_node->rank()); + for (uint32_t i = 0; i < circle_node->rank(); ++i) + noOp->dim(i) = circle_node->dim(i); + } + else + { + // For type inference + noOp->dtype(loco::DataType::FLOAT32); + } + + return noOp; + }; + + auto clear_nodes = [createNoOp](std::map<std::string, luci::CircleConst *> &nodes) { + for (auto &n : nodes) + { + auto node = n.second; + + for (auto s : loco::succs(node)) + { + if (auto outnode = dynamic_cast<luci::CircleOutput *>(s)) + { + outnode->from(createNoOp(node)); + } + else if (auto reshape_node = dynamic_cast<luci::CircleReshape *>(s)) + { + for (auto o : loco::succs(reshape_node)) + { + auto circle_output = loco::must_cast<luci::CircleOutput *>(o); + circle_output->from(createNoOp(reshape_node)); + } + } + } + } + }; + + clear_nodes(_do_w_x); + clear_nodes(_alpha); + clear_nodes(_packed_binary_code); + clear_nodes(_number_of_clusters); + clear_nodes(_size_of_clusters); + clear_nodes(_qbits_of_clusters); + clear_nodes(_dequant_weight); + } + +private: + std::map<std::string, luci::CircleConst *> _do_w_x; + std::map<std::string, luci::CircleConst *> _alpha; + std::map<std::string, luci::CircleConst *> _packed_binary_code; + std::map<std::string, luci::CircleConst *> _number_of_clusters; + std::map<std::string, luci::CircleConst *> _size_of_clusters; + std::map<std::string, luci::CircleConst *> _qbits_of_clusters; + std::map<std::string, luci::CircleConst *> _dequant_weight; +}; + +} // namespace + +namespace luci +{ + +bool FuseBCQPass::run(loco::Graph *g) +{ + BCQConverter converter; + + bool changed = false; + + for (auto node : loco::all_nodes(g)) + { + if (auto circle_const = dynamic_cast<luci::CircleConst *>(node)) + { + converter.add_BCQ_info_node(circle_const); + } + } + + for (auto node : loco::active_nodes(loco::output_nodes(g))) + { + if (auto gather = dynamic_cast<luci::CircleGather *>(node)) + { + auto params = dynamic_cast<luci::CircleConst *>(gather->params()); + if (params != nullptr && converter.has_BCQ_info(params)) + { + auto bcq_gather = g->nodes()->create<luci::CircleBCQGather>(); + + bcq_gather->input_scales(converter.get_alpha(params)); + bcq_gather->input_binary(converter.get_packed_binary_code(params)); + bcq_gather->indices(gather->indices()); + bcq_gather->input_clusters(converter.packed_clusters(params)); + + const auto binary_hidden_size = + loco::must_cast<luci::CircleConst *>(bcq_gather->input_binary())->dim(1).value() * 32; + bcq_gather->input_hidden_size(binary_hidden_size); + + if (converter.do_w_x(params)) + { + bcq_gather->axis(gather->axis()); + } + else + { + const auto axis_transpose = (gather->axis() == 0) ? 1 : 0; + bcq_gather->axis(axis_transpose); + } + + loco::replace(gather).with(bcq_gather); + + changed = true; + } + } + else if (auto fully_connected = dynamic_cast<luci::CircleFullyConnected *>(node)) + { + auto weights = dynamic_cast<luci::CircleConst *>(fully_connected->weights()); + if (weights != nullptr && converter.has_BCQ_info(weights)) + { + auto bcq_fc = g->nodes()->create<luci::CircleBCQFullyConnected>(); + + bcq_fc->weights_scales(converter.get_alpha(weights)); + bcq_fc->weights_binary(converter.get_packed_binary_code(weights)); + bcq_fc->bias(fully_connected->bias()); + bcq_fc->weights_clusters(converter.packed_clusters(weights)); + bcq_fc->fusedActivationFunction(fully_connected->fusedActivationFunction()); + + loco::Node *bcq_input = fully_connected->input(); + int32_t batch_rank = 0; + + // If input of BCQFullyConnected has more than rank 2, we should reshape it as rank 2 + const auto original_input = loco::must_cast<luci::CircleNode *>(fully_connected->input()); + if (original_input->shape_status() == ShapeStatus::VALID && original_input->rank() > 2) + { + auto new_shape = g->nodes()->create<luci::CircleConst>(); + new_shape->dtype(loco::DataType::S32); + new_shape->size<loco::DataType::S32>(2); + new_shape->rank(1); + new_shape->dim(0) = 2; + + auto batch_size = 1; + for (uint32_t i = 0; i < original_input->rank() - 1; ++i) + batch_size *= original_input->dim(i).value(); + + new_shape->at<loco::DataType::S32>(0) = batch_size; + new_shape->at<loco::DataType::S32>(1) = + original_input->dim(original_input->rank() - 1).value(); + new_shape->shape_status(ShapeStatus::VALID); + + auto reshape = g->nodes()->create<luci::CircleReshape>(); + reshape->tensor(original_input); + reshape->shape(new_shape); + + bcq_input = reshape; + batch_rank = original_input->rank() - 2; + } + + // If x_w formation, we should insert Transpose in front and back of BCQFullyConnected + if (converter.do_w_x(weights)) + { + const auto binary_hidden_size = + loco::must_cast<luci::CircleNode *>(fully_connected->input()) + ->dim(batch_rank) + .value(); + bcq_fc->weights_hidden_size(binary_hidden_size); + bcq_fc->input(bcq_input); + loco::replace(fully_connected).with(bcq_fc); + } + else + { + const auto binary_hidden_size = + loco::must_cast<luci::CircleNode *>(fully_connected->input()) + ->dim(1 + batch_rank) + .value(); + bcq_fc->weights_hidden_size(binary_hidden_size); + + auto perm = g->nodes()->create<luci::CircleConst>(); + perm->dtype(loco::DataType::S32); + perm->size<loco::DataType::S32>(2); + perm->rank(1); + perm->dim(0) = 2; + perm->at<loco::DataType::S32>(0) = 1; + perm->at<loco::DataType::S32>(1) = 0; + perm->shape_status(ShapeStatus::VALID); + + auto input_transpose = g->nodes()->create<luci::CircleTranspose>(); + input_transpose->a(bcq_input); + input_transpose->perm(perm); + + bcq_fc->input(input_transpose); + + auto output_transpose = g->nodes()->create<luci::CircleTranspose>(); + output_transpose->a(bcq_fc); + output_transpose->perm(perm); + + loco::replace(fully_connected).with(output_transpose); + } + + changed = true; + } + } + } + + if (changed) + converter.clear_BCQ_nodes(); + + return changed; +} + +} // namespace luci diff --git a/compiler/luci/pass/src/FuseInstanceNormPass.cpp b/compiler/luci/pass/src/FuseInstanceNormPass.cpp index 180b5bbef..ad8765c41 100644 --- a/compiler/luci/pass/src/FuseInstanceNormPass.cpp +++ b/compiler/luci/pass/src/FuseInstanceNormPass.cpp @@ -15,6 +15,7 @@ */ #include "luci/Pass/FuseInstanceNormPass.h" +#include "FuseInstanceNormPassInternal.h" #include <luci/IR/CircleNodes.h> @@ -114,8 +115,6 @@ bool NodeFiller<ARG_TYPE_1, ARG_TYPE_2>::with_commutative_args_of(const COMM_NOD } // namespace // Helper to check detail -namespace -{ /// @return true When node has shape of '1 x .. x 1 x depth' bool is_1D_with_dummy_dim(luci::CircleConst *node, uint32_t depth) @@ -130,7 +129,23 @@ bool is_1D_with_dummy_dim(luci::CircleConst *node, uint32_t depth) return node->dim(axis).value() == depth; } -bool is_instance_mean(luci::CircleMean *mean) +/// @return true if node shape consists of ones, except the one before the last dim: 1,...1,depth,1 +bool is_quasi_1D_with_dummy_dim(luci::CircleConst *node, uint32_t depth) +{ + auto rank = node->rank(); + // minimal accepted shape is [1 x depth x 1] + if (rank < 3) + return false; + const auto depth_axis = rank - 2; + for (uint32_t axis = 0; axis < rank; ++axis) + { + if (axis != depth_axis && node->dim(axis).value() != 1) + return false; + } + return node->dim(depth_axis).value() == depth; +} + +bool is_instance_mean_v0(luci::CircleMean *mean) { // // CHECK 1) input is rank 4 @@ -175,7 +190,53 @@ bool is_instance_mean(luci::CircleMean *mean) return mean->keep_dims(); } -} // namespace +bool is_instance_mean_v1(luci::CircleMean *mean) +{ + // + // CHECK 1) input is rank 5 (NHWCX) + // + auto input = mean->input(); + if (not loco::shape_known(input)) + return false; + auto input_shape = loco::shape_get(input).as<loco::TensorShape>(); + if (input_shape.rank() != 5) + return false; + + // + // CHECK 2) 'reduction indices' is CircleConst of value [1,2,4], that is HWX of NHWCX input shape + // + // TODO Support equivalent case, like [-3,-2] + // TODO Support non-Const case? + // TODO What if input is NCHW format in Circle? + auto red_indices = dynamic_cast<luci::CircleConst *>(mean->reduction_indices()); + if (not red_indices) + return false; + if (red_indices->rank() != 1) + return false; + std::set<int32_t> red_indices_set; + + // TODO Currently only support S32, support other types + if (red_indices->dtype() != loco::DataType::S32) + return false; + for (uint32_t i = 0; i < red_indices->dim(0).value(); ++i) + red_indices_set.insert(red_indices->at<loco::DataType::S32>(i)); + + if (red_indices_set.size() != 3) + return false; + if (red_indices_set.find(1) == red_indices_set.end()) + return false; + if (red_indices_set.find(2) == red_indices_set.end()) + return false; + if (red_indices_set.find(4) == red_indices_set.end()) + return false; + + // + // CHECK 3) keep_dims == true (?) + // + // We only have case of 'keep_dims == true' so far, but it might be okay with 'keep_dims == false' + // TODO Check this fact, and if true, return true regardless of keep_dims + return mean->keep_dims(); +} // Helper to fuse Instance Norm namespace @@ -227,14 +288,61 @@ namespace * | * V * [Out] + *------------------------------------------------------------------- + * [In] + * | + * V + * ifm + * | + * V + * +---------reshape_of_ifm ----+ (reduction indicies) + * | | | | + * | | V V + * | | mean_of_reshape -------------+ + * | V | | + * | sqdiff <--+ (reduction indicies) | + * | | | | + * | V | | + * | mean_as_variance <---+ const_as_epsilon | + * | | | | + * | V | | + * | add_as_variance <--------+ | + * | | | + * | V | + * | rsqrt const_as_gamma | + * | | | | + * | V | | + * | mul_gamma <--+ | + * | | | | + * V V V | + * mul_as_scaled_reshape mul_as_scaled_mean <-----------+ + * | | + * | const_as_beta | + * | | V + * | +------> sub + * V | + * add_as_terminal <----------+ + * | + * V + * reshape_as_terminal + * | + * V + * [Out] */ class InstanceNormPattern final { public: - InstanceNormPattern(luci::CircleAdd *candidate) + enum PatternVersion + { + Version_0, + Version_1 + }; + + InstanceNormPattern(luci::CircleAdd *candidate, PatternVersion pv) { assert(candidate); add_as_terminal = candidate; + _pv = pv; } public: @@ -244,7 +352,9 @@ public: public: // Context loco::Node *ifm = nullptr; + luci::CircleReshape *reshape_of_ifm = nullptr; luci::CircleMean *mean_of_ifm = nullptr; + luci::CircleMean *mean_of_reshape = nullptr; luci::CircleSquaredDifference *sqdiff = nullptr; luci::CircleMean *mean_as_variance = nullptr; luci::CircleConst *const_as_epsilon = nullptr; @@ -254,12 +364,14 @@ public: luci::CircleMul *mul_gamma = nullptr; luci::CircleMul *mul_as_scaled_ifm = nullptr; luci::CircleMul *mul_as_scaled_mean = nullptr; + luci::CircleMul *mul_as_scaled_reshape = nullptr; luci::CircleConst *const_as_beta = nullptr; luci::CircleSub *sub = nullptr; luci::CircleAdd *add_as_terminal = nullptr; private: bool _matched = false; + PatternVersion _pv; }; bool InstanceNormPattern::matched() @@ -273,8 +385,18 @@ bool InstanceNormPattern::matched() // Check order is DFS - CHECK_OR_FALSE(fill(&mul_as_scaled_ifm, &sub).with_commutative_args_of(add_as_terminal)); - CHECK_OR_FALSE(fill(&ifm, &mul_gamma).with_commutative_args_of(mul_as_scaled_ifm)); + if (_pv == PatternVersion::Version_0) + { + CHECK_OR_FALSE(fill(&mul_as_scaled_ifm, &sub).with_commutative_args_of(add_as_terminal)); + CHECK_OR_FALSE(fill(&ifm, &mul_gamma).with_commutative_args_of(mul_as_scaled_ifm)); + } + if (_pv == PatternVersion::Version_1) + { + CHECK_OR_FALSE(fill(&mul_as_scaled_reshape, &sub).with_commutative_args_of(add_as_terminal)); + CHECK_OR_FALSE( + fill(&reshape_of_ifm, &mul_gamma).with_commutative_args_of(mul_as_scaled_reshape)); + ifm = reshape_of_ifm->tensor(); + } CHECK_OR_FALSE(loco::shape_known(ifm)); auto ifm_shape = loco::shape_get(ifm); @@ -284,7 +406,15 @@ bool InstanceNormPattern::matched() uint32_t ifm_channel_depth = ifm_tensor_shape.dim(3).value(); CHECK_OR_FALSE(fill(&rsqrt, &const_as_gamma).with_commutative_args_of(mul_gamma)); - CHECK_OR_FALSE(is_1D_with_dummy_dim(const_as_gamma, ifm_channel_depth)); + + if (_pv == PatternVersion::Version_0) + { + CHECK_OR_FALSE(is_1D_with_dummy_dim(const_as_gamma, ifm_channel_depth)); + } + if (_pv == PatternVersion::Version_1) + { + CHECK_OR_FALSE(is_quasi_1D_with_dummy_dim(const_as_gamma, ifm_channel_depth)); + } add_as_variance = dynamic_cast<luci::CircleAdd *>(rsqrt->x()); CHECK_OR_FALSE(add_as_variance); @@ -296,29 +426,69 @@ bool InstanceNormPattern::matched() // TODO Support regarding broadcast CHECK_OR_FALSE(const_as_epsilon->size<loco::DataType::FLOAT32>() == 1); - CHECK_OR_FALSE(is_instance_mean(mean_as_variance)); + if (_pv == PatternVersion::Version_0) + { + CHECK_OR_FALSE(is_instance_mean_v0(mean_as_variance)); + } + if (_pv == PatternVersion::Version_1) + { + CHECK_OR_FALSE(is_instance_mean_v1(mean_as_variance)); + } + sqdiff = dynamic_cast<luci::CircleSquaredDifference *>(mean_as_variance->input()); CHECK_OR_FALSE(sqdiff); - loco::Node *ifm_should_be = nullptr; - CHECK_OR_FALSE(fill(&ifm_should_be, &mean_of_ifm).with_commutative_args_of(sqdiff)); - CHECK_OR_FALSE(ifm == ifm_should_be); - CHECK_OR_FALSE(is_instance_mean(mean_of_ifm)); - CHECK_OR_FALSE(ifm == mean_of_ifm->input()); + if (_pv == PatternVersion::Version_0) + { + loco::Node *ifm_should_be = nullptr; + CHECK_OR_FALSE(fill(&ifm_should_be, &mean_of_ifm).with_commutative_args_of(sqdiff)); + CHECK_OR_FALSE(ifm == ifm_should_be); + CHECK_OR_FALSE(is_instance_mean_v0(mean_of_ifm)); + CHECK_OR_FALSE(ifm == mean_of_ifm->input()); + } + if (_pv == PatternVersion::Version_1) + { + loco::Node *reshape_should_be = nullptr; + CHECK_OR_FALSE(fill(&reshape_should_be, &mean_of_reshape).with_commutative_args_of(sqdiff)); + CHECK_OR_FALSE(reshape_of_ifm == reshape_should_be); + CHECK_OR_FALSE(is_instance_mean_v1(mean_of_reshape)); + CHECK_OR_FALSE(reshape_of_ifm == mean_of_reshape->input()); + } const_as_beta = dynamic_cast<luci::CircleConst *>(sub->x()); CHECK_OR_FALSE(const_as_beta); - CHECK_OR_FALSE(is_1D_with_dummy_dim(const_as_beta, ifm_channel_depth)); + + if (_pv == PatternVersion::Version_0) + { + CHECK_OR_FALSE(is_1D_with_dummy_dim(const_as_beta, ifm_channel_depth)); + } + if (_pv == PatternVersion::Version_1) + { + CHECK_OR_FALSE(is_quasi_1D_with_dummy_dim(const_as_beta, ifm_channel_depth)); + } mul_as_scaled_mean = dynamic_cast<luci::CircleMul *>(sub->y()); CHECK_OR_FALSE(mul_as_scaled_mean); luci::CircleMul *mul_gamma_should_be = nullptr; luci::CircleMean *mean_of_ifm_should_be = nullptr; - CHECK_OR_FALSE(fill(&mul_gamma_should_be, &mean_of_ifm_should_be) - .with_commutative_args_of(mul_as_scaled_mean)); - CHECK_OR_FALSE(mul_gamma == mul_gamma_should_be); - CHECK_OR_FALSE(mean_of_ifm == mean_of_ifm_should_be); + luci::CircleMean *mean_of_reshape_should_be = nullptr; + + if (_pv == PatternVersion::Version_0) + { + CHECK_OR_FALSE(fill(&mul_gamma_should_be, &mean_of_ifm_should_be) + .with_commutative_args_of(mul_as_scaled_mean)); + CHECK_OR_FALSE(mul_gamma == mul_gamma_should_be); + CHECK_OR_FALSE(mean_of_ifm == mean_of_ifm_should_be); + } + if (_pv == PatternVersion::Version_1) + { + CHECK_OR_FALSE(fill(&mul_gamma_should_be, &mean_of_reshape_should_be) + .with_commutative_args_of(mul_as_scaled_mean)); + CHECK_OR_FALSE(mul_gamma == mul_gamma_should_be); + CHECK_OR_FALSE(mean_of_reshape == mean_of_reshape_should_be); + } + #undef CHECK_OR_FALSE _matched = true; return true; @@ -381,13 +551,28 @@ namespace luci bool FuseInstanceNormPass::run(loco::Graph *g) { bool changed = false; + luci::CircleAdd *add; + InstanceNormPattern::PatternVersion pv; + for (auto node : loco::active_nodes(loco::output_nodes(g))) { - auto add = dynamic_cast<luci::CircleAdd *>(node); - if (not add) - continue; + auto reshape = dynamic_cast<luci::CircleReshape *>(node); + if (not reshape) + { + add = dynamic_cast<luci::CircleAdd *>(node); + if (not add) + continue; + pv = InstanceNormPattern::PatternVersion::Version_0; + } + else + { + add = dynamic_cast<luci::CircleAdd *>(reshape->tensor()); + if (not add) + continue; + pv = InstanceNormPattern::PatternVersion::Version_1; + } - InstanceNormPattern pattern(add); + InstanceNormPattern pattern(add, pv); if (not pattern.matched()) continue; diff --git a/compiler/luci/pass/src/FuseInstanceNormPass.test.cpp b/compiler/luci/pass/src/FuseInstanceNormPass.test.cpp new file mode 100644 index 000000000..3037f3def --- /dev/null +++ b/compiler/luci/pass/src/FuseInstanceNormPass.test.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FuseInstanceNormPassInternal.h" + +#include <vector> + +#include <gtest/gtest.h> + +namespace +{ + +void setShape(luci::CircleNode &node, const std::vector<int> &v) +{ + node.rank(v.size()); + for (int i = 0; i < v.size(); ++i) + { + node.dim(i) = v[i]; + } +} + +} // namespace + +TEST(FuseInstanceNormPass, is_quasi_1D_with_dummy_dim) +{ + luci::CircleConst const_node; + + setShape(const_node, {}); + EXPECT_FALSE(is_quasi_1D_with_dummy_dim(&const_node, 8)); + + setShape(const_node, {1}); + EXPECT_FALSE(is_quasi_1D_with_dummy_dim(&const_node, 8)); + + setShape(const_node, {8}); + EXPECT_FALSE(is_quasi_1D_with_dummy_dim(&const_node, 8)); + + setShape(const_node, {1, 2, 1, 8, 1}); + EXPECT_FALSE(is_quasi_1D_with_dummy_dim(&const_node, 8)); + + setShape(const_node, {8, 3}); + EXPECT_FALSE(is_quasi_1D_with_dummy_dim(&const_node, 8)); + + setShape(const_node, {8, 1}); + EXPECT_FALSE(is_quasi_1D_with_dummy_dim(&const_node, 8)); + + setShape(const_node, {1, 8, 1}); + EXPECT_TRUE(is_quasi_1D_with_dummy_dim(&const_node, 8)); + + setShape(const_node, {1, 1, 1, 8, 1}); + EXPECT_TRUE(is_quasi_1D_with_dummy_dim(&const_node, 8)); +} diff --git a/compiler/luci/pass/src/FuseInstanceNormPassInternal.h b/compiler/luci/pass/src/FuseInstanceNormPassInternal.h new file mode 100644 index 000000000..32b638ba5 --- /dev/null +++ b/compiler/luci/pass/src/FuseInstanceNormPassInternal.h @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_CIRCLE_FUSE_INSTANCE_NORM_PASS_INTERNAL_H__ +#define __LUCI_CIRCLE_FUSE_INSTANCE_NORM_PASS_INTERNAL_H__ + +#include <luci/IR/CircleNodes.h> + +/// @return true When node has shape of '1 x .. x 1 x depth' +bool is_1D_with_dummy_dim(luci::CircleConst *node, uint32_t depth); + +/// @return true When node has shape of '1 x .. x depth x 1' +bool is_quasi_1D_with_dummy_dim(luci::CircleConst *node, uint32_t depth); + +#endif // __LUCI_CIRCLE_FUSE_INSTANCE_NORM_PASS_INTERNAL_H__ diff --git a/compiler/luci/pass/src/QuantizationUtils.cpp b/compiler/luci/pass/src/QuantizationUtils.cpp new file mode 100644 index 000000000..6726ce746 --- /dev/null +++ b/compiler/luci/pass/src/QuantizationUtils.cpp @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "QuantizationUtils.h" + +#include <luci/Log.h> + +#include <iostream> +#include <cmath> + +namespace luci +{ + +void compute_sym_scale_zp(float min, float max, float &scaling_factor, int64_t &zp, + float &nudged_min, float &nudged_max) +{ + assert(min != max); + + const int32_t kMaxScale = std::numeric_limits<int16_t>::max(); + const int32_t kMinScale = -kMaxScale; + const double qmin_double = kMinScale; + const double qmax_double = kMaxScale; + const double rmin = std::fmin(0, min); + const double rmax = std::fmax(0, max); + double scale_factor_from_min_side{0}; + double scale_factor_from_max_side{0}; + + if ((qmin_double * rmin) > 0) + scale_factor_from_min_side = rmin / qmin_double; + + if ((qmax_double * rmax) > 0) + scale_factor_from_max_side = rmax / qmax_double; + + scaling_factor = scale_factor_from_min_side > scale_factor_from_max_side + ? scale_factor_from_min_side + : scale_factor_from_max_side; + zp = 0; + nudged_min = static_cast<float>(qmin_double * scaling_factor); + nudged_max = static_cast<float>(qmax_double * scaling_factor); +} + +void compute_asym_scale_zp(float min, float max, float &scaling_factor, int64_t &zp, + float &nudged_min, float &nudged_max) +{ + LOGGER(l); + + assert(min <= max); + const int32_t kMinScale = 0; + const int32_t kMaxScale = 255; + const double qmin_double = kMinScale; + const double qmax_double = kMaxScale; + const double rmin = std::fmin(0, min); + const double rmax = std::fmax(0, max); + + double scale = (rmax - rmin) / (qmax_double - qmin_double); + double zero_point_double = 0; + uint8_t nudged_zero_point = 0; + if (scale == 0) + { + WARN(l) << "The minimum and maximum values are the same." << std::endl; + if (min >= 0 && max >= 0) + zero_point_double = kMinScale; + else + zero_point_double = kMaxScale; + } + else + zero_point_double = qmin_double - rmin / scale; + if (zero_point_double <= qmin_double) + { + assert(min >= 0 && max >= 0); + nudged_zero_point = kMinScale; + scale = max / (qmax_double - qmin_double); + if (min > 0 && max > 0) + WARN(l) << "The minimum and maximum values are all positive." << std::endl; + } + else if (zero_point_double >= qmax_double) + { + assert(min < 0 && max < 0); + nudged_zero_point = kMaxScale; + scale = -min / (qmax_double - qmin_double); + WARN(l) << "The minimum and maximum values are all negative." << std::endl; + } + else + { + assert(min < 0 && max >= 0); + nudged_zero_point = static_cast<uint8_t>(std::round(zero_point_double)); + } + + nudged_min = static_cast<float>((qmin_double - nudged_zero_point) * scale); + nudged_max = static_cast<float>((qmax_double - nudged_zero_point) * scale); + + scaling_factor = scale; + zp = nudged_zero_point; +} + +bool get_channel_dim_index(CircleConst *node, loco::TensorShape &dimension, int &channel_dim_index) +{ + auto succs = loco::succs(node); + if (succs.size() != 1) // assume weights is used by only one node + return false; + + for (auto out : succs) + { + auto conv = dynamic_cast<CircleConv2D *>(out); + auto dw_conv = dynamic_cast<CircleDepthwiseConv2D *>(out); + auto tw_conv = dynamic_cast<CircleTransposeConv *>(out); + auto fc = dynamic_cast<CircleFullyConnected *>(out); + + // Refer to https://github.com/Samsung/ONE/pull/2448. + if ((conv != nullptr && conv->filter() == node) || + (tw_conv != nullptr && tw_conv->filter() == node)) // OHWI + { + assert(node->rank() == 4); + dimension.dim(0).set(node->dim(0).value()); + dimension.dim(1).set(node->dim(1).value()); + dimension.dim(2).set(node->dim(2).value()); + dimension.dim(3).set(node->dim(3).value()); + channel_dim_index = 0; // Set channel_dim_index based on "O" + return true; + } + else if (dw_conv != nullptr && dw_conv->filter() == node) // IHWC + { + assert(node->rank() == 4); + dimension.dim(0).set(node->dim(0).value()); + dimension.dim(1).set(node->dim(1).value()); + dimension.dim(2).set(node->dim(2).value()); + dimension.dim(3).set(node->dim(3).value()); + channel_dim_index = 3; // Set channel_dim_index based on "C" + return true; + } + else if (fc != nullptr && fc->weights() == node) // OI + { + assert(node->rank() == 2); + dimension.dim(0).set(node->dim(0).value()); + dimension.dim(1).set(1); // Set FC layer like CONV + dimension.dim(2).set(1); + dimension.dim(3).set(node->dim(1).value()); + channel_dim_index = 0; // Set channel_dim_index based on "O" + return true; + } + else + { + // node does not support channle-wise quantization + assert(false); + } + } + + return false; +} + +uint32_t cal_offset(loco::TensorShape &dimension, uint32_t *indices) +{ + return indices[0] * dimension.dim(1).value() * dimension.dim(2).value() * + dimension.dim(3).value() + + indices[1] * dimension.dim(2).value() * dimension.dim(3).value() + + indices[2] * dimension.dim(3).value() + indices[3]; +} + +} // namespace luci diff --git a/compiler/luci/pass/src/QuantizationUtils.h b/compiler/luci/pass/src/QuantizationUtils.h new file mode 100644 index 000000000..ec0e86df8 --- /dev/null +++ b/compiler/luci/pass/src/QuantizationUtils.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __LUCI_QUANTIZATION_UTILS_H__ +#define __LUCI_QUANTIZATION_UTILS_H__ + +#include <luci/IR/CircleNodes.h> +#include <loco/IR/TensorShape.h> + +namespace luci +{ + +void compute_sym_scale_zp(float min, float max, float &scaling_factor, int64_t &zp, + float &nudged_min, float &nudged_max); + +void compute_asym_scale_zp(float min, float max, float &scaling_factor, int64_t &zp, + float &nudged_min, float &nudged_max); + +bool get_channel_dim_index(CircleConst *node, loco::TensorShape &dimension, int &channel_dim_index); + +uint32_t cal_offset(loco::TensorShape &dimension, uint32_t *indices); + +} // namespace luci + +#endif // __LUCI_QUANTIZATION_UTILS_H__ diff --git a/compiler/luci/pass/src/QuantizeDequantizeWeightsPass.cpp b/compiler/luci/pass/src/QuantizeDequantizeWeightsPass.cpp new file mode 100644 index 000000000..c492234c7 --- /dev/null +++ b/compiler/luci/pass/src/QuantizeDequantizeWeightsPass.cpp @@ -0,0 +1,495 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2019 The TensorFlow Authors. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Pass/QuantizeDequantizeWeightsPass.h" +#include "QuantizationUtils.h" + +#include <luci/IR/CircleNodes.h> +#include <luci/IR/CircleNodeVisitor.h> +#include <luci/Log.h> +#include <loco/IR/TensorShape.h> + +#include <iostream> +#include <cmath> + +namespace luci +{ + +namespace +{ + +void cal_minmax_per_channel(CircleConst *node, std::vector<float> &min, std::vector<float> &max) +{ + loco::TensorShape dimension; + dimension.rank(4); + uint32_t indices[4] = { + 0, + }; + int channel_dim_index{0}; + int size{0}; + + if (!get_channel_dim_index(node, dimension, channel_dim_index)) + { + assert(false); + return; + } + size = dimension.dim(channel_dim_index).value(); + + std::vector<bool> has_min_max_value(size, false); + min.resize(size); + max.resize(size); + for (indices[0] = 0; indices[0] < dimension.dim(0).value(); indices[0]++) + { + for (indices[1] = 0; indices[1] < dimension.dim(1).value(); indices[1]++) + { + for (indices[2] = 0; indices[2] < dimension.dim(2).value(); indices[2]++) + { + for (indices[3] = 0; indices[3] < dimension.dim(3).value(); indices[3]++) + { + int channel_idx = indices[channel_dim_index]; + auto data = node->at<loco::DataType::FLOAT32>(cal_offset(dimension, indices)); + if (has_min_max_value[channel_idx]) + { + min[channel_idx] = data < min[channel_idx] ? data : min[channel_idx]; + max[channel_idx] = data > max[channel_idx] ? data : max[channel_idx]; + } + else + { + min[channel_idx] = data; + max[channel_idx] = data; + has_min_max_value[channel_idx] = true; + } + } + } + } + } +} + +void sym_wquant_per_channel(CircleConst *node, std::vector<float> &min, std::vector<float> &max, + std::vector<float> &scaling_factor, std::vector<int64_t> &zp, + std::vector<float> &nudged_min, std::vector<float> &nudged_max) +{ + assert(node->dtype() == loco::DataType::FLOAT32); + const int32_t kMaxScale = std::numeric_limits<int16_t>::max(); + const int32_t kMinScale = -kMaxScale; + + uint32_t size = node->size<loco::DataType::FLOAT32>(); + std::vector<int32_t> quantized_values(size); + + for (size_t i = 0; i < min.size(); ++i) + { + compute_sym_scale_zp(min[i], max[i], scaling_factor[i], zp[i], nudged_min[i], nudged_max[i]); + } + + loco::TensorShape dimension; + dimension.rank(4); + uint32_t indices[4] = { + 0, + }; + int channel_dim_index{0}; + + if (!get_channel_dim_index(node, dimension, channel_dim_index)) + { + assert(false); + return; + } + + for (indices[0] = 0; indices[0] < dimension.dim(0).value(); indices[0]++) + { + for (indices[1] = 0; indices[1] < dimension.dim(1).value(); indices[1]++) + { + for (indices[2] = 0; indices[2] < dimension.dim(2).value(); indices[2]++) + { + for (indices[3] = 0; indices[3] < dimension.dim(3).value(); indices[3]++) + { + int channel_idx = indices[channel_dim_index]; + const float scaling_factor_inv = 1.0 / scaling_factor[channel_idx]; + auto data = node->at<loco::DataType::FLOAT32>(cal_offset(dimension, indices)); + data = data < nudged_min[channel_idx] ? nudged_min[channel_idx] : data; + data = data > nudged_max[channel_idx] ? nudged_max[channel_idx] : data; + quantized_values[cal_offset(dimension, indices)] = + static_cast<int32_t>(std::round(data * scaling_factor_inv)); + } + } + } + } + + node->dtype(loco::DataType::S16); // change the type of tensor + node->size<loco::DataType::S16>(size); // resize tensor + for (uint32_t i = 0; i < size; ++i) + { + node->at<loco::DataType::S16>(i) = + std::min(kMaxScale, std::max(kMinScale, quantized_values[i])); + } +} + +void sym_wdequant_per_channel(CircleConst *node, std::vector<float> &scaling_factor) +{ + assert(node->dtype() == loco::DataType::S16); + uint32_t size = node->size<loco::DataType::S16>(); + std::vector<float> dequantized_values(size); + + loco::TensorShape dimension; + dimension.rank(4); + uint32_t indices[4] = { + 0, + }; + int channel_dim_index{0}; + + if (!get_channel_dim_index(node, dimension, channel_dim_index)) + { + assert(false); + return; + } + + for (indices[0] = 0; indices[0] < dimension.dim(0).value(); indices[0]++) + { + for (indices[1] = 0; indices[1] < dimension.dim(1).value(); indices[1]++) + { + for (indices[2] = 0; indices[2] < dimension.dim(2).value(); indices[2]++) + { + for (indices[3] = 0; indices[3] < dimension.dim(3).value(); indices[3]++) + { + int channel_idx = indices[channel_dim_index]; + auto data = node->at<loco::DataType::S16>(cal_offset(dimension, indices)); + dequantized_values[cal_offset(dimension, indices)] = + static_cast<float>(data) * scaling_factor[channel_idx]; + } + } + } + } + + node->dtype(loco::DataType::FLOAT32); // change the type of tensor + node->size<loco::DataType::FLOAT32>(size); // resize tensor + for (uint32_t i = 0; i < size; ++i) + { + node->at<loco::DataType::FLOAT32>(i) = dequantized_values[i]; + } +} + +void asymmetric_wquant_per_channel(CircleConst *node, std::vector<float> &min, + std::vector<float> &max, std::vector<float> &scaling_factor, + std::vector<int64_t> &zp, std::vector<float> &nudged_min, + std::vector<float> &nudged_max) +{ + assert(node->dtype() == loco::DataType::FLOAT32); + + const int32_t kMinScale = 0; + const int32_t kMaxScale = 255; + + uint32_t size = node->size<loco::DataType::FLOAT32>(); + std::vector<int32_t> quantized_values(size); + + for (size_t i = 0; i < min.size(); ++i) + { + compute_asym_scale_zp(min[i], max[i], scaling_factor[i], zp[i], nudged_min[i], nudged_max[i]); + } + + loco::TensorShape dimension; + dimension.rank(4); + uint32_t indices[4] = { + 0, + }; + int channel_dim_index{0}; + + if (!get_channel_dim_index(node, dimension, channel_dim_index)) + { + assert(false); + return; + } + + for (indices[0] = 0; indices[0] < dimension.dim(0).value(); indices[0]++) + { + for (indices[1] = 0; indices[1] < dimension.dim(1).value(); indices[1]++) + { + for (indices[2] = 0; indices[2] < dimension.dim(2).value(); indices[2]++) + { + for (indices[3] = 0; indices[3] < dimension.dim(3).value(); indices[3]++) + { + int channel_idx = indices[channel_dim_index]; + const float scaling_factor_inv = 1.0 / scaling_factor[channel_idx]; + auto data = node->at<loco::DataType::FLOAT32>(cal_offset(dimension, indices)); + data = data < nudged_min[channel_idx] ? nudged_min[channel_idx] : data; + data = data > nudged_max[channel_idx] ? nudged_max[channel_idx] : data; + quantized_values[cal_offset(dimension, indices)] = static_cast<int32_t>( + std::round((data - nudged_min[channel_idx]) * scaling_factor_inv)); + } + } + } + } + + node->dtype(loco::DataType::U8); // change the type of tensor + node->size<loco::DataType::U8>(size); // resize tensor + for (uint32_t i = 0; i < size; ++i) + { + node->at<loco::DataType::U8>(i) = std::min(kMaxScale, std::max(kMinScale, quantized_values[i])); + } +} + +void asymmetric_wdequant_per_channel(CircleConst *node, std::vector<float> &scaling_factor, + std::vector<float> &nudged_min) +{ + assert(node->dtype() == loco::DataType::U8); + uint32_t size = node->size<loco::DataType::U8>(); + std::vector<float> dequantized_values(size); + + loco::TensorShape dimension; + dimension.rank(4); + uint32_t indices[4] = { + 0, + }; + int channel_dim_index{0}; + + if (!get_channel_dim_index(node, dimension, channel_dim_index)) + { + assert(false); + return; + } + + for (indices[0] = 0; indices[0] < dimension.dim(0).value(); indices[0]++) + { + for (indices[1] = 0; indices[1] < dimension.dim(1).value(); indices[1]++) + { + for (indices[2] = 0; indices[2] < dimension.dim(2).value(); indices[2]++) + { + for (indices[3] = 0; indices[3] < dimension.dim(3).value(); indices[3]++) + { + int channel_idx = indices[channel_dim_index]; + auto data = node->at<loco::DataType::U8>(cal_offset(dimension, indices)); + dequantized_values[cal_offset(dimension, indices)] = + static_cast<float>(data) * scaling_factor[channel_idx] + nudged_min[channel_idx]; + } + } + } + } + + node->dtype(loco::DataType::FLOAT32); // change the type of tensor + node->size<loco::DataType::FLOAT32>(size); // resize tensor + for (uint32_t i = 0; i < size; ++i) + { + node->at<loco::DataType::FLOAT32>(i) = dequantized_values[i]; + } +} + +void asymmetric_wquant_with_minmax_per_layer(CircleConst *node, float min, float max, + float &scaling_factor, int64_t &zp, float &nudged_min, + float &nudged_max) +{ + + const int32_t kMinScale = 0; + const int32_t kMaxScale = 255; + + uint32_t size = node->size<loco::DataType::FLOAT32>(); + compute_asym_scale_zp(min, max, scaling_factor, zp, nudged_min, nudged_max); + const float scaling_factor_inv = 1.0 / scaling_factor; + std::vector<int32_t> quantized_values(size); + for (uint32_t i = 0; i < size; ++i) + { + // clipping + auto data = node->at<loco::DataType::FLOAT32>(i); + data = data < nudged_min ? nudged_min : data; + data = data > nudged_max ? nudged_max : data; + quantized_values[i] = + static_cast<int32_t>(std::round((data - nudged_min) * scaling_factor_inv)); + } + + node->dtype(loco::DataType::U8); // change the type of tensor + node->size<loco::DataType::U8>(size); // resize tensor + for (uint32_t i = 0; i < size; ++i) + { + node->at<loco::DataType::U8>(i) = std::min(kMaxScale, std::max(kMinScale, quantized_values[i])); + } +} + +void asymmetric_wdequant_with_minmax_per_layer(CircleConst *node, float scaling_factor, + float nudged_min) +{ + uint32_t size = node->size<loco::DataType::U8>(); + std::vector<float> dequantized_values(size); + for (uint32_t i = 0; i < size; ++i) + { + auto data = node->at<loco::DataType::U8>(i); + dequantized_values[i] = static_cast<float>(data) * scaling_factor + nudged_min; + } + + node->dtype(loco::DataType::FLOAT32); // change the type of tensor + node->size<loco::DataType::FLOAT32>(size); // resize tensor + for (uint32_t i = 0; i < size; ++i) + { + node->at<loco::DataType::FLOAT32>(i) = dequantized_values[i]; + } +} + +bool is_quantized(const CircleNode *node) +{ + return node->dtype() == loco::DataType::U8 || // activation, weight + node->dtype() == loco::DataType::S16 || // activation, weight + node->dtype() == loco::DataType::S32; // bias +} + +// Check if node is weights of conv2d, transepose_conv2d, depthwise_conv2d, or fully_connected layer +bool is_weights(CircleNode *node) +{ + auto circle_const = dynamic_cast<CircleConst *>(node); + if (circle_const == nullptr) + return false; + + auto succs = loco::succs(node); + if (succs.size() != 1) // assume weights is used by only one node + return false; + + for (auto out : succs) + { + auto conv = dynamic_cast<CircleConv2D *>(out); + if (conv != nullptr && conv->filter() == circle_const && circle_const->rank() == 4) + return true; + + auto dw_conv = dynamic_cast<CircleDepthwiseConv2D *>(out); + if (dw_conv != nullptr && dw_conv->filter() == circle_const && circle_const->rank() == 4) + return true; + + auto tw_conv = dynamic_cast<CircleTransposeConv *>(out); + if (tw_conv != nullptr && tw_conv->filter() == circle_const && circle_const->rank() == 4) + return true; + + auto fc = dynamic_cast<CircleFullyConnected *>(out); + if (fc != nullptr && fc->weights() == circle_const && circle_const->rank() == 2) + return true; + } + return false; +} + +/** + * @brief QuantizeDequantizeWeights quantizes and dequantizes tensors for weights + * @details Find min/max values on the fly, quantize the model, and dequantize the model + */ +struct QuantizeDequantizeWeights final : public luci::CircleNodeMutableVisitor<bool> +{ + QuantizeDequantizeWeights(loco::DataType input, loco::DataType output, + QuantizationGranularity granularity) + : input_type(input), output_type(output), granularity(granularity) + { + } + + loco::DataType input_type; + loco::DataType output_type; + QuantizationGranularity granularity; + + // Quantize and dequantize input tensors of each node + bool visit(luci::CircleNode *node) + { + assert(output_type == loco::DataType::U8 || output_type == loco::DataType::S16); + LOGGER(l); + INFO(l) << "QuantizeDequantizeWeights visit node: " << node->name() << std::endl; + auto arity = node->arity(); + for (uint32_t i = 0; i < arity; i++) + { + auto input_node = node->arg(i); + auto circle_node = loco::must_cast<luci::CircleNode *>(input_node); + + // Check if this is already quantized + if (is_quantized(circle_node)) + continue; + + if (is_weights(circle_node)) + { + auto circle_const = loco::must_cast<luci::CircleConst *>(circle_node); + + // Find min/max per channel-wise + if (granularity == QuantizationGranularity::ChannelWise) + { + std::vector<float> min; + std::vector<float> max; + + cal_minmax_per_channel(circle_const, min, max); + + std::vector<float> nudged_min(min.size()); + std::vector<float> nudged_max(min.size()); + std::vector<float> scaling_factor(min.size()); + std::vector<int64_t> zp(min.size()); + + if (output_type == loco::DataType::U8) + { + asymmetric_wquant_per_channel(circle_const, min, max, scaling_factor, zp, nudged_min, + nudged_max); + asymmetric_wdequant_per_channel(circle_const, scaling_factor, nudged_min); + } + else + { + sym_wquant_per_channel(circle_const, min, max, scaling_factor, zp, nudged_min, + nudged_max); + sym_wdequant_per_channel(circle_const, scaling_factor); + } + + auto quantparam = std::make_unique<CircleQuantParam>(); + quantparam->min = nudged_min; + quantparam->max = nudged_max; + quantparam->scale = scaling_factor; + quantparam->zerop = zp; + circle_node->quantparam(std::move(quantparam)); + } + // Find min/max per layer-wise + else + { + float min = std::numeric_limits<float>::max(); + float max = std::numeric_limits<float>::lowest(); + for (uint32_t i = 0; i < circle_const->size<loco::DataType::FLOAT32>(); i++) + { + auto data = circle_const->at<loco::DataType::FLOAT32>(i); + min = data < min ? data : min; + max = data > max ? data : max; + } + float scaling_factor{0}; + int64_t zp{0}; + float nudged_min{0}; + float nudged_max{0}; + + asymmetric_wquant_with_minmax_per_layer(circle_const, min, max, scaling_factor, zp, + nudged_min, nudged_max); + asymmetric_wdequant_with_minmax_per_layer(circle_const, scaling_factor, nudged_min); + auto quantparam = std::make_unique<CircleQuantParam>(); + quantparam->min.push_back(nudged_min); + quantparam->max.push_back(nudged_max); + quantparam->scale.push_back(scaling_factor); + quantparam->zerop.push_back(zp); + circle_node->quantparam(std::move(quantparam)); + } + } + } + return false; + } +}; + +} // namespace + +bool QuantizeDequantizeWeightsPass::run(loco::Graph *g) +{ + LOGGER(l); + INFO(l) << "QuantizeDequantizeWeightsPass Start" << std::endl; + + // Quantize weights + for (auto node : loco::active_nodes(loco::output_nodes(g))) + { + QuantizeDequantizeWeights qw(_input_dtype, _output_dtype, _granularity); + auto circle_node = loco::must_cast<luci::CircleNode *>(node); + circle_node->accept(&qw); + } + + INFO(l) << "QuantizeDequantizeWeightsPass End" << std::endl; + return false; // one time run +} + +} // namespace luci diff --git a/compiler/luci/pass/src/QuantizeWithMinMaxPass.cpp b/compiler/luci/pass/src/QuantizeWithMinMaxPass.cpp new file mode 100644 index 000000000..f8abee751 --- /dev/null +++ b/compiler/luci/pass/src/QuantizeWithMinMaxPass.cpp @@ -0,0 +1,551 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2019 The TensorFlow Authors. All Rights Reserved. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Pass/QuantizeWithMinMaxPass.h" +#include "QuantizationUtils.h" + +#include <luci/IR/CircleNodes.h> +#include <luci/IR/CircleNodeVisitor.h> +#include <luci/Log.h> + +#include <oops/UserExn.h> + +#include <iostream> +#include <cmath> + +namespace luci +{ + +namespace +{ + +// Check if the node is the bias of Conv2D, DepthwiseConv2D, or FullyConnected layer +// If true, return <input, weight> pair of the successor node (used to quantize bias) +// If flase, return <nullptr, nullptr> +std::pair<loco::Node *, loco::Node *> get_input_weight_of_bias(CircleNode *node) +{ + auto circle_const = dynamic_cast<CircleConst *>(node); + if (circle_const == nullptr) + return std::make_pair(nullptr, nullptr); + + auto succs = loco::succs(node); + if (succs.size() != 1) // assume bias is used by only one node + return std::make_pair(nullptr, nullptr); + + for (auto out : succs) + { + auto conv = dynamic_cast<CircleConv2D *>(out); + if (conv != nullptr && conv->bias() == circle_const) + { + assert(conv->input() != nullptr); + assert(conv->filter() != nullptr); + return std::make_pair(conv->input(), conv->filter()); + } + auto dw_conv = dynamic_cast<CircleDepthwiseConv2D *>(out); + if (dw_conv != nullptr && dw_conv->bias() == circle_const) + { + assert(dw_conv->input() != nullptr); + assert(dw_conv->filter() != nullptr); + return std::make_pair(dw_conv->input(), dw_conv->filter()); + } + auto fc = dynamic_cast<CircleFullyConnected *>(out); + if (fc != nullptr && fc->bias() == circle_const) + { + assert(fc->input() != nullptr); + assert(fc->weights() != nullptr); + return std::make_pair(fc->input(), fc->weights()); + } + } + return std::make_pair(nullptr, nullptr); +} + +void asym_quant_bias_per_layer(CircleConst *node, float input_scale, float weight_scale, + float *scaling_factor, int64_t *zp) +{ + float scale = input_scale * weight_scale; + const float scaling_factor_inv = (scale == 0) ? 0 : 1.0 / scale; + + uint32_t size = node->size<loco::DataType::FLOAT32>(); + std::vector<int32_t> quantized_values(size); + for (uint32_t i = 0; i < size; ++i) + { + quantized_values[i] = + static_cast<int32_t>(std::round(node->at<loco::DataType::FLOAT32>(i) * scaling_factor_inv)); + } + + node->dtype(loco::DataType::S32); // change the type of tensor + node->size<loco::DataType::S32>(size); // resize tensor + const int32_t kMinScale = std::numeric_limits<int32_t>::lowest(); + const int32_t kMaxScale = std::numeric_limits<int32_t>::max(); + for (uint32_t i = 0; i < size; ++i) + { + node->at<loco::DataType::S32>(i) = + std::min(kMaxScale, std::max(kMinScale, quantized_values[i])); + } + *scaling_factor = scale; + *zp = 0; +} + +void quant_bias_per_channel(CircleConst *node, float input_scale, std::vector<float> &weight_scale, + std::vector<float> &scaling_factor, std::vector<int64_t> &zp) +{ + float scaling_factor_inv{0}; + + uint32_t size = node->size<loco::DataType::FLOAT32>(); + std::vector<int32_t> quantized_values(size); + + for (uint32_t i = 0; i < size; ++i) + { + scaling_factor[i] = input_scale * weight_scale[i]; + scaling_factor_inv = (scaling_factor[i] == 0) ? 0 : 1.0 / scaling_factor[i]; + quantized_values[i] = + static_cast<int32_t>(std::round(node->at<loco::DataType::FLOAT32>(i) * scaling_factor_inv)); + zp[i] = 0; + } + + node->dtype(loco::DataType::S32); // change the type of tensor + node->size<loco::DataType::S32>(size); // resize tensor + const int32_t kMinScale = std::numeric_limits<int32_t>::lowest(); + const int32_t kMaxScale = std::numeric_limits<int32_t>::max(); + for (uint32_t i = 0; i < size; ++i) + { + node->at<loco::DataType::S32>(i) = + std::min(kMaxScale, std::max(kMinScale, quantized_values[i])); + } +} + +bool has_min_max(const CircleNode *node) +{ + return node->quantparam() && !node->quantparam()->min.empty() && !node->quantparam()->max.empty(); +} + +bool is_quantized(const CircleNode *node) +{ + return node->dtype() == loco::DataType::U8 || // activation, weight + node->dtype() == loco::DataType::S32; // bias +} + +void sym_wquant_per_channel(CircleConst *node, std::vector<float> &scaling_factor) +{ + assert(node->dtype() == loco::DataType::FLOAT32); + + const int32_t kMaxScale = std::numeric_limits<int16_t>::max(); + const int32_t kMinScale = -kMaxScale; + + uint32_t size = node->size<loco::DataType::FLOAT32>(); + std::vector<int32_t> quantized_values(size); + + loco::TensorShape dimension; + dimension.rank(4); + uint32_t indices[4] = { + 0, + }; + int channel_dim_index{0}; + + if (!get_channel_dim_index(node, dimension, channel_dim_index)) + { + assert(false); + return; + } + + for (indices[0] = 0; indices[0] < dimension.dim(0).value(); indices[0]++) + { + for (indices[1] = 0; indices[1] < dimension.dim(1).value(); indices[1]++) + { + for (indices[2] = 0; indices[2] < dimension.dim(2).value(); indices[2]++) + { + for (indices[3] = 0; indices[3] < dimension.dim(3).value(); indices[3]++) + { + int channel_idx = indices[channel_dim_index]; + const float scaling_factor_inv = 1.0 / scaling_factor[channel_idx]; + auto data = node->at<loco::DataType::FLOAT32>(cal_offset(dimension, indices)); + quantized_values[cal_offset(dimension, indices)] = + static_cast<int32_t>(std::round(data * scaling_factor_inv)); + } + } + } + } + + node->dtype(loco::DataType::S16); // change the type of tensor + node->size<loco::DataType::S16>(size); // resize tensor + for (uint32_t i = 0; i < size; ++i) + { + node->at<loco::DataType::S16>(i) = + std::min(kMaxScale, std::max(kMinScale, quantized_values[i])); + } +} + +void asym_wquant_per_channel(CircleConst *node, std::vector<float> &min, + std::vector<float> &scaling_factor) +{ + assert(node->dtype() == loco::DataType::FLOAT32); + + const int32_t kMinScale = 0; + const int32_t kMaxScale = 255; + + uint32_t size = node->size<loco::DataType::FLOAT32>(); + std::vector<int32_t> quantized_values(size); + + loco::TensorShape dimension; + dimension.rank(4); + uint32_t indices[4] = { + 0, + }; + int channel_dim_index{0}; + + if (!get_channel_dim_index(node, dimension, channel_dim_index)) + { + assert(false); + return; + } + + for (indices[0] = 0; indices[0] < dimension.dim(0).value(); indices[0]++) + { + for (indices[1] = 0; indices[1] < dimension.dim(1).value(); indices[1]++) + { + for (indices[2] = 0; indices[2] < dimension.dim(2).value(); indices[2]++) + { + for (indices[3] = 0; indices[3] < dimension.dim(3).value(); indices[3]++) + { + int channel_idx = indices[channel_dim_index]; + const float scaling_factor_inv = 1.0 / scaling_factor[channel_idx]; + auto data = node->at<loco::DataType::FLOAT32>(cal_offset(dimension, indices)); + quantized_values[cal_offset(dimension, indices)] = + static_cast<int32_t>(std::round((data - min[channel_idx]) * scaling_factor_inv)); + } + } + } + } + + node->dtype(loco::DataType::U8); // change the type of tensor + node->size<loco::DataType::U8>(size); // resize tensor + for (uint32_t i = 0; i < size; ++i) + { + node->at<loco::DataType::U8>(i) = std::min(kMaxScale, std::max(kMinScale, quantized_values[i])); + } +} + +void asym_wquant_per_layer(CircleConst *node, float min, float scaling_factor) +{ + const int32_t kMinScale = 0; + const int32_t kMaxScale = 255; + + uint32_t size = node->size<loco::DataType::FLOAT32>(); + + const float scaling_factor_inv = 1.0 / scaling_factor; + std::vector<int32_t> quantized_values(size); + for (uint32_t i = 0; i < size; ++i) + { + auto data = node->at<loco::DataType::FLOAT32>(i); + quantized_values[i] = static_cast<int32_t>(std::round((data - min) * scaling_factor_inv)); + } + + node->dtype(loco::DataType::U8); // change the type of tensor + node->size<loco::DataType::U8>(size); // resize tensor + for (uint32_t i = 0; i < size; ++i) + { + node->at<loco::DataType::U8>(i) = std::min(kMaxScale, std::max(kMinScale, quantized_values[i])); + } +} + +// Check if node is weights of conv2d, depthwise_conv2d, or fully_connected layer +bool is_weights(CircleNode *node) +{ + auto circle_const = dynamic_cast<CircleConst *>(node); + if (circle_const == nullptr) + return false; + + auto succs = loco::succs(node); + if (succs.size() != 1) // assume weights is used by only one node + return false; + + for (auto out : succs) + { + auto conv = dynamic_cast<CircleConv2D *>(out); + if (conv != nullptr && conv->filter() == circle_const) + return true; + + auto dw_conv = dynamic_cast<CircleDepthwiseConv2D *>(out); + if (dw_conv != nullptr && dw_conv->filter() == circle_const) + return true; + + auto fc = dynamic_cast<CircleFullyConnected *>(out); + if (fc != nullptr && fc->weights() == circle_const) + return true; + } + return false; +} + +/** + * @brief QuantizeActivation quantizes tensors for activations + * @details Quantize using recorded min/max values + */ +struct QuantizeActivation final : public luci::CircleNodeMutableVisitor<bool> +{ + QuantizeActivation(loco::DataType input, loco::DataType output) + : input_type(input), output_type(output) + { + } + + loco::DataType input_type; + loco::DataType output_type; + + // Quantize input tensors of each node + bool visit(luci::CircleNode *node) + { + LOGGER(l); + INFO(l) << "QuantizeActivation visit node: " << node->name() << std::endl; + auto arity = node->arity(); + for (uint32_t i = 0; i < arity; i++) + { + auto input_node = node->arg(i); + auto circle_node = loco::must_cast<luci::CircleNode *>(input_node); + + // Check if this is already quantized + if (is_quantized(circle_node)) + continue; + + // Check if this is bias (bias is quantized later) + auto iw = get_input_weight_of_bias(circle_node); + if (iw.first != nullptr && iw.second != nullptr) + continue; + + // Check if this is activation + // We assume min/max are recorded only for activations + if (has_min_max(circle_node) && !is_weights(circle_node)) + { + // Quantize using recorded min/max + auto quantparam = circle_node->quantparam(); + assert(quantparam->min.size() == 1); // only support layer-wise quant + assert(quantparam->max.size() == 1); // only support layer-wise quant + auto min = quantparam->min[0]; + auto max = quantparam->max[0]; + + float scaling_factor{0}; + int64_t zp{0}; + float nudged_min{0}; + float nudged_max{0}; + + if (output_type == loco::DataType::U8) + { + compute_asym_scale_zp(min, max, scaling_factor, zp, nudged_min, nudged_max); + circle_node->dtype(loco::DataType::U8); + } + else + { + compute_sym_scale_zp(min, max, scaling_factor, zp, nudged_min, nudged_max); + circle_node->dtype(loco::DataType::S16); + } + + circle_node->quantparam()->max[0] = nudged_max; + circle_node->quantparam()->min[0] = nudged_min; + circle_node->quantparam()->scale.push_back(scaling_factor); + circle_node->quantparam()->zerop.push_back(zp); + } + } + return false; + } +}; + +struct QuantizeBias final : public luci::CircleNodeMutableVisitor<bool> +{ + QuantizeBias(loco::DataType input, loco::DataType output, QuantizationGranularity gr) + : input_type(input), output_type(output), granularity(gr) + { + } + + loco::DataType input_type; + loco::DataType output_type; + QuantizationGranularity granularity; + + // Quantize bias node + bool visit(luci::CircleNode *node) + { + // Check if this is already quantized + if (is_quantized(node)) + return false; + + // Check if this is bias + auto iw = get_input_weight_of_bias(node); + if (iw.first == nullptr || iw.second == nullptr) + return false; + + auto input = loco::must_cast<luci::CircleNode *>(iw.first); + auto weight = loco::must_cast<luci::CircleNode *>(iw.second); + + if (granularity == QuantizationGranularity::ChannelWise) + { + assert(input->quantparam()->scale.size() == 1); // input scale's layer-wise + auto input_scale = input->quantparam()->scale[0]; + + assert(weight->quantparam() != nullptr); // weight scale's channel-wise + auto weight_scale = weight->quantparam()->scale; + + auto circle_const = loco::must_cast<luci::CircleConst *>(node); + + uint32_t size = circle_const->size<loco::DataType::FLOAT32>(); + assert(size == weight_scale.size()); + std::vector<float> scaling_factor(size); + std::vector<int64_t> zp(size); + + quant_bias_per_channel(circle_const, input_scale, weight_scale, scaling_factor, zp); + + auto quantparam = std::make_unique<CircleQuantParam>(); + quantparam->scale = scaling_factor; + quantparam->zerop = zp; + assert(circle_const->quantparam() == nullptr); // bias should not be quantized before + circle_const->quantparam(std::move(quantparam)); + } + else + { + assert(input->quantparam()->scale.size() == 1); // Only support per-layer quant + auto input_scale = input->quantparam()->scale[0]; + + assert(weight->quantparam()->scale.size() == 1); // Only support per-layer quant + auto weight_scale = weight->quantparam()->scale[0]; + + auto circle_const = loco::must_cast<luci::CircleConst *>(node); + float scaling_factor{0}; + int64_t zp{0}; + asym_quant_bias_per_layer(circle_const, input_scale, weight_scale, &scaling_factor, &zp); + auto quantparam = std::make_unique<CircleQuantParam>(); + quantparam->scale.push_back(scaling_factor); + quantparam->zerop.push_back(zp); + assert(circle_const->quantparam() == nullptr); // bias should not be quantized before + circle_const->quantparam(std::move(quantparam)); + } + return false; + } +}; + +/** + * @brief QuantizeWeights quantizes tensors for weights + * @details Find min/max values on the fly and then quantize + */ +struct QuantizeWeights final : public luci::CircleNodeMutableVisitor<bool> +{ + QuantizeWeights(loco::DataType input, loco::DataType output, QuantizationGranularity gr) + : input_type(input), output_type(output), granularity(gr) + { + } + + loco::DataType input_type; + loco::DataType output_type; + QuantizationGranularity granularity; + + // Quantize input tensors of each node + bool visit(luci::CircleNode *node) + { + LOGGER(l); + INFO(l) << "QuantizeWeights visit node: " << node->name() << std::endl; + auto arity = node->arity(); + for (uint32_t i = 0; i < arity; i++) + { + auto input_node = node->arg(i); + auto circle_node = loco::must_cast<luci::CircleNode *>(input_node); + + // Check if this is already quantized + if (is_quantized(circle_node)) + continue; + + if (is_weights(circle_node)) + { + auto circle_const = loco::must_cast<luci::CircleConst *>(circle_node); + + // Find min/max per channel-wise + if (granularity == QuantizationGranularity::ChannelWise) + { + auto quantparam = circle_node->quantparam(); + assert(quantparam != nullptr); + auto min = quantparam->min; + auto scaling_factor = quantparam->scale; + + if (output_type == loco::DataType::U8) + { + asym_wquant_per_channel(circle_const, min, scaling_factor); + } + else + { + sym_wquant_per_channel(circle_const, scaling_factor); + } + } + // Find min/max per layer-wise + else + { + // Quantize using recorded quantparam + auto quantparam = circle_node->quantparam(); + assert(quantparam != nullptr); + assert(quantparam->min.size() == 1); // only support layer-wise quant + assert(quantparam->scale.size() == 1); // only support layer-wise quant + auto min = quantparam->min[0]; + auto scaling_factor = quantparam->scale[0]; + asym_wquant_per_layer(circle_const, min, scaling_factor); + } + } + } + return false; + } +}; + +} // namespace + +bool QuantizeWithMinMaxPass::run(loco::Graph *g) +{ + LOGGER(l); + INFO(l) << "QuantizeWithMinMaxPass Start" << std::endl; + + // Quantize activation + for (auto node : loco::active_nodes(loco::output_nodes(g))) + { + QuantizeActivation qa(_input_dtype, _output_dtype); + auto circle_node = loco::must_cast<luci::CircleNode *>(node); + circle_node->accept(&qa); + } + + // Quantize weights + for (auto node : loco::active_nodes(loco::output_nodes(g))) + { + QuantizeWeights qw(_input_dtype, _output_dtype, _granularity); + auto circle_node = loco::must_cast<luci::CircleNode *>(node); + circle_node->accept(&qw); + } + + // Quantize bias + for (auto node : loco::active_nodes(loco::output_nodes(g))) + { + QuantizeBias qb(_input_dtype, _output_dtype, _granularity); + auto circle_node = loco::must_cast<luci::CircleNode *>(node); + circle_node->accept(&qb); + } + + // Update output dtype + auto graph_outputs = g->outputs(); + for (auto node : loco::output_nodes(g)) + { + auto circle_node = loco::must_cast<luci::CircleOutput *>(node); + if (static_cast<luci::CircleNode *>(circle_node->from())->dtype() == _output_dtype) + { + circle_node->dtype(_output_dtype); + auto graph_output = graph_outputs->at(circle_node->index()); + graph_output->dtype(_output_dtype); + } + } + + INFO(l) << "QuantizeWithMinMaxPass End" << std::endl; + return false; // one time run +} + +} // namespace luci diff --git a/compiler/luci/pass/src/ResolveCustomOpAddPass.cpp b/compiler/luci/pass/src/ResolveCustomOpAddPass.cpp new file mode 100644 index 000000000..e52d667d7 --- /dev/null +++ b/compiler/luci/pass/src/ResolveCustomOpAddPass.cpp @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Pass/ResolveCustomOpAddPass.h" + +#include "flatbuffers/flexbuffers.h" + +#include <luci/IR/CircleNodes.h> +#include <luci/IR/AttrFusedActFunc.h> + +namespace +{ + +/// @brief Returns the index of BroadcastTo node among cop's inputs. +// NOTE This function assumes there is only one BroadcastTo node among its inputs. +int32_t get_broadcastTo_index_among_inputs_of(luci::CircleCustom *cop) +{ + for (uint32_t idx = 0; idx < cop->numInputs(); idx++) + { + auto input = dynamic_cast<const luci::CircleCustomOut *>(cop->inputs(idx)); + if (input) + { + auto broadcastTo = loco::must_cast<luci::CircleCustom *>(input->input()); + if (broadcastTo->custom_code() == "BroadcastTo") + return idx; + } + } + + return -1; +} + +/** BEFORE + * [CircleConst] + * | + * [CircleNode] [BroadcastTo(CircleCustom)] + * \ | + * \ [CircleCustomOUt] + * \ / + * [AddV2(CircleCustom)] + * AFTER + * + * [CircleConst] [CircleNode] + * \ / + * \ / + * [CircleAdd] + */ +bool resolve_with_BroadcastTo(luci::CircleCustom *addv2) +{ + int32_t broadcastTo_idx = get_broadcastTo_index_among_inputs_of(addv2); + + if (broadcastTo_idx == -1) + return false; + + auto input = loco::must_cast<const luci::CircleCustomOut *>(addv2->inputs(broadcastTo_idx)); + auto broadcastTo = loco::must_cast<luci::CircleCustom *>(input->input()); + + auto add = addv2->graph()->nodes()->create<luci::CircleAdd>(); + add->fusedActivationFunction(luci::FusedActFunc::NONE); + add->x(addv2->inputs(1 - broadcastTo_idx)); + add->y(broadcastTo->inputs(0)); + auto customOut = loco::succs(addv2); + assert(customOut.size() == 1); + replace(*customOut.begin()).with(add); + + return true; +} + +bool resolve_custom_op(luci::CircleCustom *addv2) +{ + const std::string custom_code = addv2->custom_code(); + const std::vector<uint8_t> custom_options = addv2->custom_options(); + + if (custom_code != "AddV2") + return false; + + if (resolve_with_BroadcastTo(addv2)) + return true; + + auto add = addv2->graph()->nodes()->create<luci::CircleAdd>(); + add->fusedActivationFunction(luci::FusedActFunc::NONE); + add->x(addv2->inputs(0)); + add->y(addv2->inputs(1)); + auto customOut = loco::succs(addv2); + assert(customOut.size() == 1); + replace(*customOut.begin()).with(add); + + return true; +} + +} // namespace + +namespace luci +{ + +bool ResolveCustomOpAddPass::run(loco::Graph *g) +{ + bool changed = false; + + for (auto node : loco::active_nodes(loco::output_nodes(g))) + { + auto cop = dynamic_cast<luci::CircleCustom *>(node); + if (not cop) + continue; + + changed |= resolve_custom_op(cop); + } + + return changed; +} + +} // namespace luci diff --git a/compiler/luci/pass/src/ResolveCustomOpBatchMatMulPass.cpp b/compiler/luci/pass/src/ResolveCustomOpBatchMatMulPass.cpp new file mode 100644 index 000000000..145e9cb62 --- /dev/null +++ b/compiler/luci/pass/src/ResolveCustomOpBatchMatMulPass.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Pass/ResolveCustomOpBatchMatMulPass.h" + +#include "flatbuffers/flexbuffers.h" + +#include <luci/IR/CircleNodes.h> + +namespace +{ + +bool resolve_custom_op(luci::CircleCustom *cop) +{ + const std::string custom_code = cop->custom_code(); + const std::vector<uint8_t> custom_options = cop->custom_options(); + + if (custom_code == "BatchMatMulV2") + { + auto batch_matmul = cop->graph()->nodes()->create<luci::CircleBatchMatMul>(); + // input + batch_matmul->x(cop->inputs(0)); + batch_matmul->y(cop->inputs(1)); + // TODO find much better way of parsing custom_options + // adj + auto map = flexbuffers::GetRoot(custom_options).AsMap(); + batch_matmul->adj_x(map["adj_x"].AsBool()); + batch_matmul->adj_y(map["adj_y"].AsBool()); + + replace(cop).with(batch_matmul); + return true; + } + return false; +} + +} // namespace + +namespace luci +{ + +bool ResolveCustomOpBatchMatMulPass::run(loco::Graph *g) +{ + bool changed = false; + for (auto node : loco::active_nodes(loco::output_nodes(g))) + { + auto cop = dynamic_cast<luci::CircleCustom *>(node); + if (not cop) + continue; + + changed |= resolve_custom_op(cop); + } + + return changed; +} + +} // namespace luci diff --git a/compiler/luci/pass/src/ResolveCustomOpMatMulPass.cpp b/compiler/luci/pass/src/ResolveCustomOpMatMulPass.cpp new file mode 100644 index 000000000..547fd22fc --- /dev/null +++ b/compiler/luci/pass/src/ResolveCustomOpMatMulPass.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "luci/Pass/ResolveCustomOpMatMulPass.h" + +#include "flatbuffers/flexbuffers.h" +#include <loco/IR/DataTypeTraits.h> + +#include <luci/IR/CircleNodes.h> + +#include <loco.h> +#include <oops/InternalExn.h> +#include <loco/Service/ShapeInference.h> +#include <loco/Service/TypeInference.h> + +namespace +{ + +template <typename T> +luci::CircleConst *create_const_node(loco::Graph *g, const loco::DataType dtype, + const std::vector<uint32_t> &shape, + const std::vector<T> &values) +{ + auto node = g->nodes()->create<luci::CircleConst>(); + node->dtype(dtype); + node->rank(shape.size()); + + uint32_t size = 1; + for (uint32_t i = 0; i < shape.size(); ++i) + { + node->dim(i) = shape.at(i); + size *= shape.at(i); + } + +#define INIT_VALUES(DT) \ + { \ + node->size<DT>(size); \ + for (uint32_t i = 0; i < values.size(); ++i) \ + node->at<DT>(i) = values[i]; \ + } + + switch (dtype) + { + case loco::DataType::U8: + INIT_VALUES(loco::DataType::U8); + break; + case loco::DataType::S16: + INIT_VALUES(loco::DataType::S16); + break; + case loco::DataType::S32: + INIT_VALUES(loco::DataType::S32); + break; + case loco::DataType::FLOAT32: + INIT_VALUES(loco::DataType::FLOAT32) + break; + default: + INTERNAL_EXN("create_const_node called with unsupported type"); + break; + } + return node; +} + +bool resolve_matmul(luci::CircleCustom *cop) +{ +#define CHECK_OR_FALSE(condition) \ + if (not(condition)) \ + return false; +#define CHECK_OR_THROW(condition, message) \ + if (not(condition)) \ + INTERNAL_EXN(message); + + auto graph = cop->graph(); + const std::vector<uint8_t> custom_options = cop->custom_options(); + auto map = flexbuffers::GetRoot(custom_options).AsMap(); + const auto U8 = loco::DataType::U8; + const auto S16 = loco::DataType::S16; + const auto S32 = loco::DataType::S32; + const auto FLOAT32 = loco::DataType::FLOAT32; + + bool transpose_a = map["transpose_a"].AsBool(); + bool transpose_b = map["transpose_b"].AsBool(); + + loco::Node *lhs = cop->inputs(0); + loco::Node *rhs = cop->inputs(1); + + // Check that the type of the first input is known + CHECK_OR_FALSE(loco::dtype_known(lhs)); + auto lhs_dtype = loco::dtype_get(cop->inputs(0)); + + // If transpose of first input is requested, its shape must be known + CHECK_OR_FALSE(!transpose_a || loco::shape_known(lhs)); + // and its rank should be at least 2 + CHECK_OR_FALSE(!transpose_a || loco::shape_get(lhs).as<loco::TensorShape>().rank() >= 2); + // Check that the shape of the 2nd input is known + CHECK_OR_FALSE(loco::shape_known(rhs)); + // TODO as of 06/23/20 TFLite only supports rank 2 for 2nd input. Fix this once that changes! + CHECK_OR_FALSE(loco::shape_get(rhs).as<loco::TensorShape>().rank() == 2); + // Check that input data type is supported + CHECK_OR_THROW(lhs_dtype == U8 || lhs_dtype == S16 || lhs_dtype == FLOAT32, + "Only UInt8, Int16 and Float32 data types are supported by MatMul"); + + if (transpose_a) + { + auto a_shape = loco::shape_get(lhs).as<loco::TensorShape>(); + // Create a permutation constant node + std::vector<uint32_t> perm; + for (uint32_t i = 0; i < a_shape.rank(); ++i) + perm.push_back(i); + std::swap(perm[a_shape.rank() - 1], perm[a_shape.rank() - 2]); + auto perm_node = create_const_node(graph, S32, {a_shape.rank()}, perm); + // Now make a transpose node + auto transpose_node = graph->nodes()->create<luci::CircleTranspose>(); + transpose_node->a(lhs); + transpose_node->perm(perm_node); + lhs = transpose_node; + } + + // Transpose the second input if needed. TFLite FullyConnected operator + // assumes the second input is in column-major order, but the input is + // in row-major order, thus we need to convert between them. + if (!transpose_b) + { + const std::vector<uint32_t> perm{1, 0}; + auto perm_node = create_const_node(graph, S32, {2}, perm); + auto transpose_node = graph->nodes()->create<luci::CircleTranspose>(); + transpose_node->a(rhs); + transpose_node->perm(perm_node); + rhs = transpose_node; + } + + // Make a constant zero-filled bias node + auto b_shape = loco::shape_get(cop->inputs(1)).as<loco::TensorShape>(); + uint32_t bias_size = b_shape.dim(transpose_b ? 1 : 0).value(); + const std::vector<float> val(bias_size, .0f); + auto bias_node = create_const_node(graph, lhs_dtype, {bias_size}, val); + auto fc_node = graph->nodes()->create<luci::CircleFullyConnected>(); + fc_node->input(lhs); + fc_node->weights(rhs); + fc_node->bias(bias_node); + fc_node->fusedActivationFunction(luci::FusedActFunc::NONE); + + replace(cop).with(fc_node); + return true; +} + +} // namespace + +namespace luci +{ + +bool ResolveCustomOpMatMulPass::run(loco::Graph *g) +{ + bool changed = false; + for (auto node : loco::active_nodes(loco::output_nodes(g))) + { + auto cop = dynamic_cast<luci::CircleCustom *>(node); + if (not cop) + continue; + + if (cop->custom_code() != "MatMul") + continue; + + if (!resolve_matmul(cop)) + continue; + + changed = true; + } + + return changed; +} + +} // namespace luci diff --git a/compiler/luci/requires.cmake b/compiler/luci/requires.cmake index e88dabd24..e52523d45 100644 --- a/compiler/luci/requires.cmake +++ b/compiler/luci/requires.cmake @@ -1,5 +1,7 @@ +require("foder") require("loco") require("locop") +require("logo") require("logo-core") require("mio-circle") require("oops") diff --git a/compiler/luci/service/src/CircleShapeInference.cpp b/compiler/luci/service/src/CircleShapeInference.cpp index fdcfa76bc..0732849db 100644 --- a/compiler/luci/service/src/CircleShapeInference.cpp +++ b/compiler/luci/service/src/CircleShapeInference.cpp @@ -27,11 +27,8 @@ namespace luci ShapeDescription ShapeInference::get(loco::Node *node) { - // TODO Adjust indentation level - { - assert(loco::shape_known(node)); - return to_shape_description(loco::shape_get(node)); - } + assert(loco::shape_known(node)); + return to_shape_description(loco::shape_get(node)); } } // namespace luci diff --git a/compiler/luci/service/src/CircleShapeInferenceRule.cpp b/compiler/luci/service/src/CircleShapeInferenceRule.cpp index c8e872b1e..a291cfe70 100644 --- a/compiler/luci/service/src/CircleShapeInferenceRule.cpp +++ b/compiler/luci/service/src/CircleShapeInferenceRule.cpp @@ -17,6 +17,8 @@ #include "luci/Service/CircleShapeInferenceRule.h" #include "Check.h" +#include "ShapeInfer_StridedSlice.h" + #include <luci/IR/CircleNodes.h> #include <luci/IR/CircleDialect.h> #include <luci/IR/CircleNodeVisitor.h> @@ -26,11 +28,25 @@ #include <algorithm> #include <cassert> +#include <cmath> #include <stdexcept> namespace { +std::ostream &operator<<(std::ostream &os, const loco::TensorShape &tensor_shape) +{ + os << "["; + for (uint32_t r = 0; r < tensor_shape.rank(); ++r) + { + if (r) + os << ","; + os << tensor_shape.dim(r).value(); + } + os << "]"; + return os; +} + // Call this for CircleAvgPool2D and CircleMaxPool2D only template <class Pool2DType> loco::NodeShape infer_pool_2d_shape(const Pool2DType *node) { @@ -176,6 +192,157 @@ loco::TensorShape broadcast_shape(const loco::TensorShape &x, const loco::Tensor return output_shape; } +// BatchMatMulV2 supports broadcasting in the batch dimensions(BatchMatMul doesn't) +// TODO Distinguish BatchMatMul and BatchMatMulV2 +loco::NodeShape infer_batchmatmul_shape(const loco::TensorShape &x_shape, + const loco::TensorShape &y_shape, bool adj_x, bool adj_y) +{ + uint32_t x_rank = x_shape.rank(); + uint32_t y_rank = y_shape.rank(); + assert(x_rank >= 2 && y_rank >= 2); + + loco::TensorShape output_shape; + output_shape.rank(x_shape.rank()); + // Braodcast in the batch dimension + if (x_rank > 2 || y_rank > 2) + { + loco::TensorShape dummy_x = x_shape; + loco::TensorShape dummy_y = y_shape; + expand_rank(dummy_x, dummy_y); + if (x_rank < y_rank) + expand_rank(output_shape, dummy_y); + + for (uint32_t d = 0; d < output_shape.rank() - 2; d++) + { + uint32_t max_dim = std::max(dummy_x.dim(d).value(), dummy_y.dim(d).value()); + if (dummy_x.dim(d) == dummy_y.dim(d) || + dummy_x.dim(d).value() * dummy_y.dim(d).value() == max_dim) + output_shape.dim(d).set(max_dim); + else + INTERNAL_EXN("BatchMatMul has wrong shape"); + } + } + + loco::Dimension x_lhs = adj_x ? x_shape.dim(x_rank - 1) : x_shape.dim(x_rank - 2); + loco::Dimension x_rhs = adj_x ? x_shape.dim(x_rank - 2) : x_shape.dim(x_rank - 1); + loco::Dimension y_lhs = adj_y ? y_shape.dim(y_rank - 1) : y_shape.dim(y_rank - 2); + loco::Dimension y_rhs = adj_y ? y_shape.dim(y_rank - 2) : y_shape.dim(y_rank - 1); + + if (not(x_rhs == y_lhs)) + INTERNAL_EXN("x_rhs and y_lhs should be same"); + + uint32_t out_rank = output_shape.rank(); + output_shape.dim(out_rank - 2) = x_lhs; + output_shape.dim(out_rank - 1) = y_rhs; + + return loco::NodeShape{output_shape}; +} + +loco::TensorShape own_shape(const luci::CircleNode *node) +{ + loco::TensorShape shape; + shape.rank(node->rank()); + for (uint32_t r = 0; r < node->rank(); ++r) + shape.dim(r) = loco::Dimension(node->dim(r).value()); + return shape; +} + +loco::TensorShape infer_reducer(const loco::Node *input, const loco::Node *indices, bool keep_dims) +{ + const loco::DataType S32 = loco::DataType::S32; + + auto input_shape = loco::shape_get(input).as<loco::TensorShape>(); + auto reduction_indices = loco::must_cast<const luci::CircleConst *>(indices); + + { // Exceptions + // TODO support non-const case + // TODO support other data type + LUCI_ASSERT(reduction_indices->dtype() == S32, "Only support int 32"); + } + + std::vector<int32_t> reduction_values; + + for (uint32_t i = 0; i < reduction_indices->size<S32>(); ++i) + { + int32_t axis = reduction_indices->at<S32>(i); + if (axis < 0) + axis += input_shape.rank(); + if (not(0 <= axis and axis < static_cast<int32_t>(input_shape.rank()))) + INTERNAL_EXN_V("Invalid reduction axis for REDUCER", oops::to_uint32(axis)); + reduction_values.push_back(axis); + } + + loco::TensorShape output_shape; + + if (keep_dims) + { + output_shape.rank(input_shape.rank()); + for (uint32_t i = 0; i < input_shape.rank(); ++i) + output_shape.dim(i) = input_shape.dim(i); + for (uint32_t i = 0; i < reduction_values.size(); ++i) + output_shape.dim(reduction_values.at(i)) = 1; + } + else + { + std::vector<bool> check_reduce(input_shape.rank(), false); + for (uint32_t i = 0; i < reduction_values.size(); ++i) + check_reduce.at(reduction_values.at(i)) = true; + + uint32_t reduce_cnt = 0; + for (uint32_t i = 0; i < check_reduce.size(); ++i) + if (check_reduce.at(i)) + ++reduce_cnt; + + output_shape.rank(input_shape.rank() - reduce_cnt); + for (uint32_t i = 0, j = 0; i < check_reduce.size(); ++i) + if (check_reduce.at(i) == false) + output_shape.dim(j++) = input_shape.dim(i); + } + + return output_shape; +} + +/** + * @brief vector_from_constant will return int64_t vector from CircleConst node + */ +template <loco::DataType T> std::vector<int64_t> vector_from_constant(luci::CircleConst *const_node) +{ + std::vector<int64_t> result; + + for (uint32_t idx = 0; idx < const_node->size<T>(); ++idx) + result.push_back(const_node->at<T>(idx)); + + return result; +} + +template <class CIRCLENODE> loco::NodeShape broadcast_xy(const CIRCLENODE *node) +{ + auto x_shape = loco::shape_get(node->x()).template as<loco::TensorShape>(); + auto y_shape = loco::shape_get(node->y()).template as<loco::TensorShape>(); + + auto output_shape = broadcast_shape(x_shape, y_shape); + + return loco::NodeShape{output_shape}; +} + +template <class CIRCLENODE> loco::NodeShape use_x(const CIRCLENODE *node) +{ + auto x_shape = loco::shape_get(node->x()).template as<loco::TensorShape>(); + return loco::NodeShape{x_shape}; +} + +template <class CIRCLENODE> loco::NodeShape use_logits(const CIRCLENODE *node) +{ + auto shape = loco::shape_get(node->logits()).template as<loco::TensorShape>(); + return loco::NodeShape{shape}; +} + +loco::NodeShape use_own(const luci::CircleNode *node) +{ + loco::TensorShape shape = own_shape(node); + return loco::NodeShape{shape}; +} + /** * @brief Class to infer the shape of CircleNode * @@ -184,20 +351,24 @@ loco::TensorShape broadcast_shape(const loco::TensorShape &x, const loco::Tensor class ShapeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::NodeShape> { public: - loco::NodeShape visit(const luci::CircleAbs *node) final - { - auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); - return loco::NodeShape{x_shape}; - } + loco::NodeShape visit(const luci::CircleAbs *node) final { return use_x(node); } - loco::NodeShape visit(const luci::CircleAdd *node) final + loco::NodeShape visit(const luci::CircleAdd *node) final { return broadcast_xy(node); } + + loco::NodeShape visit(const luci::CircleAddN *node) final { - auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); - auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>(); + auto shape = loco::shape_get(node->inputs(0)).as<loco::TensorShape>(); - auto output_shape = broadcast_shape(x_shape, y_shape); + for (uint32_t idx = 1; idx < node->arity(); ++idx) + { + auto shape_idx = loco::shape_get(node->inputs(idx)).as<loco::TensorShape>(); + if (!(shape == shape_idx)) + { + INTERNAL_EXN_V("ADD_N shape not same as the first input: ", idx); + } + } - return loco::NodeShape{output_shape}; + return loco::NodeShape{shape}; } loco::NodeShape visit(const luci::CircleArgMax *node) final @@ -211,8 +382,7 @@ public: // Only support node's shape() is CircleConst with S32/S64 // Support S32 for now. - auto const_shape_node = dynamic_cast<luci::CircleConst *>(node->dimension()); - LUCI_ASSERT(const_shape_node, "Only support CircleConst for shape of CircleArgMax"); + auto const_shape_node = loco::must_cast<luci::CircleConst *>(node->dimension()); LUCI_ASSERT(const_shape_node->dtype() == loco::DataType::S32, "Only support int32 CircleConst for CircleArgMax"); @@ -240,11 +410,58 @@ public: return loco::NodeShape{shape_output}; } + loco::NodeShape visit(const luci::CircleArgMin *node) final + { + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + auto dimension_shape = loco::shape_get(node->dimension()).as<loco::TensorShape>(); + + int64_t select_axis = 0; + { + LUCI_ASSERT(node->dimension(), "2nd input dimension() should not be nullptr"); + + // Only support node's shape() is CircleConst with S32/S64 + // Support S32 for now. + auto const_shape_node = loco::must_cast<luci::CircleConst *>(node->dimension()); + LUCI_ASSERT(const_shape_node->dtype() == loco::DataType::S32, + "Only support int32 CircleConst for CircleArgMin"); + + if (const_shape_node->rank() > 1) + INTERNAL_EXN_V("Only support rank 0/1 CircleConst", + oops::to_uint32(const_shape_node->rank())); + + select_axis = const_shape_node->scalar<loco::DataType::S32>(); + } + assert(select_axis < input_shape.rank()); + assert(select_axis >= 0); // TODO support minus of this breaks + + // NOTE select_axis is removed + loco::TensorShape shape_output; + uint32_t rank = input_shape.rank(); + uint32_t shrink = static_cast<uint32_t>(select_axis); + assert(rank > 0); + shape_output.rank(rank - 1); + for (uint32_t r = 0, d = 0; r < rank; ++r) + { + if (r == shrink) + continue; + shape_output.dim(d++) = input_shape.dim(r); + } + return loco::NodeShape{shape_output}; + } + loco::NodeShape visit(const luci::CircleAveragePool2D *node) final { return infer_pool_2d_shape(node); } + loco::NodeShape visit(const luci::CircleBatchMatMul *node) final + { + auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); + auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>(); + + return infer_batchmatmul_shape(x_shape, y_shape, node->adj_x(), node->adj_y()); + } + loco::NodeShape visit(const luci::CircleBatchToSpaceND *node) final { const loco::DataType S32 = loco::DataType::S32; @@ -254,14 +471,12 @@ public: assert(input_shape.rank() == 3 || input_shape.rank() == 4); // Only support block_shape() with S32 type CircleConst for now - auto const_block_shape = dynamic_cast<luci::CircleConst *>(node->block_shape()); - LUCI_ASSERT(const_block_shape, "Only support CircleConst for block_shape"); + auto const_block_shape = loco::must_cast<luci::CircleConst *>(node->block_shape()); LUCI_ASSERT(const_block_shape->dtype() == loco::DataType::S32, "Only support int32 block_shape"); // Only support crops() with S32 type CircleConst for now - auto const_crops = dynamic_cast<luci::CircleConst *>(node->crops()); - LUCI_ASSERT(const_crops, "Only support CircleConst for crops"); + auto const_crops = loco::must_cast<luci::CircleConst *>(node->crops()); LUCI_ASSERT(const_crops->dtype() == loco::DataType::S32, "Only support int32 crops"); auto const_block_shape_shape = loco::shape_get(const_block_shape).as<loco::TensorShape>(); @@ -295,6 +510,10 @@ public: return loco::NodeShape{shape_output}; } + loco::NodeShape visit(const luci::CircleCast *node) final { return use_x(node); } + + loco::NodeShape visit(const luci::CircleCeil *node) final { return use_x(node); } + loco::NodeShape visit(const luci::CircleConcatenation *node) final { // TODO Support when CircleConcatenation has 0 input @@ -330,16 +549,7 @@ public: return loco::NodeShape{output_shape}; } - loco::NodeShape visit(const luci::CircleConst *node) final - { - loco::TensorShape shape; - - shape.rank(node->rank()); - for (uint32_t axis = 0; axis < node->rank(); axis++) - shape.dim(axis) = node->dim(axis); - - return loco::NodeShape{shape}; - } + loco::NodeShape visit(const luci::CircleConst *node) final { return use_own(node); } loco::NodeShape visit(const luci::CircleConv2D *node) final { @@ -361,8 +571,8 @@ public: uint32_t stride_width = node->stride()->w(); uint32_t ker_height = ker_shape.dim(1).value(); uint32_t ker_width = ker_shape.dim(2).value(); - uint32_t dilation_height = 1; - uint32_t dilation_width = 1; + uint32_t dilation_height = node->dilation()->h(); + uint32_t dilation_width = node->dilation()->w(); uint32_t effective_ker_height = dilation_height * (ker_height - 1) + 1; uint32_t effective_ker_width = dilation_width * (ker_width - 1) + 1; @@ -392,11 +602,40 @@ public: return loco::NodeShape{ofm_shape}; } - loco::NodeShape visit(const luci::CircleCos *node) final + loco::NodeShape visit(const luci::CircleCos *node) final { return use_x(node); } + + loco::NodeShape visit(const luci::CircleCustom *node) final { return use_own(node); } + + loco::NodeShape visit(const luci::CircleDepthToSpace *node) final { - auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + LUCI_ASSERT(input_shape.rank() == 4, "Only input rank 4 is supported"); + + // Only data format NHWC is supported + // TODO need to clarify what to do with layout in this operator + int32_t height = input_shape.dim(1).value(); + int32_t width = input_shape.dim(2).value(); + int32_t depth = input_shape.dim(3).value(); + + int block_size = node->block_size(); + + if (block_size < 2) + INTERNAL_EXN("Block size must be >= 2"); + + if (depth % (block_size * block_size)) + { + INTERNAL_EXN("The input tensor's depth must be divisible by block_size^2"); + } - return loco::NodeShape{x_shape}; + loco::TensorShape output_shape; + output_shape.rank(4); + + output_shape.dim(0) = input_shape.dim(0).value(); + output_shape.dim(1) = height * block_size; + output_shape.dim(2) = width * block_size; + output_shape.dim(3) = depth / (block_size * block_size); + + return loco::NodeShape{output_shape}; } loco::NodeShape visit(const luci::CircleDepthwiseConv2D *node) final @@ -414,8 +653,8 @@ public: uint32_t stride_width = node->stride()->w(); uint32_t ker_height = ker_shape.dim(1).value(); uint32_t ker_width = ker_shape.dim(2).value(); - uint32_t dilation_height = 1; - uint32_t dilation_width = 1; + uint32_t dilation_height = node->dilation()->h(); + uint32_t dilation_width = node->dilation()->w(); uint32_t effective_ker_height = dilation_height * (ker_height - 1) + 1; uint32_t effective_ker_width = dilation_width * (ker_width - 1) + 1; @@ -445,30 +684,87 @@ public: return loco::NodeShape{ofm_shape}; } - loco::NodeShape visit(const luci::CircleDiv *node) final - { - auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); - auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>(); + loco::NodeShape visit(const luci::CircleDiv *node) final { return broadcast_xy(node); } - auto output_shape = broadcast_shape(x_shape, y_shape); + loco::NodeShape visit(const luci::CircleElu *node) final + { + auto input_shape = loco::shape_get(node->features()).as<loco::TensorShape>(); - return loco::NodeShape{output_shape}; + return loco::NodeShape{input_shape}; } - loco::NodeShape visit(const luci::CircleEqual *node) final + loco::NodeShape visit(const luci::CircleEqual *node) final { return broadcast_xy(node); } + + loco::NodeShape visit(const luci::CircleExp *node) final { return use_x(node); } + + loco::NodeShape visit(const luci::CircleExpandDims *node) final { - const auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); - const auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>(); - loco::TensorShape output_shape = broadcast_shape(x_shape, y_shape); + const loco::DataType S32 = loco::DataType::S32; + auto x_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + if (x_shape.rank() == 0) + { + // This maybe for unknown shape. We use shape from the node itself. + return use_own(node); + } + auto const_axis = loco::must_cast<luci::CircleConst *>(node->axis()); + LUCI_ASSERT(const_axis->dtype() == S32, "Only support int32 CircleConst for axis"); + if (const_axis->rank() != 0 && const_axis->rank() != 1) + { + INTERNAL_EXN_V("Non-scalar axis in OP", node->opnum()); + } + int32_t axis = const_axis->at<S32>(0); + LUCI_ASSERT((axis <= static_cast<int32_t>(x_shape.rank())) && + (axis >= -1 - static_cast<int32_t>(x_shape.rank())), + "Axis has to be between [-(D+1), D], where D is rank of input."); + size_t positive_axis = axis < 0 ? x_shape.rank() + axis + 1 : axis; + loco::TensorShape output_shape; + output_shape.rank(x_shape.rank() + 1); + size_t i = 0; + for (; i < positive_axis; i++) + output_shape.dim(i) = x_shape.dim(i); + output_shape.dim(i) = loco::Dimension(1); + for (; i < x_shape.rank(); i++) + output_shape.dim(i + 1) = x_shape.dim(i); return loco::NodeShape{output_shape}; } - loco::NodeShape visit(const luci::CircleExp *node) final + loco::NodeShape visit(const luci::CircleFill *node) final { - auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); - return loco::NodeShape{x_shape}; + loco::TensorShape shape; + { + LUCI_ASSERT(node->dims(), "dims input should not be nullptr"); + + auto dims_node = dynamic_cast<luci::CircleConst *>(node->dims()); + if (dims_node != nullptr) + { + // Only support node with S32 + LUCI_ASSERT(dims_node->dtype() == loco::DataType::S32, "Only support int32 CircleConst"); + + if (dims_node->rank() != 1) + INTERNAL_EXN_V("Only support rank 1 CircleConst", oops::to_uint32(dims_node->rank())); + + shape.rank(dims_node->dim(0).value()); + + for (uint32_t axis = 0; axis < shape.rank(); ++axis) + { + shape.dim(axis) = dims_node->at<loco::DataType::S32>(axis); + } + } + else + { + shape = own_shape(node); + } + } + + return loco::NodeShape{shape}; } + loco::NodeShape visit(const luci::CircleFloor *node) final { return use_x(node); } + + loco::NodeShape visit(const luci::CircleFloorDiv *node) final { return broadcast_xy(node); } + + loco::NodeShape visit(const luci::CircleFloorMod *node) final { return broadcast_xy(node); } + loco::NodeShape visit(const luci::CircleFullyConnected *node) final { auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); @@ -478,8 +774,11 @@ public: // Input: a tensor of at least rank 2 [D1, D2, ... Dn] // Weight: [# of units, K] // Output: [D1 * D2 * ... * Dn / K, # of units] - LUCI_ASSERT(input_shape.rank() >= 2, "Input rank should be at least 2"); - LUCI_ASSERT(weights_shape.rank() == 2, "Incompatible weights rank for fully connected"); + if (input_shape.rank() < 2 || weights_shape.rank() != 2) + { + // Return node own shape if shape inference is not possible + return use_own(node); + } uint32_t input_size = 1; for (uint32_t i = 0; i < input_shape.rank(); i++) @@ -495,28 +794,171 @@ public: return loco::NodeShape{out_shape}; } - loco::NodeShape visit(const luci::CircleLogicalNot *node) final + loco::NodeShape visit(const luci::CircleGather *node) final + { + loco::TensorShape output_shape; + + const auto input_shape = loco::shape_get(node->params()).as<loco::TensorShape>(); + const auto positions_shape = loco::shape_get(node->indices()).as<loco::TensorShape>(); + int32_t axis = node->axis(); + + // If CircleGather input has a dynamic shape, it can't inference this shape. So, it returns the + // shape that node already has. + if (input_shape.rank() == 0 || positions_shape.rank() == 0) + return use_own(node); + + if (axis < 0) + axis += input_shape.rank(); + + output_shape.rank(input_shape.rank() - 1 + positions_shape.rank()); + int32_t outdim_index = 0; + for (int32_t i = 0; i < axis; ++i) + output_shape.dim(outdim_index++) = input_shape.dim(i); + for (uint32_t i = 0; i < positions_shape.rank(); ++i) + output_shape.dim(outdim_index++) = positions_shape.dim(i); + for (uint32_t i = axis + 1; i < input_shape.rank(); ++i) + output_shape.dim(outdim_index++) = input_shape.dim(i); + + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleGatherNd *node) final + { + loco::TensorShape output_shape; + + const auto params_shape = loco::shape_get(node->params()).as<loco::TensorShape>(); + const auto indices_shape = loco::shape_get(node->indices()).as<loco::TensorShape>(); + + const auto params_rank = params_shape.rank(); + const auto indices_rank = indices_shape.rank(); + + // see https://www.tensorflow.org/api_docs/python/tf/gather_nd + // output.shape = indices.shape[:-1] + params.shape[indices.shape[-1]:] + // batch_dims isn't supported in tflite + + // TODO: replace exceptions with setting shape to unknown? + + if (!indices_shape.dim(indices_rank - 1).known()) + INTERNAL_EXN("Last indices dimension is unknown"); + + auto indices_last_dim = indices_shape.dim(indices_rank - 1).value(); + + if (indices_last_dim > params_rank) + INTERNAL_EXN("Last indices dimension should be <= params rank"); + + const uint32_t output_rank = indices_rank + params_rank - indices_last_dim - 1; + + output_shape.rank(output_rank); + + uint32_t output_index = 0; + for (uint32_t i = 0; i < indices_rank - 1; ++i) + { + auto &dim = indices_shape.dim(i); + if (!dim.known()) + INTERNAL_EXN("Unknown indices dimension is unsupported"); + output_shape.dim(output_index++).set(dim.value()); + } + + for (uint32_t i = indices_last_dim; i < params_rank; ++i) + { + auto &dim = params_shape.dim(i); + if (!dim.known()) + INTERNAL_EXN("Unknown params dimension is unsupported"); + output_shape.dim(output_index++).set(dim.value()); + } + + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleGreater *node) final { return broadcast_xy(node); } + + loco::NodeShape visit(const luci::CircleGreaterEqual *node) final { return broadcast_xy(node); } + + loco::NodeShape visit(const luci::CircleIf *node) final { - const auto input_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); + // Shape of CircleIf is not used. Just use input 0 + assert(node->input_count() > 0); + const auto input_shape = loco::shape_get(node->input(0)).as<loco::TensorShape>(); return loco::NodeShape{input_shape}; } - loco::NodeShape visit(const luci::CircleLogicalOr *node) final + loco::NodeShape visit(const luci::CircleL2Normalize *node) final { return use_x(node); } + + loco::NodeShape visit(const luci::CircleL2Pool2D *node) final + { + return infer_pool_2d_shape(node); + } + + loco::NodeShape visit(const luci::CircleLeakyRelu *node) final { - const auto input_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); + const auto input_shape = loco::shape_get(node->features()).as<loco::TensorShape>(); return loco::NodeShape{input_shape}; } - loco::NodeShape visit(const luci::CircleMaximum *node) final + loco::NodeShape visit(const luci::CircleLess *node) final { return broadcast_xy(node); } + + loco::NodeShape visit(const luci::CircleLessEqual *node) final { return broadcast_xy(node); } + + loco::NodeShape visit(const luci::CircleLocalResponseNormalization *node) final { - auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); - auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>(); + const auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + return loco::NodeShape{input_shape}; + } + + loco::NodeShape visit(const luci::CircleLog *node) final { return use_x(node); } + + loco::NodeShape visit(const luci::CircleLogicalAnd *node) final { return use_x(node); } + + loco::NodeShape visit(const luci::CircleLogicalNot *node) final { return use_x(node); } + + loco::NodeShape visit(const luci::CircleLogicalOr *node) final { return use_x(node); } + + loco::NodeShape visit(const luci::CircleLogistic *node) final { return use_x(node); } + + loco::NodeShape visit(const luci::CircleMatrixSetDiag *node) final + { + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + auto diagonal_shape = loco::shape_get(node->diagonal()).as<loco::TensorShape>(); + + auto rank = diagonal_shape.rank(); + + LUCI_ASSERT(rank == input_shape.rank() - 1, "diagonal rank = input rank - 1"); + + for (uint32_t i = 0; i < rank - 1; i++) + { + LUCI_ASSERT(diagonal_shape.dim(i) == input_shape.dim(i), "diagonal dims = input dims"); + } + + auto dim = std::min(input_shape.dim(rank - 1).value(), input_shape.dim(rank).value()); + + LUCI_ASSERT(dim == diagonal_shape.dim(rank - 1), "Max diag len error"); + + return loco::NodeShape{input_shape}; + } + + loco::NodeShape visit(const luci::CircleLogSoftmax *node) final { return use_logits(node); } + + loco::NodeShape visit(const luci::CircleMatrixDiag *node) final + { + loco::TensorShape output_shape; + + auto diagonal_shape = loco::shape_get(node->diagonal()).as<loco::TensorShape>(); + auto rank = diagonal_shape.rank(); - auto output_shape = broadcast_shape(x_shape, y_shape); + output_shape.rank(rank + 1); + + for (uint32_t i = 0; i < rank; i++) + { + output_shape.dim(i) = diagonal_shape.dim(i); + } + + output_shape.dim(rank) = diagonal_shape.dim(rank - 1); return loco::NodeShape{output_shape}; } + loco::NodeShape visit(const luci::CircleMaximum *node) final { return broadcast_xy(node); } + loco::NodeShape visit(const luci::CircleMaxPool2D *node) final { return infer_pool_2d_shape(node); @@ -524,67 +966,81 @@ public: loco::NodeShape visit(const luci::CircleMean *node) final { + auto output_shape = infer_reducer(node->input(), node->reduction_indices(), node->keep_dims()); + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleMinimum *node) final { return broadcast_xy(node); } + + loco::NodeShape visit(const luci::CircleMirrorPad *node) final + { const loco::DataType S32 = loco::DataType::S32; auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); - auto reduction_indices = dynamic_cast<luci::CircleConst *>(node->reduction_indices()); + auto paddings = loco::must_cast<luci::CircleConst *>(node->paddings()); - { // Exceptions - // TODO support non-const case - LUCI_ASSERT(reduction_indices, "Only support constant reduction_indices"); - // TODO support other data type - LUCI_ASSERT(reduction_indices->dtype() == S32, "Only support int 32"); - } + // TODO support non-const case + // TODO support other data type + LUCI_ASSERT(paddings->dtype() == S32, "Only support int 32 for now"); + LUCI_ASSERT(paddings->rank() == 2, "paddings should be rank 2") - std::vector<int32_t> reduction_values; + int32_t n = paddings->dim(0).value(); + int32_t v = paddings->dim(1).value(); - for (uint32_t i = 0; i < reduction_indices->size<S32>(); ++i) - { - int32_t axis = reduction_indices->at<S32>(i); - if (axis < 0) - axis += input_shape.rank(); - if (not(0 <= axis and axis < static_cast<int32_t>(input_shape.rank()))) - INTERNAL_EXN_V("Invalid reduction axis for MEAN", oops::to_uint32(axis)); - reduction_values.push_back(axis); - } + LUCI_ASSERT(v == 2, "paddings should be [n, 2]"); + LUCI_ASSERT(n == int32_t(input_shape.rank()), + "paddings [n, 2] should have same value of input rank"); loco::TensorShape output_shape; - if (node->keep_dims()) - { - output_shape.rank(input_shape.rank()); - for (uint32_t i = 0; i < input_shape.rank(); ++i) - output_shape.dim(i) = input_shape.dim(i); - for (uint32_t i = 0; i < reduction_values.size(); ++i) - output_shape.dim(reduction_values.at(i)) = 1; - } - else + output_shape.rank(input_shape.rank()); + for (int32_t ni = 0; ni < n; ++ni) { - std::vector<bool> check_reduce(input_shape.rank(), false); - for (uint32_t i = 0; i < reduction_values.size(); ++i) - check_reduce.at(reduction_values.at(i)) = true; - - uint32_t reduce_cnt = 0; - for (uint32_t i = 0; i < check_reduce.size(); ++i) - if (check_reduce.at(i)) - ++reduce_cnt; - - output_shape.rank(input_shape.rank() - reduce_cnt); - for (uint32_t i = 0, j = 0; i < check_reduce.size(); ++i) - if (check_reduce.at(i) == false) - output_shape.dim(j++) = i; + int32_t idx = ni * 2; + int value = input_shape.dim(ni).value(); + value += paddings->at<S32>(idx + 0); // left + value += paddings->at<S32>(idx + 1); // right + output_shape.dim(ni) = value; } return loco::NodeShape{output_shape}; } - loco::NodeShape visit(const luci::CircleMul *node) final - { - auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); - auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>(); + loco::NodeShape visit(const luci::CircleMul *node) final { return broadcast_xy(node); } + + loco::NodeShape visit(const luci::CircleNeg *node) final { return use_x(node); } - auto output_shape = broadcast_shape(x_shape, y_shape); + loco::NodeShape visit(const luci::CircleNotEqual *node) final { return broadcast_xy(node); } + loco::NodeShape visit(const luci::CircleOneHot *node) final + { + const loco::DataType S32 = loco::DataType::S32; + auto indices_shape = loco::shape_get(node->indices()).as<loco::TensorShape>(); + // Only support OneHot node's depth() is CircleConst with type S32 + // TODO support depth with other types + auto depth = loco::must_cast<luci::CircleConst *>(node->depth()); + LUCI_ASSERT(depth->dtype() == S32, "Only support int32 CircleConst"); + if (depth->rank() != 0) + INTERNAL_EXN_V("Only support rank 0 CircleOneHot in Depth", oops::to_uint32(depth->rank())); + loco::TensorShape output_shape; + output_shape.rank(indices_shape.rank() + 1); + auto axis = node->axis(); + if (axis < 0) + axis += indices_shape.rank() + 1; + LUCI_ASSERT(0 <= axis, "Axis is out of range"); + LUCI_ASSERT(static_cast<uint32_t>(axis) <= indices_shape.rank(), "Axis is out of range"); + uint32_t j = 0; + for (uint32_t i = 0; i < output_shape.rank(); i++) + { + if (i == static_cast<uint32_t>(axis)) + { + output_shape.dim(i) = depth->at<S32>(0); + } + else + { + output_shape.dim(i) = indices_shape.dim(j++); + } + } return loco::NodeShape{output_shape}; } @@ -636,10 +1092,9 @@ public: const loco::DataType S32 = loco::DataType::S32; auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); - auto paddings = dynamic_cast<luci::CircleConst *>(node->paddings()); + auto paddings = loco::must_cast<luci::CircleConst *>(node->paddings()); // TODO support non-const case - LUCI_ASSERT(paddings, "Only support constant reduction_indices"); // TODO support other data type LUCI_ASSERT(paddings->dtype() == S32, "Only support int 32 for now"); LUCI_ASSERT(paddings->rank() == 2, "paddings should be rank 2") @@ -666,6 +1121,93 @@ public: return loco::NodeShape{output_shape}; } + loco::NodeShape visit(const luci::CirclePow *node) final { return broadcast_xy(node); } + + loco::NodeShape visit(const luci::CirclePRelu *node) final + { + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + auto alpha_shape = loco::shape_get(node->alpha()).as<loco::TensorShape>(); + + auto output_shape = broadcast_shape(input_shape, alpha_shape); + + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleRange *node) final + { + loco::TensorShape output_shape; + output_shape.rank(1); + + auto start_node = dynamic_cast<luci::CircleConst *>(node->start()); + auto limit_node = dynamic_cast<luci::CircleConst *>(node->limit()); + auto delta_node = dynamic_cast<luci::CircleConst *>(node->delta()); + + if (start_node == nullptr || limit_node == nullptr || delta_node == nullptr) + { + return use_own(node); + } + + double start = 0, limit = 0, delta = 0; + +#define GET_RANGE_PARAM(DT) \ + start = start_node->scalar<DT>(); \ + limit = limit_node->scalar<DT>(); \ + delta = delta_node->scalar<DT>(); + + switch (start_node->dtype()) + { + case loco::DataType::FLOAT32: + GET_RANGE_PARAM(loco::DataType::FLOAT32) + break; + case loco::DataType::S32: + GET_RANGE_PARAM(loco::DataType::S32) + break; + default: + INTERNAL_EXN("Range data type not supported"); + } + +#undef GET_RANGE_PARAM + + if (delta == 0) + INTERNAL_EXN("Delta can not be zero"); + + output_shape.dim(0) = ceil((limit - start) / delta); + + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleRank *) final + { + loco::TensorShape shape_output; + shape_output.rank(0); + + return loco::NodeShape{shape_output}; + } + + loco::NodeShape visit(const luci::CircleReduceAny *node) final + { + auto output_shape = infer_reducer(node->input(), node->reduction_indices(), node->keep_dims()); + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleReduceMax *node) final + { + auto output_shape = infer_reducer(node->input(), node->reduction_indices(), node->keep_dims()); + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleReduceMin *node) final + { + auto output_shape = infer_reducer(node->input(), node->reduction_indices(), node->keep_dims()); + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleReduceProd *node) final + { + auto output_shape = infer_reducer(node->input(), node->reduction_indices(), node->keep_dims()); + return loco::NodeShape{output_shape}; + } + loco::NodeShape visit(const luci::CircleRelu *node) final { auto input_shape = loco::shape_get(node->features()).as<loco::TensorShape>(); @@ -680,15 +1222,24 @@ public: return loco::NodeShape{input_shape}; } + loco::NodeShape visit(const luci::CircleReluN1To1 *node) final + { + auto input_shape = loco::shape_get(node->features()).as<loco::TensorShape>(); + + return loco::NodeShape{input_shape}; + } + /** * @note CircleReshape has new shape info in two places: 2nd input and attribute. - * This shape inference forces both to exist, and match each other. - * When this condition satisfied, it return the inferred shape + * This shape inference uses shape from input 'shape' node when it's constant. + * If not, shape will be from node itself. shape from attribute is not used. * * TODO Change this policy when not appropriate */ loco::NodeShape visit(const luci::CircleReshape *node) final { + LOGGER(l); + const loco::DataType S32 = loco::DataType::S32; loco::TensorShape shape_by_input; @@ -698,18 +1249,21 @@ public: // Only support node's shape() is CircleConst with S32 // TODO support other node with other types auto const_shape_node = dynamic_cast<luci::CircleConst *>(node->shape()); - LUCI_ASSERT(const_shape_node, "Only support CircleConst for shape of CircleReshape"); - LUCI_ASSERT(const_shape_node->dtype() == S32, "Only support int32 CircleConst"); - - if (const_shape_node->rank() != 1) - INTERNAL_EXN_V("Only support rank 1 CircleConst", - oops::to_uint32(const_shape_node->rank())); + if (const_shape_node != nullptr) + { + LUCI_ASSERT(const_shape_node->dtype() == S32, "Only support int32 CircleConst"); - shape_by_input.rank(const_shape_node->dim(0).value()); + shape_by_input.rank(const_shape_node->size<S32>()); - for (uint32_t axis = 0; axis < shape_by_input.rank(); ++axis) + for (uint32_t axis = 0; axis < shape_by_input.rank(); ++axis) + { + shape_by_input.dim(axis) = const_shape_node->at<S32>(axis); + } + } + else { - shape_by_input.dim(axis) = const_shape_node->at<S32>(axis); + // We use shape from the node itself + shape_by_input = own_shape(node); } } @@ -723,8 +1277,12 @@ public: } } - LUCI_ASSERT(shape_by_input == shape_by_attr, - "Warning: Two new shape information mismatched for CircleReshape"); + if (!(shape_by_input == shape_by_attr)) + { + INFO(l) << "CircleReshape: Two new shape information mismatched : " << std::endl; + INFO(l) << " shape_by_input : " << shape_by_input << std::endl; + INFO(l) << " shape_by_attr : " << shape_by_attr << std::endl; + } loco::TensorShape output_shape = shape_by_input; @@ -754,94 +1312,517 @@ public: return loco::NodeShape{output_shape}; } - loco::NodeShape visit(const luci::CircleRsqrt *node) final + loco::NodeShape visit(const luci::CircleResizeBilinear *node) final { - auto input_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); - return loco::NodeShape{input_shape}; + if (input_shape.rank() != 4) + INTERNAL_EXN("Expected ResizeBilinear input to have rank 4"); + + auto *const_node = loco::must_cast<luci::CircleConst *>(node->size()); + + if (const_node->dtype() != loco::DataType::S32) + INTERNAL_EXN("Only S32 datatype is supported for ResizeBilinear size"); + + if (const_node->rank() != 1) + INTERNAL_EXN("Expected size tensor of rank 1"); + + if (const_node->dim(0).value() != 2) + INTERNAL_EXN("Expected size tensor with shape [2]"); + + loco::TensorShape output_shape; + output_shape.rank(4); + output_shape.dim(0) = input_shape.dim(0); + output_shape.dim(1) = const_node->at<loco::DataType::S32>(0); + output_shape.dim(2) = const_node->at<loco::DataType::S32>(1); + output_shape.dim(3) = input_shape.dim(3); + + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleResizeNearestNeighbor *node) final + { + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + + if (input_shape.rank() != 4) + INTERNAL_EXN("Expected ResizeNearesNeighbor input to have rank 4"); + + auto *const_node = loco::must_cast<luci::CircleConst *>(node->size()); + + if (const_node->dtype() != loco::DataType::S32) + INTERNAL_EXN("Only S32 datatype is supported for ResizeNearesNeighbor size"); + + if (const_node->rank() != 1) + INTERNAL_EXN("Expected size tensor of rank 1"); + + if (const_node->dim(0).value() != 2) + INTERNAL_EXN("Expected size tensor with shape [2]"); + + loco::TensorShape output_shape; + output_shape.rank(4); + output_shape.dim(0) = input_shape.dim(0); + output_shape.dim(1) = const_node->at<loco::DataType::S32>(0); + output_shape.dim(2) = const_node->at<loco::DataType::S32>(1); + output_shape.dim(3) = input_shape.dim(3); + + return loco::NodeShape{output_shape}; } - loco::NodeShape visit(const luci::CircleSoftmax *node) final + loco::NodeShape visit(const luci::CircleReverseSequence *node) final { - auto input_shape = loco::shape_get(node->logits()).as<loco::TensorShape>(); + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); return loco::NodeShape{input_shape}; } - loco::NodeShape visit(const luci::CircleSqrt *node) final + loco::NodeShape visit(const luci::CircleRound *node) final { return use_x(node); } + + loco::NodeShape visit(const luci::CircleReverseV2 *node) final { - auto input_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); + auto input_shape = loco::shape_get(node->tensor()).as<loco::TensorShape>(); + + LUCI_ASSERT(loco::shape_get(node->axis()).as<loco::TensorShape>().rank() == 1, + "Tensor must be 1-D"); return loco::NodeShape{input_shape}; } - loco::NodeShape visit(const luci::CircleSquaredDifference *node) final + loco::NodeShape visit(const luci::CircleRsqrt *node) final { return use_x(node); } + + loco::NodeShape visit(const luci::CircleScatterNd *node) final { - auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); - auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>(); + loco::TensorShape output_shape; + + auto shape_node = loco::must_cast<luci::CircleConst *>(node->shape()); + + const loco::DataType S32 = loco::DataType::S32; + const loco::DataType S64 = loco::DataType::S64; - auto output_shape = broadcast_shape(x_shape, y_shape); + std::vector<int64_t> vect_shape; + + if (shape_node->dtype() == S32) + vect_shape = vector_from_constant<S32>(shape_node); + else if (shape_node->dtype() == S64) + vect_shape = vector_from_constant<S64>(shape_node); + else + LUCI_ASSERT(false, "Only support int32/int64 for shape()"); + + output_shape.rank(vect_shape.size()); + for (uint32_t i = 0; i < vect_shape.size(); ++i) + output_shape.dim(i) = vect_shape[i]; return loco::NodeShape{output_shape}; } - loco::NodeShape visit(const luci::CircleSub *node) final + loco::NodeShape visit(const luci::CircleSegmentSum *node) final { - auto x_shape = loco::shape_get(node->x()).as<loco::TensorShape>(); - auto y_shape = loco::shape_get(node->y()).as<loco::TensorShape>(); + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + auto segment_shape = loco::shape_get(node->segment_ids()).as<loco::TensorShape>(); + + LUCI_ASSERT(segment_shape.rank() == 1, "segment_ids must be 1-D tensor"); + LUCI_ASSERT(segment_shape.dim(0).value() == input_shape.dim(0).value(), + "segment_ids size must be equal to the size of data's first dimension"); + + auto ids_shape_value = loco::must_cast<luci::CircleConst *>(node->segment_ids()); + + std::vector<int64_t> vect_ids; + + if (ids_shape_value->dtype() == loco::DataType::S32) + vect_ids = vector_from_constant<loco::DataType::S32>(ids_shape_value); + + LUCI_ASSERT(std::is_sorted(vect_ids.begin(), vect_ids.end()), + "segment_ids values should be sorted") + + loco::TensorShape output_shape; + + output_shape.rank(input_shape.rank()); + + for (uint32_t i = 1; i < input_shape.rank(); ++i) + output_shape.dim(i) = input_shape.dim(i); + + output_shape.dim(0) = vect_ids.back() + 1; + + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleSelect *node) final + { + auto t_shape = loco::shape_get(node->t()).as<loco::TensorShape>(); + assert(t_shape == loco::shape_get(node->e()).as<loco::TensorShape>()); + + // condition shape validation + auto c_shape = loco::shape_get(node->condition()).as<loco::TensorShape>(); + if (c_shape.rank() != t_shape.rank()) + { + if (c_shape.rank() != 0 && c_shape.rank() != 1) + INTERNAL_EXN_V("CircleSelect condition rank is not 0 nor 1: ", c_shape.rank()); + + if (c_shape.rank() == 1) + { + if (c_shape.dim(0).value() != t_shape.dim(0).value()) + INTERNAL_EXN("CircleSelect condition dim(0) should match with t.dim(0)"); + } + } + + return loco::NodeShape{t_shape}; + } - auto output_shape = broadcast_shape(x_shape, y_shape); + loco::NodeShape visit(const luci::CircleSelectV2 *node) final + { + auto c_shape = loco::shape_get(node->condition()).as<loco::TensorShape>(); + auto t_shape = loco::shape_get(node->t()).as<loco::TensorShape>(); + auto e_shape = loco::shape_get(node->e()).as<loco::TensorShape>(); + + // validate ability to broadcast shapes to each other + auto b_shape = broadcast_shape(broadcast_shape(c_shape, t_shape), e_shape); + return loco::NodeShape{b_shape}; + } + + loco::NodeShape visit(const luci::CircleShape *node) final + { + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + + loco::TensorShape output_shape; + + output_shape.rank(1); + output_shape.dim(0) = input_shape.rank(); return loco::NodeShape{output_shape}; } - // TODO CircleTanh + loco::NodeShape visit(const luci::CircleSin *node) final { return use_x(node); } - /// @brief Returns output shape of transpose. Use loco::ConstGen and luci::CircleConst for ConstT. - template <class ConstT> - loco::TensorShape output_shape_of_transpose(loco::TensorShape input_shape, - const ConstT *perm_node) + loco::NodeShape visit(const luci::CircleSlice *node) final { + const loco::DataType S32 = loco::DataType::S32; + const loco::DataType S64 = loco::DataType::S64; + + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + + auto const_begin = loco::must_cast<luci::CircleConst *>(node->begin()); + auto const_size = loco::must_cast<luci::CircleConst *>(node->size()); + loco::TensorShape output_shape; - output_shape.rank(input_shape.rank()); + std::vector<int64_t> vect_begin; // to hold both S32/S64, we use int64_t + std::vector<int64_t> vect_size; - assert(perm_node->dtype() == loco::DataType::S32); - assert(input_shape.rank() == perm_node->template size<loco::DataType::S32>()); + if (const_begin->dtype() == S32) + vect_begin = vector_from_constant<S32>(const_begin); + else if (const_begin->dtype() == S64) + vect_begin = vector_from_constant<S64>(const_begin); + else + LUCI_ASSERT(false, "Only support int32/int64 for begin()"); - for (uint32_t out_axis = 0; out_axis < output_shape.rank(); out_axis++) + if (const_size->dtype() == S32) + vect_size = vector_from_constant<S32>(const_size); + else if (const_size->dtype() == S64) + vect_size = vector_from_constant<S64>(const_size); + else + LUCI_ASSERT(false, "Only support int32/int64 for size()"); + + assert(input_shape.rank() == vect_begin.size()); + assert(input_shape.rank() == vect_size.size()); + + output_shape.rank(vect_begin.size()); + for (uint32_t idx = 0; idx < vect_begin.size(); ++idx) { - auto in_axis = perm_node->template at<loco::DataType::S32>(out_axis); - output_shape.dim(out_axis) = input_shape.dim(in_axis); + auto size = vect_size.at(idx); + if (size == -1) + { + size = input_shape.dim(idx).value() - vect_begin.at(idx); + } + output_shape.dim(idx) = size; } - return output_shape; + return loco::NodeShape{output_shape}; } - loco::NodeShape visit(const luci::CircleTranspose *node) final + loco::NodeShape visit(const luci::CircleSoftmax *node) final { return use_logits(node); } + + loco::NodeShape visit(const luci::CircleSpaceToBatchND *node) final { - auto input_shape = loco::shape_get(node->a()).as<loco::TensorShape>(); + const loco::DataType S32 = loco::DataType::S32; + + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + // Support only input rank is 3 and 4 + assert(input_shape.rank() == 3 || input_shape.rank() == 4); + + // Only support block_shape() with S32 type CircleConst for now + auto const_block_shape = loco::must_cast<luci::CircleConst *>(node->block_shape()); + LUCI_ASSERT(const_block_shape->dtype() == S32, "Only support int32 block_shape"); + + // Only support paddings() with S32 type CircleConst for now + auto const_paddings = loco::must_cast<luci::CircleConst *>(node->paddings()); + LUCI_ASSERT(const_paddings->dtype() == S32, "Only support int32 paddings"); + + auto const_block_shape_shape = loco::shape_get(const_block_shape).as<loco::TensorShape>(); + auto const_paddings_shape = loco::shape_get(const_paddings).as<loco::TensorShape>(); + assert(const_block_shape_shape.rank() == 1); + assert(const_paddings_shape.rank() == 2); + + int32_t input_spatial_dim = input_shape.rank() - 2; + assert(const_block_shape_shape.dim(0) == input_spatial_dim); + assert(const_paddings_shape.dim(0) == input_spatial_dim); + assert(const_paddings_shape.dim(1) == 2); + + // Check all values of block_shape >= 1 + uint32_t ele_count = const_block_shape->size<S32>(); + for (uint32_t e = 0; e < ele_count; ++e) + { + auto val = const_block_shape->at<S32>(e); + if (val < 1) + { + INTERNAL_EXN_V("All values of block_shape >= 1: ", e); + } + } + + loco::TensorShape shape_output; + + shape_output.rank(input_shape.rank()); + + int32_t output_batch_size = input_shape.dim(0).value(); + for (int32_t dim = 0; dim < input_spatial_dim; ++dim) + { + int dim_size = input_shape.dim(dim + 1).value(); + dim_size += const_paddings->at<S32>(dim * 2); + dim_size += const_paddings->at<S32>(dim * 2 + 1); + shape_output.dim(dim + 1) = dim_size / const_block_shape->at<S32>(dim); + + assert(dim_size % const_block_shape->at<S32>(dim) == 0); + output_batch_size = output_batch_size * const_block_shape->at<S32>(dim); + } + shape_output.dim(0) = output_batch_size; + shape_output.dim(input_shape.rank() - 1) = input_shape.dim(input_shape.rank() - 1); + + return loco::NodeShape{shape_output}; + } + + loco::NodeShape visit(const luci::CircleSpaceToDepth *node) final + { + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + LUCI_ASSERT(input_shape.rank() == 4, "Only input rank 4 is supported"); + + // Only data format NHWC is supported + int32_t height = input_shape.dim(1).value(); + int32_t width = input_shape.dim(2).value(); + int32_t depth = input_shape.dim(3).value(); + + int block_size = node->block_size(); + + if (block_size < 2) + INTERNAL_EXN("Block size must be >= 2"); + + if ((height % block_size) || (width % block_size)) + { + INTERNAL_EXN("The input tensor's height and width must be divisible by block_size"); + } + + loco::TensorShape output_shape; + output_shape.rank(4); + + output_shape.dim(0) = input_shape.dim(0).value(); + output_shape.dim(1) = height / block_size; + output_shape.dim(2) = width / block_size; + output_shape.dim(3) = block_size * block_size * depth; + + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleSparseToDense *node) final + { + loco::TensorShape shape; + { + LUCI_ASSERT(node->output_shape(), "dims input should not be nullptr"); + + auto output_shape_node = dynamic_cast<luci::CircleConst *>(node->output_shape()); + if (output_shape_node != nullptr) + { + // Only support node with S32 + LUCI_ASSERT(output_shape_node->dtype() == loco::DataType::S32, + "Only support int32 CircleConst"); + + if (output_shape_node->rank() != 1) + INTERNAL_EXN_V("Only support rank 1 CircleConst", + oops::to_uint32(output_shape_node->rank())); + + shape.rank(output_shape_node->dim(0).value()); + + for (uint32_t axis = 0; axis < shape.rank(); ++axis) + { + shape.dim(axis) = output_shape_node->at<loco::DataType::S32>(axis); + } + } + else + { + shape = own_shape(node); + } + } + + return loco::NodeShape{shape}; + } + + loco::NodeShape visit(const luci::CircleSplit *node) final + { + // We'll set Split output as same as input so that SplitOut can handle it's own shape + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + return loco::NodeShape{input_shape}; + } + + loco::NodeShape visit(const luci::CircleSplitV *node) final + { + // We'll set SplitV output as same as input so that SplitOut can handle it's own shape + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + return loco::NodeShape{input_shape}; + } + + loco::NodeShape visit(const luci::CircleSqrt *node) final { return use_x(node); } - auto canon_perm = dynamic_cast<loco::ConstGen *>(node->perm()); - auto circle_perm = dynamic_cast<luci::CircleConst *>(node->perm()); + loco::NodeShape visit(const luci::CircleSquare *node) final { return use_x(node); } - if (canon_perm) + loco::NodeShape visit(const luci::CircleSquaredDifference *node) final + { + return broadcast_xy(node); + } + + loco::NodeShape visit(const luci::CircleStridedSlice *node) final + { + auto begin_node = dynamic_cast<luci::CircleConst *>(node->begin()); + auto end_node = dynamic_cast<luci::CircleConst *>(node->end()); + auto strides_node = dynamic_cast<luci::CircleConst *>(node->strides()); + + if (begin_node == nullptr || end_node == nullptr || strides_node == nullptr) { - return loco::NodeShape{output_shape_of_transpose(input_shape, canon_perm)}; + return use_own(node); } - else if (circle_perm) + + loco::TensorShape shape = infer_output_shape(node); + return loco::NodeShape{shape}; + } + + loco::NodeShape visit(const luci::CircleSqueeze *node) final + { + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + + // TODO input shape may be unknown before runtime + std::vector<bool> do_squeeze(input_shape.rank(), false); + uint32_t num_squeezed = 0; + + if (!node->squeeze_dims().empty()) { - return loco::NodeShape{output_shape_of_transpose(input_shape, circle_perm)}; + // SqueezeDims not empty, squeeze only dims specified + for (int32_t raw_dim : node->squeeze_dims()) + { + int32_t dim = raw_dim < 0 ? raw_dim + input_shape.rank() : raw_dim; + + if (dim < 0 || static_cast<uint32_t>(dim) >= input_shape.rank() || + input_shape.dim(dim).value() != 1) + { + INTERNAL_EXN("invalid dimention specified to Squeeze"); + } + + if (!do_squeeze[dim]) + ++num_squeezed; + do_squeeze[dim] = true; + } } else - INTERNAL_EXN("perm of CircleTranspose should be either ConstGen or CircleConst"); + { + // SqueezeDims empty, squeeze any dims with size == 1 + for (uint32_t dim = 0; dim < input_shape.rank(); ++dim) + { + if (input_shape.dim(dim) == 1) + { + do_squeeze[dim] = true; + ++num_squeezed; + } + } + } + + loco::TensorShape output_shape; + output_shape.rank(input_shape.rank() - num_squeezed); + + for (uint32_t in_dim = 0, out_dim = 0; in_dim < input_shape.rank(); ++in_dim) + { + if (!do_squeeze[in_dim]) + { + output_shape.dim(out_dim++) = input_shape.dim(in_dim); + } + } + + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleSub *node) final { return broadcast_xy(node); } + + loco::NodeShape visit(const luci::CircleSum *node) final + { + auto output_shape = infer_reducer(node->input(), node->reduction_indices(), node->keep_dims()); + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleTanh *node) final { return use_x(node); } + + loco::NodeShape visit(const luci::CircleTile *node) final + { + const loco::DataType S32 = loco::DataType::S32; + + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + auto multiples = loco::must_cast<luci::CircleConst *>(node->multiples()); + + // TODO support non-const case + // TODO support S64 type + LUCI_ASSERT(multiples->dtype() == S32, "Only support int32 multiples"); + LUCI_ASSERT(multiples->rank() == 1, "multiples should be rank 1") + + uint32_t n = multiples->dim(0).value(); + + LUCI_ASSERT(n == input_shape.rank(), "length of multiples should be the same with input rank"); + + loco::TensorShape output_shape; + + output_shape.rank(input_shape.rank()); + for (uint32_t ni = 0; ni < n; ++ni) + { + int32_t multiple = multiples->at<S32>(ni); + output_shape.dim(ni) = input_shape.dim(ni).value() * static_cast<uint32_t>(multiple); + } + + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleTopKV2 *node) final + { + // set shape of this node as same as input + const auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + return loco::NodeShape{input_shape}; + } + + loco::NodeShape visit(const luci::CircleTranspose *node) final + { + auto input_shape = loco::shape_get(node->a()).as<loco::TensorShape>(); + + auto perm_node = loco::must_cast<luci::CircleConst *>(node->perm()); + + loco::TensorShape output_shape; + output_shape.rank(input_shape.rank()); + + assert(perm_node->dtype() == loco::DataType::S32); + assert(input_shape.rank() == perm_node->template size<loco::DataType::S32>()); + + for (uint32_t out_axis = 0; out_axis < output_shape.rank(); out_axis++) + { + auto in_axis = perm_node->template at<loco::DataType::S32>(out_axis); + output_shape.dim(out_axis) = input_shape.dim(in_axis); + } + + return output_shape; } loco::NodeShape visit(const luci::CircleTransposeConv *node) final { // TransposeConv's output shape is written in its 'inputSizes' argument - auto input_sizes_const = dynamic_cast<luci::CircleConst *>(node->inputSizes()); - LUCI_ASSERT(input_sizes_const, - "Only support when CircleTransposeConv's inputSizes is CircleConst") + auto input_sizes_const = loco::must_cast<luci::CircleConst *>(node->inputSizes()); + // TODO support non-const type LUCI_ASSERT(input_sizes_const->dtype() == loco::DataType::S32, "Only support S32 dtype") LUCI_ASSERT(input_sizes_const->rank() == 1 && input_sizes_const->dim(0).value() == 4, "Only support rank 1 with 4 entries") @@ -855,7 +1836,115 @@ public: return loco::NodeShape{shape}; } + loco::NodeShape visit(const luci::CircleUnpack *node) final + { + // CircleUnpack provides list(array) of Tensors which has one less dimension of the input + // We'll set shape of CircleUnpack to shape of actual outputs + // TODO fix this if any problem rises + auto value_shape = loco::shape_get(node->value()).as<loco::TensorShape>(); + + auto axis = node->axis(); + auto num = node->num(); + auto rank = static_cast<int32_t>(value_shape.rank()); + + if (rank == 0) + { + // Unknown shape + return use_own(node); + } + + LUCI_ASSERT(-rank <= axis && axis < rank, "Axis is out of range"); + + if (axis < 0) + axis += rank; + + LUCI_ASSERT(num == static_cast<int32_t>(value_shape.dim(axis).value()), + "num, axis maybe incorrect"); + + loco::TensorShape output_shape; + output_shape.rank(rank - 1); + + for (int32_t i = 0, o = 0; i < rank; ++i) + { + if (i != axis) + output_shape.dim(o++) = value_shape.dim(i); + } + + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleWhere *node) final { return use_own(node); } + + loco::NodeShape visit(const luci::CircleWhile *node) final + { + // Shape of CircleWhile is not used. Just use input 0 + assert(node->arity() > 0); + const auto input_shape = loco::shape_get(node->input(0)).as<loco::TensorShape>(); + return loco::NodeShape{input_shape}; + } + + loco::NodeShape visit(const luci::CircleZerosLike *node) final + { + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + + return loco::NodeShape{input_shape}; + } + // Circle Only + loco::NodeShape visit(const luci::CircleBCQFullyConnected *node) final + { + loco::TensorShape out_shape; + + auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); + auto weights_clusters = loco::must_cast<luci::CircleConst *>(node->weights_clusters()); + + LUCI_ASSERT(input_shape.rank() == 2, "Input rank of BCQFullyConnected should be 2"); + + int32_t qbits_sum = 0; + for (uint32_t i = 0; i < weights_clusters->dim(0).value(); ++i) + { + qbits_sum += weights_clusters->at<loco::DataType::S32>(i * 2 + 1); + } + + out_shape.rank(2); + out_shape.dim(0) = qbits_sum; + out_shape.dim(1) = input_shape.dim(1); + + return loco::NodeShape{out_shape}; + } + + loco::NodeShape visit(const luci::CircleBCQGather *node) final + { + loco::TensorShape input_shape; + loco::TensorShape output_shape; + + const auto input_binary_shape = loco::shape_get(node->input_binary()).as<loco::TensorShape>(); + const auto indices_shape = loco::shape_get(node->indices()).as<loco::TensorShape>(); + auto axis = node->axis(); + + auto input_clusters = loco::must_cast<luci::CircleConst *>(node->input_clusters()); + auto qbits_sum = 0; + for (uint32_t i = 0; i < input_clusters->dim(0).value(); ++i) + { + qbits_sum += input_clusters->at<loco::DataType::S32>(i * 2 + 1); + } + + input_shape.rank(2); + input_shape.dim(0) = qbits_sum; + input_shape.dim(1) = input_binary_shape.dim(1).value() * 32; + + output_shape.rank(input_shape.rank() - 1 + indices_shape.rank()); + int32_t outdim_index = 0; + for (int32_t i = 0; i < axis; ++i) + output_shape.dim(outdim_index++) = input_shape.dim(i); + for (uint32_t i = 0; i < indices_shape.rank(); ++i) + output_shape.dim(outdim_index++) = indices_shape.dim(i); + for (uint32_t i = axis + 1; i < input_shape.rank(); ++i) + output_shape.dim(outdim_index++) = input_shape.dim(i); + + return loco::NodeShape{output_shape}; + } + loco::NodeShape visit(const luci::CircleInstanceNorm *node) final { auto input_shape = loco::shape_get(node->input()).as<loco::TensorShape>(); @@ -877,9 +1966,230 @@ public: loco::NodeShape visit(const luci::CircleOutput *node) final { - auto from_shape = loco::shape_get(node->from()).as<loco::TensorShape>(); + auto graph_outputs = node->graph()->outputs(); + auto graph_output = graph_outputs->at(node->index()); + auto output_shape = graph_output->shape(); + + return loco::NodeShape{*output_shape}; + } + + loco::NodeShape visit(const luci::CircleOutputDummy *node) final { return use_own(node); } + + loco::NodeShape visit(const luci::CircleOutputExclude *node) final { return use_own(node); } + + loco::NodeShape visit(const luci::CircleCustomOut *node) final { return use_own(node); } + + loco::NodeShape visit(const luci::CircleIfOut *node) final + { + /** + * @note IF operator type and shape are that of the "then" and "else" + * Graph Outputs. + */ + auto circle_if = dynamic_cast<const luci::CircleIf *>(node->input()); + if (circle_if == nullptr) + { + INTERNAL_EXN("CircleIf IR is not configured correctly"); + } + + auto index = node->index(); + auto then_graph = circle_if->then_graph(); + auto else_graph = circle_if->else_graph(); + assert(then_graph != nullptr); + assert(else_graph != nullptr); + + // shape and type are assumed to be same + // these are checked at post_import_graph() in Import + auto then_outputs = loco::output_nodes(then_graph); + auto else_outputs = loco::output_nodes(else_graph); + assert(then_outputs.size() == else_outputs.size()); + assert(index < static_cast<int32_t>(then_outputs.size())); + + auto then_out = loco::must_cast<luci::CircleOutput *>(then_outputs.at(index)); + auto else_out = loco::must_cast<luci::CircleOutput *>(else_outputs.at(index)); + + auto then_graph_outputs = then_graph->outputs(); // loco::GraphOutput items + auto else_graph_outputs = else_graph->outputs(); + assert(then_graph_outputs->size() == else_graph_outputs->size()); + + auto then_graph_output = then_graph_outputs->at(then_out->index()); + auto else_graph_output = else_graph_outputs->at(else_out->index()); + (void)else_graph_output; // make compiler happy for unused variable warnings + assert(*then_graph_output->shape() == *else_graph_output->shape()); + + return loco::NodeShape{*then_graph_output->shape()}; + } + + loco::NodeShape visit(const luci::CircleSplitOut *node) final + { + const loco::DataType S32 = loco::DataType::S32; + + auto split = dynamic_cast<const luci::CircleSplit *>(node->input()); + if (split == nullptr) + INTERNAL_EXN("CircleSplit IR is not configured correctly"); + + loco::NodeShape unknown; + + auto split_shape = loco::shape_get(split).as<loco::TensorShape>(); + + auto split_dim = dynamic_cast<const luci::CircleConst *>(split->split_dim()); + if (split_dim == nullptr) + return unknown; // we need CircleConst for split_dim + LUCI_ASSERT(split_dim->dtype() == S32, "Only support int32 for split_dim"); + + assert(split_dim->size<S32>() == 1); + auto split_dim_axis = split_dim->at<S32>(0); + if (split_dim_axis < 0) + split_dim_axis += split_shape.rank(); + + auto split_dim_value = split_shape.dim(split_dim_axis).value(); + assert(split_dim_value % split->num_split() == 0); + const int split_depth = split_dim_value / split->num_split(); + + loco::TensorShape output_shape = split_shape; + + // All shapes are equally same + output_shape.dim(split_dim_axis) = loco::Dimension(split_depth); + + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleSplitVOut *node) final + { + const loco::DataType S32 = loco::DataType::S32; + + auto split = dynamic_cast<const luci::CircleSplitV *>(node->input()); + if (split == nullptr) + INTERNAL_EXN("CircleSplit IR is not configured correctly"); + + loco::NodeShape unknown; + + auto split_shape = loco::shape_get(split).as<loco::TensorShape>(); + + auto size_splits = dynamic_cast<const luci::CircleConst *>(split->size_splits()); + if (size_splits == nullptr) + return unknown; // we need CircleConst for size_splits + LUCI_ASSERT(size_splits->dtype() == S32, "Only support int32 for size_splits"); + + auto split_dim = dynamic_cast<const luci::CircleConst *>(split->split_dim()); + if (split_dim == nullptr) + return unknown; // we need CircleConst for split_dim + LUCI_ASSERT(split_dim->dtype() == S32, "Only support int32 for split_dim"); + + // fetch axis + assert(split_dim->size<S32>() == 1); + auto split_dim_axis = split_dim->at<S32>(0); + if (split_dim_axis < 0) + split_dim_axis += split_shape.rank(); + + // interpret size_splits values + int32_t size_splits_count = static_cast<int32_t>(size_splits->size<S32>()); + assert(size_splits_count == split->num_split()); + + int64_t minus_one_count = 0, size_splits_sum = 0; + for (int32_t idx = 0; idx < size_splits_count; ++idx) + { + auto size = size_splits->at<S32>(idx); + assert(size >= -1); + if (size == -1) + ++minus_one_count; + else + size_splits_sum += size; + } + if (minus_one_count > 1) + INTERNAL_EXN("CircleSplitV size_splits has more than two -1 values"); + + // calcuate this SplitVOut shape + auto input_size = split_shape.dim(split_dim_axis).value(); + assert(size_splits_sum <= input_size); + + auto index_this = node->index(); + assert(0 <= index_this && index_this < split->num_split()); + auto split_depth = size_splits->at<S32>(index_this); + if (split_depth == -1) + split_depth = input_size - size_splits_sum; + + loco::TensorShape output_shape = split_shape; + + output_shape.dim(split_dim_axis) = loco::Dimension(split_depth); + + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleTopKV2Out *node) final + { + const loco::DataType S32 = loco::DataType::S32; + + auto topkv2 = dynamic_cast<const luci::CircleTopKV2 *>(node->input()); + if (topkv2 == nullptr) + INTERNAL_EXN("CircleSplit IR is not configured correctly"); + + // shape of topkv2 is same as topkv2->input() + auto input_shape = loco::shape_get(topkv2).as<loco::TensorShape>(); + + auto node_k = loco::must_cast<const luci::CircleConst *>(topkv2->k()); + LUCI_ASSERT(node_k->dtype() == S32, "Only support Int32"); + assert(node_k->size<S32>() == 1); + + loco::TensorShape output_shape; + + output_shape.rank(input_shape.rank()); + for (uint32_t idx = 0; idx < input_shape.rank() - 1; ++idx) + { + output_shape.dim(idx) = input_shape.dim(idx); + } + output_shape.dim(input_shape.rank() - 1) = node_k->at<S32>(0); + + return loco::NodeShape{output_shape}; + } + + loco::NodeShape visit(const luci::CircleUnpackOut *node) final + { + auto unpack = dynamic_cast<const luci::CircleUnpack *>(node->input()); + if (unpack == nullptr) + { + INTERNAL_EXN("CircleUnpack IR is not configured correctly"); + } + + auto unpack_shape = loco::shape_get(unpack).as<loco::TensorShape>(); + + return loco::NodeShape{unpack_shape}; + } + + loco::NodeShape visit(const luci::CircleWhileOut *node) final + { + /** + * @note WHILE operator's shape is the same with the "cond" + * Graph input. + */ + auto circle_while = dynamic_cast<const luci::CircleWhile *>(node->input()); + if (circle_while == nullptr) + { + INTERNAL_EXN("CircleWhile IR is not configured correctly"); + } + + auto index = node->index(); + auto cond_graph = circle_while->cond_graph(); + assert(cond_graph != nullptr); + + // Assumption: the index of CircleWhileOut matches with the index of input nodes returned by + // loco::input_nodes + auto cond_inputs = loco::input_nodes(cond_graph); + auto cond_in = loco::must_cast<luci::CircleInput *>(cond_inputs.at(index)); + + auto cond_graph_inputs = cond_graph->inputs(); + auto cond_graph_input = cond_graph_inputs->at(cond_in->index()); - return loco::NodeShape{from_shape}; + auto cond_graph_input_shape = *cond_graph_input->shape(); + auto this_shape = own_shape(node); + + if (!(this_shape == cond_graph_input_shape)) + { + LOGGER(l); + WARN(l) << "Warning: CircleWhileOut '" << node->name() << "' shape mispatch " << this_shape + << " vs " << cond_graph_input_shape; + } + + return loco::NodeShape{this_shape}; } }; @@ -895,11 +2205,30 @@ bool CircleShapeInferenceRule::recognize(const loco::Dialect *d) const bool CircleShapeInferenceRule::infer(const loco::Node *node, loco::NodeShape &shape) const { + LOGGER(l); + assert(node->dialect() == CircleDialect::get()); - assert(dynamic_cast<const CircleNode *>(node) != nullptr); ShapeInferenceAlgorithm alg; - shape = dynamic_cast<const CircleNode *>(node)->accept(&alg); + auto circle_node = loco::must_cast<const CircleNode *>(node); + + bool is_shape_undefined = (circle_node->shape_status() == ShapeStatus::UNDEFINED); + bool is_shape_none = (circle_node->shape_status() == ShapeStatus::NOSHAPE); + bool is_scalar = (circle_node->rank() == 0); + + if (is_shape_undefined) + shape = circle_node->accept(&alg); + else + { + if (is_shape_none || is_scalar) + shape = own_shape(circle_node); + else + shape = circle_node->accept(&alg); + } + + VERBOSE(l, 1) << "[luci] shape: " << circle_node->name(); + VERBOSE(l, 1) << " own_shape: " << own_shape(circle_node) + << " -> infer: " << shape.as<loco::TensorShape>(); return true; } diff --git a/compiler/luci/service/src/CircleShapeInferenceRule.test.cpp b/compiler/luci/service/src/CircleShapeInferenceRule.test.cpp index 0374251a0..ac27db3bd 100644 --- a/compiler/luci/service/src/CircleShapeInferenceRule.test.cpp +++ b/compiler/luci/service/src/CircleShapeInferenceRule.test.cpp @@ -26,6 +26,8 @@ #include <loco/Service/CanonicalShapeInferenceRule.h> #include <loco/Service/MultiDialectShapeInferenceRule.h> +#include <oops/InternalExn.h> + #include <gtest/gtest.h> #include <memory> @@ -51,38 +53,39 @@ TEST(CircleShapeInferenceRuleTest, minimal_with_CircleRelu) { // Create a simple network luci::test::TestGraph graph; - auto tfl_node = graph.append<luci::CircleRelu>(graph.pull); - graph.complete(tfl_node); + auto relu_node = graph.append<luci::CircleRelu>(graph.input_node); + graph.complete(relu_node); // set shape { - graph.pull->rank(2); - graph.pull->dim(0) = 3; - graph.pull->dim(1) = 4; + graph.input_node->rank(2); + graph.input_node->dim(0) = 3; + graph.input_node->dim(1) = 4; + + graph.output_node->rank(2); + graph.output_node->dim(0) = 3; + graph.output_node->dim(1) = 4; + + luci::test::graph_input_shape(graph.input_node); + luci::test::graph_output_shape(graph.output_node); } // pre-check - ASSERT_FALSE(loco::shape_known(tfl_node)); + ASSERT_FALSE(loco::shape_known(relu_node)); // shape inference - luci::CircleShapeInferenceRule tfl_rule; - loco::CanonicalShapeInferenceRule canonical_rule; - loco::MultiDialectShapeInferenceRule rules; - - rules.bind(loco::CanonicalDialect::get(), &canonical_rule) - .bind(luci::CircleDialect::get(), &tfl_rule); - - loco::apply(&rules).to(graph.g.get()); + while (shape_pass(graph.graph()) == true) + ; // Verify { - ASSERT_TRUE(loco::shape_known(tfl_node)); - ASSERT_EQ(loco::shape_get(tfl_node).domain(), loco::Domain::Tensor); + ASSERT_TRUE(loco::shape_known(relu_node)); + ASSERT_EQ(loco::Domain::Tensor, loco::shape_get(relu_node).domain()); - auto shape = loco::shape_get(tfl_node).as<loco::TensorShape>(); - ASSERT_EQ(shape.rank(), 2); - ASSERT_EQ(shape.dim(0), 3); - ASSERT_EQ(shape.dim(1), 4); + auto shape = loco::shape_get(relu_node).as<loco::TensorShape>(); + ASSERT_EQ(2, shape.rank()); + ASSERT_EQ(3, shape.dim(0)); + ASSERT_EQ(4, shape.dim(1)); } } @@ -91,85 +94,92 @@ TEST(CircleShapeInferenceRuleTest, minimal_with_CircleRelu) TEST(CircleShapeInferenceRuleTest, avgpool2d_valid) { luci::test::TestGraph graph; - auto tfl_node = graph.append<luci::CircleAveragePool2D>(graph.pull); + auto avg_node = graph.append<luci::CircleAveragePool2D>(graph.input_node); graph.complete(); - auto pull = graph.pull; + auto input_node = graph.input_node; { - pull->shape({1, 4, 3, 1}); + input_node->shape({1, 4, 3, 1}); + luci::test::graph_input_shape(input_node); + } + auto output_node = graph.output_node; + { + output_node->shape({1, 2, 1, 1}); + luci::test::graph_output_shape(output_node); } // setting CircleAveragePool2D { - tfl_node->filter()->h(2); - tfl_node->filter()->w(2); - tfl_node->stride()->h(2); - tfl_node->stride()->w(2); - tfl_node->fusedActivationFunction(luci::FusedActFunc::NONE); - tfl_node->padding(luci::Padding::VALID); + avg_node->filter()->h(2); + avg_node->filter()->w(2); + avg_node->stride()->h(2); + avg_node->stride()->w(2); + avg_node->fusedActivationFunction(luci::FusedActFunc::NONE); + avg_node->padding(luci::Padding::VALID); } - ASSERT_FALSE(loco::shape_known(tfl_node)); + ASSERT_FALSE(loco::shape_known(avg_node)); // shape inference - luci::CircleShapeInferenceRule tfl_rule; - loco::CanonicalShapeInferenceRule canonical_rule; - loco::MultiDialectShapeInferenceRule rules; - - rules.bind(loco::CanonicalDialect::get(), &canonical_rule) - .bind(luci::CircleDialect::get(), &tfl_rule); - - loco::apply(&rules).to(graph.g.get()); + while (shape_pass(graph.graph()) == true) + ; // Verify { - ASSERT_TRUE(loco::shape_known(tfl_node)); - ASSERT_EQ(loco::shape_get(tfl_node).domain(), loco::Domain::Tensor); - - auto shape = loco::shape_get(tfl_node).as<loco::TensorShape>(); - ASSERT_EQ(shape.rank(), 4); - ASSERT_EQ(shape.dim(0).value(), 1); - ASSERT_EQ(shape.dim(1).value(), 2); - ASSERT_EQ(shape.dim(2).value(), 1); - ASSERT_EQ(shape.dim(3).value(), 1); + ASSERT_TRUE(loco::shape_known(avg_node)); + ASSERT_EQ(loco::Domain::Tensor, loco::shape_get(avg_node).domain()); + + auto shape = loco::shape_get(avg_node).as<loco::TensorShape>(); + ASSERT_EQ(4, shape.rank()); + ASSERT_EQ(1, shape.dim(0).value()); + ASSERT_EQ(2, shape.dim(1).value()); + ASSERT_EQ(1, shape.dim(2).value()); + ASSERT_EQ(1, shape.dim(3).value()); } } TEST(CircleShapeInferenceRuleTest, avgpool2d_same) { luci::test::TestGraph graph; - auto tfl_node = graph.append<luci::CircleAveragePool2D>(graph.pull); + auto avg_node = graph.append<luci::CircleAveragePool2D>(graph.input_node); graph.complete(); - auto pull = graph.pull; + auto input_node = graph.input_node; { - pull->shape({1, 4, 3, 1}); + input_node->shape({1, 4, 3, 1}); + luci::test::graph_input_shape(input_node); + } + auto output_node = graph.output_node; + { + output_node->shape({1, 2, 2, 1}); + luci::test::graph_output_shape(output_node); } // setting CircleAveragePool2D { - tfl_node->filter()->h(2); - tfl_node->filter()->w(2); - tfl_node->stride()->h(2); - tfl_node->stride()->w(2); - tfl_node->fusedActivationFunction(luci::FusedActFunc::NONE); - tfl_node->padding(luci::Padding::SAME); + avg_node->filter()->h(2); + avg_node->filter()->w(2); + avg_node->stride()->h(2); + avg_node->stride()->w(2); + avg_node->fusedActivationFunction(luci::FusedActFunc::NONE); + avg_node->padding(luci::Padding::SAME); } - ASSERT_FALSE(loco::shape_known(tfl_node)); + ASSERT_FALSE(loco::shape_known(avg_node)); // shape inference - shape_pass(graph.g.get()); + while (shape_pass(graph.graph()) == true) + ; // Verify { - ASSERT_TRUE(loco::shape_known(tfl_node)); - ASSERT_EQ(loco::shape_get(tfl_node).domain(), loco::Domain::Tensor); - - auto shape = loco::shape_get(tfl_node).as<loco::TensorShape>(); - ASSERT_EQ(shape.rank(), 4); - ASSERT_EQ(shape.dim(0).value(), 1); - ASSERT_EQ(shape.dim(1).value(), 2); - ASSERT_EQ(shape.dim(2).value(), 2); - ASSERT_EQ(shape.dim(3).value(), 1); + ASSERT_TRUE(loco::shape_known(avg_node)); + ASSERT_EQ(loco::Domain::Tensor, loco::shape_get(avg_node).domain()); + + auto shape = loco::shape_get(avg_node).as<loco::TensorShape>(); + ASSERT_EQ(4, shape.rank()); + ASSERT_EQ(1, shape.dim(0).value()); + ASSERT_EQ(2, shape.dim(1).value()); + ASSERT_EQ(2, shape.dim(2).value()); + ASSERT_EQ(1, shape.dim(3).value()); } } @@ -186,47 +196,51 @@ TEST(CircleShapeInferenceRuleTest, TFAdd_shapeinf_different) { auto g = loco::make_graph(); - auto x_node = g->nodes()->create<loco::Pull>(); + auto x_node = g->nodes()->create<luci::CircleInput>(); { x_node->rank(3); x_node->dim(0) = 2; x_node->dim(1) = 1; x_node->dim(2) = 5; } - auto y_node = g->nodes()->create<loco::Pull>(); + auto y_node = g->nodes()->create<luci::CircleInput>(); { y_node->rank(2); y_node->dim(0) = 3; y_node->dim(1) = 5; } - auto tfl_node = g->nodes()->create<luci::CircleAdd>(); + auto add_node = g->nodes()->create<luci::CircleAdd>(); { - tfl_node->x(x_node); - tfl_node->y(y_node); + add_node->x(x_node); + add_node->y(y_node); } - auto push_node = g->nodes()->create<loco::Push>(); + auto output_node = g->nodes()->create<luci::CircleOutput>(); { - push_node->from(tfl_node); + output_node->from(add_node); } auto x_input = g->inputs()->create(); { x_input->name("x"); - loco::link(x_input, x_node); + luci::link(x_input, x_node); } auto y_input = g->inputs()->create(); { y_input->name("y"); - loco::link(y_input, y_node); + luci::link(y_input, y_node); } auto output = g->outputs()->create(); { output->name("output"); - loco::link(output, push_node); + luci::link(output, output_node); } + luci::test::graph_input_shape(x_node); + luci::test::graph_input_shape(y_node); + luci::test::graph_output_shape(output_node); + // pre-check - ASSERT_FALSE(loco::shape_known(tfl_node)); + ASSERT_FALSE(loco::shape_known(add_node)); // shape inference while (shape_pass(g.get()) == true) @@ -234,14 +248,14 @@ TEST(CircleShapeInferenceRuleTest, TFAdd_shapeinf_different) // Verify { - ASSERT_TRUE(loco::shape_known(tfl_node)); - ASSERT_EQ(loco::shape_get(tfl_node).domain(), loco::Domain::Tensor); - - auto shape = loco::shape_get(tfl_node).as<loco::TensorShape>(); - ASSERT_EQ(shape.rank(), 3); - ASSERT_EQ(shape.dim(0), 2); - ASSERT_EQ(shape.dim(1), 3); - ASSERT_EQ(shape.dim(2), 5); + ASSERT_TRUE(loco::shape_known(add_node)); + ASSERT_EQ(loco::Domain::Tensor, loco::shape_get(add_node).domain()); + + auto shape = loco::shape_get(add_node).as<loco::TensorShape>(); + ASSERT_EQ(3, shape.rank()); + ASSERT_EQ(2, shape.dim(0)); + ASSERT_EQ(3, shape.dim(1)); + ASSERT_EQ(5, shape.dim(2)); } } @@ -249,10 +263,10 @@ TEST(CircleShapeInferenceRuleTest, CircleTranspose_simple) { luci::test::ExampleGraph<luci::test::ExampleGraphType::CircleTranspose> g; - g.pull->rank(3); - g.pull->dim(0) = 3; - g.pull->dim(1) = 8; - g.pull->dim(2) = 1; + g.input_node->rank(3); + g.input_node->dim(0) = 3; + g.input_node->dim(1) = 8; + g.input_node->dim(2) = 1; g.const_perm->dtype(loco::DataType::S32); g.const_perm->rank(1); @@ -262,6 +276,9 @@ TEST(CircleShapeInferenceRuleTest, CircleTranspose_simple) g.const_perm->at<loco::DataType::S32>(1) = 2; g.const_perm->at<loco::DataType::S32>(2) = 0; + luci::test::graph_input_shape(g.input_node); + luci::test::graph_output_shape(g.output_node); + // pre-check ASSERT_FALSE(loco::shape_known(g.transpose_node)); @@ -274,9 +291,336 @@ TEST(CircleShapeInferenceRuleTest, CircleTranspose_simple) ASSERT_TRUE(loco::shape_known(g.transpose_node)); auto shape = loco::shape_get(g.transpose_node).as<loco::TensorShape>(); - ASSERT_EQ(shape.rank(), 3); - ASSERT_EQ(shape.dim(0), 8); - ASSERT_EQ(shape.dim(1), 1); - ASSERT_EQ(shape.dim(2), 3); + ASSERT_EQ(3, shape.rank()); + ASSERT_EQ(8, shape.dim(0)); + ASSERT_EQ(1, shape.dim(1)); + ASSERT_EQ(3, shape.dim(2)); + } +} + +TEST(CircleShapeInferenceRuleTest, CircleSqueeze) +{ + luci::test::TestGraph graph; + auto squeeze_node = graph.append<luci::CircleSqueeze>(graph.input_node); + graph.complete(); + + auto input_node = graph.input_node; + { + input_node->shape({1, 4, 3, 1}); + } + auto output_node = graph.output_node; + { + output_node->shape({4, 3, 1}); + } + + luci::test::graph_input_shape(input_node); + luci::test::graph_output_shape(output_node); + + squeeze_node->squeeze_dims({0}); + + // pre-check + ASSERT_FALSE(loco::shape_known(squeeze_node)); + + // shape inference + while (shape_pass(graph.graph()) == true) + ; + + // Verify + { + ASSERT_TRUE(loco::shape_known(squeeze_node)); + + auto shape = loco::shape_get(squeeze_node).as<loco::TensorShape>(); + ASSERT_EQ(3, shape.rank()); + ASSERT_EQ(4, shape.dim(0)); + ASSERT_EQ(3, shape.dim(1)); + ASSERT_EQ(1, shape.dim(2)); + } +} + +TEST(CircleShapeInferenceRuleTest, CircleExpandDims) +{ + luci::test::TestGraph graph; + auto axis = graph.append<luci::CircleConst>(); + axis->dtype(loco::DataType::S32); + axis->rank(0); + axis->size<loco::DataType::S32>(1); + axis->at<loco::DataType::S32>(0) = 1; + + auto expand_dims = graph.append<luci::CircleExpandDims>(graph.input_node, axis); + graph.complete(); + + auto input_node = graph.input_node; + { + input_node->shape({4, 3}); + } + + auto output_node = graph.output_node; + { + output_node->from(expand_dims); + } + + luci::test::graph_input_shape(input_node); + luci::test::graph_output_shape(output_node); + + // shape inference + while (shape_pass(graph.graph())) + ; + + // validation + { + ASSERT_TRUE(loco::shape_known(expand_dims)); + + auto shape = loco::shape_get(expand_dims).as<loco::TensorShape>(); + + ASSERT_EQ(3, shape.rank()); + ASSERT_EQ(4, shape.dim(0)); + ASSERT_EQ(1, shape.dim(1)); + ASSERT_EQ(3, shape.dim(2)); + } +} + +TEST(CircleShapeInferenceRuleTest, CircleSqueezeAll) +{ + luci::test::TestGraph graph; + auto squeeze_node = graph.append<luci::CircleSqueeze>(graph.input_node); + graph.complete(); + + auto input_node = graph.input_node; + { + input_node->shape({1, 4, 3, 1}); + } + auto output_node = graph.output_node; + { + input_node->shape({4, 3}); + } + + luci::test::graph_input_shape(input_node); + luci::test::graph_output_shape(output_node); + + squeeze_node->squeeze_dims({}); + + // pre-check + ASSERT_FALSE(loco::shape_known(squeeze_node)); + + // shape inference + while (shape_pass(graph.graph()) == true) + ; + + // Verify + { + ASSERT_TRUE(loco::shape_known(squeeze_node)); + + auto shape = loco::shape_get(squeeze_node).as<loco::TensorShape>(); + ASSERT_EQ(2, shape.rank()); + ASSERT_EQ(4, shape.dim(0)); + ASSERT_EQ(3, shape.dim(1)); + } +} + +TEST(CircleShapeInferenceRuleTest, CircleGatherNd_simple) +{ + luci::test::TestGraph graph; + auto indices_const = graph.append<luci::CircleConst>(); + auto gather_nd_node = graph.append<luci::CircleGatherNd>(graph.input_node, indices_const); + graph.complete(); + + { + auto input_node = graph.input_node; + input_node->shape({1, 4, 4, 3}); + luci::test::graph_input_shape(input_node); + } + { + auto output_node = graph.output_node; + output_node->shape({1, 2, 2, 3}); + luci::test::graph_output_shape(output_node); + } + + { + indices_const->shape({1, 2, 3}); + } + + // pre-check + ASSERT_FALSE(loco::shape_known(gather_nd_node)); + + // shape inference + while (shape_pass(graph.graph()) == true) + ; + + // Verify + { + ASSERT_TRUE(loco::shape_known(gather_nd_node)); + + auto shape = loco::shape_get(gather_nd_node).as<loco::TensorShape>(); + ASSERT_EQ(3, shape.rank()); + ASSERT_EQ(1, shape.dim(0)); + ASSERT_EQ(2, shape.dim(1)); + ASSERT_EQ(3, shape.dim(2)); + } +} + +TEST(CircleShapeInferenceRuleTest, CircleGatherNd_slices) +{ + luci::test::TestGraph graph; + auto indices_const = graph.append<luci::CircleConst>(); + auto gather_nd_node = graph.append<luci::CircleGatherNd>(graph.input_node, indices_const); + graph.complete(); + + { + auto input_node = graph.input_node; + input_node->shape({1, 4, 4, 3}); + luci::test::graph_input_shape(input_node); + } + { + auto output_node = graph.output_node; + output_node->shape({1, 2, 4, 4, 3}); + luci::test::graph_output_shape(output_node); + } + + { + indices_const->shape({1, 2, 1}); + } + + // pre-check + ASSERT_FALSE(loco::shape_known(gather_nd_node)); + + // shape inference + while (shape_pass(graph.graph()) == true) + ; + + // Verify + { + ASSERT_TRUE(loco::shape_known(gather_nd_node)); + + auto shape = loco::shape_get(gather_nd_node).as<loco::TensorShape>(); + ASSERT_EQ(5, shape.rank()); + ASSERT_EQ(1, shape.dim(0)); + ASSERT_EQ(2, shape.dim(1)); + ASSERT_EQ(4, shape.dim(2)); + ASSERT_EQ(4, shape.dim(3)); + ASSERT_EQ(3, shape.dim(4)); + } +} + +TEST(CircleShapeInferenceRuleTest, CircleGatherNd_NEG) +{ + luci::test::TestGraph graph; + auto indices_const = graph.append<luci::CircleConst>(); + auto gather_nd_node = graph.append<luci::CircleGatherNd>(graph.input_node, indices_const); + graph.complete(); + + { + auto input_node = graph.input_node; + input_node->shape({1, 4, 4, 3}); + luci::test::graph_input_shape(input_node); + } + { + // Does not matter, because test should fail anyway + auto output_node = graph.output_node; + output_node->shape({0, 0, 0}); + luci::test::graph_output_shape(output_node); + } + + { + indices_const->shape({1, 2, 5}); + } + + // pre-check + ASSERT_FALSE(loco::shape_known(gather_nd_node)); + + // had to pack into lambda to check throw + auto lambda = [&]() { + // shape inference + while (shape_pass(graph.graph()) == true) + ; + }; + + ASSERT_THROW(lambda(), oops::InternalExn); +} + +TEST(CircleShapeInferenceRuleTest, CircleResizeNearestNeighbor) +{ + luci::test::TestGraph graph; + auto size_const = graph.append<luci::CircleConst>(); + size_const->dtype(loco::DataType::S32); + size_const->rank(1); + size_const->dim(0) = 2; + size_const->size<loco::DataType::S32>(2); + size_const->at<loco::DataType::S32>(0) = 16; + size_const->at<loco::DataType::S32>(1) = 16; + auto resize_node = graph.append<luci::CircleResizeNearestNeighbor>(graph.input_node, size_const); + graph.complete(); + + { + auto input_node = graph.input_node; + input_node->shape({1, 4, 4, 3}); + luci::test::graph_input_shape(input_node); + } + { + auto output_node = graph.output_node; + output_node->from(resize_node); + luci::test::graph_output_shape(output_node); + } + + // pre-check + ASSERT_FALSE(loco::shape_known(resize_node)); + + // shape inference + while (shape_pass(graph.graph()) == true) + ; + + // Verify + { + ASSERT_TRUE(loco::shape_known(resize_node)); + + auto shape = loco::shape_get(resize_node).as<loco::TensorShape>(); + ASSERT_EQ(4, shape.rank()); + ASSERT_EQ(1, shape.dim(0)); + ASSERT_EQ(16, shape.dim(1)); + ASSERT_EQ(16, shape.dim(2)); + ASSERT_EQ(3, shape.dim(3)); + } +} + +TEST(CircleShapeInferenceRuleTest, CircleResizeBilinear) +{ + luci::test::TestGraph graph; + auto size_const = graph.append<luci::CircleConst>(); + size_const->dtype(loco::DataType::S32); + size_const->rank(1); + size_const->dim(0) = 2; + size_const->size<loco::DataType::S32>(2); + size_const->at<loco::DataType::S32>(0) = 16; + size_const->at<loco::DataType::S32>(1) = 16; + auto resize_node = graph.append<luci::CircleResizeBilinear>(graph.input_node, size_const); + graph.complete(); + + { + auto input_node = graph.input_node; + input_node->shape({1, 4, 4, 3}); + luci::test::graph_input_shape(input_node); + } + { + auto output_node = graph.output_node; + output_node->from(resize_node); + luci::test::graph_output_shape(output_node); + } + + // pre-check + ASSERT_FALSE(loco::shape_known(resize_node)); + + // shape inference + while (shape_pass(graph.graph()) == true) + ; + + // Verify + { + ASSERT_TRUE(loco::shape_known(resize_node)); + + auto shape = loco::shape_get(resize_node).as<loco::TensorShape>(); + ASSERT_EQ(4, shape.rank()); + ASSERT_EQ(1, shape.dim(0)); + ASSERT_EQ(16, shape.dim(1)); + ASSERT_EQ(16, shape.dim(2)); + ASSERT_EQ(3, shape.dim(3)); } } diff --git a/compiler/luci/service/src/CircleTypeInference.cpp b/compiler/luci/service/src/CircleTypeInference.cpp index 669906159..aa8524a55 100644 --- a/compiler/luci/service/src/CircleTypeInference.cpp +++ b/compiler/luci/service/src/CircleTypeInference.cpp @@ -15,19 +15,13 @@ */ #include "luci/Service/CircleTypeInference.h" -#include "luci/Service/CircleTypeInferenceRule.h" -#include <luci/IR/CircleDialect.h> - -#include <loco/IR/CanonicalNode.h> -#include <loco/IR/CanonicalNodeVisitor.h> -#include <loco/IR/CanonicalDialect.h> +#include <loco.h> #include <loco/Service/TypeInference.h> + #include <mio/circle/schema_generated.h> #include <oops/InternalExn.h> -#include <memory> -#include <stdexcept> #include <type_traits> namespace diff --git a/compiler/luci/service/src/CircleTypeInferenceRule.cpp b/compiler/luci/service/src/CircleTypeInferenceRule.cpp index 21a28c1b6..de2ba3ea4 100644 --- a/compiler/luci/service/src/CircleTypeInferenceRule.cpp +++ b/compiler/luci/service/src/CircleTypeInferenceRule.cpp @@ -33,18 +33,45 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT loco::DataType visit(const luci::CircleAdd *node) final { return loco::dtype_get(node->x()); } + loco::DataType visit(const luci::CircleAddN *node) final + { + auto dtype = loco::dtype_get(node->inputs(0)); + + for (uint32_t idx = 1; idx < node->arity(); ++idx) + { + auto dtype_idx = loco::dtype_get(node->inputs(idx)); + if (dtype != dtype_idx) + { + INTERNAL_EXN_V("ADD_N dtype not same as the first input: ", idx); + } + } + + return loco::dtype_get(node->inputs(0)); + } + loco::DataType visit(const luci::CircleArgMax *node) final { return node->output_type(); } + loco::DataType visit(const luci::CircleArgMin *node) final { return node->output_type(); } + loco::DataType visit(const luci::CircleAveragePool2D *node) final { return loco::dtype_get(node->value()); } + loco::DataType visit(const luci::CircleBatchMatMul *node) final + { + return loco::dtype_get(node->x()); + } + loco::DataType visit(const luci::CircleBatchToSpaceND *node) final { return loco::dtype_get(node->input()); } + loco::DataType visit(const luci::CircleCast *node) final { return node->dtype(); } + + loco::DataType visit(const luci::CircleCeil *node) final { return loco::dtype_get(node->x()); } + loco::DataType visit(const luci::CircleConcatenation *node) final { // TODO Support when CircleConcatenation has 0 input @@ -65,6 +92,20 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT loco::DataType visit(const luci::CircleCos *node) final { return loco::dtype_get(node->x()); } + loco::DataType visit(const luci::CircleCustom *node) final + { + if (node->custom_code() == "BatchMatMulV2") + { + return loco::dtype_get(node->inputs(0)); + } + return node->dtype(); + } + + loco::DataType visit(const luci::CircleDepthToSpace *node) final + { + return loco::dtype_get(node->input()); + } + loco::DataType visit(const luci::CircleDepthwiseConv2D *node) final { return loco::dtype_get(node->input()); @@ -72,15 +113,94 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT loco::DataType visit(const luci::CircleDiv *node) final { return loco::dtype_get(node->x()); } + loco::DataType visit(const luci::CircleElu *node) final + { + return loco::dtype_get(node->features()); + } + loco::DataType visit(const luci::CircleEqual *) final { return loco::DataType::BOOL; } loco::DataType visit(const luci::CircleExp *node) final { return loco::dtype_get(node->x()); } + loco::DataType visit(const luci::CircleExpandDims *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleFill *node) final + { + return loco::dtype_get(node->value()); + } + + loco::DataType visit(const luci::CircleFloor *node) final { return loco::dtype_get(node->x()); } + + loco::DataType visit(const luci::CircleFloorDiv *node) final + { + return loco::dtype_get(node->x()); + } + + loco::DataType visit(const luci::CircleFloorMod *node) final + { + return loco::dtype_get(node->x()); + } + loco::DataType visit(const luci::CircleFullyConnected *node) final { return loco::dtype_get(node->input()); } + loco::DataType visit(const luci::CircleGather *node) final + { + return loco::dtype_get(node->params()); + } + + loco::DataType visit(const luci::CircleGatherNd *node) final + { + return loco::dtype_get(node->params()); + } + + loco::DataType visit(const luci::CircleGreater *) final { return loco::DataType::BOOL; } + + loco::DataType visit(const luci::CircleGreaterEqual *) final { return loco::DataType::BOOL; } + + loco::DataType visit(const luci::CircleIf *node) final + { + // Type of If is not used. Just use input 0 + assert(node->input_count() > 0); + return loco::dtype_get(node->input(0)); + } + + loco::DataType visit(const luci::CircleL2Normalize *node) final + { + return loco::dtype_get(node->x()); + } + + loco::DataType visit(const luci::CircleL2Pool2D *node) final + { + return loco::dtype_get(node->value()); + } + + loco::DataType visit(const luci::CircleLeakyRelu *node) final + { + return loco::dtype_get(node->features()); + } + + loco::DataType visit(const luci::CircleLess *) final { return loco::DataType::BOOL; } + + loco::DataType visit(const luci::CircleLessEqual *) final { return loco::DataType::BOOL; } + + loco::DataType visit(const luci::CircleLocalResponseNormalization *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleLog *node) final { return loco::dtype_get(node->x()); } + + loco::DataType visit(const luci::CircleLogicalAnd *node) final + { + return loco::dtype_get(node->x()); + } + loco::DataType visit(const luci::CircleLogicalNot *node) final { return loco::dtype_get(node->x()); @@ -91,6 +211,26 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT return loco::dtype_get(node->x()); } + loco::DataType visit(const luci::CircleLogistic *node) final + { + return loco::dtype_get(node->x()); + } + + loco::DataType visit(const luci::CircleLogSoftmax *node) final + { + return loco::dtype_get(node->logits()); + } + + loco::DataType visit(const luci::CircleMatrixDiag *node) final + { + return loco::dtype_get(node->diagonal()); + } + + loco::DataType visit(const luci::CircleMatrixSetDiag *node) final + { + return loco::dtype_get(node->input()); + } + loco::DataType visit(const luci::CircleMaximum *node) final { return loco::dtype_get(node->x()); } loco::DataType visit(const luci::CircleMaxPool2D *node) final @@ -103,6 +243,17 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT return loco::dtype_get(node->input()); } + loco::DataType visit(const luci::CircleMinimum *node) final { return loco::dtype_get(node->x()); } + + loco::DataType visit(const luci::CircleMirrorPad *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleNeg *node) final { return loco::dtype_get(node->x()); } + + loco::DataType visit(const luci::CircleNotEqual *) final { return loco::DataType::BOOL; } + loco::DataType visit(const luci::CirclePack *node) final { // Only support CirclePack with one or more inputs @@ -117,8 +268,63 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT loco::DataType visit(const luci::CirclePad *node) final { return loco::dtype_get(node->input()); } + loco::DataType visit(const luci::CirclePow *node) final + { + // TODO make sure types cannot differ + auto x_type = loco::dtype_get(node->x()); + auto y_type = loco::dtype_get(node->y()); + + if (x_type != y_type) + INTERNAL_EXN("Different datatype for x and y are not supported"); + + return x_type; + } + + loco::DataType visit(const luci::CirclePRelu *node) final + { + auto input_type = loco::dtype_get(node->input()); + auto alpha_type = loco::dtype_get(node->alpha()); + + if (input_type != alpha_type) + INTERNAL_EXN("Different datatype for input and alpha are not supported"); + + return input_type; + } + + loco::DataType visit(const luci::CircleRange *node) final + { + return loco::dtype_get(node->start()); + } + + loco::DataType visit(const luci::CircleRank *) final { return loco::DataType::S32; } + loco::DataType visit(const luci::CircleMul *node) final { return loco::dtype_get(node->x()); } + loco::DataType visit(const luci::CircleOneHot *node) final + { + return loco::dtype_get(node->on_value()); + } + + loco::DataType visit(const luci::CircleReduceAny *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleReduceMax *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleReduceMin *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleReduceProd *node) final + { + return loco::dtype_get(node->input()); + } + loco::DataType visit(const luci::CircleRelu *node) final { return loco::dtype_get(node->features()); @@ -129,28 +335,132 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT return loco::dtype_get(node->features()); } + loco::DataType visit(const luci::CircleReluN1To1 *node) final + { + return loco::dtype_get(node->features()); + } + loco::DataType visit(const luci::CircleReshape *node) final { return loco::dtype_get(node->tensor()); } + loco::DataType visit(const luci::CircleResizeBilinear *) final { return loco::DataType::FLOAT32; } + + loco::DataType visit(const luci::CircleResizeNearestNeighbor *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleReverseSequence *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleReverseV2 *node) final + { + return loco::dtype_get(node->tensor()); + } + + loco::DataType visit(const luci::CircleRound *node) final { return loco::dtype_get(node->x()); } + loco::DataType visit(const luci::CircleRsqrt *node) final { return loco::dtype_get(node->x()); } + loco::DataType visit(const luci::CircleScatterNd *node) final + { + return loco::dtype_get(node->updates()); + } + + loco::DataType visit(const luci::CircleSegmentSum *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleSelect *node) final + { + assert(loco::dtype_get(node->t()) == loco::dtype_get(node->e())); + return loco::dtype_get(node->t()); + } + + loco::DataType visit(const luci::CircleSelectV2 *node) final + { + assert(loco::dtype_get(node->t()) == loco::dtype_get(node->e())); + return loco::dtype_get(node->t()); + } + + loco::DataType visit(const luci::CircleShape *node) final { return node->out_type(); } + + loco::DataType visit(const luci::CircleSin *node) final { return loco::dtype_get(node->x()); } + + loco::DataType visit(const luci::CircleSlice *node) final + { + return loco::dtype_get(node->input()); + } + loco::DataType visit(const luci::CircleSoftmax *node) final { return loco::dtype_get(node->logits()); } + loco::DataType visit(const luci::CircleSpaceToBatchND *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleSpaceToDepth *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleSparseToDense *node) final + { + return loco::dtype_get(node->values()); + } + + loco::DataType visit(const luci::CircleSplit *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleSplitV *node) final + { + return loco::dtype_get(node->input()); + } + loco::DataType visit(const luci::CircleSqrt *node) final { return loco::dtype_get(node->x()); } + loco::DataType visit(const luci::CircleSquare *node) final { return loco::dtype_get(node->x()); } + loco::DataType visit(const luci::CircleSquaredDifference *node) final { return loco::dtype_get(node->x()); } + loco::DataType visit(const luci::CircleSqueeze *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleStridedSlice *node) final + { + return loco::dtype_get(node->input()); + } + loco::DataType visit(const luci::CircleSub *node) final { return loco::dtype_get(node->x()); } - // TODO CircleTanh + loco::DataType visit(const luci::CircleSum *node) final { return loco::dtype_get(node->input()); } + + loco::DataType visit(const luci::CircleTanh *node) final { return loco::dtype_get(node->x()); } + + loco::DataType visit(const luci::CircleTile *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleTopKV2 *node) final + { + return loco::dtype_get(node->input()); + } loco::DataType visit(const luci::CircleTranspose *node) final { @@ -162,7 +472,33 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT return loco::dtype_get(node->outBackprop()); } + loco::DataType visit(const luci::CircleUnpack *node) final + { + return loco::dtype_get(node->value()); + } + + loco::DataType visit(const luci::CircleWhere *) final { return loco::DataType::S64; } + + loco::DataType visit(const luci::CircleWhile *node) final + { + // Type of While is not used. Just use input 0 + assert(node->input_count() > 0); + return loco::dtype_get(node->input(0)); + } + + loco::DataType visit(const luci::CircleZerosLike *node) final + { + return loco::dtype_get(node->input()); + } + // Circle Only + loco::DataType visit(const luci::CircleBCQFullyConnected *) final + { + return loco::DataType::FLOAT32; + } + + loco::DataType visit(const luci::CircleBCQGather *) final { return loco::DataType::FLOAT32; } + loco::DataType visit(const luci::CircleInstanceNorm *node) final { return loco::dtype_get(node->input()); @@ -173,7 +509,116 @@ struct TypeInferenceAlgorithm final : public luci::CircleNodeVisitor<loco::DataT loco::DataType visit(const luci::CircleOutput *node) final { - return loco::dtype_get(node->from()); + auto graph_outputs = node->graph()->outputs(); + auto graph_output = graph_outputs->at(node->index()); + auto output_dtype = graph_output->dtype(); + + if (dynamic_cast<luci::CircleOutputDummy *>(node->from()) == nullptr && + dynamic_cast<luci::CircleOutputExclude *>(node->from()) == nullptr) + { + // We don't care for the type if from() is CircleOutputDummy or CircleOutputExclude + // from() type should match that of CircleOutput + assert(output_dtype == loco::dtype_get(node->from())); + } + return output_dtype; + } + + loco::DataType visit(const luci::CircleOutputDummy *node) final { return node->dtype(); } + + loco::DataType visit(const luci::CircleOutputExclude *node) final { return node->dtype(); } + + loco::DataType visit(const luci::CircleCustomOut *node) final { return node->dtype(); } + + loco::DataType visit(const luci::CircleIfOut *node) final + { + /** + * @note IF operator type and shape are that of the "then" and "else" + * Graph Outputs. + */ + auto circle_if = dynamic_cast<const luci::CircleIf *>(node->input()); + if (circle_if == nullptr) + { + INTERNAL_EXN("CircleIf IR is not configured correctly"); + } + + auto index = node->index(); + auto then_graph = circle_if->then_graph(); + auto else_graph = circle_if->else_graph(); + assert(then_graph != nullptr); + assert(else_graph != nullptr); + + // shape and type are assumed to be same + // these are checked at post_import_graph() in Import + auto then_outputs = loco::output_nodes(then_graph); + auto else_outputs = loco::output_nodes(else_graph); + assert(then_outputs.size() == else_outputs.size()); + assert(index < static_cast<int32_t>(then_outputs.size())); + + auto then_out = loco::must_cast<luci::CircleOutput *>(then_outputs.at(index)); + auto else_out = loco::must_cast<luci::CircleOutput *>(else_outputs.at(index)); + + auto then_graph_outputs = then_graph->outputs(); // loco::GraphOutput items + auto else_graph_outputs = else_graph->outputs(); + assert(then_graph_outputs->size() == else_graph_outputs->size()); + + auto then_graph_output = then_graph_outputs->at(then_out->index()); + auto else_graph_output = else_graph_outputs->at(else_out->index()); + (void)else_graph_output; // make compiler happy for unused variable warnings + assert(then_graph_output->dtype() == else_graph_output->dtype()); + + return then_graph_output->dtype(); + } + + loco::DataType visit(const luci::CircleSplitOut *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleSplitVOut *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleTopKV2Out *node) final + { + // First output is same as input + if (node->index() == 0) + return loco::dtype_get(node->input()); + // Second outout is always S32 + assert(node->index() == 1); + return loco::DataType::S32; + } + + loco::DataType visit(const luci::CircleUnpackOut *node) final + { + return loco::dtype_get(node->input()); + } + + loco::DataType visit(const luci::CircleWhileOut *node) final + { + /** + * @note WHILE operator's type is the same with the "cond" + * Graph Input. + */ + auto circle_while = dynamic_cast<const luci::CircleWhile *>(node->input()); + if (circle_while == nullptr) + { + INTERNAL_EXN("CircleWhile IR is not configured correctly"); + } + + auto index = node->index(); + auto cond_graph = circle_while->cond_graph(); + assert(cond_graph != nullptr); + + // Assumption: the index of CircleWhileOut matches with the index of input nodes returned by + // loco::input_nodes + auto cond_inputs = loco::input_nodes(cond_graph); + auto cond_in = loco::must_cast<luci::CircleInput *>(cond_inputs.at(index)); + + auto cond_graph_inputs = cond_graph->inputs(); + auto cond_graph_input = cond_graph_inputs->at(cond_in->index()); + + return cond_graph_input->dtype(); } }; @@ -193,7 +638,8 @@ bool CircleTypeInferenceRule::infer(const loco::Node *node, loco::DataType &dtyp TypeInferenceAlgorithm alg; - dtype = dynamic_cast<const CircleNode *>(node)->accept(&alg); + auto circle_node = loco::must_cast<const CircleNode *>(node); + dtype = circle_node->accept(&alg); assert(dtype != loco::DataType::Unknown); return true; diff --git a/compiler/luci/service/src/CircleTypeInferenceRule.test.cpp b/compiler/luci/service/src/CircleTypeInferenceRule.test.cpp index 29f45173e..711a489af 100644 --- a/compiler/luci/service/src/CircleTypeInferenceRule.test.cpp +++ b/compiler/luci/service/src/CircleTypeInferenceRule.test.cpp @@ -32,26 +32,32 @@ TEST(CircleTypeInferenceRuleTest, minimal_with_CircleRelu) { // Create a simple network luci::test::TestGraph graph; - auto tfl_node = graph.append<luci::CircleRelu>(graph.pull); - graph.complete(tfl_node); + auto relu_node = graph.append<luci::CircleRelu>(graph.input_node); + graph.complete(relu_node); - graph.pull->dtype(loco::DataType::S32); + // set dtype for nodes; like setting them in import + graph.input_node->dtype(loco::DataType::S32); + relu_node->dtype(loco::DataType::S32); + graph.output_node->dtype(loco::DataType::S32); + + luci::test::graph_input_dtype(graph.input_node); + luci::test::graph_output_dtype(graph.output_node); // pre-check - ASSERT_FALSE(loco::dtype_known(tfl_node)); + ASSERT_FALSE(loco::dtype_known(relu_node)); // type inference - luci::CircleTypeInferenceRule tfl_rule; + luci::CircleTypeInferenceRule circle_rule; loco::CanonicalTypeInferenceRule canon_rule; loco::MultiDialectTypeInferenceRule rules; rules.bind(loco::CanonicalDialect::get(), &canon_rule); - rules.bind(luci::CircleDialect::get(), &tfl_rule); + rules.bind(luci::CircleDialect::get(), &circle_rule); loco::apply(&rules).to(graph.g.get()); // Verify - ASSERT_TRUE(loco::dtype_known(tfl_node)); - auto type = loco::dtype_get(tfl_node); - ASSERT_EQ(type, loco::DataType::S32); + ASSERT_TRUE(loco::dtype_known(relu_node)); + auto type = loco::dtype_get(relu_node); + ASSERT_EQ(loco::DataType::S32, type); } diff --git a/compiler/luci/service/src/GraphBlock.h b/compiler/luci/service/src/GraphBlock.h deleted file mode 100644 index 2a455888a..000000000 --- a/compiler/luci/service/src/GraphBlock.h +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef __GRAPH_BLOCK_H__ -#define __GRAPH_BLOCK_H__ - -#include <loco.h> -#include <loco/Service/ShapeInference.h> - -#include <oops/InternalExn.h> - -#include <functional> - -// TODO Change all Canonical nodes to Circle nodes - -namespace luci -{ - -/// @brief feature layout of TFlite/Circle file -enum class FeatureLayout -{ - NHWC, -}; - -/// @brief Creates a loco::FeatureEncode with T layout (NHWC for tflite) and add it to graph. -template <FeatureLayout T> loco::FeatureEncode *make_feature_encode(loco::Node *input_for_encode); - -/// @brief Creates a loco::FeatureDecode with T layout (NHWC for tflite) and add it to graph. -template <FeatureLayout T> loco::FeatureDecode *make_feature_decode(loco::Node *input_for_decode); - -enum class FilterLayout -{ - OHWI, // a.k.a., NHWC, Tensorflow Lite uses this layout for filter - HWIO, // a.k.a., HWCN, Tensorflow uses this layout for filter -}; - -/// @brief Create a loco::FilterEncode of given layout -template <FilterLayout T> loco::FilterEncode *make_filter_encode(loco::Node *input_for_encode); - -/// @brief Create a loco::FilterDecode of given layout -template <FilterLayout T> loco::FilterDecode *make_filter_decode(loco::Node *input_for_decode); - -enum class DepthwiseFilterLayout -{ - HWCM, -}; - -/// @brief Create a loco::DepthwiseFilterDecode of given layout -template <DepthwiseFilterLayout T> -loco::DepthwiseFilterDecode *make_dw_filter_decode(loco::Node *input_for_decode); - -enum class MatrixLayout -{ - HW, - WH -}; - -/// @brief Create a loco::MatrixEncode of given layout -template <MatrixLayout T> loco::MatrixEncode *make_matrix_encode(loco::Node *input_for_encode); - -/// @brief Create a loco::MatrixDecode of given layout -template <MatrixLayout T> loco::MatrixDecode *make_matrix_decode(loco::Node *input_for_decode); - -} // luci - -// -// DomainConverter -// - -/** - * Some canonical nodes can have input of various loco::Domain, e.g., loco::Domain::Tensor, - * loco::Domain::Feature, etc. However, TFL node accepts only loco::Domain::Tensor. - * So, When converting such canonical node to TFL node and input(s) of a canonical node are not - * loco::Domain::Tensor, additional nodes need to be inserted. - * - * The following two classes helps this insertion. - * - * For example, in case of loco::Relu conversion, - * - * Before: - * - * A (output: feature) -- loco::ReLU --- B (input:feature) - * - * After: - * - * A -- loco::FeatureDecode -- locoex::TFLRelu -- loco::FeatureEncode --- B - * - * loco::ReLU (dead node) - */ - -namespace luci -{ - -/** - * @brief Handles input(s) while converting a canonical node to TFL node(s). - * This class informs DomainConverter how to handle inputs of a specific canonical node. - */ -template <class CanonicalT, class TFLT> class InputHandler -{ -public: - /** - * @brief Assign origin's inputs to replacer's inputs. - * (This is called when origin belongs in Tensor domain.) - */ - virtual void handover(CanonicalT *origin, TFLT *replacer) = 0; - - /** - * @brief Returns the list of inputs that needs to have FeatureDecode as its input. - * (This is called when origin belongs in Feature domain.) - */ - virtual std::vector<loco::Node *> getInputsToConvert(CanonicalT *origin) = 0; - - /// @brief Set the inputs of replacer to new_inputs - virtual void set(TFLT *replacer, std::vector<loco::Node *> &new_inputs) = 0; - - /// @brief Set the inputs to nullptr - virtual void nullify(CanonicalT *origin) = 0; -}; - -/** - * @brief Class to handle domain conversion while converting a canonical node to TFL node(s) - */ -template <class CanonicalT, class TFLT> class DomainConverter -{ -public: - template <FeatureLayout FeatureLayoutT> - TFLT *convert(CanonicalT *origin, InputHandler<CanonicalT, TFLT> &input_handler); -}; - -/** - * @brief Performs domain conversion - * - * 1. if origin belong to loco::Domain::Tensor, and replace origin to a TFL node. - * 2. if origin belong to loco::Domain::Feature, insert loco::FeatureDecode for input(s) and - * insert loco::FeatureEncode for output. Then replace origin to a TFL node. - * - * @return new TFL node; nullptr if shape of origin cannot be known - */ -template <class CanonicalT, class TFLT> -template <FeatureLayout FeatureLayoutT> -TFLT *DomainConverter<CanonicalT, TFLT>::convert(CanonicalT *origin, - InputHandler<CanonicalT, TFLT> &input_handler) -{ - static_assert(FeatureLayoutT == FeatureLayout::NHWC, "Feature layout should be NHWC"); - - if (!loco::shape_known(origin)) - { - return nullptr; - } - - auto tfl_node = origin->graph()->nodes()->template create<TFLT>(); - - // when the input is Tensor, just replace canonical node to TFL node. - if (loco::shape_get(origin).domain() == loco::Domain::Tensor) - { - input_handler.handover(origin, tfl_node); - - loco::replace(origin).with(tfl_node); - input_handler.nullify(origin); - - return tfl_node; - } - else if (loco::shape_get(origin).domain() == loco::Domain::Feature) - { - std::vector<loco::Node *> feature_decodes; - - for (auto input : input_handler.getInputsToConvert(origin)) - { - auto dec = make_feature_decode<FeatureLayoutT>(input); - feature_decodes.emplace_back(dec); - } - - input_handler.set(tfl_node, feature_decodes); - - auto enc = make_feature_encode<FeatureLayoutT>(tfl_node); - - loco::replace(origin).with(enc); - input_handler.nullify(origin); - - return tfl_node; - } - else - INTERNAL_EXN_V("Unsupported loco::Domain", oops::to_uint32(loco::shape_get(origin).domain())); -} - -} // namespace luci - -#endif //__GRAPH_BLOCK_H__ diff --git a/compiler/luci/service/src/GraphBlock.test.cpp b/compiler/luci/service/src/GraphBlock.test.cpp deleted file mode 100644 index 1da8c18fa..000000000 --- a/compiler/luci/service/src/GraphBlock.test.cpp +++ /dev/null @@ -1,246 +0,0 @@ -/* - * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "GraphBlock.h" - -#include "Check.h" - -#include <loco.h> - -#include <memory> - -// TODO Change all Canonical nodes to Circle nodes - -namespace -{ - -template <luci::FeatureLayout T> loco::Permutation<loco::Domain::Feature> perm(); - -template <> loco::Permutation<loco::Domain::Feature> perm<luci::FeatureLayout::NHWC>() -{ - // Make NHWC permutation for encoder and decoder - loco::Permutation<loco::Domain::Feature> NHWC; - - NHWC.axis(loco::FeatureAxis::Count) = 0; - NHWC.axis(loco::FeatureAxis::Height) = 1; - NHWC.axis(loco::FeatureAxis::Width) = 2; - NHWC.axis(loco::FeatureAxis::Depth) = 3; - - return NHWC; -} - -template <luci::FilterLayout T> loco::Permutation<loco::Domain::Filter> perm(); - -template <> loco::Permutation<loco::Domain::Filter> perm<luci::FilterLayout::HWIO>() -{ - loco::Permutation<loco::Domain::Filter> HWIO; // a.k.a., HWCN - - HWIO.axis(loco::FilterAxis::Height) = 0; - HWIO.axis(loco::FilterAxis::Width) = 1; - HWIO.axis(loco::FilterAxis::Depth) = 2; - HWIO.axis(loco::FilterAxis::Count) = 3; - - return HWIO; -} - -template <> loco::Permutation<loco::Domain::Filter> perm<luci::FilterLayout::OHWI>() -{ - - // Make NHWC permutation for encoder and decoder - loco::Permutation<loco::Domain::Filter> OHWI; // a.k.a., NHWC - - OHWI.axis(loco::FilterAxis::Count) = 0; - OHWI.axis(loco::FilterAxis::Height) = 1; - OHWI.axis(loco::FilterAxis::Width) = 2; - OHWI.axis(loco::FilterAxis::Depth) = 3; - - return OHWI; -} - -template <luci::DepthwiseFilterLayout T> loco::Permutation<loco::Domain::DepthwiseFilter> perm(); - -template <> -loco::Permutation<loco::Domain::DepthwiseFilter> perm<luci::DepthwiseFilterLayout::HWCM>() -{ - loco::Permutation<loco::Domain::DepthwiseFilter> HWCM; - - HWCM.axis(loco::DepthwiseFilterAxis::Height) = 0; - HWCM.axis(loco::DepthwiseFilterAxis::Width) = 1; - HWCM.axis(loco::DepthwiseFilterAxis::Depth) = 2; - HWCM.axis(loco::DepthwiseFilterAxis::Multiplier) = 3; - - return HWCM; -} - -template <luci::MatrixLayout T> loco::Permutation<loco::Domain::Matrix> perm(); - -template <> loco::Permutation<loco::Domain::Matrix> perm<luci::MatrixLayout::HW>() -{ - loco::Permutation<loco::Domain::Matrix> HW; - - HW.axis(loco::MatrixAxis::Height) = 0; - HW.axis(loco::MatrixAxis::Width) = 1; - - return HW; -} - -template <> loco::Permutation<loco::Domain::Matrix> perm<luci::MatrixLayout::WH>() -{ - loco::Permutation<loco::Domain::Matrix> WH; - - WH.axis(loco::MatrixAxis::Height) = 1; - WH.axis(loco::MatrixAxis::Width) = 0; - - return WH; -} - -} // namespace - -namespace luci -{ - -template <FeatureLayout T> loco::FeatureEncode *make_feature_encode(loco::Node *input_for_encode) -{ - LUCI_ASSERT(input_for_encode != nullptr, "input should not be nullptr"); - loco::Graph *g = input_for_encode->graph(); - - auto encoder = std::make_unique<loco::PermutingEncoder<loco::Domain::Feature>>(); - - encoder->perm(perm<T>()); - - auto enc = g->nodes()->create<loco::FeatureEncode>(); - enc->input(input_for_encode); - enc->encoder(std::move(encoder)); - - return enc; -} - -template <FeatureLayout T> loco::FeatureDecode *make_feature_decode(loco::Node *input_for_decode) -{ - LUCI_ASSERT(input_for_decode != nullptr, "input should not be nullptr"); - loco::Graph *g = input_for_decode->graph(); - - auto decoder = std::make_unique<loco::PermutingDecoder<loco::Domain::Feature>>(); - - decoder->perm(perm<T>()); - - auto dec = g->nodes()->create<loco::FeatureDecode>(); - dec->input(input_for_decode); - dec->decoder(std::move(decoder)); - - return dec; -} - -template <FilterLayout T> loco::FilterEncode *make_filter_encode(loco::Node *input_for_encode) -{ - LUCI_ASSERT(input_for_encode != nullptr, "filter should not be nullptr"); - loco::Graph *g = input_for_encode->graph(); - - auto encoder = std::make_unique<loco::PermutingEncoder<loco::Domain::Filter>>(); - - encoder->perm(perm<T>()); - - auto enc = g->nodes()->create<loco::FilterEncode>(); - enc->input(input_for_encode); - enc->encoder(std::move(encoder)); - - return enc; -} - -template <FilterLayout T> loco::FilterDecode *make_filter_decode(loco::Node *input_for_decode) -{ - LUCI_ASSERT(input_for_decode != nullptr, "filter should not be nullptr"); - loco::Graph *g = input_for_decode->graph(); - - auto decoder = std::make_unique<loco::PermutingDecoder<loco::Domain::Filter>>(); - - decoder->perm(perm<T>()); - - auto dec = g->nodes()->create<loco::FilterDecode>(); - dec->input(input_for_decode); - dec->decoder(std::move(decoder)); - - return dec; -} - -template <DepthwiseFilterLayout T> -loco::DepthwiseFilterDecode *make_dw_filter_decode(loco::Node *input_for_decode) -{ - LUCI_ASSERT(input_for_decode != nullptr, "filter should not be nullptr"); - loco::Graph *g = input_for_decode->graph(); - - auto decoder = std::make_unique<loco::PermutingDecoder<loco::Domain::DepthwiseFilter>>(); - - decoder->perm(perm<T>()); - - auto dec = g->nodes()->create<loco::DepthwiseFilterDecode>(); - dec->input(input_for_decode); - dec->decoder(std::move(decoder)); - - return dec; -} - -template <MatrixLayout T> loco::MatrixEncode *make_matrix_encode(loco::Node *input_for_encode) -{ - LUCI_ASSERT(input_for_encode != nullptr, "input should not be nullptr"); - loco::Graph *g = input_for_encode->graph(); - - auto encoder = std::make_unique<loco::PermutingEncoder<loco::Domain::Matrix>>(); - - encoder->perm(perm<T>()); - - auto enc = g->nodes()->create<loco::MatrixEncode>(); - enc->input(input_for_encode); - enc->encoder(std::move(encoder)); - - return enc; -} - -template <MatrixLayout T> loco::MatrixDecode *make_matrix_decode(loco::Node *input_for_decode) -{ - LUCI_ASSERT(input_for_decode != nullptr, "input should not be nullptr"); - loco::Graph *g = input_for_decode->graph(); - - auto decoder = std::make_unique<loco::PermutingDecoder<loco::Domain::Matrix>>(); - - decoder->perm(perm<T>()); - - auto dec = g->nodes()->create<loco::MatrixDecode>(); - dec->input(input_for_decode); - dec->decoder(std::move(decoder)); - - return dec; -} - -// template instantiation -template loco::FeatureEncode * -make_feature_encode<FeatureLayout::NHWC>(loco::Node *input_for_encode); - -template loco::FeatureDecode * -make_feature_decode<FeatureLayout::NHWC>(loco::Node *input_for_encode); - -template loco::FilterEncode *make_filter_encode<FilterLayout::HWIO>(loco::Node *input_for_encode); -template loco::FilterDecode *make_filter_decode<FilterLayout::OHWI>(loco::Node *input_for_decode); - -template loco::DepthwiseFilterDecode * -make_dw_filter_decode<DepthwiseFilterLayout::HWCM>(loco::Node *input_for_decode); - -template loco::MatrixEncode *make_matrix_encode<MatrixLayout::HW>(loco::Node *input_for_encode); -template loco::MatrixEncode *make_matrix_encode<MatrixLayout::WH>(loco::Node *input_for_encode); -template loco::MatrixDecode *make_matrix_decode<MatrixLayout::HW>(loco::Node *input_for_decode); -template loco::MatrixDecode *make_matrix_decode<MatrixLayout::WH>(loco::Node *input_for_decode); - -} // namespace luci diff --git a/compiler/luci/service/src/ShapeInfer_StridedSlice.cpp b/compiler/luci/service/src/ShapeInfer_StridedSlice.cpp new file mode 100644 index 000000000..341201148 --- /dev/null +++ b/compiler/luci/service/src/ShapeInfer_StridedSlice.cpp @@ -0,0 +1,298 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * Copyright 2018 The TensorFlow Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ShapeInfer_StridedSlice.h" +#include "Check.h" + +#include <luci/IR/CircleNode.h> +#include <loco/IR/DataType.h> +#include <loco/IR/NodeShape.h> +#include <oops/InternalExn.h> +#include <loco/Service/ShapeInference.h> + +#include <cmath> +#include <cstdint> +#include <limits> + +namespace +{ + +// This Op only supports 1-4D cases and since we use the reference 4D +// implementation, the 1-3D tensors are mapped to 4D. +const int kMaxDim = 4; + +const loco::DataType S32 = loco::DataType::S32; + +using int8 = int8_t; +using int16 = int16_t; + +struct StridedSliceParams +{ + int8 start_indices_count; + int16 start_indices[kMaxDim]; + int8 stop_indices_count; + int16 stop_indices[kMaxDim]; + int8 strides_count; + int16 strides[kMaxDim]; + + int16 begin_mask; + int16 ellipsis_mask; + int16 end_mask; + int16 new_axis_mask; + int16 shrink_axis_mask; +}; + +// Use until std::clamp() is available from C++17. +inline int Clamp(const int32_t v, const int32_t lo, const int32_t hi) +{ + LUCI_ASSERT(!(hi < lo), "Clamp hi < lo"); + if (hi < v) + return hi; + if (v < lo) + return lo; + return v; +} + +// Return the index for the first element along that axis. This index will be a +// positive integer between [0, axis_size - 1] that can be used to index +// directly into the data. +inline int StartForAxis(const StridedSliceParams ¶ms, const loco::TensorShape &input_shape, + uint32_t axis) +{ + const auto begin_mask = params.begin_mask; + const auto *start_indices = params.start_indices; + const auto *strides = params.strides; + const int32_t axis_size = static_cast<int>(input_shape.dim(axis).value()); + if (axis_size == 0) + { + return 0; + } + // Begin with the specified index. + int32_t start = start_indices[axis]; + + // begin_mask override + if (begin_mask & (1 << axis)) + { + if (strides[axis] > 0) + { + // Forward iteration - use the first element. These values will get + // clamped below (Note: We could have set them to 0 and axis_size-1, but + // use lowest() and max() to maintain symmetry with StopForAxis()) + start = std::numeric_limits<int32_t>::lowest(); + } + else + { + // Backward iteration - use the last element. + start = std::numeric_limits<int32_t>::max(); + } + } + + // Handle negative indices + if (start < 0) + { + start += axis_size; + } + + // Clamping + start = Clamp(start, 0, axis_size - 1); + + return start; +} + +// Return the "real" index for the end of iteration along that axis. This is an +// "end" in the traditional C sense, in that it points to one past the last +// element. ie. So if you were iterating through all elements of a 1D array of +// size 4, this function would return 4 as the stop, because it is one past the +// "real" indices of 0, 1, 2 & 3. +inline int StopForAxis(const StridedSliceParams ¶ms, const loco::TensorShape &input_shape, + int axis, int start_for_axis) +{ + const auto end_mask = params.end_mask; + const auto shrink_axis_mask = params.shrink_axis_mask; + const auto *stop_indices = params.stop_indices; + const auto *strides = params.strides; + const int axis_size = static_cast<int32_t>(input_shape.dim(axis).value()); + if (axis_size == 0) + { + return 0; + } + + // Begin with the specified index + const bool shrink_axis = shrink_axis_mask & (1 << axis); + int32_t stop = stop_indices[axis]; + + // When shrinking an axis, the end position does not matter (and can be + // incorrect when negative indexing is used, see Issue #19260). Always use + // start_for_axis + 1 to generate a length 1 slice, since start_for_axis has + // already been adjusted for negative indices. + if (shrink_axis) + { + stop = start_for_axis + 1; + } + + // end_mask override + if (end_mask & (1 << axis)) + { + if (strides[axis] > 0) + { + // Forward iteration - use the last element. These values will get + // clamped below + stop = std::numeric_limits<int32_t>::max(); + } + else + { + // Backward iteration - use the first element. + stop = std::numeric_limits<int32_t>::lowest(); + } + } + + // Handle negative indices + if (stop < 0) + { + stop += axis_size; + } + + // Clamping + // Because the end index points one past the last element, we need slightly + // different clamping ranges depending on the direction. + if (strides[axis] > 0) + { + // Forward iteration + stop = Clamp(stop, 0, axis_size); + } + else + { + // Backward iteration + stop = Clamp(stop, -1, axis_size - 1); + } + + return stop; +} + +StridedSliceParams BuildStridedSliceParams(const luci::CircleStridedSlice *node) +{ + StridedSliceParams op_params; + + if (kMaxDim < node->rank()) + { + INTERNAL_EXN_V("Cannot support StridedSlice rank > ", kMaxDim); + } + + auto begin_node = loco::must_cast<luci::CircleConst *>(node->begin()); + auto end_node = loco::must_cast<luci::CircleConst *>(node->end()); + auto strides_node = loco::must_cast<luci::CircleConst *>(node->strides()); + + uint32_t dims_count = begin_node->size<S32>(); + + op_params.start_indices_count = dims_count; + op_params.stop_indices_count = dims_count; + op_params.strides_count = dims_count; + + for (uint32_t i = 0; i < dims_count; ++i) + { + op_params.start_indices[i] = begin_node->at<S32>(i); + op_params.stop_indices[i] = end_node->at<S32>(i); + op_params.strides[i] = strides_node->at<S32>(i); + } + + op_params.begin_mask = node->begin_mask(); + op_params.ellipsis_mask = 0; + op_params.end_mask = node->end_mask(); + op_params.new_axis_mask = 0; + op_params.shrink_axis_mask = node->shrink_axis_mask(); + + return op_params; +} + +} // namespace + +namespace luci +{ + +loco::TensorShape infer_output_shape(const CircleStridedSlice *node) +{ + loco::TensorShape output_shape; + + auto input_node = loco::must_cast<luci::CircleNode *>(node->input()); + + auto begin_node = dynamic_cast<luci::CircleConst *>(node->begin()); + auto end_node = dynamic_cast<luci::CircleConst *>(node->end()); + auto strides_node = dynamic_cast<luci::CircleConst *>(node->strides()); + if (begin_node == nullptr || end_node == nullptr || strides_node == nullptr) + { + INTERNAL_EXN("StridedSlice begin/end/strides nodes are not Constant"); + } + + LUCI_ASSERT(begin_node->dtype() == S32, "Only support S32 for begin_node"); + LUCI_ASSERT(end_node->dtype() == S32, "Only support S32 for end_node"); + LUCI_ASSERT(strides_node->dtype() == S32, "Only support S32 for strides_node"); + + assert(node->ellipsis_mask() == 0); + assert(node->new_axis_mask() == 0); + + auto op_params = BuildStridedSliceParams(node); + loco::TensorShape input_shape = loco::shape_get(input_node).as<loco::TensorShape>(); + + uint32_t num_input_axes = input_shape.rank(); + assert(begin_node->size<S32>() <= num_input_axes); + assert(end_node->size<S32>() <= num_input_axes); + assert(strides_node->size<S32>() <= num_input_axes); + for (uint32_t i = 0; i < strides_node->size<S32>(); i++) + { + LUCI_ASSERT(strides_node->at<S32>(i) != 0, "Stride value has to be non-zero"); + } + + uint32_t shape_size = 0; + std::array<int32_t, 16> output_shape_data; + + for (uint32_t idx = 0; idx < num_input_axes; ++idx) + { + int32_t begin = StartForAxis(op_params, input_shape, idx); + int32_t end = StopForAxis(op_params, input_shape, idx, begin); + if (end < 0) + end = input_shape.dim(idx).value() + end + 1; + + // This is valid for both positive and negative strides + int32_t stride = strides_node->at<S32>(idx); + int32_t dim_shape = std::ceil(static_cast<float>(end - begin) / stride); + assert(dim_shape > 0); + + // When shrinking an axis, the end position does not matter (and can be + // incorrect when negative indexing is used, see Issue #19260). Always use + // begin + 1 to generate a length 1 slice, since begin has + // already been adjusted for negative indices by StartForAxis. + const bool shrink_axis = node->shrink_axis_mask() & (1 << idx); + if (shrink_axis) + { + assert(dim_shape == 1); + } + else + { + output_shape_data[shape_size++] = dim_shape; + } + } + + output_shape.rank(shape_size); + for (uint32_t idx = 0; idx < shape_size; ++idx) + { + output_shape.dim(idx) = output_shape_data[idx]; + } + + return output_shape; +} + +} // namespace luci diff --git a/compiler/luci/service/src/ShapeInfer_StridedSlice.h b/compiler/luci/service/src/ShapeInfer_StridedSlice.h new file mode 100644 index 000000000..fa800b720 --- /dev/null +++ b/compiler/luci/service/src/ShapeInfer_StridedSlice.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __SHAPE_INFER_STRIDED_SLICE_H__ +#define __SHAPE_INFER_STRIDED_SLICE_H__ + +#include <luci/IR/CircleNodes.h> + +#include <loco/IR/NodeShape.h> + +namespace luci +{ + +loco::TensorShape infer_output_shape(const CircleStridedSlice *node); + +} // namespace luci + +#endif // __SHAPE_INFER_STRIDED_SLICE_H__ diff --git a/compiler/luci/service/src/TestGraph.h b/compiler/luci/service/src/TestGraph.h index 73562040f..2865b0f44 100644 --- a/compiler/luci/service/src/TestGraph.h +++ b/compiler/luci/service/src/TestGraph.h @@ -18,7 +18,6 @@ #define __TEST_GRAPH_H__ #include <luci/IR/CircleNodes.h> -#include "GraphBlock.h" #include <loco.h> @@ -36,29 +35,29 @@ class TestGraph { public: std::unique_ptr<loco::Graph> g; - loco::Pull *pull; - loco::Push *push; + luci::CircleInput *input_node = nullptr; + luci::CircleOutput *output_node = nullptr; TestGraph() // creates Pull and Push { g = loco::make_graph(); - pull = g->nodes()->create<loco::Pull>(); + input_node = g->nodes()->create<luci::CircleInput>(); - push = g->nodes()->create<loco::Push>(); + output_node = g->nodes()->create<luci::CircleOutput>(); auto input = g->inputs()->create(); { input->name("input"); - loco::link(input, pull); + luci::link(input, input_node); } auto output = g->outputs()->create(); { output->name("output"); - loco::link(output, push); + luci::link(output, output_node); } - _next_input = pull; + _next_input = input_node; } loco::Graph *graph() { return g.get(); } @@ -73,7 +72,7 @@ public: } /// @brief Creates op T (arity=1) with arg1 as an input and appends it to graph - template <class T> T *append(loco::Node *arg1) + template <class T> T *append(luci::CircleNode *arg1) { auto node = g->nodes()->create<T>(); setInput(node, arg1); @@ -83,7 +82,7 @@ public: } /// @brief Creates op T (arity=2) with arg1, arg2 as inputs and appends it to graph - template <class T> T *append(loco::Node *arg1, loco::Node *arg2) + template <class T> T *append(luci::CircleNode *arg1, luci::CircleNode *arg2) { auto node = g->nodes()->create<T>(); setInput(node, arg1, arg2); @@ -93,7 +92,8 @@ public: } /// @brief Creates op T (arity=3) with arg1, arg2, arg3 as inputs and appends it to graph - template <class T> T *append(loco::Node *arg1, loco::Node *arg2, loco::Node *arg3) + template <class T> + T *append(luci::CircleNode *arg1, luci::CircleNode *arg2, luci::CircleNode *arg3) { auto node = g->nodes()->create<T>(); setInput(node, arg1, arg2, arg3); @@ -102,101 +102,68 @@ public: return node; } - // push will get the last appended node - void complete() { push->from(_next_input); } + // output will get the last appended node + void complete() { output_node->from(_next_input); } - void complete(loco::Node *last_node) { push->from(last_node); } + void complete(luci::CircleNode *last_node) { output_node->from(last_node); } private: // arity 1 - void setInput(loco::Node *node, loco::Node *) { assert(false && "NYI"); }; - - void setInput(loco::AvgPool2D *node, loco::Node *input) { node->ifm(input); } - void setInput(loco::BiasDecode *node, loco::Node *input) { node->input(input); }; - void setInput(loco::BiasEncode *node, loco::Node *input) { node->input(input); }; - void setInput(loco::FeatureDecode *node, loco::Node *input) { node->input(input); }; - void setInput(loco::FeatureEncode *node, loco::Node *input) { node->input(input); }; - void setInput(loco::MaxPool2D *node, loco::Node *input) { node->ifm(input); } - void setInput(loco::Push *node, loco::Node *input) { node->from(input); }; - void setInput(loco::ReLU *node, loco::Node *input) { node->input(input); }; - void setInput(loco::ReLU6 *node, loco::Node *input) { node->input(input); }; - void setInput(loco::Tanh *node, loco::Node *input) { node->input(input); }; - void setInput(loco::TensorTranspose *node, loco::Node *input) { node->input(input); }; - - void setInput(luci::CircleAveragePool2D *node, loco::Node *input) { node->value(input); }; - void setInput(luci::CircleMaxPool2D *node, loco::Node *input) { node->value(input); }; - void setInput(luci::CircleRelu *node, loco::Node *input) { node->features(input); }; - void setInput(luci::CircleRelu6 *node, loco::Node *input) { node->features(input); }; + void setInput(luci::CircleNode *, luci::CircleNode *) { assert(false && "NYI"); }; - // arity 2 - void setInput(loco::Node *node, loco::Node *, loco::Node *) { assert(false && "NYI"); }; + void setInput(luci::CircleAveragePool2D *node, luci::CircleNode *input) { node->value(input); }; + void setInput(luci::CircleRelu *node, luci::CircleNode *input) { node->features(input); }; + void setInput(luci::CircleSqueeze *node, luci::CircleNode *input) { node->input(input); }; - void setInput(loco::Conv2D *node, loco::Node *input, loco::Node *filter) + void setInput(luci::CircleGatherNd *node, luci::CircleNode *params, luci::CircleNode *indices) { - node->ifm(input); - node->ker(filter); - } - - void setInput(loco::EltwiseAdd *node, loco::Node *arg1, loco::Node *arg2) - { - node->lhs(arg1); - node->rhs(arg2); + node->params(params); + node->indices(indices); }; - void setInput(loco::FeatureBiasAdd *node, loco::Node *arg1, loco::Node *arg2) + // arity 2 + void setInput(luci::CircleNode *, luci::CircleNode *, luci::CircleNode *) { - node->value(arg1); - node->bias(arg2); + assert(false && "NYI"); }; - void setInput(luci::CircleAdd *node, loco::Node *arg1, loco::Node *arg2) + void setInput(luci::CircleExpandDims *node, luci::CircleNode *arg1, luci::CircleNode *arg2) { - node->x(arg1); - node->y(arg2); + node->input(arg1); + node->axis(arg2); }; - void setInput(luci::CircleMul *node, loco::Node *arg1, loco::Node *arg2) + void setInput(luci::CircleTranspose *node, luci::CircleNode *arg1, luci::CircleNode *arg2) { - node->x(arg1); - node->y(arg2); + node->a(arg1); + node->perm(arg2); }; - void setInput(luci::CircleSub *node, loco::Node *arg1, loco::Node *arg2) + void setInput(luci::CircleResizeBilinear *node, luci::CircleNode *input, luci::CircleNode *size) { - node->x(arg1); - node->y(arg2); + node->input(input); + node->size(size); }; - void setInput(luci::CircleTranspose *node, loco::Node *arg1, loco::Node *arg2) + void setInput(luci::CircleResizeNearestNeighbor *node, luci::CircleNode *input, + luci::CircleNode *size) { - node->a(arg1); - node->perm(arg2); + node->input(input); + node->size(size); }; // arity 3 - void setInput(loco::Node *node, loco::Node *, loco::Node *, loco::Node *) + void setInput(luci::CircleNode *, luci::CircleNode *, luci::CircleNode *, luci::CircleNode *) { assert(false && "NYI"); }; - void setInput(luci::CircleConv2D *node, loco::Node *input, loco::Node *filter, loco::Node *bias) - { - node->input(input); - node->filter(filter); - node->bias(bias); - } - private: loco::Node *_next_input; }; enum class ExampleGraphType { - FeatureBiasAdd, - ConstGen_ReLU, - FilterEncode_FilterDecode, - Transpose, - CircleTranspose, }; @@ -205,109 +172,42 @@ template <ExampleGraphType T> class ExampleGraph; /** * @brief Class to create the following: * - * Pull - FeatureEncoder - FeatureBiasAdd - FeatureDecode - Push - * | - * ConstGen - BiasEncode --+ + * CircleInput -- CircleTranspose -- CircleOutput */ -template <> class ExampleGraph<ExampleGraphType::FeatureBiasAdd> : public TestGraph +template <> class ExampleGraph<ExampleGraphType::CircleTranspose> : public TestGraph { public: - loco::FeatureEncode *fea_enc = nullptr; - loco::ConstGen *constgen = nullptr; - loco::BiasEncode *bias_enc = nullptr; - loco::FeatureBiasAdd *fea_bias_add = nullptr; - loco::FeatureDecode *fea_dec = nullptr; + luci::CircleConst *const_perm = nullptr; + luci::CircleTranspose *transpose_node = nullptr; public: ExampleGraph() { - fea_enc = luci::make_feature_encode<luci::FeatureLayout::NHWC>(pull); - constgen = append<loco::ConstGen>(); - bias_enc = append<loco::BiasEncode>(constgen); - fea_bias_add = append<loco::FeatureBiasAdd>(fea_enc, bias_enc); - fea_dec = luci::make_feature_decode<luci::FeatureLayout::NHWC>(fea_bias_add); - complete(fea_dec); + const_perm = append<luci::CircleConst>(); + transpose_node = append<luci::CircleTranspose>(input_node, const_perm); + complete(transpose_node); } }; -/** - * @brief Class to creates the following: - * - * ConstGen -- ReLU -- Push - */ -template <> class ExampleGraph<ExampleGraphType::ConstGen_ReLU> : public TestGraph -{ -public: - loco::ConstGen *constgen = nullptr; - loco::ReLU *relu = nullptr; - -public: - ExampleGraph() - { - constgen = append<loco::ConstGen>(); - relu = append<loco::ReLU>(constgen); - complete(relu); - } -}; +} // namespace test +} // namespace luci -/** - * @brief Class to creates the following: - * - * Pull -- Transpose -- Push - */ -template <> class ExampleGraph<ExampleGraphType::Transpose> : public TestGraph +namespace luci { -public: - loco::TensorTranspose *transpose = nullptr; - -public: - ExampleGraph() - { - transpose = append<loco::TensorTranspose>(pull); - complete(transpose); - } -}; - -/** - * @brief Class to creates the following: - * - * Pull -- FilterEncode -- FilterDecode -- Push - */ -template <> class ExampleGraph<ExampleGraphType::FilterEncode_FilterDecode> : public TestGraph +namespace test { -public: - loco::FilterEncode *filterEncode = nullptr; - loco::FilterDecode *filterDecode = nullptr; -public: - ExampleGraph() - { - filterEncode = luci::make_filter_encode<luci::FilterLayout::HWIO>(pull); // from Tensorflow - filterDecode = - luci::make_filter_decode<luci::FilterLayout::OHWI>(filterEncode); // to Tensorflow Lite - complete(filterDecode); - } -}; +/// @brief This will set GraphInput shape from CircleInput shape +void graph_input_shape(luci::CircleInput *input); -/** - * @brief Class to create the following: - * - * Pull -- CircleTranspose -- Push - */ -template <> class ExampleGraph<ExampleGraphType::CircleTranspose> : public TestGraph -{ -public: - loco::ConstGen *const_perm = nullptr; - luci::CircleTranspose *transpose_node = nullptr; +/// @brief This will set GraphOutput shape from CircleOutput shape +void graph_output_shape(luci::CircleOutput *output); -public: - ExampleGraph() - { - const_perm = append<loco::ConstGen>(); - transpose_node = append<luci::CircleTranspose>(pull, const_perm); - complete(transpose_node); - } -}; +/// @brief This will set GraphInput dtype from CircleInput dtype +void graph_input_dtype(luci::CircleInput *input); + +/// @brief This will set GraphOutput dtype from CircleOutput dtype +void graph_output_dtype(luci::CircleOutput *output); } // namespace test } // namespace luci diff --git a/compiler/luci/service/src/TestGraph.test.cpp b/compiler/luci/service/src/TestGraph.test.cpp new file mode 100644 index 000000000..9ede70370 --- /dev/null +++ b/compiler/luci/service/src/TestGraph.test.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "TestGraph.h" + +namespace luci +{ +namespace test +{ + +void graph_input_shape(luci::CircleInput *input) +{ + auto index = input->index(); + auto inputs = input->graph()->inputs(); + + for (uint32_t idx = 0; idx < inputs->size(); ++idx) + { + auto gi = inputs->at(idx); + if (gi->index() == index) + { + auto input_shape = std::make_unique<loco::TensorShape>(); + + input_shape->rank(input->rank()); + for (uint32_t r = 0; r < input->rank(); ++r) + input_shape->dim(r) = loco::Dimension(input->dim(r)); + + gi->shape(std::move(input_shape)); + break; + } + } +} + +void graph_output_shape(luci::CircleOutput *output) +{ + auto index = output->index(); + auto outputs = output->graph()->outputs(); + + for (uint32_t idx = 0; idx < outputs->size(); ++idx) + { + auto go = outputs->at(idx); + if (go->index() == index) + { + auto output_shape = std::make_unique<loco::TensorShape>(); + + output_shape->rank(output->rank()); + for (uint32_t r = 0; r < output->rank(); ++r) + output_shape->dim(r) = loco::Dimension(output->dim(r)); + + go->shape(std::move(output_shape)); + break; + } + } +} + +void graph_input_dtype(luci::CircleInput *input) +{ + auto index = input->index(); + auto inputs = input->graph()->inputs(); + + for (uint32_t idx = 0; idx < inputs->size(); ++idx) + { + auto gi = inputs->at(idx); + if (gi->index() == index) + { + gi->dtype(input->dtype()); + break; + } + } +} + +void graph_output_dtype(luci::CircleOutput *output) +{ + auto index = output->index(); + auto outputs = output->graph()->outputs(); + + for (uint32_t idx = 0; idx < outputs->size(); ++idx) + { + auto go = outputs->at(idx); + if (go->index() == index) + { + go->dtype(output->dtype()); + break; + } + } +} + +} // namespace test +} // namespace luci diff --git a/compiler/luci/service/src/Validate.cpp b/compiler/luci/service/src/Validate.cpp index 65b82c2b4..282a068e0 100644 --- a/compiler/luci/service/src/Validate.cpp +++ b/compiler/luci/service/src/Validate.cpp @@ -29,6 +29,19 @@ namespace { +std::ostream &operator<<(std::ostream &os, const loco::TensorShape &tensor_shape) +{ + os << "["; + for (uint32_t r = 0; r < tensor_shape.rank(); ++r) + { + if (r) + os << ","; + os << tensor_shape.dim(r).value(); + } + os << "]"; + return os; +} + /** * @brief returns a node that is CircleOutput with index is out_index in nodes */ @@ -46,7 +59,7 @@ luci::CircleOutput *find_node(std::vector<loco::Node *> nodes, loco::GraphOutput return nullptr; } -bool validate_shape_type(loco::Graph *g) +bool validate_shape_dtype(loco::Graph *g) { LOGGER(l); @@ -61,18 +74,18 @@ bool validate_shape_type(loco::Graph *g) auto circle_output = find_node(output_nodes, out_index); assert(circle_output != nullptr); assert(circle_output->from() != nullptr); - auto circle_node = dynamic_cast<luci::CircleNode *>(circle_output->from()); - assert(circle_node != nullptr); + auto circle_node = loco::must_cast<luci::CircleNode *>(circle_output->from()); assert(loco::shape_known(circle_node)); // check if output node shape is same as graph output shape - auto co_shape = loco::shape_get(circle_node); + auto co_tensor_shape = loco::shape_get(circle_node).as<loco::TensorShape>(); auto go_tensor_shape = graph_out->shape(); assert(go_tensor_shape); - auto go_shape = loco::NodeShape(*go_tensor_shape); - if (!(co_shape == go_shape)) + if (!(co_tensor_shape == *go_tensor_shape)) { - INFO(l) << "Shape for #" << out_index << " not same " << std::endl; + INFO(l) << "[luci] Shape for output #" << out_index << " not same " << std::endl; + INFO(l) << "[luci] " << circle_node->name() << " " << co_tensor_shape << " vs " + << *go_tensor_shape << std::endl; return false; } @@ -80,7 +93,7 @@ bool validate_shape_type(loco::Graph *g) assert(loco::dtype_known(circle_node)); if (graph_out->dtype() != loco::dtype_get(circle_node)) { - INFO(l) << "Type for #" << out_index << " not same " << std::endl; + INFO(l) << "[luci] Type for output #" << out_index << " not same " << std::endl; return false; } } @@ -98,7 +111,7 @@ bool validate(loco::Graph *g) if (!loco::valid(g)) return false; - if (!validate_shape_type(g)) + if (!validate_shape_dtype(g)) return false; // TODO add more validation diff --git a/compiler/luci/tester/CMakeLists.txt b/compiler/luci/tester/CMakeLists.txt index bcb47183e..3ac06ef3a 100644 --- a/compiler/luci/tester/CMakeLists.txt +++ b/compiler/luci/tester/CMakeLists.txt @@ -1,17 +1,23 @@ +nnas_include(TargetRequire) + +unset(REQUIRED_TARGETS) +list(APPEND REQUIRED_TARGETS safemain) +TargetRequire_Return(${REQUIRED_TARGETS}) + set(SRCS_READ_TESTER src/ReadTester.cpp - src/Model.cpp ) add_executable(luci_readtester "${SRCS_READ_TESTER}") target_link_libraries(luci_readtester PRIVATE luci_import) target_link_libraries(luci_readtester PRIVATE luci_service) target_link_libraries(luci_readtester PRIVATE luci_pass) +target_link_libraries(luci_readtester PRIVATE foder) target_link_libraries(luci_readtester PRIVATE oops) +target_link_libraries(luci_readtester PRIVATE safemain) set(SRCS_WRITE_TESTER src/WriteTester.cpp - src/Model.cpp ) add_executable(luci_writetester "${SRCS_WRITE_TESTER}") @@ -19,4 +25,6 @@ target_link_libraries(luci_writetester PRIVATE luci_import) target_link_libraries(luci_writetester PRIVATE luci_service) target_link_libraries(luci_writetester PRIVATE luci_pass) target_link_libraries(luci_writetester PRIVATE luci_export) +target_link_libraries(luci_writetester PRIVATE foder) target_link_libraries(luci_writetester PRIVATE oops) +target_link_libraries(luci_writetester PRIVATE safemain) diff --git a/compiler/luci/tester/src/Model.cpp b/compiler/luci/tester/src/Model.cpp deleted file mode 100644 index b02c19161..000000000 --- a/compiler/luci/tester/src/Model.cpp +++ /dev/null @@ -1,62 +0,0 @@ -#include "Model.h" - -#include <fstream> -#include <vector> - -#include <fcntl.h> -#include <unistd.h> -#include <sys/stat.h> - -namespace -{ - -class FileModel final : public luci::Model -{ -public: - explicit FileModel(const std::string &filename) : _filename(filename) {} - -public: - FileModel(const FileModel &) = delete; - FileModel(FileModel &&) = delete; - -public: - const ::circle::Model *model(void) override - { - std::ifstream file(_filename, std::ios::binary | std::ios::in); - if (!file.good()) - return nullptr; - - file.unsetf(std::ios::skipws); - - std::streampos fileSize; - file.seekg(0, std::ios::end); - fileSize = file.tellg(); - file.seekg(0, std::ios::beg); - - // reserve capacity - _data.reserve(fileSize); - - // read the data - file.read(_data.data(), fileSize); - if (file.fail()) - return nullptr; - - return ::circle::GetModel(_data.data()); - } - -private: - const std::string _filename; - std::vector<char> _data; -}; - -} // namespace - -namespace luci -{ - -std::unique_ptr<Model> load_model(const std::string &path) -{ - return std::make_unique<FileModel>(path); -} - -} // namespace luci diff --git a/compiler/luci/tester/src/Model.h b/compiler/luci/tester/src/Model.h deleted file mode 100644 index e40faf33e..000000000 --- a/compiler/luci/tester/src/Model.h +++ /dev/null @@ -1,27 +0,0 @@ -#ifndef __TESTER_MODEL_H__ -#define __TESTER_MODEL_H__ - -#include <mio/circle/schema_generated.h> - -#include <memory> - -namespace luci -{ - -struct Model -{ - virtual ~Model() = default; - - virtual const ::circle::Model *model(void) = 0; -}; - -/** - * @brief Load Circle model (as a raw Model) from a given path - * - * @note May return a nullptr - */ -std::unique_ptr<Model> load_model(const std::string &path); - -} // namespace luci - -#endif // __TESTER_MODEL_H__ diff --git a/compiler/luci/tester/src/ReadTester.cpp b/compiler/luci/tester/src/ReadTester.cpp index c105d6ce3..a1aead1bd 100644 --- a/compiler/luci/tester/src/ReadTester.cpp +++ b/compiler/luci/tester/src/ReadTester.cpp @@ -1,4 +1,20 @@ -#include "Model.h" +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <foder/FileLoader.h> #include <luci/Importer.h> #include <luci/Service/Validate.h> @@ -37,7 +53,7 @@ void show_error_message(const char *progname, std::ostream &os, const std::strin * dump graph to console if set. * i.e. "LUCI_LOG=1 luci_readtester mymodel.circle" */ -int main(int argc, char **argv) +int entry(int argc, char **argv) { if (argc != 2) { @@ -50,22 +66,17 @@ int main(int argc, char **argv) std::cout << "[INFO] Circle is '" << input_path << "'" << std::endl; // Load model from the file - std::unique_ptr<luci::Model> model = luci::load_model(input_path); - if (model == nullptr) + foder::FileLoader file_loader{input_path}; + std::vector<char> model_data = file_loader.load(); + const circle::Model *circle_model = circle::GetModel(model_data.data()); + if (circle_model == nullptr) { - std::cerr << "ERROR: Failed to load '" << input_path << "'" << std::endl; - return 255; - } - - const circle::Model *input_model = model->model(); - if (input_model == nullptr) - { - std::cerr << "ERROR: Failed to read '" << input_path << "'" << std::endl; - return 255; + std::cerr << "ERROR: Failed to load circle '" << input_path << "'" << std::endl; + return EXIT_FAILURE; } luci::Importer importer; - auto module = importer.importModule(input_model); + auto module = importer.importModule(circle_model); assert(module->size() > 0); for (size_t g = 0; g < module->size(); ++g) diff --git a/compiler/luci/tester/src/WriteTester.cpp b/compiler/luci/tester/src/WriteTester.cpp index 80019d1b1..aa7085c77 100644 --- a/compiler/luci/tester/src/WriteTester.cpp +++ b/compiler/luci/tester/src/WriteTester.cpp @@ -1,4 +1,20 @@ -#include "Model.h" +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <foder/FileLoader.h> #include <luci/Importer.h> #include <luci/Pass/ShapeInferencePass.h> @@ -52,8 +68,8 @@ public: bool store(const char *ptr, const size_t size) const final; private: - loco::Graph *_graph; - luci::Module *_module; + loco::Graph *_graph{nullptr}; + luci::Module *_module{nullptr}; const std::string _filepath; }; @@ -79,7 +95,7 @@ bool CircleExpContract::store(const char *ptr, const size_t size) const * With the graph, this will use luci_export to write to the second file * Like ReadTester, LUCI_LOG=1 environment variable is available to dump the graph */ -int main(int argc, char **argv) +int entry(int argc, char **argv) { if (argc != 3) { @@ -93,23 +109,18 @@ int main(int argc, char **argv) std::cout << "[INFO] Circle from '" << input_path << "' to '" << output_path << "'" << std::endl; // Load model from the file - std::unique_ptr<luci::Model> model = luci::load_model(input_path); - if (model == nullptr) + foder::FileLoader file_loader{input_path}; + std::vector<char> model_data = file_loader.load(); + const circle::Model *circle_model = circle::GetModel(model_data.data()); + if (circle_model == nullptr) { - std::cerr << "ERROR: Failed to load '" << input_path << "'" << std::endl; - return 255; - } - - const circle::Model *input_model = model->model(); - if (input_model == nullptr) - { - std::cerr << "ERROR: Failed to read '" << input_path << "'" << std::endl; - return 255; + std::cerr << "ERROR: Failed to load circle '" << input_path << "'" << std::endl; + return EXIT_FAILURE; } // Import from input Circle file luci::Importer importer; - auto module = importer.importModule(input_model); + auto module = importer.importModule(circle_model); assert(module->size() > 0); for (size_t g = 0; g < module->size(); ++g) diff --git a/compiler/luci/tests/CMakeLists.txt b/compiler/luci/tests/CMakeLists.txt index 4e5639047..c03835823 100644 --- a/compiler/luci/tests/CMakeLists.txt +++ b/compiler/luci/tests/CMakeLists.txt @@ -65,6 +65,35 @@ foreach(RECIPE IN ITEMS ${RECIPES}) list(APPEND TESTFILES "${CIRCLE_OUTPUT_FILE}") endforeach(RECIPE) +# Generate from res/CircleRecipes +# NOTE duplicate names should not exist or test may be incorrect +nncc_find_resource(CircleRecipes) +set(CIRCLERECIPES_DIR "${CircleRecipes_DIR}") + +file(GLOB RECIPES2 RELATIVE ${CIRCLERECIPES_DIR} "${CIRCLERECIPES_DIR}/*/test.recipe") + +foreach(RECIPE IN ITEMS ${RECIPES2}) + get_filename_component(RECIPE_PREFIX ${RECIPE} DIRECTORY) + + set(RECIPE_SOURCE_FILE "${RECIPE_PREFIX}.recipe") + set(CIRCLE_OUTPUT_FILE "${RECIPE_PREFIX}.circle") + + # Copy .recipe + add_custom_command(OUTPUT "${RECIPE_SOURCE_FILE}" + COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CIRCLERECIPES_DIR}/${RECIPE}" "${RECIPE_SOURCE_FILE}" + DEPENDS "${CIRCLERECIPES_DIR}/${RECIPE}" + COMMENT "Generating ${RECIPE_SOURCE_FILE}") + + # Generate .circle + add_custom_command(OUTPUT "${CIRCLE_OUTPUT_FILE}" + COMMAND circlechef-file "${RECIPE_SOURCE_FILE}" "${CIRCLE_OUTPUT_FILE}" + DEPENDS circlechef-file "${RECIPE_SOURCE_FILE}" + COMMENT "Generating ${CIRCLE_OUTPUT_FILE}") + + list(APPEND TESTFILES "${CIRCLE_OUTPUT_FILE}") +endforeach(RECIPE) + # Add a dummy target to create a target-level dependency. # TODO Find a way to create dependency between CTest tests (added below) and generated testfiles. add_custom_target(luci_testfiles ALL DEPENDS ${TESTFILES}) diff --git a/compiler/luci/tests/readverify.sh b/compiler/luci/tests/readverify.sh index 3403e9c19..6d6753d39 100755 --- a/compiler/luci/tests/readverify.sh +++ b/compiler/luci/tests/readverify.sh @@ -7,6 +7,9 @@ # ./readverify.sh <path/to/luci_readtester> <TEST 1> <TEST 2> ... VERIFY_SOURCE_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# set LOG enable to execute/test luci/logex codes +export LUCI_LOG=100 + WORKDIR="$1"; shift VERIFY_BINARY_PATH="$1"; shift diff --git a/compiler/luci/tests/test.lst b/compiler/luci/tests/test.lst index 08cbd6b1a..188e29828 100644 --- a/compiler/luci/tests/test.lst +++ b/compiler/luci/tests/test.lst @@ -1,5 +1,8 @@ +addread(Abs_000) addread(Add_000) +addread(Add_001) addread(Add_U8_000) +addread(AddN_000) addread(ArgMax_000) addread(ArgMax_001) addread(ArgMax_002) @@ -8,44 +11,190 @@ addread(ArgMax_U8_000) addread(ArgMax_U8_001) addread(ArgMax_U8_002) addread(ArgMax_U8_003) +addread(ArgMin_000) +addread(ArgMin_001) +addread(ArgMin_002) +addread(ArgMin_003) +addread(ArgMin_U8_000) +addread(ArgMin_U8_001) +addread(ArgMin_U8_002) +addread(ArgMin_U8_003) +addread(AveragePool2D_000) +addread(BatchMatMul_000) +addread(BatchMatMulV2_000) +addread(BatchMatMulV2_001) addread(BatchToSpaceND_000) +addread(Cast_000) +addread(Cast_001) +addread(Ceil_000) addread(Concatenation_000) addread(Concatenation_U8_000) addread(Conv2D_000) -addread(Conv2D_U8_000) addread(Conv2D_002) +addread(Conv2D_003) +addread(Conv2D_U8_000) addread(Cos_000) +addread(DepthToSpace_000) addread(DepthwiseConv2D_000) addread(DepthwiseConv2D_U8_000) +addread(DepthwiseConv2D_001) addread(Div_000) +addread(ELU_000) addread(Equal_000) addread(Exp_000) +addread(ExpandDims_000) +addread(ExpandDims_001) +addread(ExpandDims_002) +addread(ExpandDims_003) +addread(Fill_000) +addread(Fill_001) +addread(Floor_000) +addread(FloorDiv_000) +addread(FloorDiv_001) +addread(FloorMod_000) +addread(FloorMod_001) addread(FullyConnected_000) addread(FullyConnected_001) +addread(FullyConnected_002) addread(FullyConnected_U8_000) +addread(Gather_000) +addread(GatherNd_000) +addread(Greater_000) +addread(GreaterEqual_000) +addread(If_000) +addread(If_001) +addread(L2Normalize_000) +addread(L2Pool2D_000) +addread(L2Pool2D_U8_000) +addread(LeakyRelu_000) +addread(Less_000) +addread(LessEqual_000) +addread(LocalResponseNormalization_000) +addread(Log_000) +addread(LogicalAnd_000) addread(LogicalNot_000) addread(LogicalOr_000) +addread(Logistic_000) +addread(LogSoftmax_000) +addread(MatMul_000) +addread(MatrixDiag_000) +addread(MatrixSetDiag_000) +addread(Maximum_000) addread(MaxPool2D_000) addread(MaxPool2D_U8_000) addread(Mean_000) +addread(Mean_001) +addread(Minimum_000) +addread(MirrorPad_000) addread(Mul_000) addread(Mul_U8_000) +addread(Neg_000) +addread(NotEqual_000) +addread(OneHot_000) +addread(OneHot_001) +addread(OneHot_002) +addread(OneHot_003) addread(Pack_000) addread(Pack_U8_000) addread(Pad_000) +addread(Pow_000) +addread(PRelu_000) +addread(Range_000) +addread(Rank_000) +addread(ReduceAny_000) +addread(ReduceAny_001) +addread(ReduceAny_002) +addread(ReduceAny_003) +addread(ReduceMax_000) +addread(ReduceMin_000) +addread(ReduceProd_000) +addread(ReduceProd_001) +addread(ReduceProd_002) +addread(ReduceProd_003) addread(ReLU_000) +addread(ReLU6_000) +addread(ReLUN1To1_000) addread(Reshape_000) addread(Reshape_001) +addread(Reshape_002) +addread(Reshape_003) addread(Reshape_U8_000) +addread(ResizeBilinear_000) +addread(ResizeNearestNeighbor_000) +addread(ReverseSequence_000) +addread(ReverseV2_000) +addread(Round_000) addread(Rsqrt_000) +addread(ScatterNd_000) +addread(SegmentSum_000) +addread(Select_000) +addread(Select_001) +addread(Select_002) +addread(SelectV2_000) +addread(SelectV2_001) +addread(SelectV2_002) +addread(Shape_000) +addread(Sin_000) +addread(Slice_000) addread(Softmax_000) addread(Softmax_U8_000) +addread(SpaceToBatchND_000) +addread(SpaceToBatchND_001) +addread(SpaceToBatchND_002) +addread(SpaceToBatchND_003) +addread(SpaceToDepth_000) +addread(SparseToDense_000) +addread(Split_000) +addread(SplitV_000) +addread(Sqrt_000) +addread(Square_000) +addread(SquaredDifference_000) +addread(Squeeze_000) +addread(StridedSlice_000) +addread(StridedSlice_001) +addread(StridedSlice_002) addread(Sub_000) addread(Sub_U8_000) +addread(Sum_000) +addread(Sum_001) +addread(Tanh_000) +addread(Tile_000) +addread(Tile_U8_000) +addread(TopKV2_000) +addread(TopKV2_001) addread(Transpose_000) +addread(TransposeConv_000) +addread(Unpack_000) +addread(Unpack_001) +addread(Unpack_002) +addread(Unpack_003) +addread(Where_000) +addread(Where_001) +addread(While_000) +addread(While_001) +addread(While_002) +addread(While_003) +addread(YUV_TO_RGB_U8_000) +addread(ZerosLike_000) + +addread(Net_Dangle_001) +addread(Net_InstanceNorm_001) +addread(Net_InstanceNorm_002) +addread(Net_UnpackAdd_001) +addread(Net_ZeroDim_001) + +# from res/CircleRecipes +addread(BCQFullyConnected_000) +addread(BCQFullyConnected_001) +addread(BCQGather_000) +addread(CircleBatchMatMul_000) +addread(InstanceNorm_000) +addwrite(Abs_000) addwrite(Add_000) +addwrite(Add_001) addwrite(Add_U8_000) +addwrite(AddN_000) addwrite(ArgMax_000) addwrite(ArgMax_001) addwrite(ArgMax_002) @@ -54,38 +203,181 @@ addwrite(ArgMax_U8_000) addwrite(ArgMax_U8_001) addwrite(ArgMax_U8_002) addwrite(ArgMax_U8_003) +addwrite(ArgMin_000) +addwrite(ArgMin_001) +addwrite(ArgMin_002) +addwrite(ArgMin_003) +addwrite(ArgMin_U8_000) +addwrite(ArgMin_U8_001) +addwrite(ArgMin_U8_002) +addwrite(ArgMin_U8_003) +addwrite(AveragePool2D_000) +addwrite(BatchMatMul_000) +addwrite(BatchMatMulV2_000) +addwrite(BatchMatMulV2_001) addwrite(BatchToSpaceND_000) +addwrite(Cast_000) +addwrite(Cast_001) +addwrite(Ceil_000) addwrite(Concatenation_000) addwrite(Concatenation_U8_000) addwrite(Conv2D_000) -addwrite(Conv2D_U8_000) addwrite(Conv2D_002) +addwrite(Conv2D_003) +addwrite(Conv2D_U8_000) addwrite(Cos_000) +addwrite(DepthToSpace_000) addwrite(DepthwiseConv2D_000) addwrite(DepthwiseConv2D_U8_000) +addwrite(DepthwiseConv2D_001) addwrite(Div_000) +addwrite(ELU_000) addwrite(Equal_000) addwrite(Exp_000) +addwrite(ExpandDims_000) +addwrite(ExpandDims_001) +addwrite(ExpandDims_002) +addwrite(ExpandDims_003) +addwrite(Fill_000) +addwrite(Fill_001) +addwrite(Floor_000) +addwrite(FloorDiv_000) +addwrite(FloorDiv_001) +addwrite(FloorMod_000) +addwrite(FloorMod_001) addwrite(FullyConnected_000) addwrite(FullyConnected_001) +addwrite(FullyConnected_002) addwrite(FullyConnected_U8_000) +addwrite(Gather_000) +addwrite(GatherNd_000) +addwrite(Greater_000) +addwrite(GreaterEqual_000) +addwrite(If_000) +addwrite(If_001) +addwrite(L2Normalize_000) +addwrite(L2Pool2D_000) +addwrite(L2Pool2D_U8_000) +addwrite(LeakyRelu_000) +addwrite(Less_000) +addwrite(LessEqual_000) +addwrite(LocalResponseNormalization_000) +addwrite(Log_000) +addwrite(LogicalAnd_000) addwrite(LogicalNot_000) addwrite(LogicalOr_000) +addwrite(Logistic_000) +addwrite(LogSoftmax_000) +addwrite(MatMul_000) +addwrite(MatrixDiag_000) +addwrite(MatrixSetDiag_000) +addwrite(Maximum_000) addwrite(MaxPool2D_000) addwrite(MaxPool2D_U8_000) addwrite(Mean_000) +addwrite(Mean_001) +addwrite(Minimum_000) +addwrite(MirrorPad_000) addwrite(Mul_000) addwrite(Mul_U8_000) +addwrite(Neg_000) +addwrite(NotEqual_000) +addwrite(OneHot_000) +addwrite(OneHot_001) +addwrite(OneHot_002) +addwrite(OneHot_003) addwrite(Pack_000) addwrite(Pack_U8_000) addwrite(Pad_000) +addwrite(Pow_000) +addwrite(PRelu_000) +addwrite(Range_000) +addwrite(Rank_000) +addwrite(ReduceAny_000) +addwrite(ReduceAny_001) +addwrite(ReduceAny_002) +addwrite(ReduceAny_003) +addwrite(ReduceMax_000) +addwrite(ReduceMin_000) +addwrite(ReduceProd_000) +addwrite(ReduceProd_001) +addwrite(ReduceProd_002) +addwrite(ReduceProd_003) addwrite(ReLU_000) +addwrite(ReLU6_000) +addwrite(ReLUN1To1_000) addwrite(Reshape_000) addwrite(Reshape_001) +addwrite(Reshape_002) +addwrite(Reshape_003) addwrite(Reshape_U8_000) +addwrite(ResizeBilinear_000) +addwrite(ResizeNearestNeighbor_000) +addwrite(ReverseSequence_000) +addwrite(ReverseV2_000) +addwrite(Round_000) addwrite(Rsqrt_000) +addwrite(ScatterNd_000) +addwrite(SegmentSum_000) +addwrite(Select_000) +addwrite(Select_001) +addwrite(Select_002) +addwrite(SelectV2_000) +addwrite(SelectV2_001) +addwrite(SelectV2_002) +addwrite(Shape_000) +addwrite(Sin_000) +addwrite(Slice_000) addwrite(Softmax_000) addwrite(Softmax_U8_000) +addwrite(SpaceToBatchND_000) +addwrite(SpaceToBatchND_001) +addwrite(SpaceToBatchND_002) +addwrite(SpaceToBatchND_003) +addwrite(SpaceToDepth_000) +addwrite(SparseToDense_000) +addwrite(Split_000) +addwrite(SplitV_000) +addwrite(Sqrt_000) +addwrite(Square_000) +addwrite(SquaredDifference_000) +addwrite(Squeeze_000) +addwrite(StridedSlice_000) +addwrite(StridedSlice_001) +addwrite(StridedSlice_002) addwrite(Sub_000) addwrite(Sub_U8_000) +addwrite(Sum_000) +addwrite(Sum_001) +addwrite(Tanh_000) +addwrite(Tile_000) +addwrite(Tile_U8_000) +addwrite(TopKV2_000) +addwrite(TopKV2_001) addwrite(Transpose_000) +addwrite(TransposeConv_000) +addwrite(Unpack_000) +addwrite(Unpack_001) +addwrite(Unpack_002) +addwrite(Unpack_003) +addwrite(Where_000) +addwrite(Where_001) +addwrite(While_000) +addwrite(While_001) +addwrite(While_002) +addwrite(While_003) +addwrite(YUV_TO_RGB_U8_000) +addwrite(ZerosLike_000) + +addwrite(Net_Dangle_001) +addwrite(Net_InstanceNorm_001) +addwrite(Net_InstanceNorm_002) +addwrite(Net_UnpackAdd_001) +addwrite(Net_ZeroDim_001) + +# from res/CircleRecipes +addwrite(BCQFullyConnected_000) +addwrite(BCQFullyConnected_001) +addwrite(BCQGather_000) +addwrite(CircleBatchMatMul_000) +addwrite(InstanceNorm_000) |