summaryrefslogtreecommitdiff
path: root/compiler/luci/partition
diff options
context:
space:
mode:
authorChunseok Lee <chunseok.lee@samsung.com>2021-04-20 18:01:41 +0900
committerChunseok Lee <chunseok.lee@samsung.com>2021-04-20 18:01:41 +0900
commit589bb1db6db6784efe21b3fbbfbfdb79aaa5f14e (patch)
tree47a2b23ce4220e3a4150c8b12ed941555272fb0c /compiler/luci/partition
parent62529acabbafce7730601ed01d5709d7bc0d378a (diff)
downloadnnfw-589bb1db6db6784efe21b3fbbfbfdb79aaa5f14e.tar.gz
nnfw-589bb1db6db6784efe21b3fbbfbfdb79aaa5f14e.tar.bz2
nnfw-589bb1db6db6784efe21b3fbbfbfdb79aaa5f14e.zip
Diffstat (limited to 'compiler/luci/partition')
-rw-r--r--compiler/luci/partition/CMakeLists.txt29
-rw-r--r--compiler/luci/partition/README.md4
-rw-r--r--compiler/luci/partition/include/luci/Partition.h71
-rw-r--r--compiler/luci/partition/src/CircleOpCode.cpp79
-rw-r--r--compiler/luci/partition/src/CircleOpCode.h31
-rw-r--r--compiler/luci/partition/src/CircleOpCode.test.cpp31
-rw-r--r--compiler/luci/partition/src/ConnectNode.cpp38
-rw-r--r--compiler/luci/partition/src/ConnectNode.h209
-rw-r--r--compiler/luci/partition/src/ConnectNode.test.cpp19
-rw-r--r--compiler/luci/partition/src/ConnectNode.test.h146
-rw-r--r--compiler/luci/partition/src/Nodes/CircleAdd.cpp40
-rw-r--r--compiler/luci/partition/src/Nodes/CircleAdd.test.cpp100
-rw-r--r--compiler/luci/partition/src/Nodes/CircleConst.cpp27
-rw-r--r--compiler/luci/partition/src/Nodes/CircleDiv.cpp40
-rw-r--r--compiler/luci/partition/src/Nodes/CircleDiv.test.cpp100
-rw-r--r--compiler/luci/partition/src/Nodes/CircleMean.cpp41
-rw-r--r--compiler/luci/partition/src/Nodes/CircleMul.cpp40
-rw-r--r--compiler/luci/partition/src/Nodes/CircleMul.test.cpp100
-rw-r--r--compiler/luci/partition/src/Nodes/CirclePow.cpp40
-rw-r--r--compiler/luci/partition/src/Nodes/CircleRsqrt.cpp38
-rw-r--r--compiler/luci/partition/src/Nodes/CircleSqrt.cpp38
-rw-r--r--compiler/luci/partition/src/Nodes/CircleSquaredDifference.cpp40
-rw-r--r--compiler/luci/partition/src/Nodes/CircleSub.cpp40
-rw-r--r--compiler/luci/partition/src/Nodes/CircleSub.test.cpp100
-rw-r--r--compiler/luci/partition/src/Partition.cpp61
-rw-r--r--compiler/luci/partition/src/Partition.test.cpp83
-rw-r--r--compiler/luci/partition/src/PartitionCleanup.cpp139
-rw-r--r--compiler/luci/partition/src/PartitionCleanup.h34
-rw-r--r--compiler/luci/partition/src/PartitionIR.cpp101
-rw-r--r--compiler/luci/partition/src/PartitionIR.h91
-rw-r--r--compiler/luci/partition/src/PartitionIR.test.cpp75
-rw-r--r--compiler/luci/partition/src/PartitionIRDump.cpp70
-rw-r--r--compiler/luci/partition/src/PartitionIRDump.h35
-rw-r--r--compiler/luci/partition/src/PartitionMerge.cpp207
-rw-r--r--compiler/luci/partition/src/PartitionMerge.h31
-rw-r--r--compiler/luci/partition/src/PartitionPGroups.cpp139
-rw-r--r--compiler/luci/partition/src/PartitionPGroups.h39
-rw-r--r--compiler/luci/partition/src/PartitionPGroups.test.cpp80
-rw-r--r--compiler/luci/partition/src/PartitionPModules.cpp203
-rw-r--r--compiler/luci/partition/src/PartitionPModules.h31
-rw-r--r--compiler/luci/partition/src/PartitionPModules.test.cpp82
-rw-r--r--compiler/luci/partition/src/PartitionPModulesDump.cpp47
-rw-r--r--compiler/luci/partition/src/PartitionPModulesDump.h34
43 files changed, 3023 insertions, 0 deletions
diff --git a/compiler/luci/partition/CMakeLists.txt b/compiler/luci/partition/CMakeLists.txt
new file mode 100644
index 000000000..838642b6e
--- /dev/null
+++ b/compiler/luci/partition/CMakeLists.txt
@@ -0,0 +1,29 @@
+file(GLOB_RECURSE SOURCES "src/*.cpp")
+file(GLOB_RECURSE TESTS "src/*.test.cpp")
+list(REMOVE_ITEM SOURCES ${TESTS})
+
+add_library(luci_partition SHARED ${SOURCES})
+target_include_directories(luci_partition PRIVATE src)
+target_include_directories(luci_partition PUBLIC include)
+target_link_libraries(luci_partition PUBLIC luci_lang)
+target_link_libraries(luci_partition PRIVATE luci_service)
+target_link_libraries(luci_partition PRIVATE luci_log)
+target_link_libraries(luci_partition PRIVATE luci_logex)
+target_link_libraries(luci_partition PRIVATE mio_circle)
+target_link_libraries(luci_partition PRIVATE nncc_common)
+target_link_libraries(luci_partition PRIVATE oops)
+
+install(TARGETS luci_partition DESTINATION lib)
+
+if(NOT ENABLE_TEST)
+ return()
+endif(NOT ENABLE_TEST)
+
+nnas_find_package(GTest REQUIRED)
+
+GTest_AddTest(luci_partition_test ${TESTS})
+target_include_directories(luci_partition_test PRIVATE src)
+target_link_libraries(luci_partition_test luci_lang)
+target_link_libraries(luci_partition_test luci_partition)
+target_link_libraries(luci_partition_test luci_testhelper)
+target_link_libraries(luci_partition_test luci_service)
diff --git a/compiler/luci/partition/README.md b/compiler/luci/partition/README.md
new file mode 100644
index 000000000..40a46bc56
--- /dev/null
+++ b/compiler/luci/partition/README.md
@@ -0,0 +1,4 @@
+# luci-partition
+
+`luci-partition` provides partition of a model to two or more sub models and
+its connection configuration having same computational results.
diff --git a/compiler/luci/partition/include/luci/Partition.h b/compiler/luci/partition/include/luci/Partition.h
new file mode 100644
index 000000000..cf90e448b
--- /dev/null
+++ b/compiler/luci/partition/include/luci/Partition.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_PARTITION_H__
+#define __LUCI_PARTITION_H__
+
+#include <luci/IR/Module.h>
+
+#include <memory>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+namespace luci
+{
+
+/**
+ * @brief PartitionTable holds partition information
+ */
+struct PartitionTable
+{
+ std::vector<std::string> groups;
+ std::string default_group;
+
+ // assign by opcode name: OPCODENAME=group
+ std::unordered_map<std::string /* OPCODENAME */, std::string /* group */> byopcodes;
+
+ // TODO add assign by OP name
+};
+
+/**
+ * @brief PartedModule holds partitioned module and group name
+ */
+struct PartedModule
+{
+ std::unique_ptr<Module> module;
+ // group name used to partition this module
+ std::string group;
+
+ // unique name(filename) of this module
+ std::string name;
+};
+
+struct PartedModules
+{
+ std::vector<PartedModule> pmodules;
+
+ // TODO add connections ?
+};
+
+/**
+ * @brief Method to do paritioning from module and PartitionTable to produce PartedModules
+ */
+PartedModules apply(Module *module, const PartitionTable &partition);
+
+} // namespace luci
+
+#endif // __LUCI_PARTITION_H__
diff --git a/compiler/luci/partition/src/CircleOpCode.cpp b/compiler/luci/partition/src/CircleOpCode.cpp
new file mode 100644
index 000000000..86694fa40
--- /dev/null
+++ b/compiler/luci/partition/src/CircleOpCode.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "CircleOpCode.h"
+
+#include <luci/IR/CircleNodes.h>
+#include <luci/IR/CircleNodeVisitor.h>
+
+#include <mio/circle/schema_generated.h>
+
+namespace
+{
+
+using namespace luci;
+using namespace circle;
+
+class QueryOpCode final : public CircleNodeVisitor<BuiltinOperator>
+{
+public:
+// NOTE only circle operator may have BuiltinOperator_XXX
+#define CIRCLE_NODE(OPCODE, CIRCLE_CLASS) \
+ BuiltinOperator visit(const CIRCLE_CLASS *) final { return BuiltinOperator_##OPCODE; }
+#define CIRCLE_VNODE(OPCODE, CIRCLE_CLASS)
+
+#include "luci/IR/CircleNodes.lst"
+#undef CIRCLE_VNODE
+#undef CIRCLE_NODE
+
+ // NOTE only builtin operators should be called (NOT virtual nodes)
+};
+
+class QueryCircleName final : public luci::CircleNodeVisitor<const char *>
+{
+public:
+// NOTE provide names for circle virtual nodes
+#define CIRCLE_NODE(OPCODE, CIRCLE_CLASS)
+#define CIRCLE_VNODE(OPCODE, CIRCLE_CLASS) \
+ const char *visit(const CIRCLE_CLASS *) final { return #OPCODE; }
+
+#include "luci/IR/CircleNodes.lst"
+#undef CIRCLE_VNODE
+#undef CIRCLE_NODE
+
+ // default is null
+ const char *visit(const luci::CircleNode *) final { return nullptr; }
+};
+
+} // namespace
+
+namespace luci
+{
+
+std::string opcode_name(const CircleNode *node)
+{
+ QueryCircleName qcn;
+ auto cname = node->accept(&qcn);
+ if (cname != nullptr)
+ return std::string(cname);
+
+ QueryOpCode qoc;
+ auto opcode = node->accept(&qoc);
+ auto name = circle::EnumNameBuiltinOperator(opcode);
+ return std::string(name);
+}
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/CircleOpCode.h b/compiler/luci/partition/src/CircleOpCode.h
new file mode 100644
index 000000000..d17b09261
--- /dev/null
+++ b/compiler/luci/partition/src/CircleOpCode.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_PARTITION_CIRCLE_OP_CODE_H__
+#define __LUCI_PARTITION_CIRCLE_OP_CODE_H__
+
+#include <luci/IR/CircleNode.h>
+
+#include <string>
+
+namespace luci
+{
+
+std::string opcode_name(const CircleNode *node);
+
+} // namespace luci
+
+#endif // __LUCI_PARTITION_CIRCLE_OP_CODE_H__
diff --git a/compiler/luci/partition/src/CircleOpCode.test.cpp b/compiler/luci/partition/src/CircleOpCode.test.cpp
new file mode 100644
index 000000000..d2524a2ef
--- /dev/null
+++ b/compiler/luci/partition/src/CircleOpCode.test.cpp
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "CircleOpCode.h"
+
+// NOTE any node will do for testing
+#include <luci/IR/Nodes/CircleSqrt.h>
+
+#include <gtest/gtest.h>
+
+TEST(CircleOpCodeTest, name)
+{
+ auto g = loco::make_graph();
+ auto node = g->nodes()->create<luci::CircleSqrt>();
+
+ auto name = luci::opcode_name(node);
+ ASSERT_EQ(name, "SQRT");
+}
diff --git a/compiler/luci/partition/src/ConnectNode.cpp b/compiler/luci/partition/src/ConnectNode.cpp
new file mode 100644
index 000000000..336be7c57
--- /dev/null
+++ b/compiler/luci/partition/src/ConnectNode.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+#include <oops/UserExn.h>
+
+namespace luci
+{
+
+void clone_connect(const luci::CircleNode *node, luci::CloneContext &clonecontext)
+{
+ ConnectNode cn(clonecontext);
+ node->accept(&cn);
+}
+
+luci::CircleNode *ConnectNode::find_clone(const luci::CircleNode *node)
+{
+ auto it = _clonecontext.find(node);
+ if (it == _clonecontext.end())
+ throw oops::UserExn("Invalid node in ConnectNode");
+ return it->second;
+}
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/ConnectNode.h b/compiler/luci/partition/src/ConnectNode.h
new file mode 100644
index 000000000..017c587e5
--- /dev/null
+++ b/compiler/luci/partition/src/ConnectNode.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_PARTITION_CONNECT_NODE_H__
+#define __LUCI_PARTITION_CONNECT_NODE_H__
+
+#include <luci/IR/CircleNode.h>
+#include <luci/IR/CircleNodeVisitor.h>
+
+namespace luci
+{
+
+/**
+ * @note MapNode2Clone is used as a map from original node to cloned node
+ * to find input of a cloned node
+ *
+ * (Original) (Clone)
+ *
+ * [A] [A']
+ * | [B] | [B']
+ * | | | |
+ * \ / \ /
+ * [C] [C']
+ *
+ * From view of [C'] we need to find [A'] and [B']. We know [C] from [C'],
+ * then we can get from input of [C] as [A], [B] then [A]->[A'] and [B]->[B']
+ * from the map.
+ */
+using MapNode2Clone = std::map<const CircleNode * /* ORG */, CircleNode * /* CLONE */>;
+
+struct CloneContext
+{
+ std::pair<MapNode2Clone::iterator, bool> emplace(const CircleNode *org, CircleNode *clone)
+ {
+ return node2clone.emplace(org, clone);
+ }
+ MapNode2Clone::iterator find(const CircleNode *org) { return node2clone.find(org); }
+ MapNode2Clone::iterator end(void) { return node2clone.end(); }
+
+ MapNode2Clone node2clone;
+};
+
+class ConnectNode final : public luci::CircleNodeVisitor<void>
+{
+public:
+ ConnectNode(luci::CloneContext &clonecontext) : _clonecontext(clonecontext){};
+
+public:
+ // void visit(const luci::CircleAbs *) final;
+ void visit(const luci::CircleAdd *) final;
+ // void visit(const luci::CircleAddN *) final;
+ // void visit(const luci::CircleArgMax *) final;
+ // void visit(const luci::CircleArgMin *) final;
+ // void visit(const luci::CircleAveragePool2D *) final;
+ // void visit(const luci::CircleBatchMatMul *) final;
+ // void visit(const luci::CircleBatchToSpaceND *) final;
+ // void visit(const luci::CircleCast *) final;
+ // void visit(const luci::CircleCeil *) final;
+ // void visit(const luci::CircleConcatenation *) final;
+ void visit(const luci::CircleConst *) final;
+ // void visit(const luci::CircleConv2D *) final;
+ // void visit(const luci::CircleCos *) final;
+ // void visit(const luci::CircleCustom *) final;
+ // void visit(const luci::CircleDepthToSpace *) final;
+ // void visit(const luci::CircleDepthwiseConv2D *) final;
+ // void visit(const luci::CircleDequantize *) final;
+ void visit(const luci::CircleDiv *) final;
+ // void visit(const luci::CircleElu *) final;
+ // void visit(const luci::CircleEqual *) final;
+ // void visit(const luci::CircleExp *) final;
+ // void visit(const luci::CircleExpandDims *) final;
+ // void visit(const luci::CircleFakeQuant *) final;
+ // void visit(const luci::CircleFill *) final;
+ // void visit(const luci::CircleFloor *) final;
+ // void visit(const luci::CircleFloorDiv *) final;
+ // void visit(const luci::CircleFloorMod *) final;
+ // void visit(const luci::CircleFullyConnected *) final;
+ // void visit(const luci::CircleGather *) final;
+ // void visit(const luci::CircleGatherNd *) final;
+ // void visit(const luci::CircleGreater *) final;
+ // void visit(const luci::CircleGreaterEqual *) final;
+ // void visit(const luci::CircleIf *) final;
+ // void visit(const luci::CircleL2Normalize *) final;
+ // void visit(const luci::CircleL2Pool2D *) final;
+ // void visit(const luci::CircleLeakyRelu *) final;
+ // void visit(const luci::CircleLess *) final;
+ // void visit(const luci::CircleLessEqual *) final;
+ // void visit(const luci::CircleLocalResponseNormalization *) final;
+ // void visit(const luci::CircleLog *) final;
+ // void visit(const luci::CircleLogicalAnd *) final;
+ // void visit(const luci::CircleLogicalNot *) final;
+ // void visit(const luci::CircleLogicalOr *) final;
+ // void visit(const luci::CircleLogistic *) final;
+ // void visit(const luci::CircleLogSoftmax *) final;
+ // void visit(const luci::CircleMatrixDiag *) final;
+ // void visit(const luci::CircleMatrixSetDiag *) final;
+ // void visit(const luci::CircleMaximum *) final;
+ // void visit(const luci::CircleMaxPool2D *) final;
+ void visit(const luci::CircleMean *) final;
+ // void visit(const luci::CircleMinimum *) final;
+ // void visit(const luci::CircleMirrorPad *) final;
+ void visit(const luci::CircleMul *) final;
+ // void visit(const luci::CircleNeg *) final;
+ // void visit(const luci::CircleNonMaxSuppressionV4 *) final;
+ // void visit(const luci::CircleNonMaxSuppressionV5 *) final;
+ // void visit(const luci::CircleNotEqual *) final;
+ // void visit(const luci::CircleOneHot *) final;
+ // void visit(const luci::CirclePack *) final;
+ // void visit(const luci::CirclePad *) final;
+ // void visit(const luci::CirclePadV2 *) final;
+ void visit(const luci::CirclePow *) final;
+ // void visit(const luci::CirclePRelu *) final;
+ // void visit(const luci::CircleRange *) final;
+ // void visit(const luci::CircleRank *) final;
+ // void visit(const luci::CircleReduceAny *) final;
+ // void visit(const luci::CircleReduceMax *) final;
+ // void visit(const luci::CircleReduceMin *) final;
+ // void visit(const luci::CircleReduceProd *) final;
+ // void visit(const luci::CircleRelu *) final;
+ // void visit(const luci::CircleRelu6 *) final;
+ // void visit(const luci::CircleReluN1To1 *) final;
+ // void visit(const luci::CircleReshape *) final;
+ // void visit(const luci::CircleResizeBilinear *) final;
+ // void visit(const luci::CircleResizeNearestNeighbor *) final;
+ // void visit(const luci::CircleReverseSequence *) final;
+ // void visit(const luci::CircleReverseV2 *) final;
+ // void visit(const luci::CircleRound *) final;
+ void visit(const luci::CircleRsqrt *) final;
+ // void visit(const luci::CircleScatterNd *) final;
+ // void visit(const luci::CircleSegmentSum *) final;
+ // void visit(const luci::CircleSelect *) final;
+ // void visit(const luci::CircleSelectV2 *) final;
+ // void visit(const luci::CircleShape *) final;
+ // void visit(const luci::CircleSin *) final;
+ // void visit(const luci::CircleSlice *) final;
+ // void visit(const luci::CircleSoftmax *) final;
+ // void visit(const luci::CircleSpaceToBatchND *) final;
+ // void visit(const luci::CircleSpaceToDepth *) final;
+ // void visit(const luci::CircleSparseToDense *) final;
+ // void visit(const luci::CircleSplit *) final;
+ // void visit(const luci::CircleSplitV *) final;
+ void visit(const luci::CircleSqrt *) final;
+ // void visit(const luci::CircleSquare *) final;
+ void visit(const luci::CircleSquaredDifference *) final;
+ // void visit(const luci::CircleSqueeze *) final;
+ // void visit(const luci::CircleStridedSlice *) final;
+ void visit(const luci::CircleSub *) final;
+ // void visit(const luci::CircleSum *) final;
+ // void visit(const luci::CircleTanh *) final;
+ // void visit(const luci::CircleTile *) final;
+ // void visit(const luci::CircleTopKV2 *) final;
+ // void visit(const luci::CircleTranspose *) final;
+ // void visit(const luci::CircleTransposeConv *) final;
+ // void visit(const luci::CircleUnidirectionalSequenceLSTM *) final;
+ // void visit(const luci::CircleUnique *) final;
+ // void visit(const luci::CircleUnpack *) final;
+ // void visit(const luci::CircleWhere *) final;
+ // void visit(const luci::CircleWhile *) final;
+ // void visit(const luci::CircleZerosLike *) final;
+
+ // Circle Only
+ // void visit(const luci::CircleBCQFullyConnected *) final;
+ // void visit(const luci::CircleBCQGather *) final;
+ // void visit(const luci::CircleInstanceNorm *) final;
+
+ // Virtual
+ // void visit(const luci::CircleCustomOut *) final;
+ // void visit(const luci::CircleIfOut *) final;
+ // void visit(const luci::CircleInput *) final;
+ // void visit(const luci::CircleNonMaxSuppressionV4Out *) final;
+ // void visit(const luci::CircleNonMaxSuppressionV5Out *) final;
+ // void visit(const luci::CircleOutput *) final;
+ // void visit(const luci::CircleOutputDummy *) final;
+ // void visit(const luci::CircleOutputExclude *) final;
+ // void visit(const luci::CircleSplitOut *) final;
+ // void visit(const luci::CircleSplitVOut *) final;
+ // void visit(const luci::CircleTopKV2Out *) final;
+ // void visit(const luci::CircleUniqueOut *) final;
+ // void visit(const luci::CircleUnpackOut *) final;
+ // void visit(const luci::CircleWhileOut *) final;
+
+public:
+ luci::CircleNode *find_clone(const luci::CircleNode *node);
+
+protected:
+ luci::CloneContext &_clonecontext;
+};
+
+/**
+ * @brief Connect cloned node from input node
+ */
+void clone_connect(const luci::CircleNode *node, luci::CloneContext &clonecontext);
+
+} // namespace luci
+
+#endif // __LUCI_PARTITION_CONNECT_NODE_H__
diff --git a/compiler/luci/partition/src/ConnectNode.test.cpp b/compiler/luci/partition/src/ConnectNode.test.cpp
new file mode 100644
index 000000000..a2009c654
--- /dev/null
+++ b/compiler/luci/partition/src/ConnectNode.test.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.test.h"
+
+// This file validates "ConnectNode.test.h". Please DO NOT remove this file.
diff --git a/compiler/luci/partition/src/ConnectNode.test.h b/compiler/luci/partition/src/ConnectNode.test.h
new file mode 100644
index 000000000..f7333ff99
--- /dev/null
+++ b/compiler/luci/partition/src/ConnectNode.test.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __CONNECT_NODE_TEST_H__
+#define __CONNECT_NODE_TEST_H__
+
+#include "ConnectNode.h"
+
+#include <luci/Service/CircleNodeClone.h>
+#include <luci/test/TestIOGraph.h>
+
+#include <loco/IR/Graph.h>
+
+#include <initializer_list>
+#include <memory>
+#include <stdexcept>
+#include <vector>
+
+namespace luci
+{
+namespace test
+{
+
+template <unsigned N> class TestIsOGraph : public TestIsGraphlet<N>, public TestOGraphlet
+{
+public:
+ TestIsOGraph() = default;
+
+public:
+ virtual void init(const std::initializer_list<ShapeU32> shape_in, const ShapeU32 shape_out)
+ {
+ if (shape_in.size() != N)
+ throw std::runtime_error("Failed to init TestIsOGraph");
+
+ TestIsGraphlet<N>::init(TestIsGraphlet<N>::g(), shape_in);
+ TestOGraphlet::init(TestIsGraphlet<N>::g(), shape_out);
+ }
+};
+
+template <class T> class NodeGraphletT
+{
+public:
+ virtual void init(loco::Graph *g)
+ {
+ _node = g->nodes()->create<T>();
+ _node->dtype(loco::DataType::S32);
+ _node->name("node");
+ }
+
+ T *node(void) const { return _node; }
+
+protected:
+ T *_node{nullptr};
+};
+
+template <class T> class NodeIsGraphletT
+{
+public:
+ virtual void init(loco::Graph *g, uint32_t n)
+ {
+ _node = g->nodes()->create<T>(n);
+ _node->dtype(loco::DataType::S32);
+ _node->name("node");
+ }
+
+ T *node(void) const { return _node; }
+
+protected:
+ T *_node{nullptr};
+};
+
+/**
+ * @brief ConnectionTestHelper provides common framework for testing
+ * cloned CircleNode connection
+ */
+class ConnectionTestHelper
+{
+public:
+ ConnectionTestHelper() { _graph_clone = loco::make_graph(); }
+
+public:
+ template <unsigned N> void prepare_inputs(TestIsOGraph<N> *isograph)
+ {
+ assert(N == isograph->num_inputs());
+
+ for (uint32_t i = 0; i < N; ++i)
+ {
+ auto *input = _graph_clone->nodes()->create<luci::CircleInput>();
+ luci::copy_common_attributes(isograph->input(i), input);
+ _clonectx.emplace(isograph->input(i), input);
+ _inputs.push_back(input);
+ }
+ }
+
+ /**
+ * @note prepare_inputs_miss is for negative testing
+ */
+ template <unsigned N> void prepare_inputs_miss(TestIsOGraph<N> *isograph)
+ {
+ assert(N == isograph->num_inputs());
+
+ for (uint32_t i = 0; i < N; ++i)
+ {
+ auto *input = _graph_clone->nodes()->create<luci::CircleInput>();
+ luci::copy_common_attributes(isograph->input(i), input);
+ if (i != 0)
+ _clonectx.emplace(isograph->input(i), input);
+ _inputs.push_back(input);
+ }
+ }
+
+ void clone_connect(luci::CircleNode *node, luci::CircleNode *clone)
+ {
+ _clonectx.emplace(node, clone);
+
+ luci::clone_connect(node, _clonectx);
+ }
+
+public:
+ loco::Graph *graph_clone(void) { return _graph_clone.get(); }
+
+ luci::CircleNode *inputs(uint32_t idx) { return _inputs.at(idx); }
+
+protected:
+ luci::CloneContext _clonectx;
+ std::vector<luci::CircleInput *> _inputs;
+ std::unique_ptr<loco::Graph> _graph_clone; // graph for clones
+};
+
+} // namespace test
+} // namespace luci
+
+#endif // __CONNECT_NODE_TEST_H__
diff --git a/compiler/luci/partition/src/Nodes/CircleAdd.cpp b/compiler/luci/partition/src/Nodes/CircleAdd.cpp
new file mode 100644
index 000000000..d393997e9
--- /dev/null
+++ b/compiler/luci/partition/src/Nodes/CircleAdd.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+namespace
+{
+
+void connect(luci::ConnectNode *cn, const luci::CircleAdd *node)
+{
+ auto *cloned = loco::must_cast<luci::CircleAdd *>(cn->find_clone(node));
+
+ luci::CircleNode *x = loco::must_cast<luci::CircleNode *>(node->x());
+ luci::CircleNode *y = loco::must_cast<luci::CircleNode *>(node->y());
+
+ cloned->x(cn->find_clone(x));
+ cloned->y(cn->find_clone(y));
+}
+
+} // namespace
+
+namespace luci
+{
+
+void ConnectNode::visit(const luci::CircleAdd *node) { connect(this, node); }
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/Nodes/CircleAdd.test.cpp b/compiler/luci/partition/src/Nodes/CircleAdd.test.cpp
new file mode 100644
index 000000000..e457b83d2
--- /dev/null
+++ b/compiler/luci/partition/src/Nodes/CircleAdd.test.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+#include "ConnectNode.test.h"
+
+#include <luci/Service/CircleNodeClone.h>
+
+#include <gtest/gtest.h>
+
+namespace
+{
+
+using namespace luci::test;
+
+class NodeGraphlet : public NodeGraphletT<luci::CircleAdd>
+{
+public:
+ NodeGraphlet() = default;
+
+public:
+ void init(loco::Graph *g) override
+ {
+ NodeGraphletT<luci::CircleAdd>::init(g);
+
+ _node->fusedActivationFunction(luci::FusedActFunc::RELU);
+ }
+};
+
+class TestNodeGraph : public TestIsOGraph<2>, public NodeGraphlet
+{
+public:
+ TestNodeGraph() = default;
+
+public:
+ void init(const ShapeU32 shape)
+ {
+ TestIsOGraph<2>::init({shape, shape}, shape);
+ NodeGraphlet::init(g());
+
+ node()->x(input(0));
+ node()->y(input(1));
+
+ output()->from(node());
+ }
+};
+
+} // namespace
+
+TEST(ConnectNodeTest, connect_Add)
+{
+ TestNodeGraph tng;
+ tng.init({2, 3});
+
+ ConnectionTestHelper cth;
+ cth.prepare_inputs(&tng);
+
+ auto *node = tng.node();
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleAdd *>(node));
+
+ auto *clone = luci::clone_node(node, cth.graph_clone());
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleAdd *>(clone));
+
+ cth.clone_connect(node, clone);
+
+ ASSERT_EQ(2, clone->arity());
+ ASSERT_EQ(cth.inputs(0), clone->arg(0));
+ ASSERT_EQ(cth.inputs(1), clone->arg(1));
+}
+
+TEST(ConnectNodeTest, connect_Add_NEG)
+{
+ TestNodeGraph tng;
+ tng.init({2, 3});
+
+ ConnectionTestHelper cth;
+ cth.prepare_inputs_miss(&tng);
+
+ auto *node = tng.node();
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleAdd *>(node));
+
+ auto *clone = luci::clone_node(node, cth.graph_clone());
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleAdd *>(clone));
+
+ EXPECT_ANY_THROW(cth.clone_connect(node, clone));
+}
diff --git a/compiler/luci/partition/src/Nodes/CircleConst.cpp b/compiler/luci/partition/src/Nodes/CircleConst.cpp
new file mode 100644
index 000000000..118cd8de2
--- /dev/null
+++ b/compiler/luci/partition/src/Nodes/CircleConst.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+namespace luci
+{
+
+void ConnectNode::visit(const luci::CircleConst *)
+{
+ // Nothing to do
+}
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/Nodes/CircleDiv.cpp b/compiler/luci/partition/src/Nodes/CircleDiv.cpp
new file mode 100644
index 000000000..480338542
--- /dev/null
+++ b/compiler/luci/partition/src/Nodes/CircleDiv.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+namespace
+{
+
+void connect(luci::ConnectNode *cn, const luci::CircleDiv *node)
+{
+ auto *cloned = loco::must_cast<luci::CircleDiv *>(cn->find_clone(node));
+
+ luci::CircleNode *x = loco::must_cast<luci::CircleNode *>(node->x());
+ luci::CircleNode *y = loco::must_cast<luci::CircleNode *>(node->y());
+
+ cloned->x(cn->find_clone(x));
+ cloned->y(cn->find_clone(y));
+}
+
+} // namespace
+
+namespace luci
+{
+
+void ConnectNode::visit(const luci::CircleDiv *node) { connect(this, node); }
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/Nodes/CircleDiv.test.cpp b/compiler/luci/partition/src/Nodes/CircleDiv.test.cpp
new file mode 100644
index 000000000..226932337
--- /dev/null
+++ b/compiler/luci/partition/src/Nodes/CircleDiv.test.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+#include "ConnectNode.test.h"
+
+#include <luci/Service/CircleNodeClone.h>
+
+#include <gtest/gtest.h>
+
+namespace
+{
+
+using namespace luci::test;
+
+class NodeGraphlet : public NodeGraphletT<luci::CircleDiv>
+{
+public:
+ NodeGraphlet() = default;
+
+public:
+ void init(loco::Graph *g) override
+ {
+ NodeGraphletT<luci::CircleDiv>::init(g);
+
+ _node->fusedActivationFunction(luci::FusedActFunc::RELU);
+ }
+};
+
+class TestNodeGraph : public TestIsOGraph<2>, public NodeGraphlet
+{
+public:
+ TestNodeGraph() = default;
+
+public:
+ void init(const ShapeU32 shape)
+ {
+ TestIsOGraph<2>::init({shape, shape}, shape);
+ NodeGraphlet::init(g());
+
+ node()->x(input(0));
+ node()->y(input(1));
+
+ output()->from(node());
+ }
+};
+
+} // namespace
+
+TEST(ConnectNodeTest, connect_Div)
+{
+ TestNodeGraph tng;
+ tng.init({2, 3});
+
+ ConnectionTestHelper cth;
+ cth.prepare_inputs(&tng);
+
+ auto *node = tng.node();
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleDiv *>(node));
+
+ auto *clone = luci::clone_node(node, cth.graph_clone());
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleDiv *>(clone));
+
+ cth.clone_connect(node, clone);
+
+ ASSERT_EQ(2, clone->arity());
+ ASSERT_EQ(cth.inputs(0), clone->arg(0));
+ ASSERT_EQ(cth.inputs(1), clone->arg(1));
+}
+
+TEST(ConnectNodeTest, connect_Div_NEG)
+{
+ TestNodeGraph tng;
+ tng.init({2, 3});
+
+ ConnectionTestHelper cth;
+ cth.prepare_inputs_miss(&tng);
+
+ auto *node = tng.node();
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleDiv *>(node));
+
+ auto *clone = luci::clone_node(node, cth.graph_clone());
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleDiv *>(clone));
+
+ EXPECT_ANY_THROW(cth.clone_connect(node, clone));
+}
diff --git a/compiler/luci/partition/src/Nodes/CircleMean.cpp b/compiler/luci/partition/src/Nodes/CircleMean.cpp
new file mode 100644
index 000000000..b634e5838
--- /dev/null
+++ b/compiler/luci/partition/src/Nodes/CircleMean.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+namespace
+{
+
+void connect(luci::ConnectNode *cn, const luci::CircleMean *node)
+{
+ auto *cloned = loco::must_cast<luci::CircleMean *>(cn->find_clone(node));
+
+ luci::CircleNode *input = loco::must_cast<luci::CircleNode *>(node->input());
+ luci::CircleNode *reduction_indices =
+ loco::must_cast<luci::CircleNode *>(node->reduction_indices());
+
+ cloned->input(cn->find_clone(input));
+ cloned->reduction_indices(cn->find_clone(reduction_indices));
+}
+
+} // namespace
+
+namespace luci
+{
+
+void ConnectNode::visit(const luci::CircleMean *node) { connect(this, node); }
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/Nodes/CircleMul.cpp b/compiler/luci/partition/src/Nodes/CircleMul.cpp
new file mode 100644
index 000000000..2cd2b4038
--- /dev/null
+++ b/compiler/luci/partition/src/Nodes/CircleMul.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+namespace
+{
+
+void connect(luci::ConnectNode *cn, const luci::CircleMul *node)
+{
+ auto *cloned = loco::must_cast<luci::CircleMul *>(cn->find_clone(node));
+
+ luci::CircleNode *x = loco::must_cast<luci::CircleNode *>(node->x());
+ luci::CircleNode *y = loco::must_cast<luci::CircleNode *>(node->y());
+
+ cloned->x(cn->find_clone(x));
+ cloned->y(cn->find_clone(y));
+}
+
+} // namespace
+
+namespace luci
+{
+
+void ConnectNode::visit(const luci::CircleMul *node) { connect(this, node); }
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/Nodes/CircleMul.test.cpp b/compiler/luci/partition/src/Nodes/CircleMul.test.cpp
new file mode 100644
index 000000000..99cf0824d
--- /dev/null
+++ b/compiler/luci/partition/src/Nodes/CircleMul.test.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+#include "ConnectNode.test.h"
+
+#include <luci/Service/CircleNodeClone.h>
+
+#include <gtest/gtest.h>
+
+namespace
+{
+
+using namespace luci::test;
+
+class NodeGraphlet : public NodeGraphletT<luci::CircleMul>
+{
+public:
+ NodeGraphlet() = default;
+
+public:
+ void init(loco::Graph *g)
+ {
+ NodeGraphletT<luci::CircleMul>::init(g);
+
+ _node->fusedActivationFunction(luci::FusedActFunc::RELU);
+ }
+};
+
+class TestNodeGraph : public TestIsOGraph<2>, public NodeGraphlet
+{
+public:
+ TestNodeGraph() = default;
+
+public:
+ void init(const ShapeU32 shape)
+ {
+ TestIsOGraph<2>::init({shape, shape}, shape);
+ NodeGraphlet::init(g());
+
+ node()->x(input(0));
+ node()->y(input(1));
+
+ output()->from(node());
+ }
+};
+
+} // namespace
+
+TEST(ConnectNodeTest, connect_Mul)
+{
+ TestNodeGraph tng;
+ tng.init({2, 3});
+
+ ConnectionTestHelper cth;
+ cth.prepare_inputs(&tng);
+
+ auto *node = tng.node();
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleMul *>(node));
+
+ auto *clone = luci::clone_node(node, cth.graph_clone());
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleMul *>(clone));
+
+ cth.clone_connect(node, clone);
+
+ ASSERT_EQ(2, clone->arity());
+ ASSERT_EQ(cth.inputs(0), clone->arg(0));
+ ASSERT_EQ(cth.inputs(1), clone->arg(1));
+}
+
+TEST(ConnectNodeTest, connect_Mul_NEG)
+{
+ TestNodeGraph tng;
+ tng.init({2, 3});
+
+ ConnectionTestHelper cth;
+ cth.prepare_inputs_miss(&tng);
+
+ auto *node = tng.node();
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleMul *>(node));
+
+ auto *clone = luci::clone_node(node, cth.graph_clone());
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleMul *>(clone));
+
+ EXPECT_ANY_THROW(cth.clone_connect(node, clone));
+}
diff --git a/compiler/luci/partition/src/Nodes/CirclePow.cpp b/compiler/luci/partition/src/Nodes/CirclePow.cpp
new file mode 100644
index 000000000..fb180ee69
--- /dev/null
+++ b/compiler/luci/partition/src/Nodes/CirclePow.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+namespace
+{
+
+void connect(luci::ConnectNode *cn, const luci::CirclePow *node)
+{
+ auto *cloned = loco::must_cast<luci::CirclePow *>(cn->find_clone(node));
+
+ luci::CircleNode *x = loco::must_cast<luci::CircleNode *>(node->x());
+ luci::CircleNode *y = loco::must_cast<luci::CircleNode *>(node->y());
+
+ cloned->x(cn->find_clone(x));
+ cloned->y(cn->find_clone(y));
+}
+
+} // namespace
+
+namespace luci
+{
+
+void ConnectNode::visit(const luci::CirclePow *node) { connect(this, node); }
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/Nodes/CircleRsqrt.cpp b/compiler/luci/partition/src/Nodes/CircleRsqrt.cpp
new file mode 100644
index 000000000..03e64aad0
--- /dev/null
+++ b/compiler/luci/partition/src/Nodes/CircleRsqrt.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+namespace
+{
+
+void connect(luci::ConnectNode *cn, const luci::CircleRsqrt *node)
+{
+ auto *cloned = loco::must_cast<luci::CircleRsqrt *>(cn->find_clone(node));
+
+ luci::CircleNode *x = loco::must_cast<luci::CircleNode *>(node->x());
+
+ cloned->x(cn->find_clone(x));
+}
+
+} // namespace
+
+namespace luci
+{
+
+void ConnectNode::visit(const luci::CircleRsqrt *node) { connect(this, node); }
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/Nodes/CircleSqrt.cpp b/compiler/luci/partition/src/Nodes/CircleSqrt.cpp
new file mode 100644
index 000000000..f737aac8d
--- /dev/null
+++ b/compiler/luci/partition/src/Nodes/CircleSqrt.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+namespace
+{
+
+void connect(luci::ConnectNode *cn, const luci::CircleSqrt *node)
+{
+ auto *cloned = loco::must_cast<luci::CircleSqrt *>(cn->find_clone(node));
+
+ luci::CircleNode *x = loco::must_cast<luci::CircleNode *>(node->x());
+
+ cloned->x(cn->find_clone(x));
+}
+
+} // namespace
+
+namespace luci
+{
+
+void ConnectNode::visit(const luci::CircleSqrt *node) { connect(this, node); }
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/Nodes/CircleSquaredDifference.cpp b/compiler/luci/partition/src/Nodes/CircleSquaredDifference.cpp
new file mode 100644
index 000000000..40dd31706
--- /dev/null
+++ b/compiler/luci/partition/src/Nodes/CircleSquaredDifference.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+namespace
+{
+
+void connect(luci::ConnectNode *cn, const luci::CircleSquaredDifference *node)
+{
+ auto *cloned = loco::must_cast<luci::CircleSquaredDifference *>(cn->find_clone(node));
+
+ luci::CircleNode *x = loco::must_cast<luci::CircleNode *>(node->x());
+ luci::CircleNode *y = loco::must_cast<luci::CircleNode *>(node->y());
+
+ cloned->x(cn->find_clone(x));
+ cloned->y(cn->find_clone(y));
+}
+
+} // namespace
+
+namespace luci
+{
+
+void ConnectNode::visit(const luci::CircleSquaredDifference *node) { connect(this, node); }
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/Nodes/CircleSub.cpp b/compiler/luci/partition/src/Nodes/CircleSub.cpp
new file mode 100644
index 000000000..8ac294b7b
--- /dev/null
+++ b/compiler/luci/partition/src/Nodes/CircleSub.cpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+namespace
+{
+
+void connect(luci::ConnectNode *cn, const luci::CircleSub *node)
+{
+ auto *cloned = loco::must_cast<luci::CircleSub *>(cn->find_clone(node));
+
+ luci::CircleNode *x = loco::must_cast<luci::CircleNode *>(node->x());
+ luci::CircleNode *y = loco::must_cast<luci::CircleNode *>(node->y());
+
+ cloned->x(cn->find_clone(x));
+ cloned->y(cn->find_clone(y));
+}
+
+} // namespace
+
+namespace luci
+{
+
+void ConnectNode::visit(const luci::CircleSub *node) { connect(this, node); }
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/Nodes/CircleSub.test.cpp b/compiler/luci/partition/src/Nodes/CircleSub.test.cpp
new file mode 100644
index 000000000..7c0d83745
--- /dev/null
+++ b/compiler/luci/partition/src/Nodes/CircleSub.test.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "ConnectNode.h"
+
+#include "ConnectNode.test.h"
+
+#include <luci/Service/CircleNodeClone.h>
+
+#include <gtest/gtest.h>
+
+namespace
+{
+
+using namespace luci::test;
+
+class NodeGraphlet : public NodeGraphletT<luci::CircleSub>
+{
+public:
+ NodeGraphlet() = default;
+
+public:
+ void init(loco::Graph *g)
+ {
+ NodeGraphletT<luci::CircleSub>::init(g);
+
+ _node->fusedActivationFunction(luci::FusedActFunc::RELU);
+ }
+};
+
+class TestNodeGraph : public TestIsOGraph<2>, public NodeGraphlet
+{
+public:
+ TestNodeGraph() = default;
+
+public:
+ void init(const ShapeU32 shape)
+ {
+ TestIsOGraph<2>::init({shape, shape}, shape);
+ NodeGraphlet::init(g());
+
+ node()->x(input(0));
+ node()->y(input(1));
+
+ output()->from(node());
+ }
+};
+
+} // namespace
+
+TEST(ConnectNodeTest, connect_Sub)
+{
+ TestNodeGraph tng;
+ tng.init({2, 3});
+
+ ConnectionTestHelper cth;
+ cth.prepare_inputs(&tng);
+
+ auto *node = tng.node();
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleSub *>(node));
+
+ auto *clone = luci::clone_node(node, cth.graph_clone());
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleSub *>(clone));
+
+ cth.clone_connect(node, clone);
+
+ ASSERT_EQ(2, clone->arity());
+ ASSERT_EQ(cth.inputs(0), clone->arg(0));
+ ASSERT_EQ(cth.inputs(1), clone->arg(1));
+}
+
+TEST(ConnectNodeTest, connect_Sub_NEG)
+{
+ TestNodeGraph tng;
+ tng.init({2, 3});
+
+ ConnectionTestHelper cth;
+ cth.prepare_inputs_miss(&tng);
+
+ auto *node = tng.node();
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleSub *>(node));
+
+ auto *clone = luci::clone_node(node, cth.graph_clone());
+ ASSERT_NO_THROW(loco::must_cast<luci::CircleSub *>(clone));
+
+ EXPECT_ANY_THROW(cth.clone_connect(node, clone));
+}
diff --git a/compiler/luci/partition/src/Partition.cpp b/compiler/luci/partition/src/Partition.cpp
new file mode 100644
index 000000000..cc7106ca9
--- /dev/null
+++ b/compiler/luci/partition/src/Partition.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "PartitionIR.h"
+#include "PartitionIRDump.h"
+#include "PartitionPGroups.h"
+#include "PartitionMerge.h"
+#include "PartitionCleanup.h"
+#include "PartitionPModules.h"
+#include "PartitionPModulesDump.h"
+
+#include "luci/Partition.h"
+#include "luci/Log.h"
+
+#include <cassert>
+
+namespace luci
+{
+
+/**
+ * @brief This will return Partitioned Modules object
+ */
+PartedModules apply(Module *source, const PartitionTable &partition)
+{
+ assert(source != nullptr);
+
+ LOGGER(l);
+
+ auto pgroups = produce_pgroups(source, partition);
+ INFO(l) << "--- Partition Graph (1)------------------------";
+ INFO(l) << pgroups.get();
+
+ auto mpgroups = merge_pgroups(pgroups.get());
+ INFO(l) << "--- Partition Graph (2)------------------------";
+ INFO(l) << mpgroups.get();
+
+ remove_unused_inputoutputs(mpgroups.get(), source);
+ INFO(l) << "--- Partition Graph (3)------------------------";
+ INFO(l) << mpgroups.get();
+
+ auto pmodules = produce_pmodules(mpgroups.get());
+ INFO(l) << "--- Modules -----------------------------------";
+ INFO(l) << &pmodules;
+
+ return pmodules;
+}
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/Partition.test.cpp b/compiler/luci/partition/src/Partition.test.cpp
new file mode 100644
index 000000000..9e24c441c
--- /dev/null
+++ b/compiler/luci/partition/src/Partition.test.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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/Partition.h"
+
+#include <luci/test/TestIOGraph.h>
+
+#include <luci/IR/Nodes/CircleSqrt.h>
+
+#include <gtest/gtest.h>
+
+namespace
+{
+
+using namespace luci::test;
+
+class SqrtGraphlet
+{
+public:
+ SqrtGraphlet() = default;
+
+public:
+ void init(loco::Graph *g, const ShapeU32 input_shape)
+ {
+ _sqrt = g->nodes()->create<luci::CircleSqrt>();
+ _sqrt->dtype(loco::DataType::S32);
+ _sqrt->name("sqrt");
+ }
+
+protected:
+ luci::CircleSqrt *_sqrt = nullptr;
+};
+
+class SqrtGraph : public TestIOGraph, public SqrtGraphlet
+{
+public:
+ SqrtGraph() = default;
+
+public:
+ void init(const ShapeU32 shape)
+ {
+ TestIOGraph::init(shape, shape);
+ SqrtGraphlet::init(g(), shape);
+
+ _sqrt->x(input());
+
+ output()->from(_sqrt);
+ }
+};
+
+} // namespace
+
+TEST(PartitionTest, simple_apply)
+{
+ luci::Module module;
+
+ SqrtGraph g;
+ g.init({3, 3});
+ g.transfer_to(&module);
+
+ luci::PartitionTable pt;
+ pt.default_group = "A";
+
+ auto pms = apply(&module, pt);
+
+ ASSERT_EQ(1, pms.pmodules.size());
+
+ auto &pm = *pms.pmodules.begin();
+ ASSERT_NE(nullptr, pm.module->graph());
+}
diff --git a/compiler/luci/partition/src/PartitionCleanup.cpp b/compiler/luci/partition/src/PartitionCleanup.cpp
new file mode 100644
index 000000000..6545295df
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionCleanup.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "PartitionCleanup.h"
+
+#include "luci/Log.h"
+
+namespace
+{
+
+using CircleNodes = std::vector<luci::CircleNode *>;
+
+/**
+ * @note Original source outputs should be outputs
+ */
+void gather_graph_outputs(CircleNodes &nodes, const luci::Module *source)
+{
+ // graph outputs are treated as used
+ auto graph = source->graph();
+ for (uint32_t n = 0; n < graph->outputs()->size(); ++n)
+ {
+ auto output = luci::output_node(graph, n); // output is CircleOutput
+ assert(output != nullptr);
+
+ auto node = loco::must_cast<luci::CircleNode *>(output->from());
+
+ nodes.push_back(node);
+ }
+
+ // TODO add unused virtual outputs
+}
+
+/**
+ * @note If one PGroup requires an input, that input should be an output
+ * from another PGroup
+ */
+void gather_pgroups_outputs(CircleNodes &nodes, const luci::PGroups *pgroups)
+{
+ // input of a pgroup is used output
+ for (auto &pgroup : pgroups->pgroups)
+ {
+ for (auto input : pgroup->inputs)
+ {
+ nodes.push_back(input);
+ }
+ }
+}
+
+} // namespace
+
+namespace luci
+{
+
+void remove_unused_inputoutputs(luci::PGroups *pgroups, const luci::Module *source)
+{
+ assert(source != nullptr);
+ assert(pgroups != nullptr);
+
+ LOGGER(l);
+
+ // TODO support multiple subgraph
+ assert(source->size() == 1);
+
+ INFO(l) << "--- Cleanup unused inputs/outputs";
+
+ // remove input within same pgroup
+ for (auto &pgroup : pgroups->pgroups)
+ {
+ bool changed;
+ do
+ {
+ changed = false;
+ for (auto it = pgroup->inputs.begin(); it != pgroup->inputs.end(); ++it)
+ {
+ auto input = *it;
+ if (pgroups->pgroup_of(input) == pgroup.get())
+ {
+ INFO(l) << " Cleanup input " << input->name() << " from group " << pgroup->group;
+ pgroup->inputs.erase(it);
+ changed = true;
+ break;
+ }
+ // NOTE CircleConst is one of input type, as they are registered as
+ // input to some node and then (should be) merged.
+ // Remove if this input is CircleConst
+ if (dynamic_cast<CircleConst *>(input) != nullptr)
+ {
+ INFO(l) << " Cleanup CircleConst " << input->name() << " from group " << pgroup->group;
+ pgroup->inputs.erase(it);
+ changed = true;
+ break;
+ }
+ }
+ } while (changed);
+ }
+
+ // remove unused output(s)
+ // 'used_outputs' will hold actual used outputs for all PGroups
+ CircleNodes used_outputs;
+
+ gather_graph_outputs(used_outputs, source);
+ gather_pgroups_outputs(used_outputs, pgroups);
+
+ for (auto &pgroup : pgroups->pgroups)
+ {
+ bool changed;
+ do
+ {
+ changed = false;
+ for (auto it = pgroup->outputs.begin(); it != pgroup->outputs.end(); ++it)
+ {
+ auto output = *it;
+ auto oit = std::find(used_outputs.begin(), used_outputs.end(), output);
+ if (oit == used_outputs.end())
+ {
+ INFO(l) << " Cleanup output " << output->name() << " from group " << pgroup->group;
+ pgroup->outputs.erase(it);
+ changed = true;
+ break;
+ }
+ }
+ } while (changed);
+ }
+}
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/PartitionCleanup.h b/compiler/luci/partition/src/PartitionCleanup.h
new file mode 100644
index 000000000..f81b4a7cb
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionCleanup.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_PARTITON_CLEANUP_H__
+#define __LUCI_PARTITON_CLEANUP_H__
+
+#include "PartitionIR.h"
+
+#include <luci/IR/Module.h>
+
+namespace luci
+{
+
+/**
+ * @brief This will remove unused inputs/outputs in each pgroup of pgroups
+ */
+void remove_unused_inputoutputs(luci::PGroups *, const luci::Module *);
+
+} // namespace luci
+
+#endif // __LUCI_PARTITON_CLEANUP_H__
diff --git a/compiler/luci/partition/src/PartitionIR.cpp b/compiler/luci/partition/src/PartitionIR.cpp
new file mode 100644
index 000000000..ebd6b25fa
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionIR.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "PartitionIR.h"
+#include "CircleOpCode.h"
+
+#include "luci/Log.h"
+
+#include <cassert>
+#include <ostream>
+#include <iostream>
+
+namespace luci
+{
+
+std::unique_ptr<PGroups> PGroups::make_copy(void) const
+{
+ auto d_pgroups = std::make_unique<luci::PGroups>();
+
+ for (auto &s_pgroup : pgroups)
+ {
+ // make a copy of s_pgroup to d_pgroup
+ std::unique_ptr<luci::PGroup> d_pgroup = std::make_unique<luci::PGroup>();
+
+ d_pgroup->group = s_pgroup->group;
+ d_pgroup->id = s_pgroup->id;
+
+ for (auto &pnode : s_pgroup->pnodes)
+ {
+ auto pnodec = std::make_unique<luci::PNode>();
+ pnodec->node = pnode->node;
+ pnodec->group = pnode->group;
+ pnodec->pgroup = d_pgroup.get();
+ d_pgroup->pnodes.push_back(std::move(pnodec));
+ }
+
+ for (auto &input : s_pgroup->inputs)
+ d_pgroup->inputs.push_back(input);
+
+ for (auto &output : s_pgroup->outputs)
+ d_pgroup->outputs.push_back(output);
+
+ // copy node2group
+ for (auto it = node2group.begin(); it != node2group.end(); ++it)
+ d_pgroups->node2group[it->first] = it->second;
+
+ // build id2pgroup
+ d_pgroups->id2pgroup[d_pgroup->id] = d_pgroup.get();
+
+ d_pgroups->pgroups.push_back(std::move(d_pgroup));
+ // note: d_pgroup is now nullptr as it's moved
+ }
+
+ return std::move(d_pgroups);
+}
+
+std::string PGroups::group_of(luci::CircleNode *node) const
+{
+ assert(node != nullptr);
+
+ LOGGER(l);
+
+ auto it = node2group.find(node);
+ if (it == node2group.end())
+ {
+ INFO(l) << "PGroups::group_of " << node << "(" << node->name() << ") not found" << std::endl;
+ return "";
+ }
+ return it->second;
+}
+
+const PGroup *PGroups::pgroup_of(luci::CircleNode *node) const
+{
+ assert(node != nullptr);
+
+ for (auto &pgroup : pgroups)
+ {
+ for (auto &pnode : pgroup->pnodes)
+ {
+ if (node == pnode->node)
+ return pgroup.get();
+ }
+ }
+ // node maybe graph input (CircleInput)
+ return nullptr;
+}
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/PartitionIR.h b/compiler/luci/partition/src/PartitionIR.h
new file mode 100644
index 000000000..852e38cc0
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionIR.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_PARTITION_IR_H__
+#define __LUCI_PARTITION_IR_H__
+
+#include <luci/IR/CircleNodes.h>
+
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace luci
+{
+
+struct PGroup;
+
+/**
+ * @brief Partition Node with CircleNode with group name
+ * @note node just points to source luci::CircleNode, NOT the cloned node
+ * CloneContext is used to find cloned node from source node
+ */
+struct PNode
+{
+ const luci::CircleNode *node = nullptr;
+ std::string group;
+
+ const PGroup *pgroup = nullptr;
+};
+
+/**
+ * @brief Partition Group with Partition Nodes of same group and I/Os nodes
+ */
+struct PGroup
+{
+ std::vector<std::unique_ptr<PNode>> pnodes;
+ std::string group;
+ uint32_t id = 0;
+
+ // I/O while partitioning
+ std::vector<luci::CircleNode *> inputs;
+ std::vector<luci::CircleNode *> outputs;
+};
+
+struct PGroups
+{
+ std::vector<std::unique_ptr<PGroup>> pgroups;
+
+ // node2group is to find group key from source node
+ std::map<const luci::CircleNode *, std::string> node2group;
+
+ // id2pngroup is to find *pngroup from pngroup id
+ std::map<uint32_t, PGroup *> id2pgroup;
+
+ // default group key for reference
+ std::string default_group;
+
+public:
+ /**
+ * @brief return a copy of PGroups
+ */
+ std::unique_ptr<PGroups> make_copy(void) const;
+
+ /**
+ * @brief return group key of node, empty string if not found
+ */
+ std::string group_of(luci::CircleNode *node) const;
+
+ /**
+ * @brief return holding pgroup of node, nullptr if not found
+ */
+ const PGroup *pgroup_of(luci::CircleNode *node) const;
+};
+
+} // namespace luci
+
+#endif // __LUCI_PARTITION_IR_H__
diff --git a/compiler/luci/partition/src/PartitionIR.test.cpp b/compiler/luci/partition/src/PartitionIR.test.cpp
new file mode 100644
index 000000000..4c051a96d
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionIR.test.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "PartitionIR.h"
+
+// NOTE any node will do for testing
+#include <luci/IR/Nodes/CircleAdd.h>
+
+#include <gtest/gtest.h>
+
+#include <memory>
+
+TEST(PartitionIRTest, PNode_ctor)
+{
+ auto g = loco::make_graph();
+ auto node = g->nodes()->create<luci::CircleAdd>();
+
+ luci::PNode pnode;
+ pnode.node = node;
+
+ ASSERT_NE(nullptr, pnode.node);
+ ASSERT_EQ(nullptr, pnode.pgroup);
+}
+
+// TODO add more tests with luci::PNode
+
+TEST(PartitionIRTest, PGroup_ctor)
+{
+ auto g = loco::make_graph();
+ auto node = g->nodes()->create<luci::CircleAdd>();
+
+ luci::PGroup pgroup;
+ auto pnode = std::make_unique<luci::PNode>();
+ pnode->node = node;
+
+ pgroup.pnodes.push_back(std::move(pnode));
+
+ ASSERT_NE(pgroup.pnodes.end(), pgroup.pnodes.begin());
+ ASSERT_EQ(0, pgroup.inputs.size());
+ ASSERT_EQ(0, pgroup.outputs.size());
+}
+
+// TODO add more tests with luci::PGroup
+
+TEST(PartitionIRTest, PGroups_ctor)
+{
+ auto g = loco::make_graph();
+ auto node = g->nodes()->create<luci::CircleAdd>();
+
+ auto pnode = std::make_unique<luci::PNode>();
+ pnode->node = node;
+
+ auto pgroup = std::make_unique<luci::PGroup>();
+ pgroup->pnodes.push_back(std::move(pnode));
+
+ luci::PGroups pgroups;
+ pgroups.pgroups.push_back(std::move(pgroup));
+
+ ASSERT_NE(pgroups.pgroups.end(), pgroups.pgroups.begin());
+}
+
+// TODO add more tests with luci::PGroups
diff --git a/compiler/luci/partition/src/PartitionIRDump.cpp b/compiler/luci/partition/src/PartitionIRDump.cpp
new file mode 100644
index 000000000..4f2c26800
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionIRDump.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "PartitionIRDump.h"
+
+#include "CircleOpCode.h"
+
+#include <iostream>
+
+namespace luci
+{
+
+void dump(std::ostream &os, const PNode *pnode)
+{
+ os << "PNode: " << pnode->group << ", " << pnode->node << ":" << luci::opcode_name(pnode->node)
+ << ":" << pnode->node->name() << std::endl;
+}
+
+void dump(std::ostream &os, const PGroup *pgroup)
+{
+ os << "--- PGroup: " << pgroup->group << std::endl;
+ os << "Input(s): ";
+ for (auto &node_in : pgroup->inputs)
+ os << node_in->name() << " ";
+ os << std::endl;
+ for (auto &pnode : pgroup->pnodes)
+ {
+ dump(os, pnode.get());
+ }
+ os << "Output(s): ";
+ for (auto &node_out : pgroup->outputs)
+ os << node_out->name() << " ";
+ os << std::endl;
+}
+
+void dump(std::ostream &os, const PGroups *pgroups)
+{
+ for (auto &pgroup : pgroups->pgroups)
+ {
+ dump(os, pgroup.get());
+ }
+ os << "--- Node2Group items: " << std::endl;
+ for (auto it = pgroups->node2group.begin(); it != pgroups->node2group.end(); ++it)
+ {
+ auto node = it->first;
+ auto group = it->second;
+ os << " Node: " << node << "(" << node->name() << "): " << group << std::endl;
+ }
+}
+
+} // namespace luci
+
+std::ostream &operator<<(std::ostream &os, const luci::PGroups *pgroups)
+{
+ luci::dump(os, pgroups);
+ return os;
+}
diff --git a/compiler/luci/partition/src/PartitionIRDump.h b/compiler/luci/partition/src/PartitionIRDump.h
new file mode 100644
index 000000000..8a4b3f579
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionIRDump.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_PARTITION_IR_DUMP_H__
+#define __LUCI_PARTITION_IR_DUMP_H__
+
+#include "PartitionIR.h"
+
+#include <iostream>
+
+namespace luci
+{
+
+void dump(std::ostream &os, const PNode *pnode);
+void dump(std::ostream &os, const PGroup *pgroup);
+void dump(std::ostream &os, const PGroups *pgroups);
+
+} // namespace luci
+
+std::ostream &operator<<(std::ostream &os, const luci::PGroups *pgroups);
+
+#endif // __LUCI_PARTITION_IR_DUMP_H__
diff --git a/compiler/luci/partition/src/PartitionMerge.cpp b/compiler/luci/partition/src/PartitionMerge.cpp
new file mode 100644
index 000000000..038fc2a0c
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionMerge.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "PartitionMerge.h"
+
+#include <algorithm>
+
+namespace
+{
+
+/**
+ * @brief return true if pgroup_i output is one of the inputs of pgroup
+ */
+bool is_input_of(const luci::PGroup *pgroup_i, const luci::PGroup *pgroup)
+{
+ for (auto *output : pgroup_i->outputs)
+ {
+ for (auto *input : pgroup->inputs)
+ {
+ if (input == output)
+ return true;
+ }
+ }
+ return false;
+}
+
+/**
+ * @brief return true if there is only one input or all the inputs have same group
+ * @note pgroups is used to find group of pgroup
+ */
+bool is_input_same(const luci::PGroup *pgroup, const luci::PGroups *pgroups)
+{
+ assert(pgroups != nullptr);
+ assert(pgroup != nullptr);
+
+ const luci::PGroup *input_pgroup = nullptr;
+ std::string group;
+ for (auto &input : pgroup->inputs)
+ {
+ auto input_group = pgroups->group_of(input);
+ // NOTE: all the nodes should be registered and return should be valid group.
+ // convert_to_proups() should ensure this.
+ // assert here to find if there is any problem with this.
+ assert(not input_group.empty());
+ if (input_group.empty())
+ input_group = pgroups->default_group;
+
+ if (group.empty())
+ group = input_group;
+ else
+ {
+ if (group != input_group)
+ return false;
+ }
+ // if there are multiple inputs, all the inputs should be in same pgroup
+ // https://github.com/Samsung/ONE/issues/6230#issuecomment-801618150
+ // https://github.com/Samsung/ONE/issues/6230#issuecomment-801680531
+ auto pgroup_input = pgroups->pgroup_of(input);
+ if (pgroup_input != nullptr)
+ {
+ if (input_pgroup == nullptr)
+ input_pgroup = pgroup_input;
+ else
+ {
+ if (input_pgroup != pgroup_input)
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/**
+ * @brief merge pgroup into pgroup_i
+ * @note output of pgroup_i should be input of pgroup
+ */
+void merge_into(luci::PGroup *pgroup, luci::PGroup *pgroup_i)
+{
+ for (auto &pnode : pgroup->pnodes)
+ {
+ // update pgroup for this pnode
+ pnode->pgroup = pgroup_i;
+ assert(pnode->group == pgroup_i->group);
+
+ // we don't need to add this in topological order:
+ // all the nodes will be created first then connection will be held
+ pgroup_i->pnodes.push_back(std::move(pnode));
+ // note: pnode is now nullptr as it's moved into pgroup_i->pnodes
+ }
+
+ for (auto &input : pgroup->inputs)
+ {
+ // add inputs of pgroup to pgroup_i if not member of pgroup_i
+ bool found_in_pgroup_i = false;
+ for (auto &pnode : pgroup_i->pnodes)
+ {
+ if (input == pnode->node)
+ {
+ found_in_pgroup_i = true;
+ break;
+ }
+ }
+ // skip if this input is already in the inputs
+ auto fit = std::find(pgroup_i->inputs.begin(), pgroup_i->inputs.end(), input);
+ if (fit != pgroup_i->inputs.end())
+ {
+ found_in_pgroup_i = true;
+ }
+ // note: if we force found_in_pgroup_i to false, for testing there will be
+ // unnecessary inputs
+ if (not found_in_pgroup_i)
+ {
+ // node input maybe in another pgroup
+ pgroup_i->inputs.push_back(input);
+ }
+ }
+ // add outputs of pgroup to pgroup_i outputs if not exist
+ for (auto &output : pgroup->outputs)
+ {
+ auto it = std::find(pgroup_i->outputs.begin(), pgroup_i->outputs.end(), output);
+ if (it == pgroup_i->outputs.end())
+ {
+ pgroup_i->outputs.push_back(output);
+ }
+ }
+}
+
+} // namespace
+
+namespace luci
+{
+
+/**
+ * @brief This will merge pgroups with same group values in topological order
+ */
+std::unique_ptr<luci::PGroups> merge_pgroups(const luci::PGroups *s_pgroups)
+{
+ // Make a copy of pgroups to apply merge action
+ // Q) do we really need a copy?
+ auto d_pgroups = s_pgroups->make_copy();
+
+ // Merge partition graphs
+ // - This is initial implementation that works for limited networks
+ // - if A and B is same group -> if A is input of B -> ... -> merge B into A
+ auto &pgroups = d_pgroups->pgroups;
+ bool changed;
+ do
+ {
+ changed = false;
+ for (auto &pgroup_i : pgroups)
+ {
+ bool merged = false;
+ for (auto it = pgroups.begin(); it != pgroups.end(); ++it)
+ {
+ auto &pgroup = *it;
+
+ // skip if same object
+ if (pgroup->id == pgroup_i->id)
+ continue;
+ // skip if different group
+ if (pgroup->group != pgroup_i->group)
+ continue;
+ // skip if not connected
+ if (!is_input_of(pgroup_i.get(), pgroup.get()))
+ continue;
+ // skip if there are multiple inputs but inputs differ in group
+ if (!is_input_same(pgroup.get(), d_pgroups.get()))
+ continue;
+ // TODO add more condition may be needed
+
+ merge_into(pgroup.get(), pgroup_i.get());
+
+ auto eit = d_pgroups->id2pgroup.find(pgroup->id);
+ assert(eit != d_pgroups->id2pgroup.end());
+ d_pgroups->id2pgroup.erase(eit);
+
+ // remove merged pgroup from pgroups
+ pgroups.erase(it);
+
+ merged = true;
+ break;
+ }
+ if (merged)
+ {
+ changed = true;
+ break;
+ }
+ }
+ } while (changed);
+
+ return std::move(d_pgroups);
+}
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/PartitionMerge.h b/compiler/luci/partition/src/PartitionMerge.h
new file mode 100644
index 000000000..5c9fec2d2
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionMerge.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_PARTITON_MERGE_H__
+#define __LUCI_PARTITON_MERGE_H__
+
+#include "PartitionIR.h"
+
+#include <memory>
+
+namespace luci
+{
+
+std::unique_ptr<luci::PGroups> merge_pgroups(const luci::PGroups *s_pgroups);
+
+} // namespace luci
+
+#endif // __LUCI_PARTITON_MERGE_H__
diff --git a/compiler/luci/partition/src/PartitionPGroups.cpp b/compiler/luci/partition/src/PartitionPGroups.cpp
new file mode 100644
index 000000000..594ed6c40
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionPGroups.cpp
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "PartitionPGroups.h"
+#include "PartitionIR.h"
+#include "CircleOpCode.h"
+
+#include "luci/Partition.h"
+#include "luci/Log.h"
+#include "luci/LogHelper.h"
+
+#include <luci/IR/CircleNodes.h>
+#include <luci/IR/CircleNodeVisitor.h>
+
+#include <loco.h>
+
+namespace
+{
+
+class IsVirtualNode final : public luci::CircleNodeVisitor<bool>
+{
+public:
+ bool visit(const luci::CircleInput *) final { return true; }
+ bool visit(const luci::CircleOutput *) final { return true; }
+ // TODO add all virtual nodes
+
+ // default is false
+ bool visit(const luci::CircleNode *) final { return false; }
+};
+
+bool check_allocate_partition(const luci::CircleNode *node)
+{
+ IsVirtualNode query;
+ if (node->accept(&query))
+ return false;
+ /**
+ * @note About CircleConst
+ * CirleConst acts like a part of some CircleNode and managing mulitiple
+ * used(referenced) CircleConst is a bit difficult if it's used across
+ * different PGroup. So we treat this different to other types.
+ * https://github.com/Samsung/ONE/issues/6230#issuecomment-809802813
+ */
+ if (dynamic_cast<const luci::CircleConst *>(node) != nullptr)
+ return false;
+ return true;
+}
+
+} // namespace
+
+namespace luci
+{
+
+std::unique_ptr<luci::PGroups> produce_pgroups(const luci::Module *source,
+ const luci::PartitionTable &partition)
+{
+ assert(source != nullptr);
+ // TODO support multiple subgraphs
+ assert(source->size() == 1);
+
+ LOGGER(l);
+
+ auto pgroups = std::make_unique<luci::PGroups>();
+
+ pgroups->default_group = partition.default_group;
+
+ // Create a PGroup per CircleNode: each PGroup will have one CircleNode
+ auto graph = source->graph();
+ auto nodes = graph->nodes();
+ for (uint32_t idx = 0; idx < nodes->size(); ++idx)
+ {
+ auto node = loco::must_cast<luci::CircleNode *>(nodes->at(idx));
+
+ // check if node is normal node that we are interested
+ if (check_allocate_partition(node))
+ {
+ auto opcodename = luci::opcode_name(node);
+ assert(!opcodename.empty());
+
+ auto group = partition.default_group;
+ auto it = partition.byopcodes.find(opcodename);
+ if (it != partition.byopcodes.end())
+ group = it->second;
+
+ INFO(l) << "Op: " << node->name() << ": " << opcodename << ", " << node << ", " << group
+ << std::endl;
+
+ auto pgroup = std::make_unique<luci::PGroup>();
+ pgroup->group = group;
+ pgroup->id = idx + 1;
+
+ auto pnode = std::make_unique<luci::PNode>();
+ pnode->node = node;
+ pnode->group = group;
+ pnode->pgroup = pgroup.get();
+
+ pgroup->pnodes.push_back(std::move(pnode));
+
+ // Set input of PGroup
+ for (uint32_t in = 0; in < node->arity(); ++in)
+ {
+ auto input = loco::must_cast<luci::CircleNode *>(node->arg(in));
+ // this input maybe CircleInput in source graph
+ // --> not confident this is safe
+ pgroup->inputs.push_back(input);
+ }
+ // Set output of PGroup: node itself or multiple virtual outputs
+ // TODO support multiple virtual outputs
+ pgroup->outputs.push_back(node);
+
+ pgroups->node2group[node] = group;
+ pgroups->id2pgroup[pgroup->id] = pgroup.get();
+
+ pgroups->pgroups.push_back(std::move(pgroup));
+ }
+ else
+ {
+ INFO(l) << "Skip Op: " << node->name() << std::endl;
+ // record as default group
+ pgroups->node2group[node] = partition.default_group;
+ }
+ }
+
+ return std::move(pgroups);
+}
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/PartitionPGroups.h b/compiler/luci/partition/src/PartitionPGroups.h
new file mode 100644
index 000000000..998e11cbd
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionPGroups.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_PARTITON_PGROUPS_H__
+#define __LUCI_PARTITON_PGROUPS_H__
+
+#include "PartitionIR.h"
+
+#include "luci/Partition.h"
+
+#include <luci/IR/Module.h>
+
+namespace luci
+{
+
+/**
+ * @brief This will produce a PGroups from Module and PartitionTable.
+ * @note Each PGroup will hold one CircleNode and partition key value as group.
+ * Supports only single Graph in the Module for now.
+ */
+std::unique_ptr<luci::PGroups> produce_pgroups(const luci::Module *source,
+ const luci::PartitionTable &partition);
+
+} // namespace luci
+
+#endif // __LUCI_PARTITON_PGROUPS_H__
diff --git a/compiler/luci/partition/src/PartitionPGroups.test.cpp b/compiler/luci/partition/src/PartitionPGroups.test.cpp
new file mode 100644
index 000000000..960f3cde9
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionPGroups.test.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "PartitionPGroups.h"
+
+#include <luci/test/TestIOGraph.h>
+
+#include <luci/IR/Nodes/CircleSqrt.h>
+
+#include <gtest/gtest.h>
+
+namespace
+{
+
+using namespace luci::test;
+
+class SqrtGraphlet
+{
+public:
+ SqrtGraphlet() = default;
+
+public:
+ void init(loco::Graph *g, const ShapeU32 input_shape)
+ {
+ _sqrt = g->nodes()->create<luci::CircleSqrt>();
+ _sqrt->dtype(loco::DataType::S32);
+ _sqrt->name("sqrt");
+ }
+
+protected:
+ luci::CircleSqrt *_sqrt = nullptr;
+};
+
+class SqrtGraph : public TestIOGraph, public SqrtGraphlet
+{
+public:
+ SqrtGraph() = default;
+
+public:
+ void init(const ShapeU32 shape)
+ {
+ TestIOGraph::init(shape, shape);
+ SqrtGraphlet::init(g(), shape);
+
+ _sqrt->x(input());
+
+ output()->from(_sqrt);
+ }
+};
+
+} // namespace
+
+TEST(PartitionPGroupsTest, simple_produce)
+{
+ luci::Module module;
+
+ SqrtGraph g;
+ g.init({3, 3});
+ g.transfer_to(&module);
+
+ luci::PartitionTable pt;
+ pt.default_group = "A";
+
+ auto pgs = produce_pgroups(&module, pt);
+
+ ASSERT_EQ(1, pgs->pgroups.size());
+}
diff --git a/compiler/luci/partition/src/PartitionPModules.cpp b/compiler/luci/partition/src/PartitionPModules.cpp
new file mode 100644
index 000000000..36f4d47a4
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionPModules.cpp
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "PartitionPModules.h"
+#include "ConnectNode.h"
+
+#include "luci/Service/CircleNodeClone.h"
+#include "luci/Log.h"
+
+#include <loco.h>
+
+namespace
+{
+
+void add_graph_input(loco::Graph *graph, luci::CircleInput *input_node)
+{
+ assert(graph != nullptr);
+ assert(input_node != nullptr);
+
+ auto graph_input = graph->inputs()->create();
+ graph_input->name(input_node->name());
+
+ // Set GraphInputOutputIndex for graph
+ input_node->index(graph_input->index());
+
+ // Data type
+ graph_input->dtype(input_node->dtype());
+
+ // Shape of GraphInput
+ auto input_shape = std::make_unique<loco::TensorShape>();
+ input_shape->rank(input_node->rank());
+ for (uint32_t r = 0; r < input_node->rank(); ++r)
+ {
+ if (input_node->dim(r).known())
+ input_shape->dim(r).set(input_node->dim(r).value());
+ }
+ graph_input->shape(std::move(input_shape));
+}
+
+void add_graph_output(loco::Graph *graph, luci::CircleOutput *output_node)
+{
+ assert(graph != nullptr);
+ assert(output_node != nullptr);
+
+ auto graph_output = graph->outputs()->create();
+ graph_output->name(output_node->name());
+
+ // Set GraphInputOutputIndex for graph
+ output_node->index(graph_output->index());
+
+ // Data type
+ graph_output->dtype(output_node->dtype());
+
+ // Shape of GraphOutput
+ auto output_shape = std::make_unique<loco::TensorShape>();
+ output_shape->rank(output_node->rank());
+ for (uint32_t r = 0; r < output_node->rank(); ++r)
+ {
+ if (output_node->dim(r).known())
+ output_shape->dim(r).set(output_node->dim(r).value());
+ }
+ graph_output->shape(std::move(output_shape));
+}
+
+/**
+ * @brief Build loco::graph from pgroup into graph
+ */
+void build_graph(loco::Graph *graph, const luci::PGroup *pgroup)
+{
+ LOGGER(l);
+
+ luci::CloneContext clonectx;
+
+ // add input node(s)
+ for (auto *input : pgroup->inputs)
+ {
+ auto *input_clone = graph->nodes()->create<luci::CircleInput>();
+ luci::copy_common_attributes(input, input_clone);
+
+ add_graph_input(graph, input_clone);
+ clonectx.emplace(input, input_clone);
+
+ INFO(l) << "MAP: "
+ << " input(" << input << ") -> " << input_clone << "(" << input_clone->name() << ")";
+ }
+
+ // add CircleConst for inputs
+ for (auto &pnode : pgroup->pnodes)
+ {
+ auto node = pnode->node;
+ uint32_t arity = node->arity();
+ for (uint32_t a = 0; a < arity; ++a)
+ {
+ auto in_a_const = dynamic_cast<luci::CircleConst *>(node->arg(a));
+ if (in_a_const != nullptr)
+ {
+ auto it = clonectx.find(in_a_const);
+ if (it == clonectx.end())
+ {
+ auto *clone = clone_node(in_a_const, graph);
+ clonectx.emplace(in_a_const, clone);
+
+ INFO(l) << "MAP: "
+ << " const(" << in_a_const << ") -> " << clone << "(" << clone->name() << ")";
+ }
+ }
+ }
+ }
+
+ // add nodes
+ for (auto &pnode : pgroup->pnodes)
+ {
+ auto *clone = clone_node(pnode->node, graph);
+ clonectx.emplace(pnode->node, clone);
+
+ INFO(l) << "MAP: "
+ << " node(" << pnode->node << ") -> " << clone << "(" << clone->name() << ")";
+ }
+ // connect nodes
+ for (auto &pnode : pgroup->pnodes)
+ {
+ clone_connect(pnode->node, clonectx);
+ }
+
+ // add output node(s)
+ for (auto *output : pgroup->outputs)
+ {
+ auto *output_clone = graph->nodes()->create<luci::CircleOutput>();
+ luci::copy_common_attributes(output, output_clone);
+ // note: we don't add output_clone to clonectx.
+ // logically, output is not used as an input to any other nodes.
+
+ auto it = clonectx.find(output);
+ assert(it != clonectx.end());
+ output_clone->from(it->second);
+
+ add_graph_output(graph, output_clone);
+
+ INFO(l) << "MAP: "
+ << "output(" << output << ") -> " << output_clone << "(" << output_clone->name() << ")"
+ << ": from " << it->second << "(" << it->second->name() << ")";
+ }
+}
+
+std::string make_name(const luci::PGroup *pgroup)
+{
+ auto &first_pnode = *pgroup->pnodes.begin();
+ auto *first_node = first_pnode->node;
+ std::string name = first_node->graph()->name();
+ name = name + "_" + pgroup->group;
+ return name;
+}
+
+} // namespace
+
+namespace luci
+{
+
+/**
+ * @brief This will produce list of luci::Module as PartedModules from pgroups
+ */
+luci::PartedModules produce_pmodules(const luci::PGroups *pgroups)
+{
+ LOGGER(l);
+
+ luci::PartedModules pms;
+
+ for (auto &pgroup : pgroups->pgroups)
+ {
+ luci::PartedModule pm;
+ pm.module = std::make_unique<luci::Module>();
+ pm.group = pgroup->group;
+
+ auto graph = loco::make_graph();
+
+ auto graph_name = make_name(pgroup.get());
+ graph->name(graph_name);
+
+ INFO(l) << "--- Partition Graph build----------------------";
+ INFO(l) << "--- name: " << graph_name;
+ build_graph(graph.get(), pgroup.get());
+
+ pm.module->add(std::move(graph));
+ pms.pmodules.emplace_back(std::move(pm));
+ }
+
+ return pms;
+}
+
+} // namespace luci
diff --git a/compiler/luci/partition/src/PartitionPModules.h b/compiler/luci/partition/src/PartitionPModules.h
new file mode 100644
index 000000000..628ada56c
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionPModules.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_PARTITON_PMODULES_H__
+#define __LUCI_PARTITON_PMODULES_H__
+
+#include "PartitionIR.h"
+
+#include "luci/Partition.h"
+
+namespace luci
+{
+
+luci::PartedModules produce_pmodules(const luci::PGroups *pgroups);
+
+} // namespace luci
+
+#endif // __LUCI_PARTITON_PMODULES_H__
diff --git a/compiler/luci/partition/src/PartitionPModules.test.cpp b/compiler/luci/partition/src/PartitionPModules.test.cpp
new file mode 100644
index 000000000..99c39e839
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionPModules.test.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "PartitionPModules.h"
+#include "PartitionPGroups.h"
+
+#include <luci/test/TestIOGraph.h>
+
+#include <luci/IR/Nodes/CircleSqrt.h>
+
+#include <gtest/gtest.h>
+
+namespace
+{
+
+using namespace luci::test;
+
+class SqrtGraphlet
+{
+public:
+ SqrtGraphlet() = default;
+
+public:
+ void init(loco::Graph *g, const ShapeU32 input_shape)
+ {
+ _sqrt = g->nodes()->create<luci::CircleSqrt>();
+ _sqrt->dtype(loco::DataType::S32);
+ _sqrt->name("sqrt");
+ }
+
+protected:
+ luci::CircleSqrt *_sqrt = nullptr;
+};
+
+class SqrtGraph : public TestIOGraph, public SqrtGraphlet
+{
+public:
+ SqrtGraph() = default;
+
+public:
+ void init(const ShapeU32 shape)
+ {
+ TestIOGraph::init(shape, shape);
+ SqrtGraphlet::init(g(), shape);
+
+ _sqrt->x(input());
+
+ output()->from(_sqrt);
+ }
+};
+
+} // namespace
+
+TEST(PartitionPModulesTest, simple_convert)
+{
+ luci::Module module;
+
+ SqrtGraph g;
+ g.init({3, 3});
+ g.transfer_to(&module);
+
+ luci::PartitionTable pt;
+ pt.default_group = "A";
+
+ auto pgs = produce_pgroups(&module, pt);
+ auto pms = produce_pmodules(pgs.get());
+
+ ASSERT_EQ(1, pms.pmodules.size());
+}
diff --git a/compiler/luci/partition/src/PartitionPModulesDump.cpp b/compiler/luci/partition/src/PartitionPModulesDump.cpp
new file mode 100644
index 000000000..ee50bc6fb
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionPModulesDump.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "PartitionPModulesDump.h"
+
+#include "luci/LogHelper.h"
+
+#include <iostream>
+
+namespace luci
+{
+
+void dump(std::ostream &os, const PartedModule *pmodule)
+{
+ os << "--- PartedModule: " << pmodule->group << std::endl;
+ os << luci::fmt(pmodule->module->graph());
+}
+
+void dump(std::ostream &os, const PartedModules *pmodules)
+{
+ for (auto &pmodule : pmodules->pmodules)
+ {
+ dump(os, &pmodule);
+ }
+ os << std::endl;
+}
+
+} // namespace luci
+
+std::ostream &operator<<(std::ostream &os, const luci::PartedModules *pmodules)
+{
+ luci::dump(os, pmodules);
+ return os;
+}
diff --git a/compiler/luci/partition/src/PartitionPModulesDump.h b/compiler/luci/partition/src/PartitionPModulesDump.h
new file mode 100644
index 000000000..e77b235f4
--- /dev/null
+++ b/compiler/luci/partition/src/PartitionPModulesDump.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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_PARTITION_PMODULES_DUMP_H__
+#define __LUCI_PARTITION_PMODULES_DUMP_H__
+
+#include "luci/Partition.h"
+
+#include <iostream>
+
+namespace luci
+{
+
+void dump(std::ostream &os, const PartedModule *pmodule);
+void dump(std::ostream &os, const PartedModules *pmodules);
+
+} // namespace luci
+
+std::ostream &operator<<(std::ostream &os, const luci::PartedModules *pmodules);
+
+#endif // __LUCI_PARTITION_PMODULES_DUMP_H__