summaryrefslogtreecommitdiff
path: root/compiler/luci-interpreter/src/loader
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/luci-interpreter/src/loader')
-rw-r--r--compiler/luci-interpreter/src/loader/CMakeLists.txt39
-rw-r--r--compiler/luci-interpreter/src/loader/GraphLoader.cpp186
-rw-r--r--compiler/luci-interpreter/src/loader/GraphLoader.h5
-rw-r--r--compiler/luci-interpreter/src/loader/KernelBuilder.cpp612
-rw-r--r--compiler/luci-interpreter/src/loader/KernelBuilder.h65
-rw-r--r--compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp597
-rw-r--r--compiler/luci-interpreter/src/loader/KernelBuilderHelper.cpp64
-rw-r--r--compiler/luci-interpreter/src/loader/KernelBuilderHelper.h84
-rw-r--r--compiler/luci-interpreter/src/loader/ModuleLoader.cpp11
-rw-r--r--compiler/luci-interpreter/src/loader/ModuleLoader.h5
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Abs.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Add.cpp40
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/ArgMax.cpp39
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/AveragePool2D.cpp64
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/BatchMatMul.cpp70
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/BatchToSpaceND.cpp38
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Builders.h37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Cast.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Concatenation.cpp42
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Conv2D.cpp66
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/DepthToSpace.cpp39
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/DepthwiseConv2D.cpp67
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Dequantize.cpp35
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Div.cpp39
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Elu.cpp35
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Equal.cpp38
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Exp.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/ExpandDims.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Fill.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Floor.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/FloorDiv.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/FloorMod.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/FullyConnected.cpp42
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Gather.cpp42
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Gelu.cpp38
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Greater.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/GreaterEqual.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/HardSwish.cpp35
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/If.cpp47
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/InstanceNorm.cpp43
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/L2Normalize.cpp39
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/L2Pool2D.cpp44
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/LeakyRelu.cpp38
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Less.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/LessEqual.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/LocalResponseNormalization.cpp42
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Log.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/LogSoftmax.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/LogicalAnd.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/LogicalNot.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/LogicalOr.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Logistic.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/MaxPool2D.cpp44
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Maximum.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Mean.cpp61
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Minimum.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/MirrorPad.cpp40
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Mul.cpp40
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Neg.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/NotEqual.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/OneHot.cpp42
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/PRelu.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Pack.cpp44
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Pad.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/PadV2.cpp38
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Pow.cpp38
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Quantize.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/ReduceMax.cpp55
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/ReduceProd.cpp55
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Relu.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Relu6.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Reshape.cpp38
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/ResizeBilinear.cpp41
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/ResizeNearestNeighbor.cpp46
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/ReverseV2.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Rsqrt.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/SVDF.cpp92
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Select.cpp38
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Shape.cpp39
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Slice.cpp39
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Softmax.cpp39
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/SpaceToBatchND.cpp39
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/SpaceToDepth.cpp39
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Split.cpp40
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/SplitV.cpp41
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Sqrt.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Square.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/SquaredDifference.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Squeeze.cpp39
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/StridedSlice.cpp47
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Sub.cpp40
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Sum.cpp54
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Tanh.cpp36
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Transpose.cpp37
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/TransposeConv.cpp62
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/UnidirectionalSequenceLSTM.cpp106
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/Unpack.cpp42
-rw-r--r--compiler/luci-interpreter/src/loader/nodes/While.cpp47
98 files changed, 4758 insertions, 637 deletions
diff --git a/compiler/luci-interpreter/src/loader/CMakeLists.txt b/compiler/luci-interpreter/src/loader/CMakeLists.txt
index d99485d06..292771592 100644
--- a/compiler/luci-interpreter/src/loader/CMakeLists.txt
+++ b/compiler/luci-interpreter/src/loader/CMakeLists.txt
@@ -1,22 +1,39 @@
-nnas_find_package(GTest REQUIRED)
-
set(SOURCES
GraphLoader.h
GraphLoader.cpp
+ KernelBuilderHelper.h
+ KernelBuilderHelper.cpp
KernelBuilder.h
KernelBuilder.cpp
ModuleLoader.h
ModuleLoader.cpp
- RuntimeToIR.h)
+ RuntimeToIR.h
+ nodes/Builders.h)
+
+# include kernel specific builders
+macro(REGISTER_KERNEL NODE)
+ list(APPEND SOURCES "nodes/${NODE}.cpp")
+endmacro(REGISTER_KERNEL)
+include(${KERNEL_REGISTER_FILE})
+
+add_library(${LUCI_INTERPRETER_LOADER} STATIC ${SOURCES})
+if (NOT NNCC_LIBRARY_NO_PIC)
+ set_target_properties(${LUCI_INTERPRETER_LOADER} PROPERTIES POSITION_INDEPENDENT_CODE ON)
+endif(NOT NNCC_LIBRARY_NO_PIC)
+target_include_directories(${LUCI_INTERPRETER_LOADER} PUBLIC "${LUCI_INTERPRETER_PAL_DIR}")
+target_include_directories(${LUCI_INTERPRETER_LOADER} PUBLIC "${LUCI_INTERPRETER_SOURCE_DIR}")
-add_library(luci_interpreter_loader STATIC ${SOURCES})
-set_target_properties(luci_interpreter_loader PROPERTIES POSITION_INDEPENDENT_CODE ON)
-target_include_directories(luci_interpreter_loader PUBLIC "${LUCI_INTERPRETER_SOURCE_DIR}")
-target_link_libraries(luci_interpreter_loader
- PUBLIC luci_lang luci_interpreter_core
- PRIVATE luci_interpreter_kernels nncc_common)
+target_link_libraries(${LUCI_INTERPRETER_LOADER}
+ PUBLIC luci_lang ${LUCI_INTERPRETER_CORE}
+ PRIVATE ${LUCI_INTERPRETER_KERNELS} nncc_common luci_plan)
+
+if(NOT ENABLE_TEST)
+ return()
+endif(NOT ENABLE_TEST)
+
+nnas_find_package(GTest REQUIRED)
set(TEST_SOURCES KernelBuilder.test.cpp)
-GTest_AddTest(luci_interpreter_loader_test ${TEST_SOURCES})
-target_link_libraries(luci_interpreter_loader_test luci_interpreter_loader)
+GTest_AddTest(${LUCI_INTERPRETER_LOADER}_test ${TEST_SOURCES})
+target_link_libraries(${LUCI_INTERPRETER_LOADER}_test ${LUCI_INTERPRETER_LOADER})
diff --git a/compiler/luci-interpreter/src/loader/GraphLoader.cpp b/compiler/luci-interpreter/src/loader/GraphLoader.cpp
index 95c654769..ba99a579b 100644
--- a/compiler/luci-interpreter/src/loader/GraphLoader.cpp
+++ b/compiler/luci-interpreter/src/loader/GraphLoader.cpp
@@ -18,6 +18,7 @@
#include "loader/KernelBuilder.h"
+#include <luci/Plan/CircleNodeExecutionPlan.h>
#include <loco/IR/Algorithm.h>
namespace luci_interpreter
@@ -57,13 +58,41 @@ const void *getNodeData(const luci::CircleConst *node, size_t *data_size)
return getNodeDataImpl<DataType::U8>(node, data_size);
case DataType::FLOAT32:
return getNodeDataImpl<DataType::FLOAT32>(node, data_size);
+ case DataType::S8:
+ return getNodeDataImpl<DataType::S8>(node, data_size);
+ case DataType::S16:
+ return getNodeDataImpl<DataType::S16>(node, data_size);
case DataType::S32:
return getNodeDataImpl<DataType::S32>(node, data_size);
+ case DataType::S64:
+ return getNodeDataImpl<DataType::S64>(node, data_size);
+ case DataType::BOOL:
+ return getNodeDataImpl<DataType::BOOL>(node, data_size);
default:
throw std::runtime_error("Unsupported type.");
}
}
+const void *getNodeData(const luci::CircleCustom *node, size_t *data_size)
+{
+ if (node->custom_code() != "CircleReferencingConst")
+ return nullptr;
+
+ // helper struct which describes data loaded to custom_options of CircleReferencingConst node
+ // TODO move this struct to header
+ struct ConstDataReference
+ {
+ const uint8_t *data = nullptr;
+ uint32_t size = 0;
+ };
+
+ const auto &custom_options = node->custom_options();
+ const auto &const_data_ref = *reinterpret_cast<const ConstDataReference *>(custom_options.data());
+
+ *data_size = const_data_ref.size;
+ return const_data_ref.data;
+}
+
bool isExecutableNode(const luci::CircleNode *node)
{
switch (node->opcode())
@@ -74,10 +103,30 @@ bool isExecutableNode(const luci::CircleNode *node)
case luci::CircleOpcode::CIRCLEOUTPUT:
case luci::CircleOpcode::CIRCLEOUTPUTEXCLUDE:
// The following nodes denote outputs of multiple-output nodes.
+ case luci::CircleOpcode::CIRCLEBIDIRECTIONAL_SEQUENCE_LSTM_OUT:
+ case luci::CircleOpcode::CIRCLECUSTOMOUT:
case luci::CircleOpcode::CIRCLEIFOUT:
+ case luci::CircleOpcode::CIRCLENONMAXSUPPRESSIONV4OUT:
+ case luci::CircleOpcode::CIRCLENONMAXSUPPRESSIONV5OUT:
case luci::CircleOpcode::CIRCLESPLITOUT:
+ case luci::CircleOpcode::CIRCLESPLITVOUT:
+ case luci::CircleOpcode::CIRCLETOPKV2OUT:
+ case luci::CircleOpcode::CIRCLEUNIQUEOUT:
case luci::CircleOpcode::CIRCLEUNPACKOUT:
+ case luci::CircleOpcode::CIRCLEVARIABLE:
+ case luci::CircleOpcode::CIRCLEWHILEOUT:
return false;
+ // Custom nodes may be executable and non-executable
+ case luci::CircleOpcode::CUSTOM:
+ {
+ auto const custom_node = loco::must_cast<const luci::CircleCustom *>(node);
+
+ // TODO handle more non-executable Custom ops here
+ if (custom_node->custom_code() == "CircleReferencingConst")
+ return false;
+
+ return true;
+ }
default:
return true;
}
@@ -91,23 +140,43 @@ bool isTensorProducingNode(const luci::CircleNode *node)
case luci::CircleOpcode::CIRCLEOUTPUT:
// The following nodes are multiple-output nodes. They do not produce tensors, the tensors
// are produced by the corresponding *Out nodes instead.
+ case luci::CircleOpcode::BIDIRECTIONAL_SEQUENCE_LSTM:
+ case luci::CircleOpcode::CUSTOM:
case luci::CircleOpcode::IF:
+ case luci::CircleOpcode::NON_MAX_SUPPRESSION_V4:
+ case luci::CircleOpcode::NON_MAX_SUPPRESSION_V5:
case luci::CircleOpcode::SPLIT:
+ case luci::CircleOpcode::SPLIT_V:
+ case luci::CircleOpcode::TOPK_V2:
+ case luci::CircleOpcode::UNIQUE:
case luci::CircleOpcode::UNPACK:
+ case luci::CircleOpcode::WHILE:
return false;
default:
return true;
}
}
+bool isSupportedCustomNode(const luci::CircleNode *node)
+{
+ const auto custom_node = loco::must_cast<const luci::CircleCustom *>(node);
+
+ // TODO handle more Custom ops here
+ if (custom_node->custom_code() == "CircleReferencingConst")
+ return true;
+
+ return false;
+}
+
} // namespace
GraphLoader::GraphLoader(
- const loco::Graph *graph, RuntimeGraph *runtime_graph, RuntimeToIR &runtime_to_ir,
- const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph,
- std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor)
- : _graph(graph), _runtime_graph(runtime_graph), _runtime_to_ir(runtime_to_ir),
- _graph_to_runtime_graph(graph_to_runtime_graph), _node_to_tensor(node_to_tensor)
+ const loco::Graph *graph, RuntimeGraph *runtime_graph, RuntimeToIR &runtime_to_ir,
+ const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph,
+ std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor, IMemoryManager *memory_manager)
+ : _graph(graph), _runtime_graph(runtime_graph), _runtime_to_ir(runtime_to_ir),
+ _graph_to_runtime_graph(graph_to_runtime_graph), _node_to_tensor(node_to_tensor),
+ _memory_manager(memory_manager)
{
}
@@ -117,24 +186,36 @@ void GraphLoader::loadTensors()
{
const auto *node = loco::must_cast<const luci::CircleNode *>(_graph->nodes()->at(i));
+ if (node->opcode() == luci::CircleOpcode::CUSTOM && !isSupportedCustomNode(node))
+ {
+ const auto *cnode = loco::must_cast<const luci::CircleCustom *>(node);
+ throw std::runtime_error("Unsupported Custom operator. " + cnode->custom_code() + " in " +
+ node->name());
+ }
+
if (!isTensorProducingNode(node))
continue;
- // Only Input and Const nodes have shapes. Shapes of intermediate tensors will be inferred.
+ // Only Input, Const, Custom and Variable nodes have shapes. Shapes of intermediate tensors will
+ // be inferred.
Shape shape{};
- if (const auto *input_node = dynamic_cast<const luci::CircleInput *>(node))
+ switch (node->opcode())
{
- shape = getNodeShape(input_node);
- }
- else if (const auto *const_node = dynamic_cast<const luci::CircleConst *>(node))
- {
- shape = getNodeShape(const_node);
+ case luci::CircleOpcode::CIRCLECONST:
+ case luci::CircleOpcode::CIRCLECUSTOMOUT:
+ case luci::CircleOpcode::CIRCLEINPUT:
+ case luci::CircleOpcode::CIRCLEVARIABLE:
+ shape = getNodeShape(node);
+ break;
+ default:
+ break;
}
AffineQuantization quantization;
if (node->quantparam() != nullptr)
{
const luci::CircleQuantParam *params = node->quantparam();
+ assert(params->scale.size() == params->zerop.size());
quantization.scale.assign(params->scale.cbegin(), params->scale.cend());
quantization.zero_point.assign(params->zerop.cbegin(), params->zerop.cend());
quantization.quantized_dimension = params->quantized_dimension;
@@ -143,12 +224,40 @@ void GraphLoader::loadTensors()
auto tensor = std::make_unique<Tensor>(node->dtype(), std::move(shape), std::move(quantization),
node->name());
+ // If node has execution plan then read memory offsets for nodes
+ // from the beginning of shared memory buffer. Used in Static Memory Manager.
+ if (luci::has_execution_plan(node))
+ {
+ auto execution_plan = luci::get_execution_plan(node);
+ assert(!execution_plan.offsets().empty());
+ tensor->set_offset(execution_plan.offsets().front());
+ }
+
if (const auto *const_node = dynamic_cast<const luci::CircleConst *>(node))
{
size_t data_size{};
const void *const_data = getNodeData(const_node, &data_size);
if (const_data != nullptr)
+ {
+ _memory_manager->allocate_memory(*tensor);
tensor->writeData(const_data, data_size);
+ }
+ }
+ else if (const auto *custom_out_node = dynamic_cast<const luci::CircleCustomOut *>(node))
+ {
+ const auto *custom_node =
+ loco::must_cast<const luci::CircleCustom *>(custom_out_node->input());
+
+ if (custom_node->custom_code() == "CircleReferencingConst")
+ {
+ size_t data_size{};
+ const void *const_data = getNodeData(custom_node, &data_size);
+ if (const_data != nullptr)
+ {
+ _memory_manager->allocate_memory(*tensor);
+ tensor->writeData(const_data, data_size);
+ }
+ }
}
_node_to_tensor.emplace(node, tensor.get());
@@ -165,6 +274,7 @@ void GraphLoader::initInputOutputTensors() const
for (size_t i = 0; i < input_nodes.size(); ++i)
{
input_tensors[i] = _node_to_tensor.at(input_nodes[i]);
+ _memory_manager->allocate_memory(*input_tensors[i]);
}
_runtime_graph->setInputTensors(input_tensors);
@@ -183,16 +293,54 @@ void GraphLoader::loadOperators()
KernelBuilder kernel_builder(_graph_to_runtime_graph, _node_to_tensor);
// Create kernels for executable nodes. This has to be done in execution order.
- for (const loco::Node *loco_node :
- loco::postorder_traversal(loco::output_nodes(const_cast<loco::Graph *>(_graph))))
+ auto graph = const_cast<loco::Graph *>(_graph);
+
+ auto const graph_nodes = loco::all_nodes(graph);
+
+ // Checking for execution plan in node annotations.
+ bool has_execution_annotation = true;
+ auto const checking_exec_plan = [&has_execution_annotation](auto const node) {
+ const auto *circle_node = loco::must_cast<const luci::CircleNode *>(node);
+ if (!luci::has_execution_plan(circle_node))
+ has_execution_annotation = false;
+ };
+ std::for_each(begin(graph_nodes), end(graph_nodes), checking_exec_plan);
+
+ if (has_execution_annotation)
{
- const auto *node = loco::must_cast<const luci::CircleNode *>(loco_node);
+ // Build ordered_nodes vector that stores the order of execution of graph nodes.
+ std::vector<const luci::CircleNode *> ordered_nodes(graph_nodes.size());
+
+ auto const filler = [&ordered_nodes](auto const node) {
+ const auto *circle_node = loco::must_cast<const luci::CircleNode *>(node);
+ auto const position = luci::get_execution_plan(circle_node).order_in_plan();
+ ordered_nodes.at(position) = circle_node;
+ };
+ std::for_each(begin(graph_nodes), end(graph_nodes), filler);
- if (isExecutableNode(node))
+ for (auto node : ordered_nodes)
+ {
+ if (isExecutableNode(node))
+ {
+ std::unique_ptr<Kernel> kernel = kernel_builder.build(node);
+ _runtime_to_ir.kernel_to_node.emplace(kernel.get(), node);
+ _runtime_graph->addKernel(std::move(kernel));
+ }
+ }
+ }
+ else
+ {
+ // If it is impossible to build the execution order plan,
+ // then we use the default postorder_traversal approach.
+ for (const loco::Node *loco_node : loco::postorder_traversal(loco::output_nodes(graph)))
{
- std::unique_ptr<Kernel> kernel = node->accept(&kernel_builder);
- _runtime_to_ir.kernel_to_node.emplace(kernel.get(), node);
- _runtime_graph->addKernel(std::move(kernel));
+ const auto *node = loco::must_cast<const luci::CircleNode *>(loco_node);
+ if (isExecutableNode(node))
+ {
+ std::unique_ptr<Kernel> kernel = kernel_builder.build(node);
+ _runtime_to_ir.kernel_to_node.emplace(kernel.get(), node);
+ _runtime_graph->addKernel(std::move(kernel));
+ }
}
}
}
diff --git a/compiler/luci-interpreter/src/loader/GraphLoader.h b/compiler/luci-interpreter/src/loader/GraphLoader.h
index 89c5bcad7..fe066ecf8 100644
--- a/compiler/luci-interpreter/src/loader/GraphLoader.h
+++ b/compiler/luci-interpreter/src/loader/GraphLoader.h
@@ -19,6 +19,7 @@
#include "core/RuntimeGraph.h"
#include "loader/RuntimeToIR.h"
+#include "luci_interpreter/MemoryManager.h"
#include <loco/IR/Graph.h>
@@ -32,7 +33,8 @@ class GraphLoader
public:
GraphLoader(const loco::Graph *graph, RuntimeGraph *runtime_graph, RuntimeToIR &runtime_to_ir,
const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph,
- std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor);
+ std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor,
+ IMemoryManager *memory_manager);
void loadTensors();
void initInputOutputTensors() const;
@@ -42,6 +44,7 @@ private:
const loco::Graph *_graph;
RuntimeGraph *_runtime_graph;
RuntimeToIR &_runtime_to_ir;
+ IMemoryManager *_memory_manager;
const std::unordered_map<const loco::Graph *, RuntimeGraph *> &_graph_to_runtime_graph;
std::unordered_map<const loco::Node *, Tensor *> &_node_to_tensor;
diff --git a/compiler/luci-interpreter/src/loader/KernelBuilder.cpp b/compiler/luci-interpreter/src/loader/KernelBuilder.cpp
index 126a1cb5b..c1e2c630a 100644
--- a/compiler/luci-interpreter/src/loader/KernelBuilder.cpp
+++ b/compiler/luci-interpreter/src/loader/KernelBuilder.cpp
@@ -15,586 +15,118 @@
*/
#include "loader/KernelBuilder.h"
+#include "loader/nodes/Builders.h"
-#include "kernels/Add.h"
-#include "kernels/ArgMax.h"
-#include "kernels/AveragePool2D.h"
-#include "kernels/Concatenation.h"
-#include "kernels/Conv2D.h"
-#include "kernels/DepthToSpace.h"
-#include "kernels/DepthwiseConv2D.h"
-#include "kernels/Elu.h"
-#include "kernels/FullyConnected.h"
-#include "kernels/If.h"
-#include "kernels/L2Normalize.h"
-#include "kernels/L2Pool2D.h"
-#include "kernels/LeakyRelu.h"
-#include "kernels/LocalResponseNormalization.h"
-#include "kernels/Logistic.h"
-#include "kernels/MaxPool2D.h"
-#include "kernels/Mean.h"
-#include "kernels/Mul.h"
-#include "kernels/Pad.h"
-#include "kernels/Reshape.h"
-#include "kernels/Reverse.h"
-#include "kernels/Rsqrt.h"
-#include "kernels/Slice.h"
-#include "kernels/Softmax.h"
-#include "kernels/SpaceToDepth.h"
-#include "kernels/Split.h"
-#include "kernels/StridedSlice.h"
-#include "kernels/Sqrt.h"
-#include "kernels/Squeeze.h"
-#include "kernels/Tanh.h"
-#include "kernels/Unpack.h"
-#include "kernels/Transpose.h"
-#include "kernels/TransposeConv.h"
+#include <luci/IR/CircleOpcode.h>
+#include <luci/IR/CircleNodeDecl.h>
#include <stdexcept>
-namespace luci_interpreter
-{
-
-template <typename CircleNodeOut>
-static std::vector<const loco::Node *> collectOutputNodes(const luci::CircleNode *node)
+namespace
{
- std::vector<const CircleNodeOut *> output_nodes;
- for (const loco::Node *loco_node : loco::succs(node))
- {
- output_nodes.push_back(loco::must_cast<const CircleNodeOut *>(loco_node));
- }
- std::sort(output_nodes.begin(), output_nodes.end(),
- [](const CircleNodeOut *node1, const CircleNodeOut *node2) {
- return node1->index() < node2->index();
- });
- return {output_nodes.cbegin(), output_nodes.cend()};
-}
-const Tensor *KernelBuilder::getInputTensor(const loco::Node *node) const
+// TODO Extract this helper function
+const std::string toString(luci::CircleOpcode opcode)
{
- const Tensor *tensor = _node_to_tensor.at(node);
- assert(tensor != nullptr);
- return tensor;
-}
+ static const char *names[] = {
+#define CIRCLE_NODE(OPCODE, CIRCLE_CLASS) #CIRCLE_CLASS,
+#define CIRCLE_VNODE(OPCODE, CIRCLE_CLASS) #CIRCLE_CLASS,
+#include <luci/IR/CircleNodes.lst>
+#undef CIRCLE_NODE
+#undef CIRCLE_VNODE
+ };
-const Tensor *KernelBuilder::getOptionalInputTensor(const loco::Node *node) const
-{
- if (dynamic_cast<const luci::CircleOutputExclude *>(node))
- {
- return nullptr;
- }
- return getInputTensor(node);
-}
+ auto const node_name = names[static_cast<int>(opcode)];
-Tensor *KernelBuilder::getOutputTensor(const loco::Node *node) const
-{
- Tensor *tensor = _node_to_tensor.at(node);
- assert(tensor != nullptr);
- return tensor;
-}
+ assert(std::string(node_name).substr(0, 6) == "Circle"); // FIX_ME_UNLESS
-std::vector<Tensor *>
-KernelBuilder::getOutputTensors(const std::vector<const loco::Node *> &nodes) const
-{
- std::vector<Tensor *> tensors;
- tensors.reserve(nodes.size());
- for (const loco::Node *node : nodes)
- tensors.push_back(getOutputTensor(node));
- return tensors;
+ // Return substring of class name ("Circle" is sliced out)
+ // Ex: Return "Conv2D" for "CircleConv2D" node
+ return std::string(node_name).substr(6);
}
-RuntimeGraph *KernelBuilder::getRuntimeGraph(const loco::Graph *graph) const
-{
- RuntimeGraph *runtime_graph = _graph_to_runtime_graph.at(graph);
- assert(runtime_graph != nullptr);
- return runtime_graph;
-}
+} // namespace
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleAdd *node)
+namespace luci_interpreter
{
- assert(node->arity() == 2);
-
- const Tensor *input1 = getInputTensor(node->x());
- const Tensor *input2 = getInputTensor(node->y());
- Tensor *output = getOutputTensor(node);
- AddParams params{};
- params.activation = node->fusedActivationFunction();
+#define CIRCLE_NODE(OPCODE, CLASS) CLASS,
+#define CIRCLE_VNODE(OPCODE, CLASS) CLASS,
- return std::make_unique<kernels::Add>(input1, input2, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleArgMax *node)
+// This enum is auxiliary.
+// It is duplicate of luci::CircleOpcode but initialized with CLASS instead of OPCODE,
+// because list of target operators is in format of CLASS names
+enum class BuilderId
{
- assert(node->arity() == 2);
- const Tensor *input = getInputTensor(node->input());
- const Tensor *axis = getInputTensor(node->dimension());
- Tensor *output = getOutputTensor(node);
+#include <luci/IR/CircleNodes.lst>
+ Size // casts to count of values in BuilderId enum
+};
- ArgMaxParams params{};
- params.output_type = node->output_type();
+#undef CIRCLE_VNODE
+#undef CIRCLE_NODE
- return std::make_unique<kernels::ArgMax>(input, axis, output, params);
-}
+/**
+ * @brief Registry of kernel builders
+ *
+ * This class contains mapping from Opcodes to kernel builder functions
+ */
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleAveragePool2D *node)
+class KernelBuilderRegistry
{
- assert(node->arity() == 1);
+public:
+ using KernelBuilderFunc = std::unique_ptr<Kernel>(const luci::CircleNode *,
+ KernelBuilderHelper &);
- const Tensor *input = getInputTensor(node->value());
- Tensor *output = getOutputTensor(node);
+ KernelBuilderRegistry() : _operator_builders(size_t(BuilderId::Size), nullptr)
+ {
+#define REGISTER_KERNEL(name) \
+ register_kernel_builder(BuilderId::Circle##name, build_kernel_Circle##name);
- Pool2DParams params{};
- params.padding = node->padding();
- params.filter_height = node->filter()->h();
- params.filter_width = node->filter()->w();
- params.stride_height = node->stride()->h();
- params.stride_width = node->stride()->w();
- params.activation = node->fusedActivationFunction();
+#include "KernelsToBuild.lst"
- return std::make_unique<kernels::AveragePool2D>(input, output, params);
-}
+#undef REGISTER_KERNEL
+ }
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleConcatenation *node)
-{
- std::vector<const Tensor *> inputs(node->numValues());
- for (uint32_t i = 0; i < node->numValues(); ++i)
+ KernelBuilderFunc *get_kernel_builder_func(luci::CircleOpcode opcode) const
{
- inputs[i] = getInputTensor(node->values(i));
+ return _operator_builders.at(size_t(opcode));
}
- Tensor *output = getOutputTensor(node);
-
- ConcatenationParams params{};
- params.axis = node->axis();
-
- return std::make_unique<kernels::Concatenation>(std::move(inputs), output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleConst *)
-{
- throw std::runtime_error("Const node cannot be executed.");
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleConv2D *node)
-{
- assert(node->arity() == 3);
-
- const Tensor *input = getInputTensor(node->input());
- const Tensor *filter = getInputTensor(node->filter());
- const Tensor *bias = getInputTensor(node->bias());
- Tensor *output = getOutputTensor(node);
-
- Conv2DParams params{};
- params.padding = node->padding();
- params.stride_height = node->stride()->h();
- params.stride_width = node->stride()->w();
- params.dilation_height_factor = node->dilation()->h();
- params.dilation_width_factor = node->dilation()->w();
- params.activation = node->fusedActivationFunction();
-
- return std::make_unique<kernels::Conv2D>(input, filter, bias, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleDepthToSpace *node)
-{
- assert(node->arity() == 1);
-
- const Tensor *input = getInputTensor(node->input());
- Tensor *output = getOutputTensor(node);
-
- DepthToSpaceParams params{};
- params.block_size = node->block_size();
-
- return std::make_unique<kernels::DepthToSpace>(input, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleDepthwiseConv2D *node)
-{
- assert(node->arity() == 3);
-
- const Tensor *input = getInputTensor(node->input());
- const Tensor *filter = getInputTensor(node->filter());
- const Tensor *bias = getInputTensor(node->bias());
- Tensor *output = getOutputTensor(node);
- DepthwiseConv2DParams params{};
- params.padding = node->padding();
- params.depth_multiplier = node->depthMultiplier();
- params.stride_height = node->stride()->h();
- params.stride_width = node->stride()->w();
- params.dilation_height_factor = node->dilation()->h();
- params.dilation_width_factor = node->dilation()->w();
- params.activation = node->fusedActivationFunction();
+private:
+ std::vector<KernelBuilderFunc *> _operator_builders;
- return std::make_unique<kernels::DepthwiseConv2D>(input, filter, bias, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleElu *node)
-{
- assert(node->arity() == 1);
-
- const Tensor *input = getInputTensor(node->features());
- Tensor *output = getOutputTensor(node);
-
- return std::make_unique<kernels::Elu>(input, output);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleFullyConnected *node)
-{
- assert(node->arity() == 3);
-
- const Tensor *input = getInputTensor(node->input());
- const Tensor *weights = getInputTensor(node->weights());
- const Tensor *bias = getOptionalInputTensor(node->bias());
- Tensor *output = getOutputTensor(node);
-
- FullyConnectedParams params{};
- params.activation = node->fusedActivationFunction();
-
- return std::make_unique<kernels::FullyConnected>(input, weights, bias, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleIf *node)
-{
- auto output_nodes = collectOutputNodes<luci::CircleIfOut>(node);
- assert(node->arity() == 1 + node->input_count());
- assert(output_nodes.size() == static_cast<size_t>(node->output_count()));
-
- const Tensor *cond = getInputTensor(node->cond());
- std::vector<const Tensor *> inputs(node->input_count());
- for (uint32_t i = 0; i < node->input_count(); ++i)
+ void register_kernel_builder(BuilderId id, KernelBuilderFunc *func)
{
- inputs[i] = getInputTensor(node->input(i));
+ // Using BuilderId is a duplicate of luci::CirclreOpcode,
+ // size_t(id) is equal to size_t(corresponding operation opcode).
+ assert(size_t(id) < _operator_builders.size());
+ _operator_builders[size_t(id)] = func;
}
- std::vector<Tensor *> outputs = getOutputTensors(output_nodes);
-
- RuntimeGraph *then_graph = getRuntimeGraph(node->then_graph());
- RuntimeGraph *else_graph = getRuntimeGraph(node->else_graph());
-
- return std::make_unique<kernels::If>(cond, std::move(inputs), std::move(outputs), then_graph,
- else_graph);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleInput *)
-{
- throw std::runtime_error("Input node cannot be executed.");
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleL2Normalize *node)
-{
- assert(node->arity() == 1);
-
- const Tensor *input = getInputTensor(node->x());
- Tensor *output = getOutputTensor(node);
+};
- L2NormParams params{};
- params.activation = node->fusedActivationFunction();
-
- return std::make_unique<kernels::L2Normalize>(input, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleL2Pool2D *node)
-{
- assert(node->arity() == 1);
-
- const Tensor *input = getInputTensor(node->value());
- Tensor *output = getOutputTensor(node);
-
- Pool2DParams params{};
- params.padding = node->padding();
- params.filter_height = node->filter()->h();
- params.filter_width = node->filter()->w();
- params.stride_height = node->stride()->h();
- params.stride_width = node->stride()->w();
- params.activation = node->fusedActivationFunction();
-
- return std::make_unique<kernels::L2Pool2D>(input, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLeakyRelu *node)
-{
- assert(node->arity() == 1);
- const Tensor *input = getInputTensor(node->features());
- Tensor *output = getOutputTensor(node);
-
- LeakyReluParams params{};
- params.alpha = node->alpha();
-
- return std::make_unique<kernels::LeakyRelu>(input, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLocalResponseNormalization *node)
-{
- assert(node->arity() == 1);
- const Tensor *input = getInputTensor(node->input());
- Tensor *output = getOutputTensor(node);
-
- LocalResponseNormalizationParams params{};
- params.radius = node->radius();
- params.bias = node->bias();
- params.alpha = node->alpha();
- params.beta = node->beta();
-
- return std::make_unique<kernels::LocalResponseNormalization>(input, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleLogistic *node)
+KernelBuilder::KernelBuilder(
+ const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph,
+ const std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor)
+ : KernelBuilderHelper(graph_to_runtime_graph, node_to_tensor)
{
- assert(node->arity() == 1);
-
- const Tensor *input = getInputTensor(node->x());
- Tensor *output = getOutputTensor(node);
-
- return std::make_unique<kernels::Logistic>(input, output);
+ _builder_registry = std::make_unique<KernelBuilderRegistry>();
}
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMaxPool2D *node)
+KernelBuilder::~KernelBuilder()
{
- assert(node->arity() == 1);
-
- const Tensor *input = getInputTensor(node->value());
- Tensor *output = getOutputTensor(node);
-
- Pool2DParams params{};
- params.padding = node->padding();
- params.filter_height = node->filter()->h();
- params.filter_width = node->filter()->w();
- params.stride_height = node->stride()->h();
- params.stride_width = node->stride()->w();
- params.activation = node->fusedActivationFunction();
-
- return std::make_unique<kernels::MaxPool2D>(input, output, params);
+ // Need to define in this CPP to hide KernelBuilderRegistry internals.
+ // This destructor deletes _builder_registry
}
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMean *node)
+std::unique_ptr<Kernel> KernelBuilder::build(const luci::CircleNode *node)
{
- assert(node->arity() == 2);
-
- const Tensor *input = getInputTensor(node->input());
- const Tensor *axes = getInputTensor(node->reduction_indices());
- Tensor *output = getOutputTensor(node);
-
- ReducerParams params{};
- params.keep_dims = node->keep_dims();
-
- return std::make_unique<kernels::Mean>(input, axes, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleMul *node)
-{
- assert(node->arity() == 2);
-
- const Tensor *input1 = getInputTensor(node->x());
- const Tensor *input2 = getInputTensor(node->y());
- Tensor *output = getOutputTensor(node);
-
- MulParams params{};
- params.activation = node->fusedActivationFunction();
-
- return std::make_unique<kernels::Mul>(input1, input2, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleOutput *)
-{
- throw std::runtime_error("Output node cannot be executed.");
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CirclePad *node)
-{
- assert(node->arity() == 2);
-
- const Tensor *input = getInputTensor(node->input());
- const Tensor *paddings = getInputTensor(node->paddings());
- Tensor *output = getOutputTensor(node);
-
- return std::make_unique<kernels::Pad>(input, paddings, output);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleReshape *node)
-{
- assert(node->arity() == 2);
-
- const Tensor *input = getInputTensor(node->tensor());
- const Tensor *shape = getInputTensor(node->shape());
- Tensor *output = getOutputTensor(node);
-
- // NOTE 'newShape' attribute is ignored.
- return std::make_unique<kernels::Reshape>(input, shape, output);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleReverseV2 *node)
-{
- assert(node->arity() == 2);
-
- const Tensor *input = getInputTensor(node->tensor());
- const Tensor *axes = getInputTensor(node->axis());
- Tensor *output = getOutputTensor(node);
-
- return std::make_unique<kernels::Reverse>(input, axes, output);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleRsqrt *node)
-{
- assert(node->arity() == 1);
-
- const Tensor *input = getInputTensor(node->x());
- Tensor *output = getOutputTensor(node);
-
- return std::make_unique<kernels::Rsqrt>(input, output);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSlice *node)
-{
- assert(node->arity() == 3);
-
- const Tensor *input = getInputTensor(node->input());
- const Tensor *begin = getInputTensor(node->begin());
- const Tensor *size = getInputTensor(node->size());
-
- Tensor *output = getOutputTensor(node);
-
- return std::make_unique<kernels::Slice>(input, begin, size, output);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSoftmax *node)
-{
- assert(node->arity() == 1);
-
- const Tensor *input = getInputTensor(node->logits());
- Tensor *output = getOutputTensor(node);
-
- SoftmaxParams params{};
- params.beta = node->beta();
-
- return std::make_unique<kernels::Softmax>(input, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSpaceToDepth *node)
-{
- assert(node->arity() == 1);
- const Tensor *input = getInputTensor(node->input());
-
- Tensor *output = getOutputTensor(node);
-
- SpaceToDepthParams params{};
- params.block_size = node->block_size();
-
- return std::make_unique<kernels::SpaceToDepth>(input, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSplit *node)
-{
- auto output_nodes = collectOutputNodes<luci::CircleSplitOut>(node);
- assert(node->arity() == 2);
- assert(output_nodes.size() == static_cast<size_t>(node->num_split()));
-
- const Tensor *axis = getInputTensor(node->split_dim());
- const Tensor *input = getInputTensor(node->input());
- std::vector<Tensor *> outputs = getOutputTensors(output_nodes);
-
- // NOTE 'num_splits' attribute is ignored.
- return std::make_unique<kernels::Split>(axis, input, std::move(outputs));
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSqrt *node)
-{
- assert(node->arity() == 1);
-
- const Tensor *input = getInputTensor(node->x());
- Tensor *output = getOutputTensor(node);
-
- return std::make_unique<kernels::Sqrt>(input, output);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleSqueeze *node)
-{
- assert(node->arity() == 1);
-
- const Tensor *input = getInputTensor(node->input());
- Tensor *output = getOutputTensor(node);
-
- SqueezeParams params{};
- params.squeeze_dims = node->squeeze_dims();
-
- return std::make_unique<kernels::Squeeze>(input, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleStridedSlice *node)
-{
- assert(node->arity() == 4);
-
- const Tensor *input = getInputTensor(node->input());
- const Tensor *begin = getInputTensor(node->begin());
- const Tensor *end = getInputTensor(node->end());
- const Tensor *strides = getInputTensor(node->strides());
-
- Tensor *output = getOutputTensor(node);
-
- StridedSliceParams params{};
- params.begin_mask = node->begin_mask();
- params.ellipsis_mask = node->ellipsis_mask();
- params.end_mask = node->end_mask();
- params.new_axis_mask = node->new_axis_mask();
- params.shrink_axis_mask = node->shrink_axis_mask();
-
- return std::make_unique<kernels::StridedSlice>(input, begin, end, strides, output, params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleTanh *node)
-{
- assert(node->arity() == 1);
-
- const Tensor *input = getInputTensor(node->x());
- Tensor *output = getOutputTensor(node);
-
- return std::make_unique<kernels::Tanh>(input, output);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleTranspose *node)
-{
- assert(node->arity() == 2);
-
- const Tensor *input = getInputTensor(node->a());
- const Tensor *perm = getInputTensor(node->perm());
- Tensor *output = getOutputTensor(node);
-
- return std::make_unique<kernels::Transpose>(input, perm, output);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleTransposeConv *node)
-{
- assert(node->arity() == 4);
-
- const Tensor *input_sizes = getInputTensor(node->inputSizes());
- const Tensor *filter = getInputTensor(node->filter());
- const Tensor *out_backprop = getInputTensor(node->outBackprop());
- const Tensor *bias = getOptionalInputTensor(node->bias());
-
- Tensor *output = getOutputTensor(node);
-
- TransposeConvParams params{};
- params.padding = node->padding();
- params.stride_height = node->stride()->h();
- params.stride_width = node->stride()->w();
-
- return std::make_unique<kernels::TransposeConv>(input_sizes, filter, out_backprop, bias, output,
- params);
-}
-
-std::unique_ptr<Kernel> KernelBuilder::visit(const luci::CircleUnpack *node)
-{
- auto output_nodes = collectOutputNodes<luci::CircleUnpackOut>(node);
- assert(node->arity() == 1);
- assert(output_nodes.size() == static_cast<size_t>(node->num()));
-
- const Tensor *input = getInputTensor(node->value());
- std::vector<Tensor *> outputs = getOutputTensors(output_nodes);
-
- UnpackParams params{};
- params.axis = node->axis();
+ auto specific_builder = _builder_registry->get_kernel_builder_func(node->opcode());
+ if (specific_builder != nullptr)
+ return specific_builder(node, *this);
- // NOTE 'num' attribute is ignored.
- return std::make_unique<kernels::Unpack>(input, std::move(outputs), params);
+ std::string msg = "Unsupported operator: ";
+ msg += toString(node->opcode()) + " in " + std::string(node->name());
+ throw std::invalid_argument(msg.c_str());
}
} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/KernelBuilder.h b/compiler/luci-interpreter/src/loader/KernelBuilder.h
index 31cb9d8fc..b1f383394 100644
--- a/compiler/luci-interpreter/src/loader/KernelBuilder.h
+++ b/compiler/luci-interpreter/src/loader/KernelBuilder.h
@@ -17,79 +17,34 @@
#ifndef LUCI_INTERPRETER_LOADER_KERNELBUILDER_H
#define LUCI_INTERPRETER_LOADER_KERNELBUILDER_H
+#include "loader/KernelBuilderHelper.h"
+
#include "core/Kernel.h"
#include "core/RuntimeGraph.h"
#include <luci/IR/CircleNodeVisitor.h>
#include <memory>
-#include <vector>
#include <unordered_map>
namespace luci_interpreter
{
-class KernelBuilder : public luci::CircleNodeVisitor<std::unique_ptr<Kernel>>
+class KernelBuilderRegistry;
+
+class KernelBuilder : public KernelBuilderHelper
{
public:
KernelBuilder(
- const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph,
- const std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor)
- : _graph_to_runtime_graph(graph_to_runtime_graph), _node_to_tensor(node_to_tensor)
- {
- }
-
- std::unique_ptr<Kernel> visit(const luci::CircleAdd *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleArgMax *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleAveragePool2D *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleConcatenation *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleConv2D *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleConst *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleDepthToSpace *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleDepthwiseConv2D *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleElu *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleFullyConnected *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleIf *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleL2Normalize *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleL2Pool2D *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleLeakyRelu *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleLocalResponseNormalization *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleLogistic *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleInput *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleMaxPool2D *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleMean *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleMul *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleOutput *node) override;
- std::unique_ptr<Kernel> visit(const luci::CirclePad *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleReshape *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleReverseV2 *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleRsqrt *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleSlice *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleSoftmax *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleSpaceToDepth *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleSplit *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleStridedSlice *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleSqrt *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleSqueeze *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleTanh *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleTranspose *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleTransposeConv *node) override;
- std::unique_ptr<Kernel> visit(const luci::CircleUnpack *node) override;
-
-private:
- const Tensor *getInputTensor(const loco::Node *node) const;
-
- const Tensor *getOptionalInputTensor(const loco::Node *node) const;
-
- Tensor *getOutputTensor(const loco::Node *node) const;
+ const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph,
+ const std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor);
- std::vector<Tensor *> getOutputTensors(const std::vector<const loco::Node *> &nodes) const;
+ ~KernelBuilder();
- RuntimeGraph *getRuntimeGraph(const loco::Graph *graph) const;
+ std::unique_ptr<Kernel> build(const luci::CircleNode *node);
private:
- const std::unordered_map<const loco::Graph *, RuntimeGraph *> &_graph_to_runtime_graph;
- const std::unordered_map<const loco::Node *, Tensor *> &_node_to_tensor;
+ std::unique_ptr<KernelBuilderRegistry> _builder_registry;
};
} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp b/compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp
index 4e2bc3d0b..10a01f418 100644
--- a/compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp
+++ b/compiler/luci-interpreter/src/loader/KernelBuilder.test.cpp
@@ -16,35 +16,67 @@
#include "loader/GraphLoader.h"
#include "loader/KernelBuilder.h"
+#include "luci_interpreter/SimpleMemoryManager.h"
#include <kernels/Add.h>
#include <kernels/ArgMax.h>
#include <kernels/AveragePool2D.h>
+#include <kernels/BatchMatMul.h>
+#include <kernels/Cast.h>
#include <kernels/Concatenation.h>
#include <kernels/Conv2D.h>
#include <kernels/DepthToSpace.h>
#include <kernels/DepthwiseConv2D.h>
+#include <kernels/Div.h>
#include <kernels/Elu.h>
+#include <kernels/Exp.h>
+#include <kernels/Floor.h>
+#include <kernels/FloorDiv.h>
+#include <kernels/Equal.h>
#include <kernels/FullyConnected.h>
+#include <kernels/Greater.h>
+#include <kernels/GreaterEqual.h>
+#include <kernels/InstanceNorm.h>
#include <kernels/L2Normalize.h>
#include <kernels/L2Pool2D.h>
#include <kernels/LeakyRelu.h>
+#include <kernels/Less.h>
+#include <kernels/LessEqual.h>
#include <kernels/LocalResponseNormalization.h>
+#include <kernels/LogicalAnd.h>
+#include <kernels/LogicalNot.h>
+#include <kernels/LogicalOr.h>
#include <kernels/Logistic.h>
+#include <kernels/LogSoftmax.h>
+#include <kernels/Maximum.h>
#include <kernels/MaxPool2D.h>
#include <kernels/Mean.h>
+#include <kernels/Minimum.h>
#include <kernels/Mul.h>
+#include <kernels/Neg.h>
+#include <kernels/NotEqual.h>
+#include <kernels/OneHot.h>
#include <kernels/Pad.h>
+#include <kernels/PadV2.h>
+#include <kernels/Pow.h>
+#include <kernels/PRelu.h>
+#include <kernels/Relu.h>
+#include <kernels/Relu6.h>
#include <kernels/Reshape.h>
-#include <kernels/Reverse.h>
+#include <kernels/ResizeBilinear.h>
+#include <kernels/ResizeNearestNeighbor.h>
+#include <kernels/ReverseV2.h>
#include <kernels/Rsqrt.h>
#include <kernels/Slice.h>
#include <kernels/Softmax.h>
#include <kernels/SpaceToDepth.h>
#include <kernels/Split.h>
+#include <kernels/SplitV.h>
#include <kernels/Sqrt.h>
+#include <kernels/SquaredDifference.h>
#include <kernels/Squeeze.h>
#include <kernels/StridedSlice.h>
+#include <kernels/Sub.h>
#include <kernels/Tanh.h>
#include <kernels/Transpose.h>
#include <kernels/TransposeConv.h>
@@ -63,6 +95,9 @@ class KernelBuilderTest : public Test
{
protected:
luci::CircleInput *createInputNode() { return createNode<luci::CircleInput>(); }
+ void SetUp() override { _memory_manager = std::make_unique<SimpleMemoryManager>(); }
+
+ std::unique_ptr<IMemoryManager> _memory_manager;
template <typename NodeT, typename... Args> NodeT *createNode(Args &&... args)
{
@@ -86,15 +121,16 @@ protected:
{
std::unordered_map<const loco::Graph *, RuntimeGraph *> graph_to_runtime_graph;
- RuntimeGraph runtime_graph(nullptr);
+ RuntimeGraph runtime_graph(nullptr, _memory_manager.get());
+ graph_to_runtime_graph[&_graph] = &runtime_graph;
RuntimeToIR runtime_to_ir;
GraphLoader graph_loader(&_graph, &runtime_graph, runtime_to_ir, graph_to_runtime_graph,
- _node_to_tensor);
+ _node_to_tensor, _memory_manager.get());
graph_loader.loadTensors();
KernelBuilder kernel_builder(graph_to_runtime_graph, _node_to_tensor);
- auto kernel = op->accept(&kernel_builder);
+ auto kernel = kernel_builder.build(op);
return std::unique_ptr<KernelT>(dynamic_cast<KernelT *>(kernel.release()));
}
@@ -175,6 +211,41 @@ TEST_F(KernelBuilderTest, AveragePool2D)
EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
}
+TEST_F(KernelBuilderTest, BatchMatMul)
+{
+ auto *lhs = createInputNode();
+ auto *rhs = createInputNode();
+
+ auto *op = createNode<luci::CircleBatchMatMul>();
+ op->x(lhs);
+ op->y(rhs);
+ op->adj_x(false);
+ op->adj_y(false);
+
+ auto kernel = buildKernel<kernels::BatchMatMul>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->x(), lhs);
+ checkTensor(kernel->y(), rhs);
+ checkTensor(kernel->output(), op);
+ EXPECT_THAT(kernel->params().adj_x, Eq(op->adj_x()));
+ EXPECT_THAT(kernel->params().adj_y, Eq(op->adj_y()));
+}
+
+TEST_F(KernelBuilderTest, Cast)
+{
+ auto *input = createInputNode();
+
+ auto *op = createNode<luci::CircleCast>();
+ op->x(input);
+
+ auto kernel = buildKernel<kernels::Cast>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input(), input);
+ checkTensor(kernel->output(), op);
+}
+
TEST_F(KernelBuilderTest, Concatenation)
{
auto *input1 = createInputNode();
@@ -192,6 +263,7 @@ TEST_F(KernelBuilderTest, Concatenation)
checkTensor(kernel->input(1), input2);
checkTensor(kernel->output(), op);
EXPECT_THAT(kernel->params().axis, Eq(op->axis()));
+ EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
}
TEST_F(KernelBuilderTest, Conv2D)
@@ -279,6 +351,26 @@ TEST_F(KernelBuilderTest, DepthwiseConv2D)
EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
}
+TEST_F(KernelBuilderTest, Div)
+{
+ auto *input1 = createInputNode();
+ auto *input2 = createInputNode();
+
+ auto *op = createNode<luci::CircleDiv>();
+ op->x(input1);
+ op->y(input2);
+
+ op->fusedActivationFunction(luci::FusedActFunc::RELU);
+
+ auto kernel = buildKernel<kernels::Div>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input1(), input1);
+ checkTensor(kernel->input2(), input2);
+ checkTensor(kernel->output(), op);
+ EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
+}
+
TEST_F(KernelBuilderTest, Elu)
{
auto *input = createInputNode();
@@ -293,6 +385,68 @@ TEST_F(KernelBuilderTest, Elu)
checkTensor(kernel->output(), op);
}
+TEST_F(KernelBuilderTest, Exp)
+{
+ auto *input = createInputNode();
+
+ auto *op = createNode<luci::CircleExp>();
+ op->x(input);
+
+ auto kernel = buildKernel<kernels::Exp>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input(), input);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, Floor)
+{
+ auto *input = createInputNode();
+
+ auto *op = createNode<luci::CircleFloor>();
+ op->x(input);
+
+ auto kernel = buildKernel<kernels::Floor>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input(), input);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, FloorDiv)
+{
+ auto *x = createInputNode();
+ auto *y = createInputNode();
+
+ auto *op = createNode<luci::CircleFloorDiv>();
+ op->x(x);
+ op->y(y);
+
+ auto kernel = buildKernel<kernels::FloorDiv>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->x(), x);
+ checkTensor(kernel->y(), y);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, Equal)
+{
+ auto *x_input = createInputNode();
+ auto *y_input = createInputNode();
+
+ auto *op = createNode<luci::CircleEqual>();
+ op->x(x_input);
+ op->y(y_input);
+
+ auto kernel = buildKernel<kernels::Equal>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->x(), x_input);
+ checkTensor(kernel->y(), y_input);
+ checkTensor(kernel->output(), op);
+}
+
TEST_F(KernelBuilderTest, FullyConnected)
{
auto *input = createInputNode();
@@ -316,6 +470,65 @@ TEST_F(KernelBuilderTest, FullyConnected)
EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
}
+TEST_F(KernelBuilderTest, Greater)
+{
+ auto *x_input = createInputNode();
+ auto *y_input = createInputNode();
+
+ auto *op = createNode<luci::CircleGreater>();
+ op->x(x_input);
+ op->y(y_input);
+
+ auto kernel = buildKernel<kernels::Greater>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->x(), x_input);
+ checkTensor(kernel->y(), y_input);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, GreaterEqual)
+{
+ auto *x_input = createInputNode();
+ auto *y_input = createInputNode();
+
+ auto *op = createNode<luci::CircleGreaterEqual>();
+ op->x(x_input);
+ op->y(y_input);
+
+ auto kernel = buildKernel<kernels::GreaterEqual>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->x(), x_input);
+ checkTensor(kernel->y(), y_input);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, InstanceNorm)
+{
+ auto *input = createInputNode();
+ auto *gamma = createInputNode();
+ auto *beta = createInputNode();
+
+ auto *op = createNode<luci::CircleInstanceNorm>();
+ op->input(input);
+ op->gamma(gamma);
+ op->beta(beta);
+
+ op->epsilon(1e-05);
+ op->fusedActivationFunction(luci::FusedActFunc::RELU);
+
+ auto kernel = buildKernel<kernels::InstanceNorm>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input(), input);
+ checkTensor(kernel->gamma(), gamma);
+ checkTensor(kernel->beta(), beta);
+ checkTensor(kernel->output(), op);
+ EXPECT_THAT(kernel->params().epsilon, Eq(op->epsilon()));
+ EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
+}
+
TEST_F(KernelBuilderTest, L2Normalize)
{
auto *input = createInputNode();
@@ -377,6 +590,40 @@ TEST_F(KernelBuilderTest, LeakyRelu)
EXPECT_THAT(kernel->params().alpha, Eq(op->alpha()));
}
+TEST_F(KernelBuilderTest, Less)
+{
+ auto *x_input = createInputNode();
+ auto *y_input = createInputNode();
+
+ auto *op = createNode<luci::CircleLess>();
+ op->x(x_input);
+ op->y(y_input);
+
+ auto kernel = buildKernel<kernels::Less>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->x(), x_input);
+ checkTensor(kernel->y(), y_input);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, LessEqual)
+{
+ auto *x_input = createInputNode();
+ auto *y_input = createInputNode();
+
+ auto *op = createNode<luci::CircleLessEqual>();
+ op->x(x_input);
+ op->y(y_input);
+
+ auto kernel = buildKernel<kernels::LessEqual>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->x(), x_input);
+ checkTensor(kernel->y(), y_input);
+ checkTensor(kernel->output(), op);
+}
+
TEST_F(KernelBuilderTest, LocalResponseNormalization)
{
auto *input = createInputNode();
@@ -400,6 +647,54 @@ TEST_F(KernelBuilderTest, LocalResponseNormalization)
EXPECT_THAT(kernel->params().beta, Eq(op->beta()));
}
+TEST_F(KernelBuilderTest, LogicalAnd)
+{
+ auto *input1 = createInputNode();
+ auto *input2 = createInputNode();
+
+ auto *op = createNode<luci::CircleLogicalAnd>();
+ op->x(input1);
+ op->y(input2);
+
+ auto kernel = buildKernel<kernels::LogicalAnd>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input1(), input1);
+ checkTensor(kernel->input2(), input2);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, LogicalNot)
+{
+ auto *input = createInputNode();
+
+ auto *op = createNode<luci::CircleLogicalNot>();
+ op->x(input);
+
+ auto kernel = buildKernel<kernels::LogicalNot>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input(), input);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, LogicalOr)
+{
+ auto *input1 = createInputNode();
+ auto *input2 = createInputNode();
+
+ auto *op = createNode<luci::CircleLogicalOr>();
+ op->x(input1);
+ op->y(input2);
+
+ auto kernel = buildKernel<kernels::LogicalOr>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input1(), input1);
+ checkTensor(kernel->input2(), input2);
+ checkTensor(kernel->output(), op);
+}
+
TEST_F(KernelBuilderTest, Logistic)
{
auto *input = createInputNode();
@@ -414,6 +709,37 @@ TEST_F(KernelBuilderTest, Logistic)
checkTensor(kernel->output(), op);
}
+TEST_F(KernelBuilderTest, LogSoftmax)
+{
+ auto *input = createInputNode();
+
+ auto *op = createNode<luci::CircleLogSoftmax>();
+ op->logits(input);
+
+ auto kernel = buildKernel<kernels::LogSoftmax>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input(), input);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, Maximum)
+{
+ auto *input1 = createInputNode();
+ auto *input2 = createInputNode();
+
+ auto *op = createNode<luci::CircleMaximum>();
+ op->x(input1);
+ op->y(input2);
+
+ auto kernel = buildKernel<kernels::Maximum>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input1(), input1);
+ checkTensor(kernel->input2(), input2);
+ checkTensor(kernel->output(), op);
+}
+
TEST_F(KernelBuilderTest, MaxPool2D)
{
auto *input = createInputNode();
@@ -461,6 +787,23 @@ TEST_F(KernelBuilderTest, Mean)
EXPECT_THAT(kernel->params().keep_dims, Eq(op->keep_dims()));
}
+TEST_F(KernelBuilderTest, Minimum)
+{
+ auto *input1 = createInputNode();
+ auto *input2 = createInputNode();
+
+ auto *op = createNode<luci::CircleMinimum>();
+ op->x(input1);
+ op->y(input2);
+
+ auto kernel = buildKernel<kernels::Minimum>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input1(), input1);
+ checkTensor(kernel->input2(), input2);
+ checkTensor(kernel->output(), op);
+}
+
TEST_F(KernelBuilderTest, Mul)
{
auto *input1 = createInputNode();
@@ -481,6 +824,62 @@ TEST_F(KernelBuilderTest, Mul)
EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
}
+TEST_F(KernelBuilderTest, Neg)
+{
+ auto *input = createInputNode();
+
+ auto *op = createNode<luci::CircleNeg>();
+ op->x(input);
+
+ auto kernel = buildKernel<kernels::Neg>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input(), input);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, NotEqual)
+{
+ auto *x_input = createInputNode();
+ auto *y_input = createInputNode();
+
+ auto *op = createNode<luci::CircleNotEqual>();
+ op->x(x_input);
+ op->y(y_input);
+
+ auto kernel = buildKernel<kernels::NotEqual>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->x(), x_input);
+ checkTensor(kernel->y(), y_input);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, OneHot)
+{
+ auto *indices = createInputNode();
+ auto *depth = createInputNode();
+ auto *on_value = createInputNode();
+ auto *off_value = createInputNode();
+ auto axis = 1;
+
+ auto *op = createNode<luci::CircleOneHot>();
+ op->indices(indices);
+ op->depth(depth);
+ op->on_value(on_value);
+ op->off_value(off_value);
+ op->axis(axis);
+
+ auto kernel = buildKernel<kernels::OneHot>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->indices(), indices);
+ checkTensor(kernel->depth(), depth);
+ checkTensor(kernel->on_value(), on_value);
+ checkTensor(kernel->off_value(), off_value);
+ EXPECT_THAT(kernel->params().axis, Eq(op->axis()));
+}
+
TEST_F(KernelBuilderTest, Pad)
{
auto *input = createInputNode();
@@ -498,6 +897,88 @@ TEST_F(KernelBuilderTest, Pad)
checkTensor(kernel->output(), op);
}
+TEST_F(KernelBuilderTest, PadV2)
+{
+ auto *input = createInputNode();
+ auto *paddings = createInputNode();
+ auto *constant_values = createInputNode();
+
+ auto *op = createNode<luci::CirclePadV2>();
+ op->input(input);
+ op->paddings(paddings);
+ op->constant_values(constant_values);
+
+ auto kernel = buildKernel<kernels::PadV2>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input(), input);
+ checkTensor(kernel->paddings(), paddings);
+ checkTensor(kernel->constant_values(), constant_values);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, Pow)
+{
+ auto *input1 = createInputNode();
+ auto *input2 = createInputNode();
+
+ auto *op = createNode<luci::CirclePow>();
+ op->x(input1);
+ op->y(input2);
+
+ auto kernel = buildKernel<kernels::Pow>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input1(), input1);
+ checkTensor(kernel->input2(), input2);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, PRelu)
+{
+ auto *input = createInputNode();
+ auto *alpha = createInputNode();
+
+ auto *op = createNode<luci::CirclePRelu>();
+ op->input(input);
+ op->alpha(alpha);
+
+ auto kernel = buildKernel<kernels::PRelu>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input(), input);
+ checkTensor(kernel->alpha(), alpha);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, Relu)
+{
+ auto *input = createInputNode();
+
+ auto *op = createNode<luci::CircleRelu>();
+ op->features(input);
+
+ auto kernel = buildKernel<kernels::Relu>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input(), input);
+ checkTensor(kernel->output(), op);
+}
+
+TEST_F(KernelBuilderTest, Relu6)
+{
+ auto *input = createInputNode();
+
+ auto *op = createNode<luci::CircleRelu6>();
+ op->features(input);
+
+ auto kernel = buildKernel<kernels::Relu6>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input(), input);
+ checkTensor(kernel->output(), op);
+}
+
TEST_F(KernelBuilderTest, Reshape)
{
auto *input = createInputNode();
@@ -515,6 +996,48 @@ TEST_F(KernelBuilderTest, Reshape)
checkTensor(kernel->output(), op);
}
+TEST_F(KernelBuilderTest, ResizeBilinear)
+{
+ auto *input = createInputNode();
+ auto *size = createInputNode();
+
+ auto *op = createNode<luci::CircleResizeBilinear>();
+ op->input(input);
+ op->size(size);
+ op->align_corners(true);
+ op->half_pixel_centers(true);
+
+ auto kernel = buildKernel<kernels::ResizeBilinear>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input(), input);
+ checkTensor(kernel->size(), size);
+ checkTensor(kernel->output(), op);
+ EXPECT_THAT(kernel->params().align_corners, Eq(op->align_corners()));
+ EXPECT_THAT(kernel->params().half_pixel_centers, Eq(op->half_pixel_centers()));
+}
+
+TEST_F(KernelBuilderTest, ResizeNearestNeighbor)
+{
+ auto *input = createInputNode();
+ auto *size = createInputNode();
+
+ auto *op = createNode<luci::CircleResizeNearestNeighbor>();
+ op->input(input);
+ op->size(size);
+ op->align_corners(true);
+
+ auto kernel = buildKernel<kernels::ResizeNearestNeighbor>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input(), input);
+ checkTensor(kernel->size(), size);
+ checkTensor(kernel->output(), op);
+ EXPECT_THAT(kernel->params().align_corners, Eq(op->align_corners()));
+ // TODO currently half_pixel_centers are not implemented on CircleResizeNearestNeighbor
+ // after adding, need to be updated.
+}
+
TEST_F(KernelBuilderTest, ReverseV2)
{
auto *input = createInputNode();
@@ -524,7 +1047,7 @@ TEST_F(KernelBuilderTest, ReverseV2)
op->tensor(input);
op->axis(axes);
- auto kernel = buildKernel<kernels::Reverse>(op);
+ auto kernel = buildKernel<kernels::ReverseV2>(op);
ASSERT_THAT(kernel, NotNull());
checkTensor(kernel->input(), input);
@@ -622,6 +1145,31 @@ TEST_F(KernelBuilderTest, Split)
checkTensor(kernel->output(1), output2);
}
+TEST_F(KernelBuilderTest, SplitV)
+{
+ auto *input = createInputNode();
+ auto *size_splits = createInputNode();
+ auto *axis = createInputNode();
+ auto *op = createNode<luci::CircleSplitV>();
+ auto *output0 = createNodeOut<luci::CircleSplitVOut>(op, 0);
+ auto *output1 = createNodeOut<luci::CircleSplitVOut>(op, 1);
+
+ op->input(input);
+ op->size_splits(size_splits);
+ op->split_dim(axis);
+
+ op->num_split(2);
+
+ auto kernel = buildKernel<kernels::SplitV>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input(), input);
+ checkTensor(kernel->size_splits(), size_splits);
+ checkTensor(kernel->axis(), axis);
+ checkTensor(kernel->output(0), output0);
+ checkTensor(kernel->output(1), output1);
+}
+
TEST_F(KernelBuilderTest, Sqrt)
{
auto *input = createInputNode();
@@ -636,6 +1184,23 @@ TEST_F(KernelBuilderTest, Sqrt)
checkTensor(kernel->output(), op);
}
+TEST_F(KernelBuilderTest, SquaredDifference)
+{
+ auto *input1 = createInputNode();
+ auto *input2 = createInputNode();
+
+ auto *op = createNode<luci::CircleSquaredDifference>();
+ op->x(input1);
+ op->y(input2);
+
+ auto kernel = buildKernel<kernels::SquaredDifference>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input1(), input1);
+ checkTensor(kernel->input2(), input2);
+ checkTensor(kernel->output(), op);
+}
+
TEST_F(KernelBuilderTest, Squeeze)
{
auto *input = createInputNode();
@@ -687,6 +1252,26 @@ TEST_F(KernelBuilderTest, StridedSlice)
EXPECT_THAT(kernel->params().shrink_axis_mask, Eq(op->shrink_axis_mask()));
}
+TEST_F(KernelBuilderTest, Sub)
+{
+ auto *input1 = createInputNode();
+ auto *input2 = createInputNode();
+
+ auto *op = createNode<luci::CircleSub>();
+ op->x(input1);
+ op->y(input2);
+
+ op->fusedActivationFunction(luci::FusedActFunc::RELU);
+
+ auto kernel = buildKernel<kernels::Sub>(op);
+ ASSERT_THAT(kernel, NotNull());
+
+ checkTensor(kernel->input1(), input1);
+ checkTensor(kernel->input2(), input2);
+ checkTensor(kernel->output(), op);
+ EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
+}
+
TEST_F(KernelBuilderTest, Tanh)
{
auto *input = createInputNode();
@@ -734,6 +1319,7 @@ TEST_F(KernelBuilderTest, TransposeConv)
op->padding(luci::Padding::SAME);
op->stride()->h(11);
op->stride()->w(13);
+ op->fusedActivationFunction(luci::FusedActFunc::NONE);
auto kernel = buildKernel<kernels::TransposeConv>(op);
ASSERT_THAT(kernel, NotNull());
@@ -746,6 +1332,7 @@ TEST_F(KernelBuilderTest, TransposeConv)
EXPECT_THAT(kernel->params().padding, Eq(op->padding()));
EXPECT_THAT(kernel->params().stride_height, Eq(op->stride()->h()));
EXPECT_THAT(kernel->params().stride_width, Eq(op->stride()->w()));
+ EXPECT_THAT(kernel->params().activation, Eq(op->fusedActivationFunction()));
}
TEST_F(KernelBuilderTest, Unpack)
diff --git a/compiler/luci-interpreter/src/loader/KernelBuilderHelper.cpp b/compiler/luci-interpreter/src/loader/KernelBuilderHelper.cpp
new file mode 100644
index 000000000..23c96a6db
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/KernelBuilderHelper.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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 "loader/KernelBuilderHelper.h"
+
+#include <luci/IR/Nodes/CircleOutput.h>
+
+namespace luci_interpreter
+{
+
+const Tensor *KernelBuilderHelper::getInputTensor(const loco::Node *node) const
+{
+ const Tensor *tensor = _node_to_tensor.at(node);
+ assert(tensor != nullptr);
+ return tensor;
+}
+
+const Tensor *KernelBuilderHelper::getOptionalInputTensor(const loco::Node *node) const
+{
+ if (dynamic_cast<const luci::CircleOutputExclude *>(node))
+ {
+ return nullptr;
+ }
+ return getInputTensor(node);
+}
+
+Tensor *KernelBuilderHelper::getOutputTensor(const loco::Node *node) const
+{
+ Tensor *tensor = _node_to_tensor.at(node);
+ assert(tensor != nullptr);
+ return tensor;
+}
+
+std::vector<Tensor *>
+KernelBuilderHelper::getOutputTensors(const std::vector<const loco::Node *> &nodes) const
+{
+ std::vector<Tensor *> tensors;
+ tensors.reserve(nodes.size());
+ for (const loco::Node *node : nodes)
+ tensors.push_back(getOutputTensor(node));
+ return tensors;
+}
+
+RuntimeGraph *KernelBuilderHelper::getRuntimeGraph(const loco::Graph *graph) const
+{
+ RuntimeGraph *runtime_graph = _graph_to_runtime_graph.at(graph);
+ assert(runtime_graph != nullptr);
+ return runtime_graph;
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/KernelBuilderHelper.h b/compiler/luci-interpreter/src/loader/KernelBuilderHelper.h
new file mode 100644
index 000000000..d6fb253b1
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/KernelBuilderHelper.h
@@ -0,0 +1,84 @@
+/*
+ * 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_INTERPRETER_LOADER_KERNELBUILDER_HELPER_H
+#define LUCI_INTERPRETER_LOADER_KERNELBUILDER_HELPER_H
+
+#include "core/Kernel.h"
+#include "core/RuntimeGraph.h"
+
+#include <loco/IR/Graph.h>
+#include <loco/IR/Node.h>
+
+#include <vector>
+#include <unordered_map>
+
+namespace luci_interpreter
+{
+
+class KernelBuilderHelper
+{
+public:
+ KernelBuilderHelper(
+ const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph,
+ const std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor)
+ : _graph_to_runtime_graph(graph_to_runtime_graph), _node_to_tensor(node_to_tensor)
+ {
+ }
+
+public:
+ const Tensor *getInputTensor(const loco::Node *node) const;
+ const Tensor *getOptionalInputTensor(const loco::Node *node) const;
+
+ Tensor *getOutputTensor(const loco::Node *node) const;
+ std::vector<Tensor *> getOutputTensors(const std::vector<const loco::Node *> &nodes) const;
+
+ RuntimeGraph *getRuntimeGraph(const loco::Graph *graph) const;
+
+public:
+ const std::unordered_map<const loco::Graph *, RuntimeGraph *> &graph_to_runtime_graph() const
+ {
+ return _graph_to_runtime_graph;
+ }
+
+ const std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor() const
+ {
+ return _node_to_tensor;
+ }
+
+private:
+ const std::unordered_map<const loco::Graph *, RuntimeGraph *> &_graph_to_runtime_graph;
+ const std::unordered_map<const loco::Node *, Tensor *> &_node_to_tensor;
+};
+
+template <typename CircleNodeOut>
+std::vector<const loco::Node *> collectOutputNodes(const loco::Node *node)
+{
+ std::vector<const CircleNodeOut *> output_nodes;
+ for (const loco::Node *loco_node : loco::succs(node))
+ {
+ output_nodes.push_back(loco::must_cast<const CircleNodeOut *>(loco_node));
+ }
+ std::sort(output_nodes.begin(), output_nodes.end(),
+ [](const CircleNodeOut *node1, const CircleNodeOut *node2) {
+ return node1->index() < node2->index();
+ });
+ return {output_nodes.cbegin(), output_nodes.cend()};
+}
+
+} // namespace luci_interpreter
+
+#endif // LUCI_INTERPRETER_LOADER_KERNELBUILDER_HELPER_H
diff --git a/compiler/luci-interpreter/src/loader/ModuleLoader.cpp b/compiler/luci-interpreter/src/loader/ModuleLoader.cpp
index b9a2ae0a9..2f278b087 100644
--- a/compiler/luci-interpreter/src/loader/ModuleLoader.cpp
+++ b/compiler/luci-interpreter/src/loader/ModuleLoader.cpp
@@ -23,9 +23,10 @@ namespace luci_interpreter
ModuleLoader::ModuleLoader(const luci::Module *module, RuntimeModule *runtime_module,
RuntimeToIR &runtime_to_ir,
- std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor)
- : _module(module), _runtime_module(runtime_module), _runtime_to_ir(runtime_to_ir),
- _node_to_tensor(node_to_tensor)
+ std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor,
+ IMemoryManager *memory_manager)
+ : _module(module), _runtime_module(runtime_module), _runtime_to_ir(runtime_to_ir),
+ _node_to_tensor(node_to_tensor), _memory_manager(memory_manager)
{
}
@@ -35,14 +36,14 @@ void ModuleLoader::load()
// process for control flow nodes.
for (size_t i = 0; i < _module->size(); ++i)
{
- _graph_to_runtime_graph.emplace(_module->graph(i), _runtime_module->addGraph());
+ _graph_to_runtime_graph.emplace(_module->graph(i), _runtime_module->addGraph(_memory_manager));
}
for (size_t i = 0; i < _module->size(); ++i)
{
const loco::Graph *graph = _module->graph(i);
RuntimeGraph *runtime_graph = _graph_to_runtime_graph.at(graph);
GraphLoader loader(graph, runtime_graph, _runtime_to_ir, _graph_to_runtime_graph,
- _node_to_tensor);
+ _node_to_tensor, _memory_manager);
loader.loadTensors();
loader.initInputOutputTensors();
loader.loadOperators();
diff --git a/compiler/luci-interpreter/src/loader/ModuleLoader.h b/compiler/luci-interpreter/src/loader/ModuleLoader.h
index 1af0ed747..11326a2ee 100644
--- a/compiler/luci-interpreter/src/loader/ModuleLoader.h
+++ b/compiler/luci-interpreter/src/loader/ModuleLoader.h
@@ -19,6 +19,7 @@
#include "core/RuntimeModule.h"
#include "loader/RuntimeToIR.h"
+#include "luci_interpreter/MemoryManager.h"
#include <luci/IR/Module.h>
@@ -32,11 +33,13 @@ class ModuleLoader
public:
ModuleLoader(const luci::Module *module, RuntimeModule *runtime_module,
RuntimeToIR &runtime_to_ir,
- std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor);
+ std::unordered_map<const loco::Node *, Tensor *> &node_to_tensor,
+ IMemoryManager *memory_manager);
void load();
private:
+ IMemoryManager *_memory_manager;
const luci::Module *_module;
RuntimeModule *_runtime_module;
RuntimeToIR &_runtime_to_ir;
diff --git a/compiler/luci-interpreter/src/loader/nodes/Abs.cpp b/compiler/luci-interpreter/src/loader/nodes/Abs.cpp
new file mode 100644
index 000000000..394711145
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Abs.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/Abs.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleAbs(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleAbs *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->x());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Abs>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Add.cpp b/compiler/luci-interpreter/src/loader/nodes/Add.cpp
new file mode 100644
index 000000000..501e84752
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Add.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 "Builders.h"
+
+#include "kernels/Add.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleAdd(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleAdd *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input1 = helper.getInputTensor(node->x());
+ const Tensor *input2 = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ AddParams params{};
+ params.activation = node->fusedActivationFunction();
+
+ return std::make_unique<kernels::Add>(input1, input2, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/ArgMax.cpp b/compiler/luci-interpreter/src/loader/nodes/ArgMax.cpp
new file mode 100644
index 000000000..f3ca55744
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/ArgMax.cpp
@@ -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.
+ */
+
+#include "Builders.h"
+
+#include "kernels/ArgMax.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleArgMax(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleArgMax *>(circle_node);
+ assert(node->arity() == 2);
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *axis = helper.getInputTensor(node->dimension());
+ Tensor *output = helper.getOutputTensor(node);
+
+ ArgMaxParams params{};
+ params.output_type = node->output_type();
+
+ return std::make_unique<kernels::ArgMax>(input, axis, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/AveragePool2D.cpp b/compiler/luci-interpreter/src/loader/nodes/AveragePool2D.cpp
new file mode 100644
index 000000000..a8135706f
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/AveragePool2D.cpp
@@ -0,0 +1,64 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/AveragePool2D.h"
+#include <luci/Plan/CircleNodeExecutionPlan.h>
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleAveragePool2D(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleAveragePool2D *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->value());
+ Tensor *output = helper.getOutputTensor(node);
+
+ Pool2DParams params{};
+ params.padding = node->padding();
+ params.filter_height = node->filter()->h();
+ params.filter_width = node->filter()->w();
+ params.stride_height = node->stride()->h();
+ params.stride_width = node->stride()->w();
+ params.activation = node->fusedActivationFunction();
+
+ // It is unknown what data will be stored in scratchpad tensor,
+ // using UINT8 as a most general option
+ auto scratchpad = std::make_unique<Tensor>(DataType::U8, Shape({}), AffineQuantization{}, "");
+ scratchpad->set_observable(false);
+ scratchpad->set_data_buffer(nullptr);
+ // If node has execution plan then read memory offsets for scratchpad temporary tensor
+ // from the beginning of shared memory buffer.
+ // Used in Static Memory Manager.
+ // TODO move tensors offset initialization to one place
+ if (luci::has_execution_plan(node))
+ {
+ const auto execution_plan = luci::get_execution_plan(node);
+ // Check whether the offset for the current CircleConv2D temporary was found.
+ if (execution_plan.offsets().size() > 1)
+ // If this is true, then we keep this offset in scratchpad.
+ scratchpad->set_offset(execution_plan.offsets().at(1));
+ }
+ Tensor *tmp = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad));
+
+ return std::make_unique<kernels::AveragePool2D>(input, output, tmp, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/BatchMatMul.cpp b/compiler/luci-interpreter/src/loader/nodes/BatchMatMul.cpp
new file mode 100644
index 000000000..9da2f6d93
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/BatchMatMul.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/BatchMatMul.h"
+#include <luci/Plan/CircleNodeExecutionPlan.h>
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleBatchMatMul(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleBatchMatMul *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *lhs = helper.getInputTensor(node->x());
+ const Tensor *rhs = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ auto lhs_scratchpad =
+ std::make_unique<Tensor>(lhs->element_type(), Shape({}), AffineQuantization{}, "");
+ lhs_scratchpad->set_observable(false);
+ lhs_scratchpad->set_data_buffer(nullptr);
+ auto rhs_scratchpad =
+ std::make_unique<Tensor>(rhs->element_type(), Shape({}), AffineQuantization{}, "");
+ rhs_scratchpad->set_observable(false);
+ rhs_scratchpad->set_data_buffer(nullptr);
+ // If node has execution plan then read memory offsets for scratchpad temporary tensor
+ // from the beginning of shared memory buffer.
+ // Used in Static Memory Manager.
+ // TODO move tensors offset initialization to one place
+ if (luci::has_execution_plan(node))
+ {
+ const auto execution_plan = luci::get_execution_plan(node);
+ // Check whether the offset for the current BatchMatMul temporary was found.
+ if (execution_plan.offsets().size() > 1)
+ {
+ assert(execution_plan.offsets().size() == 3);
+
+ // If this is true, then we keep this offset in scratchpad.
+ lhs_scratchpad->set_offset(execution_plan.offsets().at(1));
+ rhs_scratchpad->set_offset(execution_plan.offsets().at(2));
+ }
+ }
+ Tensor *lhs_tmp = helper.getRuntimeGraph(node->graph())->addTensor(std::move(lhs_scratchpad));
+ Tensor *rhs_tmp = helper.getRuntimeGraph(node->graph())->addTensor(std::move(rhs_scratchpad));
+
+ BatchMatMulParams params;
+ params.adj_x = node->adj_x();
+ params.adj_y = node->adj_y();
+
+ return std::make_unique<kernels::BatchMatMul>(lhs, rhs, output, lhs_tmp, rhs_tmp, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/BatchToSpaceND.cpp b/compiler/luci-interpreter/src/loader/nodes/BatchToSpaceND.cpp
new file mode 100644
index 000000000..ac6ebb30f
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/BatchToSpaceND.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 "Builders.h"
+
+#include "kernels/BatchToSpaceND.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleBatchToSpaceND(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleBatchToSpaceND *>(circle_node);
+ assert(node->arity() == 3);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *block_shape = helper.getInputTensor(node->block_shape());
+ const Tensor *crops = helper.getInputTensor(node->crops());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::BatchToSpaceND>(input, block_shape, crops, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Builders.h b/compiler/luci-interpreter/src/loader/nodes/Builders.h
new file mode 100644
index 000000000..eab284008
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Builders.h
@@ -0,0 +1,37 @@
+/*
+ * 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_INTERPRETER_LOADER_NODES_BUILDERS_H
+#define LUCI_INTERPRETER_LOADER_NODES_BUILDERS_H
+
+#include "loader/KernelBuilderHelper.h"
+
+#include "luci/IR/CircleNodes.h"
+
+namespace luci_interpreter
+{
+
+#define REGISTER_KERNEL(name) \
+ std::unique_ptr<Kernel> build_kernel_Circle##name(const luci::CircleNode *circle_node, \
+ KernelBuilderHelper &helper);
+
+#include "KernelsToBuild.lst"
+
+#undef REGISTER_KERNEL
+
+} // namespace luci_interpreter
+
+#endif // LUCI_INTERPRETER_LOADER_NODES_BUILDERS_H
diff --git a/compiler/luci-interpreter/src/loader/nodes/Cast.cpp b/compiler/luci-interpreter/src/loader/nodes/Cast.cpp
new file mode 100644
index 000000000..a16354c96
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Cast.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Cast.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleCast(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleCast *>(circle_node);
+
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->x());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Cast>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Concatenation.cpp b/compiler/luci-interpreter/src/loader/nodes/Concatenation.cpp
new file mode 100644
index 000000000..ba2564ea2
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Concatenation.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Concatenation.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleConcatenation(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleConcatenation *>(circle_node);
+ std::vector<const Tensor *> inputs(node->numValues());
+ for (uint32_t i = 0; i < node->numValues(); ++i)
+ {
+ inputs[i] = helper.getInputTensor(node->values(i));
+ }
+ Tensor *output = helper.getOutputTensor(node);
+
+ ConcatenationParams params{};
+ params.axis = node->axis();
+ params.activation = node->fusedActivationFunction();
+
+ return std::make_unique<kernels::Concatenation>(std::move(inputs), output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Conv2D.cpp b/compiler/luci-interpreter/src/loader/nodes/Conv2D.cpp
new file mode 100644
index 000000000..218165e20
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Conv2D.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Conv2D.h"
+#include <luci/Plan/CircleNodeExecutionPlan.h>
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleConv2D(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleConv2D *>(circle_node);
+ assert(node->arity() == 3);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *filter = helper.getInputTensor(node->filter());
+ const Tensor *bias = helper.getOptionalInputTensor(node->bias());
+ Tensor *output = helper.getOutputTensor(node);
+
+ // It is unknown what data will be stored in scratchpad tensor,
+ // using UINT8 as a most general option
+ auto scratchpad = std::make_unique<Tensor>(DataType::U8, Shape({}), AffineQuantization{}, "");
+ scratchpad->set_observable(false);
+ scratchpad->set_data_buffer(nullptr);
+ // If node has execution plan then read memory offsets for scratchpad temporary tensor
+ // from the beginning of shared memory buffer.
+ // Used in Static Memory Manager.
+ // TODO move tensors offset initialization to one place
+ if (luci::has_execution_plan(node))
+ {
+ const auto execution_plan = luci::get_execution_plan(node);
+ // Check whether the offset for the current CircleConv2D temporary was found.
+ if (execution_plan.offsets().size() > 1)
+ // If this is true, then we keep this offset in scratchpad.
+ scratchpad->set_offset(execution_plan.offsets().at(1));
+ }
+ Tensor *tmp = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad));
+
+ Conv2DParams params{};
+ params.padding = node->padding();
+ params.stride_height = node->stride()->h();
+ params.stride_width = node->stride()->w();
+ params.dilation_height_factor = node->dilation()->h();
+ params.dilation_width_factor = node->dilation()->w();
+ params.activation = node->fusedActivationFunction();
+
+ return std::make_unique<kernels::Conv2D>(input, filter, bias, output, tmp, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/DepthToSpace.cpp b/compiler/luci-interpreter/src/loader/nodes/DepthToSpace.cpp
new file mode 100644
index 000000000..174946367
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/DepthToSpace.cpp
@@ -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.
+ */
+
+#include "Builders.h"
+
+#include "kernels/DepthToSpace.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleDepthToSpace(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleDepthToSpace *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ Tensor *output = helper.getOutputTensor(node);
+
+ DepthToSpaceParams params{};
+ params.block_size = node->block_size();
+
+ return std::make_unique<kernels::DepthToSpace>(input, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/DepthwiseConv2D.cpp b/compiler/luci-interpreter/src/loader/nodes/DepthwiseConv2D.cpp
new file mode 100644
index 000000000..8af1e3b58
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/DepthwiseConv2D.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/DepthwiseConv2D.h"
+#include <luci/Plan/CircleNodeExecutionPlan.h>
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleDepthwiseConv2D(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleDepthwiseConv2D *>(circle_node);
+ assert(node->arity() == 3);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *filter = helper.getInputTensor(node->filter());
+ const Tensor *bias = helper.getInputTensor(node->bias());
+ Tensor *output = helper.getOutputTensor(node);
+
+ DepthwiseConv2DParams params{};
+ params.padding = node->padding();
+ params.depth_multiplier = node->depthMultiplier();
+ params.stride_height = node->stride()->h();
+ params.stride_width = node->stride()->w();
+ params.dilation_height_factor = node->dilation()->h();
+ params.dilation_width_factor = node->dilation()->w();
+ params.activation = node->fusedActivationFunction();
+
+ // It is unknown what data will be stored in scratchpad tensor,
+ // using UINT8 as a most general option
+ auto scratchpad = std::make_unique<Tensor>(DataType::U8, Shape({}), AffineQuantization{}, "");
+ scratchpad->set_observable(false);
+ scratchpad->set_data_buffer(nullptr);
+ // If node has execution plan then read memory offsets for scratchpad temporary tensor
+ // from the beginning of shared memory buffer.
+ // Used in Static Memory Manager.
+ // TODO move tensors offset initialization to one place
+ if (luci::has_execution_plan(node))
+ {
+ const auto execution_plan = luci::get_execution_plan(node);
+ // Check whether the offset for the current CircleConv2D temporary was found.
+ if (execution_plan.offsets().size() > 1)
+ // If this is true, then we keep this offset in scratchpad.
+ scratchpad->set_offset(execution_plan.offsets().at(1));
+ }
+ Tensor *tmp = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad));
+
+ return std::make_unique<kernels::DepthwiseConv2D>(input, filter, bias, output, tmp, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Dequantize.cpp b/compiler/luci-interpreter/src/loader/nodes/Dequantize.cpp
new file mode 100644
index 000000000..787322e9b
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Dequantize.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/Dequantize.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleDequantize(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleDequantize *>(circle_node);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Dequantize>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Div.cpp b/compiler/luci-interpreter/src/loader/nodes/Div.cpp
new file mode 100644
index 000000000..0611dfdab
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Div.cpp
@@ -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.
+ */
+
+#include "Builders.h"
+
+#include "kernels/Div.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleDiv(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleDiv *>(circle_node);
+ assert(node->arity() == 2);
+ const Tensor *input1 = helper.getInputTensor(node->x());
+ const Tensor *input2 = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ DivParams params{};
+ params.activation = node->fusedActivationFunction();
+
+ return std::make_unique<kernels::Div>(input1, input2, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Elu.cpp b/compiler/luci-interpreter/src/loader/nodes/Elu.cpp
new file mode 100644
index 000000000..a79985e3b
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Elu.cpp
@@ -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.
+ */
+
+#include "Builders.h"
+
+#include "kernels/Elu.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleElu(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleElu *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->features());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Elu>(input, output);
+}
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Equal.cpp b/compiler/luci-interpreter/src/loader/nodes/Equal.cpp
new file mode 100644
index 000000000..59692883f
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Equal.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 "Builders.h"
+
+#include "kernels/Equal.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleEqual(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+
+{
+ const auto *node = loco::must_cast<const luci::CircleEqual *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *x = helper.getInputTensor(node->x());
+ const Tensor *y = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Equal>(x, y, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Exp.cpp b/compiler/luci-interpreter/src/loader/nodes/Exp.cpp
new file mode 100644
index 000000000..30d11cb89
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Exp.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Exp.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleExp(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleExp *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->x());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Exp>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/ExpandDims.cpp b/compiler/luci-interpreter/src/loader/nodes/ExpandDims.cpp
new file mode 100644
index 000000000..9840c34e5
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/ExpandDims.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/ExpandDims.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleExpandDims(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleExpandDims *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *axis = helper.getInputTensor(node->axis());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::ExpandDims>(input, axis, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Fill.cpp b/compiler/luci-interpreter/src/loader/nodes/Fill.cpp
new file mode 100644
index 000000000..3aefdf1c5
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Fill.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/Fill.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleFill(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleFill *>(circle_node);
+ assert(node->arity() == 2);
+
+ const auto dims = helper.getInputTensor(node->dims());
+ const auto value = helper.getInputTensor(node->value());
+ auto output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Fill>(dims, value, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Floor.cpp b/compiler/luci-interpreter/src/loader/nodes/Floor.cpp
new file mode 100644
index 000000000..e0a223116
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Floor.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Floor.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleFloor(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleFloor *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->x());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Floor>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/FloorDiv.cpp b/compiler/luci-interpreter/src/loader/nodes/FloorDiv.cpp
new file mode 100644
index 000000000..a45d89e38
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/FloorDiv.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/FloorDiv.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleFloorDiv(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleFloorDiv *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *x = helper.getInputTensor(node->x());
+ const Tensor *y = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::FloorDiv>(x, y, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/FloorMod.cpp b/compiler/luci-interpreter/src/loader/nodes/FloorMod.cpp
new file mode 100644
index 000000000..a4852f13e
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/FloorMod.cpp
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/FloorMod.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleFloorMod(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleFloorMod *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *x = helper.getInputTensor(node->x());
+ const Tensor *y = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::FloorMod>(x, y, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/FullyConnected.cpp b/compiler/luci-interpreter/src/loader/nodes/FullyConnected.cpp
new file mode 100644
index 000000000..b7b742b8a
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/FullyConnected.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/FullyConnected.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleFullyConnected(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleFullyConnected *>(circle_node);
+ assert(node->arity() == 3);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *weights = helper.getInputTensor(node->weights());
+ const Tensor *bias = helper.getOptionalInputTensor(node->bias());
+ Tensor *output = helper.getOutputTensor(node);
+
+ FullyConnectedParams params{};
+ params.activation = node->fusedActivationFunction();
+ params.keep_num_dims = node->keep_num_dims();
+
+ return std::make_unique<kernels::FullyConnected>(input, weights, bias, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Gather.cpp b/compiler/luci-interpreter/src/loader/nodes/Gather.cpp
new file mode 100644
index 000000000..2ee2906e0
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Gather.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/Gather.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleGather(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleGather *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *params = helper.getInputTensor(node->params());
+ const Tensor *indices = helper.getInputTensor(node->indices());
+ Tensor *output = helper.getOutputTensor(node);
+
+ GatherParams gparams{};
+ gparams.axis = node->axis();
+ // TODO support batch_dims
+ gparams.batch_dims = 0;
+
+ return std::make_unique<kernels::Gather>(params, indices, output, gparams);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Gelu.cpp b/compiler/luci-interpreter/src/loader/nodes/Gelu.cpp
new file mode 100644
index 000000000..fc77a5817
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Gelu.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/Gelu.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleGelu(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleGelu *>(circle_node);
+ assert(node->arity() == 1);
+ const Tensor *input = helper.getInputTensor(node->features());
+ Tensor *output = helper.getOutputTensor(node);
+
+ GeluParams params{};
+ params.approximate = node->approximate();
+
+ return std::make_unique<kernels::Gelu>(input, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Greater.cpp b/compiler/luci-interpreter/src/loader/nodes/Greater.cpp
new file mode 100644
index 000000000..80aa63cf0
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Greater.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Greater.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleGreater(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleGreater *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *x = helper.getInputTensor(node->x());
+ const Tensor *y = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Greater>(x, y, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/GreaterEqual.cpp b/compiler/luci-interpreter/src/loader/nodes/GreaterEqual.cpp
new file mode 100644
index 000000000..272f2843b
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/GreaterEqual.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/GreaterEqual.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleGreaterEqual(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleGreaterEqual *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *x = helper.getInputTensor(node->x());
+ const Tensor *y = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::GreaterEqual>(x, y, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/HardSwish.cpp b/compiler/luci-interpreter/src/loader/nodes/HardSwish.cpp
new file mode 100644
index 000000000..2e62f2402
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/HardSwish.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/HardSwish.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleHardSwish(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleHardSwish *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->features());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::HardSwish>(input, output);
+}
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/If.cpp b/compiler/luci-interpreter/src/loader/nodes/If.cpp
new file mode 100644
index 000000000..3ac7d4941
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/If.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 "Builders.h"
+
+#include "kernels/If.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleIf(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleIf *>(circle_node);
+ auto output_nodes = collectOutputNodes<luci::CircleIfOut>(node);
+ assert(node->arity() == 1 + node->input_count());
+ assert(output_nodes.size() == static_cast<size_t>(node->output_count()));
+
+ const Tensor *cond = helper.getInputTensor(node->cond());
+ std::vector<const Tensor *> inputs(node->input_count());
+ for (uint32_t i = 0; i < node->input_count(); ++i)
+ {
+ inputs[i] = helper.getInputTensor(node->input(i));
+ }
+ std::vector<Tensor *> outputs = helper.getOutputTensors(output_nodes);
+
+ RuntimeGraph *then_graph = helper.getRuntimeGraph(node->then_graph());
+ RuntimeGraph *else_graph = helper.getRuntimeGraph(node->else_graph());
+
+ return std::make_unique<kernels::If>(cond, std::move(inputs), std::move(outputs), then_graph,
+ else_graph);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/InstanceNorm.cpp b/compiler/luci-interpreter/src/loader/nodes/InstanceNorm.cpp
new file mode 100644
index 000000000..06031e5bc
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/InstanceNorm.cpp
@@ -0,0 +1,43 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/InstanceNorm.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleInstanceNorm(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleInstanceNorm *>(circle_node);
+ assert(node->arity() == 3);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *gamma = helper.getInputTensor(node->gamma());
+ const Tensor *beta = helper.getInputTensor(node->beta());
+
+ Tensor *output = helper.getOutputTensor(node);
+
+ InstanceNormParams params{};
+ params.epsilon = node->epsilon();
+ params.activation = node->fusedActivationFunction();
+
+ return std::make_unique<kernels::InstanceNorm>(input, gamma, beta, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/L2Normalize.cpp b/compiler/luci-interpreter/src/loader/nodes/L2Normalize.cpp
new file mode 100644
index 000000000..6e22e6d4e
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/L2Normalize.cpp
@@ -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.
+ */
+
+#include "Builders.h"
+
+#include "kernels/L2Normalize.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleL2Normalize(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleL2Normalize *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->x());
+ Tensor *output = helper.getOutputTensor(node);
+
+ L2NormParams params{};
+ params.activation = node->fusedActivationFunction();
+
+ return std::make_unique<kernels::L2Normalize>(input, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/L2Pool2D.cpp b/compiler/luci-interpreter/src/loader/nodes/L2Pool2D.cpp
new file mode 100644
index 000000000..95b55896f
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/L2Pool2D.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/L2Pool2D.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleL2Pool2D(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleL2Pool2D *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->value());
+ Tensor *output = helper.getOutputTensor(node);
+
+ Pool2DParams params{};
+ params.padding = node->padding();
+ params.filter_height = node->filter()->h();
+ params.filter_width = node->filter()->w();
+ params.stride_height = node->stride()->h();
+ params.stride_width = node->stride()->w();
+ params.activation = node->fusedActivationFunction();
+
+ return std::make_unique<kernels::L2Pool2D>(input, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/LeakyRelu.cpp b/compiler/luci-interpreter/src/loader/nodes/LeakyRelu.cpp
new file mode 100644
index 000000000..bbf5067b1
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/LeakyRelu.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 "Builders.h"
+
+#include "kernels/LeakyRelu.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleLeakyRelu(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleLeakyRelu *>(circle_node);
+ assert(node->arity() == 1);
+ const Tensor *input = helper.getInputTensor(node->features());
+ Tensor *output = helper.getOutputTensor(node);
+
+ LeakyReluParams params{};
+ params.alpha = node->alpha();
+
+ return std::make_unique<kernels::LeakyRelu>(input, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Less.cpp b/compiler/luci-interpreter/src/loader/nodes/Less.cpp
new file mode 100644
index 000000000..ae914ecc9
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Less.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Less.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleLess(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleLess *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *x = helper.getInputTensor(node->x());
+ const Tensor *y = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Less>(x, y, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/LessEqual.cpp b/compiler/luci-interpreter/src/loader/nodes/LessEqual.cpp
new file mode 100644
index 000000000..f1b424b55
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/LessEqual.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/LessEqual.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleLessEqual(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleLessEqual *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *x = helper.getInputTensor(node->x());
+ const Tensor *y = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::LessEqual>(x, y, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/LocalResponseNormalization.cpp b/compiler/luci-interpreter/src/loader/nodes/LocalResponseNormalization.cpp
new file mode 100644
index 000000000..962ca2d7c
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/LocalResponseNormalization.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/LocalResponseNormalization.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel>
+build_kernel_CircleLocalResponseNormalization(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleLocalResponseNormalization *>(circle_node);
+ assert(node->arity() == 1);
+ const Tensor *input = helper.getInputTensor(node->input());
+ Tensor *output = helper.getOutputTensor(node);
+
+ LocalResponseNormalizationParams params{};
+ params.radius = node->radius();
+ params.bias = node->bias();
+ params.alpha = node->alpha();
+ params.beta = node->beta();
+
+ return std::make_unique<kernels::LocalResponseNormalization>(input, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Log.cpp b/compiler/luci-interpreter/src/loader/nodes/Log.cpp
new file mode 100644
index 000000000..048e3101e
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Log.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/Log.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleLog(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleLog *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->x());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Log>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/LogSoftmax.cpp b/compiler/luci-interpreter/src/loader/nodes/LogSoftmax.cpp
new file mode 100644
index 000000000..432204115
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/LogSoftmax.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/LogSoftmax.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleLogSoftmax(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleLogSoftmax *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->logits());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::LogSoftmax>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/LogicalAnd.cpp b/compiler/luci-interpreter/src/loader/nodes/LogicalAnd.cpp
new file mode 100644
index 000000000..bf3cb671a
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/LogicalAnd.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/LogicalAnd.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleLogicalAnd(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleLogicalAnd *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input1 = helper.getInputTensor(node->x());
+ const Tensor *input2 = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::LogicalAnd>(input1, input2, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/LogicalNot.cpp b/compiler/luci-interpreter/src/loader/nodes/LogicalNot.cpp
new file mode 100644
index 000000000..fefcd9a06
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/LogicalNot.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/LogicalNot.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleLogicalNot(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleLogicalNot *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->x());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::LogicalNot>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/LogicalOr.cpp b/compiler/luci-interpreter/src/loader/nodes/LogicalOr.cpp
new file mode 100644
index 000000000..a416cb401
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/LogicalOr.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/LogicalOr.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleLogicalOr(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleLogicalOr *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input1 = helper.getInputTensor(node->x());
+ const Tensor *input2 = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::LogicalOr>(input1, input2, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Logistic.cpp b/compiler/luci-interpreter/src/loader/nodes/Logistic.cpp
new file mode 100644
index 000000000..4a69deef1
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Logistic.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Logistic.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleLogistic(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleLogistic *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->x());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Logistic>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/MaxPool2D.cpp b/compiler/luci-interpreter/src/loader/nodes/MaxPool2D.cpp
new file mode 100644
index 000000000..f66a206ca
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/MaxPool2D.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/MaxPool2D.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleMaxPool2D(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleMaxPool2D *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->value());
+ Tensor *output = helper.getOutputTensor(node);
+
+ Pool2DParams params{};
+ params.padding = node->padding();
+ params.filter_height = node->filter()->h();
+ params.filter_width = node->filter()->w();
+ params.stride_height = node->stride()->h();
+ params.stride_width = node->stride()->w();
+ params.activation = node->fusedActivationFunction();
+
+ return std::make_unique<kernels::MaxPool2D>(input, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Maximum.cpp b/compiler/luci-interpreter/src/loader/nodes/Maximum.cpp
new file mode 100644
index 000000000..d0bff776a
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Maximum.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Maximum.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleMaximum(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleMaximum *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input1 = helper.getInputTensor(node->x());
+ const Tensor *input2 = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Maximum>(input1, input2, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Mean.cpp b/compiler/luci-interpreter/src/loader/nodes/Mean.cpp
new file mode 100644
index 000000000..0dec63e79
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Mean.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 "Builders.h"
+
+#include "kernels/Mean.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleMean(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleMean *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *axes = helper.getInputTensor(node->reduction_indices());
+ Tensor *output = helper.getOutputTensor(node);
+
+ auto temp_index_unique =
+ std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, "");
+ temp_index_unique->set_observable(false);
+ temp_index_unique->set_data_buffer(nullptr);
+ Tensor *temp_index =
+ helper.getRuntimeGraph(node->graph())->addTensor(std::move(temp_index_unique));
+
+ auto resolved_axes_unique =
+ std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, "");
+ resolved_axes_unique->set_observable(false);
+ resolved_axes_unique->set_data_buffer(nullptr);
+ Tensor *resolved_axes =
+ helper.getRuntimeGraph(node->graph())->addTensor(std::move(resolved_axes_unique));
+
+ auto temp_sum_unique =
+ std::make_unique<Tensor>(input->element_type(), Shape({}), AffineQuantization{}, "");
+ temp_sum_unique->set_observable(false);
+ temp_sum_unique->set_data_buffer(nullptr);
+ Tensor *temp_sum = helper.getRuntimeGraph(node->graph())->addTensor(std::move(temp_sum_unique));
+
+ ReducerParams params{};
+ params.keep_dims = node->keep_dims();
+
+ return std::make_unique<kernels::Mean>(input, axes, output, temp_index, resolved_axes, temp_sum,
+ params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Minimum.cpp b/compiler/luci-interpreter/src/loader/nodes/Minimum.cpp
new file mode 100644
index 000000000..1a49c1090
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Minimum.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Minimum.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleMinimum(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleMinimum *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input1 = helper.getInputTensor(node->x());
+ const Tensor *input2 = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Minimum>(input1, input2, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/MirrorPad.cpp b/compiler/luci-interpreter/src/loader/nodes/MirrorPad.cpp
new file mode 100644
index 000000000..b221b4574
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/MirrorPad.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 "Builders.h"
+
+#include "kernels/MirrorPad.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleMirrorPad(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleMirrorPad *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *paddings = helper.getInputTensor(node->paddings());
+ Tensor *output = helper.getOutputTensor(node);
+
+ MirrorPadParams params{};
+ params.mode = node->mode();
+
+ return std::make_unique<kernels::MirrorPad>(input, paddings, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Mul.cpp b/compiler/luci-interpreter/src/loader/nodes/Mul.cpp
new file mode 100644
index 000000000..f9984853a
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Mul.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 "Builders.h"
+
+#include "kernels/Mul.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleMul(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleMul *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input1 = helper.getInputTensor(node->x());
+ const Tensor *input2 = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ MulParams params{};
+ params.activation = node->fusedActivationFunction();
+
+ return std::make_unique<kernels::Mul>(input1, input2, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Neg.cpp b/compiler/luci-interpreter/src/loader/nodes/Neg.cpp
new file mode 100644
index 000000000..9a9ecf991
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Neg.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Neg.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleNeg(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleNeg *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->x());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Neg>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/NotEqual.cpp b/compiler/luci-interpreter/src/loader/nodes/NotEqual.cpp
new file mode 100644
index 000000000..3916a5854
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/NotEqual.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/NotEqual.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleNotEqual(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleNotEqual *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *x = helper.getInputTensor(node->x());
+ const Tensor *y = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::NotEqual>(x, y, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/OneHot.cpp b/compiler/luci-interpreter/src/loader/nodes/OneHot.cpp
new file mode 100644
index 000000000..a40160945
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/OneHot.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/OneHot.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleOneHot(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleOneHot *>(circle_node);
+ assert(node->arity() == 4);
+
+ const Tensor *indices = helper.getInputTensor(node->indices());
+ const Tensor *depth = helper.getInputTensor(node->depth());
+ const Tensor *on_value = helper.getInputTensor(node->on_value());
+ const Tensor *off_value = helper.getInputTensor(node->off_value());
+ Tensor *output = helper.getOutputTensor(node);
+
+ OneHotParams params{};
+ params.axis = node->axis();
+
+ return std::make_unique<kernels::OneHot>(indices, depth, on_value, off_value, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/PRelu.cpp b/compiler/luci-interpreter/src/loader/nodes/PRelu.cpp
new file mode 100644
index 000000000..f3d700c95
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/PRelu.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/PRelu.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CirclePRelu(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CirclePRelu *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *alpha = helper.getInputTensor(node->alpha());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::PRelu>(input, alpha, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Pack.cpp b/compiler/luci-interpreter/src/loader/nodes/Pack.cpp
new file mode 100644
index 000000000..efc5850e0
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Pack.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Pack.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CirclePack(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CirclePack *>(circle_node);
+ assert(node->arity() == node->values_count());
+
+ std::vector<const Tensor *> inputs(node->values_count());
+ for (uint32_t i = 0; i < node->values_count(); ++i)
+ {
+ inputs[i] = helper.getInputTensor(node->values(i));
+ }
+ Tensor *output = helper.getOutputTensor(node);
+
+ PackParams params{};
+ params.axis = node->axis();
+ params.values_count = node->values_count();
+
+ return std::make_unique<kernels::Pack>(std::move(inputs), output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Pad.cpp b/compiler/luci-interpreter/src/loader/nodes/Pad.cpp
new file mode 100644
index 000000000..67ce997a7
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Pad.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Pad.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CirclePad(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CirclePad *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *paddings = helper.getInputTensor(node->paddings());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Pad>(input, paddings, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/PadV2.cpp b/compiler/luci-interpreter/src/loader/nodes/PadV2.cpp
new file mode 100644
index 000000000..e378a972a
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/PadV2.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 "Builders.h"
+
+#include "kernels/PadV2.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CirclePadV2(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CirclePadV2 *>(circle_node);
+ assert(node->arity() == 3);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *paddings = helper.getInputTensor(node->paddings());
+ const Tensor *constant_values = helper.getInputTensor(node->constant_values());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::PadV2>(input, paddings, constant_values, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Pow.cpp b/compiler/luci-interpreter/src/loader/nodes/Pow.cpp
new file mode 100644
index 000000000..d32fc3dbb
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Pow.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 "Builders.h"
+
+#include "kernels/Pow.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CirclePow(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CirclePow *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input1 = helper.getInputTensor(node->x());
+ const Tensor *input2 = helper.getInputTensor(node->y());
+
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Pow>(input1, input2, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Quantize.cpp b/compiler/luci-interpreter/src/loader/nodes/Quantize.cpp
new file mode 100644
index 000000000..cb36fb6da
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Quantize.cpp
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/Quantize.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleQuantize(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleQuantize *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Quantize>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/ReduceMax.cpp b/compiler/luci-interpreter/src/loader/nodes/ReduceMax.cpp
new file mode 100644
index 000000000..1a8522dd6
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/ReduceMax.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/ReduceMax.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleReduceMax(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleReduceMax *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *axes = helper.getInputTensor(node->reduction_indices());
+ Tensor *output = helper.getOutputTensor(node);
+
+ auto temp_index_unique =
+ std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, "");
+ temp_index_unique->set_observable(false);
+ temp_index_unique->set_data_buffer(nullptr);
+ Tensor *temp_index =
+ helper.getRuntimeGraph(node->graph())->addTensor(std::move(temp_index_unique));
+
+ auto resolved_axes_unique =
+ std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, "");
+ resolved_axes_unique->set_observable(false);
+ resolved_axes_unique->set_data_buffer(nullptr);
+ Tensor *resolved_axes =
+ helper.getRuntimeGraph(node->graph())->addTensor(std::move(resolved_axes_unique));
+
+ ReducerParams params{};
+ params.keep_dims = node->keep_dims();
+
+ return std::make_unique<kernels::ReduceMax>(input, axes, output, temp_index, resolved_axes,
+ params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/ReduceProd.cpp b/compiler/luci-interpreter/src/loader/nodes/ReduceProd.cpp
new file mode 100644
index 000000000..1610e20a9
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/ReduceProd.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/ReduceProd.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleReduceProd(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleReduceProd *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *axes = helper.getInputTensor(node->reduction_indices());
+ Tensor *output = helper.getOutputTensor(node);
+
+ auto temp_index_unique =
+ std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, "");
+ temp_index_unique->set_observable(false);
+ temp_index_unique->set_data_buffer(nullptr);
+ Tensor *temp_index =
+ helper.getRuntimeGraph(node->graph())->addTensor(std::move(temp_index_unique));
+
+ auto resolved_axes_unique =
+ std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, "");
+ resolved_axes_unique->set_observable(false);
+ resolved_axes_unique->set_data_buffer(nullptr);
+ Tensor *resolved_axes =
+ helper.getRuntimeGraph(node->graph())->addTensor(std::move(resolved_axes_unique));
+
+ ReducerParams params{};
+ params.keep_dims = node->keep_dims();
+
+ return std::make_unique<kernels::ReduceProd>(input, axes, output, temp_index, resolved_axes,
+ params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Relu.cpp b/compiler/luci-interpreter/src/loader/nodes/Relu.cpp
new file mode 100644
index 000000000..1d64c1c4e
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Relu.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Relu.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleRelu(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleRelu *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->features());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Relu>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Relu6.cpp b/compiler/luci-interpreter/src/loader/nodes/Relu6.cpp
new file mode 100644
index 000000000..e50cd2545
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Relu6.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Relu6.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleRelu6(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleRelu6 *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->features());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Relu6>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Reshape.cpp b/compiler/luci-interpreter/src/loader/nodes/Reshape.cpp
new file mode 100644
index 000000000..76ddd88a3
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Reshape.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 "Builders.h"
+
+#include "kernels/Reshape.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleReshape(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleReshape *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input = helper.getInputTensor(node->tensor());
+ const Tensor *shape = helper.getInputTensor(node->shape());
+ Tensor *output = helper.getOutputTensor(node);
+
+ // NOTE 'newShape' attribute is ignored.
+ return std::make_unique<kernels::Reshape>(input, shape, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/ResizeBilinear.cpp b/compiler/luci-interpreter/src/loader/nodes/ResizeBilinear.cpp
new file mode 100644
index 000000000..dc2b88ad3
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/ResizeBilinear.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 "Builders.h"
+
+#include "kernels/ResizeBilinear.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleResizeBilinear(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleResizeBilinear *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *size = helper.getInputTensor(node->size());
+ Tensor *output = helper.getOutputTensor(node);
+
+ ResizeBilinearParams params{};
+ params.align_corners = node->align_corners();
+ params.half_pixel_centers = node->half_pixel_centers();
+
+ return std::make_unique<kernels::ResizeBilinear>(input, size, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/ResizeNearestNeighbor.cpp b/compiler/luci-interpreter/src/loader/nodes/ResizeNearestNeighbor.cpp
new file mode 100644
index 000000000..c7058ae78
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/ResizeNearestNeighbor.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/ResizeNearestNeighbor.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel>
+build_kernel_CircleResizeNearestNeighbor(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleResizeNearestNeighbor *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *size = helper.getInputTensor(node->size());
+ Tensor *output = helper.getOutputTensor(node);
+
+ ResizeNearestNeighborParams params{};
+ params.align_corners = node->align_corners();
+ // TODO update half_pixel_centers after CircleResizeNearestNeighbor updated
+ // Current CircleResizeNearestNeighbor don't have half_pixel_centers.
+ // default value on current is false.
+ // it need to be updated when CircleResizeNearestNeighbor updated.
+ params.half_pixel_centers = false;
+
+ return std::make_unique<kernels::ResizeNearestNeighbor>(input, size, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/ReverseV2.cpp b/compiler/luci-interpreter/src/loader/nodes/ReverseV2.cpp
new file mode 100644
index 000000000..c1a7f5350
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/ReverseV2.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/ReverseV2.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleReverseV2(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleReverseV2 *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input = helper.getInputTensor(node->tensor());
+ const Tensor *axes = helper.getInputTensor(node->axis());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::ReverseV2>(input, axes, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Rsqrt.cpp b/compiler/luci-interpreter/src/loader/nodes/Rsqrt.cpp
new file mode 100644
index 000000000..0714a5dba
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Rsqrt.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Rsqrt.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleRsqrt(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleRsqrt *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->x());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Rsqrt>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/SVDF.cpp b/compiler/luci-interpreter/src/loader/nodes/SVDF.cpp
new file mode 100644
index 000000000..d172ef438
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/SVDF.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/SVDF.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleSVDF(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleSVDF *>(circle_node);
+ assert(node->arity() == 5);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *feature = helper.getInputTensor(node->weight_feature());
+ const Tensor *time = helper.getInputTensor(node->weight_time());
+ const Tensor *bias = helper.getOptionalInputTensor(node->bias());
+ const Tensor *input_activation_state = helper.getInputTensor(node->input_activation_state());
+ Tensor *output = helper.getOutputTensor(node);
+
+ auto scratchpad_tensor = std::make_unique<Tensor>(input_activation_state->element_type(),
+ Shape({}), AffineQuantization{}, "");
+ scratchpad_tensor->set_observable(false);
+ scratchpad_tensor->set_data_buffer(nullptr);
+ Tensor *tmp = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad_tensor));
+
+ DataType data_type = input->element_type() == DataType::S8 ? DataType::S32 : DataType::FLOAT32;
+
+ scratchpad_tensor = std::make_unique<Tensor>(data_type, Shape({}), AffineQuantization{}, "");
+ scratchpad_tensor->set_observable(false);
+ scratchpad_tensor->set_data_buffer(nullptr);
+ Tensor *tmp_1 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad_tensor));
+
+ if (data_type == DataType::FLOAT32 &&
+ (feature->element_type() == DataType::S8 || feature->element_type() == DataType::U8))
+ {
+ data_type = feature->element_type();
+ }
+
+ scratchpad_tensor = std::make_unique<Tensor>(data_type, Shape({}), AffineQuantization{}, "");
+ scratchpad_tensor->set_observable(false);
+ scratchpad_tensor->set_data_buffer(nullptr);
+ Tensor *tmp_2 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad_tensor));
+
+ data_type = DataType::FLOAT32;
+
+ scratchpad_tensor = std::make_unique<Tensor>(data_type, Shape({}), AffineQuantization{}, "");
+ scratchpad_tensor->set_observable(false);
+ scratchpad_tensor->set_data_buffer(nullptr);
+ Tensor *tmp_3 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad_tensor));
+
+ scratchpad_tensor = std::make_unique<Tensor>(data_type, Shape({}), AffineQuantization{}, "");
+ scratchpad_tensor->set_observable(false);
+ scratchpad_tensor->set_data_buffer(nullptr);
+ Tensor *tmp_4 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad_tensor));
+
+ scratchpad_tensor = std::make_unique<Tensor>(data_type, Shape({}), AffineQuantization{}, "");
+ scratchpad_tensor->set_observable(false);
+ scratchpad_tensor->set_data_buffer(nullptr);
+ Tensor *tmp_5 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad_tensor));
+
+ scratchpad_tensor = std::make_unique<Tensor>(data_type, Shape({}), AffineQuantization{}, "");
+ scratchpad_tensor->set_observable(false);
+ scratchpad_tensor->set_data_buffer(nullptr);
+ Tensor *tmp_6 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratchpad_tensor));
+
+ SVDFParams params{};
+ params.activation = node->fusedActivationFunction();
+ params.svdf_rank = node->svdf_rank();
+ params.asymmetric_quantize_inputs = node->asymmetric_quantize_inputs();
+
+ return std::make_unique<kernels::SVDF>(input, feature, time, bias, input_activation_state, output,
+ tmp, tmp_1, tmp_2, tmp_3, tmp_4, tmp_5, tmp_6, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Select.cpp b/compiler/luci-interpreter/src/loader/nodes/Select.cpp
new file mode 100644
index 000000000..a0f18047b
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Select.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/Select.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleSelect(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleSelect *>(circle_node);
+ assert(node->arity() == 3);
+
+ const Tensor *c = helper.getInputTensor(node->condition());
+ const Tensor *t = helper.getInputTensor(node->t());
+ const Tensor *e = helper.getInputTensor(node->e());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Select>(c, t, e, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Shape.cpp b/compiler/luci-interpreter/src/loader/nodes/Shape.cpp
new file mode 100644
index 000000000..d1edbc794
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Shape.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/Shape.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleShape(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleShape *>(circle_node);
+ assert(node->arity() == 1);
+
+ const auto input = helper.getInputTensor(node->input());
+ auto output = helper.getOutputTensor(node);
+
+ ShapeParams shape_params{};
+ shape_params.out_type = node->out_type();
+
+ return std::make_unique<kernels::ShapeKernel>(input, output, shape_params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Slice.cpp b/compiler/luci-interpreter/src/loader/nodes/Slice.cpp
new file mode 100644
index 000000000..60ac6417c
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Slice.cpp
@@ -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.
+ */
+
+#include "Builders.h"
+
+#include "kernels/Slice.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleSlice(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleSlice *>(circle_node);
+ assert(node->arity() == 3);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *begin = helper.getInputTensor(node->begin());
+ const Tensor *size = helper.getInputTensor(node->size());
+
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Slice>(input, begin, size, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Softmax.cpp b/compiler/luci-interpreter/src/loader/nodes/Softmax.cpp
new file mode 100644
index 000000000..f41f63f6f
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Softmax.cpp
@@ -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.
+ */
+
+#include "Builders.h"
+
+#include "kernels/Softmax.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleSoftmax(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleSoftmax *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->logits());
+ Tensor *output = helper.getOutputTensor(node);
+
+ SoftmaxParams params{};
+ params.beta = node->beta();
+
+ return std::make_unique<kernels::Softmax>(input, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/SpaceToBatchND.cpp b/compiler/luci-interpreter/src/loader/nodes/SpaceToBatchND.cpp
new file mode 100644
index 000000000..b6e6cf516
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/SpaceToBatchND.cpp
@@ -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.
+ */
+
+#include "Builders.h"
+
+#include "kernels/SpaceToBatchND.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleSpaceToBatchND(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleSpaceToBatchND *>(circle_node);
+ assert(node->arity() == 3);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *block_shape = helper.getInputTensor(node->block_shape());
+ const Tensor *paddings = helper.getInputTensor(node->paddings());
+
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::SpaceToBatchND>(input, block_shape, paddings, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/SpaceToDepth.cpp b/compiler/luci-interpreter/src/loader/nodes/SpaceToDepth.cpp
new file mode 100644
index 000000000..63fdb95ec
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/SpaceToDepth.cpp
@@ -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.
+ */
+
+#include "Builders.h"
+
+#include "kernels/SpaceToDepth.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleSpaceToDepth(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleSpaceToDepth *>(circle_node);
+ assert(node->arity() == 1);
+ const Tensor *input = helper.getInputTensor(node->input());
+
+ Tensor *output = helper.getOutputTensor(node);
+
+ SpaceToDepthParams params{};
+ params.block_size = node->block_size();
+
+ return std::make_unique<kernels::SpaceToDepth>(input, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Split.cpp b/compiler/luci-interpreter/src/loader/nodes/Split.cpp
new file mode 100644
index 000000000..3f6d4a7df
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Split.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 "Builders.h"
+
+#include "kernels/Split.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleSplit(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleSplit *>(circle_node);
+ auto output_nodes = collectOutputNodes<luci::CircleSplitOut>(node);
+ assert(node->arity() == 2);
+ assert(output_nodes.size() == static_cast<size_t>(node->num_split()));
+
+ const Tensor *axis = helper.getInputTensor(node->split_dim());
+ const Tensor *input = helper.getInputTensor(node->input());
+ std::vector<Tensor *> outputs = helper.getOutputTensors(output_nodes);
+
+ // NOTE 'num_splits' attribute is ignored.
+ return std::make_unique<kernels::Split>(axis, input, std::move(outputs));
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/SplitV.cpp b/compiler/luci-interpreter/src/loader/nodes/SplitV.cpp
new file mode 100644
index 000000000..0788822ca
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/SplitV.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 "Builders.h"
+
+#include "kernels/SplitV.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleSplitV(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleSplitV *>(circle_node);
+ auto output_nodes = collectOutputNodes<luci::CircleSplitVOut>(node);
+ assert(node->arity() == 3);
+ assert(output_nodes.size() == static_cast<size_t>(node->num_split()));
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *sizes_data = helper.getInputTensor(node->size_splits());
+ const Tensor *axis = helper.getInputTensor(node->split_dim());
+ std::vector<Tensor *> outputs = helper.getOutputTensors(output_nodes);
+
+ // NOTE 'num_splits' attribute is ignored.
+ return std::make_unique<kernels::SplitV>(input, sizes_data, axis, std::move(outputs));
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Sqrt.cpp b/compiler/luci-interpreter/src/loader/nodes/Sqrt.cpp
new file mode 100644
index 000000000..b9843fe0b
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Sqrt.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Sqrt.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleSqrt(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleSqrt *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->x());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Sqrt>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Square.cpp b/compiler/luci-interpreter/src/loader/nodes/Square.cpp
new file mode 100644
index 000000000..0ad7c1772
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Square.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Square.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleSquare(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleSquare *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->x());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Square>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/SquaredDifference.cpp b/compiler/luci-interpreter/src/loader/nodes/SquaredDifference.cpp
new file mode 100644
index 000000000..e4c6fd851
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/SquaredDifference.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/SquaredDifference.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleSquaredDifference(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleSquaredDifference *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input1 = helper.getInputTensor(node->x());
+ const Tensor *input2 = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::SquaredDifference>(input1, input2, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Squeeze.cpp b/compiler/luci-interpreter/src/loader/nodes/Squeeze.cpp
new file mode 100644
index 000000000..6885f8077
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Squeeze.cpp
@@ -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.
+ */
+
+#include "Builders.h"
+
+#include "kernels/Squeeze.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleSqueeze(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleSqueeze *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ Tensor *output = helper.getOutputTensor(node);
+
+ SqueezeParams params{};
+ params.squeeze_dims = node->squeeze_dims();
+
+ return std::make_unique<kernels::Squeeze>(input, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/StridedSlice.cpp b/compiler/luci-interpreter/src/loader/nodes/StridedSlice.cpp
new file mode 100644
index 000000000..359b4e3e9
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/StridedSlice.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 "Builders.h"
+
+#include "kernels/StridedSlice.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleStridedSlice(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleStridedSlice *>(circle_node);
+ assert(node->arity() == 4);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *begin = helper.getInputTensor(node->begin());
+ const Tensor *end = helper.getInputTensor(node->end());
+ const Tensor *strides = helper.getInputTensor(node->strides());
+
+ Tensor *output = helper.getOutputTensor(node);
+
+ StridedSliceParams params{};
+ params.begin_mask = node->begin_mask();
+ params.ellipsis_mask = node->ellipsis_mask();
+ params.end_mask = node->end_mask();
+ params.new_axis_mask = node->new_axis_mask();
+ params.shrink_axis_mask = node->shrink_axis_mask();
+
+ return std::make_unique<kernels::StridedSlice>(input, begin, end, strides, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Sub.cpp b/compiler/luci-interpreter/src/loader/nodes/Sub.cpp
new file mode 100644
index 000000000..a6252cb53
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Sub.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 "Builders.h"
+
+#include "kernels/Sub.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleSub(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleSub *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input1 = helper.getInputTensor(node->x());
+ const Tensor *input2 = helper.getInputTensor(node->y());
+ Tensor *output = helper.getOutputTensor(node);
+
+ SubParams params{};
+ params.activation = node->fusedActivationFunction();
+
+ return std::make_unique<kernels::Sub>(input1, input2, output, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Sum.cpp b/compiler/luci-interpreter/src/loader/nodes/Sum.cpp
new file mode 100644
index 000000000..6dfe362c9
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Sum.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2023 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 "Builders.h"
+
+#include "kernels/Sum.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleSum(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleSum *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *axes = helper.getInputTensor(node->reduction_indices());
+ Tensor *output = helper.getOutputTensor(node);
+
+ auto temp_index_unique =
+ std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, "");
+ temp_index_unique->set_observable(false);
+ temp_index_unique->set_data_buffer(nullptr);
+ Tensor *temp_index =
+ helper.getRuntimeGraph(node->graph())->addTensor(std::move(temp_index_unique));
+
+ auto resolved_axes_unique =
+ std::make_unique<Tensor>(DataType::S32, Shape({}), AffineQuantization{}, "");
+ resolved_axes_unique->set_observable(false);
+ resolved_axes_unique->set_data_buffer(nullptr);
+ Tensor *resolved_axes =
+ helper.getRuntimeGraph(node->graph())->addTensor(std::move(resolved_axes_unique));
+
+ ReducerParams params{};
+ params.keep_dims = node->keep_dims();
+
+ return std::make_unique<kernels::Sum>(input, axes, output, temp_index, resolved_axes, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Tanh.cpp b/compiler/luci-interpreter/src/loader/nodes/Tanh.cpp
new file mode 100644
index 000000000..a58ef60a8
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Tanh.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Tanh.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleTanh(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleTanh *>(circle_node);
+ assert(node->arity() == 1);
+
+ const Tensor *input = helper.getInputTensor(node->x());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Tanh>(input, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Transpose.cpp b/compiler/luci-interpreter/src/loader/nodes/Transpose.cpp
new file mode 100644
index 000000000..ea17d8311
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Transpose.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Transpose.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleTranspose(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleTranspose *>(circle_node);
+ assert(node->arity() == 2);
+
+ const Tensor *input = helper.getInputTensor(node->a());
+ const Tensor *perm = helper.getInputTensor(node->perm());
+ Tensor *output = helper.getOutputTensor(node);
+
+ return std::make_unique<kernels::Transpose>(input, perm, output);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/TransposeConv.cpp b/compiler/luci-interpreter/src/loader/nodes/TransposeConv.cpp
new file mode 100644
index 000000000..72d1aecf7
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/TransposeConv.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/TransposeConv.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleTransposeConv(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleTransposeConv *>(circle_node);
+ assert(node->arity() == 4);
+
+ const Tensor *input_sizes = helper.getInputTensor(node->inputSizes());
+ const Tensor *filter = helper.getInputTensor(node->filter());
+ const Tensor *out_backprop = helper.getInputTensor(node->outBackprop());
+ const Tensor *bias = helper.getOptionalInputTensor(node->bias());
+
+ Tensor *output = helper.getOutputTensor(node);
+
+ DataType scratch_data_type =
+ helper.getInputTensor(node)->element_type() == DataType::S16 ? DataType::S64 : DataType::S32;
+
+ auto scratch_tensor =
+ std::make_unique<Tensor>(scratch_data_type, Shape({}), AffineQuantization{}, "");
+ scratch_tensor->set_observable(false);
+ scratch_tensor->set_data_buffer(nullptr);
+ Tensor *tmp = helper.getRuntimeGraph(node->graph())->addTensor(std::move(scratch_tensor));
+
+ TransposeConvParams params{};
+ params.padding = node->padding();
+ params.stride_height = node->stride()->h();
+ params.stride_width = node->stride()->w();
+ params.activation = node->fusedActivationFunction();
+
+ // TODO support activation
+ if (params.activation != luci::FusedActFunc::NONE)
+ {
+ throw std::runtime_error("Unsupported activation of TransposeConv");
+ }
+
+ return std::make_unique<kernels::TransposeConv>(input_sizes, filter, out_backprop, bias, output,
+ tmp, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/UnidirectionalSequenceLSTM.cpp b/compiler/luci-interpreter/src/loader/nodes/UnidirectionalSequenceLSTM.cpp
new file mode 100644
index 000000000..f4cf0b869
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/UnidirectionalSequenceLSTM.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
+ * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "Builders.h"
+
+#include "kernels/UnidirectionalSequenceLSTM.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel>
+build_kernel_CircleUnidirectionalSequenceLSTM(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleUnidirectionalSequenceLSTM *>(circle_node);
+ assert(node->arity() == 24);
+
+ const Tensor *input = helper.getInputTensor(node->input());
+ const Tensor *input_to_input_weights =
+ helper.getOptionalInputTensor(node->input_to_input_weights());
+ const Tensor *input_to_cell_weights = helper.getInputTensor(node->input_to_cell_weights());
+ const Tensor *input_to_forget_weights = helper.getInputTensor(node->input_to_forget_weights());
+ const Tensor *input_to_output_weights = helper.getInputTensor(node->input_to_output_weights());
+ const Tensor *recurrent_to_input_weights =
+ helper.getOptionalInputTensor(node->recurrent_to_input_weights());
+ const Tensor *recurrent_to_cell_weights =
+ helper.getInputTensor(node->recurrent_to_cell_weights());
+ const Tensor *recurrent_to_forget_weights =
+ helper.getInputTensor(node->recurrent_to_forget_weights());
+ const Tensor *recurrent_to_output_weights =
+ helper.getInputTensor(node->recurrent_to_output_weights());
+ const Tensor *cell_to_input_weights =
+ helper.getOptionalInputTensor(node->cell_to_input_weights());
+ const Tensor *cell_to_forget_weights =
+ helper.getOptionalInputTensor(node->cell_to_forget_weights());
+ const Tensor *cell_to_output_weights =
+ helper.getOptionalInputTensor(node->cell_to_output_weights());
+ const Tensor *input_gate_bias = helper.getOptionalInputTensor(node->input_gate_bias());
+ const Tensor *forget_gate_bias = helper.getInputTensor(node->forget_gate_bias());
+ const Tensor *cell_gate_bias = helper.getInputTensor(node->cell_gate_bias());
+ const Tensor *output_gate_bias = helper.getInputTensor(node->output_gate_bias());
+ const Tensor *projection_weights = helper.getOptionalInputTensor(node->projection_weights());
+ const Tensor *projection_bias = helper.getOptionalInputTensor(node->projection_bias());
+ const Tensor *output_state = helper.getInputTensor(node->output_state());
+ const Tensor *cell_state = helper.getInputTensor(node->cell_state());
+ const Tensor *input_layer_norm_coefficients =
+ helper.getOptionalInputTensor(node->input_layer_norm_coefficients());
+ const Tensor *forget_layer_norm_coefficients =
+ helper.getOptionalInputTensor(node->forget_layer_norm_coefficients());
+ const Tensor *cell_layer_norm_coefficients =
+ helper.getOptionalInputTensor(node->cell_layer_norm_coefficients());
+ const Tensor *output_layer_norm_coefficients =
+ helper.getOptionalInputTensor(node->output_layer_norm_coefficients());
+ Tensor *output = helper.getOutputTensor(node);
+
+ // scratch pad tensor
+ // NOTE provide more scratch pads if support hybrid or integer
+ auto sp_output_state =
+ std::make_unique<Tensor>(output_state->element_type(), Shape({}), AffineQuantization{}, "");
+ sp_output_state->set_observable(false);
+ sp_output_state->set_data_buffer(nullptr);
+ Tensor *tmp_1 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(sp_output_state));
+
+ auto sp_cell_state =
+ std::make_unique<Tensor>(cell_state->element_type(), Shape({}), AffineQuantization{}, "");
+ sp_cell_state->set_observable(false);
+ sp_cell_state->set_data_buffer(nullptr);
+ Tensor *tmp_2 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(sp_cell_state));
+
+ auto sp_3 = std::make_unique<Tensor>(input->element_type(), Shape({}), AffineQuantization{}, "");
+ sp_3->set_observable(false);
+ sp_3->set_data_buffer(nullptr);
+ Tensor *tmp_3 = helper.getRuntimeGraph(node->graph())->addTensor(std::move(sp_3));
+
+ UnidirectionalSequenceLSTMParams params{};
+ params.activation = node->fusedActivationFunction();
+ params.cell_clip = node->cell_clip();
+ params.proj_clip = node->proj_clip();
+ params.time_major = node->time_major();
+ params.asymmetric_quantize_inputs = node->asymmetric_quantize_inputs();
+
+ return std::make_unique<kernels::UnidirectionalSequenceLSTM>(
+ input, input_to_input_weights, input_to_forget_weights, input_to_cell_weights,
+ input_to_output_weights, recurrent_to_input_weights, recurrent_to_forget_weights,
+ recurrent_to_cell_weights, recurrent_to_output_weights, cell_to_input_weights,
+ cell_to_forget_weights, cell_to_output_weights, input_gate_bias, forget_gate_bias,
+ cell_gate_bias, output_gate_bias, projection_weights, projection_bias, output_state, cell_state,
+ input_layer_norm_coefficients, forget_layer_norm_coefficients, cell_layer_norm_coefficients,
+ output_layer_norm_coefficients, output, tmp_1, tmp_2, tmp_3, params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/Unpack.cpp b/compiler/luci-interpreter/src/loader/nodes/Unpack.cpp
new file mode 100644
index 000000000..a1c0d323a
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/Unpack.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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 "Builders.h"
+
+#include "kernels/Unpack.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleUnpack(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleUnpack *>(circle_node);
+ auto output_nodes = collectOutputNodes<luci::CircleUnpackOut>(node);
+ assert(node->arity() == 1);
+ assert(output_nodes.size() == static_cast<size_t>(node->num()));
+
+ const Tensor *input = helper.getInputTensor(node->value());
+ std::vector<Tensor *> outputs = helper.getOutputTensors(output_nodes);
+
+ UnpackParams params{};
+ params.axis = node->axis();
+
+ // NOTE 'num' attribute is ignored.
+ return std::make_unique<kernels::Unpack>(input, std::move(outputs), params);
+}
+
+} // namespace luci_interpreter
diff --git a/compiler/luci-interpreter/src/loader/nodes/While.cpp b/compiler/luci-interpreter/src/loader/nodes/While.cpp
new file mode 100644
index 000000000..8fde6ec8a
--- /dev/null
+++ b/compiler/luci-interpreter/src/loader/nodes/While.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 "Builders.h"
+
+#include "kernels/While.h"
+
+namespace luci_interpreter
+{
+
+std::unique_ptr<Kernel> build_kernel_CircleWhile(const luci::CircleNode *circle_node,
+ KernelBuilderHelper &helper)
+{
+ const auto *node = loco::must_cast<const luci::CircleWhile *>(circle_node);
+
+ auto output_nodes = collectOutputNodes<luci::CircleWhileOut>(node);
+ assert(node->arity() == node->input_count());
+ assert(output_nodes.size() == static_cast<size_t>(node->output_count()));
+
+ std::vector<const Tensor *> inputs(node->input_count());
+ for (uint32_t i = 0; i < node->input_count(); ++i)
+ {
+ inputs[i] = helper.getInputTensor(node->input(i));
+ }
+ std::vector<Tensor *> outputs = helper.getOutputTensors(output_nodes);
+
+ RuntimeGraph *cond_graph = helper.getRuntimeGraph(node->cond_graph());
+ RuntimeGraph *body_graph = helper.getRuntimeGraph(node->body_graph());
+
+ return std::make_unique<kernels::While>(std::move(inputs), std::move(outputs), cond_graph,
+ body_graph);
+}
+
+} // namespace luci_interpreter