summaryrefslogtreecommitdiff
path: root/runtime/contrib/pure_arm_compute/src
diff options
context:
space:
mode:
Diffstat (limited to 'runtime/contrib/pure_arm_compute/src')
-rw-r--r--runtime/contrib/pure_arm_compute/src/compilation.cc6434
-rw-r--r--runtime/contrib/pure_arm_compute/src/compilation.h75
-rw-r--r--runtime/contrib/pure_arm_compute/src/event.cc31
-rw-r--r--runtime/contrib/pure_arm_compute/src/event.h33
-rw-r--r--runtime/contrib/pure_arm_compute/src/execution.cc628
-rw-r--r--runtime/contrib/pure_arm_compute/src/execution.h119
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/FeatureSink.h80
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/FeatureSource.h77
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/IExecutionBuilder.h49
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/MatrixSink.h91
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/MatrixSource.h82
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/Model.cc128
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/Model.h538
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/Sink.h45
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/Sinks.h97
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/Source.h46
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/Swizzle.h115
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/Tensor3DSink.h89
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/Tensor3DSource.h89
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/TensorSource.h83
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/VectorSink.h73
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/VectorSource.h69
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/arm_compute.cc87
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/arm_compute.h337
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/arm_compute/Cast.cc152
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/arm_compute/Cast.h156
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/arm_compute/feature/View.h156
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/arm_compute/kernel/View.h110
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/arm_compute/matrix/View.h104
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/arm_compute/tensor/View.h112
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/Reader.h105
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/Utils.h82
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/View.h132
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/nnapi/kernel/Reader.h94
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/nnapi/matrix/Reader.h90
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/ConstView.h111
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/Reader.h116
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/View.h121
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Abs.cc59
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Abs.h68
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Add.cc67
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Add.h110
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ArgMax.cc64
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ArgMax.h70
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/AvgPool2D.cc124
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/AvgPool2D.h198
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/BatchToSpaceNd.cc63
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/BatchToSpaceNd.h83
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Cast.cc62
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Cast.h108
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Concat.cc69
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Concat.h109
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Conv2D.cc126
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Conv2D.h200
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/DepthToSpace.cc65
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/DepthToSpace.h70
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/DepthwiseConv2D.cc128
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/DepthwiseConv2D.h198
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Dequantize.cc62
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Dequantize.h106
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Div.cc67
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Div.h108
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/EmbeddingLookup.cc65
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/EmbeddingLookup.h109
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Equal.cc65
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Equal.h83
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Exp.cc63
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Exp.h69
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Floor.cc62
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Floor.h108
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/FullyConnected.cc69
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/FullyConnected.h114
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Gather.cc67
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Gather.h109
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/HashtableLookup.cc68
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/HashtableLookup.h109
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/L2Normalization.cc60
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/L2Normalization.h106
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/L2Pool2D.cc124
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/L2Pool2D.h198
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/LocalResponseNormalization.cc64
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/LocalResponseNormalization.h73
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/LogicalAnd.cc65
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/LogicalAnd.h83
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/LogicalNot.cc60
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/LogicalNot.h82
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/LogicalOr.cc65
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/LogicalOr.h83
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Logistic.cc63
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Logistic.h105
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Lstm.cc85
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Lstm.h131
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/MaxPool2D.cc124
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/MaxPool2D.h202
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Mean.cc67
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Mean.h108
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Mul.cc67
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Mul.h106
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Neg.cc63
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Neg.h69
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Node.h60
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/NodeVisitor.h493
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/NotEqual.cc65
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/NotEqual.h83
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/PReLU.cc65
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/PReLU.h109
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Pack.cc69
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Pack.h72
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Pad.cc63
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Pad.h107
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/RSQRT.cc62
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/RSQRT.h105
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ReLU.cc63
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ReLU.h108
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ReLU1.cc63
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ReLU1.h108
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ReLU6.cc63
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ReLU6.h104
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ReduceMax.cc65
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ReduceMax.h107
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ReduceMin.cc65
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ReduceMin.h107
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ReduceSum.cc65
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ReduceSum.h70
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Reshape.cc66
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Reshape.h108
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ResizeBilinear.cc67
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/ResizeBilinear.h108
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Rnn.cc66
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Rnn.h113
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/SQRT.cc62
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/SQRT.h105
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Softmax.cc65
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Softmax.h109
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/SpaceToBatchND.cc67
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/SpaceToBatchND.h71
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/SpaceToDepth.cc65
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/SpaceToDepth.h109
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Split.cc72
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Split.h109
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/SquaredDifference.cc64
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/SquaredDifference.h106
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Squeeze.cc66
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Squeeze.h108
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/StridedSlice.cc88
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/StridedSlice.h113
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Sub.cc67
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Sub.h109
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Tanh.cc63
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Tanh.h107
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/TopKV2.cc70
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/TopKV2.h110
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Transpose.cc65
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Transpose.h109
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/TransposeConv.cc74
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/TransposeConv.h74
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Unpack.cc68
-rw-r--r--runtime/contrib/pure_arm_compute/src/internal/op/Unpack.h72
-rw-r--r--runtime/contrib/pure_arm_compute/src/library_info.cc17
-rw-r--r--runtime/contrib/pure_arm_compute/src/logging.h74
-rw-r--r--runtime/contrib/pure_arm_compute/src/memory.cc55
-rw-r--r--runtime/contrib/pure_arm_compute/src/memory.h69
-rw-r--r--runtime/contrib/pure_arm_compute/src/model.cc1082
-rw-r--r--runtime/contrib/pure_arm_compute/src/model.h70
164 files changed, 23536 insertions, 0 deletions
diff --git a/runtime/contrib/pure_arm_compute/src/compilation.cc b/runtime/contrib/pure_arm_compute/src/compilation.cc
new file mode 100644
index 000000000..8cc86ebae
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/compilation.cc
@@ -0,0 +1,6434 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file compilation.cc
+ * @brief This file contains ANeuralNetworksCompilation APIs and related classes
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#include <NeuralNetworks.h>
+
+// For CLKernelLibraryEx initialization
+#include "arm_compute/core/CL/CLHelpers.h"
+#include "arm_compute/core/CL/CLKernelLibrary.h"
+#include "arm_compute/core/CL/CLKernelLibraryEx.h"
+
+#include <arm_compute/runtime/IFunction.h>
+#include <arm_compute/runtime/CL/CLScheduler.h>
+#include <arm_compute/runtime/CL/CLSubTensor.h>
+#include <arm_compute/runtime/CL/CLFunctions.h> // Include all ARM Compute CL functions
+#include <arm_compute/runtime/CL/CLFunctionsEx.h> // Include all ARM Compute EX CL functions
+
+#include <arm_compute/runtime/SubTensor.h>
+#include <arm_compute/runtime/NEON/NEFunctions.h> // Include all ARM Compute NEON functions
+#include <arm_compute/runtime/NEON/NEFunctionsEx.h> // Include all ARM Compute EX NEON functions
+
+#include "internal/arm_compute.h"
+#include "internal/arm_compute/Cast.h"
+#include "internal/arm_compute/matrix/View.h"
+#include "internal/arm_compute/kernel/View.h"
+#include "internal/nnapi/matrix/Reader.h"
+#include "internal/nnapi/kernel/Reader.h"
+#include "internal/nnapi/feature/Reader.h"
+#include "internal/nnapi/feature/View.h"
+#include "internal/nnapi/tensor/Reader.h"
+#include "internal/arm_compute/feature/View.h"
+#include "internal/arm_compute/tensor/View.h"
+
+#include <arm_compute/runtime/misc/functions/GenericReshapeLayer.h>
+#include <arm_compute/runtime/misc/functions/GenericGather.h>
+
+#include "misc/matrix/IndexIterator.h"
+#include "misc/kernel/IndexIterator.h"
+#include "misc/feature/IndexIterator.h"
+#include "misc/tensor/IndexIterator.h"
+
+#include <cpp14/memory.h>
+
+#include "compilation.h"
+#include "model.h"
+#include "logging.h"
+
+using namespace arm_compute::misc;
+
+template <typename T> T from_env(const char *);
+
+template <> bool from_env(const char *s)
+{
+ if (s == nullptr)
+ {
+ return false;
+ }
+
+ return std::stoi(s) != 0;
+}
+
+const char *to_string(const PaddingCode &code)
+{
+ assert((ANEURALNETWORKS_PADDING_SAME == code) || (ANEURALNETWORKS_PADDING_VALID == code));
+
+ switch (code)
+ {
+ case ANEURALNETWORKS_PADDING_SAME:
+ return "ANEURALNETWORKS_PADDING_SAME";
+ case ANEURALNETWORKS_PADDING_VALID:
+ return "ANEURALNETWORKS_PADDING_VALID";
+ }
+
+ return nullptr;
+}
+
+struct Padding
+{
+ uint32_t top;
+ uint32_t bottom;
+ uint32_t left;
+ uint32_t right;
+};
+
+struct Stride
+{
+ uint32_t vertical;
+ uint32_t horizontal;
+};
+
+Padding valid_padding(void)
+{
+ //
+ // ANEURALNETWORKS_PADDING_VALID
+ //
+ // VALID padding. No padding.
+ //
+ // When the input size is not evenly divisible by the filter size,
+ // the input at the end that could not fill the whole filter tile
+ // will simply be ignored.
+ //
+ Padding padding;
+
+ padding.top = 0;
+ padding.bottom = 0;
+ padding.left = 0;
+ padding.right = 0;
+
+ return padding;
+}
+
+Padding same_padding(const nnfw::misc::feature::Shape &ifm_shape,
+ const nnfw::misc::feature::Shape &ofm_shape, const Stride &stride, uint32_t kw,
+ uint32_t kh)
+{
+ Padding padding;
+
+ // ANEURALNETWORKS_PADDING_SAME (from NNAPI spec)
+ //
+ // SAME padding. Padding on both ends are the "same":
+ //
+ // padding_to_beginning = total_padding / 2
+ // padding_to_end = (total_padding + 1)/2.
+ //
+ const int32_t vertical_needed_input = (ofm_shape.H - 1) * stride.vertical + kh;
+ const int32_t vertical_total_padding = std::max(0, vertical_needed_input - ifm_shape.H);
+
+ const int32_t horizontal_needed_input = (ofm_shape.W - 1) * stride.horizontal + kw;
+ const int32_t horizontal_total_padding = std::max(0, horizontal_needed_input - ifm_shape.W);
+
+ padding.top = vertical_total_padding / 2;
+ padding.bottom = (vertical_total_padding + 1) / 2;
+ padding.left = horizontal_total_padding / 2;
+ padding.right = (horizontal_total_padding + 1) / 2;
+
+ return padding;
+}
+
+::arm_compute::PadStrideInfo asPadStrideInfo(const Padding &padding, const Stride &stride)
+{
+ return ::arm_compute::PadStrideInfo{stride.horizontal,
+ stride.vertical,
+ padding.left,
+ padding.right,
+ padding.top,
+ padding.bottom,
+ ::arm_compute::DimensionRoundingType::FLOOR};
+}
+
+::arm_compute::ActivationLayerInfo asActInfo(FuseCode act)
+{
+ if (act == ANEURALNETWORKS_FUSED_NONE)
+ {
+ return ::arm_compute::ActivationLayerInfo();
+ }
+ else if (act == ANEURALNETWORKS_FUSED_RELU)
+ {
+ return ::arm_compute::ActivationLayerInfo(
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU);
+ }
+ else if (act == ANEURALNETWORKS_FUSED_RELU1)
+ {
+ return ::arm_compute::ActivationLayerInfo(
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 1.0f, -1.0f);
+ }
+ else if (act == ANEURALNETWORKS_FUSED_RELU6)
+ {
+ return ::arm_compute::ActivationLayerInfo(
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.0f, 0.0f);
+ }
+ else
+ {
+ throw std::runtime_error("Not supported, yet");
+ }
+}
+
+struct IAllocationContext
+{
+ virtual ~IAllocationContext() = default;
+
+ virtual ::arm_compute::ITensor *at(const ::internal::tflite::operand::Index &ind) const = 0;
+};
+
+#include "internal/IExecutionBuilder.h"
+
+using Initializer = std::function<void(::arm_compute::ITensor &)>;
+using Stage = std::function<void(const IAllocationContext &, IExecutionBuilder &)>;
+
+using namespace std::placeholders;
+
+template <typename T>
+static void initFeatureTensor(::arm_compute::ITensor &tensor,
+ const nnfw::misc::feature::Shape &feature_shape,
+ const uint8_t *feature_base, const size_t feature_size)
+{
+ const ::internal::nnapi::feature::Reader<T> from{
+ feature_shape, reinterpret_cast<const T *>(feature_base), feature_size};
+ ::internal::arm_compute::feature::View<T> into{&tensor};
+
+ ::nnfw::misc::feature::iterate(feature_shape)
+ << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
+ const auto value = from.at(batch, ch, row, col);
+ into.at(batch, ch, row, col) = value;
+ };
+}
+
+template <typename T>
+static void initVectorTensor(::arm_compute::ITensor &tensor, const uint8_t *vec_base,
+ const size_t vec_size)
+{
+ for (uint32_t n = 0; n < vec_size; ++n)
+ {
+ const ::arm_compute::Coordinates coordinate{n};
+
+ T *into = reinterpret_cast<T *>(tensor.ptr_to_element(coordinate));
+
+ const T *from = reinterpret_cast<const T *>(vec_base) + n;
+ const auto value = *from;
+
+ *into = value;
+ }
+}
+
+template <typename T>
+static void initTensor3D(::arm_compute::ITensor &tensor,
+ const nnfw::misc::tensor::Shape &tensor_shape, const uint8_t *tensor_base,
+ const size_t tensor_size)
+{
+ const ::internal::nnapi::tensor::Reader<T> from{
+ tensor_shape, reinterpret_cast<const T *>(tensor_base), tensor_size};
+ ::internal::arm_compute::tensor::View<T> into{&tensor};
+
+ ::nnfw::misc::tensor::iterate(tensor_shape) << [&](const nnfw::misc::tensor::Index &index_nnapi) {
+ ::nnfw::misc::tensor::Index index_ACL = ::nnfw::misc::tensor::copy_reverse(index_nnapi);
+ into.at(index_ACL) = from.at(index_nnapi);
+ };
+}
+
+template <typename T>
+static void initMatrixTensor(::arm_compute::ITensor &tensor,
+ const nnfw::misc::matrix::Shape &matrix_shape,
+ const uint8_t *matrix_base, const size_t matrix_size)
+{
+ const ::internal::nnapi::matrix::Reader<T> from{
+ matrix_shape, reinterpret_cast<const T *>(matrix_base), matrix_size};
+ ::internal::arm_compute::matrix::View<T> into{&tensor};
+
+ ::nnfw::misc::matrix::iterate(matrix_shape) << [&](uint32_t row, uint32_t col) {
+ const auto value = from.at(row, col);
+ into.at(row, col) = value;
+ };
+}
+
+template <typename T>
+static void initReorderVectorTensor(::arm_compute::ITensor &tensor, const uint8_t *vec_base,
+ const size_t vec_size)
+{
+ for (uint32_t n = 0; n < vec_size; ++n)
+ {
+ const ::arm_compute::Coordinates coordinate{ToARMComputeAxis(vec_size, n).value()};
+
+ T *into = reinterpret_cast<T *>(tensor.ptr_to_element(coordinate));
+
+ const T *from = reinterpret_cast<const T *>(vec_base) + n;
+ const auto value = *from;
+
+ *into = value;
+ }
+}
+
+template <typename T>
+static void initKernelTensor(::arm_compute::ITensor &tensor,
+ const nnfw::misc::kernel::Shape &kernel_shape,
+ const uint8_t *kernel_base, const size_t kernel_size)
+{
+ const ::internal::nnapi::kernel::Reader<T> from{
+ kernel_shape, reinterpret_cast<const T *>(kernel_base), kernel_size};
+ ::internal::arm_compute::kernel::View<T> into{&tensor};
+
+ ::nnfw::misc::kernel::iterate(kernel_shape)
+ << [&](uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) {
+ const auto value = from.at(nth, ch, row, col);
+ into.at(nth, ch, row, col) = value;
+ };
+}
+
+/**
+ * @brief Structure to provide interface methods of compilation plan builder
+ */
+struct IPlanBuilder
+{
+ /**
+ * @brief Destruct IPlanBuilder object using default destructor
+ */
+ virtual ~IPlanBuilder() = default;
+
+ /**
+ * @brief Add TensorInfo with Shape Constraints
+ * @param [in] ind Index of operand
+ * @param [in] info TensorInfo value to set to index of operand
+ * @return N/A
+ */
+ virtual void addShapeConstr(const ::internal::tflite::operand::Index &ind,
+ const ::arm_compute::TensorInfo &info) = 0;
+ /**
+ * @brief Add Subsumption constraints
+ * @param [in] ind Index of operand
+ * @param [in] base Index of base operand of Subsumption
+ * @param [in] offset Offset of Subsumption
+ * @param [in] shape Shape of Subsumption
+ * @param [in] extend_parent extend_parent value of Subsumption
+ * @return N/A
+ */
+ virtual void addSubsumptionConstr(const ::internal::tflite::operand::Index &ind,
+ const ::internal::tflite::operand::Index &base,
+ const ::arm_compute::Coordinates &offset,
+ const ::arm_compute::TensorShape &shape,
+ bool extend_parent = false) = 0;
+ /**
+ * @brief Add Initializer lambda with ITensor param
+ * @param [in] ind Index of operand
+ * @param [in] initializer Initializer to add
+ * @return N/A
+ */
+ virtual void addInitializer(const ::internal::tflite::operand::Index &ind,
+ const Initializer &initializer) = 0;
+ /**
+ * @brief Add Stage lambda with IAllocationContext and IExecutionBuilder params
+ * @param [in] stage Stage to add
+ * @return N/A
+ */
+ virtual void addStage(const Stage &stage) = 0;
+};
+
+//
+// ActivationBuilder
+//
+class ActivationBuilder
+{
+public:
+ ActivationBuilder(IExecutionBuilder &builder) : _builder(builder)
+ {
+ // DO NOTHING
+ }
+
+private:
+ void appendReLU(::arm_compute::ITensor *tensor);
+ void appendReLU6(::arm_compute::ITensor *tensor);
+ void appendReLU1(::arm_compute::ITensor *tensor);
+
+public:
+ void append(FuseCode code, ::arm_compute::ITensor *tensor);
+
+private:
+ IExecutionBuilder &_builder;
+};
+
+void ActivationBuilder::appendReLU(::arm_compute::ITensor *ifm_alloc)
+{
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>();
+
+ fn->configure(CAST_CL(ifm_alloc), nullptr, act_info);
+
+ _builder.append("ReLU", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>();
+
+ fn->configure(ifm_alloc, nullptr, act_info);
+
+ _builder.append("ReLU", std::move(fn));
+ }
+}
+
+void ActivationBuilder::appendReLU1(::arm_compute::ITensor *ifm_alloc)
+{
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 1.0f, -1.0f};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>();
+
+ fn->configure(CAST_CL(ifm_alloc), nullptr, act_info);
+
+ _builder.append("ReLU1", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>();
+
+ fn->configure(ifm_alloc, nullptr, act_info);
+
+ _builder.append("ReLU1", std::move(fn));
+ }
+}
+
+void ActivationBuilder::appendReLU6(::arm_compute::ITensor *ifm_alloc)
+{
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.0f, 0.0f};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>();
+
+ fn->configure(CAST_CL(ifm_alloc), nullptr, act_info);
+
+ _builder.append("ReLU6", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>();
+
+ fn->configure(ifm_alloc, nullptr, act_info);
+
+ _builder.append("ReLU6", std::move(fn));
+ }
+}
+
+void ActivationBuilder::append(FuseCode code, ::arm_compute::ITensor *ifm_alloc)
+{
+ switch (code)
+ {
+ case ANEURALNETWORKS_FUSED_NONE:
+ {
+ // DO NOTHING
+ break;
+ }
+ case ANEURALNETWORKS_FUSED_RELU:
+ {
+ appendReLU(ifm_alloc);
+ break;
+ }
+ case ANEURALNETWORKS_FUSED_RELU1:
+ {
+ appendReLU1(ifm_alloc);
+ break;
+ }
+ case ANEURALNETWORKS_FUSED_RELU6:
+ {
+ appendReLU6(ifm_alloc);
+ break;
+ }
+ default:
+ {
+ throw std::runtime_error("Not supported, yet");
+ }
+ }
+}
+
+class Planner : public ::internal::tflite::op::NodeVisitor
+{
+public:
+ Planner(const ::internal::tflite::operand::Set &ctx, IPlanBuilder &builder)
+ : _ctx{ctx}, _builder{builder}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void visit(const ::internal::tflite::op::Add::Node &node) override;
+ void visit(const ::internal::tflite::op::Sub::Node &node) override;
+ void visit(const ::internal::tflite::op::Mul::Node &node) override;
+ void visit(const ::internal::tflite::op::Div::Node &node) override;
+ void visit(const ::internal::tflite::op::Conv2D::Implicit::Node &node) override;
+ void visit(const ::internal::tflite::op::Conv2D::Explicit::Node &node) override;
+ void visit(const ::internal::tflite::op::DepthwiseConv2D::Implicit::Node &node) override;
+ void visit(const ::internal::tflite::op::DepthwiseConv2D::Explicit::Node &node) override;
+ void visit(const ::internal::tflite::op::Dequantize::Node &node) override;
+ void visit(const ::internal::tflite::op::MaxPool2D::Implicit::Node &node) override;
+ void visit(const ::internal::tflite::op::MaxPool2D::Explicit::Node &node) override;
+ void visit(const ::internal::tflite::op::AvgPool2D::Implicit::Node &node) override;
+ void visit(const ::internal::tflite::op::AvgPool2D::Explicit::Node &node) override;
+ void visit(const ::internal::tflite::op::Concat::Node &node) override;
+ void visit(const ::internal::tflite::op::FullyConnected::Node &node) override;
+ void visit(const ::internal::tflite::op::ResizeBilinear::Node &node) override;
+ void visit(const ::internal::tflite::op::Reshape::Node &node) override;
+ void visit(const ::internal::tflite::op::Squeeze::Node &node) override;
+ void visit(const ::internal::tflite::op::Softmax::Node &node) override;
+ void visit(const ::internal::tflite::op::StridedSlice::Node &node) override;
+ void visit(const ::internal::tflite::op::ReduceMax::Node &node) override;
+ void visit(const ::internal::tflite::op::ReduceMin::Node &node) override;
+ void visit(const ::internal::tflite::op::Cast::Node &node) override;
+ void visit(const ::internal::tflite::op::TopKV2::Node &node) override;
+ void visit(const ::internal::tflite::op::Gather::Node &node) override;
+ void visit(const ::internal::tflite::op::PReLU::Node &node) override;
+ void visit(const ::internal::tflite::op::ReLU::Node &node) override;
+ void visit(const ::internal::tflite::op::ReLU1::Node &node) override;
+ void visit(const ::internal::tflite::op::ReLU6::Node &node) override;
+ void visit(const ::internal::tflite::op::Tanh::Node &node) override;
+ void visit(const ::internal::tflite::op::Logistic::Node &node) override;
+ void visit(const ::internal::tflite::op::Mean::Node &node) override;
+ void visit(const ::internal::tflite::op::RNN::Node &node) override;
+ void visit(const ::internal::tflite::op::Transpose::Node &node) override;
+ void visit(const ::internal::tflite::op::LSTM::Node &node) override;
+ void visit(const ::internal::tflite::op::Floor::Node &node) override;
+ void visit(const ::internal::tflite::op::Split::Node &node) override;
+ void visit(const ::internal::tflite::op::ArgMax::Node &node) override;
+ void visit(const ::internal::tflite::op::RSQRT::Node &node) override;
+ void visit(const ::internal::tflite::op::SQRT::Node &node) override;
+ void visit(const ::internal::tflite::op::Pad::Node &node) override;
+ void visit(const ::internal::tflite::op::SpaceToDepth::Node &node) override;
+ void visit(const ::internal::tflite::op::SpaceToBatchND::Node &node) override;
+ void visit(const ::internal::tflite::op::BatchToSpaceNd::Node &node) override;
+ void visit(const ::internal::tflite::op::L2Pool2D::Implicit::Node &node) override;
+ void visit(const ::internal::tflite::op::L2Pool2D::Explicit::Node &node) override;
+ void visit(const ::internal::tflite::op::EmbeddingLookup::Node &node) override;
+ void visit(const ::internal::tflite::op::HashtableLookup::Node &node) override;
+ void visit(const ::internal::tflite::op::L2Normalization::Node &node) override;
+ void visit(const ::internal::tflite::op::SquaredDifference::Node &node) override;
+ void visit(const ::internal::tflite::op::LocalResponseNormalization::Node &node) override;
+ void visit(const ::internal::tflite::op::DepthToSpace::Node &node) override;
+ void visit(const ::internal::tflite::op::Unpack::Node &node) override;
+ void visit(const ::internal::tflite::op::Neg::Node &node) override;
+ void visit(const ::internal::tflite::op::Exp::Node &node) override;
+ void visit(const ::internal::tflite::op::ReduceSum::Node &node) override;
+ void visit(const ::internal::tflite::op::Equal::Node &node) override;
+ void visit(const ::internal::tflite::op::TransposeConv::Node &node) override;
+ void visit(const ::internal::tflite::op::Pack::Node &node) override;
+ void visit(const ::internal::tflite::op::Abs::Node &node) override;
+ void visit(const ::internal::tflite::op::NotEqual::Node &node) override;
+ void visit(const ::internal::tflite::op::LogicalAnd::Node &node) override;
+ void visit(const ::internal::tflite::op::LogicalNot::Node &node) override;
+ void visit(const ::internal::tflite::op::LogicalOr::Node &node) override;
+
+private:
+ const ::internal::tflite::operand::Set &_ctx;
+ IPlanBuilder &_builder;
+};
+
+void Planner::visit(const ::internal::tflite::op::Add::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index lhs_index{node.param().lhs_index};
+ const ::internal::tflite::operand::Index rhs_index{node.param().rhs_index};
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ // TODO Should move to the place where the operand is handled, if it is possible.
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+
+ if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape()))
+ {
+ const auto broadcast_rank =
+ std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank());
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(lhs_index).shape())
+ .extendRank(broadcast_rank);
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(rhs_index).shape())
+ .extendRank(broadcast_rank);
+ }
+ _builder.addShapeConstr(
+ lhs_index, asTensorInfo(asTensorShape(_ctx.at(lhs_index).shape()), _ctx.at(lhs_index).type(),
+ _ctx.at(lhs_index).scale(), _ctx.at(lhs_index).zeroPoint()));
+ _builder.addShapeConstr(
+ rhs_index, asTensorInfo(asTensorShape(_ctx.at(rhs_index).shape()), _ctx.at(rhs_index).type(),
+ _ctx.at(rhs_index).scale(), _ctx.at(rhs_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int lhs_index;
+ int rhs_index;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.lhs_index = lhs_index.asInt();
+ param.rhs_index = rhs_index.asInt();
+
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ const auto lhs_shape = _ctx.at(lhs_index).shape();
+ const auto rhs_shape = _ctx.at(rhs_index).shape();
+ auto stage = [param, lhs_shape, rhs_shape](const IAllocationContext &ctx,
+ IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto lhs_alloc = ctx.at(::internal::tflite::operand::Index{param.lhs_index});
+ auto rhs_alloc = ctx.at(::internal::tflite::operand::Index{param.rhs_index});
+
+ std::unique_ptr<::arm_compute::IFunction> fn;
+
+ {
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto l = nnfw::cpp14::make_unique<::arm_compute::CLArithmeticAddition>();
+
+ // TODO Decide ConvertPolicy (WARP? SATURATE?) according to NN API specification
+ l->configure(CAST_CL(lhs_alloc), CAST_CL(rhs_alloc), CAST_CL(ofm_alloc),
+ ::arm_compute::ConvertPolicy::SATURATE);
+
+ fn = std::move(l);
+ }
+ else // NEON
+ {
+ auto l = nnfw::cpp14::make_unique<::arm_compute::NEArithmeticAddition>();
+
+ // TODO Decide ConvertPolicy (WARP? SATURATE?) according to NN API specification
+ l->configure(lhs_alloc, rhs_alloc, ofm_alloc, ::arm_compute::ConvertPolicy::SATURATE);
+
+ fn = std::move(l);
+ }
+ }
+
+ builder.append("Add", std::move(fn));
+
+ ActivationBuilder{builder}.append(param.activation, ofm_alloc);
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Sub::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index lhs_index{node.param().lhs_index};
+ const ::internal::tflite::operand::Index rhs_index{node.param().rhs_index};
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+
+ if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape()))
+ {
+ const auto broadcast_rank =
+ std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank());
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(lhs_index).shape())
+ .extendRank(broadcast_rank);
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(rhs_index).shape())
+ .extendRank(broadcast_rank);
+ }
+ _builder.addShapeConstr(
+ lhs_index, asTensorInfo(asTensorShape(_ctx.at(lhs_index).shape()), _ctx.at(lhs_index).type(),
+ _ctx.at(lhs_index).scale(), _ctx.at(lhs_index).zeroPoint()));
+ _builder.addShapeConstr(
+ rhs_index, asTensorInfo(asTensorShape(_ctx.at(rhs_index).shape()), _ctx.at(rhs_index).type(),
+ _ctx.at(rhs_index).scale(), _ctx.at(rhs_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int lhs_index;
+ int rhs_index;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.lhs_index = lhs_index.asInt();
+ param.rhs_index = rhs_index.asInt();
+
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto lhs_alloc = ctx.at(::internal::tflite::operand::Index{param.lhs_index});
+ auto rhs_alloc = ctx.at(::internal::tflite::operand::Index{param.rhs_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLArithmeticSubtraction>();
+
+ // TODO Decide ConvertPolicy (WARP? SATURATE?) according to NN API specification
+ fn->configure(CAST_CL(lhs_alloc), CAST_CL(rhs_alloc), CAST_CL(ofm_alloc),
+ ::arm_compute::ConvertPolicy::SATURATE);
+
+ builder.append("Sub", std::move(fn));
+ }
+ else // NEON
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEArithmeticSubtraction>();
+
+ // TODO Decide ConvertPolicy (WARP? SATURATE?) according to NN API specification
+ fn->configure(lhs_alloc, rhs_alloc, ofm_alloc, ::arm_compute::ConvertPolicy::SATURATE);
+
+ builder.append("Sub", std::move(fn));
+ }
+
+ ActivationBuilder{builder}.append(param.activation, ofm_alloc);
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Mul::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index lhs_index{node.param().lhs_index};
+ const ::internal::tflite::operand::Index rhs_index{node.param().rhs_index};
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ if (_ctx.at(ofm_index).scale() > 0)
+ {
+ assert(_ctx.at(ofm_index).scale() > _ctx.at(lhs_index).scale() * _ctx.at(rhs_index).scale());
+ }
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+
+ if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape()))
+ {
+ const auto broadcast_rank =
+ std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank());
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(lhs_index).shape())
+ .extendRank(broadcast_rank);
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(rhs_index).shape())
+ .extendRank(broadcast_rank);
+ }
+ _builder.addShapeConstr(
+ lhs_index, asTensorInfo(asTensorShape(_ctx.at(lhs_index).shape()), _ctx.at(lhs_index).type(),
+ _ctx.at(lhs_index).scale(), _ctx.at(lhs_index).zeroPoint()));
+ _builder.addShapeConstr(
+ rhs_index, asTensorInfo(asTensorShape(_ctx.at(rhs_index).shape()), _ctx.at(rhs_index).type(),
+ _ctx.at(rhs_index).scale(), _ctx.at(rhs_index).zeroPoint()));
+
+ struct Param
+ {
+ int ofm_index;
+ int lhs_index;
+ int rhs_index;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.lhs_index = lhs_index.asInt();
+ param.rhs_index = rhs_index.asInt();
+
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto lhs_input_alloc = ctx.at(::internal::tflite::operand::Index{param.lhs_index});
+ auto rhs_input_alloc = ctx.at(::internal::tflite::operand::Index{param.rhs_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLPixelWiseMultiplication>();
+
+ fn->configure(CAST_CL(lhs_input_alloc), CAST_CL(rhs_input_alloc), CAST_CL(output_alloc),
+ 1.0, // scale
+ arm_compute::ConvertPolicy::SATURATE,
+ arm_compute::RoundingPolicy::TO_NEAREST_EVEN);
+
+ builder.append("Mul", std::move(fn));
+ }
+ else // NEON
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEPixelWiseMultiplication>();
+
+ fn->configure(lhs_input_alloc, rhs_input_alloc, output_alloc,
+ 1.0, // scale
+ arm_compute::ConvertPolicy::SATURATE, arm_compute::RoundingPolicy::TO_ZERO);
+
+ builder.append("Mul", std::move(fn));
+ }
+
+ ActivationBuilder{builder}.append(param.activation, output_alloc);
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Div::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+
+ const ::internal::tflite::operand::Index lhs_index{node.param().lhs_index};
+ const ::internal::tflite::operand::Index rhs_index{node.param().rhs_index};
+
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+
+ if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape()))
+ {
+ const auto broadcast_rank =
+ std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank());
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(lhs_index).shape())
+ .extendRank(broadcast_rank);
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(rhs_index).shape())
+ .extendRank(broadcast_rank);
+ }
+
+ _builder.addShapeConstr(
+ lhs_index, asTensorInfo(asTensorShape(_ctx.at(lhs_index).shape()), _ctx.at(lhs_index).type(),
+ _ctx.at(lhs_index).scale(), _ctx.at(lhs_index).zeroPoint()));
+ _builder.addShapeConstr(
+ rhs_index, asTensorInfo(asTensorShape(_ctx.at(rhs_index).shape()), _ctx.at(rhs_index).type(),
+ _ctx.at(rhs_index).scale(), _ctx.at(rhs_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int lhs_index;
+ int rhs_index;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.lhs_index = lhs_index.asInt();
+ param.rhs_index = rhs_index.asInt();
+
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto lhs_alloc = ctx.at(::internal::tflite::operand::Index{param.lhs_index});
+ auto rhs_alloc = ctx.at(::internal::tflite::operand::Index{param.rhs_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLArithmeticDivision>();
+
+ fn->configure(CAST_CL(lhs_alloc), CAST_CL(rhs_alloc), CAST_CL(ofm_alloc));
+
+ builder.append("Div", std::move(fn));
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+
+ ActivationBuilder{builder}.append(param.activation, ofm_alloc);
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Conv2D::Implicit::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index ker_index{node.param().ker_index};
+ const ::internal::tflite::operand::Index bias_index{node.param().bias_index};
+
+ const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index};
+ const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index};
+
+ const ::internal::tflite::operand::Index padding_index{node.param().padding_index};
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
+ const auto ker_shape = _ctx.at(ker_index).shape().asKernel();
+ const auto bias_size = _ctx.at(bias_index).shape().asVector();
+
+ const PaddingCode padding_type =
+ static_cast<PaddingCode>(_ctx.at(padding_index).asScalar<int32_t>());
+
+ Stride stride;
+
+ stride.vertical = _ctx.at(vstride_index).asScalar<int32_t>();
+ stride.horizontal = _ctx.at(hstride_index).asScalar<int32_t>();
+
+ assert((ANEURALNETWORKS_PADDING_SAME == padding_type) ||
+ (ANEURALNETWORKS_PADDING_VALID == padding_type));
+
+ // TODO Should move to the place where the operand is handled, if it is possible.
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ker_index, asTensorInfo(asTensorShape(_ctx.at(ker_index).shape()), _ctx.at(ker_index).type(),
+ _ctx.at(ker_index).scale(), _ctx.at(ker_index).zeroPoint()));
+ _builder.addShapeConstr(bias_index,
+ asTensorInfo(asTensorShape(_ctx.at(bias_index).shape()),
+ _ctx.at(bias_index).type(), _ctx.at(bias_index).scale(),
+ _ctx.at(bias_index).zeroPoint()));
+
+ // Set initializer for kernel
+ {
+ auto ker_base = _ctx.at(ker_index).data().base();
+ auto ker_size = _ctx.at(ker_index).data().size();
+ auto ker_type = _ctx.at(ker_index).type();
+
+ switch (ker_type)
+ {
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ {
+ auto initializer = std::bind(initKernelTensor<float>, _1, ker_shape, ker_base, ker_size);
+ _builder.addInitializer(ker_index, initializer);
+ break;
+ }
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ {
+ auto initializer = std::bind(initKernelTensor<uint8_t>, _1, ker_shape, ker_base, ker_size);
+ _builder.addInitializer(ker_index, initializer);
+ break;
+ }
+ default:
+ {
+ throw std::runtime_error("Not supported");
+ }
+ }
+ }
+
+ // Set initializer for bias
+ {
+ auto bias_base = _ctx.at(bias_index).data().base();
+ auto bias_type = _ctx.at(bias_index).type();
+
+ switch (bias_type)
+ {
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ {
+ auto initializer = std::bind(initVectorTensor<float>, _1, bias_base, bias_size);
+ _builder.addInitializer(bias_index, initializer);
+ break;
+ }
+ case ANEURALNETWORKS_TENSOR_INT32:
+ {
+ auto initializer = std::bind(initVectorTensor<int32_t>, _1, bias_base, bias_size);
+ _builder.addInitializer(bias_index, initializer);
+ break;
+ }
+ default:
+ {
+ throw std::runtime_error("Not supported");
+ }
+ }
+ }
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ int ker_index;
+ int bias_index;
+
+ Padding padding;
+ Stride stride;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+ param.ker_index = ker_index.asInt();
+ param.bias_index = bias_index.asInt();
+
+ param.stride = stride;
+ param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME)
+ ? same_padding(ifm_shape, ofm_shape, stride, ker_shape.W, ker_shape.H)
+ : valid_padding();
+
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+ auto ker_alloc = ctx.at(::internal::tflite::operand::Index{param.ker_index});
+ auto bias_alloc = ctx.at(::internal::tflite::operand::Index{param.bias_index});
+
+ const auto conv_info = asPadStrideInfo(param.padding, param.stride);
+ const auto fused_act = asActInfo(param.activation);
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ std::unique_ptr<::arm_compute::CLConvolutionLayer> fn{new ::arm_compute::CLConvolutionLayer};
+
+ // To pass the fused_act parameter, it calls the WeightsInfo() and Size2D(1U, 1U) (dilation)
+ // functions like the default parameter.
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ker_alloc), CAST_CL(bias_alloc), CAST_CL(ofm_alloc),
+ conv_info, ::arm_compute::WeightsInfo(), ::arm_compute::Size2D(1U, 1U),
+ fused_act);
+
+ builder.append("Conv2D", std::move(fn));
+ }
+ else
+ {
+ std::unique_ptr<::arm_compute::NEConvolutionLayer> fn{new ::arm_compute::NEConvolutionLayer};
+
+ // To pass the fused_act parameter, it calls the WeightsInfo() and Size2D(1U, 1U) (dilation)
+ // functions like the default parameter.
+ fn->configure(ifm_alloc, ker_alloc, bias_alloc, ofm_alloc, conv_info,
+ ::arm_compute::WeightsInfo(), ::arm_compute::Size2D(1U, 1U), fused_act);
+
+ builder.append("Conv2D", std::move(fn));
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Conv2D::Explicit::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index ker_index{node.param().ker_index};
+ const ::internal::tflite::operand::Index bias_index{node.param().bias_index};
+
+ const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index};
+ const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index};
+
+ const ::internal::tflite::operand::Index padding_left_index{node.param().padding_left_index};
+ const ::internal::tflite::operand::Index padding_right_index{node.param().padding_right_index};
+ const ::internal::tflite::operand::Index padding_top_index{node.param().padding_top_index};
+ const ::internal::tflite::operand::Index padding_bottom_index{node.param().padding_bottom_index};
+
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ const int32_t padding_left = _ctx.at(padding_left_index).asScalar<int32_t>();
+ const int32_t padding_right = _ctx.at(padding_right_index).asScalar<int32_t>();
+ const int32_t padding_top = _ctx.at(padding_top_index).asScalar<int32_t>();
+ const int32_t padding_bottom = _ctx.at(padding_bottom_index).asScalar<int32_t>();
+
+ Stride stride;
+
+ stride.vertical = _ctx.at(vstride_index).asScalar<int32_t>();
+ stride.horizontal = _ctx.at(hstride_index).asScalar<int32_t>();
+
+ // TODO Should move to the place where the operand is handled, if it is possible.
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ker_index, asTensorInfo(asTensorShape(_ctx.at(ker_index).shape()), _ctx.at(ker_index).type(),
+ _ctx.at(ker_index).scale(), _ctx.at(ker_index).zeroPoint()));
+ _builder.addShapeConstr(bias_index,
+ asTensorInfo(asTensorShape(_ctx.at(bias_index).shape()),
+ _ctx.at(bias_index).type(), _ctx.at(bias_index).scale(),
+ _ctx.at(bias_index).zeroPoint()));
+
+ // Set initializer for kernel
+ // Workaround for https://github.sec.samsung.net/STAR/nnfw/issues/2319
+ if (_ctx.at(ker_index).hasData())
+ {
+ const auto ker_shape = _ctx.at(ker_index).shape().asKernel();
+ auto ker_base = _ctx.at(ker_index).data().base();
+ auto ker_size = _ctx.at(ker_index).data().size();
+ auto ker_type = _ctx.at(ker_index).type();
+
+ switch (ker_type)
+ {
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ {
+ auto initializer = std::bind(initKernelTensor<float>, _1, ker_shape, ker_base, ker_size);
+ _builder.addInitializer(ker_index, initializer);
+ break;
+ }
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ {
+ auto initializer = std::bind(initKernelTensor<uint8_t>, _1, ker_shape, ker_base, ker_size);
+ _builder.addInitializer(ker_index, initializer);
+ break;
+ }
+ default:
+ {
+ throw std::runtime_error("Not supported");
+ }
+ }
+ }
+
+ // Set initializer for bias
+ // See above comment.
+ if (_ctx.at(bias_index).hasData())
+ {
+ const auto bias_size = _ctx.at(bias_index).shape().asVector();
+ auto bias_base = _ctx.at(bias_index).data().base();
+ auto bias_type = _ctx.at(bias_index).type();
+
+ switch (bias_type)
+ {
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ {
+ auto initializer = std::bind(initVectorTensor<float>, _1, bias_base, bias_size);
+ _builder.addInitializer(bias_index, initializer);
+ break;
+ }
+ case ANEURALNETWORKS_TENSOR_INT32:
+ {
+ auto initializer = std::bind(initVectorTensor<int32_t>, _1, bias_base, bias_size);
+ _builder.addInitializer(bias_index, initializer);
+ break;
+ }
+ default:
+ {
+ throw std::runtime_error("Not supported");
+ }
+ }
+ }
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ int ker_index;
+ int bias_index;
+
+ Padding padding;
+ Stride stride;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+ param.ker_index = ker_index.asInt();
+ param.bias_index = bias_index.asInt();
+
+ param.stride = stride;
+
+ param.padding.left = padding_left;
+ param.padding.right = padding_right;
+ param.padding.top = padding_top;
+ param.padding.bottom = padding_bottom;
+
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+ auto ker_alloc = ctx.at(::internal::tflite::operand::Index{param.ker_index});
+ auto bias_alloc = ctx.at(::internal::tflite::operand::Index{param.bias_index});
+
+ const auto conv_info = asPadStrideInfo(param.padding, param.stride);
+ const auto fused_act = asActInfo(param.activation);
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ std::unique_ptr<::arm_compute::CLConvolutionLayer> fn{new ::arm_compute::CLConvolutionLayer};
+
+ // To pass the fused_act parameter, it calls the WeightsInfo() and Size2D(1U, 1U) (dilation)
+ // functions like the default parameter.
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ker_alloc), CAST_CL(bias_alloc), CAST_CL(ofm_alloc),
+ conv_info, ::arm_compute::WeightsInfo(), ::arm_compute::Size2D(1U, 1U),
+ fused_act);
+
+ builder.append("Conv2D", std::move(fn));
+ }
+ else
+ {
+ std::unique_ptr<::arm_compute::NEConvolutionLayer> fn{new ::arm_compute::NEConvolutionLayer};
+
+ // To pass the fused_act parameter, it calls the WeightsInfo() and Size2D(1U, 1U) (dilation)
+ // functions like the default parameter.
+ fn->configure(ifm_alloc, ker_alloc, bias_alloc, ofm_alloc, conv_info,
+ ::arm_compute::WeightsInfo(), ::arm_compute::Size2D(1U, 1U), fused_act);
+
+ builder.append("Conv2D", std::move(fn));
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::DepthwiseConv2D::Implicit::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index ker_index{node.param().ker_index};
+ const ::internal::tflite::operand::Index bias_index{node.param().bias_index};
+
+ const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index};
+ const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index};
+
+ const ::internal::tflite::operand::Index padding_index{node.param().padding_index};
+ const ::internal::tflite::operand::Index multiplier_index{node.param().multiplier_index};
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
+
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
+ const auto ker_shape = _ctx.at(ker_index).shape().asFeature();
+ const auto bias_size = _ctx.at(bias_index).shape().asVector();
+
+ auto multiplier = _ctx.at(multiplier_index).asScalar<int>();
+
+ assert(ker_shape.C == bias_size);
+ assert(ker_shape.C == ifm_shape.C * multiplier);
+
+ const PaddingCode padding_type =
+ static_cast<PaddingCode>(_ctx.at(padding_index).asScalar<int32_t>());
+
+ Stride stride;
+
+ stride.vertical = _ctx.at(vstride_index).asScalar<int32_t>();
+ stride.horizontal = _ctx.at(hstride_index).asScalar<int32_t>();
+
+ assert((ANEURALNETWORKS_PADDING_SAME == padding_type) ||
+ (ANEURALNETWORKS_PADDING_VALID == padding_type));
+
+ // TODO Should move to the place where the operand is handled, if it is possible.
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+ // NOTE DepthwiseConv2D kernel is of shape [1, KER_W, KER_H, IFM_C * MULTIPLIER]
+ _builder.addShapeConstr(
+ ker_index, asTensorInfo(asTensorShape(_ctx.at(ker_index).shape()), _ctx.at(ker_index).type(),
+ _ctx.at(ker_index).scale(), _ctx.at(ker_index).zeroPoint()));
+ _builder.addShapeConstr(bias_index,
+ asTensorInfo(asTensorShape(_ctx.at(bias_index).shape()),
+ _ctx.at(bias_index).type(), _ctx.at(bias_index).scale(),
+ _ctx.at(bias_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ int ker_index;
+ int bias_index;
+
+ Padding padding;
+ Stride stride;
+
+ int multipler;
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+ param.ker_index = ker_index.asInt();
+ param.bias_index = bias_index.asInt();
+
+ param.stride = stride;
+ param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME)
+ ? same_padding(ifm_shape, ofm_shape, stride, ker_shape.W, ker_shape.H)
+ : valid_padding();
+
+ param.multipler = multiplier;
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ VERBOSE(DepthwiseConv2D) << "OFM_C: " << ofm_shape.C << std::endl;
+ VERBOSE(DepthwiseConv2D) << "OFM_H: " << ofm_shape.H << std::endl;
+ VERBOSE(DepthwiseConv2D) << "OFM_W: " << ofm_shape.W << std::endl;
+
+ VERBOSE(DepthwiseConv2D) << "IFM_C: " << ifm_shape.C << std::endl;
+ VERBOSE(DepthwiseConv2D) << "IFM_H: " << ifm_shape.H << std::endl;
+ VERBOSE(DepthwiseConv2D) << "IFM_W: " << ifm_shape.W << std::endl;
+
+ VERBOSE(DepthwiseConv2D) << "KER_C: " << ker_shape.C << std::endl;
+ VERBOSE(DepthwiseConv2D) << "KER_H: " << ker_shape.H << std::endl;
+ VERBOSE(DepthwiseConv2D) << "KER_W: " << ker_shape.W << std::endl;
+
+ VERBOSE(DepthwiseConv2D) << "STRIDE_H: " << param.stride.vertical << std::endl;
+ VERBOSE(DepthwiseConv2D) << "STRIDE_W: " << param.stride.horizontal << std::endl;
+
+ VERBOSE(DepthwiseConv2D) << "ACTIVATION: " << param.activation << std::endl;
+
+ VERBOSE(DepthwiseConv2D) << "PAD(T): " << param.padding.top << std::endl;
+ VERBOSE(DepthwiseConv2D) << "PAD(B): " << param.padding.bottom << std::endl;
+ VERBOSE(DepthwiseConv2D) << "PAD(L): " << param.padding.left << std::endl;
+ VERBOSE(DepthwiseConv2D) << "PAD(R): " << param.padding.right << std::endl;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+ auto ker_alloc = ctx.at(::internal::tflite::operand::Index{param.ker_index});
+ auto bias_alloc = ctx.at(::internal::tflite::operand::Index{param.bias_index});
+
+ const auto conv_info = asPadStrideInfo(param.padding, param.stride);
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLDepthwiseConvolutionLayer>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ker_alloc), CAST_CL(bias_alloc), CAST_CL(ofm_alloc),
+ conv_info, param.multipler);
+
+ builder.append("DepthwiseConv2D", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEDepthwiseConvolutionLayer>();
+
+ fn->configure(ifm_alloc, ker_alloc, bias_alloc, ofm_alloc, conv_info, param.multipler);
+
+ builder.append("DepthwiseConv2D", std::move(fn));
+ }
+
+ ActivationBuilder{builder}.append(param.activation, ofm_alloc);
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::DepthwiseConv2D::Explicit::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index ker_index{node.param().ker_index};
+ const ::internal::tflite::operand::Index bias_index{node.param().bias_index};
+
+ const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index};
+ const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index};
+
+ const ::internal::tflite::operand::Index padding_left_index{node.param().padding_left_index};
+ const ::internal::tflite::operand::Index padding_right_index{node.param().padding_right_index};
+ const ::internal::tflite::operand::Index padding_top_index{node.param().padding_top_index};
+ const ::internal::tflite::operand::Index padding_bottom_index{node.param().padding_bottom_index};
+
+ const ::internal::tflite::operand::Index multiplier_index{node.param().multiplier_index};
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
+
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
+ const auto ker_shape = _ctx.at(ker_index).shape().asFeature();
+ const auto bias_size = _ctx.at(bias_index).shape().asVector();
+
+ auto multiplier = _ctx.at(multiplier_index).asScalar<int>();
+
+ assert(ker_shape.C == bias_size);
+ assert(ker_shape.C == ifm_shape.C * multiplier);
+
+ const int32_t padding_left = _ctx.at(padding_left_index).asScalar<int32_t>();
+ const int32_t padding_right = _ctx.at(padding_right_index).asScalar<int32_t>();
+ const int32_t padding_top = _ctx.at(padding_top_index).asScalar<int32_t>();
+ const int32_t padding_bottom = _ctx.at(padding_bottom_index).asScalar<int32_t>();
+
+ Stride stride;
+
+ stride.vertical = _ctx.at(vstride_index).asScalar<int32_t>();
+ stride.horizontal = _ctx.at(hstride_index).asScalar<int32_t>();
+
+ // TODO Should move to the place where the operand is handled, if it is possible.
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+ // NOTE DepthwiseConv2D kernel is of shape [1, KER_W, KER_H, IFM_C * MULTIPLIER]
+ _builder.addShapeConstr(
+ ker_index, asTensorInfo(asTensorShape(_ctx.at(ker_index).shape()), _ctx.at(ker_index).type(),
+ _ctx.at(ker_index).scale(), _ctx.at(ker_index).zeroPoint()));
+ _builder.addShapeConstr(bias_index,
+ asTensorInfo(asTensorShape(_ctx.at(bias_index).shape()),
+ _ctx.at(bias_index).type(), _ctx.at(bias_index).scale(),
+ _ctx.at(bias_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ int ker_index;
+ int bias_index;
+
+ Padding padding;
+ Stride stride;
+
+ int multipler;
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+ param.ker_index = ker_index.asInt();
+ param.bias_index = bias_index.asInt();
+
+ param.stride = stride;
+
+ param.padding.left = padding_left;
+ param.padding.right = padding_right;
+ param.padding.top = padding_top;
+ param.padding.bottom = padding_bottom;
+
+ param.multipler = multiplier;
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ VERBOSE(DepthwiseConv2D) << "OFM_C: " << ofm_shape.C << std::endl;
+ VERBOSE(DepthwiseConv2D) << "OFM_H: " << ofm_shape.H << std::endl;
+ VERBOSE(DepthwiseConv2D) << "OFM_W: " << ofm_shape.W << std::endl;
+
+ VERBOSE(DepthwiseConv2D) << "IFM_C: " << ifm_shape.C << std::endl;
+ VERBOSE(DepthwiseConv2D) << "IFM_H: " << ifm_shape.H << std::endl;
+ VERBOSE(DepthwiseConv2D) << "IFM_W: " << ifm_shape.W << std::endl;
+
+ VERBOSE(DepthwiseConv2D) << "KER_C: " << ker_shape.C << std::endl;
+ VERBOSE(DepthwiseConv2D) << "KER_H: " << ker_shape.H << std::endl;
+ VERBOSE(DepthwiseConv2D) << "KER_W: " << ker_shape.W << std::endl;
+
+ VERBOSE(DepthwiseConv2D) << "STRIDE_H: " << param.stride.vertical << std::endl;
+ VERBOSE(DepthwiseConv2D) << "STRIDE_W: " << param.stride.horizontal << std::endl;
+
+ VERBOSE(DepthwiseConv2D) << "ACTIVATION: " << param.activation << std::endl;
+
+ VERBOSE(DepthwiseConv2D) << "PAD(T): " << param.padding.top << std::endl;
+ VERBOSE(DepthwiseConv2D) << "PAD(B): " << param.padding.bottom << std::endl;
+ VERBOSE(DepthwiseConv2D) << "PAD(L): " << param.padding.left << std::endl;
+ VERBOSE(DepthwiseConv2D) << "PAD(R): " << param.padding.right << std::endl;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+ auto ker_alloc = ctx.at(::internal::tflite::operand::Index{param.ker_index});
+ auto bias_alloc = ctx.at(::internal::tflite::operand::Index{param.bias_index});
+
+ const auto conv_info = asPadStrideInfo(param.padding, param.stride);
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLDepthwiseConvolutionLayer>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ker_alloc), CAST_CL(bias_alloc), CAST_CL(ofm_alloc),
+ conv_info, param.multipler);
+
+ builder.append("DepthwiseConv2D", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEDepthwiseConvolutionLayer>();
+
+ fn->configure(ifm_alloc, ker_alloc, bias_alloc, ofm_alloc, conv_info, param.multipler);
+
+ builder.append("DepthwiseConv2D", std::move(fn));
+ }
+
+ ActivationBuilder{builder}.append(param.activation, ofm_alloc);
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Dequantize::Node &node)
+{
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+
+ assert(_ctx.at(input_index).shape().rank() >= 0 && _ctx.at(input_index).shape().rank() <= 4);
+ assert(_ctx.at(input_index).shape() == _ctx.at(output_index).shape());
+ assert(_ctx.at(input_index).type() == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
+ assert(_ctx.at(output_index).type() == ANEURALNETWORKS_TENSOR_FLOAT32);
+
+ // Set Shape Constraints
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(input_index,
+ asTensorInfo(asTensorShape(_ctx.at(input_index).shape()),
+ _ctx.at(input_index).type(), _ctx.at(input_index).scale(),
+ _ctx.at(input_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int output_index;
+ int input_index;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input_index = input_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+
+ std::unique_ptr<::arm_compute::IFunction> fn;
+
+ {
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto l = nnfw::cpp14::make_unique<::arm_compute::CLCast>();
+
+ l->configure(CAST_CL(input_alloc), CAST_CL(output_alloc));
+ fn = std::move(l);
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ }
+
+ builder.append("Dequantize", std::move(fn));
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::MaxPool2D::Implicit::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ const ::internal::tflite::operand::Index kh_index{node.param().kh_index};
+ const ::internal::tflite::operand::Index kw_index{node.param().kw_index};
+
+ const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index};
+ const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index};
+
+ const ::internal::tflite::operand::Index padding_index{node.param().padding_index};
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
+
+ const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>();
+ const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>();
+
+ const int32_t vstride = _ctx.at(vstride_index).asScalar<int32_t>();
+ const int32_t hstride = _ctx.at(hstride_index).asScalar<int32_t>();
+
+ const PaddingCode padding_type =
+ static_cast<PaddingCode>(_ctx.at(padding_index).asScalar<int32_t>());
+
+ assert((ANEURALNETWORKS_PADDING_SAME == padding_type) ||
+ (ANEURALNETWORKS_PADDING_VALID == padding_type));
+
+ // TODO Should move to the place where the operand is handled, if it is possible.
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+
+ uint32_t kw;
+ uint32_t kh;
+
+ Padding padding;
+ Stride stride;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ param.kh = kh;
+ param.kw = kw;
+
+ param.stride.vertical = vstride;
+ param.stride.horizontal = hstride;
+
+ param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME)
+ ? same_padding(ifm_shape, ofm_shape, param.stride, kw, kh)
+ : valid_padding();
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ VERBOSE(MaxPool2D) << "IFM_H: " << ifm_shape.H << std::endl;
+ VERBOSE(MaxPool2D) << "IFM_W: " << ifm_shape.W << std::endl;
+ VERBOSE(MaxPool2D) << "OFM_H: " << ofm_shape.H << std::endl;
+ VERBOSE(MaxPool2D) << "OFM_W: " << ofm_shape.W << std::endl;
+ VERBOSE(MaxPool2D) << "KER_H: " << kh << std::endl;
+ VERBOSE(MaxPool2D) << "KER_W: " << kw << std::endl;
+ VERBOSE(MaxPool2D) << "STRIDE_H: " << vstride << std::endl;
+ VERBOSE(MaxPool2D) << "STRIDE_W: " << hstride << std::endl;
+ VERBOSE(MaxPool2D) << "PAD(T): " << param.padding.top << std::endl;
+ VERBOSE(MaxPool2D) << "PAD(B): " << param.padding.bottom << std::endl;
+ VERBOSE(MaxPool2D) << "PAD(L): " << param.padding.left << std::endl;
+ VERBOSE(MaxPool2D) << "PAD(R): " << param.padding.right << std::endl;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ ::arm_compute::PoolingLayerInfo info{::arm_compute::PoolingType::MAX,
+ ::arm_compute::Size2D{param.kw, param.kh},
+ asPadStrideInfo(param.padding, param.stride)};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer};
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), info);
+
+ builder.append("MaxPool2D", std::move(fn));
+ }
+ else
+ {
+ std::unique_ptr<::arm_compute::NEPoolingLayer> fn{new ::arm_compute::NEPoolingLayer};
+
+ fn->configure(ifm_alloc, ofm_alloc, info);
+
+ builder.append("MaxPool2D", std::move(fn));
+ }
+
+ ActivationBuilder{builder}.append(param.activation, ofm_alloc);
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::MaxPool2D::Explicit::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ const ::internal::tflite::operand::Index kh_index{node.param().kh_index};
+ const ::internal::tflite::operand::Index kw_index{node.param().kw_index};
+
+ const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index};
+ const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index};
+
+ const ::internal::tflite::operand::Index padding_left_index{node.param().padding_left_index};
+ const ::internal::tflite::operand::Index padding_right_index{node.param().padding_right_index};
+ const ::internal::tflite::operand::Index padding_top_index{node.param().padding_top_index};
+ const ::internal::tflite::operand::Index padding_bottom_index{node.param().padding_bottom_index};
+
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
+
+ const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>();
+ const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>();
+
+ const int32_t vstride = _ctx.at(vstride_index).asScalar<int32_t>();
+ const int32_t hstride = _ctx.at(hstride_index).asScalar<int32_t>();
+
+ const int32_t padding_left = _ctx.at(padding_left_index).asScalar<int32_t>();
+ const int32_t padding_right = _ctx.at(padding_right_index).asScalar<int32_t>();
+ const int32_t padding_top = _ctx.at(padding_top_index).asScalar<int32_t>();
+ const int32_t padding_bottom = _ctx.at(padding_bottom_index).asScalar<int32_t>();
+
+ // TODO Should move to the place where the operand is handled, if it is possible.
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+
+ uint32_t kw;
+ uint32_t kh;
+
+ Padding padding;
+ Stride stride;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ param.kh = kh;
+ param.kw = kw;
+
+ param.stride.vertical = vstride;
+ param.stride.horizontal = hstride;
+
+ param.padding.left = padding_left;
+ param.padding.right = padding_right;
+ param.padding.top = padding_top;
+ param.padding.bottom = padding_bottom;
+
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ VERBOSE(MaxPool2D) << "IFM_H: " << ifm_shape.H << std::endl;
+ VERBOSE(MaxPool2D) << "IFM_W: " << ifm_shape.W << std::endl;
+ VERBOSE(MaxPool2D) << "OFM_H: " << ofm_shape.H << std::endl;
+ VERBOSE(MaxPool2D) << "OFM_W: " << ofm_shape.W << std::endl;
+ VERBOSE(MaxPool2D) << "KER_H: " << kh << std::endl;
+ VERBOSE(MaxPool2D) << "KER_W: " << kw << std::endl;
+ VERBOSE(MaxPool2D) << "STRIDE_H: " << vstride << std::endl;
+ VERBOSE(MaxPool2D) << "STRIDE_W: " << hstride << std::endl;
+ VERBOSE(MaxPool2D) << "PAD(T): " << param.padding.top << std::endl;
+ VERBOSE(MaxPool2D) << "PAD(B): " << param.padding.bottom << std::endl;
+ VERBOSE(MaxPool2D) << "PAD(L): " << param.padding.left << std::endl;
+ VERBOSE(MaxPool2D) << "PAD(R): " << param.padding.right << std::endl;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ ::arm_compute::PoolingLayerInfo info{::arm_compute::PoolingType::MAX,
+ ::arm_compute::Size2D{param.kw, param.kh},
+ asPadStrideInfo(param.padding, param.stride)};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer};
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), info);
+
+ builder.append("MaxPool2D", std::move(fn));
+ }
+ else
+ {
+ std::unique_ptr<::arm_compute::NEPoolingLayer> fn{new ::arm_compute::NEPoolingLayer};
+
+ fn->configure(ifm_alloc, ofm_alloc, info);
+
+ builder.append("MaxPool2D", std::move(fn));
+ }
+
+ ActivationBuilder{builder}.append(param.activation, ofm_alloc);
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::AvgPool2D::Implicit::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ const ::internal::tflite::operand::Index kh_index{node.param().kh_index};
+ const ::internal::tflite::operand::Index kw_index{node.param().kw_index};
+
+ const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index};
+ const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index};
+
+ const ::internal::tflite::operand::Index padding_index{node.param().padding_index};
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
+
+ const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>();
+ const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>();
+
+ const int32_t vstride = _ctx.at(vstride_index).asScalar<int32_t>();
+ const int32_t hstride = _ctx.at(hstride_index).asScalar<int32_t>();
+
+ const PaddingCode padding_type =
+ static_cast<PaddingCode>(_ctx.at(padding_index).asScalar<int32_t>());
+
+ assert((ANEURALNETWORKS_PADDING_SAME == padding_type) ||
+ (ANEURALNETWORKS_PADDING_VALID == padding_type));
+
+ // TODO Should move to the place where the operand is handled, if it is possible.
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+
+ uint32_t kw;
+ uint32_t kh;
+
+ Padding padding;
+ Stride stride;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ param.kh = kh;
+ param.kw = kw;
+
+ param.stride.vertical = vstride;
+ param.stride.horizontal = hstride;
+
+ param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME)
+ ? same_padding(ifm_shape, ofm_shape, param.stride, kw, kh)
+ : valid_padding();
+
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ VERBOSE(AvgPool2D) << "IFM_H: " << ifm_shape.H << std::endl;
+ VERBOSE(AvgPool2D) << "IFM_W: " << ifm_shape.W << std::endl;
+ VERBOSE(AvgPool2D) << "OFM_H: " << ofm_shape.H << std::endl;
+ VERBOSE(AvgPool2D) << "OFM_W: " << ofm_shape.W << std::endl;
+ VERBOSE(AvgPool2D) << "KER_H: " << kh << std::endl;
+ VERBOSE(AvgPool2D) << "KER_W: " << kw << std::endl;
+ VERBOSE(AvgPool2D) << "STRIDE_H: " << vstride << std::endl;
+ VERBOSE(AvgPool2D) << "STRIDE_W: " << hstride << std::endl;
+ VERBOSE(AvgPool2D) << "PAD: " << to_string(padding_type) << std::endl;
+ VERBOSE(AvgPool2D) << "PAD(T): " << param.padding.top << std::endl;
+ VERBOSE(AvgPool2D) << "PAD(B): " << param.padding.bottom << std::endl;
+ VERBOSE(AvgPool2D) << "PAD(L): " << param.padding.left << std::endl;
+ VERBOSE(AvgPool2D) << "PAD(R): " << param.padding.right << std::endl;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ ::arm_compute::PoolingLayerInfo info{
+ ::arm_compute::PoolingType::AVG, ::arm_compute::Size2D{param.kw, param.kh},
+ asPadStrideInfo(param.padding, param.stride), true /* exclude_padding */};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer};
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), info);
+
+ builder.append("AvgPool2D", std::move(fn));
+ }
+ else
+ {
+ std::unique_ptr<::arm_compute::NEPoolingLayer> fn{new ::arm_compute::NEPoolingLayer};
+
+ fn->configure(ifm_alloc, ofm_alloc, info);
+
+ builder.append("AvgPool2D", std::move(fn));
+ }
+
+ ActivationBuilder{builder}.append(param.activation, ofm_alloc);
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::AvgPool2D::Explicit::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ const ::internal::tflite::operand::Index kh_index{node.param().kh_index};
+ const ::internal::tflite::operand::Index kw_index{node.param().kw_index};
+
+ const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index};
+ const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index};
+
+ const ::internal::tflite::operand::Index padding_left_index{node.param().padding_left_index};
+ const ::internal::tflite::operand::Index padding_right_index{node.param().padding_right_index};
+ const ::internal::tflite::operand::Index padding_top_index{node.param().padding_top_index};
+ const ::internal::tflite::operand::Index padding_bottom_index{node.param().padding_bottom_index};
+
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
+
+ const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>();
+ const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>();
+
+ const int32_t vstride = _ctx.at(vstride_index).asScalar<int32_t>();
+ const int32_t hstride = _ctx.at(hstride_index).asScalar<int32_t>();
+
+ const int32_t padding_left = _ctx.at(padding_left_index).asScalar<int32_t>();
+ const int32_t padding_right = _ctx.at(padding_right_index).asScalar<int32_t>();
+ const int32_t padding_top = _ctx.at(padding_top_index).asScalar<int32_t>();
+ const int32_t padding_bottom = _ctx.at(padding_bottom_index).asScalar<int32_t>();
+
+ // TODO Should move to the place where the operand is handled, if it is possible.
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+
+ uint32_t kw;
+ uint32_t kh;
+
+ Padding padding;
+ Stride stride;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ param.kh = kh;
+ param.kw = kw;
+
+ param.stride.vertical = vstride;
+ param.stride.horizontal = hstride;
+
+ param.padding.left = padding_left;
+ param.padding.right = padding_right;
+ param.padding.top = padding_top;
+ param.padding.bottom = padding_bottom;
+
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ VERBOSE(AvgPool2D) << "IFM_H: " << ifm_shape.H << std::endl;
+ VERBOSE(AvgPool2D) << "IFM_W: " << ifm_shape.W << std::endl;
+ VERBOSE(AvgPool2D) << "OFM_H: " << ofm_shape.H << std::endl;
+ VERBOSE(AvgPool2D) << "OFM_W: " << ofm_shape.W << std::endl;
+ VERBOSE(AvgPool2D) << "KER_H: " << kh << std::endl;
+ VERBOSE(AvgPool2D) << "KER_W: " << kw << std::endl;
+ VERBOSE(AvgPool2D) << "STRIDE_H: " << vstride << std::endl;
+ VERBOSE(AvgPool2D) << "STRIDE_W: " << hstride << std::endl;
+ VERBOSE(AvgPool2D) << "PAD(T): " << param.padding.top << std::endl;
+ VERBOSE(AvgPool2D) << "PAD(B): " << param.padding.bottom << std::endl;
+ VERBOSE(AvgPool2D) << "PAD(L): " << param.padding.left << std::endl;
+ VERBOSE(AvgPool2D) << "PAD(R): " << param.padding.right << std::endl;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ ::arm_compute::PoolingLayerInfo info{
+ ::arm_compute::PoolingType::AVG, ::arm_compute::Size2D{param.kw, param.kh},
+ asPadStrideInfo(param.padding, param.stride), true /* exclude_padding */};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer};
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), info);
+
+ builder.append("AvgPool2D", std::move(fn));
+ }
+ else
+ {
+ std::unique_ptr<::arm_compute::NEPoolingLayer> fn{new ::arm_compute::NEPoolingLayer};
+
+ fn->configure(ifm_alloc, ofm_alloc, info);
+
+ builder.append("AvgPool2D", std::move(fn));
+ }
+
+ ActivationBuilder{builder}.append(param.activation, ofm_alloc);
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Concat::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index axis_index{node.param().axis_index};
+
+ // NOTE This implementation assumes that inputs and output are a feature
+ const auto ofm_shape = _ctx.at(ofm_index).shape();
+ uint32_t input_rank = ofm_shape.rank();
+ int32_t axis = _ctx.at(axis_index).asScalar<int32_t>();
+
+ // Handle negative axis
+ if (axis < 0)
+ {
+ axis += input_rank;
+ }
+
+ // Set Shape Constraints and TensorInfo (for output)
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+
+ // Set Shape Constraints and TensorInfo (for input)
+ const uint32_t coord_index = ToARMComputeAxis(input_rank, axis).value();
+ uint32_t depth = 0;
+
+ ::arm_compute::Coordinates coordinates;
+ coordinates.set_num_dimensions(input_rank);
+
+ for (const auto &index : node.param().ifm_indexes)
+ {
+ const ::internal::tflite::operand::Index ifm_index{index};
+ const auto ifm_shape = _ctx.at(ifm_index).shape();
+
+ coordinates[coord_index] = depth;
+
+ _builder.addSubsumptionConstr(ifm_index, ofm_index, coordinates,
+ asTensorShape(_ctx.at(ifm_index).shape()), true);
+
+ depth += ifm_shape.dim(axis);
+ }
+
+ // NOTE Concat has no actual operation!
+ // However, dummy stage is added because profiler assumes every operation make a stage.
+ auto stage = [](const IAllocationContext &ctx, IExecutionBuilder &builder) {};
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::FullyConnected::Node &node)
+{
+ VERBOSE(FullyConnected) << "Configure FULLY_CONNECTED operation" << std::endl;
+
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+ const ::internal::tflite::operand::Index weight_index{node.param().weight_index};
+ const ::internal::tflite::operand::Index bias_index{node.param().bias_index};
+
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ assert(_ctx.at(input_index).shape().rank() >= 2);
+ assert(_ctx.at(output_index).shape().rank() == 2);
+ assert(_ctx.at(weight_index).shape().rank() == 2);
+ assert(_ctx.at(bias_index).shape().rank() == 1);
+
+ const auto input_rank = _ctx.at(input_index).shape().rank();
+ // TODO Currently we are not handling where the case is that the input's rank is 3.
+ // The handling should be added in the future.
+ assert(input_rank != 3);
+
+ const auto output_size = _ctx.at(output_index).shape().dim(1);
+ assert(_ctx.at(bias_index).shape().dim(0) == output_size);
+ assert(_ctx.at(weight_index).shape().dim(0) == output_size);
+ const auto batch_size = _ctx.at(output_index).shape().dim(0);
+ const auto input_size = _ctx.at(weight_index).shape().dim(1);
+
+ // Check for reshaping input's shape into rank-2
+ bool needs_reshape = false;
+ internal::tflite::operand::Shape reshape(2);
+ if (input_rank == 4)
+ {
+ nnfw::misc::feature::Shape ifm_shape_feature = _ctx.at(input_index).shape().asFeature();
+ auto feature_size =
+ ifm_shape_feature.N * ifm_shape_feature.C * ifm_shape_feature.H * ifm_shape_feature.W;
+ assert(feature_size == batch_size * input_size);
+
+ _builder.addShapeConstr(input_index,
+ asTensorInfo(asTensorShape(_ctx.at(input_index).shape(), false),
+ _ctx.at(input_index).type(), _ctx.at(input_index).scale(),
+ _ctx.at(input_index).zeroPoint()));
+
+ // for reshaping
+ needs_reshape = true;
+ reshape.dim(0) = batch_size; /* H */
+ reshape.dim(1) = input_size; /* W */
+ }
+ else if (input_rank == 2)
+ {
+ auto ifm_shape = _ctx.at(input_index).shape();
+ nnfw::misc::matrix::Shape ifm_shape_matrix = ifm_shape.asMatrix();
+ assert(ifm_shape.dim(0) == batch_size);
+ assert(ifm_shape.dim(1) == input_size);
+
+ _builder.addShapeConstr(input_index,
+ asTensorInfo(asTensorShape(_ctx.at(input_index).shape()),
+ _ctx.at(input_index).type(), _ctx.at(input_index).scale(),
+ _ctx.at(input_index).zeroPoint()));
+ }
+
+ // TODO Should move to the place where the operand is handled, if it is possible.
+ // Set Shape Constraints
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(weight_index,
+ asTensorInfo(asTensorShape(_ctx.at(weight_index).shape()),
+ _ctx.at(weight_index).type(), _ctx.at(weight_index).scale(),
+ _ctx.at(weight_index).zeroPoint()));
+ _builder.addShapeConstr(bias_index,
+ asTensorInfo(asTensorShape(_ctx.at(bias_index).shape()),
+ _ctx.at(bias_index).type(), _ctx.at(bias_index).scale(),
+ _ctx.at(bias_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int output_index;
+
+ int input_index;
+ int weight_index;
+ int bias_index;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input_index = input_index.asInt();
+ param.weight_index = weight_index.asInt();
+ param.bias_index = bias_index.asInt();
+
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ auto stage = [param, needs_reshape, reshape](const IAllocationContext &ctx,
+ IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+ auto weight_alloc = ctx.at(::internal::tflite::operand::Index{param.weight_index});
+ auto bias_alloc = ctx.at(::internal::tflite::operand::Index{param.bias_index});
+
+ auto fn = nnfw::cpp14::make_unique<arm_compute::CLFullyConnectedReshapingLayer>();
+
+ fn->configure(CAST_CL(input_alloc), CAST_CL(weight_alloc), CAST_CL(bias_alloc),
+ CAST_CL(output_alloc), needs_reshape, asTensorShape(reshape));
+
+ builder.append("FullyConnected", std::move(fn));
+
+ ActivationBuilder{builder}.append(param.activation, output_alloc);
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::ResizeBilinear::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index height_index{node.param().height_index};
+ const ::internal::tflite::operand::Index width_index{node.param().width_index};
+
+ // TODO Should move to the place where the operand is handled, if it is possible.
+ // Set Shape Constraints
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+
+ int new_height;
+ int new_width;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+ param.new_height = _ctx.at(height_index).asScalar<int32_t>();
+ param.new_width = _ctx.at(width_index).asScalar<int32_t>();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLScale>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc),
+ ::arm_compute::InterpolationPolicy::BILINEAR,
+ ::arm_compute::BorderMode::REPLICATE, ::arm_compute::PixelValue(0.f),
+ ::arm_compute::SamplingPolicy::TOP_LEFT);
+
+ builder.append("ResizeBilinear", std::move(fn));
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Reshape::Node &node)
+{
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+
+ auto input_shape = asTensorShape(_ctx.at(input_index).shape(), false);
+ auto output_shape = asTensorShape(_ctx.at(output_index).shape(), false);
+
+ assert(input_shape[0] * input_shape[1] * input_shape[2] * input_shape[3] ==
+ output_shape[0] * output_shape[1] * output_shape[2] * output_shape[3]);
+
+ // TODO Should move to the place where the operand is handled, if it is possible.
+ _builder.addShapeConstr(output_index, asTensorInfo(output_shape, _ctx.at(output_index).type(),
+ _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(input_index, asTensorInfo(input_shape, _ctx.at(input_index).type(),
+ _ctx.at(input_index).scale(),
+ _ctx.at(input_index).zeroPoint()));
+
+ struct Param
+ {
+ int output_index;
+ int input_index;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input_index = input_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ // GenericReshape first apply NCHW->NHWC permutation, and apply reshape
+ auto fn = nnfw::cpp14::make_unique<GenericReshapeLayer>();
+
+ fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc));
+
+ builder.append("Reshape", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<GenericReshapeLayer>();
+
+ fn->configure(input_alloc, output_alloc);
+
+ builder.append("Reshape", std::move(fn));
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Squeeze::Node &node)
+{
+ // node.param().dims_index_optional is ignored since output tensor already has squeezed shape
+ // by freezer and toco
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+
+ // Set Shape Constraints
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(input_index,
+ asTensorInfo(asTensorShape(_ctx.at(input_index).shape()),
+ _ctx.at(input_index).type(), _ctx.at(input_index).scale(),
+ _ctx.at(input_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int output_index;
+ int input_index;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input_index = input_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLReshapeLayer>();
+
+ fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc));
+
+ builder.append("Squeeze", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEReshapeLayer>();
+
+ fn->configure(input_alloc, output_alloc);
+
+ builder.append("Squeeze", std::move(fn));
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Softmax::Node &node)
+{
+ VERBOSE(Softmax) << "Configure SOFTMAX operation" << std::endl;
+
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+ const ::internal::tflite::operand::Index scale_index{node.param().scale_index};
+
+ assert(_ctx.at(output_index).shape().rank() == _ctx.at(input_index).shape().rank());
+ assert(_ctx.at(scale_index).shape().rank() == 0);
+
+ // TODO Should move to the place where the operand is handled, if it is possible.
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(input_index,
+ asTensorInfo(asTensorShape(_ctx.at(input_index).shape()),
+ _ctx.at(input_index).type(), _ctx.at(input_index).scale(),
+ _ctx.at(input_index).zeroPoint()));
+
+ struct Param
+ {
+ int output_index;
+ int input_index;
+ float scale;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input_index = input_index.asInt();
+ param.scale = _ctx.at(scale_index).asScalar<float>();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLSoftmaxLayer>();
+
+ fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc), param.scale);
+
+ builder.append("Softmax", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NESoftmaxLayer>();
+
+ fn->configure(input_alloc, output_alloc, param.scale);
+
+ builder.append("Softmax", std::move(fn));
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::StridedSlice::Node &node)
+{
+ VERBOSE(StridedSlice) << "Configure STRIDED_SLICE operation" << std::endl;
+
+ const ::internal::tflite::operand::Index outputData_index{node.param().outputData_index};
+
+ const ::internal::tflite::operand::Index inputData_index{node.param().inputData_index};
+ const ::internal::tflite::operand::Index startData_index{node.param().startData_index};
+ const ::internal::tflite::operand::Index endData_index{node.param().endData_index};
+ const ::internal::tflite::operand::Index stridesData_index{node.param().stridesData_index};
+ const ::internal::tflite::operand::Index beginMask_index{node.param().beginMask_index};
+ const ::internal::tflite::operand::Index endMask_index{node.param().endMask_index};
+ const ::internal::tflite::operand::Index shrinkAxisMask_index{node.param().shrinkAxisMask_index};
+
+ // Set Shape Constraints
+ _builder.addShapeConstr(outputData_index,
+ asTensorInfo(asTensorShape(_ctx.at(outputData_index).shape()),
+ _ctx.at(outputData_index).type(),
+ _ctx.at(outputData_index).scale(),
+ _ctx.at(outputData_index).zeroPoint()));
+ _builder.addShapeConstr(
+ inputData_index,
+ asTensorInfo(asTensorShape(_ctx.at(inputData_index).shape()), _ctx.at(inputData_index).type(),
+ _ctx.at(inputData_index).scale(), _ctx.at(inputData_index).zeroPoint()));
+
+ assert(_ctx.at(startData_index).shape().rank() == 1);
+ assert(_ctx.at(endData_index).shape().rank() == 1);
+ assert(_ctx.at(stridesData_index).shape().rank() == 1);
+ _builder.addShapeConstr(
+ startData_index,
+ asTensorInfo(asTensorShape(_ctx.at(startData_index).shape()), _ctx.at(startData_index).type(),
+ _ctx.at(startData_index).scale(), _ctx.at(startData_index).zeroPoint()));
+ _builder.addShapeConstr(endData_index, asTensorInfo(asTensorShape(_ctx.at(endData_index).shape()),
+ _ctx.at(endData_index).type(),
+ _ctx.at(endData_index).scale(),
+ _ctx.at(endData_index).zeroPoint()));
+ _builder.addShapeConstr(
+ stridesData_index,
+ asTensorInfo(asTensorShape(_ctx.at(endData_index).shape()), _ctx.at(stridesData_index).type(),
+ _ctx.at(stridesData_index).scale(), _ctx.at(stridesData_index).zeroPoint()));
+
+ // Set initializers for indices data such as order of inputData
+ int input_rank = _ctx.at(inputData_index).shape().rank();
+ std::vector<int32_t> starts;
+ std::vector<int32_t> ends;
+ std::vector<int32_t> strides;
+ starts.resize(input_rank, 0);
+ ends.resize(input_rank, 0);
+ strides.resize(input_rank, 0);
+ {
+ auto input_shape = _ctx.at(inputData_index).shape();
+ auto startData_base = _ctx.at(startData_index).data().base();
+ auto endData_base = _ctx.at(endData_index).data().base();
+ auto stridesData_base = _ctx.at(stridesData_index).data().base();
+ const auto startData_size = _ctx.at(startData_index).shape().asVector();
+ const auto endData_size = _ctx.at(endData_index).shape().asVector();
+ const auto stridesData_size = _ctx.at(stridesData_index).shape().asVector();
+
+ assert(_ctx.at(startData_index).type() == ANEURALNETWORKS_TENSOR_INT32);
+ assert(_ctx.at(endData_index).type() == ANEURALNETWORKS_TENSOR_INT32);
+ assert(_ctx.at(stridesData_index).type() == ANEURALNETWORKS_TENSOR_INT32);
+ assert(startData_size == input_rank);
+ assert(endData_size == input_rank);
+ assert(stridesData_size == input_rank);
+
+ assert(startData_base != nullptr);
+ for (uint32_t n = 0; n < input_rank; ++n)
+ {
+ auto axis = ToARMComputeAxis(input_rank, n).value();
+
+ int32_t start_value = *(reinterpret_cast<const int32_t *>(startData_base) + n);
+ starts[axis] = start_value;
+
+ int32_t end_value = *(reinterpret_cast<const int32_t *>(endData_base) + n);
+ ends[axis] = end_value;
+
+ int32_t strides_value = *(reinterpret_cast<const int32_t *>(stridesData_base) + n);
+ strides[axis] = strides_value;
+ }
+ }
+
+ struct Param
+ {
+ int32_t outputData_index;
+ int32_t inputData_index;
+
+ std::vector<int32_t> starts;
+ std::vector<int32_t> ends;
+ std::vector<int32_t> strides;
+
+ int32_t beginMask;
+ int32_t endMask;
+ int32_t shrinkAxisMask;
+ };
+
+ Param param;
+ param.outputData_index = outputData_index.asInt();
+ param.inputData_index = inputData_index.asInt();
+
+ param.starts = starts;
+ param.ends = ends;
+ param.strides = strides;
+
+ // Set mask bits such as order of inputData
+ param.beginMask = _ctx.at(beginMask_index).asReorderBits<int32_t>(input_rank);
+ param.endMask = _ctx.at(endMask_index).asReorderBits<int32_t>(input_rank);
+ param.shrinkAxisMask = _ctx.at(shrinkAxisMask_index).asReorderBits<int32_t>(input_rank);
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto outputData_alloc = ctx.at(::internal::tflite::operand::Index{param.outputData_index});
+ auto inputData_alloc = ctx.at(::internal::tflite::operand::Index{param.inputData_index});
+
+ ::arm_compute::Coordinates starts;
+ ::arm_compute::Coordinates ends;
+ ::arm_compute::BiStrides strides;
+ for (int i = 0; i < param.starts.size(); ++i)
+ {
+ starts.set(i, param.starts[i]);
+ ends.set(i, param.ends[i]);
+ strides.set(i, param.strides[i]);
+ }
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLStridedSlice>();
+
+ fn->configure(CAST_CL(inputData_alloc), CAST_CL(outputData_alloc), starts, ends, strides,
+ param.beginMask, param.endMask, param.shrinkAxisMask);
+
+ builder.append("StridedSlice", std::move(fn));
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::ReduceMin::Node &node)
+{
+ VERBOSE(ReduceMin) << "Configure REDUCEMIN operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index axis_index{node.param().axis_index};
+
+ auto ifm_shape = _ctx.at(ifm_index).shape();
+ auto ofm_shape = _ctx.at(ofm_index).shape();
+ auto axis_shape = _ctx.at(axis_index).shape();
+ assert(ifm_shape.rank() <= 4);
+ assert(ofm_shape.rank() <= ifm_shape.rank());
+ assert(_ctx.at(axis_index).hasData());
+ assert(axis_shape.rank() == 0 || axis_shape.rank() == 1);
+
+ // NOTE For the 4-dimensions, if the rank of input and output are different, this runtime only
+ // supports cases reducing height and width or reducing depth.
+ // TODO We have to support all cases of dimensions up to 4.
+ // For correct permuting, we have to set output's shape to be equal in dimension position of the
+ // input. But the positions of the same dimensions in the input and output may be set differently.
+ // For example {2,3,4,5}(input's shape) can be reduced to {3,5}(output's shape). The original
+ // output shape should be {1,3,1,5}, but real output shape may be {3,5}. If you simply try to
+ // extend it in 4 dimensions, it should be {1,1,3,5}.
+ // Even if output shape is changed to {1,3,1,5}, there is another problem. It is that shape of
+ // output tensor used at next operation is changed to {1,3,1,5} after this operation even if the
+ // next operation is not desired.
+ if (ifm_shape.rank() == 4 && ifm_shape.rank() != ofm_shape.rank())
+ {
+ if (ofm_shape.rank() == 2)
+ {
+ // Reducing HW
+ assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(3) == ofm_shape.dim(1));
+ }
+ else if (ofm_shape.rank() == 3)
+ {
+ // Reducing C or
+ // (Reducing H and C(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1)
+ assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(1) == ofm_shape.dim(1) &&
+ ifm_shape.dim(2) == ofm_shape.dim(2) ||
+ (ifm_shape.dim(0) == ofm_shape.dim(0) &&
+ (ifm_shape.dim(1) == ofm_shape.dim(1) || ifm_shape.dim(2) == ofm_shape.dim(1)) &&
+ ifm_shape.dim(3) == 1 && ofm_shape.dim(2) == 1));
+ }
+ }
+
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ std::set<uint32_t> axis;
+ {
+ const auto ifm_rank = ifm_shape.rank();
+ switch (axis_shape.rank())
+ {
+ case 0: // scalar
+ {
+ int32_t axis_value = _ctx.at(axis_index).asScalar<int32_t>();
+ if (axis_value < 0)
+ {
+ axis_value += ifm_rank;
+ }
+ axis.insert(ToARMComputeAxis(ifm_rank, axis_value).value());
+ break;
+ }
+ case 1: // vector
+ {
+ const auto axis_base = _ctx.at(axis_index).data().base();
+ const auto axis_size = _ctx.at(axis_index).shape().asVector();
+
+ // If axis's data does not exist as constant values and can be gotten as input data, we have
+ // to find a way to infer output shape when sinking output.
+ assert(axis_base != nullptr);
+ for (uint32_t n = 0; n < axis_size; ++n)
+ {
+ int32_t axis_value = *(reinterpret_cast<const int32_t *>(axis_base) + n);
+ if (axis_value < 0)
+ {
+ axis_value += ifm_rank;
+ }
+ axis.insert(ToARMComputeAxis(ifm_rank, axis_value).value());
+ }
+ break;
+ }
+ default:
+ throw std::runtime_error("Not supported");
+ break;
+ }
+ }
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ std::set<uint32_t> axis;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+ param.axis = axis;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLReduceOperation>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), param.axis,
+ ::arm_compute::ReduceOperation::MIN);
+
+ builder.append("ReduceMin", std::move(fn));
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::ReduceMax::Node &node)
+{
+ VERBOSE(ReduceMax) << "Configure REDUCEMAX operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index axis_index{node.param().axis_index};
+
+ auto ifm_shape = _ctx.at(ifm_index).shape();
+ auto ofm_shape = _ctx.at(ofm_index).shape();
+ auto axis_shape = _ctx.at(axis_index).shape();
+ assert(ifm_shape.rank() <= 4);
+ assert(ofm_shape.rank() <= ifm_shape.rank());
+ assert(_ctx.at(axis_index).hasData());
+ assert(axis_shape.rank() == 0 || axis_shape.rank() == 1);
+
+ // NOTE For the 4-dimensions, if the rank of input and output are different, this runtime only
+ // supports cases reducing height and width or reducing depth.
+ // TODO We have to support all cases of dimensions up to 4.
+ // For correct permuting, we have to set output's shape to be equal in dimension position of the
+ // input. But the positions of the same dimensions in the input and output may be set differently.
+ // For example {2,3,4,5}(input's shape) can be reduced to {3,5}(output's shape). The original
+ // output shape should be {1,3,1,5}, but real output shape may be {3,5}. If you simply try to
+ // extend it in 4 dimensions, it should be {1,1,3,5}.
+ // Even if output shape is changed to {1,3,1,5}, there is another problem. It is that shape of
+ // output tensor used at next operation is changed to {1,3,1,5} after this operation even if the
+ // next operation is not desired.
+ if (ifm_shape.rank() == 4 && ifm_shape.rank() != ofm_shape.rank())
+ {
+ if (ofm_shape.rank() == 2)
+ {
+ // Reducing HW
+ assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(3) == ofm_shape.dim(1));
+ }
+ else if (ofm_shape.rank() == 3)
+ {
+ // Reducing C or
+ // (Reducing H and C(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1)
+ assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(1) == ofm_shape.dim(1) &&
+ ifm_shape.dim(2) == ofm_shape.dim(2) ||
+ (ifm_shape.dim(0) == ofm_shape.dim(0) &&
+ (ifm_shape.dim(1) == ofm_shape.dim(1) || ifm_shape.dim(2) == ofm_shape.dim(1)) &&
+ ifm_shape.dim(3) == 1 && ofm_shape.dim(2) == 1));
+ }
+ }
+
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ std::set<uint32_t> axis;
+ {
+ const auto ifm_rank = ifm_shape.rank();
+ switch (axis_shape.rank())
+ {
+ case 0: // scalar
+ {
+ int32_t axis_value = _ctx.at(axis_index).asScalar<int32_t>();
+ if (axis_value < 0)
+ {
+ axis_value += ifm_rank;
+ }
+ axis.insert(ToARMComputeAxis(ifm_rank, axis_value).value());
+ break;
+ }
+ case 1: // vector
+ {
+ const auto axis_base = _ctx.at(axis_index).data().base();
+ const auto axis_size = _ctx.at(axis_index).shape().asVector();
+
+ // If axis's data does not exist as constant values and can be gotten as input data, we have
+ // to find a way to infer output shape when sinking output.
+ assert(axis_base != nullptr);
+ for (uint32_t n = 0; n < axis_size; ++n)
+ {
+ int32_t axis_value = *(reinterpret_cast<const int32_t *>(axis_base) + n);
+ if (axis_value < 0)
+ {
+ axis_value += ifm_rank;
+ }
+ axis.insert(ToARMComputeAxis(ifm_rank, axis_value).value());
+ }
+ break;
+ }
+ default:
+ throw std::runtime_error("Not supported");
+ break;
+ }
+ }
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ std::set<uint32_t> axis;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+ param.axis = axis;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLReduceOperation>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), param.axis,
+ ::arm_compute::ReduceOperation::MAX);
+
+ builder.append("ReduceMax", std::move(fn));
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Cast::Node &node)
+{
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+
+ assert(_ctx.at(output_index).shape() == _ctx.at(input_index).shape());
+
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(input_index,
+ asTensorInfo(asTensorShape(_ctx.at(input_index).shape()),
+ _ctx.at(input_index).type(), _ctx.at(input_index).scale(),
+ _ctx.at(input_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int input_index;
+ int output_index;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input_index = input_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+
+ std::unique_ptr<::arm_compute::IFunction> fn;
+
+ {
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto l = nnfw::cpp14::make_unique<::arm_compute::CLCast>();
+
+ l->configure(CAST_CL(input_alloc), CAST_CL(output_alloc));
+ fn = std::move(l);
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ }
+
+ builder.append("Cast", std::move(fn));
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::TopKV2::Node &node)
+{
+ const ::internal::tflite::operand::Index outputValues_index{node.param().outputValues_index};
+ const ::internal::tflite::operand::Index outputIndices_index{node.param().outputIndices_index};
+
+ const ::internal::tflite::operand::Index inputData_index{node.param().inputData_index};
+ const ::internal::tflite::operand::Index k_index{node.param().k_index};
+
+ // Currently, we only support the vector input.
+ assert(_ctx.at(inputData_index).shape().rank() == 1 ||
+ _ctx.at(inputData_index).shape().rank() == 2);
+
+ const int32_t k = _ctx.at(k_index).asScalar<int32_t>();
+
+ // Set shape constraints
+ _builder.addShapeConstr(outputValues_index,
+ asTensorInfo(asTensorShape(_ctx.at(outputValues_index).shape()),
+ _ctx.at(outputValues_index).type(),
+ _ctx.at(outputValues_index).scale(),
+ _ctx.at(outputValues_index).zeroPoint()));
+ _builder.addShapeConstr(outputIndices_index,
+ asTensorInfo(asTensorShape(_ctx.at(outputIndices_index).shape()),
+ _ctx.at(outputIndices_index).type(),
+ _ctx.at(outputIndices_index).scale(),
+ _ctx.at(outputIndices_index).zeroPoint()));
+ _builder.addShapeConstr(
+ inputData_index,
+ asTensorInfo(asTensorShape(_ctx.at(inputData_index).shape()), _ctx.at(inputData_index).type(),
+ _ctx.at(inputData_index).scale(), _ctx.at(inputData_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int32_t outputValues_index;
+ int32_t outputIndices_index;
+
+ int32_t inputData_index;
+ int32_t k;
+ };
+
+ Param param;
+
+ param.outputValues_index = outputValues_index.asInt();
+ param.outputIndices_index = outputIndices_index.asInt();
+ param.inputData_index = inputData_index.asInt();
+ param.k = k;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto values_alloc = ctx.at(::internal::tflite::operand::Index{param.outputValues_index});
+ auto indices_alloc = ctx.at(::internal::tflite::operand::Index{param.outputIndices_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.inputData_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLTopKV2>();
+
+ fn->configure(CAST_CL(input_alloc), param.k, CAST_CL(values_alloc), CAST_CL(indices_alloc));
+
+ builder.append("TopKV2", std::move(fn));
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Gather::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index indices_index{node.param().indices_index};
+
+ const ::internal::tflite::operand::Index axis_index{node.param().axis_index};
+
+ const auto ifm_shape = _ctx.at(ifm_index).shape();
+ const auto indices_shape = _ctx.at(indices_index).shape();
+ const auto axis_shape = _ctx.at(axis_index).shape();
+ const auto ofm_shape = _ctx.at(ofm_index).shape();
+
+ assert(ifm_shape.rank() <= 4);
+ assert(indices_shape.rank() <= 3);
+ assert(ofm_shape.rank() <= 4);
+ assert(_ctx.at(axis_index).hasData());
+ assert(axis_shape.rank() == 0);
+
+ // Set Shape Constraints
+ _builder.addShapeConstr(ofm_index,
+ asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape(), false),
+ _ctx.at(ofm_index).type(), _ctx.at(ofm_index).scale(),
+ _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(ifm_index,
+ asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape(), false),
+ _ctx.at(ifm_index).type(), _ctx.at(ifm_index).scale(),
+ _ctx.at(ifm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ indices_index, asTensorInfo(asTensorShape(_ctx.at(indices_index).shape(), false),
+ _ctx.at(indices_index).type(), _ctx.at(indices_index).scale(),
+ _ctx.at(indices_index).zeroPoint()));
+
+ const int32_t axis_value = static_cast<int>(_ctx.at(axis_index).asScalar<int32_t>());
+ const int axis = ToARMComputeAxis(ifm_shape.rank(), axis_value).value();
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ int indices_index;
+
+ int axis;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+ param.indices_index = indices_index.asInt();
+
+ param.axis = axis;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+ auto indices_alloc = ctx.at(::internal::tflite::operand::Index{param.indices_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ std::unique_ptr<::arm_compute::IFunction> fn;
+
+ auto l = nnfw::cpp14::make_unique<GenericGather>();
+ l->configure(CAST_CL(ifm_alloc), CAST_CL(indices_alloc), CAST_CL(ofm_alloc), param.axis);
+ fn = std::move(l);
+ builder.append("Gather", std::move(fn));
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::PReLU::Node &node)
+{
+ VERBOSE(PReLU) << "Configure PReLU operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index alpha_index{node.param().alpha_index};
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+
+ if (!(_ctx.at(ifm_index).shape() == _ctx.at(alpha_index).shape()))
+ {
+ const auto broadcast_rank =
+ std::max(_ctx.at(ifm_index).shape().rank(), _ctx.at(alpha_index).shape().rank());
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(ifm_index).shape())
+ .extendRank(broadcast_rank);
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(alpha_index).shape())
+ .extendRank(broadcast_rank);
+ }
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ _builder.addShapeConstr(alpha_index,
+ asTensorInfo(asTensorShape(_ctx.at(alpha_index).shape()),
+ _ctx.at(alpha_index).type(), _ctx.at(alpha_index).scale(),
+ _ctx.at(alpha_index).zeroPoint()));
+
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ int alpha_index;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+ param.alpha_index = alpha_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+ auto alpha_alloc = ctx.at(::internal::tflite::operand::Index{param.alpha_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLPReLU>();
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(alpha_alloc), CAST_CL(ofm_alloc));
+ builder.append("PReLU", std::move(fn));
+ }
+ else
+ {
+ // TODO Add NEON support
+
+ throw std::runtime_error("Not supported, yet");
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::ReLU::Node &node)
+{
+ VERBOSE(ReLU) << "Configure ReLU operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ // Set shape constraints
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), act_info);
+
+ builder.append("ReLU", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>();
+
+ fn->configure(ifm_alloc, ofm_alloc, act_info);
+
+ builder.append("ReLU", std::move(fn));
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::ReLU1::Node &node)
+{
+ VERBOSE(ReLU1) << "Configure ReLU1 operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ // Set shape constraints
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 1.0f, -1.0f};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), act_info);
+
+ builder.append("ReLU1", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>();
+
+ fn->configure(ifm_alloc, ofm_alloc, act_info);
+
+ builder.append("ReLU1", std::move(fn));
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::ReLU6::Node &node)
+{
+ VERBOSE(ReLU6) << "Configure ReLU6 operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ // Set shape constraints
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::BOUNDED_RELU, 6.0f};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), act_info);
+
+ builder.append("ReLU6", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>();
+
+ fn->configure(ifm_alloc, ofm_alloc, act_info);
+
+ builder.append("ReLU6", std::move(fn));
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Tanh::Node &node)
+{
+ VERBOSE(Tanh) << "Configure Tanh operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ // Set shape constraints
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::TANH, 1.0f, 1.0f};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), act_info);
+
+ builder.append("Tanh", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>();
+
+ fn->configure(ifm_alloc, ofm_alloc, act_info);
+
+ builder.append("Tanh", std::move(fn));
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Logistic::Node &node)
+{
+ VERBOSE(Logistic) << "Configure Logistic operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ // Set shape constraints
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LOGISTIC};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), act_info);
+
+ builder.append("Logistic", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>();
+
+ fn->configure(ifm_alloc, ofm_alloc, act_info);
+
+ builder.append("Logistic", std::move(fn));
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+// Reduce Mean
+void Planner::visit(const ::internal::tflite::op::Mean::Node &node)
+{
+ VERBOSE(Mean) << "Configure Mean operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index axis_index{node.param().axis_index};
+ const ::internal::tflite::operand::Index keep_dims_index{node.param().keep_dims_index};
+ const int keep_dims = _ctx.at(keep_dims_index).asScalar<int>();
+
+ const auto ifm_shape = _ctx.at(ifm_index).shape();
+ const auto ofm_shape = _ctx.at(ofm_index).shape();
+
+ // NOTE For the 4-dimensions, if the rank of input and output are different, this runtime only
+ // supports cases reducing height and width or reducing depth.
+ // TODO We have to support all cases of dimensions up to 4.
+ // For correct permuting, we have to set output's shape to be equal in dimension position of the
+ // input. But the positions of the same dimensions in the input and output may be set differently.
+ // For example {2,3,4,5}(input's shape) can be reduced to {3,5}(output's shape). The original
+ // output shape should be {1,3,1,5}, but real output shape may be {3,5}. If you simply try to
+ // extend it in 4 dimensions, it should be {1,1,3,5}.
+ // Even if output shape is changed to {1,3,1,5}, there is another problem. It is that shape of
+ // output tensor used at next operation is changed to {1,3,1,5} after this operation even if the
+ // next operation is not desired.
+ if (ifm_shape.rank() == 4 && ifm_shape.rank() != ofm_shape.rank())
+ {
+ if (ofm_shape.rank() == 2)
+ {
+ // Reducing HW
+ assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(3) == ofm_shape.dim(1));
+ }
+ else if (ofm_shape.rank() == 3)
+ {
+ // Reducing C or
+ // (Reducing H and C(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1)
+ assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(1) == ofm_shape.dim(1) &&
+ ifm_shape.dim(2) == ofm_shape.dim(2) ||
+ (ifm_shape.dim(0) == ofm_shape.dim(0) &&
+ (ifm_shape.dim(1) == ofm_shape.dim(1) || ifm_shape.dim(2) == ofm_shape.dim(1)) &&
+ ifm_shape.dim(3) == 1 && ofm_shape.dim(2) == 1));
+ }
+ }
+
+ // Set shape constraints
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+ _builder.addShapeConstr(axis_index,
+ asTensorInfo(asTensorShape(_ctx.at(axis_index).shape()),
+ _ctx.at(axis_index).type(), _ctx.at(axis_index).scale(),
+ _ctx.at(axis_index).zeroPoint()));
+
+ std::set<uint32_t> axis;
+ {
+ const auto ifm_rank = ifm_shape.rank();
+ const auto axis_shape = _ctx.at(axis_index).shape();
+ switch (axis_shape.rank())
+ {
+ case 0: // scalar
+ {
+ int32_t axis_value = _ctx.at(axis_index).asScalar<int32_t>();
+ if (axis_value < 0)
+ {
+ axis_value += ifm_rank;
+ }
+ axis.insert(ToARMComputeAxis(ifm_rank, axis_value).value());
+ break;
+ }
+ case 1: // vector
+ {
+ const auto axis_base = _ctx.at(axis_index).data().base();
+ const auto axis_size = _ctx.at(axis_index).shape().asVector();
+
+ // If axis's data does not exist as constant values and can be gotten as input data, we have
+ // to find a way to infer output shape when sinking output.
+ assert(axis_base != nullptr);
+ for (uint32_t n = 0; n < axis_size; ++n)
+ {
+ int32_t axis_value = *(reinterpret_cast<const int32_t *>(axis_base) + n);
+ if (axis_value < 0)
+ {
+ axis_value += ifm_rank;
+ }
+ axis.insert(ToARMComputeAxis(ifm_rank, axis_value).value());
+ }
+ break;
+ }
+ default:
+ throw std::runtime_error("Not supported");
+ break;
+ }
+ }
+
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ bool keep_dims;
+ std::set<uint32_t> axis;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+ param.keep_dims = keep_dims > 0 ? true : false;
+ param.axis = axis;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ ::arm_compute::Coordinates reduction_axis;
+ size_t i = 0;
+ for (auto index : param.axis)
+ {
+ reduction_axis.set(i++, index);
+ }
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLReduceMean>();
+
+ fn->configure(CAST_CL(ifm_alloc), reduction_axis, param.keep_dims, CAST_CL(ofm_alloc));
+
+ builder.append("Mean", std::move(fn));
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::RNN::Node &node)
+{
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index hidden_state_out_index{
+ node.param().hidden_state_out_index};
+
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+ const ::internal::tflite::operand::Index weights_index{node.param().weights_index};
+ const ::internal::tflite::operand::Index recurrent_weights_index{
+ node.param().recurrent_weights_index};
+ const ::internal::tflite::operand::Index bias_index{node.param().bias_index};
+ const ::internal::tflite::operand::Index hidden_state_in_index{
+ node.param().hidden_state_in_index};
+ const ::internal::tflite::operand::Index fused_activation_index{
+ node.param().fused_activation_index};
+
+ assert(_ctx.at(output_index).shape().rank() == 2 &&
+ _ctx.at(hidden_state_out_index).shape().rank() == 2 &&
+ _ctx.at(input_index).shape().rank() == 2 && _ctx.at(weights_index).shape().rank() == 2 &&
+ _ctx.at(recurrent_weights_index).shape().rank() == 2 &&
+ _ctx.at(hidden_state_in_index).shape().rank() == 2);
+ assert(_ctx.at(bias_index).shape().rank() == 1);
+
+ const auto batch_size = _ctx.at(output_index).shape().dim(0);
+ assert(batch_size == _ctx.at(input_index).shape().dim(0) &&
+ batch_size == _ctx.at(hidden_state_in_index).shape().dim(0) &&
+ batch_size == _ctx.at(hidden_state_out_index).shape().dim(0));
+ assert(_ctx.at(input_index).shape().dim(1) == _ctx.at(weights_index).shape().dim(1));
+
+ const auto num_units = _ctx.at(output_index).shape().dim(1);
+ assert(num_units == _ctx.at(weights_index).shape().dim(0) &&
+ num_units == _ctx.at(recurrent_weights_index).shape().dim(0) &&
+ num_units == _ctx.at(bias_index).shape().dim(0));
+ assert(num_units == _ctx.at(output_index).shape().dim(1) &&
+ num_units == _ctx.at(recurrent_weights_index).shape().dim(1) &&
+ num_units == _ctx.at(hidden_state_in_index).shape().dim(1) &&
+ num_units == _ctx.at(hidden_state_out_index).shape().dim(1));
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(hidden_state_out_index,
+ asTensorInfo(asTensorShape(_ctx.at(hidden_state_out_index).shape()),
+ _ctx.at(hidden_state_out_index).type(),
+ _ctx.at(hidden_state_out_index).scale(),
+ _ctx.at(hidden_state_out_index).zeroPoint()));
+ _builder.addShapeConstr(input_index,
+ asTensorInfo(asTensorShape(_ctx.at(input_index).shape()),
+ _ctx.at(input_index).type(), _ctx.at(input_index).scale(),
+ _ctx.at(input_index).zeroPoint()));
+ _builder.addShapeConstr(weights_index, asTensorInfo(asTensorShape(_ctx.at(weights_index).shape()),
+ _ctx.at(weights_index).type(),
+ _ctx.at(weights_index).scale(),
+ _ctx.at(weights_index).zeroPoint()));
+ _builder.addShapeConstr(recurrent_weights_index,
+ asTensorInfo(asTensorShape(_ctx.at(recurrent_weights_index).shape()),
+ _ctx.at(recurrent_weights_index).type(),
+ _ctx.at(recurrent_weights_index).scale(),
+ _ctx.at(recurrent_weights_index).zeroPoint()));
+ _builder.addShapeConstr(bias_index,
+ asTensorInfo(asTensorShape(_ctx.at(bias_index).shape()),
+ _ctx.at(bias_index).type(), _ctx.at(bias_index).scale(),
+ _ctx.at(bias_index).zeroPoint()));
+ _builder.addShapeConstr(hidden_state_in_index,
+ asTensorInfo(asTensorShape(_ctx.at(hidden_state_in_index).shape()),
+ _ctx.at(hidden_state_in_index).type(),
+ _ctx.at(hidden_state_in_index).scale(),
+ _ctx.at(hidden_state_in_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int output_index;
+ int hidden_state_out_index;
+
+ int input_index;
+ int weights_index;
+ int recurrent_weights_index;
+ int bias_index;
+ int hidden_state_in_index;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.hidden_state_out_index = hidden_state_out_index.asInt();
+
+ param.input_index = input_index.asInt();
+ param.weights_index = weights_index.asInt();
+ param.recurrent_weights_index = recurrent_weights_index.asInt();
+ param.bias_index = bias_index.asInt();
+ param.hidden_state_in_index = hidden_state_in_index.asInt();
+ param.activation = static_cast<FuseCode>(_ctx.at(fused_activation_index).asScalar<int32_t>());
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto hidden_state_out_alloc =
+ ctx.at(::internal::tflite::operand::Index{param.hidden_state_out_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+ auto weights_alloc = ctx.at(::internal::tflite::operand::Index{param.weights_index});
+ auto recurrent_weights_alloc =
+ ctx.at(::internal::tflite::operand::Index{param.recurrent_weights_index});
+ auto bias_alloc = ctx.at(::internal::tflite::operand::Index{param.bias_index});
+ auto hidden_state_in_alloc =
+ ctx.at(::internal::tflite::operand::Index{param.hidden_state_in_index});
+ auto act_info = asActivationInfo(param.activation);
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ std::unique_ptr<::arm_compute::CLCopy> copy_fn{new ::arm_compute::CLCopy};
+ copy_fn->configure(CAST_CL(hidden_state_in_alloc), CAST_CL(hidden_state_out_alloc));
+ builder.append("COPY", std::move(copy_fn));
+
+ std::unique_ptr<::arm_compute::CLRNNLayer> rnn_fn{new ::arm_compute::CLRNNLayer};
+
+ // The hidden_state_in's data must be copied to hidden_state_out_alloc before fn->run() is
+ // performed.
+ rnn_fn->configure(CAST_CL(input_alloc), CAST_CL(weights_alloc),
+ CAST_CL(recurrent_weights_alloc), CAST_CL(bias_alloc),
+ CAST_CL(hidden_state_out_alloc), CAST_CL(output_alloc), act_info);
+
+ builder.append("RNN", std::move(rnn_fn));
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::LSTM::Node &node)
+{
+ // TODO Implement LSTM op
+ throw std::runtime_error("Not supported, yet");
+}
+
+void Planner::visit(const ::internal::tflite::op::Transpose::Node &node)
+{
+ VERBOSE(Transpose) << "Configure Transpose operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index permu_index{node.param().permu_index};
+
+ assert(_ctx.at(ifm_index).shape().rank() == _ctx.at(ofm_index).shape().rank());
+ assert(_ctx.at(permu_index).hasData() == true);
+
+ // Set shape constraints
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ const int32_t *pv;
+ int rank;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+ param.pv = reinterpret_cast<const int32_t *>(_ctx.at(permu_index).data().base());
+ param.rank = _ctx.at(ifm_index).shape().rank();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ const auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLPermute>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc),
+ getARMComputePermutationVector(param.rank, param.pv));
+
+ builder.append("Transpose", std::move(fn));
+ }
+ else
+ {
+ throw std::runtime_error("Not supported, yet");
+ }
+
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Floor::Node &node)
+{
+ VERBOSE(Floor) << "Configure Floor operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().output_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().input_index};
+
+ // Set shape constraints
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLFloor>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc));
+
+ builder.append("Floor", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEFloor>();
+
+ fn->configure(ifm_alloc, ofm_alloc);
+
+ builder.append("Floor", std::move(fn));
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::ArgMax::Node &node)
+{
+ VERBOSE(ArgMax) << "Configure ARGMAX operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index axis_index{node.param().axis_index};
+
+ auto ifm_shape = _ctx.at(ifm_index).shape();
+ auto ofm_shape = _ctx.at(ofm_index).shape();
+ auto axis_shape = _ctx.at(axis_index).shape();
+
+ assert(_ctx.at(axis_index).hasData());
+ // Axis dimension is always 1.
+ assert(axis_shape.rank() == 1);
+ assert((ifm_shape.rank() - 1) == ofm_shape.rank());
+
+ _builder.addShapeConstr(ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape(), false),
+ _ctx.at(ofm_index).type()));
+ _builder.addShapeConstr(ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape(), false),
+ _ctx.at(ifm_index).type()));
+
+ std::vector<uint32_t> l_axis;
+ const auto axis_size = _ctx.at(axis_index).shape().asVector();
+ auto axis_base = _ctx.at(axis_index).data().base();
+ auto axis_type = _ctx.at(axis_index).type();
+ // TODO Should support axis size > 1.
+ assert(axis_size == 1);
+ // axis is tensor with 1 dimension - always a vector.
+ assert(axis_base != nullptr);
+ for (uint32_t n = 0; n < axis_size; ++n)
+ {
+ int32_t axis_value = *(reinterpret_cast<const int32_t *>(axis_base) + n);
+ if (axis_value < 0)
+ {
+ axis_value += ifm_shape.rank();
+ }
+ l_axis.push_back(ToARMComputeAxis(ifm_shape.rank(), axis_value).value());
+ }
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ std::vector<uint32_t> axis;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+ param.axis = l_axis;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ {
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLArgOperation>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), param.axis,
+ ::arm_compute::ArgOperation::MAX);
+
+ builder.append("ArgMax", std::move(fn));
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::SQRT::Node &node)
+{
+ VERBOSE(SQRT) << "Configure SQRT operation" << std::endl;
+
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+
+ // Set shape constraints
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(input_index,
+ asTensorInfo(asTensorShape(_ctx.at(input_index).shape()),
+ _ctx.at(input_index).type(), _ctx.at(input_index).scale(),
+ _ctx.at(input_index).zeroPoint()));
+
+ struct Param
+ {
+ int output_index;
+ int input_index;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input_index = input_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::SQRT};
+
+ {
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>();
+
+ fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc), act_info);
+
+ builder.append("SQRT", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>();
+
+ fn->configure(input_alloc, output_alloc, act_info);
+
+ builder.append("SQRT", std::move(fn));
+ }
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::RSQRT::Node &node)
+{
+ VERBOSE(RSQRT) << "Configure Rsqrt operation" << std::endl;
+
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+
+ // Set shape constraints
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(input_index,
+ asTensorInfo(asTensorShape(_ctx.at(input_index).shape()),
+ _ctx.at(input_index).type(), _ctx.at(input_index).scale(),
+ _ctx.at(input_index).zeroPoint()));
+
+ struct Param
+ {
+ int output_index;
+ int input_index;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input_index = input_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLRsqrtLayer>();
+
+ fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc));
+
+ builder.append("RSQRT", std::move(fn));
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Equal::Node &node)
+{
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input1_index{node.param().input1_index};
+ const ::internal::tflite::operand::Index input2_index{node.param().input2_index};
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+
+ if (!(_ctx.at(input1_index).shape() == _ctx.at(input2_index).shape()))
+ {
+ const auto broadcast_rank =
+ std::max(_ctx.at(input1_index).shape().rank(), _ctx.at(input2_index).shape().rank());
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input1_index).shape())
+ .extendRank(broadcast_rank);
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input2_index).shape())
+ .extendRank(broadcast_rank);
+ }
+ _builder.addShapeConstr(input1_index,
+ asTensorInfo(asTensorShape(_ctx.at(input1_index).shape()),
+ _ctx.at(input1_index).type(), _ctx.at(input1_index).scale(),
+ _ctx.at(input1_index).zeroPoint()));
+ _builder.addShapeConstr(input2_index,
+ asTensorInfo(asTensorShape(_ctx.at(input2_index).shape()),
+ _ctx.at(input2_index).type(), _ctx.at(input2_index).scale(),
+ _ctx.at(input2_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int output_index;
+ int input1_index;
+ int input2_index;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input1_index = input1_index.asInt();
+ param.input2_index = input2_index.asInt();
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input1_alloc = ctx.at(::internal::tflite::operand::Index{param.input1_index});
+ auto input2_alloc = ctx.at(::internal::tflite::operand::Index{param.input2_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLComparison>();
+
+ fn->configure(CAST_CL(input1_alloc), CAST_CL(input2_alloc), CAST_CL(output_alloc),
+ ::arm_compute::ComparisonOperation::Equal);
+
+ builder.append("Equal", std::move(fn));
+ }
+ else
+ {
+ // TODO Add NEON support
+
+ throw std::runtime_error("Not supported, yet");
+ }
+ };
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::TransposeConv::Node &node)
+{
+ VERBOSE(TransposeConv) << "Configure TransposeConv operation" << std::endl;
+
+ const ::internal::tflite::operand::Index op_shape_index{node.param().op_shape_index};
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index ker_index{node.param().ker_index};
+
+ const ::internal::tflite::operand::Index padding_index{node.param().padding_index};
+ const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index};
+ const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index};
+
+ // Only 4D tensors are supported
+ assert(_ctx.at(ofm_index).shape().rank() == 4);
+ assert(_ctx.at(ofm_index).shape().rank() == _ctx.at(ifm_index).shape().rank());
+ assert(_ctx.at(ofm_index).shape().rank() == _ctx.at(ker_index).shape().rank());
+
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
+ const auto ker_shape = _ctx.at(ker_index).shape().asFeature();
+
+ assert(_ctx.at(padding_index).hasData() == true);
+
+ const int32_t vstride = _ctx.at(vstride_index).asScalar<int32_t>();
+ const int32_t hstride = _ctx.at(hstride_index).asScalar<int32_t>();
+
+ const PaddingCode padding_type =
+ static_cast<PaddingCode>(_ctx.at(padding_index).asScalar<int32_t>());
+
+ assert(vstride > 0);
+ assert(hstride > 0);
+ assert((ANEURALNETWORKS_PADDING_SAME == padding_type) ||
+ (ANEURALNETWORKS_PADDING_VALID == padding_type));
+ assert(ifm_shape.N == ofm_shape.N);
+ assert(ifm_shape.C == ker_shape.C);
+ assert(ker_shape.N == ofm_shape.C);
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ker_index, asTensorInfo(asTensorShape(_ctx.at(ker_index).shape()), _ctx.at(ker_index).type(),
+ _ctx.at(ker_index).scale(), _ctx.at(ker_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ int ker_index;
+ Padding padding;
+ Stride stride;
+ uint32_t invalid_horizontal;
+ uint32_t invalid_vertical;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+ param.ker_index = ker_index.asInt();
+
+ param.stride.horizontal = hstride;
+ param.stride.vertical = vstride;
+
+ param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME)
+ ? same_padding(ofm_shape, ifm_shape, param.stride, ker_shape.W, ker_shape.H)
+ : valid_padding();
+
+ param.invalid_horizontal =
+ (padding_type == ANEURALNETWORKS_PADDING_SAME)
+ ? 0
+ : ofm_shape.W - (1 + (ifm_shape.W - 1) * hstride) - (ker_shape.W - 1);
+ param.invalid_vertical =
+ (padding_type == ANEURALNETWORKS_PADDING_SAME)
+ ? 0
+ : ofm_shape.H - (1 + (ifm_shape.H - 1) * param.stride.vertical) - (ker_shape.H - 1);
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+ auto ker_alloc = ctx.at(::internal::tflite::operand::Index{param.ker_index});
+
+ // Only rank 4 is supported
+ const int rank = 4;
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLTransposeConvLayer>();
+
+ auto symmetric_tconv_info = asPadStrideInfo(param.padding, param.stride);
+
+ // TODO Support WeightInfo in some cases in order to performance improvement
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ker_alloc), nullptr, CAST_CL(ofm_alloc),
+ symmetric_tconv_info, param.invalid_horizontal, param.invalid_vertical);
+ builder.append("TransposeConv", std::move(fn));
+ }
+ else
+ {
+ throw std::runtime_error("Not supported, yet");
+ }
+ };
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::SquaredDifference::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index lhs_index{node.param().lhs_index};
+ const ::internal::tflite::operand::Index rhs_index{node.param().rhs_index};
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+
+ if (!(_ctx.at(lhs_index).shape() == _ctx.at(rhs_index).shape()))
+ {
+ const auto broadcast_rank =
+ std::max(_ctx.at(lhs_index).shape().rank(), _ctx.at(rhs_index).shape().rank());
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(lhs_index).shape())
+ .extendRank(broadcast_rank);
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(rhs_index).shape())
+ .extendRank(broadcast_rank);
+ }
+ _builder.addShapeConstr(
+ lhs_index, asTensorInfo(asTensorShape(_ctx.at(lhs_index).shape()), _ctx.at(lhs_index).type(),
+ _ctx.at(lhs_index).scale(), _ctx.at(lhs_index).zeroPoint()));
+ _builder.addShapeConstr(
+ rhs_index, asTensorInfo(asTensorShape(_ctx.at(rhs_index).shape()), _ctx.at(rhs_index).type(),
+ _ctx.at(rhs_index).scale(), _ctx.at(rhs_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int lhs_index;
+ int rhs_index;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.lhs_index = lhs_index.asInt();
+ param.rhs_index = rhs_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto lhs_alloc = ctx.at(::internal::tflite::operand::Index{param.lhs_index});
+ auto rhs_alloc = ctx.at(::internal::tflite::operand::Index{param.rhs_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLElementwiseSquaredDiff>();
+
+ fn->configure(CAST_CL(lhs_alloc), CAST_CL(rhs_alloc), CAST_CL(ofm_alloc));
+ builder.append("SquaredDifference", std::move(fn));
+ }
+ else
+ {
+ // TODO Enable NEON Support
+ throw std::runtime_error("Not supported, yet");
+ }
+
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Split::Node &node)
+{
+ VERBOSE(Split) << "Configure Split operation" << std::endl;
+
+ const ::internal::tflite::operand::Index axis_index{node.param().axis_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ const auto ifm_shape = _ctx.at(ifm_index).shape();
+ int32_t axis = _ctx.at(axis_index).asScalar<int32_t>();
+
+ // Handle negative axis
+ if (axis < 0)
+ {
+ axis += ifm_shape.rank();
+ }
+
+ const int32_t num_split = node.param().ofm_indexes.size();
+ const auto input_size = ifm_shape.dim(axis);
+ assert(input_size % num_split == 0);
+ const int32_t slice_size = input_size / num_split;
+
+ // Set Shape Constraints and TensorInfo (for input)
+ _builder.addShapeConstr(ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()),
+ _ctx.at(ifm_index).type()));
+
+ // Set Shape Constraints and TensorInfo (for output)
+ const auto rank = ifm_shape.rank();
+ const uint32_t coord_index = ToARMComputeAxis(rank, axis).value();
+ uint32_t depth = 0;
+
+ ::arm_compute::Coordinates coordinates;
+ coordinates.set_num_dimensions(rank);
+
+ for (const auto &index : node.param().ofm_indexes)
+ {
+ const ::internal::tflite::operand::Index ofm_index{index};
+
+ coordinates[coord_index] = depth;
+
+ _builder.addSubsumptionConstr(ofm_index, ifm_index, coordinates,
+ asTensorShape(_ctx.at(ofm_index).shape()), true);
+ depth += slice_size;
+ }
+
+ // NOTE Split has no actual operation!
+}
+
+void Planner::visit(const ::internal::tflite::op::Pad::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index paddings_index{node.param().paddings_index};
+
+ assert(_ctx.at(paddings_index).hasData() == true);
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(ifm_index,
+ asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape(), false),
+ _ctx.at(ifm_index).type(), _ctx.at(ifm_index).scale(),
+ _ctx.at(ifm_index).zeroPoint()));
+ _builder.addShapeConstr(ofm_index,
+ asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape(), false),
+ _ctx.at(ofm_index).type(), _ctx.at(ofm_index).scale(),
+ _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ paddings_index, asTensorInfo(asTensorShape(_ctx.at(paddings_index).shape(), false),
+ _ctx.at(paddings_index).type(), _ctx.at(paddings_index).scale(),
+ _ctx.at(paddings_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ ::arm_compute::PixelValue pixel_value;
+ ::arm_compute::PaddingList padding_list;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ // initializer for padding
+ auto rank = _ctx.at(ifm_index).shape().rank();
+ auto pad_type = _ctx.at(paddings_index).type();
+
+ if (pad_type == ANEURALNETWORKS_TENSOR_INT32)
+ {
+ auto pad_base = _ctx.at(paddings_index).data().base();
+ auto pad_shape = _ctx.at(paddings_index).shape();
+
+ param.padding_list.resize(rank);
+ for (int32_t n = 0; n < rank; ++n)
+ {
+ const int32_t *from = reinterpret_cast<const int32_t *>(pad_base) + (n * pad_shape.dim(1));
+ auto axis = ToARMComputeAxis(rank, n).value();
+
+ param.padding_list[axis] = ::arm_compute::PaddingInfo{from[0], from[1]};
+ }
+ auto data_type = asDataType(_ctx.at(ifm_index).type());
+ auto quant_info =
+ asQuantizationInfo(_ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint());
+ param.pixel_value = ::arm_compute::PixelValue{0, data_type, quant_info};
+ }
+ else
+ {
+ throw std::runtime_error("Only Int32 datatype is supported for Pad values");
+ }
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ {
+ if (::internal::arm_compute::isGpuMode()) // GPU
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLPadLayer>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), param.padding_list,
+ param.pixel_value);
+
+ builder.append("PAD", std::move(fn));
+ }
+ else // NEON
+ {
+ // TODO Enable NEON Support
+ throw std::runtime_error("Not supported, yet");
+ }
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::SpaceToDepth::Node &node)
+{
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+ const ::internal::tflite::operand::Index block_size_index{node.param().block_size_index};
+
+ const auto input_batch = _ctx.at(input_index).shape().dim(0);
+ const auto output_batch = _ctx.at(output_index).shape().dim(0);
+ const auto input_depth = _ctx.at(input_index).shape().dim(3);
+ const auto output_depth = _ctx.at(output_index).shape().dim(3);
+ const auto block_size = _ctx.at(block_size_index).asScalar<int32_t>();
+ const auto input_height = _ctx.at(input_index).shape().dim(1);
+ const auto input_width = _ctx.at(input_index).shape().dim(2);
+
+ // All assertions as per NNAPI specification.
+ assert(_ctx.at(input_index).shape().rank() == 4);
+ assert(_ctx.at(output_index).shape().rank() == 4);
+ assert((block_size >= 1) && (input_height % block_size == 0) && (input_width % block_size == 0));
+ assert(input_batch == output_batch);
+ assert(input_depth * block_size * block_size == output_depth);
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape(), false),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(input_index,
+ asTensorInfo(asTensorShape(_ctx.at(input_index).shape(), false),
+ _ctx.at(input_index).type(), _ctx.at(input_index).scale(),
+ _ctx.at(input_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int output_index;
+ int input_index;
+ int32_t block_size;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input_index = input_index.asInt();
+ param.block_size = block_size;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+
+ {
+ if (::internal::arm_compute::isGpuMode()) // GPU
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLSpaceToDepth>();
+
+ fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc), param.block_size);
+
+ builder.append("SpaceToDepth", std::move(fn));
+ }
+ else // NEON
+ {
+ // TODO Enable NEON Support
+ throw std::runtime_error("Not supported, yet");
+ }
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::SpaceToBatchND::Node &node)
+{
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+ const ::internal::tflite::operand::Index block_size_index{node.param().block_size_index};
+ const ::internal::tflite::operand::Index padding_size_index{node.param().padding_size_index};
+
+ const auto &output_shape = _ctx.at(output_index).shape();
+ const auto &input_shape = _ctx.at(input_index).shape();
+ const auto &padding_size_shape = _ctx.at(padding_size_index).shape();
+ auto block_size_base = reinterpret_cast<const int32_t *>(_ctx.at(block_size_index).data().base());
+ auto padding_size_base =
+ reinterpret_cast<const int32_t *>(_ctx.at(padding_size_index).data().base());
+
+ { // New block for assertions
+ const auto &block_size_shape = _ctx.at(block_size_index).shape();
+
+ // Currently, only 4D NHWC input/output op_context are supported.
+ // The 4D array need to have exactly 2 spatial dimensions.
+ // TODO: Support arbitrary dimension in SpaceToBatchND.
+ assert(input_shape.rank() == 4);
+ assert(output_shape.rank() == 4);
+ assert(block_size_shape.rank() == 1);
+ assert(padding_size_shape.rank() == 2);
+
+ assert(output_shape.dim(3) == input_shape.dim(3));
+ assert(block_size_shape.dim(0) == 2);
+ assert(padding_size_shape.dim(0) == 2);
+ assert(padding_size_shape.dim(1) == 2);
+
+ assert(_ctx.at(block_size_index).hasData() && _ctx.at(padding_size_index).hasData());
+ assert(_ctx.at(block_size_index).type() == ANEURALNETWORKS_TENSOR_INT32);
+ assert(_ctx.at(padding_size_index).type() == ANEURALNETWORKS_TENSOR_INT32);
+
+ assert(block_size_base[0] > 0 && block_size_base[1] > 0);
+ assert(output_shape.dim(0) == input_shape.dim(0) * block_size_base[0] * block_size_base[1]);
+ assert(output_shape.dim(1) ==
+ (input_shape.dim(1) + padding_size_base[0] + padding_size_base[1]) / block_size_base[0]);
+ assert(output_shape.dim(2) ==
+ (input_shape.dim(2) + padding_size_base[2] + padding_size_base[3]) / block_size_base[1]);
+ }
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape(), false),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(input_index,
+ asTensorInfo(asTensorShape(_ctx.at(input_index).shape(), false),
+ _ctx.at(input_index).type(), _ctx.at(input_index).scale(),
+ _ctx.at(input_index).zeroPoint()));
+
+ _builder.addShapeConstr(block_size_index,
+ asTensorInfo(asTensorShape(_ctx.at(block_size_index).shape()),
+ _ctx.at(block_size_index).type(),
+ _ctx.at(block_size_index).scale(),
+ _ctx.at(block_size_index).zeroPoint()));
+
+ _builder.addShapeConstr(padding_size_index,
+ asTensorInfo(asTensorShape(_ctx.at(padding_size_index).shape()),
+ _ctx.at(padding_size_index).type(),
+ _ctx.at(padding_size_index).scale(),
+ _ctx.at(padding_size_index).zeroPoint()));
+
+ { // Append block_size initializer
+ auto initializer = [block_size_base](::arm_compute::ITensor &tensor) {
+ const auto block_size_y = block_size_base[0];
+ const auto block_size_x = block_size_base[1];
+
+ auto into = reinterpret_cast<int32_t *>(tensor.ptr_to_element({0}));
+ into[0] = block_size_x;
+ into[1] = block_size_y;
+ };
+ _builder.addInitializer(block_size_index, initializer);
+ }
+
+ { // Append padding_size initializer
+ auto initializer = [padding_size_base, padding_size_shape](::arm_compute::ITensor &tensor) {
+ // If n == 0, then the axis is the height
+ // If n == 1, then the axis is the width
+ for (size_t n = 0; n < padding_size_shape.dim(0); ++n)
+ {
+ const auto from = padding_size_base + (n * padding_size_shape.dim(1));
+ auto into = reinterpret_cast<int32_t *>(tensor.ptr_to_element({0, 1 - n}));
+ into[0] = from[0];
+ into[1] = from[1];
+ }
+ };
+ _builder.addInitializer(padding_size_index, initializer);
+ }
+
+ // Construct operation parameters
+ struct Param
+ {
+ int output_index;
+ int input_index;
+ int block_size_index;
+ int padding_size_index;
+ int32_t rank;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input_index = input_index.asInt();
+ param.block_size_index = block_size_index.asInt();
+ param.padding_size_index = padding_size_index.asInt();
+ param.rank = _ctx.at(input_index).shape().rank();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+ auto block_size_alloc = ctx.at(::internal::tflite::operand::Index{param.block_size_index});
+ auto padding_size_alloc = ctx.at(::internal::tflite::operand::Index{param.padding_size_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLSpaceToBatchND>();
+
+ fn->configure(CAST_CL(input_alloc), CAST_CL(block_size_alloc), CAST_CL(padding_size_alloc),
+ CAST_CL(output_alloc));
+ builder.append("SpaceToBatchND", std::move(fn));
+ }
+ else
+ {
+ // TODO Enable NEON Support
+ throw std::runtime_error("Not supported, yet");
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::BatchToSpaceNd::Node &node)
+{
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+ const ::internal::tflite::operand::Index block_size_index{node.param().block_size_index};
+
+ assert(_ctx.at(input_index).shape().rank() == 4);
+ assert(_ctx.at(output_index).shape().rank() == 4);
+ assert(_ctx.at(block_size_index).shape().rank() == 1);
+ assert(_ctx.at(block_size_index).hasData() == true);
+
+ const int32_t *block_size =
+ reinterpret_cast<const int32_t *>(_ctx.at(block_size_index).data().base());
+
+ const auto &output_shape = _ctx.at(output_index).shape();
+ const auto &input_shape = _ctx.at(input_index).shape();
+ const auto &block_size_shape = _ctx.at(block_size_index).shape();
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ output_index, asTensorInfo(asTensorShape(output_shape, false), _ctx.at(output_index).type(),
+ _ctx.at(output_index).scale(), _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(
+ input_index, asTensorInfo(asTensorShape(input_shape, false), _ctx.at(input_index).type(),
+ _ctx.at(input_index).scale(), _ctx.at(input_index).zeroPoint()));
+
+ _builder.addShapeConstr(block_size_index, asTensorInfo(asTensorShape(block_size_shape),
+ _ctx.at(block_size_index).type(),
+ _ctx.at(block_size_index).scale(),
+ _ctx.at(block_size_index).zeroPoint()));
+
+ // initializer for block_size
+ {
+ const auto block_size_base =
+ reinterpret_cast<const int32_t *>(_ctx.at(block_size_index).data().base());
+
+ assert(output_shape.dim(3) == input_shape.dim(3));
+ assert(output_shape.dim(1) == input_shape.dim(1) * block_size_base[0]);
+ assert(output_shape.dim(2) == input_shape.dim(2) * block_size_base[1]);
+ assert(output_shape.dim(0) == input_shape.dim(0) / (block_size_base[0] * block_size_base[1]));
+ assert(_ctx.at(block_size_index).type() == ANEURALNETWORKS_TENSOR_INT32);
+
+ assert((_ctx.at(block_size_index).data().size() / sizeof(int32_t)) == 2 &&
+ block_size_base[0] > 0 && block_size_base[1] > 0);
+
+ auto initializer = [block_size_base](::arm_compute::ITensor &tensor) {
+ const int32_t *from = reinterpret_cast<const int32_t *>(block_size_base);
+ int32_t *into = reinterpret_cast<int32_t *>(tensor.ptr_to_element({0}));
+ into[0] = from[1];
+ into[1] = from[0];
+ };
+ _builder.addInitializer(block_size_index, initializer);
+ }
+
+ // Construct operation parameters
+ struct Param
+ {
+ int output_index;
+ int input_index;
+ int block_size_index;
+ const int32_t *block_size;
+ int32_t rank;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input_index = input_index.asInt();
+ param.block_size_index = block_size_index.asInt();
+ param.block_size = block_size;
+ param.rank = _ctx.at(input_index).shape().rank();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+ auto block_size_alloc = ctx.at(::internal::tflite::operand::Index{param.block_size_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLBatchToSpaceLayer>();
+
+ fn->configure(CAST_CL(input_alloc), CAST_CL(block_size_alloc), CAST_CL(output_alloc));
+ builder.append("BatchToSpaceND", std::move(fn));
+ }
+ else
+ {
+ // TODO Enable NEON Support
+ throw std::runtime_error("Not supported, yet");
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::L2Normalization::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+
+ // {CL|Neon}L2Normalization performs the reduction only along dimension 0
+ // L2 Normalization always performs the reduction along the depth axis
+ // Thus, we repurpose {CL|Neon}NormalizationLayers to act as depthwise L2 normalizations by
+ // choosing normalization parameters as below
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ int32_t radius;
+ float alpha;
+ float beta;
+ float bias;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ param.radius = 2 * _ctx.at(ifm_index).shape().dim(3) + 1; // normSize = depth * 2 + 1
+ param.alpha = 1.0f; // In the implementation to make alpha_ become 1
+ param.beta = 0.5f; // pow(reduction, -0.5) = 1 / sqrt(reduction)
+ param.bias = 0.0f; // Don't offset the reduction.
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ const auto norm_info =
+ ::arm_compute::NormalizationLayerInfo(::arm_compute::NormType::CROSS_MAP, param.radius,
+ param.alpha, param.beta, param.bias, false);
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLNormalizationLayer>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), norm_info);
+
+ builder.append("L2Normalize", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NENormalizationLayer>();
+
+ fn->configure(ifm_alloc, ofm_alloc, norm_info);
+
+ builder.append("L2Normalize", std::move(fn));
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::L2Pool2D::Implicit::Node &node)
+
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ const ::internal::tflite::operand::Index kh_index{node.param().kh_index};
+ const ::internal::tflite::operand::Index kw_index{node.param().kw_index};
+
+ const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index};
+ const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index};
+
+ const ::internal::tflite::operand::Index padding_index{node.param().padding_index};
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature();
+ const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature();
+
+ const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>();
+ const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>();
+
+ const int32_t vstride = _ctx.at(vstride_index).asScalar<int32_t>();
+ const int32_t hstride = _ctx.at(hstride_index).asScalar<int32_t>();
+
+ const PaddingCode padding_type =
+ static_cast<PaddingCode>(_ctx.at(padding_index).asScalar<int32_t>());
+
+ assert((ANEURALNETWORKS_PADDING_SAME == padding_type) ||
+ (ANEURALNETWORKS_PADDING_VALID == padding_type));
+
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+
+ uint32_t kw;
+ uint32_t kh;
+
+ Padding padding;
+ Stride stride;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ param.kh = kh;
+ param.kw = kw;
+
+ param.stride.vertical = vstride;
+ param.stride.horizontal = hstride;
+
+ param.padding = (padding_type == ANEURALNETWORKS_PADDING_SAME)
+ ? same_padding(ifm_shape, ofm_shape, param.stride, kw, kh)
+ : valid_padding();
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ ::arm_compute::PoolingLayerInfo info{::arm_compute::PoolingType::L2,
+ ::arm_compute::Size2D{param.kw, param.kh},
+ asPadStrideInfo(param.padding, param.stride)};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer};
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), info);
+
+ builder.append("L2Pool2D", std::move(fn));
+ }
+ else
+ {
+ std::unique_ptr<::arm_compute::NEPoolingLayer> fn{new ::arm_compute::NEPoolingLayer};
+
+ fn->configure(ifm_alloc, ofm_alloc, info);
+
+ builder.append("L2Pool2D", std::move(fn));
+ }
+
+ ActivationBuilder{builder}.append(param.activation, ofm_alloc);
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::L2Pool2D::Explicit::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ const ::internal::tflite::operand::Index kh_index{node.param().kh_index};
+ const ::internal::tflite::operand::Index kw_index{node.param().kw_index};
+
+ const ::internal::tflite::operand::Index vstride_index{node.param().vstride_index};
+ const ::internal::tflite::operand::Index hstride_index{node.param().hstride_index};
+
+ const ::internal::tflite::operand::Index padding_left_index{node.param().padding_left_index};
+ const ::internal::tflite::operand::Index padding_right_index{node.param().padding_right_index};
+ const ::internal::tflite::operand::Index padding_top_index{node.param().padding_top_index};
+ const ::internal::tflite::operand::Index padding_bottom_index{node.param().padding_bottom_index};
+
+ const ::internal::tflite::operand::Index activation_index{node.param().activation_index};
+
+ const int32_t kh = _ctx.at(kh_index).asScalar<int32_t>();
+ const int32_t kw = _ctx.at(kw_index).asScalar<int32_t>();
+
+ const int32_t vstride = _ctx.at(vstride_index).asScalar<int32_t>();
+ const int32_t hstride = _ctx.at(hstride_index).asScalar<int32_t>();
+
+ const int32_t padding_left = _ctx.at(padding_left_index).asScalar<int32_t>();
+ const int32_t padding_right = _ctx.at(padding_right_index).asScalar<int32_t>();
+ const int32_t padding_top = _ctx.at(padding_top_index).asScalar<int32_t>();
+ const int32_t padding_bottom = _ctx.at(padding_bottom_index).asScalar<int32_t>();
+
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+
+ uint32_t kw;
+ uint32_t kh;
+
+ Padding padding;
+ Stride stride;
+
+ FuseCode activation;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ param.kh = kh;
+ param.kw = kw;
+
+ param.stride.vertical = vstride;
+ param.stride.horizontal = hstride;
+
+ param.padding.left = padding_left;
+ param.padding.right = padding_right;
+ param.padding.top = padding_top;
+ param.padding.bottom = padding_bottom;
+
+ param.activation = static_cast<FuseCode>(_ctx.at(activation_index).asScalar<int32_t>());
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ ::arm_compute::PoolingLayerInfo info{::arm_compute::PoolingType::L2,
+ ::arm_compute::Size2D{param.kw, param.kh},
+ asPadStrideInfo(param.padding, param.stride)};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ std::unique_ptr<::arm_compute::CLPoolingLayer> fn{new ::arm_compute::CLPoolingLayer};
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), info);
+
+ builder.append("L2Pool2D", std::move(fn));
+ }
+ else
+ {
+ std::unique_ptr<::arm_compute::NEPoolingLayer> fn{new ::arm_compute::NEPoolingLayer};
+
+ fn->configure(ifm_alloc, ofm_alloc, info);
+
+ builder.append("L2Pool2D", std::move(fn));
+ }
+
+ ActivationBuilder{builder}.append(param.activation, ofm_alloc);
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::EmbeddingLookup::Node &node)
+{
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index lookups_index{node.param().lookups_index};
+ const ::internal::tflite::operand::Index values_index{node.param().values_index};
+
+ const auto &output_obj = _ctx.at(output_index);
+ const auto &lookups_obj = _ctx.at(lookups_index);
+ const auto &values_obj = _ctx.at(values_index);
+
+ // Verify operand here, not at configure() to avoid acl's modifying
+ // TensorShape sometimes(Issue: https://github.sec.samsung.net/STAR/nnfw/issues/729)
+ {
+ assert(lookups_obj.type() == ANEURALNETWORKS_TENSOR_INT32);
+
+ const auto &output_shape = output_obj.shape();
+ const auto &lookups_shape = lookups_obj.shape();
+ const auto &values_shape = values_obj.shape();
+
+ assert(lookups_shape.rank() == 1);
+ assert(values_shape.rank() >= 2);
+
+ // output should be a n-D tensor with the same rank and shape as the values tensor, except for
+ // the first dimension which has the same size as lookups' only dimension.
+ assert(output_shape.rank() == values_shape.rank());
+ assert(output_shape.dim(0) == lookups_shape.dim(0));
+ for (size_t n = 1; n < output_shape.rank(); ++n)
+ {
+ assert(output_shape.dim(n) == values_shape.dim(n));
+ }
+ }
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(output_obj.shape(), false), output_obj.type(),
+ output_obj.scale(), output_obj.zeroPoint()));
+ _builder.addShapeConstr(lookups_index,
+ asTensorInfo(asTensorShape(lookups_obj.shape()), lookups_obj.type(),
+ lookups_obj.scale(), lookups_obj.zeroPoint()));
+ _builder.addShapeConstr(values_index,
+ asTensorInfo(asTensorShape(values_obj.shape(), false), values_obj.type(),
+ values_obj.scale(), values_obj.zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int32_t output_index;
+ int32_t lookups_index;
+ int32_t values_index;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.lookups_index = lookups_index.asInt();
+ param.values_index = values_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto lookups_alloc = ctx.at(::internal::tflite::operand::Index{param.lookups_index});
+ auto values_alloc = ctx.at(::internal::tflite::operand::Index{param.values_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLEmbeddingLookup>();
+
+ fn->configure(CAST_CL(values_alloc), CAST_CL(output_alloc), CAST_CL(lookups_alloc));
+
+ builder.append("EmbeddingLookup", std::move(fn));
+ }
+ else
+ {
+ // TODO Enable NEON Support
+ throw std::runtime_error("Not supported, yet");
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::HashtableLookup::Node &node)
+{
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index hits_index{node.param().hits_index};
+ const ::internal::tflite::operand::Index lookups_index{node.param().lookups_index};
+ const ::internal::tflite::operand::Index values_index{node.param().values_index};
+ const ::internal::tflite::operand::Index keys_index{node.param().keys_index};
+
+ const auto &lookups_obj = _ctx.at(lookups_index);
+ const auto &keys_obj = _ctx.at(keys_index);
+ const auto &hits_obj = _ctx.at(hits_index);
+ const auto &values_obj = _ctx.at(values_index);
+ const auto &output_obj = _ctx.at(output_index);
+
+ assert(lookups_obj.type() == ANEURALNETWORKS_TENSOR_INT32);
+ assert(keys_obj.type() == ANEURALNETWORKS_TENSOR_INT32);
+ assert(hits_obj.type() == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM);
+
+ const auto &lookups_shape = lookups_obj.shape();
+ const auto &keys_shape = keys_obj.shape();
+ const auto &hits_shape = hits_obj.shape();
+ const auto &values_shape = values_obj.shape();
+ const auto &output_shape = output_obj.shape();
+
+ assert(values_shape.rank() == output_shape.rank());
+
+ assert(lookups_shape.rank() == 1);
+ assert(keys_shape.rank() == 1);
+ assert(values_shape.dim(0) == keys_shape.dim(0));
+ assert(lookups_shape.dim(0) == output_shape.dim(0));
+
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(hits_index,
+ asTensorInfo(asTensorShape(_ctx.at(hits_index).shape()),
+ _ctx.at(hits_index).type(), _ctx.at(hits_index).type(),
+ _ctx.at(hits_index).zeroPoint()));
+
+ _builder.addShapeConstr(lookups_index, asTensorInfo(asTensorShape(_ctx.at(lookups_index).shape()),
+ _ctx.at(lookups_index).type(),
+ _ctx.at(lookups_index).scale(),
+ _ctx.at(lookups_index).zeroPoint()));
+ _builder.addShapeConstr(values_index,
+ asTensorInfo(asTensorShape(_ctx.at(values_index).shape()),
+ _ctx.at(values_index).type(), _ctx.at(values_index).scale(),
+ _ctx.at(values_index).zeroPoint()));
+ _builder.addShapeConstr(keys_index,
+ asTensorInfo(asTensorShape(_ctx.at(keys_index).shape()),
+ _ctx.at(keys_index).type(), _ctx.at(keys_index).scale(),
+ _ctx.at(keys_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int32_t output_index;
+ int32_t hits_index;
+ int32_t lookups_index;
+ int32_t values_index;
+ int32_t keys_index;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.hits_index = hits_index.asInt();
+ param.lookups_index = lookups_index.asInt();
+ param.values_index = values_index.asInt();
+ param.keys_index = keys_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto hits_alloc = ctx.at(::internal::tflite::operand::Index{param.hits_index});
+ auto lookups_alloc = ctx.at(::internal::tflite::operand::Index{param.lookups_index});
+ auto values_alloc = ctx.at(::internal::tflite::operand::Index{param.values_index});
+ auto keys_alloc = ctx.at(::internal::tflite::operand::Index{param.keys_index});
+
+ if (::internal::arm_compute::isGpuMode()) // GPU
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLHashtableLookup>();
+
+ fn->configure(CAST_CL(lookups_alloc), CAST_CL(keys_alloc), CAST_CL(values_alloc),
+ CAST_CL(output_alloc), CAST_CL(hits_alloc));
+
+ builder.append("HashtableLookup", std::move(fn));
+ }
+ else // NEON
+ {
+ // TODO Enable NEON Support
+ throw std::runtime_error("Not supported, yet");
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::LocalResponseNormalization::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index radius_index{node.param().radius_index};
+ const ::internal::tflite::operand::Index bias_index{node.param().bias_index};
+ const ::internal::tflite::operand::Index alpha_index{node.param().alpha_index};
+ const ::internal::tflite::operand::Index beta_index{node.param().beta_index};
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ int32_t radius;
+ float bias;
+ float alpha;
+ float beta;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ param.radius = _ctx.at(radius_index).asScalar<int32_t>();
+ param.alpha = _ctx.at(alpha_index).asScalar<float>();
+ param.beta = _ctx.at(beta_index).asScalar<float>();
+ param.bias = _ctx.at(bias_index).asScalar<float>();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ const auto norm_info = ::arm_compute::NormalizationLayerInfo(::arm_compute::NormType::CROSS_MAP,
+ param.radius * 2 + 1, param.alpha,
+ param.beta, param.bias, false);
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLNormalizationLayer>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), norm_info);
+
+ builder.append("LocalResponseNormalization", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NENormalizationLayer>();
+
+ fn->configure(ifm_alloc, ofm_alloc, norm_info);
+
+ builder.append("LocalResponseNormalization", std::move(fn));
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::DepthToSpace::Node &node)
+{
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+ const ::internal::tflite::operand::Index block_size_index{node.param().block_size_index};
+
+ assert(_ctx.at(input_index).shape().rank() == 4);
+ assert(_ctx.at(output_index).shape().rank() == 4);
+
+ int32_t block_size = _ctx.at(block_size_index).asScalar<int32_t>();
+ assert(block_size > 0);
+
+ { // assertions block
+ const auto output_shape = _ctx.at(output_index).shape();
+ const auto input_shape = _ctx.at(input_index).shape();
+ assert(output_shape.dim(0) == input_shape.dim(0));
+ assert(output_shape.dim(1) == input_shape.dim(1) * block_size);
+ assert(output_shape.dim(2) == input_shape.dim(2) * block_size);
+ assert(input_shape.dim(3) % (block_size * block_size) == 0);
+ assert(output_shape.dim(3) == input_shape.dim(3) / (block_size * block_size));
+ }
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape(), false),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(input_index,
+ asTensorInfo(asTensorShape(_ctx.at(input_index).shape(), false),
+ _ctx.at(input_index).type(), _ctx.at(input_index).scale(),
+ _ctx.at(input_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int output_index;
+ int input_index;
+ int32_t block_size;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input_index = input_index.asInt();
+ param.block_size = block_size;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+
+ {
+ if (::internal::arm_compute::isGpuMode()) // GPU
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLDepthToSpace>();
+
+ fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc), param.block_size);
+
+ builder.append("DepthToSpace", std::move(fn));
+ }
+ else // NEON
+ {
+ // TODO Enable NEON Support
+ throw std::runtime_error("Not supported, yet");
+ }
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Unpack::Node &node)
+{
+ VERBOSE(Unpack) << "Configure Unpack operation" << std::endl;
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ uint32_t input_rank = _ctx.at(ifm_index).shape().rank();
+
+ assert(input_rank == 4 || input_rank == 3 || input_rank == 2);
+ _builder.addShapeConstr(ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()),
+ _ctx.at(ifm_index).type()));
+
+ int32_t axis =
+ _ctx.at(::internal::tflite::operand::Index{node.param().axis_index}).asScalar<int32_t>();
+ // Negatige axis is supported, -1 implies R-1 axis where R is input rank
+ if (axis < 0)
+ {
+ axis += input_rank;
+ assert(axis >= 0);
+ }
+ uint32_t axis_uint = ToARMComputeAxis(input_rank, axis).value();
+ // int32_t num_split =
+ // _ctx.at(::internal::tflite::operand::Index{node.param().num_split_index}).asScalar<int32_t>();
+
+ for (const auto &index : node.param().ofm_indexes)
+ {
+ const ::internal::tflite::operand::Index ofm_index{index};
+ _builder.addShapeConstr(ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()),
+ _ctx.at(ofm_index).type()));
+ }
+
+ struct Param
+ {
+ std::vector<int32_t> ofm_indexes;
+ int ifm_index;
+ uint32_t axis;
+ };
+
+ if (input_rank == 4)
+ {
+ // TODO: generate test case for this and generalize 4D method all cases.
+ throw std::runtime_error("UNPACK_4D not implemented");
+ }
+ else if (input_rank == 3)
+ {
+ Param param;
+ param.ifm_index = ifm_index.asInt();
+ param.axis = axis_uint;
+ for (const auto &index : node.param().ofm_indexes)
+ {
+ param.ofm_indexes.push_back(index);
+ }
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLUnstack>();
+ std::vector<::arm_compute::ICLTensor *> outputs;
+ for (const auto &index : param.ofm_indexes)
+ {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{index});
+ outputs.push_back(CAST_CL(output_alloc));
+ }
+ fn->configure(CAST_CL(input_alloc), outputs, param.axis);
+
+ builder.append("Unpack", std::move(fn));
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ };
+
+ _builder.addStage(stage);
+ }
+ else if (input_rank == 2)
+ {
+ throw std::runtime_error("UNPACK_2D not implemented");
+ }
+ else
+ {
+ throw std::runtime_error("UNPACK axis is not valid");
+ }
+}
+
+void Planner::visit(const ::internal::tflite::op::Pack::Node &node)
+{
+ VERBOSE(Pack) << "Configure Pack operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const uint32_t output_rank = _ctx.at(ofm_index).shape().rank();
+ const uint32_t input_rank = output_rank - 1;
+
+ assert(output_rank == 4 || output_rank == 3 || output_rank == 2);
+
+ for (const auto &index : node.param().ifm_indexes)
+ {
+ const ::internal::tflite::operand::Index ifm_index{index};
+ assert(_ctx.at(ifm_index).shape().rank() == input_rank);
+ _builder.addShapeConstr(ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()),
+ _ctx.at(ifm_index).type()));
+ }
+
+ _builder.addShapeConstr(ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()),
+ _ctx.at(ofm_index).type()));
+
+ int32_t axis =
+ _ctx.at(::internal::tflite::operand::Index{node.param().axis_index}).asScalar<int32_t>();
+ // A negative axis implies axis from the end.
+ // For example, axis = -1 implies the first axis from the end, i.e. axis = Rank - 1.
+ // Similarly, axis = -2 imples second axis from the end, i.e. axis = Rank - 2.
+ if (axis < 0)
+ {
+ axis += output_rank;
+ assert(axis >= 0);
+ }
+ uint32_t axis_uint = ToARMComputeAxis(output_rank, axis).value();
+
+ struct Param
+ {
+ std::vector<int32_t> ifm_indexes;
+ int ofm_index;
+ uint32_t axis;
+ };
+
+ if (input_rank == 3)
+ {
+ // TODO: generate test case for this and generalize 4D method all cases.
+ throw std::runtime_error("PACK_3D not implemented");
+ }
+ else if (input_rank == 2)
+ {
+ Param param;
+ param.ofm_index = ofm_index.asInt();
+ param.axis = axis_uint;
+
+ for (const auto &index : node.param().ifm_indexes)
+ {
+ param.ifm_indexes.push_back(index);
+ }
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLStackLayer>();
+ std::vector<::arm_compute::ICLTensor *> inputs;
+ for (const auto &index : param.ifm_indexes)
+ {
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{index});
+ inputs.push_back(CAST_CL(input_alloc));
+ }
+ fn->configure(inputs, param.axis, CAST_CL(output_alloc));
+
+ builder.append("Pack", std::move(fn));
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ };
+
+ _builder.addStage(stage);
+ }
+ else if (input_rank == 1)
+ {
+ throw std::runtime_error("PACK_1D not implemented");
+ }
+ else
+ {
+ throw std::runtime_error("PACK axis is not valid");
+ }
+}
+
+void Planner::visit(const ::internal::tflite::op::Neg::Node &node)
+{
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLNeg>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc));
+ builder.append("Neg", std::move(fn));
+ }
+ else
+ {
+ // TODO Enable NEON Support
+ throw std::runtime_error("Not supported, yet");
+ }
+
+ };
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Exp::Node &node)
+{
+ VERBOSE(Exp) << "Configure Exp operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+
+ // Set shape constraints
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLExpLayer>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc));
+
+ builder.append("Exp", std::move(fn));
+ }
+ else
+ {
+ throw std::runtime_error("Not supported");
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::ReduceSum::Node &node)
+{
+ VERBOSE(ReduceSum) << "Configure ReduceSum operation" << std::endl;
+
+ const ::internal::tflite::operand::Index ofm_index{node.param().ofm_index};
+ const ::internal::tflite::operand::Index ifm_index{node.param().ifm_index};
+ const ::internal::tflite::operand::Index axis_index{node.param().axis_index};
+
+ const auto ifm_shape = _ctx.at(ifm_index).shape();
+ const auto ofm_shape = _ctx.at(ofm_index).shape();
+ const auto axis_shape = _ctx.at(axis_index).shape();
+
+ assert(ifm_shape.rank() <= 4);
+ assert(ofm_shape.rank() <= ifm_shape.rank());
+ assert(_ctx.at(axis_index).hasData());
+ assert(axis_shape.rank() == 0 || axis_shape.rank() == 1);
+
+ // NOTE For the 4-dimensions, if the rank of input and output are different, this runtime only
+ // supports cases reducing height and width or reducing depth.
+ // TODO We have to support all cases of dimensions up to 4.
+ // For correct permuting, we have to set output's shape to be equal in dimension position of the
+ // input. But the positions of the same dimensions in the input and output may be set differently.
+ // For example {2,3,4,5}(input's shape) can be reduced to {3,5}(output's shape). The original
+ // output shape should be {1,3,1,5}, but real output shape may be {3,5}. If you simply try to
+ // extend it in 4 dimensions, it should be {1,1,3,5}.
+ // Even if output shape is changed to {1,3,1,5}, there is another problem. It is that shape of
+ // output tensor used at next operation is changed to {1,3,1,5} after this operation even if the
+ // next operation is not desired.
+ if (ifm_shape.rank() == 4 && ifm_shape.rank() != ofm_shape.rank())
+ {
+ if (ofm_shape.rank() == 2)
+ {
+ // Reducing HW
+ assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(3) == ofm_shape.dim(1));
+ }
+ else if (ofm_shape.rank() == 3)
+ {
+ // Reducing C or
+ // (Reducing H and C(ifm and ofm) == 1) or (Reducing W and C(ifm and ofm) == 1)
+ assert(ifm_shape.dim(0) == ofm_shape.dim(0) && ifm_shape.dim(1) == ofm_shape.dim(1) &&
+ ifm_shape.dim(2) == ofm_shape.dim(2) ||
+ (ifm_shape.dim(0) == ofm_shape.dim(0) &&
+ (ifm_shape.dim(1) == ofm_shape.dim(1) || ifm_shape.dim(2) == ofm_shape.dim(1)) &&
+ ifm_shape.dim(3) == 1 && ofm_shape.dim(2) == 1));
+ }
+ }
+
+ // Set shape constraints
+ _builder.addShapeConstr(
+ ofm_index, asTensorInfo(asTensorShape(_ctx.at(ofm_index).shape()), _ctx.at(ofm_index).type(),
+ _ctx.at(ofm_index).scale(), _ctx.at(ofm_index).zeroPoint()));
+ _builder.addShapeConstr(
+ ifm_index, asTensorInfo(asTensorShape(_ctx.at(ifm_index).shape()), _ctx.at(ifm_index).type(),
+ _ctx.at(ifm_index).scale(), _ctx.at(ifm_index).zeroPoint()));
+
+ uint32_t input_rank = ifm_shape.rank();
+ std::set<uint32_t> axis;
+ int32_t axis_rank = axis_shape.rank();
+
+ if (axis_rank == 0)
+ {
+ int32_t axis_value = _ctx.at(axis_index).asScalar<int32_t>();
+ if (axis_value < 0)
+ {
+ axis_value += input_rank;
+ }
+ axis.insert(ToARMComputeAxis(input_rank, axis_value).value());
+ }
+ else if (axis_rank == 1)
+ {
+ const auto axis_base = _ctx.at(axis_index).data().base();
+ const auto axis_size = _ctx.at(axis_index).shape().asVector();
+
+ // If axis's data does not exist as constant values and can be gotten as input data, we have to
+ // find a way to infer output shape when sinking output.
+ assert(axis_base != nullptr);
+ for (uint32_t n = 0; n < axis_size; ++n)
+ {
+ int32_t axis_value = *(reinterpret_cast<const int32_t *>(axis_base) + n);
+ if (axis_value < 0)
+ {
+ axis_value += input_rank;
+ }
+ axis.insert(ToARMComputeAxis(input_rank, axis_value).value());
+ }
+ }
+ else
+ {
+ throw std::runtime_error("Not supported axis");
+ }
+
+ struct Param
+ {
+ int ofm_index;
+ int ifm_index;
+ std::set<uint32_t> axis;
+ };
+
+ Param param;
+
+ param.ofm_index = ofm_index.asInt();
+ param.ifm_index = ifm_index.asInt();
+ param.axis = axis;
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto ofm_alloc = ctx.at(::internal::tflite::operand::Index{param.ofm_index});
+ auto ifm_alloc = ctx.at(::internal::tflite::operand::Index{param.ifm_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLReduceOperation>();
+
+ fn->configure(CAST_CL(ifm_alloc), CAST_CL(ofm_alloc), param.axis,
+ ::arm_compute::ReduceOperation::SUM);
+
+ builder.append("ReduceSum", std::move(fn));
+ }
+ else
+ throw std::runtime_error("Not supported, yet");
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::Abs::Node &node)
+{
+ VERBOSE(Tanh) << "Configure Abs operation" << std::endl;
+
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+
+ // Set shape constraints
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+ _builder.addShapeConstr(input_index,
+ asTensorInfo(asTensorShape(_ctx.at(input_index).shape()),
+ _ctx.at(input_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+
+ struct Param
+ {
+ int output_index;
+ int input_index;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input_index = input_index.asInt();
+
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+
+ const ::arm_compute::ActivationLayerInfo act_info{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::ABS};
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLActivationLayer>();
+
+ fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc), act_info);
+
+ builder.append("Abs", std::move(fn));
+ }
+ else
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::NEActivationLayer>();
+
+ fn->configure(input_alloc, output_alloc, act_info);
+
+ builder.append("Abs", std::move(fn));
+ }
+ };
+
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::NotEqual::Node &node)
+{
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input1_index{node.param().input1_index};
+ const ::internal::tflite::operand::Index input2_index{node.param().input2_index};
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+
+ if (!(_ctx.at(input1_index).shape() == _ctx.at(input2_index).shape()))
+ {
+ const auto broadcast_rank =
+ std::max(_ctx.at(input1_index).shape().rank(), _ctx.at(input2_index).shape().rank());
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input1_index).shape())
+ .extendRank(broadcast_rank);
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input2_index).shape())
+ .extendRank(broadcast_rank);
+ }
+ _builder.addShapeConstr(input1_index,
+ asTensorInfo(asTensorShape(_ctx.at(input1_index).shape()),
+ _ctx.at(input1_index).type(), _ctx.at(input1_index).scale(),
+ _ctx.at(input1_index).zeroPoint()));
+ _builder.addShapeConstr(input2_index,
+ asTensorInfo(asTensorShape(_ctx.at(input2_index).shape()),
+ _ctx.at(input2_index).type(), _ctx.at(input2_index).scale(),
+ _ctx.at(input2_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int output_index;
+ int input1_index;
+ int input2_index;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input1_index = input1_index.asInt();
+ param.input2_index = input2_index.asInt();
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input1_alloc = ctx.at(::internal::tflite::operand::Index{param.input1_index});
+ auto input2_alloc = ctx.at(::internal::tflite::operand::Index{param.input2_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLComparison>();
+
+ fn->configure(CAST_CL(input1_alloc), CAST_CL(input2_alloc), CAST_CL(output_alloc),
+ ::arm_compute::ComparisonOperation::NotEqual);
+
+ builder.append("NotEqual", std::move(fn));
+ }
+ else
+ {
+ // TODO Add NEON support
+
+ throw std::runtime_error("Not supported yet");
+ }
+ };
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::LogicalAnd::Node &node)
+{
+ VERBOSE(Logical_AND) << "Configure Logical_AND operation" << std::endl;
+
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input1_index{node.param().input1_index};
+ const ::internal::tflite::operand::Index input2_index{node.param().input2_index};
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+
+ if (!(_ctx.at(input1_index).shape() == _ctx.at(input2_index).shape()))
+ {
+ const auto broadcast_rank =
+ std::max(_ctx.at(input1_index).shape().rank(), _ctx.at(input2_index).shape().rank());
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input1_index).shape())
+ .extendRank(broadcast_rank);
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input2_index).shape())
+ .extendRank(broadcast_rank);
+ }
+ _builder.addShapeConstr(input1_index,
+ asTensorInfo(asTensorShape(_ctx.at(input1_index).shape()),
+ _ctx.at(input1_index).type(), _ctx.at(input1_index).scale(),
+ _ctx.at(input1_index).zeroPoint()));
+ _builder.addShapeConstr(input2_index,
+ asTensorInfo(asTensorShape(_ctx.at(input2_index).shape()),
+ _ctx.at(input2_index).type(), _ctx.at(input2_index).scale(),
+ _ctx.at(input2_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int output_index;
+ int input1_index;
+ int input2_index;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input1_index = input1_index.asInt();
+ param.input2_index = input2_index.asInt();
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input1_alloc = ctx.at(::internal::tflite::operand::Index{param.input1_index});
+ auto input2_alloc = ctx.at(::internal::tflite::operand::Index{param.input2_index});
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLBinaryLogicalOp>();
+
+ fn->configure(CAST_CL(input1_alloc), CAST_CL(input2_alloc), CAST_CL(output_alloc),
+ ::arm_compute::BinaryLogicalOperation::AND);
+
+ builder.append("LogicalAnd", std::move(fn));
+ }
+ else
+ {
+ // TODO Add NEON support
+
+ throw std::runtime_error("Not supported yet");
+ }
+ };
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::LogicalNot::Node &node)
+{
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input_index{node.param().input_index};
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ ::arm_compute::DataType::U8, _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+
+ _builder.addShapeConstr(input_index,
+ asTensorInfo(asTensorShape(_ctx.at(input_index).shape()),
+ ::arm_compute::DataType::U8, _ctx.at(input_index).scale(),
+ _ctx.at(input_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int output_index;
+ int input_index;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input_index = input_index.asInt();
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input_alloc = ctx.at(::internal::tflite::operand::Index{param.input_index});
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLBitwiseNot>();
+
+ fn->configure(CAST_CL(input_alloc), CAST_CL(output_alloc));
+
+ builder.append("LogicalNot", std::move(fn));
+ }
+ else
+ {
+ // TODO Add NEON support
+
+ throw std::runtime_error("Not supported yet");
+ }
+ };
+ _builder.addStage(stage);
+}
+
+void Planner::visit(const ::internal::tflite::op::LogicalOr::Node &node)
+{
+ VERBOSE(LogicalOr) << "Configure LogicalOr operation" << std::endl;
+
+ const ::internal::tflite::operand::Index output_index{node.param().output_index};
+ const ::internal::tflite::operand::Index input1_index{node.param().input1_index};
+ const ::internal::tflite::operand::Index input2_index{node.param().input2_index};
+
+ // Set Shape Constraints and TensorInfo
+ _builder.addShapeConstr(output_index,
+ asTensorInfo(asTensorShape(_ctx.at(output_index).shape()),
+ _ctx.at(output_index).type(), _ctx.at(output_index).scale(),
+ _ctx.at(output_index).zeroPoint()));
+
+ if (!(_ctx.at(input1_index).shape() == _ctx.at(input2_index).shape()))
+ {
+ const auto broadcast_rank =
+ std::max(_ctx.at(input1_index).shape().rank(), _ctx.at(input2_index).shape().rank());
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input1_index).shape())
+ .extendRank(broadcast_rank);
+ const_cast<::internal::tflite::operand::Shape &>(_ctx.at(input2_index).shape())
+ .extendRank(broadcast_rank);
+ }
+
+ _builder.addShapeConstr(input1_index,
+ asTensorInfo(asTensorShape(_ctx.at(input1_index).shape()),
+ _ctx.at(input1_index).type(), _ctx.at(input1_index).scale(),
+ _ctx.at(input1_index).zeroPoint()));
+ _builder.addShapeConstr(input2_index,
+ asTensorInfo(asTensorShape(_ctx.at(input2_index).shape()),
+ _ctx.at(input2_index).type(), _ctx.at(input2_index).scale(),
+ _ctx.at(input2_index).zeroPoint()));
+
+ // Construct operation parameters
+ struct Param
+ {
+ int output_index;
+ int input1_index;
+ int input2_index;
+ };
+
+ Param param;
+
+ param.output_index = output_index.asInt();
+ param.input1_index = input1_index.asInt();
+ param.input2_index = input2_index.asInt();
+ auto stage = [param](const IAllocationContext &ctx, IExecutionBuilder &builder) {
+ auto output_alloc = ctx.at(::internal::tflite::operand::Index{param.output_index});
+ auto input1_alloc = ctx.at(::internal::tflite::operand::Index{param.input1_index});
+ auto input2_alloc = ctx.at(::internal::tflite::operand::Index{param.input2_index});
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto fn = nnfw::cpp14::make_unique<::arm_compute::CLBinaryLogicalOp>();
+
+ fn->configure(CAST_CL(input1_alloc), CAST_CL(input2_alloc), CAST_CL(output_alloc),
+ ::arm_compute::BinaryLogicalOperation::OR);
+
+ builder.append("LogicalOr", std::move(fn));
+ }
+ else
+ {
+ // TODO Add NEON support
+
+ throw std::runtime_error("Not supported yet");
+ }
+ };
+ _builder.addStage(stage);
+}
+
+class AllocationContext final : public IAllocationContext
+{
+public:
+ AllocationContext(::internal::arm_compute::Plan &plan) : _plan{plan}
+ {
+ // DO NOTHING
+ }
+
+public:
+ ::arm_compute::ITensor *at(const ::internal::tflite::operand::Index &ind) const override
+ {
+ return _plan.operands().at(ind).ptr();
+ }
+
+private:
+ ::internal::arm_compute::Plan &_plan;
+};
+
+class ExecutionBuilder final : public IExecutionBuilder
+{
+public:
+ ExecutionBuilder(::internal::arm_compute::Plan &plan) : _plan{plan}
+ {
+ // DO NOTHING
+ }
+
+public:
+ void append(const std::string &name, std::unique_ptr<::arm_compute::IFunction> &&f) override
+ {
+ _plan.operations().append(std::move(f));
+ _plan.operations().at(_plan.operations().size() - 1).name() = name;
+ }
+
+#ifdef TFLITE_PROFILING_ENABLED
+public:
+ int plan_op_size() const { return _plan.operations().size(); }
+ void addOpIndexToSteps(int from, int to, int op_idx)
+ {
+ for (int i = from; i < to; ++i)
+ _plan.operations().at(i).op_idx() = op_idx;
+ }
+#endif
+
+private:
+ ::internal::arm_compute::Plan &_plan;
+};
+
+/**
+ * @brief Class to provide methods of compilation plan builder
+ */
+class PlanBuilder final : public IPlanBuilder
+{
+public:
+ /**
+ * @brief Construct a new PlanBuilder object with Plan
+ * @param [in] plan The Plan object
+ */
+ PlanBuilder(::internal::arm_compute::Plan &plan) : _plan{plan}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Add TensorInfo with Shape Constraints
+ * @param [in] ind Index of operand
+ * @param [in] info TensorInfo value to set to index of operand
+ * @return N/A
+ */
+ void addShapeConstr(const ::internal::tflite::operand::Index &ind,
+ const ::arm_compute::TensorInfo &info) override;
+
+public:
+ /**
+ * @brief Add Subsumption constraints
+ * @param [in] ind Index of operand
+ * @param [in] base Index of base operand of Subsumption
+ * @param [in] offset Offset of Subsumption
+ * @param [in] shape Shape of Subsumption
+ * @param [in] extend_parent extend_parent value of Subsumption
+ * @return N/A
+ */
+ void addSubsumptionConstr(const ::internal::tflite::operand::Index &ind,
+ const ::internal::tflite::operand::Index &base,
+ const ::arm_compute::Coordinates &offset,
+ const ::arm_compute::TensorShape &shape, bool extend_parent) override;
+
+public:
+ /**
+ * @brief Add Initializer lambda with ITensor param
+ * @param [in] ind Index of operand
+ * @param [in] initializer Initializer to add
+ * @return N/A
+ */
+ void addInitializer(const ::internal::tflite::operand::Index &ind,
+ const Initializer &initializer) override;
+
+public:
+ /**
+ * @brief Add Stage lambda with IAllocationContext and IExecutionBuilder params
+ * @param [in] stage Stage to add
+ * @return N/A
+ */
+ void addStage(const Stage &stage) override;
+
+public:
+ /**
+ * @brief Finilize(build) the Plan
+ * @return N/A
+ */
+ void finalize(void) const;
+
+private:
+ ::internal::arm_compute::Plan &_plan;
+
+private:
+ struct Subsumption
+ {
+ public:
+ Subsumption(const ::internal::tflite::operand::Index &base,
+ const ::arm_compute::Coordinates &offset, const ::arm_compute::TensorShape &shape,
+ bool extend_parent)
+ : _base{base}, _offset{offset}, _shape{shape}, _extend_parent{extend_parent}
+ {
+ // DO NOTHING
+ }
+
+ public:
+ const ::internal::tflite::operand::Index &base(void) const { return _base; }
+ const ::arm_compute::Coordinates &offset(void) const { return _offset; }
+ const ::arm_compute::TensorShape &shape(void) const { return _shape; }
+ const bool extend_parent(void) const { return _extend_parent; }
+
+ private:
+ const ::internal::tflite::operand::Index _base;
+ const ::arm_compute::Coordinates _offset;
+ const ::arm_compute::TensorShape _shape;
+ const bool _extend_parent;
+ };
+
+private:
+ std::map<int, ::arm_compute::TensorInfo> _tensor_info_ctx;
+ std::map<int, std::shared_ptr<Subsumption>> _subsumption_ctx;
+ std::map<int, Initializer> _initializer_ctx;
+ std::vector<Stage> _stages;
+};
+
+void PlanBuilder::addShapeConstr(const ::internal::tflite::operand::Index &ind,
+ const ::arm_compute::TensorInfo &info)
+{
+ _tensor_info_ctx[ind.asInt()] = info;
+}
+
+void PlanBuilder::addSubsumptionConstr(const ::internal::tflite::operand::Index &ind,
+ const ::internal::tflite::operand::Index &base,
+ const ::arm_compute::Coordinates &offset,
+ const ::arm_compute::TensorShape &shape, bool extend_parent)
+{
+ _subsumption_ctx[ind.asInt()] = std::make_shared<Subsumption>(base, offset, shape, extend_parent);
+}
+
+void PlanBuilder::addInitializer(const ::internal::tflite::operand::Index &ind,
+ const Initializer &initializer)
+{
+ _initializer_ctx[ind.asInt()] = initializer;
+}
+
+void PlanBuilder::addStage(const Stage &stage) { _stages.emplace_back(stage); }
+
+#include <stack>
+
+void PlanBuilder::finalize(void) const
+{
+ // ITensor objects to be initialized later
+ std::vector<std::shared_ptr<::arm_compute::ITensor>> tensors;
+
+ // Create Tensor & CLSubTensor
+ auto isAllocated = [this](int ind) {
+ const ::internal::tflite::operand::Index operand_index{ind};
+ return _plan.operands().exist(operand_index);
+ };
+
+ auto setCLTensor = [&](int ind) {
+ auto tensor = std::make_shared<::arm_compute::CLTensor>();
+
+ tensor->allocator()->init(_tensor_info_ctx.at(ind));
+
+ // NOTE Do NOT allocate here. allocate should be invoked after configure functions
+ _plan.operands().set(::internal::tflite::operand::Index{ind}, tensor);
+ tensors.emplace_back(tensor);
+ };
+
+ auto setCLSubTensor = [&](int curr) {
+ const auto &sub_info = *(_subsumption_ctx.find(curr)->second);
+
+ auto base_tensor = _plan.operands().at(sub_info.base()).ptr();
+
+ assert(base_tensor != nullptr);
+
+ auto curr_tensor = std::make_shared<::arm_compute::CLSubTensor>(
+ CAST_CL(base_tensor), sub_info.shape(), sub_info.offset(), sub_info.extend_parent());
+
+ _plan.operands().set(::internal::tflite::operand::Index{curr}, curr_tensor);
+ };
+
+ auto setNETensor = [&](int ind) {
+ auto tensor = std::make_shared<::arm_compute::Tensor>();
+
+ tensor->allocator()->init(_tensor_info_ctx.at(ind));
+
+ // NOTE Do NOT allocate here. allocate should be invoked after configure functions
+ _plan.operands().set(::internal::tflite::operand::Index{ind}, tensor);
+ tensors.emplace_back(tensor);
+ };
+
+ auto setNESubTensor = [&](int curr) {
+ const auto &sub_info = *(_subsumption_ctx.find(curr)->second);
+
+ auto base_tensor = _plan.operands().at(sub_info.base()).ptr();
+
+ assert(base_tensor != nullptr);
+
+ auto curr_tensor = std::make_shared<::arm_compute::SubTensor>(base_tensor, sub_info.shape(),
+ sub_info.offset());
+
+ _plan.operands().set(::internal::tflite::operand::Index{curr}, curr_tensor);
+ };
+
+ for (auto it = _subsumption_ctx.begin(); it != _subsumption_ctx.end(); ++it)
+ {
+ std::stack<int> stack;
+
+ stack.push(it->first);
+
+ while (!stack.empty())
+ {
+ const auto curr = stack.top();
+
+ if (isAllocated(curr))
+ {
+ // Skip if already allocated
+ stack.pop();
+ continue;
+ }
+
+ auto it_s = _subsumption_ctx.find(curr);
+
+ if (it_s == _subsumption_ctx.end())
+ {
+ if (::internal::arm_compute::isGpuMode())
+ setCLTensor(curr);
+ else
+ setNETensor(curr);
+ stack.pop();
+ continue;
+ }
+
+ const auto &sub_info = *(it_s->second);
+
+ if (isAllocated(sub_info.base().asInt()))
+ {
+ if (::internal::arm_compute::isGpuMode())
+ setCLSubTensor(curr);
+ else
+ setNESubTensor(curr);
+ stack.pop();
+ }
+ else
+ {
+ // Allocate base tensor first
+ stack.push(sub_info.base().asInt());
+ }
+ }
+ }
+
+ for (auto it = _tensor_info_ctx.begin(); it != _tensor_info_ctx.end(); ++it)
+ {
+ if (isAllocated(it->first))
+ {
+ // Skip if already allocated
+ continue;
+ }
+
+ if (::internal::arm_compute::isGpuMode())
+ setCLTensor(it->first);
+ else
+ setNETensor(it->first);
+ }
+
+ // Process Stage
+ AllocationContext allocation_context{_plan};
+ ExecutionBuilder execution_builder{_plan};
+
+ for (int idx = 0; idx < _stages.size(); idx++)
+ {
+ const auto &stage = _stages[idx];
+#ifdef TFLITE_PROFILING_ENABLED
+ int from = execution_builder.plan_op_size();
+#endif
+ stage(allocation_context, execution_builder);
+#ifdef TFLITE_PROFILING_ENABLED
+ int to = execution_builder.plan_op_size();
+ execution_builder.addOpIndexToSteps(from, to, idx);
+#endif
+ }
+
+ // Allocate Tensor Memory
+ for (const auto &tensor : tensors)
+ {
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto cl_tensor = CAST_CL(tensor.get());
+ cl_tensor->allocator()->allocate();
+ }
+ else
+ {
+ auto ne_tensor = CAST_NE(tensor.get());
+ ne_tensor->allocator()->allocate();
+ }
+ }
+
+ // Fill weight/bias
+ for (auto it = _initializer_ctx.begin(); it != _initializer_ctx.end(); ++it)
+ {
+ const ::internal::tflite::operand::Index operand_index{it->first};
+ _plan.operands().at(operand_index).access(it->second);
+ }
+
+ // Initialize CLTensors that have data in their corresponding NNAPI operand but are not
+ // initialized yet
+ const auto &operands = _plan.model().operands();
+ for (int idx = 0; idx < operands.size(); ++idx)
+ {
+ const ::internal::tflite::operand::Index operand_idx{idx};
+ if (isAllocated(idx) && operands.at(operand_idx).hasData() &&
+ _initializer_ctx.find(idx) == _initializer_ctx.end())
+ {
+ auto rank = operands.at(operand_idx).shape().rank();
+ auto base = operands.at(operand_idx).data().base();
+ auto type = operands.at(operand_idx).type();
+ auto shape = operands.at(operand_idx).shape();
+
+ // Need to support scalar types (ANEURALNETWORKS_FLOAT32 and ANEURALNETWORKS_INT32)
+ // for rank > 1 tensor, because it can be operand of broadcast operation
+ switch (rank)
+ {
+ case 0: // scalar
+ {
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ {
+ auto initializer = std::bind(initVectorTensor<float>, _1, base, 1);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ {
+ auto initializer = std::bind(initVectorTensor<int32_t>, _1, base, 1);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ case ANEURALNETWORKS_UINT32:
+ {
+ auto initializer = std::bind(initVectorTensor<uint32_t>, _1, base, 1);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ {
+ auto initializer = std::bind(initVectorTensor<uint8_t>, _1, base, 1);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ default:
+ throw std::runtime_error("Unknown scalar type, type : " + std::to_string(type));
+ break;
+ }
+ break;
+ }
+ case 1: // vector
+ {
+ auto size = shape.asVector();
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ {
+ auto initializer = std::bind(initVectorTensor<float>, _1, base, size);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ {
+ auto initializer = std::bind(initVectorTensor<int32_t>, _1, base, size);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ {
+ auto initializer = std::bind(initVectorTensor<uint8_t>, _1, base, size);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ default:
+ throw std::runtime_error("Unknown tensor type, type : " + std::to_string(type));
+ break;
+ }
+ break;
+ }
+ case 2: // matrix
+ {
+ const auto matrix_shape = shape.asMatrix();
+ auto size = operands.at(operand_idx).data().size();
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ {
+ auto initializer = std::bind(initMatrixTensor<float>, _1, matrix_shape, base, size);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ {
+ auto initializer = std::bind(initMatrixTensor<int32_t>, _1, matrix_shape, base, size);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ {
+ auto initializer = std::bind(initMatrixTensor<uint8_t>, _1, matrix_shape, base, size);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ default:
+ throw std::runtime_error("Unknown tensor type, type : " + std::to_string(type));
+ break;
+ }
+ break;
+ }
+ case 3: // 3D tensor
+ {
+ const auto tensor_shape = shape.asTensor();
+ auto size = operands.at(operand_idx).data().size();
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ {
+ auto initializer = std::bind(initTensor3D<float>, _1, tensor_shape, base, size);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ {
+ auto initializer = std::bind(initTensor3D<int32_t>, _1, tensor_shape, base, size);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ {
+ auto initializer = std::bind(initTensor3D<uint8_t>, _1, tensor_shape, base, size);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ default:
+ throw std::runtime_error("Unknown tensor type, type : " + std::to_string(type));
+ break;
+ }
+ break;
+ }
+ case 4: // feature
+ {
+ const auto feature_shape = shape.asFeature();
+ auto size = operands.at(operand_idx).data().size();
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ {
+ auto initializer = std::bind(initFeatureTensor<float>, _1, feature_shape, base, size);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ {
+ auto initializer =
+ std::bind(initFeatureTensor<int32_t>, _1, feature_shape, base, size);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ {
+ auto initializer =
+ std::bind(initFeatureTensor<uint8_t>, _1, feature_shape, base, size);
+ _plan.operands().at(operand_idx).access(initializer);
+ break;
+ }
+ default:
+ throw std::runtime_error("Unknown tensor type, type : " + std::to_string(type));
+ break;
+ }
+ break;
+ }
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+ }
+ }
+}
+
+//
+// NNAPI Implementation
+//
+int ANeuralNetworksCompilation_create(ANeuralNetworksModel *model,
+ ANeuralNetworksCompilation **compilation)
+{
+ if ((model == nullptr) || (compilation == nullptr))
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (!model->isFinished())
+ {
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ std::shared_ptr<const internal::tflite::Model> internal;
+
+ model->release(internal);
+
+ ANeuralNetworksCompilation *compilation_ptr = new ANeuralNetworksCompilation(internal);
+ if (compilation_ptr == nullptr)
+ {
+ return ANEURALNETWORKS_OUT_OF_MEMORY;
+ }
+ *compilation = compilation_ptr;
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksCompilation_setPreference(ANeuralNetworksCompilation *compilation,
+ int32_t preference)
+{
+ if (compilation == nullptr)
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ // NOTE Pure CL runimte currently ignores this API call
+ // TODO Use preference
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksCompilation_finish(ANeuralNetworksCompilation *compilation)
+{
+ if (compilation == nullptr)
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (::internal::arm_compute::isGpuMode())
+ {
+ arm_compute::CLScheduler::get().default_init();
+ // NOTE CLKernelLibraryEx must use the same context as CLScheduler
+ // It did not check whether another device is available.
+ arm_compute::CLKernelLibraryEx::get().init(
+ "./cl_kernels/", arm_compute::CLScheduler::get().context(), cl::Device::getDefault());
+ }
+
+ const auto &operands = compilation->plan().model().operands();
+ const auto &operations = compilation->plan().model().operations();
+
+ PlanBuilder plan_builder{compilation->plan()};
+
+ for (uint32_t n = 0; n < operations.size(); ++n)
+ {
+ operations.at(n).accept(Planner{operands, plan_builder});
+ }
+
+ plan_builder.finalize();
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksCompilation_free(ANeuralNetworksCompilation *compilation)
+{
+ delete compilation;
+}
diff --git a/runtime/contrib/pure_arm_compute/src/compilation.h b/runtime/contrib/pure_arm_compute/src/compilation.h
new file mode 100644
index 000000000..1a06d06b9
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/compilation.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file compilation.h
+ * @brief This file defines ANeuralNetworksCompilation class for handling Compilation NNAPI
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __COMPILATION_H__
+#define __COMPILATION_H__
+
+#include "internal/Model.h"
+#include "internal/arm_compute.h"
+
+/**
+ * @brief struct to define Compilation of NNAPI
+ */
+struct ANeuralNetworksCompilation
+{
+public:
+ /**
+ * @brief Construct with params
+ * @param [in] model Pointer of internal::tflite::Model to set internal::arm_compute::Plan
+ */
+ ANeuralNetworksCompilation(const std::shared_ptr<const internal::tflite::Model> &model)
+ : _plan{new internal::arm_compute::Plan{model}}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get reference of internal::arm_compute::Plan
+ * @return Reference of internal::arm_compute::Plan
+ */
+ internal::arm_compute::Plan &plan(void) { return *_plan; }
+
+public:
+ /**
+ * @brief Publish internal Plan to param
+ * @param [out] plan Pointer of internal::arm_compute::Plan to be set
+ * @return N/A
+ */
+ void publish(std::shared_ptr<const internal::arm_compute::Plan> &plan) { plan = _plan; }
+ /**
+ * @brief Get @c true if ANeuralNetworksCompilation_finish has been called, otherwise @c false
+ * @return @c true if ANeuralNetworksCompilation_finish has been called, otherwise @c false
+ */
+ bool isFinished(void) { return _isFinished; }
+ /**
+ * @brief Mark compilation process finished
+ * @return N/A
+ */
+ void markAsFinished() { _isFinished = true; }
+
+private:
+ std::shared_ptr<internal::arm_compute::Plan> _plan;
+ bool _isFinished{false};
+};
+
+#endif
diff --git a/runtime/contrib/pure_arm_compute/src/event.cc b/runtime/contrib/pure_arm_compute/src/event.cc
new file mode 100644
index 000000000..247586cc3
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/event.cc
@@ -0,0 +1,31 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <NeuralNetworks.h>
+
+#include "event.h"
+
+int ANeuralNetworksEvent_wait(ANeuralNetworksEvent *event)
+{
+ if (event == nullptr)
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksEvent_free(ANeuralNetworksEvent *event) { delete event; }
diff --git a/runtime/contrib/pure_arm_compute/src/event.h b/runtime/contrib/pure_arm_compute/src/event.h
new file mode 100644
index 000000000..b5595583c
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/event.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file event.h
+ * @brief This file defines ANeuralNetworksEvent struct for handling Event NNAPI
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __EVENT_H__
+#define __EVENT_H__
+
+/**
+ * @brief struct to define Event of NNAPI
+ */
+struct ANeuralNetworksEvent
+{
+};
+
+#endif
diff --git a/runtime/contrib/pure_arm_compute/src/execution.cc b/runtime/contrib/pure_arm_compute/src/execution.cc
new file mode 100644
index 000000000..657d25288
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/execution.cc
@@ -0,0 +1,628 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <NeuralNetworks.h>
+
+#include "compilation.h"
+#include "execution.h"
+#include "profiling/profiling.h"
+#include "profiling/profiler.h"
+#include "event.h"
+
+#include "internal/VectorSource.h"
+#include "internal/MatrixSource.h"
+#include "internal/Tensor3DSource.h"
+#include "internal/FeatureSource.h"
+#include "internal/TensorSource.h"
+
+#include "internal/Sinks.h"
+#include "internal/VectorSink.h"
+#include "internal/MatrixSink.h"
+#include "internal/Tensor3DSink.h"
+#include "internal/FeatureSink.h"
+
+#include "misc/feature/IndexIterator.h"
+
+#include <arm_compute/runtime/CL/CLScheduler.h>
+
+#include <cassert>
+
+static void asVectorSource(ANeuralNetworksExecution *execution, int32_t type, int32_t index,
+ int32_t len, const void *buffer, size_t length)
+{
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ execution->source<VectorSource<float>>(index, len, reinterpret_cast<const float *>(buffer),
+ length);
+ break;
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ execution->source<VectorSource<int32_t>>(index, len,
+ reinterpret_cast<const int32_t *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_UINT32:
+ execution->source<VectorSource<uint32_t>>(index, len,
+ reinterpret_cast<const uint32_t *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ execution->source<VectorSource<uint8_t>>(index, len,
+ reinterpret_cast<const uint8_t *>(buffer), length);
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+static void asMatrixSource(ANeuralNetworksExecution *execution, int32_t type, int32_t index,
+ const nnfw::misc::matrix::Shape &shape, const void *buffer,
+ size_t length)
+{
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ execution->source<MatrixSource<float>>(index, shape, reinterpret_cast<const float *>(buffer),
+ length);
+ break;
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ execution->source<MatrixSource<int32_t>>(index, shape,
+ reinterpret_cast<const int32_t *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_UINT32:
+ execution->source<MatrixSource<uint32_t>>(index, shape,
+ reinterpret_cast<const uint32_t *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ execution->source<MatrixSource<uint8_t>>(index, shape,
+ reinterpret_cast<const uint8_t *>(buffer), length);
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+static void asTensor3DSource(ANeuralNetworksExecution *execution, int32_t type, int32_t index,
+ const nnfw::misc::tensor::Shape &shape, const void *buffer,
+ size_t length)
+{
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ execution->source<Tensor3DSource<float>>(index, shape,
+ reinterpret_cast<const float *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ execution->source<Tensor3DSource<int32_t>>(index, shape,
+ reinterpret_cast<const int32_t *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_UINT32:
+ execution->source<Tensor3DSource<uint32_t>>(
+ index, shape, reinterpret_cast<const uint32_t *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ execution->source<Tensor3DSource<uint8_t>>(index, shape,
+ reinterpret_cast<const uint8_t *>(buffer), length);
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+static void asTensorSource(ANeuralNetworksExecution *execution, int32_t type, int32_t index,
+ const nnfw::misc::tensor::Shape &shape, const void *buffer,
+ size_t length)
+{
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ execution->source<TensorSource<float>>(index, shape, reinterpret_cast<const float *>(buffer),
+ length);
+ break;
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ execution->source<TensorSource<int32_t>>(index, shape,
+ reinterpret_cast<const int32_t *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_UINT32:
+ execution->source<TensorSource<uint32_t>>(index, shape,
+ reinterpret_cast<const uint32_t *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ execution->source<TensorSource<uint8_t>>(index, shape,
+ reinterpret_cast<const uint8_t *>(buffer), length);
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+static void asFeatureSource(ANeuralNetworksExecution *execution, int32_t type, int32_t index,
+ const nnfw::misc::feature::Shape &shape, const void *buffer,
+ size_t length)
+{
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ execution->source<FeatureSource<float>>(index, shape, reinterpret_cast<const float *>(buffer),
+ length);
+ break;
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ execution->source<FeatureSource<int32_t>>(index, shape,
+ reinterpret_cast<const int32_t *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_UINT32:
+ execution->source<FeatureSource<uint32_t>>(
+ index, shape, reinterpret_cast<const uint32_t *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ execution->source<FeatureSource<uint8_t>>(index, shape,
+ reinterpret_cast<const uint8_t *>(buffer), length);
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+static void asVectorSink(ANeuralNetworksExecution *execution, int32_t type, int32_t index,
+ int32_t len, void *buffer, size_t length)
+{
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ execution->sink<VectorSink<float>>(index, len, reinterpret_cast<float *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ execution->sink<VectorSink<int32_t>>(index, len, reinterpret_cast<int32_t *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_UINT32:
+ execution->sink<VectorSink<uint32_t>>(index, len, reinterpret_cast<uint32_t *>(buffer),
+ length);
+ break;
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ execution->sink<VectorSink<uint8_t>>(index, len, reinterpret_cast<uint8_t *>(buffer), length);
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+static void asMatrixSink(ANeuralNetworksExecution *execution, int32_t type, int32_t index,
+ int32_t H, int32_t W, void *buffer, size_t length)
+{
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ execution->sink<MatrixSink<float>>(index, H, W, reinterpret_cast<float *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ execution->sink<MatrixSink<int32_t>>(index, H, W, reinterpret_cast<int32_t *>(buffer),
+ length);
+ break;
+ case ANEURALNETWORKS_UINT32:
+ execution->sink<MatrixSink<uint32_t>>(index, H, W, reinterpret_cast<uint32_t *>(buffer),
+ length);
+ break;
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ execution->sink<MatrixSink<uint8_t>>(index, H, W, reinterpret_cast<uint8_t *>(buffer),
+ length);
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+static void asFeatureSink(ANeuralNetworksExecution *execution, int32_t type, int32_t index,
+ const nnfw::misc::feature::Shape &shape, void *buffer, size_t length)
+{
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ execution->sink<FeatureSink<float>>(index, shape, reinterpret_cast<float *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ execution->sink<FeatureSink<int32_t>>(index, shape, reinterpret_cast<int32_t *>(buffer),
+ length);
+ break;
+ case ANEURALNETWORKS_UINT32:
+ execution->sink<FeatureSink<uint32_t>>(index, shape, reinterpret_cast<uint32_t *>(buffer),
+ length);
+ break;
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ execution->sink<FeatureSink<uint8_t>>(index, shape, reinterpret_cast<uint8_t *>(buffer),
+ length);
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+static void asTensor3DSink(ANeuralNetworksExecution *execution, int32_t type, int32_t index,
+ const nnfw::misc::tensor::Shape &shape, void *buffer, size_t length)
+{
+ assert(shape.rank() == 3);
+
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ execution->sink<Tensor3DSink<float>>(index, shape, reinterpret_cast<float *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ execution->sink<Tensor3DSink<int32_t>>(index, shape, reinterpret_cast<int32_t *>(buffer),
+ length);
+ break;
+ case ANEURALNETWORKS_UINT32:
+ execution->sink<Tensor3DSink<uint32_t>>(index, shape, reinterpret_cast<uint32_t *>(buffer),
+ length);
+ break;
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ execution->sink<Tensor3DSink<uint8_t>>(index, shape, reinterpret_cast<uint8_t *>(buffer),
+ length);
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+static void asTensorSink(ANeuralNetworksExecution *execution, int32_t type, int32_t index,
+ const nnfw::misc::tensor::Shape &shape, void *buffer, size_t length)
+{
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ execution->sink<TensorSink<float>>(index, shape, reinterpret_cast<float *>(buffer), length);
+ break;
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ execution->sink<TensorSink<int32_t>>(index, shape, reinterpret_cast<int32_t *>(buffer),
+ length);
+ break;
+ case ANEURALNETWORKS_UINT32:
+ execution->sink<TensorSink<uint32_t>>(index, shape, reinterpret_cast<uint32_t *>(buffer),
+ length);
+ break;
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ execution->sink<TensorSink<uint8_t>>(index, shape, reinterpret_cast<uint8_t *>(buffer),
+ length);
+ break;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+//
+// NNAPI Implementation
+//
+int ANeuralNetworksExecution_create(ANeuralNetworksCompilation *compilation,
+ ANeuralNetworksExecution **execution)
+{
+ if ((compilation == nullptr) || (execution == nullptr))
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ std::shared_ptr<const ::internal::arm_compute::Plan> plan;
+ compilation->publish(plan);
+ ANeuralNetworksExecution *execution_ptr = new ANeuralNetworksExecution{plan};
+ if (execution_ptr == nullptr)
+ {
+ return ANEURALNETWORKS_OUT_OF_MEMORY;
+ }
+ *execution = execution_ptr;
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksExecution_setInput(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type, const void *buffer,
+ size_t length)
+{
+ // Don't check type
+ // Comment about ANeuralNetworksOperandType in NeuralNetworks.h:
+ // If the input or output is optional and omitted then it need not have a fully specified tensor
+ // operand type
+ if ((execution == nullptr) || ((buffer == nullptr) && (length != 0)))
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ const auto &operands = execution->plan().model().operands();
+
+ // TODO Check type conflicts
+
+ // NOTE The current implemenation assumes that every input is a feature map.
+ // TODO Remove this assumption
+ const auto operand_index = execution->plan().model().inputs.at(index);
+ int32_t input_type = operands.at(operand_index).type();
+ // NOTE TFLite passes type parameter unconditionally as nullptr.
+ // Is it necessary to reget type value already set in model step?
+ if (type != nullptr)
+ {
+ input_type = type->type;
+ }
+
+ auto shape = operands.at(operand_index).shape();
+ auto rank = shape.rank();
+
+ if (rank == 1)
+ {
+ const auto len = shape.dim(0);
+
+ asVectorSource(execution, input_type, index, len, buffer, length);
+ }
+ else if (rank == 2)
+ {
+ const auto &operand_shape = shape.asMatrix();
+
+ asMatrixSource(execution, input_type, index, operand_shape, buffer, length);
+ }
+ else if (rank == 3)
+ {
+ const auto &operand_shape = shape.asTensor();
+
+ asTensor3DSource(execution, input_type, index, operand_shape, buffer, length);
+ }
+ else if (rank == 4)
+ {
+ const auto &operand_shape = shape.asFeature();
+
+ asFeatureSource(execution, input_type, index, operand_shape, buffer, length);
+ }
+ else
+ {
+ // NOTE TensorSource is much slower than specialized Source(s)
+ const auto &operand_shape = shape.asTensor();
+
+ asTensorSource(execution, input_type, index, operand_shape, buffer, length);
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+// squeeze(shape) eliminates all the dimensions whose dimensionality is 1
+// For example, squeeze([3, 1, 3]) returns [3, 3]
+static nnfw::misc::tensor::Shape squeeze(const nnfw::misc::tensor::Shape &shape)
+{
+ nnfw::misc::tensor::Shape res(0);
+
+ for (uint32_t axis = 0; axis < shape.rank(); ++axis)
+ {
+ if (shape.dim(axis) != 1)
+ {
+ res.append(shape.dim(axis));
+ }
+ }
+
+ return res;
+}
+
+int ANeuralNetworksExecution_setOutput(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type, void *buffer,
+ size_t length)
+{
+ // Don't check type
+ // Comment about ANeuralNetworksOperandType in NeuralNetworks.h:
+ // If the input or output is optional and omitted then it need not have a fully specified tensor
+ // operand type
+ if ((execution == nullptr) || ((buffer == nullptr) && (length != 0)))
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ const auto &operands = execution->plan().model().operands();
+
+ // TODO Check type conflicts
+
+ const auto operand_index = execution->plan().model().outputs.at(index);
+ int32_t output_type = operands.at(operand_index).type();
+ const auto &output_shape = operands.at(operand_index).shape();
+
+ if (output_shape.rank() == 1)
+ {
+ const auto len = output_shape.dim(0);
+
+ asVectorSink(execution, output_type, index, len, buffer, length);
+ }
+ else if (output_shape.rank() == 2)
+ {
+ const auto H = output_shape.dim(0);
+ const auto W = output_shape.dim(1);
+
+ asMatrixSink(execution, output_type, index, H, W, buffer, length);
+ }
+ else if (output_shape.rank() == 3)
+ {
+ asTensor3DSink(execution, output_type, index, output_shape, buffer, length);
+ }
+ else if ((output_shape.rank() == 4))
+ {
+ const auto &operand_shape = operands.at(operand_index).shape().asFeature();
+
+ asFeatureSink(execution, output_type, index, operand_shape, buffer, length);
+ }
+ else
+ {
+ // NOTE TensorSink is much slower than specialized Sink(s)
+ const auto &shape = operands.at(operand_index).shape();
+ asTensorSink(execution, output_type, index, shape, buffer, length);
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksExecution_startCompute(ANeuralNetworksExecution *execution,
+ ANeuralNetworksEvent **event)
+{
+ if ((execution == nullptr) || (event == nullptr))
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ // TODO: Handle event
+ ANeuralNetworksEvent *event_ptr = new ANeuralNetworksEvent{};
+ if (event_ptr == nullptr)
+ {
+ return ANEURALNETWORKS_OUT_OF_MEMORY;
+ }
+ *event = event_ptr;
+
+ return ANeuralNetworksExecution_compute(execution);
+}
+
+int ANeuralNetworksExecution_compute(ANeuralNetworksExecution *execution)
+{
+ if (execution == nullptr)
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ const bool sync = profiling::Context::get().sync();
+ const auto &plan = execution->plan();
+ const auto &model = plan.model();
+
+ // Set input(s)
+ for (uint32_t n = 0; n < model.inputs.size(); ++n)
+ {
+ auto setter = [&](::arm_compute::ITensor &tensor) { execution->source(n).push(tensor); };
+
+ // Some operand may not be defined at plan. Because some operands
+ // may be useless at ACL (ex. shape tensor for Reshape operator)
+ // So added a sanity check.
+ if (plan.operands().exist(model.inputs.at(n)))
+ {
+ plan.operands().at(model.inputs.at(n)).access(setter);
+ }
+ }
+
+ const auto &operations = execution->plan().operations();
+
+ for (uint32_t n = 0; n < operations.size(); ++n)
+ {
+ auto prof = profiling::Context::get().getProfiler();
+ SCOPED_OPERATOR_PROFILE(prof, operations.at(n).op_idx());
+ operations.at(n).run();
+
+ if (sync)
+ {
+ arm_compute::CLScheduler::get().sync();
+ }
+ }
+
+ // Get output(s)
+ for (uint32_t n = 0; n < model.outputs.size(); ++n)
+ {
+ auto getter = [&](::arm_compute::ITensor &tensor) { execution->sink(n).pull(tensor); };
+
+ plan.operands().at(model.outputs.at(n)).access(getter);
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksExecution_free(ANeuralNetworksExecution *execution) {}
+
+// TODO: implement this. added to fix link error on test build.
+int ANeuralNetworksExecution_setInputFromMemory(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory, size_t offset,
+ size_t length)
+{
+ if ((execution == nullptr) || (memory == nullptr))
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ assert(false);
+ return -1;
+}
+
+// TODO: implement this. added to fix link error on test build.
+int ANeuralNetworksExecution_setOutputFromMemory(ANeuralNetworksExecution *execution, int32_t index,
+ const ANeuralNetworksOperandType *type,
+ const ANeuralNetworksMemory *memory, size_t offset,
+ size_t length)
+{
+ if ((execution == nullptr) || (memory == nullptr))
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ assert(false);
+ return -1;
+}
+
+int ANeuralNetworksExecution_getOutputOperandRank(ANeuralNetworksExecution *execution,
+ int32_t index, uint32_t *rank)
+{
+ if ((execution == nullptr) || (rank == nullptr))
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ const auto &operands = execution->plan().model().operands();
+ const auto operand_index = execution->plan().model().outputs.at(index);
+ const auto &output_shape = operands.at(operand_index).shape();
+
+ *rank = output_shape.rank();
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksExecution_getOutputOperandDimensions(ANeuralNetworksExecution *execution,
+ int32_t index, uint32_t *dimensions)
+{
+ if ((execution == nullptr) || (dimensions == nullptr))
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ const auto &operands = execution->plan().model().operands();
+ const auto operand_index = execution->plan().model().outputs.at(index);
+ const auto &output_shape = operands.at(operand_index).shape();
+
+ for (uint32_t axis = 0; axis < output_shape.rank(); ++axis)
+ {
+ dimensions[axis] = static_cast<uint32_t>(output_shape.dim(axis));
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
diff --git a/runtime/contrib/pure_arm_compute/src/execution.h b/runtime/contrib/pure_arm_compute/src/execution.h
new file mode 100644
index 000000000..f55ab3fbf
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/execution.h
@@ -0,0 +1,119 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file execution.h
+ * @brief This file contains ANeuralNetworksExecution class for handling Execution NNAPI such as
+ * ANeuralNetworksExecution_create, ANeuralNetworksExecution_setInput
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __EXECUTION_H__
+#define __EXECUTION_H__
+
+#include "internal/arm_compute.h"
+#include "internal/Sink.h"
+#include "internal/Source.h"
+
+/**
+ * @brief struct to express Execution of NNAPI
+ */
+struct ANeuralNetworksExecution
+{
+public:
+ /**
+ * @brief Construct with params
+ * @param [in] plan Pointer to get internal::arm_compute::Plan
+ */
+ ANeuralNetworksExecution(const std::shared_ptr<const internal::arm_compute::Plan> &plan)
+ : _plan{plan}
+ {
+ _sources.resize(_plan->model().inputs.size());
+ _sinks.resize(_plan->model().outputs.size());
+ }
+
+public:
+ /**
+ * @brief Get reference of internal::arm_compute::Plan
+ * @return Const reference of internal::arm_compute::Plan
+ */
+ const internal::arm_compute::Plan &plan(void) const { return *_plan; }
+
+private:
+ std::shared_ptr<const internal::arm_compute::Plan> _plan;
+
+public:
+ /**
+ * @brief Set the nth source with param
+ * @param [in] n Index of the nth source
+ * @param [in] source Pointer to set the nth source from
+ * @return N/A
+ */
+ // TODO Use InputIndex instead of int
+ void source(int n, std::unique_ptr<Source> &&source) { _sources.at(n) = std::move(source); }
+ /**
+ * @brief Set the nth source with param
+ * @param [in] n Index of the nth source
+ * @param [in] args Arguments to set the nth source from
+ * @return N/A
+ */
+ template <typename T, typename... Args> void source(int n, Args &&... args)
+ {
+ source(n, std::unique_ptr<T>{new T{std::forward<Args>(args)...}});
+ }
+
+public:
+ /**
+ * @brief Get the nth source
+ * @param [in] n Index of the nth source
+ * @return Const reference of Source
+ */
+ const Source &source(int n) const { return *(_sources.at(n)); }
+
+public:
+ /**
+ * @brief Set the nth sink with param
+ * @param [in] n Index of the nth sink
+ * @param [in] sink Pointer to set the nth sink from
+ * @return N/A
+ */
+ // TODO Use OutputIndex instead of int
+ void sink(int n, std::unique_ptr<Sink> &&sink) { _sinks.at(n) = std::move(sink); }
+ /**
+ * @brief Set the nth sink with param
+ * @param [in] n Index of the nth sink
+ * @param [in] args Arguments to set the nth sink from
+ * @return N/A
+ */
+ template <typename T, typename... Args> void sink(int n, Args &&... args)
+ {
+ sink(n, std::unique_ptr<T>{new T{std::forward<Args>(args)...}});
+ }
+
+public:
+ /**
+ * @brief Get the nth sink
+ * @param [in] n Index of the nth sink
+ * @return Const reference of Sink
+ */
+ const Sink &sink(int n) const { return *(_sinks.at(n)); }
+
+private:
+ std::vector<std::unique_ptr<Source>> _sources;
+ std::vector<std::unique_ptr<Sink>> _sinks;
+};
+
+#endif
diff --git a/runtime/contrib/pure_arm_compute/src/internal/FeatureSink.h b/runtime/contrib/pure_arm_compute/src/internal/FeatureSink.h
new file mode 100644
index 000000000..7c6884141
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/FeatureSink.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file        FeatureSink.h
+ * @brief       This file contains FeatureSink class
+ * @ingroup     COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_FEATURE_SINK_H__
+#define __INTERNAL_FEATURE_SINK_H__
+
+#include "internal/Sink.h"
+#include "internal/nnapi/feature/View.h"
+#include "internal/arm_compute/feature/View.h"
+
+#include <misc/feature/Shape.h>
+#include "misc/feature/IndexIterator.h"
+
+/**
+ * @brief Class to store Feature(4D) output data.
+ * This is for pulling data to internal tensor from other tensor.
+ * @tparam T Type of the data elements
+ */
+template <typename T> class FeatureSink final : public Sink
+{
+public:
+ /**
+ * @brief Construct a FeatureSink object
+ *
+ * @param[in] shape 4D tensor dimensions for this feature
+ * @param[in] base Base pointer of the actual data
+ * @param[in] size Size of the data
+ */
+ FeatureSink(const nnfw::misc::feature::Shape &shape, T *base, const size_t size)
+ : _shape{shape}, _base{base}, _size{size}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Pull the data into the internal structure
+ * @param[in] tensor The tensor which contains source data
+ * @return N/A
+ */
+ void pull(::arm_compute::ITensor &tensor) const override
+ {
+ const ::internal::arm_compute::feature::View<T> from{&tensor};
+ // TODO Should remove casting.
+ // Inevitably casting must be done.
+ ::internal::nnapi::feature::View<T> into{_shape, _base, _size};
+
+ ::nnfw::misc::feature::iterate(_shape)
+ << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
+ const auto value = from.at(batch, ch, row, col);
+ into.at(batch, ch, row, col) = value;
+ };
+ }
+
+private:
+ const nnfw::misc::feature::Shape _shape;
+ T *const _base;
+ const size_t _size;
+};
+
+#endif // __INTERNAL_FEATURE_SINK_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/FeatureSource.h b/runtime/contrib/pure_arm_compute/src/internal/FeatureSource.h
new file mode 100644
index 000000000..772beb701
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/FeatureSource.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file        FeatureSource.h
+ * @brief       This file contains FeatureSource class
+ * @ingroup     COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_FEATURE_SOURCE_H__
+#define __INTERNAL_FEATURE_SOURCE_H__
+
+#include <misc/feature/Shape.h>
+#include <misc/feature/IndexIterator.h>
+
+#include "internal/nnapi/feature/Reader.h"
+#include "internal/arm_compute/feature/View.h"
+
+/**
+ * @brief Class to store feature(4D) input data.
+ * This is for push out the data to another tensor.
+ * @tparam T Type of the data elements
+ */
+template <typename T> class FeatureSource final : public Source
+{
+public:
+ /**
+ * @brief Construct a FeatureSource object
+ *
+ * @param[in] shape 4D tensor dimensions for this feature
+ * @param[in] base Base pointer of the actual data
+ * @param[in] size Size of the data
+ */
+ FeatureSource(const nnfw::misc::feature::Shape &shape, const T *base, const size_t size)
+ : _shape{shape}, _base{base}, _size{size}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Push the data out to the another tensor
+ * @param[out] The tensor that output data will be stored
+ * @return N/A
+ */
+ void push(::arm_compute::ITensor &tensor) const override
+ {
+ const ::internal::nnapi::feature::Reader<T> from{_shape, _base, _size};
+ ::internal::arm_compute::feature::View<T> into{&tensor};
+
+ ::nnfw::misc::feature::iterate(_shape)
+ << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
+ const auto value = from.at(batch, ch, row, col);
+ into.at(batch, ch, row, col) = value;
+ };
+ }
+
+private:
+ const nnfw::misc::feature::Shape _shape;
+ const T *const _base;
+ const size_t _size;
+};
+
+#endif // __INTERNAL_FEATURE_SOURCE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/IExecutionBuilder.h b/runtime/contrib/pure_arm_compute/src/internal/IExecutionBuilder.h
new file mode 100644
index 000000000..2a6e2a743
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/IExecutionBuilder.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file IExecutionBuilder.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines interface of ExecutionBuilder
+ */
+#ifndef __INTERNAL_IEXECUTION_BUILDER_H__
+#define __INTERNAL_IEXECUTION_BUILDER_H__
+
+#include <arm_compute/runtime/IFunction.h>
+
+#include <memory>
+#include <string>
+
+/**
+ * @brief Struct to define interface of ExecutionBuilder
+ */
+struct IExecutionBuilder
+{
+ /**
+ * @brief Destroy the IExecutionBuilder object
+ */
+ virtual ~IExecutionBuilder() = default;
+
+ /**
+ * @brief Append function to execute
+ * @param[in] name Name of function
+ * @param[in] f Function to append
+ * @return N/A
+ */
+ virtual void append(const std::string &name, std::unique_ptr<::arm_compute::IFunction> &&f) = 0;
+};
+
+#endif // __INTERNAL_IEXECUTION_BUILDER_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/MatrixSink.h b/runtime/contrib/pure_arm_compute/src/internal/MatrixSink.h
new file mode 100644
index 000000000..23ecc112b
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/MatrixSink.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file MatrixSink.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines MatrixSink class
+ */
+#ifndef __INTERNAL_MATRIX_SINK_H__
+#define __INTERNAL_MATRIX_SINK_H__
+
+#include "internal/Sink.h"
+
+#include <arm_compute/core/ITensor.h>
+#include <arm_compute/core/Window.h>
+#include <arm_compute/core/Helpers.h>
+
+#include <cstdint>
+#include <cstring>
+#include <cassert>
+
+/**
+ * @brief Class to get matrix data from arm compute tensor
+ */
+template <typename T> class MatrixSink final : public Sink
+{
+public:
+ /**
+ * @brief Construct a new Matrix Sink object
+ * @param[in] H Height of matrix
+ * @param[in] W Width of matrix
+ * @param[in] base Pointer to get data
+ * @param[in] size Size of matrix
+ */
+ MatrixSink(const int32_t H, const int32_t W, T *base, const size_t size)
+ : _height{H}, _width{W}, _base{base}
+ {
+ assert(size >= _height * _width * sizeof(T));
+ }
+
+public:
+ /**
+ * @brief Get matrix data from arm compute tensor to base
+ * @param[in] tensor Tensor object of arm compute to get data
+ * @return N/A
+ */
+ void pull(::arm_compute::ITensor &tensor) const override
+ {
+ assert(tensor.info()->dimension(0) == _width);
+ assert(tensor.info()->dimension(1) == _height);
+
+ using ::arm_compute::Window;
+ using ::arm_compute::Iterator;
+ using ::arm_compute::Coordinates;
+ using ::arm_compute::execute_window_loop;
+
+ Window window;
+
+ window.use_tensor_dimensions(tensor.info()->tensor_shape(), ::arm_compute::Window::DimY);
+
+ Iterator it(&tensor, window);
+ execute_window_loop(window,
+ [&](const ::arm_compute::Coordinates &id) {
+ const auto row = id.y();
+ memcpy(_base + row * _width, it.ptr(), _width * sizeof(T));
+ },
+ it);
+ }
+
+private:
+ const int32_t _height;
+ const int32_t _width;
+
+private:
+ T *const _base;
+};
+
+#endif // __INTERNAL_MATRIX_SINK_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/MatrixSource.h b/runtime/contrib/pure_arm_compute/src/internal/MatrixSource.h
new file mode 100644
index 000000000..71d6a804f
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/MatrixSource.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file MatrixSource.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines MatrixSource class
+ */
+#ifndef __INTERNAL_MATRIX_SOURCE_H__
+#define __INTERNAL_MATRIX_SOURCE_H__
+
+#include <arm_compute/core/ITensor.h>
+#include <arm_compute/core/Window.h>
+#include <arm_compute/core/Helpers.h>
+
+#include "internal/Source.h"
+
+/**
+ * @brief Class to push matrix data to arm compute tensor
+ */
+template <typename T> class MatrixSource final : public Source
+{
+public:
+ /**
+ * @brief Construct a new MatrixSource object
+ * @param[in] shape Shape of matrix
+ * @param[in] base Pointer of matrix data to push
+ * @param[in] size Size of matrix
+ */
+ MatrixSource(const nnfw::misc::matrix::Shape &shape, const T *base, const size_t size)
+ : _shape{shape}, _base{base}, _size{size}
+ {
+ // do nothing
+ }
+
+public:
+ /**
+ * @brief Push matrix data to arm compute tensor
+ * @param[out] tensor Tensor object of arm compute to push matrix data
+ * @return N/A
+ */
+ void push(::arm_compute::ITensor &tensor) const override
+ {
+ using ::arm_compute::Window;
+ using ::arm_compute::Iterator;
+ using ::arm_compute::Coordinates;
+ using ::arm_compute::execute_window_loop;
+
+ Window window;
+ window.use_tensor_dimensions(tensor.info()->tensor_shape(), ::arm_compute::Window::DimY);
+
+ int32_t width = _shape.W;
+
+ Iterator it(&tensor, window);
+ execute_window_loop(window,
+ [&](const ::arm_compute::Coordinates &id) {
+ const auto height = id.y();
+ memcpy(it.ptr(), _base + height * width, width * sizeof(T));
+ },
+ it);
+ }
+
+private:
+ const nnfw::misc::matrix::Shape _shape;
+ const T *const _base;
+ const size_t _size;
+};
+
+#endif // __INTERNAL_MATRIX_SOURCE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/Model.cc b/runtime/contrib/pure_arm_compute/src/internal/Model.cc
new file mode 100644
index 000000000..03753fea2
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/Model.cc
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/Model.h"
+
+namespace internal
+{
+namespace tflite
+{
+namespace operand
+{
+
+Shape::Shape(uint32_t rank) : nnfw::misc::tensor::Shape(rank)
+{
+ // DO NOTHING
+}
+
+int32_t Shape::asVector(void) const
+{
+ assert(rank() == 1);
+
+ return dim(0);
+}
+
+nnfw::misc::matrix::Shape Shape::asMatrix(void) const
+{
+ assert(rank() == 2);
+
+ const auto height = dim(0);
+ const auto width = dim(1);
+
+ return nnfw::misc::matrix::Shape(height, width);
+}
+
+nnfw::misc::feature::Shape Shape::asFeature(void) const
+{
+ assert(rank() == 4);
+
+ // Feature Map in NNAPI
+ // - Dimension(0) -> Batch
+ // - Dimension(1) -> Height
+ // - Dimension(2) -> Width
+ // - Dimension(3) -> Depth
+
+ const auto batch = dim(0);
+ const auto depth = dim(3);
+ const auto height = dim(1);
+ const auto width = dim(2);
+
+ return nnfw::misc::feature::Shape(batch, depth, height, width);
+}
+
+nnfw::misc::tensor::Shape Shape::asTensor(void) const
+{
+ return nnfw::misc::tensor::Shape(*this); // this shape represents shape of NNAPI
+}
+
+nnfw::misc::kernel::Shape Shape::asKernel(void) const
+{
+ assert(rank() == 4);
+
+ // Convolution Kernel in NNAPI
+ // - Dimension(0) -> Count
+ // - Dimension(1) -> Height
+ // - Dimension(2) -> Width
+ // - Dimension(3) -> Depth
+ const auto count = dim(0);
+ const auto depth = dim(3);
+ const auto height = dim(1);
+ const auto width = dim(2);
+
+ return nnfw::misc::kernel::Shape(count, depth, height, width);
+}
+
+// Extended dimension is filled with 1.
+void Shape::extendRank(size_t to_rank)
+{
+ for (int i = rank() + 1; i <= to_rank; ++i)
+ {
+ prepend(1);
+ }
+}
+
+} // namespace operand
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace operand
+{
+
+Index Set::append(const Shape &shape, int32_t type, float scale, int32_t zeroPoint)
+{
+ int32_t index = _objects.size();
+
+ _objects.emplace_back(new Object{shape, type, scale, zeroPoint});
+
+ return Index{index};
+}
+
+const Object &Set::at(const Index &index) const { return *(_objects.at(index.asInt())); }
+
+Object &Set::at(const Index &index) { return *(_objects.at(index.asInt())); }
+
+bool Set::exist(const Index &index) const
+{
+ return index.asInt() >= 0 && index.asInt() < _objects.size();
+}
+
+} // namespace operand
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/Model.h b/runtime/contrib/pure_arm_compute/src/internal/Model.h
new file mode 100644
index 000000000..bdcf32f6f
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/Model.h
@@ -0,0 +1,538 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Model.h
+ * @brief This file contains classes for handle internal Model object
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_MODEL_H__
+#define __INTERNAL_MODEL_H__
+
+namespace internal
+{
+namespace tflite
+{
+namespace operand
+{
+
+/**
+ * @brief Class to express index of operand.
+ */
+class Index
+{
+public:
+ /**
+ * @brief Construct a new Index object for operand with param.
+ * @param [in] value The number of index
+ */
+ explicit Index(int value) : _value{value}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get index value as int
+ * @return Index value as int
+ */
+ int asInt(void) const { return _value; }
+
+private:
+ int _value;
+};
+
+} // namespace operand
+} // namespace tflite
+} // namespace internal
+
+#include <vector>
+#include <cstdint>
+
+#include "misc/feature/Shape.h"
+#include "misc/matrix/Shape.h"
+#include "misc/kernel/Shape.h"
+#include "misc/tensor/Shape.h"
+
+namespace internal
+{
+namespace tflite
+{
+namespace operand
+{
+
+/**
+ * @brief Class to express shape of operand.
+ */
+struct Shape : public nnfw::misc::tensor::Shape
+{
+public:
+ /**
+ * @brief Construct a new Shape object for operand with param.
+ * @param [in] rank The rank value of shape
+ */
+ Shape(uint32_t rank);
+
+public:
+ /**
+ * @brief Get dimension value of tensor as vector
+ * @return Dimension value(int32_t) of tensor as vector
+ */
+ int32_t asVector(void) const;
+ /**
+ * @brief Get dimension values of tensor as feature::Shape
+ * @return Dimension values of tensor as feature::Shape
+ */
+ nnfw::misc::feature::Shape asFeature(void) const;
+ /**
+ * @brief Get dimension values of tensor as matrix::Shape
+ * @return Dimension values of tensor as matrix::Shape
+ */
+ nnfw::misc::matrix::Shape asMatrix(void) const;
+ /**
+ * @brief Get dimension values of tensor as kernel::Shape
+ * @return Dimension values of tensor as kernel::Shape
+ */
+ nnfw::misc::kernel::Shape asKernel(void) const;
+ /**
+ * @brief Get dimension values of tensor::Shape
+ * @return Dimension values of tensor::Shape
+ */
+ nnfw::misc::tensor::Shape asTensor(void) const;
+
+public:
+ /**
+ * @brief Extend rank of Shape object for operand with param.
+ * @param [in] to_rank The rank value to be extended to
+ * @return N/A
+ */
+ void extendRank(size_t);
+};
+
+} // namespace operand
+} // namespace tflite
+} // namespace internal
+
+#include <algorithm>
+
+namespace internal
+{
+namespace tflite
+{
+namespace operand
+{
+
+/**
+ * @brief Class to have data of operand.
+ */
+struct Data
+{
+ /**
+ * @brief Destruct this object
+ */
+ virtual ~Data() = default;
+
+ /**
+ * @brief Get size of data
+ * @return size of data
+ */
+ virtual size_t size(void) const = 0;
+ /**
+ * @brief Get the base address of data
+ * @return the base address of data
+ */
+ virtual const uint8_t *base(void) const = 0;
+};
+
+/**
+ * @brief Class to have cached data of operand.
+ */
+class CachedData final : public Data
+{
+public:
+ /**
+ * @brief Construct a new CachedData object for operand with param.
+ * @param [in] base the base address of data
+ * @param [in] size the size of data
+ */
+ CachedData(const uint8_t *base, size_t size) : _base{new uint8_t[size]}, _size{size}
+ {
+ std::copy(base, base + size, _base);
+ }
+
+public:
+ /**
+ * @brief Destruct this object
+ */
+ ~CachedData() { delete[] _base; }
+
+public:
+ /**
+ * @brief Get size of data
+ * @return size of data
+ */
+ size_t size(void) const override { return _size; }
+ /**
+ * @brief Get the base address of data
+ * @return the base address of data
+ */
+ const uint8_t *base(void) const override { return _base; }
+
+private:
+ uint8_t *_base;
+ size_t _size;
+};
+
+/**
+ * @brief Class to have external data of operand.
+ */
+class ExternalData final : public Data
+{
+public:
+ /**
+ * @brief Construct a new ExternalData object for operand with param.
+ * @param [in] base the base address of data
+ * @param [in] size the size of data
+ */
+ ExternalData(const uint8_t *base, size_t size) : _base{base}, _size{size}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get size of data
+ * @return size of data
+ */
+ size_t size(void) const override { return _size; }
+ /**
+ * @brief Get the base address of data
+ * @return the base address of data
+ */
+ const uint8_t *base(void) const override { return _base; }
+
+private:
+ const uint8_t *_base;
+ const size_t _size;
+};
+
+} // namespace operand
+} // namespace tflite
+} // namespace internal
+
+#include <memory>
+#include <cassert>
+#include <functional>
+#include "internal/Swizzle.h"
+
+namespace internal
+{
+namespace tflite
+{
+namespace operand
+{
+
+/**
+ * @brief Class to express operand as object.
+ */
+class Object
+{
+public:
+ /**
+ * @brief Construct a new Object object for operand with param.
+ * @param [in] shape shape of operand
+ * @param [in] type type of operand
+ * @param [in] scale scale of operand
+ * @param [in] zeroPoint zeroPoint of operand
+ */
+ explicit Object(const Shape &shape, const int32_t type, const float scale,
+ const int32_t zeroPoint)
+ : _shape{shape}, _type{type}, _scale{scale}, _zeroPoint{zeroPoint}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get shape of operand
+ * @return Reference of shape of operand
+ */
+ const Shape &shape(void) const { return _shape; }
+ /**
+ * @brief Get type of operand
+ * @return type of operand
+ */
+ const int32_t type(void) const { return _type; }
+ /**
+ * @brief Get scale of operand
+ * @return scale of operand
+ */
+ const float scale(void) const { return _scale; }
+ /**
+ * @brief Get zeroPoint of operand
+ * @return zeroPoint of operand
+ */
+ const int32_t zeroPoint(void) const { return _zeroPoint; }
+
+private:
+ void data(std::unique_ptr<Data> &&data) { _data = std::move(data); }
+
+public:
+ /**
+ * @brief Get data of operand
+ * @return Reference of data of operand
+ */
+ const Data &data(void) const { return *_data; }
+ /**
+ * @brief Get true if Object has data, otherwise @c false
+ * @return @c true if Object has data, otherwise @c false
+ */
+ bool hasData(void) const { return _data != nullptr; }
+
+public:
+ /**
+ * @brief Set data of operand with param
+ * @param [in] args arguments of data to be set
+ * @return N/A
+ */
+ template <typename T, typename... Args> void data(Args &&... args)
+ {
+ data(std::unique_ptr<T>(new T{std::forward<Args>(args)...}));
+ }
+
+public:
+ /**
+ * @brief Get value of data as scalar
+ * @return value of data as scalar
+ */
+ template <typename T> T asScalar(void) const
+ {
+ assert((_shape.rank() == 0) || ((_shape.rank() == 1) && (_shape.dim(0) == 1)));
+ assert(_data != nullptr);
+ assert((_data->base() != nullptr) && (_data->size() == sizeof(T)));
+
+ return *(reinterpret_cast<const T *>(_data->base()));
+ }
+
+public:
+ /**
+ * @brief Get value of data as ReorderBits
+ * @param [in] numOfBits The number of bits to be reordered to
+ * @return value of data as ReorderBits
+ */
+ template <typename T> T asReorderBits(size_t numOfBits) const
+ {
+ assert((_shape.rank() == 0) || ((_shape.rank() == 1) && (_shape.dim(0) == 1)));
+ assert(_data != nullptr);
+ assert((_data->base() != nullptr) && (_data->size() == sizeof(T)));
+
+ return ReorderBits<T>(asScalar<T>(), numOfBits);
+ }
+
+private:
+ const Shape _shape;
+ const int32_t _type;
+ const float _scale;
+ const int32_t _zeroPoint;
+ std::unique_ptr<Data> _data;
+};
+
+} // namespace operand
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace operand
+{
+
+/**
+ * @brief Class to have object instances in a kind of set
+ */
+class Set
+{
+public:
+ /**
+ * @brief Iterate objects with fn
+ * @param [in] fn function to be iterated
+ * @return N/A
+ */
+ void iterate(const std::function<void(const Index &)> &fn)
+ {
+ for (uint32_t n = 0; n < _objects.size(); ++n)
+ {
+ const Index operand_index{static_cast<int>(n)};
+ fn(operand_index);
+ }
+ }
+
+public:
+ /**
+ * @brief Append Object for operand with param
+ * @param [in] shape shape of operand
+ * @param [in] type type of operand
+ * @param [in] scale scale of operand
+ * @param [in] zeroPoint zeroPoint of operand
+ * @return Value of Index which has been appended to
+ */
+ Index append(const Shape &, int32_t type, float scale, int32_t zeroPoint);
+
+public:
+ /**
+ * @brief Get Object at Index
+ * @param [in] index Index to be at
+ * @return Const refernece of Object
+ */
+ const Object &at(const Index &) const;
+ /**
+ * @brief Get Object at Index
+ * @param [in] index Index to be at
+ * @return Refernece of Object
+ */
+ Object &at(const Index &);
+ /**
+ * @brief Get size of operands in Set
+ * @return Value of size
+ */
+ size_t size(void) const { return _objects.size(); }
+ bool exist(const Index &) const;
+
+private:
+ std::vector<std::unique_ptr<Object>> _objects;
+};
+
+} // namespace operand
+} // namespace tflite
+} // namespace internal
+
+#include "internal/op/NodeVisitor.h"
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+
+/**
+ * @brief Class to have sequence operators.
+ */
+class Sequence
+{
+public:
+ /**
+ * @brief Construct a new Sequence object for operator as default
+ */
+ Sequence() = default;
+
+public:
+ /**
+ * @brief Get size of operators in Sequence
+ * @return Value of size
+ */
+ uint32_t size(void) const { return _ops.size(); }
+
+public:
+ /**
+ * @brief Get op::Node at Index
+ * @param [in] nth index to be at
+ * @return Refernece of op::Node
+ */
+ op::Node &at(uint32_t nth) { return *(_ops.at(nth)); }
+ /**
+ * @brief Get op::Node at Index
+ * @param [in] nth index to be at
+ * @return Const refernece of op::Node
+ */
+ const op::Node &at(uint32_t nth) const { return *(_ops.at(nth)); }
+
+private:
+ Sequence &emplace_back(std::unique_ptr<op::Node> &&node)
+ {
+ _ops.emplace_back(std::move(node));
+ return (*this);
+ }
+
+public:
+ /**
+ * @brief Add op::Node with param
+ * @param [in] args arguments of op::Node to be set
+ * @return Reference of Sequence
+ */
+ template <typename T, typename... Args> Sequence &emplace_back(Args &&... args)
+ {
+ return emplace_back(std::unique_ptr<T>(new T{std::forward<Args>(args)...}));
+ }
+
+private:
+ std::vector<std::unique_ptr<op::Node>> _ops;
+};
+
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+
+/**
+ * @brief Class to have operand::Set as operands and op::Sequence as operators
+ */
+class Model
+{
+public:
+ /**
+ * @brief Get operand::Set
+ * @return Reference of operand::Set
+ */
+ operand::Set &operands(void) { return _operands; }
+ /**
+ * @brief Get operand::Set
+ * @return Const reference of operand::Set
+ */
+ const operand::Set &operands(void) const { return _operands; }
+
+public:
+ /**
+ * @brief Get op::Sequence
+ * @return Reference of op::Sequence
+ */
+ op::Sequence &operations(void) { return _operations; }
+ /**
+ * @brief Get op::Sequence
+ * @return Const reference of op::Sequence
+ */
+ const op::Sequence &operations(void) const { return _operations; }
+
+private:
+ operand::Set _operands;
+ op::Sequence _operations;
+
+public:
+ // TODO Hide these fields
+ std::vector<operand::Index> inputs; /**< indexes of operand as input */
+ std::vector<operand::Index> outputs; /**< indexes of operand as output */
+};
+
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_MODEL_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/Sink.h b/runtime/contrib/pure_arm_compute/src/internal/Sink.h
new file mode 100644
index 000000000..6f44561ea
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/Sink.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Sink.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines Sink struct
+ */
+#ifndef __INTERNAL_SINK_H__
+#define __INTERNAL_SINK_H__
+
+#include <arm_compute/core/ITensor.h>
+
+/**
+ * @brief Struct to get tensor data from arm compute tensor (abstract)
+ */
+struct Sink
+{
+ /**
+ * @brief Destroy the Sink object
+ */
+ virtual ~Sink() = default;
+
+ /**
+ * @brief Get tensor data from arm compute tensor
+ * @param[in] tensor Tensor object of arm compute to get data
+ * @return N/A
+ */
+ virtual void pull(::arm_compute::ITensor &tensor) const = 0;
+};
+
+#endif // __INTERNAL_SINK_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/Sinks.h b/runtime/contrib/pure_arm_compute/src/internal/Sinks.h
new file mode 100644
index 000000000..7317c67c1
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/Sinks.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file        Sinks.h
+ * @brief       This file contains TensorSink class
+ * @ingroup     COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_SINKS_H__
+#define __INTERNAL_SINKS_H__
+
+#include "internal/Sink.h"
+
+// TODO Extract TensorSink into TensorSink.h
+//
+// TensorSink
+//
+#include "internal/Swizzle.h"
+
+#include "internal/nnapi/tensor/View.h"
+#include "internal/arm_compute/tensor/View.h"
+
+#include "misc/tensor/IndexIterator.h"
+
+/**
+ * @brief Class to store NN model output data for general-shaped tensors.
+ * This is for pulling data to internal tensor from other tensor.
+ * @tparam T Type of the data elements
+ */
+template <typename T> class TensorSink final : public Sink
+{
+public:
+ /**
+ * @brief Construct a TensorSink object
+ *
+ * @param[in] shape general-shaped tensor dimensions
+ * @param[in] base Base pointer of the actual data
+ * @param[in] size Size of the data
+ */
+ TensorSink(const nnfw::misc::tensor::Shape &shape, T *base, const size_t size)
+ : _shape{shape}, _base{base}, _size{size}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Pull the data into the internal structure
+ * @param[in] tensor The tensor which contains source data
+ * @return N/A
+ */
+ void pull(::arm_compute::ITensor &tensor) const override
+ {
+ const ::internal::arm_compute::tensor::View<T> from{&tensor};
+ ::internal::nnapi::tensor::View<T> into{_shape, _base, _size};
+
+ using ::nnfw::misc::tensor::iterate;
+ using ::nnfw::misc::tensor::Index;
+
+ const uint32_t rank = _shape.rank();
+
+ ::nnfw::misc::tensor::iterate(_shape) << [&](const Index &raw) {
+ Index permuted(raw.rank());
+
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ permuted.at(ToARMComputeAxis(rank, axis).value()) = raw.at(axis);
+ }
+
+ const auto value = from.at(permuted);
+ into.at(raw) = value;
+ };
+ }
+
+private:
+ const nnfw::misc::tensor::Shape _shape;
+
+private:
+ T *const _base;
+ const size_t _size;
+};
+
+#endif // __INTERNAL_SINKS_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/Source.h b/runtime/contrib/pure_arm_compute/src/internal/Source.h
new file mode 100644
index 000000000..fa8f1e811
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/Source.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Source.h
+ * @brief This file contains Source struct for pushing ITensor
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_SOURCE_H__
+#define __INTERNAL_SOURCE_H__
+
+#include <arm_compute/core/ITensor.h>
+
+/**
+ * @brief Struct to push inner source to ITensor.
+ */
+struct Source
+{
+ /**
+ * @brief Destructor as default
+ */
+ virtual ~Source() = default;
+
+ /**
+ * @brief Push inner source to ITensor
+ * @param [in] tensor ITensor to be pushed into
+ * @return N/A
+ */
+ virtual void push(::arm_compute::ITensor &tensor) const = 0;
+};
+
+#endif // __INTERNAL_SOURCE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/Swizzle.h b/runtime/contrib/pure_arm_compute/src/internal/Swizzle.h
new file mode 100644
index 000000000..f127b8a3b
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/Swizzle.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Swizzle.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines ARMComputeAxis class and utility functions to support mapping
+ * between arm compute axis and NNAPI axis
+ */
+#ifndef __SWIZZLE_H__
+#define __SWIZZLE_H__
+
+/**
+ * @brief Class to represent arm compute axis
+ */
+class ARMComputeAxis
+{
+public:
+ /**
+ * @brief Construct a new ARMComputeAxis object
+ */
+ ARMComputeAxis() = default;
+
+public:
+ /**
+ * @brief Construct a new ARMComputeAxis object
+ * @param[in] value Raw axis number
+ */
+ explicit ARMComputeAxis(uint32_t value) : _value{value}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get raw axis number
+ * @return Raw axis number
+ */
+ uint32_t value(void) const { return _value; }
+
+private:
+ uint32_t _value;
+};
+
+/**
+ * @brief Convert T/F Lite / NNAPI axis (based on ...NHWC) to arm compute axis (WHCN...)
+ * @param[in] rank Rank of shape
+ * @param[in] axis Axis to map
+ * @return ARMComputeAxis including arm compute axis info
+ */
+inline ARMComputeAxis ToARMComputeAxis(uint32_t rank, uint32_t axis)
+{
+ assert(rank > axis);
+ const ARMComputeAxis reversed{(rank - axis) - 1};
+
+ if (rank < 4)
+ {
+ return reversed;
+ }
+
+ // DEPTH
+ if (0 == reversed.value())
+ {
+ return ARMComputeAxis{2};
+ }
+ // WIDTH
+ if (1 == reversed.value())
+ {
+ return ARMComputeAxis{0};
+ }
+ // HEIGHT
+ if (2 == reversed.value())
+ {
+ return ARMComputeAxis{1};
+ }
+
+ // ELSE
+ return reversed;
+}
+
+#include <cassert>
+
+/**
+ * @brief Covert bitmask info from NNAPI axis to arm compute axis
+ * @param[in] in Bitmask data
+ * @param[in] numOfBits Used bits (rank)
+ * @return Coverted bitmask
+ */
+template <typename T> inline T ReorderBits(T in, size_t numOfBits)
+{
+ assert(numOfBits > 0);
+ T out = 0;
+ for (int32_t i = numOfBits - 1; i >= 0; --i)
+ {
+ const uint32_t toShift = numOfBits - ToARMComputeAxis(numOfBits, i).value() - 1;
+ out += ((in & 1) << toShift);
+ in >>= 1;
+ }
+ return out;
+}
+
+#endif // __SWIZZLE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/Tensor3DSink.h b/runtime/contrib/pure_arm_compute/src/internal/Tensor3DSink.h
new file mode 100644
index 000000000..1e14e2d6c
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/Tensor3DSink.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Tensor3DSink.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines Tensor3DSink class
+ */
+#ifndef __TENSOR3D_SINK_H__
+#define __TENSOR3D_SINK_H__
+
+#include "internal/Sink.h"
+
+//
+// This is mempcy() version of generic TensorSink for 3D tensor
+//
+#include <arm_compute/core/ITensor.h>
+#include <arm_compute/core/Window.h>
+#include <arm_compute/core/Helpers.h>
+
+/**
+ * @brief Class to get tensor data from arm compute tensor
+ */
+template <typename T> class Tensor3DSink final : public Sink
+{
+public:
+ /**
+ * @brief Construct a new Tensor3DSink object
+ * @param[in] shape Shape of tensor
+ * @param[in] base Pointer to get data
+ * @param[in] size Size of tensor
+ */
+ Tensor3DSink(const nnfw::misc::tensor::Shape &shape, T *base, const size_t size)
+ : _shape{shape}, _base{base}, _size{size}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get tensor data from arm compute tensor to base
+ * @param[in] tensor Tensor object of arm compute to get data
+ * @return N/A
+ */
+ void pull(::arm_compute::ITensor &tensor) const override
+ {
+ using ::arm_compute::Window;
+ using ::arm_compute::Iterator;
+ using ::arm_compute::Coordinates;
+ using ::arm_compute::execute_window_loop;
+
+ Window window;
+
+ window.use_tensor_dimensions(tensor.info()->tensor_shape(), ::arm_compute::Window::DimY);
+ int32_t height_width = _shape.dim(1) * _shape.dim(2);
+ int32_t width = _shape.dim(2);
+
+ Iterator it(&tensor, window);
+ execute_window_loop(window,
+ [&](const ::arm_compute::Coordinates &id) {
+ const auto z = id.z();
+ const auto y = id.y();
+ memcpy(_base + z * height_width + y * width, it.ptr(), width * sizeof(T));
+ },
+ it);
+ }
+
+private:
+ const nnfw::misc::tensor::Shape _shape;
+
+private:
+ T *const _base;
+ const size_t _size;
+};
+
+#endif // __TENSOR3D_SINK_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/Tensor3DSource.h b/runtime/contrib/pure_arm_compute/src/internal/Tensor3DSource.h
new file mode 100644
index 000000000..3d8d1b958
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/Tensor3DSource.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Tensor3DSource.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines Tensor3DSource class
+ */
+#ifndef __TENSOR3D_SOURCE_H__
+#define __TENSOR3D_SOURCE_H__
+
+#include "internal/Source.h"
+
+//
+// This is memcpy() version of generic TensorSource for 3D tensor
+//
+#include <arm_compute/core/ITensor.h>
+#include <arm_compute/core/Window.h>
+#include <arm_compute/core/Helpers.h>
+
+/**
+ * @brief Class to push tensor data to arm compute tensor
+ */
+template <typename T> class Tensor3DSource final : public Source
+{
+public:
+ /**
+ * @brief Construct a new Tensor3DSource object
+ * @param[in] shape Shape of tensor
+ * @param[in] base Pointer of tensor data to push
+ * @param[in] size Size of tensor
+ */
+ Tensor3DSource(const nnfw::misc::tensor::Shape &shape, const T *base, const size_t size)
+ : _shape{shape}, _base{base}, _size{size}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Push tensor data to arm compute tensor
+ * @param[out] tensor Tensor object of arm compute to push tensor data
+ * @return N/A
+ */
+ void push(::arm_compute::ITensor &tensor) const override
+ {
+ using ::arm_compute::Window;
+ using ::arm_compute::Iterator;
+ using ::arm_compute::Coordinates;
+ using ::arm_compute::execute_window_loop;
+
+ Window window;
+
+ window.use_tensor_dimensions(tensor.info()->tensor_shape(), ::arm_compute::Window::DimY);
+ int32_t height_width = _shape.dim(1) * _shape.dim(2);
+ int32_t width = _shape.dim(2);
+
+ Iterator it(&tensor, window);
+ execute_window_loop(window,
+ [&](const ::arm_compute::Coordinates &id) {
+ const auto z = id.z();
+ const auto y = id.y();
+ memcpy(it.ptr(), _base + z * height_width + y * width, width * sizeof(T));
+ },
+ it);
+ }
+
+private:
+ const nnfw::misc::tensor::Shape _shape;
+
+private:
+ const T *const _base;
+ const size_t _size;
+};
+
+#endif // __TENSOR3D_SOURCE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/TensorSource.h b/runtime/contrib/pure_arm_compute/src/internal/TensorSource.h
new file mode 100644
index 000000000..114d3588e
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/TensorSource.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file TensorSource.h
+ * @brief This file contains TensorSource class which is inherited from Source class
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_TENSOR_SOURCE_H__
+#define __INTERNAL_TENSOR_SOURCE_H__
+
+#include <misc/tensor/Shape.h>
+#include <misc/tensor/IndexIterator.h>
+
+#include "internal/Source.h"
+#include "internal/Swizzle.h"
+#include "internal/nnapi/tensor/Reader.h"
+#include "internal/arm_compute/tensor/View.h"
+
+// NOTE TensorSource is much slower than specialized Source(s)
+/**
+ * @brief Class to define constructor and push function
+ */
+template <typename T> class TensorSource final : public Source
+{
+public:
+ /**
+ * @brief Construct a new TensorSource object with params
+ * @param [in] shape Shape of tensor
+ * @param [in] base Base address
+ * @param [in] size Size of tensor
+ */
+ TensorSource(const nnfw::misc::tensor::Shape &shape, const T *base, const size_t size)
+ : _shape{shape}, _base{base}, _size{size}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Function for pushing tensor
+ * @param [in] tensor Tensor to be pushed
+ * @return N/A
+ */
+ void push(::arm_compute::ITensor &tensor) const override
+ {
+ const ::internal::nnapi::tensor::Reader<T> from{_shape, _base, _size};
+ ::internal::arm_compute::tensor::View<T> into{&tensor};
+
+ ::nnfw::misc::tensor::iterate(_shape) << [&](const nnfw::misc::tensor::Index &index_nnapi) {
+ const auto rank = index_nnapi.rank();
+ nnfw::misc::tensor::Index index_ACL(rank);
+
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ index_ACL.at(ToARMComputeAxis(rank, axis).value()) = index_nnapi.at(axis);
+ }
+
+ into.at(index_ACL) = from.at(index_nnapi);
+ };
+ }
+
+private:
+ const nnfw::misc::tensor::Shape _shape;
+ const T *const _base;
+ const size_t _size;
+};
+
+#endif // __INTERNAL_TENSOR_SOURCE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/VectorSink.h b/runtime/contrib/pure_arm_compute/src/internal/VectorSink.h
new file mode 100644
index 000000000..a630ef1c1
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/VectorSink.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file        VectorSink.h
+ * @brief       This file contains VectorSink class
+ * @ingroup     COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_VECTOR_SINK_H__
+#define __INTERNAL_VECTOR_SINK_H__
+
+#include "internal/Sink.h"
+
+#include <arm_compute/core/ITensor.h>
+
+#include <cassert>
+
+/**
+ * @brief Class to store vector(2D) output data.
+ * This is for pulling out the data to another tensor.
+ * @tparam T Type of the data elements
+ */
+template <typename T> class VectorSink final : public Sink
+{
+public:
+ /**
+ * @brief Construct a VectorSink object
+ * @param[in] vlen Length of the vector
+ * @param[in] base Base pointer of the actual data
+ * @param[in] size Size of the data
+ */
+ VectorSink(const int32_t vlen, T *base, const size_t size) : _vlen{vlen}, _base{base}
+ {
+ assert(size >= _vlen * sizeof(T));
+ }
+
+public:
+ /**
+ * @brief Pull the data into the internal structure
+ * @param[in] tensor The tensor which contains source data
+ * @return N/A
+ */
+ void pull(::arm_compute::ITensor &tensor) const override
+ {
+ for (int32_t n = 0; n < _vlen; ++n)
+ {
+ auto from = reinterpret_cast<T *>(tensor.ptr_to_element(::arm_compute::Coordinates{n}));
+ auto into = _base + n;
+
+ *into = *from;
+ }
+ }
+
+private:
+ const int32_t _vlen;
+ T *const _base;
+};
+
+#endif // __INTERNAL_VECTOR_SINK_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/VectorSource.h b/runtime/contrib/pure_arm_compute/src/internal/VectorSource.h
new file mode 100644
index 000000000..48d3d3209
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/VectorSource.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file        VectorSource.h
+ * @brief       This file contains VectorSource class
+ * @ingroup     COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_VECTOR_SOURCE_H__
+#define __INTERNAL_VECTOR_SOURCE_H__
+
+#include "internal/Source.h"
+
+/**
+ * @brief Class to store vector(2D) input data.
+ * This is for push out the data to another tensor.
+ * @tparam T Type of the data elements
+ */
+template <typename T> class VectorSource final : public Source
+{
+public:
+ /**
+ * @brief Construct a VectorSource object
+ * @param[in] vlen Length of the vector
+ * @param[in] base Base pointer of the actual data
+ * @param[in] size Size of the data
+ */
+ VectorSource(const int32_t vlen, const T *base, const size_t size) : _vlen{vlen}, _base{base}
+ {
+ assert(size >= _vlen * sizeof(T));
+ }
+
+public:
+ /**
+ * @brief Push the data out to the another tensor
+ * @param[out] The tensor that output data will be stored
+ * @return N/A
+ */
+ void push(::arm_compute::ITensor &tensor) const override
+ {
+ for (int32_t n = 0; n < _vlen; ++n)
+ {
+ auto from = _base + n;
+ auto into = reinterpret_cast<T *>(tensor.ptr_to_element(::arm_compute::Coordinates{n}));
+
+ *into = *from;
+ }
+ }
+
+private:
+ const int32_t _vlen;
+ const T *const _base;
+};
+
+#endif // __INTERNAL_VECTOR_SOURCE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute.cc b/runtime/contrib/pure_arm_compute/src/internal/arm_compute.cc
new file mode 100644
index 000000000..a7be2068d
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute.cc
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/arm_compute.h"
+
+#include <arm_compute/runtime/CL/CLScheduler.h>
+
+#include <cassert>
+
+namespace internal
+{
+namespace arm_compute
+{
+namespace operand
+{
+
+void Object::access(const std::function<void(::arm_compute::ITensor &tensor)> &fn) const
+{
+ if (::internal::arm_compute::isGpuMode())
+ {
+ auto &queue = ::arm_compute::CLScheduler::get().queue();
+
+ auto cl_tensor = _tensor.get();
+ CAST_CL(cl_tensor)->map(queue);
+ fn(*_tensor);
+ CAST_CL(cl_tensor)->unmap(queue);
+ }
+ else
+ {
+ fn(*_tensor);
+ }
+}
+
+} // namespace operand
+} // namepsace arm_compute
+} // namespace internal
+
+namespace internal
+{
+namespace arm_compute
+{
+namespace operand
+{
+
+Context &Context::set(const ::internal::tflite::operand::Index &id,
+ const std::shared_ptr<::arm_compute::ITensor> &tensor)
+{
+ assert(_objects.find(id.asInt()) == _objects.end());
+
+ _objects[id.asInt()] = Object{tensor};
+ return (*this);
+}
+
+} // namespace operand
+} // namepsace arm_compute
+} // namespace internal
+
+namespace internal
+{
+namespace arm_compute
+{
+
+bool isGpuMode()
+{
+ char *neon = std::getenv("NEON");
+ if (neon == nullptr)
+ return true;
+ else if (neon[0] == '1')
+ return false;
+ return true;
+}
+
+} // namepsace arm_compute
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute.h b/runtime/contrib/pure_arm_compute/src/internal/arm_compute.h
new file mode 100644
index 000000000..fb6acaf81
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute.h
@@ -0,0 +1,337 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file        arm_compute.h
+ * @brief       This file contains arm_compute library related classes
+ * @ingroup     COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_ARM_COMPUTE_H__
+#define __INTERNAL_ARM_COMPUTE_H__
+
+#include <arm_compute/core/ITensor.h>
+#include <arm_compute/runtime/CL/CLTensor.h>
+#include <arm_compute/runtime/Tensor.h>
+
+namespace internal
+{
+namespace arm_compute
+{
+namespace operand
+{
+
+/**
+ * @brief Class to access the tensor object
+ */
+class Object
+{
+public:
+ Object() = default;
+
+public:
+ Object(const std::shared_ptr<::arm_compute::ITensor> &tensor) : _tensor{tensor}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get the tensor pointer
+ * @return The tensor pointer
+ */
+ ::arm_compute::ITensor *ptr(void) const { return _tensor.get(); }
+
+private:
+ std::shared_ptr<::arm_compute::ITensor> _tensor;
+
+public:
+ /**
+ * @brief Access the tensor object and run the given function
+ : @param[in] fn The actual behavior when accessing the tensor object
+ * @return N/A
+ */
+ void access(const std::function<void(::arm_compute::ITensor &tensor)> &fn) const;
+};
+
+} // namespace operand
+} // namepsace arm_compute
+} // namespace internal
+
+#include "internal/Model.h"
+
+#include <map>
+
+namespace internal
+{
+namespace arm_compute
+{
+namespace operand
+{
+
+/**
+ * @brief Class to manage Object instances
+ */
+class Context
+{
+public:
+ /**
+ * @brief Set index and tensor pair
+ * @param[in] ind The operand index
+ * @param[in] tensor The tensor object
+ * @return This object reference
+ */
+ Context &set(const ::internal::tflite::operand::Index &ind,
+ const std::shared_ptr<::arm_compute::ITensor> &tensor);
+
+public:
+ /**
+ * @brief Check if the tensor for given index is exist
+ * @param[in] ind The operand Index
+ * @return @c true if the entry for ind is exist, otherwise @c false
+ */
+ bool exist(const ::internal::tflite::operand::Index &ind) const
+ {
+ return _objects.find(ind.asInt()) != _objects.end();
+ }
+
+public:
+ /**
+ * @brief Lookup the tensor with the given index
+ * @param[in] ind The index as the key
+ * @return The object const reference
+ */
+ const Object &at(const ::internal::tflite::operand::Index &ind) const
+ {
+ return _objects.at(ind.asInt());
+ }
+
+ /**
+ * @brief Lookup the tensor with the given index
+ * @param[in] ind The index as the key
+ * @return The object reference
+ */
+ Object &at(const ::internal::tflite::operand::Index &ind) { return _objects.at(ind.asInt()); }
+
+private:
+ std::map<int, Object> _objects;
+};
+
+} // namespace operand
+} // namepsace arm_compute
+} // namespace internal
+
+#include <arm_compute/runtime/IFunction.h>
+
+namespace internal
+{
+namespace arm_compute
+{
+namespace op
+{
+
+/**
+ * @brief Class to wrap IFunction
+ */
+class Step
+{
+public:
+ /**
+ * @brief Construct a Step object
+ * @param[in] func The compiled code to be executed
+ */
+ Step(std::unique_ptr<::arm_compute::IFunction> &&func) : _func{std::move(func)}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Run _func
+ * @return N/A
+ */
+ void run(void) const { _func->run(); }
+
+public:
+ /**
+ * @brief Get member @c _name
+ * @return The name as const reference
+ */
+ const std::string &name(void) const { return _name; }
+ /**
+ * @brief Get member @c _name
+ * @return The name as reference
+ */
+ std::string &name(void) { return _name; }
+
+private:
+ std::string _name;
+ std::unique_ptr<::arm_compute::IFunction> _func;
+#ifdef TFLITE_PROFILING_ENABLED
+public:
+ /**
+ * @brief Get member @c _op_index
+ * @return The operation index as value
+ */
+ int op_idx() const { return _op_idx; }
+ /**
+ * @brief Get member @c _op_index
+ * @return The operation index as reference
+ */
+ int &op_idx() { return _op_idx; }
+private:
+ int _op_idx;
+#endif
+};
+
+} // namespace op
+} // namepsace arm_compute
+} // namespace internal
+
+namespace internal
+{
+namespace arm_compute
+{
+namespace op
+{
+
+/**
+ * @brief Class managing compiled operation code Sequence
+ */
+class Sequence
+{
+public:
+ /**
+ * @brief Get size of sequence
+ * @return Number of sequence steps
+ */
+ uint32_t size(void) const { return _functions.size(); }
+
+public:
+ /**
+ * @brief Append a Function to the sequence
+ * @param[in] func Function to be appended
+ * @return This object reference
+ */
+ Sequence &append(std::unique_ptr<::arm_compute::IFunction> &&func)
+ {
+ _functions.emplace_back(std::move(func));
+ return (*this);
+ }
+
+public:
+ /**
+ * @brief Get the step entry on the index @c n
+ * @param[in] n The index
+ * @return The step object as reference
+ */
+ Step &at(uint32_t n) { return _functions.at(n); }
+ /**
+ * @brief Get the step entry on the index @c n
+ * @param[in] n The index
+ * @return The step object as const reference
+ */
+ const Step &at(uint32_t n) const { return _functions.at(n); }
+
+private:
+ // TODO Rename _functions as _steps
+ std::vector<Step> _functions;
+};
+
+} // namespace op
+} // namepsace arm_compute
+} // namespace internal
+
+namespace internal
+{
+namespace arm_compute
+{
+
+/**
+ * @brief Class to manage compiled operation sequence
+ */
+class Plan
+{
+public:
+ /**
+ * @brief Construct a Plan object
+ * @param[in] model Model that we want to compile
+ */
+ Plan(const std::shared_ptr<const ::internal::tflite::Model> &model) : _model(model)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get the model object
+ * @return The model object as const reference
+ */
+ const ::internal::tflite::Model &model(void) const { return *_model; }
+
+public:
+ /**
+ * @brief Get operand context
+ * @return The operand context as reference
+ */
+ operand::Context &operands(void) { return _operands; }
+ /**
+ * @brief Get operand context
+ * @return The operand context as const reference
+ */
+ const operand::Context &operands(void) const { return _operands; }
+
+public:
+ /**
+ * @brief Get operation sequence
+ * @return The operation sequence as reference
+ */
+ op::Sequence &operations(void) { return _ops; }
+ /**
+ * @brief Get operation sequence
+ * @return The operation sequence as const reference
+ */
+ const op::Sequence &operations(void) const { return _ops; }
+
+private:
+ std::shared_ptr<const ::internal::tflite::Model> _model;
+ operand::Context _operands;
+ op::Sequence _ops;
+};
+
+} // namepsace arm_compute
+} // namespace internal
+
+#include <arm_compute/core/ITensor.h>
+
+namespace internal
+{
+namespace arm_compute
+{
+
+/**
+ * @brief Check if this runtime runs on GPU or NEON
+ * @return @c true if GPU mode, otherwise @c false
+ */
+bool isGpuMode();
+
+#define CAST_CL(tensor) static_cast<::arm_compute::CLTensor *>(tensor)
+#define CAST_NE(tensor) static_cast<::arm_compute::Tensor *>(tensor)
+
+} // namepsace arm_compute
+} // namespace internal
+
+#endif // __INTERNAL_ARM_COMPUTE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute/Cast.cc b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/Cast.cc
new file mode 100644
index 000000000..1a5c735ee
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/Cast.cc
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/arm_compute/Cast.h"
+
+#include "internal/Swizzle.h"
+
+::arm_compute::Coordinates getARMComputeAxises(uint32_t rank)
+{
+ ::arm_compute::Coordinates res{};
+
+ res.set_num_dimensions(rank);
+
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ res.set(axis, ToARMComputeAxis(rank, axis).value());
+ }
+
+ return res;
+}
+
+::arm_compute::Coordinates asARMComputeCoordinates(const ::arm_compute::Coordinates &runtime_coord,
+ const ::arm_compute::Coordinates &axises)
+{
+ ::arm_compute::Coordinates id{};
+ assert(runtime_coord.num_dimensions() == axises.num_dimensions());
+ for (size_t i = 0; i < runtime_coord.num_dimensions(); ++i)
+ {
+ id.set(axises[i], runtime_coord[i]);
+ }
+ return id;
+}
+
+// Restructure runtime_permutationVector to ACL_permutationVector
+::arm_compute::PermutationVector getARMComputePermutationVector(uint32_t rank,
+ const int32_t *runtime_pv)
+{
+ // rank upto 4 is supported
+ assert(rank <= 4);
+ assert(runtime_pv != nullptr);
+
+ int new_pv[4] = {0};
+ ::arm_compute::Coordinates axises = getARMComputeAxises(rank);
+
+ for (uint32_t i = 0; i < rank; ++i)
+ {
+ new_pv[axises[i]] = ToARMComputeAxis(rank, runtime_pv[i]).value();
+ }
+
+ ::arm_compute::PermutationVector ACL_PV =
+ ::arm_compute::PermutationVector{new_pv[0], new_pv[1], new_pv[2], new_pv[3]};
+ ACL_PV.set_num_dimensions(rank);
+
+ return ACL_PV;
+}
+
+::arm_compute::TensorShape asTensorShape(const internal::tflite::operand::Shape &shape,
+ bool apply_dim_correction)
+{
+ const uint32_t rank = shape.rank();
+
+ ::arm_compute::TensorShape res{};
+
+ res.set_num_dimensions(rank);
+
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ // NOTE In some cases, in incorrect dimensions is required.
+ // For example, intput_size is 1 in LSTM. The input-to-input weights([num_units, input_size]) of
+ // LSTM is used as the weight of the FullyConnected.
+ // The FullyConnected's weight must be greater or equal than 2-dimensions.
+ // However, if the dimension correction is applied to input_to_input_weights with input_size
+ // equal to 1, it will be changed to 1-D.
+ // So input_to_input_weights is not used by the weight of FullyConnected.
+ res.set(ToARMComputeAxis(rank, axis).value(), shape.dim(axis), apply_dim_correction);
+ }
+
+ return res;
+}
+
+::arm_compute::DataType asDataType(const int32_t type)
+{
+ switch (type)
+ {
+ case ANEURALNETWORKS_FLOAT32:
+ case ANEURALNETWORKS_TENSOR_FLOAT32:
+ return ::arm_compute::DataType::F32;
+ case ANEURALNETWORKS_INT32:
+ case ANEURALNETWORKS_TENSOR_INT32:
+ return ::arm_compute::DataType::S32;
+ case ANEURALNETWORKS_UINT32:
+ return ::arm_compute::DataType::U32;
+ case ANEURALNETWORKS_TENSOR_QUANT8_ASYMM:
+ return ::arm_compute::DataType::QASYMM8;
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+::arm_compute::ActivationLayerInfo asActivationInfo(FuseCode code)
+{
+ switch (code)
+ {
+ case ANEURALNETWORKS_FUSED_NONE:
+ return ::arm_compute::ActivationLayerInfo{};
+ case ANEURALNETWORKS_FUSED_RELU:
+ return ::arm_compute::ActivationLayerInfo{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::RELU};
+ case ANEURALNETWORKS_FUSED_RELU1:
+ return ::arm_compute::ActivationLayerInfo{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 1.0f, -1.0f};
+ case ANEURALNETWORKS_FUSED_RELU6:
+ return ::arm_compute::ActivationLayerInfo{
+ ::arm_compute::ActivationLayerInfo::ActivationFunction::LU_BOUNDED_RELU, 6.0f, 0.0f};
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+::arm_compute::QuantizationInfo asQuantizationInfo(const float scale, const int32_t offset)
+{
+ return ::arm_compute::QuantizationInfo(scale, offset);
+}
+
+::arm_compute::TensorInfo asTensorInfo(const ::arm_compute::TensorShape &shape, const int32_t type,
+ const float scale, const int32_t zeroPoint)
+{
+ return ::arm_compute::TensorInfo(shape, 1, asDataType(type),
+ asQuantizationInfo(scale, zeroPoint));
+}
+
+::arm_compute::TensorInfo asTensorInfo(const ::arm_compute::TensorShape &shape,
+ const ::arm_compute::DataType &type, const float scale,
+ const int32_t zeroPoint)
+{
+ return ::arm_compute::TensorInfo(shape, 1, type, asQuantizationInfo(scale, zeroPoint));
+}
diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute/Cast.h b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/Cast.h
new file mode 100644
index 000000000..211a6ac87
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/Cast.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Cast.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines casting functions from internal object to arm compute object
+ */
+#ifndef __ARM_COMPUTE_CAST_H__
+#define __ARM_COMPUTE_CAST_H__
+
+#include <arm_compute/core/Coordinates.h>
+#include <arm_compute/core/TensorInfo.h>
+#include <arm_compute/core/TensorShape.h>
+#include <arm_compute/core/Types.h>
+
+#include <NeuralNetworks.h>
+
+#include "internal/Model.h"
+
+/**
+ * @brief Generate arm compute coordinate object from rank
+ * @param[in] rank Rank number
+ * @return Coordinate object
+ */
+::arm_compute::Coordinates getARMComputeAxises(uint32_t rank);
+
+/**
+ * @brief Generate arm compute coordinate object from runtime coordinate object
+ * @param[in] runtime_coord Runtime coordinates object
+ * @param[in] axises Coordinates for axises to map runtime-coordinates to
+ * arm_compute-coordinates
+ * @return Arm_compute coordinate object
+ */
+::arm_compute::Coordinates asARMComputeCoordinates(const ::arm_compute::Coordinates &runtime_coord,
+ const ::arm_compute::Coordinates &axises);
+
+/**
+* @brief Generate arm compute permutation vector from runtime permutation vector
+* @param[in] rank Rank number supported upto 4
+* @param[in] runtime_pv Integer array for runtime permutation vector
+* @return Permutation vector of arm compute
+*/
+::arm_compute::PermutationVector getARMComputePermutationVector(uint32_t rank,
+ const int32_t *runtime_pv);
+/**
+ * @brief Cast from shape of internal to arm compute
+ * @param[in] shape Internal shape object
+ * @param[in] apply_dim_correction Flag to state whether apply dimension correction after setting
+ * one dimension in arm compute
+ * @return TensorShape object of arm compute
+ */
+::arm_compute::TensorShape asTensorShape(const internal::tflite::operand::Shape &shape,
+ bool apply_dim_correction = true);
+
+/**
+ * @brief Cast from data type enum of NNAPI to arm compute
+ * @param[in] type NNAPI data type
+ * @return Data type of arm compute
+ */
+::arm_compute::DataType asDataType(const int32_t type);
+
+/**
+ * @brief Cast from NNAPI activation type enum to activation object of arm compute
+ * @param[in] code NNAPI activation type
+ * @return ActivationLayerInfo object of arm compute
+ */
+::arm_compute::ActivationLayerInfo asActivationInfo(FuseCode code);
+
+/**
+ * @brief Generate quantization info object of arm compute
+ * @param[in] scale Scale of quantization
+ * @param[in] offset Offset of quantization
+ * @return QuantizationInfo object of arm compute
+ */
+::arm_compute::QuantizationInfo asQuantizationInfo(const float scale, const int32_t offset);
+
+/**
+ * @brief Cast from internal tensor info to tensor info object of arm compute
+ * @param[in] shape Tensor shape
+ * @param[in] type Tensor type
+ * @param[in] scale Scale of tensor quantization
+ * @param[in] zeroPoint Zeropoint of tensor quantization
+ * @return TensorInfo object of arm compute
+ */
+::arm_compute::TensorInfo asTensorInfo(const ::arm_compute::TensorShape &shape, const int32_t type,
+ const float scale = 0.0f, const int32_t zeroPoint = 0);
+
+/**
+ * @brief Cast from internal tensor info to tensor info object of arm compute
+ * @param[in] shape Tensor shape
+ * @param[in] type Tensor type of arm compute
+ * @param[in] scale Scale of tensor quantization
+ * @param[in] zeroPoint Zeropoint of tensor quantization
+ * @return TensorInfo object of arm compute
+ */
+::arm_compute::TensorInfo asTensorInfo(const ::arm_compute::TensorShape &shape,
+ const ::arm_compute::DataType &type, const float scale,
+ const int32_t zeroPoint);
+
+/**
+ * @brief Set value to arm compute tensor with casting
+ * @param[in] value Value to set
+ * @param[out] to Target tensor of arm compute
+ * @param[in] id Position of element
+ * @return N/A
+ */
+template <typename FromT>
+void copyCast(const FromT value, ::arm_compute::ITensor *to, const ::arm_compute::Coordinates &id)
+{
+ switch (to->info()->data_type())
+ {
+ case ::arm_compute::DataType::F32:
+ {
+ *reinterpret_cast<float *>(to->ptr_to_element(id)) = static_cast<float>(value);
+ break;
+ }
+ case ::arm_compute::DataType::S32:
+ {
+ *reinterpret_cast<int32_t *>(to->ptr_to_element(id)) = static_cast<int32_t>(value);
+ break;
+ }
+ case ::arm_compute::DataType::U32:
+ {
+ *reinterpret_cast<uint32_t *>(to->ptr_to_element(id)) = static_cast<uint32_t>(value);
+ break;
+ }
+ case ::arm_compute::DataType::QASYMM8:
+ {
+ float realValue = static_cast<float>(value);
+ // NOTE We haven't known the policy of rounding for quantization.
+ // So this is set to a temporary value.
+ *(to->ptr_to_element(id)) = to->info()->quantization_info().quantize(
+ realValue, ::arm_compute::RoundingPolicy::TO_ZERO);
+ break;
+ }
+ default:
+ throw std::runtime_error("Not supported, yet");
+ break;
+ }
+}
+
+#endif // __ARM_COMPUTE_CAST_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute/feature/View.h b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/feature/View.h
new file mode 100644
index 000000000..c989ef4c2
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/feature/View.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file View.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::arm_compute::feature::View class
+ */
+#ifndef __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__
+#define __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__
+
+#include "misc/feature/Reader.h"
+
+#include <arm_compute/core/ITensor.h>
+
+namespace internal
+{
+namespace arm_compute
+{
+namespace feature
+{
+
+/**
+ * @brief Class to access feature's element
+ */
+template <typename T> class View final : public nnfw::misc::feature::Reader<T>
+{
+public:
+ /**
+ * @brief Construct a new View object
+ * @param[in] tensor Feature to support access
+ */
+ View(::arm_compute::ITensor *tensor) : _tensor{tensor}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get value of element in 3D feature using channel, row and column
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Value of element
+ */
+ T at(uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ const auto offset = feature_index_to_byte_offset(ch, row, col);
+
+ T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset);
+
+ return *ptr;
+ }
+
+ /**
+ * @brief Get value of element in 4D feature using batch, channel, row and column
+ * @param[in] batch Batch index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Value of element
+ */
+ T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ const auto offset = feature_index_to_byte_offset(batch, ch, row, col);
+
+ T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset);
+
+ return *ptr;
+ }
+
+public:
+ /**
+ * @brief Get reference of element in 3D feature using channel, row and column
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Reference of element
+ */
+ T &at(uint32_t ch, uint32_t row, uint32_t col)
+ {
+ const auto offset = feature_index_to_byte_offset(ch, row, col);
+
+ T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset);
+
+ return *ptr;
+ }
+
+ /**
+ * @brief Get reference of element in 4D feature using batch, channel, row and column
+ * @param[in] batch Batch index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Reference of element
+ */
+ T &at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col)
+ {
+ const auto offset = feature_index_to_byte_offset(batch, ch, row, col);
+
+ T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset);
+
+ return *ptr;
+ }
+
+private:
+ /**
+ * @brief Get offset of element in 3D feature
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Offset of element
+ */
+ size_t feature_index_to_byte_offset(uint32_t ch, uint32_t row, uint32_t col) const
+ {
+ // ARM Compute uses CHW ordering
+ return _tensor->info()->offset_element_in_bytes(::arm_compute::Coordinates{col, row, ch});
+ }
+
+ /**
+ * @brief Get offset of element in 4D feature
+ * @param[in] batch Batch index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Offset of element
+ */
+ size_t feature_index_to_byte_offset(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const
+ {
+ // ARM Compute uses CHW ordering
+ return _tensor->info()->offset_element_in_bytes(
+ ::arm_compute::Coordinates{col, row, ch, batch});
+ }
+
+private:
+ ::arm_compute::ITensor *_tensor;
+};
+
+} // namespace feature
+} // namespace arm_compute
+} // namespace internal
+
+#endif // __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute/kernel/View.h b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/kernel/View.h
new file mode 100644
index 000000000..399cdf913
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/kernel/View.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file View.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internel::arm_compute::kernel::View class
+ */
+#ifndef __INTERNAL_ARM_COMPUTE_KERNEL_VIEW_H__
+#define __INTERNAL_ARM_COMPUTE_KERNEL_VIEW_H__
+
+#include "misc/kernel/Shape.h"
+#include "misc/kernel/Reader.h"
+
+#include <arm_compute/core/ITensor.h>
+
+namespace internal
+{
+namespace arm_compute
+{
+namespace kernel
+{
+
+/**
+ * @brief Class to access kernel's element
+ */
+template <typename T> class View final : public nnfw::misc::kernel::Reader<T>
+{
+public:
+ /**
+ * @brief Construct a new View object
+ * @param[in] tensor Kernel to support access
+ */
+ View(::arm_compute::ITensor *tensor) : _tensor{tensor}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get value of element in kernel
+ * @param[in] nth Kernel index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Value of element
+ */
+ T at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ const auto offset = kernel_index_to_byte_offset(nth, ch, row, col);
+
+ T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset);
+
+ return *ptr;
+ }
+
+public:
+ /**
+ * @brief Get reference of element in kernel
+ * @param[in] nth Kernel index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Reference of element
+ */
+ T &at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col)
+ {
+ const auto offset = kernel_index_to_byte_offset(nth, ch, row, col);
+
+ T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset);
+
+ return *ptr;
+ }
+
+private:
+ /**
+ * @brief Get offset of element in kernel
+ * @param[in] nth Kernel index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Offset of element
+ */
+ size_t kernel_index_to_byte_offset(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const
+ {
+ return _tensor->info()->offset_element_in_bytes(::arm_compute::Coordinates{col, row, ch, nth});
+ }
+
+private:
+ ::arm_compute::ITensor *_tensor;
+};
+
+} // namespace kernel
+} // namespace arm_compute
+} // namespace internal
+
+#endif // __INTERNAL_ARM_COMPUTE_FEATURE_VIEW_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute/matrix/View.h b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/matrix/View.h
new file mode 100644
index 000000000..305fff729
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/matrix/View.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file View.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::arm_compute::matrix::View class
+ */
+#ifndef __INTERNAL_ARM_COMPUTE_MATRIX_VIEW_H__
+#define __INTERNAL_ARM_COMPUTE_MATRIX_VIEW_H__
+
+#include "misc/matrix/Shape.h"
+#include "misc/matrix/Reader.h"
+
+#include <arm_compute/core/ITensor.h>
+
+namespace internal
+{
+namespace arm_compute
+{
+namespace matrix
+{
+
+/**
+ * @brief Class to access matrix's element
+ */
+template <typename T> class View final : public nnfw::misc::matrix::Reader<T>
+{
+public:
+ /**
+ * @brief Construct a new View object
+ * @param[in] tensor Matrix to support access
+ */
+ View(::arm_compute::ITensor *tensor) : _tensor{tensor}
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Get value of element in matrix
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Value of element
+ */
+ T at(uint32_t row, uint32_t col) const override
+ {
+ const auto offset = matrix_index_to_byte_offset(row, col);
+
+ T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset);
+
+ return *ptr;
+ }
+
+public:
+ /**
+ * @brief Get reference of element in matrix
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Refence of element
+ */
+ T &at(uint32_t row, uint32_t col)
+ {
+ const auto offset = matrix_index_to_byte_offset(row, col);
+
+ T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset);
+
+ return *ptr;
+ }
+
+private:
+ /**
+ * @brief Get offset of element in matrix
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Offset of element
+ */
+ size_t matrix_index_to_byte_offset(uint32_t row, uint32_t col) const
+ {
+ return _tensor->info()->offset_element_in_bytes(::arm_compute::Coordinates{col, row});
+ }
+
+private:
+ ::arm_compute::ITensor *_tensor;
+};
+
+} // namespace matrix
+} // namespace arm_compute
+} // namespace internal
+
+#endif // __INTERNAL_ARM_COMPUTE_MATRIX_VIEW_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/arm_compute/tensor/View.h b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/tensor/View.h
new file mode 100644
index 000000000..372bd682d
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/arm_compute/tensor/View.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file View.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::arm_compute::tensor::View class
+ */
+#ifndef __INTERNAL_ARM_COMPUTE_TENSOR_VIEW_H__
+#define __INTERNAL_ARM_COMPUTE_TENSOR_VIEW_H__
+
+#include "misc/tensor/Shape.h"
+#include "misc/tensor/Index.h"
+
+#include <arm_compute/core/ITensor.h>
+
+namespace internal
+{
+namespace arm_compute
+{
+namespace tensor
+{
+
+/**
+ * @brief Class to access tensor's element
+ */
+template <typename T> class View
+{
+public:
+ /**
+ * @brief Construct a new View object
+ * @param[in] tensor Tensor to support access
+ */
+ View(::arm_compute::ITensor *tensor) : _tensor{tensor}
+ {
+ // DO NOTHING
+ }
+
+private:
+ /**
+ * @brief Get offset of element in tensor
+ * @param[in] index Index of element
+ * @return Offset of element
+ */
+ uint32_t byte_offset_of(const nnfw::misc::tensor::Index &index) const
+ {
+ // NOTE index.rank() >= _tensor->info()->num_dimensions() should hold here
+ const uint32_t rank = index.rank();
+
+ ::arm_compute::Coordinates coordinates;
+
+ coordinates.set_num_dimensions(rank);
+
+ for (uint32_t axis = 0; axis < rank; ++axis)
+ {
+ coordinates[axis] = index.at(axis);
+ }
+
+ return _tensor->info()->offset_element_in_bytes(coordinates);
+ }
+
+public:
+ /**
+ * @brief Get value of element in tensor
+ * @param[in] index Index of element
+ * @return Value of element
+ */
+ T at(const nnfw::misc::tensor::Index &index) const
+ {
+ const auto offset = byte_offset_of(index);
+
+ T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset);
+
+ return *ptr;
+ }
+
+ /**
+ * @brief Get reference of element in tensor
+ * @param[in] index Index of element
+ * @return Reference of element
+ */
+ T &at(const nnfw::misc::tensor::Index &index)
+ {
+ const auto offset = byte_offset_of(index);
+
+ T *ptr = reinterpret_cast<T *>(_tensor->buffer() + offset);
+
+ return *ptr;
+ }
+
+private:
+ ::arm_compute::ITensor *_tensor;
+};
+
+} // namespace tensor
+} // namespace arm_compute
+} // namespace internal
+
+#endif // __INTERNAL_ARM_COMPUTE_TENSOR_VIEW_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/Reader.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/Reader.h
new file mode 100644
index 000000000..ac25692a1
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/Reader.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Reader.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::nnapi::feature::Reader
+ */
+#ifndef __INTERNAL_NNAPI_FEATURE_READER_H__
+#define __INTERNAL_NNAPI_FEATURE_READER_H__
+
+#include "internal/nnapi/feature/Utils.h"
+
+#include "misc/feature/Reader.h"
+
+namespace internal
+{
+namespace nnapi
+{
+namespace feature
+{
+
+/**
+ * @brief Class to support reading element in feature(3D, 4D)
+ */
+template <typename T> class Reader final : public nnfw::misc::feature::Reader<T>
+{
+public:
+ /**
+ * @brief Construct a new Reader object
+ * @param[in] shape Shape of feature
+ * @param[in] ptr Pointer to feature data
+ * @param[in] len Size of tensor (byte)
+ */
+ // NOTE The parameter len denotes the number of bytes.
+ Reader(const ::nnfw::misc::feature::Shape &shape, const T *ptr, size_t len)
+ : _shape{shape}, _ptr{ptr}
+ {
+ assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len);
+ }
+
+public:
+ /**
+ * @brief Get shape of feature
+ * @return Shape of feature
+ */
+ const nnfw::misc::feature::Shape &shape(void) const { return _shape; }
+
+public:
+ /**
+ * @brief Get value of element using channel, row, and column index for 3D feature
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Value of element
+ */
+ T at(uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ uint32_t index = index_of(_shape, ch, row, col);
+
+ const auto arr = reinterpret_cast<const T *>(_ptr);
+
+ return arr[index];
+ }
+
+ /**
+ * @brief Get value of element using batch, channel, row, and column index for 4D feature
+ * @param[in] batch Batch index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Value of element
+ */
+ T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ uint32_t index = index_of(_shape, batch, ch, row, col);
+
+ return _ptr[index];
+ }
+
+private:
+ nnfw::misc::feature::Shape _shape;
+
+private:
+ const T *_ptr;
+};
+
+} // namespace feature
+} // namespace nnapi
+} // namespace internal
+
+#endif // __INTERNAL_NNAPI_FEATURE_READER_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/Utils.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/Utils.h
new file mode 100644
index 000000000..ee59d217e
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/Utils.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Utils.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines utility functions used in internal::nnapi::feature namespace
+ */
+#ifndef __INTERNAL_NNAPI_FEATURE_UTILS_H__
+#define __INTERNAL_NNAPI_FEATURE_UTILS_H__
+
+#include "misc/feature/Shape.h"
+
+namespace internal
+{
+namespace nnapi
+{
+namespace feature
+{
+
+/**
+ * @brief Get position of element using channel, row, and column for 3D feature
+ * @param[in] shape Shape of feature
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Position of element
+ */
+inline uint32_t index_of(const ::nnfw::misc::feature::Shape &shape, uint32_t ch, uint32_t row,
+ uint32_t col)
+{
+ uint32_t res = 0;
+
+ // NNAPI uses NHWC ordering
+ res += row * shape.W * shape.C;
+ res += col * shape.C;
+ res += ch;
+
+ return res;
+}
+
+/**
+ * @brief Get position of element using batch, channel, row, and column for 4D feature
+ * @param[in] shape Shape of feature
+ * @param[in] batch Batch index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Position of element
+ */
+inline uint32_t index_of(const ::nnfw::misc::feature::Shape &shape, uint32_t batch, uint32_t ch,
+ uint32_t row, uint32_t col)
+{
+ uint32_t res = 0;
+
+ // NNAPI uses NHWC ordering
+ res += batch * shape.H * shape.W * shape.C;
+ res += row * shape.W * shape.C;
+ res += col * shape.C;
+ res += ch;
+
+ return res;
+}
+
+} // namespace feature
+} // namespace nnapi
+} // namespace internal
+
+#endif // __INTERNAL_NNAPI_FEATURE_UTILS_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/View.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/View.h
new file mode 100644
index 000000000..965e42f1c
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/feature/View.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file View.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::nnapi::feature::View class
+ */
+#ifndef __INTERNAL_NNAPI_FEATURE_VIEW_H__
+#define __INTERNAL_NNAPI_FEATURE_VIEW_H__
+
+#include "internal/nnapi/feature/Utils.h"
+
+#include "misc/feature/Reader.h"
+
+namespace internal
+{
+namespace nnapi
+{
+namespace feature
+{
+
+/**
+ * @brief Class to access feature's element information using index
+ */
+template <typename T> class View final : public nnfw::misc::feature::Reader<T>
+{
+public:
+ /**
+ * @brief Construct a new View object
+ * @param[in] shape Shape of feature
+ * @param[in] ptr Pointer to feature data
+ * @param[in] len Size of feature (byte)
+ * @return
+ */
+ // NOTE The parameter len denotes the number of bytes.
+ View(const ::nnfw::misc::feature::Shape &shape, T *ptr, size_t len) : _shape{shape}, _ptr{ptr}
+ {
+ assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len);
+ }
+
+public:
+ /**
+ * @brief Get shape of feature
+ * @return Shape of feature
+ */
+ const nnfw::misc::feature::Shape &shape(void) const { return _shape; }
+
+public:
+ /**
+ * @brief Get value of element in 3D feature using channel, row, and column index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Value of element
+ */
+ T at(uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ uint32_t index = index_of(_shape, ch, row, col);
+
+ return _ptr[index];
+ }
+
+ /**
+ * @brief Get value of element in 4D feature using batch, channel, row and column index
+ * @param[in] batch Batch index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Value of element
+ */
+ T at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ uint32_t index = index_of(_shape, batch, ch, row, col);
+
+ return _ptr[index];
+ }
+
+ /**
+ * @brief Get reference of element in 3D feature using channel, row, and column index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Reference of element
+ */
+ T &at(uint32_t ch, uint32_t row, uint32_t col)
+ {
+ uint32_t index = index_of(_shape, ch, row, col);
+
+ return _ptr[index];
+ }
+
+ /**
+ * @brief Get reference of element in 4D feature using batch, channel, row and column index
+ * @param[in] batch Batch index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Reference of element
+ */
+ T &at(uint32_t batch, uint32_t ch, uint32_t row, uint32_t col)
+ {
+ uint32_t index = index_of(_shape, batch, ch, row, col);
+
+ return _ptr[index];
+ }
+
+private:
+ nnfw::misc::feature::Shape _shape;
+
+private:
+ T *_ptr;
+};
+
+} // namespace feature
+} // namespace nnapi
+} // namespace internal
+
+#endif // __INTERNAL_NNAPI_FEATURE_VIEW_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/kernel/Reader.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/kernel/Reader.h
new file mode 100644
index 000000000..ae964f74c
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/kernel/Reader.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Reader.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::nnapi::kernel::Reader class
+ */
+#ifndef __INTERNAL_NNAPI_KERNEL_READER_H__
+#define __INTERNAL_NNAPI_KERNEL_READER_H__
+
+#include "misc/kernel/Shape.h"
+#include "misc/kernel/Reader.h"
+
+namespace internal
+{
+namespace nnapi
+{
+namespace kernel
+{
+
+/**
+ * @brief Class to support reading element in kernel
+ */
+template <typename T> class Reader final : public nnfw::misc::kernel::Reader<T>
+{
+public:
+ /**
+ * @brief Construct a new Reader object
+ * @param[in] shape Shape of kernel
+ * @param[in] ptr Pointer to kernel data
+ * @param[in] len Size of kernel (byte)
+ */
+ // NOTE The parameter len denotes the number of bytes.
+ Reader(const ::nnfw::misc::kernel::Shape &shape, const T *ptr, size_t len)
+ : _shape{shape}, _ptr{ptr}
+ {
+ assert(shape.N * shape.C * shape.H * shape.W * sizeof(T) == len);
+ }
+
+public:
+ /**
+ * @brief Get shape of kernel
+ * @return Shape of kernel
+ */
+ const nnfw::misc::kernel::Shape &shape(void) const { return _shape; }
+
+public:
+ /**
+ * @brief Get value of element for kernel
+ * @param[in] nth Kernel index
+ * @param[in] ch Channel index
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Value of element
+ */
+ T at(uint32_t nth, uint32_t ch, uint32_t row, uint32_t col) const override
+ {
+ // NNAPI uses NHWC ordering
+ uint32_t index = 0;
+
+ index += nth * _shape.H * _shape.W * _shape.C;
+ index += row * _shape.W * _shape.C;
+ index += col * _shape.C;
+ index += ch;
+
+ return _ptr[index];
+ }
+
+private:
+ nnfw::misc::kernel::Shape _shape;
+
+private:
+ const T *_ptr;
+};
+
+} // namespace kernel
+} // namespace nnapi
+} // namespace internal
+
+#endif // __INTERNAL_NNAPI_KERNEL_READER_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/matrix/Reader.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/matrix/Reader.h
new file mode 100644
index 000000000..f03a4be31
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/matrix/Reader.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Reader.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::nnapi::matrix::Reader class
+ */
+#ifndef __INTERNAL_NNAPI_MATRIX_READER_H__
+#define __INTERNAL_NNAPI_MATRIX_READER_H__
+
+#include "misc/matrix/Shape.h"
+#include "misc/matrix/Reader.h"
+
+namespace internal
+{
+namespace nnapi
+{
+namespace matrix
+{
+
+/**
+ * @brief Class to support reading element in matrix
+ */
+template <typename T> class Reader final : public nnfw::misc::matrix::Reader<T>
+{
+public:
+ /**
+ * @brief Construct a new Reader object
+ * @param[in] shape Shape of matrix
+ * @param[in] ptr Pointer to matrix data
+ * @param[in] len Size of matrix (byte)
+ */
+ // NOTE The parameter len denotes the number of bytes.
+ Reader(const ::nnfw::misc::matrix::Shape &shape, const T *ptr, size_t len)
+ : _shape{shape}, _ptr{ptr}
+ {
+ assert(shape.H * shape.W * sizeof(T) == len);
+ }
+
+public:
+ /**
+ * @brief Get shape of matrix
+ * @return Shape of matrix
+ */
+ const nnfw::misc::matrix::Shape &shape(void) const { return _shape; }
+
+public:
+ /**
+ * @brief Get value of element for matrix
+ * @param[in] row Row index
+ * @param[in] col Column index
+ * @return Value of element
+ */
+ T at(uint32_t row, uint32_t col) const override
+ {
+ // NNAPI uses NHWC ordering
+ uint32_t index = 0;
+
+ index += row * _shape.W;
+ index += col;
+
+ return _ptr[index];
+ }
+
+private:
+ nnfw::misc::matrix::Shape _shape;
+
+private:
+ const T *_ptr;
+};
+
+} // namespace matrix
+} // namespace nnapi
+} // namespace internal
+
+#endif // __INTERNAL_NNAPI_MATRIX_READER_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/ConstView.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/ConstView.h
new file mode 100644
index 000000000..6a3fff646
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/ConstView.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file        ConstView.h
+ * @brief       This file contains ConstView class
+ * @ingroup     COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_NNAPI_TENSOR_CONST_VIEW_H__
+#define __INTERNAL_NNAPI_TENSOR_CONST_VIEW_H__
+
+#include "util/tensor/Shape.h"
+#include "util/tensor/Index.h"
+
+namespace internal
+{
+namespace nnapi
+{
+namespace tensor
+{
+
+/**
+ * @brief Wrapper class to read tensor values
+ * @tparam T The tensor element type
+ */
+template <typename T> class ConstView
+{
+public:
+ /**
+ * @brief Construct a ConstView class
+ * @param[in] shape Tensor shape
+ * @param[in] ptr The base pointer of actual data
+ * @param[in] len The number of bytes
+ */
+ ConstView(const ::nnfw::misc::tensor::Shape &shape, const uint8_t *ptr, size_t len)
+ : _shape{shape}, _ptr{ptr}, _len{len}
+ {
+ // DO NOTHING
+ }
+
+public:
+ const nnfw::misc::tensor::Shape &shape(void) const { return _shape; }
+
+private:
+ // TODO Make this as a helper function, and share it for both View<T> and ConstView<T>
+ /**
+ * @brief Calculate offset for the given tensor index
+ * @param[in] index Tensor index
+ * @return The calculated offset
+ */
+ uint32_t offset_of(const nnfw::misc::tensor::Index &index) const
+ {
+ if (_shape.rank() == 0)
+ {
+ return 0;
+ }
+
+ uint32_t offset = index.at(0);
+
+ // Stride decreases as axis increases in NNAPI
+ for (uint32_t axis = 1; axis < _shape.rank(); ++axis)
+ {
+ offset *= _shape.dim(axis);
+ offset += index.at(axis);
+ }
+
+ return offset;
+ }
+
+public:
+ /**
+ * @brief Get the value on the given index
+ * @param[in] index Flattened tensor index
+ * @return The value on the given index
+ */
+ T at(const nnfw::misc::tensor::Index &index) const
+ {
+ const auto offset = offset_of(index);
+
+ const T *arr = reinterpret_cast<const T *>(_ptr);
+
+ return arr[offset];
+ }
+
+private:
+ const nnfw::misc::tensor::Shape _shape;
+
+private:
+ const uint8_t *const _ptr;
+ const size_t _len;
+};
+
+} // namespace tensor
+} // namespace nnapi
+} // namespace internal
+
+#endif // __INTERNAL_NNAPI_TENSOR_CONST_VIEW_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/Reader.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/Reader.h
new file mode 100644
index 000000000..fc6d490da
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/Reader.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file        Reader.h
+ * @brief       This file contains Reader class
+ * @ingroup     COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_NNAPI_TENSOR_READER_H__
+#define __INTERNAL_NNAPI_TENSOR_READER_H__
+
+#include <vector>
+#include "misc/tensor/Reader.h"
+
+namespace internal
+{
+namespace nnapi
+{
+namespace tensor
+{
+
+/**
+ * @brief Wrapper class to read tensor values
+ * @tparam T The tensor element type
+ */
+template <typename T> class Reader final : public nnfw::misc::tensor::Reader<T>
+{
+public:
+ /**
+ * @brief Construct a Reader class
+ * @param[in] shape Tensor shape
+ * @param[in] ptr The base pointer of actual data
+ * @param[in] len The number of bytes
+ */
+ Reader(const ::nnfw::misc::tensor::Shape &shape, const T *ptr, size_t len)
+ : _shape{shape}, _ptr{ptr}
+ {
+ assert(shape.num_elements() * sizeof(T) == len);
+ initialize();
+ }
+
+public:
+ /**
+ * @brief Get shape object
+ * @return The shape as const reference
+ */
+ const nnfw::misc::tensor::Shape &shape(void) const { return _shape; }
+
+public:
+ /**
+ * @brief Get the value on the given index
+ * @param[in] index_nnapi Flattened tensor index
+ * @return The value on the given index
+ */
+ T at(const nnfw::misc::tensor::Index &index_nnapi) const override
+ {
+ uint32_t offset = 0;
+
+ for (int i = 0; i < _shape.rank(); i++)
+ offset += index_nnapi.at(i) * _stridess.at(i);
+
+ return _ptr[offset];
+ }
+
+private:
+ /**
+ * @brief Initializes @c _stridess
+ * @return N/A
+ * @note Assuming that shape is [d4, .. , d1] and data is stored at a pointer ptr,
+ we need to calculate the offset of index [i4, .. i1] as follows:
+ offset = i4 * (d3 * d2 * d1) +
+ i3 * (d2 * d1) +
+ i2 * (d1) +
+ i1
+ So (d4 * d3 * d2 * d1) or (d3 * d2 * d1) or (d2 * d1) happens whenever offset is
+ calculate. To minimize this repetitive calculation,
+ _stridess[n] contains _spape[n-1]*_spape[n-2]*_spape[0]
+ */
+ void initialize(void)
+ {
+ for (int r = 0; r < _shape.rank(); r++)
+ {
+ int elem_count = 1;
+ for (int k = r + 1; k < _shape.rank(); k++)
+ elem_count *= _shape.dim(k);
+ _stridess.emplace_back(elem_count);
+ }
+ }
+
+private:
+ nnfw::misc::tensor::Shape _shape;
+
+private:
+ const T *_ptr;
+ std::vector<int32_t> _stridess;
+};
+
+} // namespace tensor
+} // namespace nnapi
+} // namespace internal
+
+#endif // __INTERNAL_NNAPI_TENSOR_READER_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/View.h b/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/View.h
new file mode 100644
index 000000000..4766851b9
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/nnapi/tensor/View.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file View.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::nnapi::tensor::View class
+ */
+#ifndef __INTERNAL_NNAPI_TENSOR_VIEW_H__
+#define __INTERNAL_NNAPI_TENSOR_VIEW_H__
+
+#include "misc/tensor/Shape.h"
+#include "misc/tensor/Index.h"
+
+namespace internal
+{
+namespace nnapi
+{
+namespace tensor
+{
+
+/**
+ * @brief Class to access tensor's element information using index
+ */
+template <typename T> class View
+{
+public:
+ /**
+ * @brief Construct a new View object
+ * @param[in] shape Shape of tensor
+ * @param[in] ptr Pointer to tensor data
+ * @param[in] len Size of tensor (byte)
+ */
+ // NOTE The parameter len denotes the number of bytes.
+ View(const ::nnfw::misc::tensor::Shape &shape, T *ptr, size_t len) : _shape{shape}, _ptr{ptr}
+ {
+ assert(shape.num_elements() * sizeof(T) == len);
+ }
+
+public:
+ /**
+ * @brief Get shape of tensor
+ * @return Shape of tensor
+ */
+ const nnfw::misc::tensor::Shape &shape(void) const { return _shape; }
+
+private:
+ /**
+ * @brief Get position of element using index in tensor
+ * @param[in] index Index of element
+ * @return Position of element
+ */
+ uint32_t offset_of(const nnfw::misc::tensor::Index &index) const
+ {
+ if (_shape.rank() == 0)
+ {
+ return 0;
+ }
+
+ uint32_t offset = index.at(0);
+
+ // Stride decreases as axis increases in NNAPI
+ for (uint32_t axis = 1; axis < _shape.rank(); ++axis)
+ {
+ offset *= _shape.dim(axis);
+ offset += index.at(axis);
+ }
+
+ return offset;
+ }
+
+public:
+ /**
+ * @brief Get value of element at index
+ * @param[in] index Index of element
+ * @return Value of element at index
+ */
+ T at(const nnfw::misc::tensor::Index &index) const
+ {
+ const auto offset = offset_of(index);
+
+ return _ptr[offset];
+ }
+
+ /**
+ * @brief Get reference of element at index
+ * @param[in] index Index of element
+ * @return Reference of element at index
+ */
+ T &at(const nnfw::misc::tensor::Index &index)
+ {
+ const auto offset = offset_of(index);
+
+ return _ptr[offset];
+ }
+
+private:
+ nnfw::misc::tensor::Shape _shape;
+
+private:
+ T *_ptr;
+};
+
+} // namespace tensor
+} // namespace nnapi
+} // namespace internal
+
+#endif // __INTERNAL_NNAPI_TENSOR_VIEW_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Abs.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Abs.cc
new file mode 100644
index 000000000..e23a9538c
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Abs.cc
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Abs.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Abs
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Abs
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Abs
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ output_index = outputs[0];
+ input_index = inputs[0];
+}
+
+} // namespace Abs
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Abs.h b/runtime/contrib/pure_arm_compute/src/internal/op/Abs.h
new file mode 100644
index 000000000..0be8b0205
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Abs.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_ABS_H__
+#define __INTERNAL_OP_ABS_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Abs
+{
+
+struct Param
+{
+ int32_t output_index;
+ int32_t input_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Abs
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_ABS_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Add.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Add.cc
new file mode 100644
index 000000000..52803261f
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Add.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Add.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Add
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Add
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Add
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 3 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> LHS Tensor Index
+ // 1 -> RHS Tensor Index
+ // 2 -> Activation Index
+ lhs_index = inputs[0];
+ rhs_index = inputs[1];
+ activation_index = inputs[2];
+}
+
+} // namespace Add
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Add.h b/runtime/contrib/pure_arm_compute/src/internal/op/Add.h
new file mode 100644
index 000000000..a7804a569
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Add.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Add.h
+ * @brief This file contains accept function and params for Add operation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_ADD_H__
+#define __INTERNAL_OP_ADD_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Add
+{
+
+/**
+ * @brief Struct of Add operation's param
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Output format index */
+
+ int32_t lhs_index; /**< Left hand side index */
+ int32_t rhs_index; /**< Right hand side index */
+ int32_t activation_index; /**< Activation index */
+
+ /**
+ * @brief Construct a new Param object for Add as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for Add with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for Add
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for Add with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for Add
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for Add
+ * @return Parameters of Add
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for Add
+ * @param [in] v Node visitor for invoking visit function of Add
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Add
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_ADD_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ArgMax.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ArgMax.cc
new file mode 100644
index 000000000..485430377
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ArgMax.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "internal/op/ArgMax.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ArgMax
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace ArgMax
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ArgMax
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Axis Tensor Index
+ ifm_index = inputs[0];
+ axis_index = inputs[1];
+}
+
+} // namespace ArgMax
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ArgMax.h b/runtime/contrib/pure_arm_compute/src/internal/op/ArgMax.h
new file mode 100644
index 000000000..780af2232
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ArgMax.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_ARGMAX_H__
+#define __INTERNAL_OP_ARGMAX_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ArgMax
+{
+
+struct Param
+{
+ int32_t ofm_index;
+
+ int32_t ifm_index;
+ int32_t axis_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace ArgMax
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_ARGMAX_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/AvgPool2D.cc b/runtime/contrib/pure_arm_compute/src/internal/op/AvgPool2D.cc
new file mode 100644
index 000000000..ae4c9411e
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/AvgPool2D.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/AvgPool2D.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace AvgPool2D
+{
+namespace Explicit
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Explicit
+
+namespace Implicit
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Implicit
+} // namespace AvgPool2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace AvgPool2D
+{
+namespace Explicit
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 10 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> IFM Tensor Index
+ // 1 -> Padding_left index
+ // 2 -> Padding_right index
+ // 3 -> Padding_top index
+ // 4 -> Padding_bottom index
+ // 5 -> Horizontal (over width) Stride Index
+ // 6 -> Vertial (over height) Stride Index
+ // 7 -> Filter Width Index
+ // 8 -> Filter Height Index
+ // 9 -> FuseCode (activation) Index
+ ifm_index = inputs[0];
+ padding_left_index = inputs[1];
+ padding_right_index = inputs[2];
+ padding_top_index = inputs[3];
+ padding_bottom_index = inputs[4];
+ hstride_index = inputs[5];
+ vstride_index = inputs[6];
+ kw_index = inputs[7];
+ kh_index = inputs[8];
+ activation_index = inputs[9];
+}
+
+} // namespace Explicit
+
+namespace Implicit
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 7 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> IFM Tensor Index
+ // 1 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index
+ // 2 -> Horizontal (over width) Stride Index
+ // 3 -> Vertial (over height) Stride Index
+ // 4 -> Filter Width Index
+ // 5 -> Filter Height Index
+ // 6 -> FuseCode (activation) Index
+ ifm_index = inputs[0];
+ padding_index = inputs[1];
+ hstride_index = inputs[2];
+ vstride_index = inputs[3];
+ kw_index = inputs[4];
+ kh_index = inputs[5];
+ activation_index = inputs[6];
+}
+
+} // namespace Implicit
+} // namespace AvgPool2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/AvgPool2D.h b/runtime/contrib/pure_arm_compute/src/internal/op/AvgPool2D.h
new file mode 100644
index 000000000..cf9061ca9
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/AvgPool2D.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file AvgPool2D.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::AvgPool2D Param structs
+ * and internal::tflite::op::AvgPool2D Node classes
+ */
+#ifndef __INTERNAL_OP_AVG_POOL_2D_H__
+#define __INTERNAL_OP_AVG_POOL_2D_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace AvgPool2D
+{
+namespace Explicit
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Index of output feature map */
+
+ int32_t ifm_index; /**< Index of input feature map */
+
+ int32_t kw_index; /**< Index of kernel width */
+ int32_t kh_index; /**< Index of kernel height */
+
+ int32_t hstride_index; /**< Index of horizontal stride */
+ int32_t vstride_index; /**< Index of vertical stride */
+
+ int32_t padding_left_index; /**< Index of padding left */
+ int32_t padding_right_index; /**< Index of padding right */
+ int32_t padding_top_index; /**< Index of padding top */
+ int32_t padding_bottom_index; /**< Index of padding bottom */
+
+ int32_t activation_index; /**< Index of activation */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Explicit
+
+namespace Implicit
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Index of output feature map */
+
+ int32_t ifm_index; /**< Index of input feature map */
+
+ int32_t kw_index; /**< Index of kernel width */
+ int32_t kh_index; /**< Index of kernel height */
+
+ int32_t hstride_index; /**< Index of horizontal stride */
+ int32_t vstride_index; /**< Index of vertical stride */
+
+ int32_t padding_index; /**< Index of padding */
+ int32_t activation_index; /**< Index of activation */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Implicit
+} // namespace AvgPool2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_MAX_POOL_2D_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/BatchToSpaceNd.cc b/runtime/contrib/pure_arm_compute/src/internal/op/BatchToSpaceNd.cc
new file mode 100644
index 000000000..0768039d0
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/BatchToSpaceNd.cc
@@ -0,0 +1,63 @@
+/*Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "internal/op/BatchToSpaceNd.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace BatchToSpaceNd
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace BatchToSpaceNd
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace BatchToSpaceNd
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Block size Index
+ input_index = inputs[0];
+ block_size_index = inputs[1];
+}
+
+} // namespace BatchToSpaceNd
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/BatchToSpaceNd.h b/runtime/contrib/pure_arm_compute/src/internal/op/BatchToSpaceNd.h
new file mode 100644
index 000000000..a514cb44c
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/BatchToSpaceNd.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_BATCHTOSPACE_ND_H__
+#define __INTERNAL_OP_BATCHTOSPACE_ND_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace BatchToSpaceNd
+{
+
+struct Param
+{
+ int32_t output_index;
+
+ int32_t input_index;
+ int32_t block_size_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+} // namespace BatchToSpaceNd
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace BatchToSpaceNd
+{
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace BatchToSpaceNd
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_BATCHTOSPACE_Nd_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Cast.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Cast.cc
new file mode 100644
index 000000000..13f58f137
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Cast.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Cast.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Cast
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Cast
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Cast
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ // 0 -> input Tensor Index
+ input_index = inputs[0];
+}
+
+} // namespace Cast
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Cast.h b/runtime/contrib/pure_arm_compute/src/internal/op/Cast.h
new file mode 100644
index 000000000..8af741a16
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Cast.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Cast.h
+ * @brief This file contains accept function and params for Cast operation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_CAST_H__
+#define __INTERNAL_OP_CAST_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Cast
+{
+
+/**
+ * @brief Struct of Cast operation's param
+ */
+struct Param
+{
+ int32_t output_index; /**< Output index */
+
+ int32_t input_index; /**< Input index */
+
+ /**
+ * @brief Construct a new Param object for Cast as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for Cast with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for Cast
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for Cast with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for Cast
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for Cast
+ * @return Parameters of Cast
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for Cast
+ * @param [in] v Node visitor for invoking visit function of Cast
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Cast
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_Cast_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Concat.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Concat.cc
new file mode 100644
index 000000000..ee1730051
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Concat.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Concat.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Concat
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Concat
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Concat
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // When there are N + 1 inputs, each input should be interpreted as follows:
+ //
+ // [0, N) -> Input tensors
+ // N -> Axis
+ axis_index = inputs[inputCount - 1];
+
+ for (uint32_t n = 0; n < inputCount - 1; ++n)
+ {
+ ifm_indexes.emplace_back(inputs[n]);
+ }
+}
+
+} // namespace Concat
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Concat.h b/runtime/contrib/pure_arm_compute/src/internal/op/Concat.h
new file mode 100644
index 000000000..207f964fb
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Concat.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Concat.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines Concat node
+ */
+
+#ifndef __INTERNAL_OP_CONCAT_H__
+#define __INTERNAL_OP_CONCAT_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+#include <vector>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Concat
+{
+
+/**
+ * @brief Struct to manipulate parameter for Concat operation
+ */
+struct Param
+{
+ int32_t ofm_index; //!< index for output
+
+ std::vector<int32_t> ifm_indexes; //!< index for input
+ int32_t axis_index; //!< index for axis
+
+ /**
+ * @brief Default Constructor
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object
+ * @param[in] inputCount the number of inputs
+ * @param[in] inputs pointer for input data
+ * @param[in] outputCount the number of outputs
+ * @param[in] outputs pointer for input data
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define Concat Operation
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Concat Node object
+ * @param param Parameter for Concat Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Default Destructor
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameter
+ * @return Param reference
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Accept a NodeVisitor so that it can visit this node
+ * @param [in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param; //!< parameter for Concat node
+};
+
+} // namespace Concat
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_CONCAT_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Conv2D.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Conv2D.cc
new file mode 100644
index 000000000..a24d14632
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Conv2D.cc
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Conv2D.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Conv2D
+{
+namespace Explicit
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Explicit
+
+namespace Implicit
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Implicit
+} // namespace Conv2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Conv2D
+{
+namespace Explicit
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 10 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ //
+ // 0 -> IFM Tensor Index
+ // 1 -> Kernel Tensor Index
+ // 2 -> Bias Tensor Index
+ // 3 -> Padding_left index
+ // 4 -> Padding_right index
+ // 5 -> Padding_top index
+ // 6 -> Padding_bottom index
+ // 7 -> Stride (width) Index
+ // 8 -> Stride (height) INdex
+ // 9 -> Activation Index
+ ifm_index = inputs[0];
+ ker_index = inputs[1];
+ bias_index = inputs[2];
+ padding_left_index = inputs[3];
+ padding_right_index = inputs[4];
+ padding_top_index = inputs[5];
+ padding_bottom_index = inputs[6];
+ hstride_index = inputs[7];
+ vstride_index = inputs[8];
+ activation_index = inputs[9];
+}
+
+} // namespace Explicit
+
+namespace Implicit
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 7 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ //
+ // 0 -> IFM Tensor Index
+ // 1 -> Kernel Tensor Index
+ // 2 -> Bias Tensor Index
+ // 3 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index
+ // 4 -> Stride (width) Index
+ // 5 -> Stride (height) INdex
+ // 6 -> Activation Index
+ ifm_index = inputs[0];
+ ker_index = inputs[1];
+ bias_index = inputs[2];
+ padding_index = inputs[3];
+ hstride_index = inputs[4];
+ vstride_index = inputs[5];
+ activation_index = inputs[6];
+}
+
+} // namespace Implicit
+} // namespace Conv2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Conv2D.h b/runtime/contrib/pure_arm_compute/src/internal/op/Conv2D.h
new file mode 100644
index 000000000..de46fbb9c
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Conv2D.h
@@ -0,0 +1,200 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Conv2D.h
+ * @brief This file contains accept function and params for Conv2D operation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_CONV_2D_H__
+#define __INTERNAL_OP_CONV_2D_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Conv2D
+{
+namespace Explicit
+{
+
+/**
+ * @brief Struct of Conv2D(explicit) operation's param
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Output format index */
+
+ int32_t ifm_index; /**< Input format index */
+ int32_t ker_index; /**< Kernel index */
+ int32_t bias_index; /**< Bias index */
+
+ int32_t hstride_index; /**< Horizontal stride index */
+ int32_t vstride_index; /**< Vertical stride index */
+
+ int32_t padding_left_index; /**< Left padding index */
+ int32_t padding_right_index; /**< Right padding index */
+ int32_t padding_top_index; /**< Top padding index */
+ int32_t padding_bottom_index; /**< Bottomd padding index */
+
+ int32_t activation_index; /**< Activation index */
+
+ /**
+ * @brief Construct a new Param object for Conv2D(explicit) as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for Conv2D(explicit) with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for Conv2D(explicit)
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for conv2D(explicit) with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for conv2D(explicit)
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for conv2D(explicit)
+ * @return Parameters of conv2D(explicit)
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for conv2D(explicit)
+ * @param [in] v Node visitor for invoking visit function of conv2D(explicit)
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Explicit
+
+namespace Implicit
+{
+
+/**
+ * @brief Struct of Conv2D(implicit) operation's param
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Output format index */
+
+ int32_t ifm_index; /**< Input format index */
+ int32_t ker_index; /**< Kernel index */
+ int32_t bias_index; /**< Bias index */
+
+ int32_t hstride_index; /**< Horizontal stride index */
+ int32_t vstride_index; /**< Vertical stride index */
+
+ int32_t padding_index; /**< Padding index */
+ int32_t activation_index; /**< Activation index */
+
+ /**
+ * @brief Construct a new Param object for Conv2D(implicit) as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for Conv2D(implicit) with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for Conv2D(implicit)
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for conv2D(implicit) with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for conv2D(implicit)
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for conv2D(implicit)
+ * @return Parameters of conv2D(implicit)
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for conv2D(implicit)
+ * @param [in] v Node visitor for invoking visit function of conv2D(implicit)
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Implicit
+} // namespace Conv2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_CONV_2D_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/DepthToSpace.cc b/runtime/contrib/pure_arm_compute/src/internal/op/DepthToSpace.cc
new file mode 100644
index 000000000..db164a148
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/DepthToSpace.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/DepthToSpace.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace DepthToSpace
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace DepthToSpace
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace DepthToSpace
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Block size Index
+ input_index = inputs[0];
+ block_size_index = inputs[1];
+}
+
+} // namespace DepthToSpace
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/DepthToSpace.h b/runtime/contrib/pure_arm_compute/src/internal/op/DepthToSpace.h
new file mode 100644
index 000000000..dd4c5c914
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/DepthToSpace.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_DEPTHTOSPACE_H__
+#define __INTERNAL_OP_DEPTHTOSPACE_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace DepthToSpace
+{
+
+struct Param
+{
+ int32_t output_index;
+
+ int32_t input_index;
+ int32_t block_size_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace DepthToSpace
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_DEPTHTOSPACE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/DepthwiseConv2D.cc b/runtime/contrib/pure_arm_compute/src/internal/op/DepthwiseConv2D.cc
new file mode 100644
index 000000000..f4d1ca3c5
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/DepthwiseConv2D.cc
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/DepthwiseConv2D.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace DepthwiseConv2D
+{
+namespace Explicit
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Explicit
+
+namespace Implicit
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Implicit
+} // namespace DepthwiseConv2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace DepthwiseConv2D
+{
+namespace Explicit
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 11 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> IFM Tensor Index
+ // 1 -> Kernel Tensor Index
+ // 2 -> Bias Tensor Index
+ // 3 -> Padding_left index
+ // 4 -> Padding_right index
+ // 5 -> Padding_top index
+ // 6 -> Padding_bottom index
+ // 7 -> Stride (width) Index
+ // 8 -> Stride (height) INdex
+ // 9 -> Depthwise Multiplier
+ // 10 -> Activation Index
+ ifm_index = inputs[0];
+ ker_index = inputs[1];
+ bias_index = inputs[2];
+ padding_left_index = inputs[3];
+ padding_right_index = inputs[4];
+ padding_top_index = inputs[5];
+ padding_bottom_index = inputs[6];
+ hstride_index = inputs[7];
+ vstride_index = inputs[8];
+ multiplier_index = inputs[9];
+ activation_index = inputs[10];
+}
+
+} // namespace Explicit
+
+namespace Implicit
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 8 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> IFM Tensor Index
+ // 1 -> Kernel Tensor Index
+ // 2 -> Bias Tensor Index
+ // 3 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index
+ // 4 -> Stride (width) Index
+ // 5 -> Stride (height) INdex
+ // 6 -> Depthwise Multiplier
+ // 7 -> Activation Index
+ ifm_index = inputs[0];
+ ker_index = inputs[1];
+ bias_index = inputs[2];
+ padding_index = inputs[3];
+ hstride_index = inputs[4];
+ vstride_index = inputs[5];
+ multiplier_index = inputs[6];
+ activation_index = inputs[7];
+}
+
+} // namespace Implicit
+} // namespace DepthwiseConv2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/DepthwiseConv2D.h b/runtime/contrib/pure_arm_compute/src/internal/op/DepthwiseConv2D.h
new file mode 100644
index 000000000..01a9e48be
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/DepthwiseConv2D.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file DepthwiseConv2D.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::DepthwiseConv2D Param structs
+ * and internal::tflite::op::DepthwiseConv2D Node classes
+ */
+#ifndef __INTERNAL_OP_DEPTHWISE_CONV_2D_H__
+#define __INTERNAL_OP_DEPTHWISE_CONV_2D_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace DepthwiseConv2D
+{
+namespace Explicit
+{
+
+/**
+ * @brief Struct to have indexes for explicit padding DepthwiseConv2D operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Index of output feature map */
+
+ int32_t ifm_index; /**< Index of input feature map */
+ int32_t ker_index; /**< Index of kernel */
+ int32_t bias_index; /**< Index of bias */
+
+ int32_t hstride_index; /**< Index of horizontal stride */
+ int32_t vstride_index; /**< Index of vertical stride */
+
+ int32_t padding_left_index; /**< Index of padding left */
+ int32_t padding_right_index; /**< Index of padding right */
+ int32_t padding_top_index; /**< Index of padding top */
+ int32_t padding_bottom_index; /**< Index of padding bottom */
+
+ int32_t multiplier_index; /**< Index of multipler */
+ int32_t activation_index; /**< Index of activation */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an explicit padding DepthwiseConv2D operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Explicit
+
+/**
+ * @brief Struct to have indexes for implicit padding DepthwiseConv2D operation parameter
+ */
+namespace Implicit
+{
+
+struct Param
+{
+ int32_t ofm_index; /**< Index of output feature map */
+
+ int32_t ifm_index; /**< Index of input feature map */
+ int32_t ker_index; /**< Index of kernel */
+ int32_t bias_index; /**< Index of bias */
+
+ int32_t hstride_index; /**< Index of horizontal stride */
+ int32_t vstride_index; /**< Index of vertical stride */
+
+ int32_t padding_index; /**< Index of padding */
+ int32_t multiplier_index; /**< Index of multipler */
+ int32_t activation_index; /**< Index of activation */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an implicit padding DepthwiseConv2D operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Implicit
+} // namespace DepthwiseConv2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_CONV_2D_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Dequantize.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Dequantize.cc
new file mode 100644
index 000000000..7062463a2
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Dequantize.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Dequantize.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Dequantize
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Dequantize
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Dequantize
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ // 0 -> input Tensor Index
+ input_index = inputs[0];
+}
+
+} // namespace Dequantize
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Dequantize.h b/runtime/contrib/pure_arm_compute/src/internal/op/Dequantize.h
new file mode 100644
index 000000000..f19898e9e
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Dequantize.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Dequantize.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::Dequantize::Param struct
+ * and internal::tflite::op::Dequantize::Node class
+ */
+#ifndef __INTERNAL_OP_DEQUANTIZE_H__
+#define __INTERNAL_OP_DEQUANTIZE_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Dequantize
+{
+
+/**
+ * @brief Struct to have indexes for Dequantize operation parameter
+ */
+struct Param
+{
+ int32_t output_index; /**< Index of output feature map */
+
+ int32_t input_index; /**< Index of input feature map */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an Dequantize operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Dequantize
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_DEQUANTIZE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Div.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Div.cc
new file mode 100644
index 000000000..649407eab
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Div.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Div.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Div
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Div
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Div
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 3 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> LHS Tensor Index
+ // 1 -> RHS Tensor Index
+ // 2 -> Activation Index
+ lhs_index = inputs[0];
+ rhs_index = inputs[1];
+ activation_index = inputs[2];
+}
+
+} // namespace Div
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Div.h b/runtime/contrib/pure_arm_compute/src/internal/op/Div.h
new file mode 100644
index 000000000..d5fc09d19
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Div.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Div.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::Div::Param struct
+ * and internal::tflite::op::Div::Node class
+ */
+#ifndef __INTERNAL_OP_DIV_H__
+#define __INTERNAL_OP_DIV_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Div
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Index of output feature map */
+
+ int32_t lhs_index; /**< Index of lhs */
+ int32_t rhs_index; /**< Index of rhs */
+ int32_t activation_index; /**< Index of activation */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Div
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_DIV_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/EmbeddingLookup.cc b/runtime/contrib/pure_arm_compute/src/internal/op/EmbeddingLookup.cc
new file mode 100644
index 000000000..a6eda3473
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/EmbeddingLookup.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/EmbeddingLookup.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace EmbeddingLookup
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace EmbeddingLookup
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace EmbeddingLookup
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Lookups Index
+ // 1 -> Values Index
+ lookups_index = inputs[0];
+ values_index = inputs[1];
+}
+
+} // namespace EmbeddingLookup
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/EmbeddingLookup.h b/runtime/contrib/pure_arm_compute/src/internal/op/EmbeddingLookup.h
new file mode 100644
index 000000000..17e8485f7
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/EmbeddingLookup.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file EmbeddingLookup.h
+ * @brief This file contains accept function and params for EmbeddingLookup operation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_EMBEDDING_LOOKUP_H__
+#define __INTERNAL_OP_EMBEDDING_LOOKUP_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace EmbeddingLookup
+{
+
+/**
+ * @brief Struct of EmbeddingLookup operation's param
+ */
+struct Param
+{
+ int32_t output_index; /**< Output index */
+
+ int32_t lookups_index; /**< Lookups index */
+ int32_t values_index; /**< Values index */
+
+ /**
+ * @brief Construct a new Param object for EmbeddingLookup as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for EmbeddingLookup with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for EmbeddingLookup
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for EmbeddingLookup with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for EmbeddingLookup
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for EmbeddingLookup
+ * @return Parameters of EmbeddingLookup
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for EmbeddingLookup
+ * @param [in] v Node visitor for invoking visit function of EmbeddingLookup
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace EmbeddingLookup
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_EMBEDDING_LOOKUP_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Equal.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Equal.cc
new file mode 100644
index 000000000..b9cccc6a9
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Equal.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Equal.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Equal
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Equal
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Equal
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input1 Tensor Index
+ // 1 -> input2 Tensor Index
+ input1_index = inputs[0];
+ input2_index = inputs[1];
+}
+
+} // namespace Equal
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Equal.h b/runtime/contrib/pure_arm_compute/src/internal/op/Equal.h
new file mode 100644
index 000000000..78b9f846f
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Equal.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_EQUAL_H__
+#define __INTERNAL_OP_EQUAL_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Equal
+{
+
+struct Param
+{
+ int32_t output_index;
+
+ int32_t input1_index;
+ int32_t input2_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+} // namespace Equal
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Equal
+{
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Equal
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_EQUAL_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Exp.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Exp.cc
new file mode 100644
index 000000000..6f1aa8f42
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Exp.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Exp.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Exp
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Exp
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Exp
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ ifm_index = inputs[0];
+}
+
+} // namespace Exp
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Exp.h b/runtime/contrib/pure_arm_compute/src/internal/op/Exp.h
new file mode 100644
index 000000000..ac7f244b7
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Exp.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_EXP_H__
+#define __INTERNAL_OP_EXP_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Exp
+{
+
+struct Param
+{
+ int32_t ofm_index;
+
+ int32_t ifm_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Exp
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_EXP_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Floor.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Floor.cc
new file mode 100644
index 000000000..c04f0c8ab
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Floor.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Floor.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Floor
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Floor
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Floor
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ // 0 -> input Tensor Index
+ input_index = inputs[0];
+}
+
+} // namespace Floor
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Floor.h b/runtime/contrib/pure_arm_compute/src/internal/op/Floor.h
new file mode 100644
index 000000000..5264ec10c
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Floor.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Floor.h
+ * @brief This file contains accept function and params for Floor operation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_FLOOR_H__
+#define __INTERNAL_OP_FLOOR_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Floor
+{
+
+/**
+ * @brief Struct of Floor operation's param
+ */
+struct Param
+{
+ int32_t output_index; /**< Output index */
+
+ int32_t input_index; /**< Input index */
+
+ /**
+ * @brief Construct a new Param object for Floor as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for Floor with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for Floor
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for Floor with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for Floor
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for Floor
+ * @return Parameters of Floor
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for Floor
+ * @param [in] v Node visitor for invoking visit function of Floor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Floor
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_FLOOR_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/FullyConnected.cc b/runtime/contrib/pure_arm_compute/src/internal/op/FullyConnected.cc
new file mode 100644
index 000000000..491fa5918
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/FullyConnected.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/FullyConnected.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace FullyConnected
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace FullyConnected
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace FullyConnected
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 4 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> A tensor, specifying the input.
+ // 1 -> A 2-D tensor, specifying the weights
+ // 2 -> A 1-D tensor, specifying the bias
+ // 3 -> An INT32 value, and has to be one of the FuseCode values
+ input_index = inputs[0];
+ weight_index = inputs[1];
+ bias_index = inputs[2];
+ activation_index = inputs[3];
+}
+
+} // namespace FullyConnected
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/FullyConnected.h b/runtime/contrib/pure_arm_compute/src/internal/op/FullyConnected.h
new file mode 100644
index 000000000..434308435
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/FullyConnected.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file FullyConnected.h
+ * @brief This file contains accept function and params for FullyConnected operation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_FULLY_CONNTECTED_H__
+#define __INTERNAL_OP_FULLY_CONNTECTED_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace FullyConnected
+{
+
+/**
+ * @brief Struct of FullyConnected operation's param
+ */
+struct Param
+{
+ int32_t output_index; /**< Output index */
+
+ int32_t input_index; /**< Input index */
+ int32_t weight_index; /**< Weight index */
+ int32_t bias_index; /**< Bias index */
+ int32_t activation_index; /**< Activation index */
+
+ /**
+ * @brief Construct a new Param object for FullyConnected as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for FullyConnected with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for FullyConnected
+ */
+class Node final : public op::Node
+{
+ /**
+ * @brief Construct a new Node object for FullyConnected with param
+ * @param [in] param Parameters for Node
+ */
+public:
+ /**
+ * @brief Destroy the Node object for FullyConnected
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for FullyConnected
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Parameter Get parameters for FullyConnected
+ * @return _param Parameters of FullyConnected
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for FullyConnected
+ * @param [in] v Node visitor for invoking visit function of FullyConnected
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace FullyConnected
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_FULLY_CONNTECTED_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Gather.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Gather.cc
new file mode 100644
index 000000000..bc517d28c
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Gather.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Gather.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Gather
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Gather
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Gather
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 3 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input Tensor Index
+ // 1 -> indices Tensor Index
+ // 2 -> axis Index
+ ifm_index = inputs[0];
+ indices_index = inputs[1];
+ axis_index = inputs[2];
+}
+
+} // namespace Gather
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Gather.h b/runtime/contrib/pure_arm_compute/src/internal/op/Gather.h
new file mode 100644
index 000000000..d40794f99
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Gather.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Gather.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines Gather operation
+ */
+
+#ifndef __INTERNAL_OP_GATHER_H__
+#define __INTERNAL_OP_GATHER_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Gather
+{
+
+/**
+ * @brief Struct to manipulate parameter for Gather operation
+ */
+struct Param
+{
+ int32_t ofm_index; //!< index for output feature map
+
+ int32_t ifm_index; //!< index for ifm tensor
+ int32_t indices_index; //!< index for indices tensor
+ int32_t axis_index; //!< index for axis
+
+ /**
+ * @brief Default Constructor
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object
+ * @param[in] inputCount the number of inputs
+ * @param[in] inputs pointer for input data
+ * @param[in] outputCount the number of outputs
+ * @param[in] outputs pointer for input data
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define Gather Operation
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Tanh Node object
+ * @param param Parameter for Tanh Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Default Destructor
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameter
+ * @return Param reference
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Accept a NodeVisitor so that it can visit this node
+ * @param [in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param; //!< parameter for Gather node
+};
+
+} // namespace Gather
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_GATHER_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/HashtableLookup.cc b/runtime/contrib/pure_arm_compute/src/internal/op/HashtableLookup.cc
new file mode 100644
index 000000000..7e04ecf82
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/HashtableLookup.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/HashtableLookup.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace HashtableLookup
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace HashtableLookup
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace HashtableLookup
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 3 && outputCount == 2);
+
+ output_index = outputs[0];
+ hits_index = outputs[1];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Lookups Index
+ // 1 -> Keys Index
+ // 2 -> Values Index
+ lookups_index = inputs[0];
+ keys_index = inputs[1];
+ values_index = inputs[2];
+}
+
+} // namespace HashtableLookup
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/HashtableLookup.h b/runtime/contrib/pure_arm_compute/src/internal/op/HashtableLookup.h
new file mode 100644
index 000000000..a5b43d1c7
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/HashtableLookup.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file HashtableLookup.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::HashtableLookup::Param struct
+ * and internal::tflite::op::HashtableLookup::Node class
+ */
+#ifndef __INTERNAL_OP_HASHTABLE_LOOKUP_H__
+#define __INTERNAL_OP_HASHTABLE_LOOKUP_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace HashtableLookup
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t output_index; /**< Index of output feature map */
+ int32_t hits_index; /**< Index of hits */
+
+ int32_t lookups_index; /**< Index of lookups */
+ int32_t values_index; /**< Index of values */
+ int32_t keys_index; /**< Index of keys */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace HashtableLookup
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_HASHTABLE_LOOKUP_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/L2Normalization.cc b/runtime/contrib/pure_arm_compute/src/internal/op/L2Normalization.cc
new file mode 100644
index 000000000..44a6ee63d
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/L2Normalization.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/L2Normalization.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace L2Normalization
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace L2Normalization
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace L2Normalization
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ ifm_index = inputs[0];
+}
+
+} // namespace L2Normalization
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/L2Normalization.h b/runtime/contrib/pure_arm_compute/src/internal/op/L2Normalization.h
new file mode 100644
index 000000000..2e94fac11
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/L2Normalization.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file L2Normalization.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::L2Normalization::Param struct
+ * and internal::tflite::op::L2Normalization::Node class
+ */
+#ifndef __INTERNAL_OP_L2_NORMALIZATION_H__
+#define __INTERNAL_OP_L2_NORMALIZATION_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace L2Normalization
+{
+
+/**
+ * @brief Struct to have indexes for L2Normalization operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Index of output feature map */
+
+ int32_t ifm_index; /**< Index of input feature map */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an L2Normalization operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace L2Normalization
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_L2_NORMALIZATION_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/L2Pool2D.cc b/runtime/contrib/pure_arm_compute/src/internal/op/L2Pool2D.cc
new file mode 100644
index 000000000..64041ab49
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/L2Pool2D.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/L2Pool2D.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace L2Pool2D
+{
+namespace Explicit
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Explicit
+
+namespace Implicit
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Implicit
+} // namespace L2Pool2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace L2Pool2D
+{
+namespace Explicit
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 10 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> IFM Tensor Index
+ // 1 -> Padding_left index
+ // 2 -> Padding_right index
+ // 3 -> Padding_top index
+ // 4 -> Padding_bottom index
+ // 5 -> Horizontal (over width) Stride Index
+ // 6 -> Vertial (over height) Stride Index
+ // 7 -> Filter Width Index
+ // 8 -> Filter Height Index
+ // 9 -> FuseCode (activation) Index
+ ifm_index = inputs[0];
+ padding_left_index = inputs[1];
+ padding_right_index = inputs[2];
+ padding_top_index = inputs[3];
+ padding_bottom_index = inputs[4];
+ hstride_index = inputs[5];
+ vstride_index = inputs[6];
+ kw_index = inputs[7];
+ kh_index = inputs[8];
+ activation_index = inputs[9];
+}
+
+} // namespace Explicit
+
+namespace Implicit
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 7 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> IFM Tensor Index
+ // 1 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index
+ // 2 -> Horizontal (over width) Stride Index
+ // 3 -> Vertial (over height) Stride Index
+ // 4 -> Filter Width Index
+ // 5 -> Filter Height Index
+ // 6 -> FuseCode (activation) Index
+ ifm_index = inputs[0];
+ padding_index = inputs[1];
+ hstride_index = inputs[2];
+ vstride_index = inputs[3];
+ kw_index = inputs[4];
+ kh_index = inputs[5];
+ activation_index = inputs[6];
+}
+
+} // namespace Implicit
+} // namespace L2Pool2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/L2Pool2D.h b/runtime/contrib/pure_arm_compute/src/internal/op/L2Pool2D.h
new file mode 100644
index 000000000..facb223c7
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/L2Pool2D.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file L2Pool2D.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::L2Pool2D Param structs
+ * and internal::tflite::op::L2Pool2D Node classes
+ */
+#ifndef __INTERNAL_OP_L2_POOL_2D_H__
+#define __INTERNAL_OP_L2_POOL_2D_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace L2Pool2D
+{
+namespace Explicit
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Index of output feature map */
+
+ int32_t ifm_index; /**< Index of input feature map */
+
+ int32_t kw_index; /**< Index of kernel width */
+ int32_t kh_index; /**< Index of kernel height */
+
+ int32_t hstride_index; /**< Index of horizontal stride */
+ int32_t vstride_index; /**< Index of vertical stride */
+
+ int32_t padding_left_index; /**< Index of padding left */
+ int32_t padding_right_index; /**< Index of padding right */
+ int32_t padding_top_index; /**< Index of padding top */
+ int32_t padding_bottom_index; /**< Index of padding bottom */
+
+ int32_t activation_index; /**< Index of activation */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Explicit
+
+namespace Implicit
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Index of output feature map */
+
+ int32_t ifm_index; /**< Index of input feature map */
+
+ int32_t kw_index; /**< Index of kernel width */
+ int32_t kh_index; /**< Index of kernel height */
+
+ int32_t hstride_index; /**< Index of horizontal stride */
+ int32_t vstride_index; /**< Index of vertical stride */
+
+ int32_t padding_index; /**< Index of padding */
+ int32_t activation_index; /**< Index of activation */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Implicit
+} // namespace L2Pool2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_L2_POOL_2D_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LocalResponseNormalization.cc b/runtime/contrib/pure_arm_compute/src/internal/op/LocalResponseNormalization.cc
new file mode 100644
index 000000000..b7419d923
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/LocalResponseNormalization.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/LocalResponseNormalization.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LocalResponseNormalization
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace LocalResponseNormalization
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LocalResponseNormalization
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 5 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ ifm_index = inputs[0];
+ radius_index = inputs[1];
+ bias_index = inputs[2];
+ alpha_index = inputs[3];
+ beta_index = inputs[4];
+}
+
+} // namespace LocalResponseNormalization
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LocalResponseNormalization.h b/runtime/contrib/pure_arm_compute/src/internal/op/LocalResponseNormalization.h
new file mode 100644
index 000000000..29e0699ad
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/LocalResponseNormalization.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_LOCAL_RESPONSE_NORMALIZATION_H__
+#define __INTERNAL_OP_LOCAL_RESPONSE_NORMALIZATION_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LocalResponseNormalization
+{
+
+struct Param
+{
+ int32_t ofm_index;
+
+ int32_t ifm_index;
+ int32_t radius_index;
+ int32_t bias_index;
+ int32_t alpha_index;
+ int32_t beta_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace LocalResponseNormalization
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_LOCAL_RESPONSE_NORMALIZATION_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LogicalAnd.cc b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalAnd.cc
new file mode 100644
index 000000000..5b7da4d3b
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalAnd.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/LogicalAnd.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LogicalAnd
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace LogicalAnd
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LogicalAnd
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input1 Tensor Index
+ // 1 -> input2 Tensor Index
+ input1_index = inputs[0];
+ input2_index = inputs[1];
+}
+
+} // namespace LogicalAnd
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LogicalAnd.h b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalAnd.h
new file mode 100644
index 000000000..2f53f756d
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalAnd.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_LOGICAL_AND_H__
+#define __INTERNAL_OP_LOGICAL_AND_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LogicalAnd
+{
+
+struct Param
+{
+ int32_t output_index;
+
+ int32_t input1_index;
+ int32_t input2_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+} // namespace LogicalAnd
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LogicalAnd
+{
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace LogicalAnd
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_LOGICAL_AND_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LogicalNot.cc b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalNot.cc
new file mode 100644
index 000000000..4cb6a8e2a
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalNot.cc
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/LogicalNot.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LogicalNot
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace LogicalNot
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LogicalNot
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ input_index = inputs[0];
+}
+
+} // namespace LogicalNot
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LogicalNot.h b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalNot.h
new file mode 100644
index 000000000..9593deafe
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalNot.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_LOGICAL_NOT_H__
+#define __INTERNAL_OP_LOGICAL_NOT_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LogicalNot
+{
+
+struct Param
+{
+ int32_t output_index;
+
+ int32_t input_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+} // namespace LogicalNot
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LogicalNot
+{
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace LogicalNot
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_LOGICAL_NOT_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LogicalOr.cc b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalOr.cc
new file mode 100644
index 000000000..8295f6f0b
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalOr.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/LogicalOr.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LogicalOr
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace LogicalOr
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LogicalOr
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input1 Tensor Index
+ // 1 -> input2 Tensor Index
+ input1_index = inputs[0];
+ input2_index = inputs[1];
+}
+
+} // namespace LogicalOr
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/LogicalOr.h b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalOr.h
new file mode 100644
index 000000000..6487fa720
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/LogicalOr.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_LOGICAL_OR_H__
+#define __INTERNAL_OP_LOGICAL_OR_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LogicalOr
+{
+
+struct Param
+{
+ int32_t output_index;
+
+ int32_t input1_index;
+ int32_t input2_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+} // namespace LogicalOr
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LogicalOr
+{
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace LogicalOr
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_LOGICAL_OR_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Logistic.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Logistic.cc
new file mode 100644
index 000000000..93ecd043c
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Logistic.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Logistic.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Logistic
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Logistic
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Logistic
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ ifm_index = inputs[0];
+}
+
+} // namespace Logistic
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Logistic.h b/runtime/contrib/pure_arm_compute/src/internal/op/Logistic.h
new file mode 100644
index 000000000..a42fdc0d4
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Logistic.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Logistic.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::Logistic::Param struct
+ * and internal::tflite::op::Logistic::Node class
+ */
+#ifndef __INTERNAL_OP_LOGISTIC_H__
+#define __INTERNAL_OP_LOGISTIC_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Logistic
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Index of output feature map */
+
+ int32_t ifm_index; /**< Index of input feature map */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Logistic
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_LOGISTIC_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Lstm.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Lstm.cc
new file mode 100644
index 000000000..3f5e9a490
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Lstm.cc
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Lstm.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LSTM
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace LSTM
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LSTM
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 23 && outputCount == 4);
+
+ scratch_buffer_index = outputs[0];
+ output_state_out_index = outputs[1];
+ cell_state_out_index = outputs[2];
+ output_index = outputs[3];
+
+ input_index = inputs[0];
+ input_to_input_weights_index = inputs[1];
+ input_to_forget_weights_index = inputs[2];
+ input_to_cell_weights_index = inputs[3];
+ input_to_output_weights_index = inputs[4];
+ recurrent_to_input_weights_index = inputs[5];
+ recurrent_to_forget_weights_index = inputs[6];
+ recurrent_to_cell_weights_index = inputs[7];
+ recurrent_to_output_weights_index = inputs[8];
+ cell_to_input_weights_index = inputs[9];
+ cell_to_forget_weights_index = inputs[10];
+ cell_to_output_weights_index = inputs[11];
+ input_gate_bias_index = inputs[12];
+ forget_gate_bias_index = inputs[13];
+ cell_bias_index = inputs[14];
+ output_gate_bias_index = inputs[15];
+ projection_weights_index = inputs[16];
+ projection_bias_index = inputs[17];
+ output_state_in_index = inputs[18];
+ cell_state_in_index = inputs[19];
+ activation_index = inputs[20];
+ cell_threshold_index = inputs[21];
+ projection_threshold_index = inputs[22];
+}
+
+} // namespace LSTM
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Lstm.h b/runtime/contrib/pure_arm_compute/src/internal/op/Lstm.h
new file mode 100644
index 000000000..f51f0402a
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Lstm.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Lstm.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::LSTM::Param struct
+ * and internal::tflite::op::LSTM::Node class
+ */
+#ifndef __INTERNAL_OP_LSTM_H__
+#define __INTERNAL_OP_LSTM_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace LSTM
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t scratch_buffer_index; /**< Index of scartch buffer */
+ int32_t output_state_out_index; /**< Index of output state out */
+ int32_t cell_state_out_index; /**< Index of cell state out */
+ int32_t output_index; /**< Index of output */
+
+ int32_t input_index; /**< Index of input */
+ int32_t input_to_input_weights_index; /**< Index of input to input weights */
+ int32_t input_to_forget_weights_index; /**< Index of input to forget weights */
+ int32_t input_to_cell_weights_index; /**< Index of input to cell weights */
+ int32_t input_to_output_weights_index; /**< Index of input to output weights */
+ int32_t recurrent_to_input_weights_index; /**< Index of recurrent to input weights */
+ int32_t recurrent_to_forget_weights_index; /**< Index of recurrent to forget weights */
+ int32_t recurrent_to_cell_weights_index; /**< Index of recurrent to cell weights */
+ int32_t recurrent_to_output_weights_index; /**< Index of recurrent to output weights */
+ int32_t cell_to_input_weights_index; /**< Index of cell to input weights */
+ int32_t cell_to_forget_weights_index; /**< Index of cell to forget weights */
+ int32_t cell_to_output_weights_index; /**< Index of cell to output weights */
+ int32_t input_gate_bias_index; /**< Index of input gate bias */
+ int32_t forget_gate_bias_index; /**< Index of forget gate bias */
+ int32_t cell_bias_index; /**< Index of cell bias */
+ int32_t output_gate_bias_index; /**< Index of output gate bias */
+ int32_t projection_weights_index; /**< Index of projection weights */
+ int32_t projection_bias_index; /**< Index of projection bias */
+ int32_t output_state_in_index; /**< Index of output state in */
+ int32_t cell_state_in_index; /**< Index of cell state in */
+ int32_t activation_index; /**< Index of activation */
+ int32_t cell_threshold_index; /**< Index of cell threshold */
+ int32_t projection_threshold_index; /**< Index of projection threshold */
+
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace LSTM
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_LSTM_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/MaxPool2D.cc b/runtime/contrib/pure_arm_compute/src/internal/op/MaxPool2D.cc
new file mode 100644
index 000000000..0c80f1f5c
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/MaxPool2D.cc
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/MaxPool2D.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace MaxPool2D
+{
+namespace Explicit
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Explicit
+
+namespace Implicit
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Implicit
+} // namespace MaxPool2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace MaxPool2D
+{
+namespace Explicit
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 10 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> IFM Tensor Index
+ // 1 -> Padding_left index
+ // 2 -> Padding_right index
+ // 3 -> Padding_top index
+ // 4 -> Padding_bottom index
+ // 5 -> Horizontal (over width) Stride Index
+ // 6 -> Vertial (over height) Stride Index
+ // 7 -> Filter Width Index
+ // 8 -> Filter Height Index
+ // 9 -> FuseCode (activation) Index
+ ifm_index = inputs[0];
+ padding_left_index = inputs[1];
+ padding_right_index = inputs[2];
+ padding_top_index = inputs[3];
+ padding_bottom_index = inputs[4];
+ hstride_index = inputs[5];
+ vstride_index = inputs[6];
+ kw_index = inputs[7];
+ kh_index = inputs[8];
+ activation_index = inputs[9];
+}
+
+} // namespace Explicit
+
+namespace Implicit
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 7 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> IFM Tensor Index
+ // 1 -> Padding Code (ANEURALNETWORKS_PADDING_SAME or ANEURALNETWORKS_PADDING_VALID) Index
+ // 2 -> Horizontal (over width) Stride Index
+ // 3 -> Vertial (over height) Stride Index
+ // 4 -> Filter Width Index
+ // 5 -> Filter Height Index
+ // 6 -> FuseCode (activation) Index
+ ifm_index = inputs[0];
+ padding_index = inputs[1];
+ hstride_index = inputs[2];
+ vstride_index = inputs[3];
+ kw_index = inputs[4];
+ kh_index = inputs[5];
+ activation_index = inputs[6];
+}
+
+} // namespace Implicit
+} // namespace MaxPool2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/MaxPool2D.h b/runtime/contrib/pure_arm_compute/src/internal/op/MaxPool2D.h
new file mode 100644
index 000000000..329ccecb7
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/MaxPool2D.h
@@ -0,0 +1,202 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file MaxPool2D.h
+ * @brief This file contains accept function and params for MaxPool2D operation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_MAX_POOL_2D_H__
+#define __INTERNAL_OP_MAX_POOL_2D_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace MaxPool2D
+{
+namespace Explicit
+{
+
+/**
+ * @brief Struct of MaxPool2D(Explicit) operation's param
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Output format index */
+
+ int32_t ifm_index; /**< Input format index */
+
+ int32_t kw_index; /**< Kernel width index */
+ int32_t kh_index; /**< Kernel height index */
+
+ int32_t hstride_index; /**< Horizontal stride index */
+ int32_t vstride_index; /**< Vertical stride index */
+
+ int32_t padding_left_index; /**< Left padding index */
+ int32_t padding_right_index; /**< Right padding index */
+ int32_t padding_top_index; /**< Top padding index */
+ int32_t padding_bottom_index; /**< Bottom padding index */
+
+ int32_t activation_index; /**< Activation index */
+
+ /**
+ * @brief Construct a new Param object for MaxPool2D(Explicit) as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for MaxPool2D(Explicit) with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for MaxPool2D(Explicit)
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for MaxPool2D(Explicit) with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for MaxPool2D(Explicit)
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for MaxPool2D(Explicit)
+ * @return Parameters of MaxPool2D(Explicit)
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for MaxPool2D(Explicit)
+ * @param [in] v Node visitor for invoking visit function of MaxPool2D(Explicit)
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Explicit
+
+namespace Implicit
+{
+
+/**
+ * @brief Struct of MaxPool2D(Implicit) operation's param
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Output format index */
+
+ int32_t ifm_index; /**< Input format index */
+
+ int32_t kw_index; /**< Kernel width index */
+ int32_t kh_index; /**< Kernel height index */
+
+ int32_t hstride_index; /**< Horizontal stride index */
+ int32_t vstride_index; /**< Vertical stride index */
+
+ int32_t padding_index; /**< Padding index */
+ int32_t activation_index; /**< Activation index */
+
+ /**
+ * @brief Construct a new Param object for MaxPool2D(Implicit) as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for MaxPool2D(Implicit) with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for MaxPool2D(Implicit)
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for MaxPool2D(Implicit) with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for MaxPool2D(Implicit)
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for MaxPool2D(Implicit)
+ * @return Parameters of MaxPool2D(Implicit)
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for MaxPool2D(Implicit)
+ * @param [in] v Node visitor for invoking visit function of MaxPool2D(Implicit)
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Implicit
+} // namespace MaxPool2D
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_MAX_POOL_2D_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Mean.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Mean.cc
new file mode 100644
index 000000000..222a3ee4a
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Mean.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Mean.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Mean
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Mean
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Mean
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 3 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> ifm Tensor Index
+ // 1 -> axis Tensor Index
+ // 2 -> keep_dims Index
+ ifm_index = inputs[0];
+ axis_index = inputs[1];
+ keep_dims_index = inputs[2];
+}
+
+} // namespace Mean
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Mean.h b/runtime/contrib/pure_arm_compute/src/internal/op/Mean.h
new file mode 100644
index 000000000..f8e7ed308
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Mean.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Mean.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::Mean::Param struct
+ * and internal::tflite::op::Mean::Node class
+ */
+#ifndef __INTERNAL_OP_MEAN_H__
+#define __INTERNAL_OP_MEAN_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Mean
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Index of output feature map */ // output
+
+ int32_t ifm_index; /**< Index of input feature map */ // input
+ int32_t axis_index; /**< Index of axis */ // axis
+ int32_t keep_dims_index; /**< Index of keep dims */ // keep_dims
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Mean
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_MEAN_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Mul.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Mul.cc
new file mode 100644
index 000000000..2a2ae00ed
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Mul.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Mul.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Mul
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Mul
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Mul
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 3 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> LHS Tensor Index
+ // 1 -> RHS Tensor Index
+ // 2 -> Activation Index
+ lhs_index = inputs[0];
+ rhs_index = inputs[1];
+ activation_index = inputs[2];
+}
+
+} // namespace Mul
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Mul.h b/runtime/contrib/pure_arm_compute/src/internal/op/Mul.h
new file mode 100644
index 000000000..9710dd057
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Mul.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Mul.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::Mul class
+ */
+#ifndef __INTERNAL_OP_MUL_H__
+#define __INTERNAL_OP_MUL_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Mul
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /** Index of output feature map */
+
+ int32_t lhs_index; /** Index of lhs */
+ int32_t rhs_index; /** Index of rhs */
+ int32_t activation_index; /** Index of activation */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Mul
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_MUL_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Neg.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Neg.cc
new file mode 100644
index 000000000..72fecf484
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Neg.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Neg.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Neg
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Neg
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Neg
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ ifm_index = inputs[0];
+}
+
+} // namespace Neg
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Neg.h b/runtime/contrib/pure_arm_compute/src/internal/op/Neg.h
new file mode 100644
index 000000000..77507df3d
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Neg.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_NEG_H__
+#define __INTERNAL_OP_NEG_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Neg
+{
+
+struct Param
+{
+ int32_t ofm_index;
+
+ int32_t ifm_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Neg
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_NEG_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Node.h b/runtime/contrib/pure_arm_compute/src/internal/op/Node.h
new file mode 100644
index 000000000..be1cbdb5b
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Node.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Node.h
+ * @brief This file contains struct of Node and NodeVisitor
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_NODE_H__
+#define __INTERNAL_OP_NODE_H__
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+
+/**
+ * @brief Struct of operation NodeVisitor
+ */
+struct NodeVisitor;
+
+/**
+ * @brief Struct of operation Node
+ */
+struct Node
+{
+ /**
+ * @brief Destroy the Node object for operation
+ */
+ virtual ~Node() = default;
+
+ /**
+ * @brief Function for accepting node for operation
+ * @param [in] v Node visitor for invoking visit function of operation
+ * @return N/A
+ */
+ virtual void accept(NodeVisitor &&) const = 0;
+};
+
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_NODE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/NodeVisitor.h b/runtime/contrib/pure_arm_compute/src/internal/op/NodeVisitor.h
new file mode 100644
index 000000000..0c1a4001d
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/NodeVisitor.h
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file NodeVisitor.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines NodeVisitor
+ */
+
+#ifndef __INTERNAL_OP_NODE_VISITOR_H__
+#define __INTERNAL_OP_NODE_VISITOR_H__
+
+#include "internal/op/Add.h"
+#include "internal/op/Sub.h"
+#include "internal/op/Mul.h"
+#include "internal/op/Div.h"
+#include "internal/op/Conv2D.h"
+#include "internal/op/DepthwiseConv2D.h"
+#include "internal/op/Dequantize.h"
+#include "internal/op/MaxPool2D.h"
+#include "internal/op/AvgPool2D.h"
+#include "internal/op/ArgMax.h"
+#include "internal/op/Concat.h"
+#include "internal/op/Reshape.h"
+#include "internal/op/ResizeBilinear.h"
+#include "internal/op/StridedSlice.h"
+#include "internal/op/FullyConnected.h"
+#include "internal/op/Softmax.h"
+#include "internal/op/ReduceMax.h"
+#include "internal/op/ReduceMin.h"
+#include "internal/op/Cast.h"
+#include "internal/op/TopKV2.h"
+#include "internal/op/Gather.h"
+#include "internal/op/PReLU.h"
+#include "internal/op/ReLU.h"
+#include "internal/op/ReLU1.h"
+#include "internal/op/ReLU6.h"
+#include "internal/op/Tanh.h"
+#include "internal/op/Squeeze.h"
+#include "internal/op/Logistic.h"
+#include "internal/op/Mean.h"
+#include "internal/op/Rnn.h"
+#include "internal/op/Transpose.h"
+#include "internal/op/Lstm.h"
+#include "internal/op/Floor.h"
+#include "internal/op/Split.h"
+#include "internal/op/RSQRT.h"
+#include "internal/op/SQRT.h"
+#include "internal/op/Pad.h"
+#include "internal/op/SpaceToDepth.h"
+#include "internal/op/SpaceToBatchND.h"
+#include "internal/op/L2Pool2D.h"
+#include "internal/op/EmbeddingLookup.h"
+#include "internal/op/HashtableLookup.h"
+#include "internal/op/L2Normalization.h"
+#include "internal/op/SquaredDifference.h"
+#include "internal/op/LocalResponseNormalization.h"
+#include "internal/op/DepthToSpace.h"
+#include "internal/op/Unpack.h"
+#include "internal/op/Neg.h"
+#include "internal/op/Exp.h"
+#include "internal/op/ReduceSum.h"
+#include "internal/op/Equal.h"
+#include "internal/op/BatchToSpaceNd.h"
+#include "internal/op/TransposeConv.h"
+#include "internal/op/Pack.h"
+#include "internal/op/Abs.h"
+#include "internal/op/NotEqual.h"
+#include "internal/op/LogicalAnd.h"
+#include "internal/op/LogicalNot.h"
+#include "internal/op/LogicalOr.h"
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+
+/**
+ * @brief Struct to define visitor for operation Nodes
+ */
+struct NodeVisitor
+{
+ /**
+ * @brief Destruct NodeVisitor object with default
+ */
+ virtual ~NodeVisitor() = default;
+
+ /**
+ * @brief Visit an Add node
+ * @param[in] node Add node to visit
+ * @return N/A
+ */
+ virtual void visit(const Add::Node &) = 0;
+ /**
+ * @brief Visit a Mul node
+ * @param[in] node Mul node to visit
+ * @return N/A
+ */
+ virtual void visit(const Sub::Node &) = 0;
+ /**
+ * @brief Visit a Mul node
+ * @param[in] node Mul node to visit
+ * @return N/A
+ */
+ virtual void visit(const Mul::Node &) = 0;
+ /**
+ * @brief Visit a Div node
+ * @param[in] node Div node to visit
+ * @return N/A
+ */
+ virtual void visit(const Div::Node &) = 0;
+ /**
+ * @brief Visit a Conv2D node with implicit padding
+ * @param[in] node Conv2D node to visit
+ * @return N/A
+ */
+ virtual void visit(const Conv2D::Implicit::Node &) = 0;
+ /**
+ * @brief Visit a Conv2D node with explicit padding
+ * @param[in] node Conv2D node to visit
+ * @return N/A
+ */
+ virtual void visit(const Conv2D::Explicit::Node &) = 0;
+ /**
+ * @brief Visit a DepthwiseConv2D node with implicit padding
+ * @param[in] node DepthwiseConv2D node to visit
+ * @return N/A
+ */
+ virtual void visit(const DepthwiseConv2D::Implicit::Node &) = 0;
+ /**
+ * @brief Visit a DepthwiseConv2D node with explicit padding
+ * @param[in] node DepthwiseConv2D node to visit
+ * @return N/A
+ */
+ virtual void visit(const DepthwiseConv2D::Explicit::Node &) = 0;
+ /**
+ * @brief Visit a Dequantize node
+ * @param[in] node Dequantize node to visit
+ * @return N/A
+ */
+ virtual void visit(const Dequantize::Node &) = 0;
+ /**
+ * @brief Visit a MaxPool2D node with implicit padding
+ * @param[in] node MaxPool2D node to visit
+ * @return N/A
+ */
+ virtual void visit(const MaxPool2D::Implicit::Node &) = 0;
+ /**
+ * @brief Visit a MaxPool2D node with explicit padding
+ * @param[in] node MaxPool2D node to visit
+ * @return N/A
+ */
+ virtual void visit(const MaxPool2D::Explicit::Node &) = 0;
+ /**
+ * @brief Visit an AvgPool2D node with implicit padding
+ * @param[in] node AvgPool2D node to visit
+ * @return N/A
+ */
+ virtual void visit(const AvgPool2D::Implicit::Node &) = 0;
+ /**
+ * @brief Visit an AvgPool2D node with explicit padding
+ * @param[in] node AvgPool2D node to visit
+ * @return N/A
+ */
+ virtual void visit(const AvgPool2D::Explicit::Node &) = 0;
+ /**
+ * @brief Visit a Concat node
+ * @param[in] node Concat node to visit
+ * @return N/A
+ */
+ virtual void visit(const Concat::Node &) = 0;
+ /**
+ * @brief Visit a ArgMax node
+ * @param[in] node ArgMax node to visit
+ * @return N/A
+ */
+ virtual void visit(const ArgMax::Node &) = 0;
+ /**
+ * @brief Visit an Reshape node
+ * @param[in] node Reshape node to visit
+ * @return N/A
+ */
+ virtual void visit(const Reshape::Node &) = 0;
+ /**
+ * @brief Visit an ResizeBilinear node
+ * @param[in] node ResizeBilinear node to visit
+ * @return N/A
+ */
+ virtual void visit(const ResizeBilinear::Node &) = 0;
+ /**
+ * @brief Visit a StridedSlice node
+ * @param[in] node StridedSlice node to visit
+ * @return N/A
+ */
+ virtual void visit(const StridedSlice::Node &) = 0;
+ /**
+ * @brief Visit a FullyConnected node
+ * @param[in] node FullyConnected node to visit
+ * @return N/A
+ */
+ virtual void visit(const FullyConnected::Node &) = 0;
+ /**
+ * @brief Visit a Softmax node
+ * @param[in] node Softmax node to visit
+ * @return N/A
+ */
+ virtual void visit(const Softmax::Node &) = 0;
+ /**
+ * @brief Visit a ReduceMax node
+ * @param[in] node ReduceMax node to visit
+ * @return N/A
+ */
+ virtual void visit(const ReduceMax::Node &) = 0;
+ /**
+ * @brief Visit a ReduceMin node
+ * @param[in] node ReduceMin node to visit
+ * @return N/A
+ */
+ virtual void visit(const ReduceMin::Node &) = 0;
+ /**
+ * @brief Visit a Cast node
+ * @param[in] node Cast node to visit
+ * @return N/A
+ */
+ virtual void visit(const Cast::Node &) = 0;
+ /**
+ * @brief Visit a TopKV2 node
+ * @param[in] node TopKV2 node to visit
+ * @return N/A
+ */
+ virtual void visit(const TopKV2::Node &) = 0;
+ /**
+ * @brief Visit a Gather node
+ * @param[in] node Gather node to visit
+ * @return N/A
+ */
+ virtual void visit(const Gather::Node &) = 0;
+ /**
+ * @brief Visit an PReLU node
+ * @param[in] node PReLU node to visit
+ * @return N/A
+ */
+ virtual void visit(const PReLU::Node &) = 0;
+ /**
+ * @brief Visit an ReLU node
+ * @param[in] node Relu node to visit
+ * @return N/A
+ */
+ virtual void visit(const ReLU::Node &) = 0;
+ /**
+ * @brief Visit a ReLU1 node
+ * @param[in] node ReLU1 node to visit
+ * @return N/A
+ */
+ virtual void visit(const ReLU1::Node &) = 0;
+ /**
+ * @brief Visit a ReLU6 node
+ * @param[in] node ReLU6 node to visit
+ * @return N/A
+ */
+ virtual void visit(const ReLU6::Node &) = 0;
+ /**
+ * @brief Visit a Tanh node
+ * @param[in] node Tanh node to visit
+ * @return N/A
+ */
+ virtual void visit(const Tanh::Node &) = 0;
+ /**
+ * @brief Visit a Squeeze node
+ * @param[in] node Squeeze node to visit
+ * @return N/A
+ */
+ virtual void visit(const Squeeze::Node &) = 0;
+ /**
+ * @brief Visit an Logistic node
+ * @param[in] node Logistic node to visit
+ * @return N/A
+ */
+ virtual void visit(const Logistic::Node &) = 0;
+ /**
+ * @brief Visit a Mean node
+ * @param[in] node Mean node to visit
+ * @return N/A
+ */
+ virtual void visit(const Mean::Node &) = 0;
+ /**
+ * @brief Visit an RNN node
+ * @param[in] node RNN node to visit
+ * @return N/A
+ */
+ virtual void visit(const RNN::Node &) = 0;
+ /**
+ * @brief Visit a Transpose node
+ * @param[in] node Transpose node to visit
+ * @return N/A
+ */
+ virtual void visit(const Transpose::Node &) = 0;
+ /**
+ * @brief Visit an LSTM node
+ * @param[in] node LSTM node to visit
+ * @return N/A
+ */
+ virtual void visit(const LSTM::Node &) = 0;
+ /**
+ * @brief Visit a Floor node
+ * @param[in] node Floor node to visit
+ * @return N/A
+ */
+ virtual void visit(const Floor::Node &) = 0;
+ /**
+ * @brief Visit a Split node
+ * @param[in] node Split node to visit
+ * @return N/A
+ */
+ virtual void visit(const Split::Node &) = 0;
+ /**
+ * @brief Visit an RSQRT node
+ * @param[in] node RSQRT node to visit
+ * @return N/A
+ */
+ virtual void visit(const RSQRT::Node &) = 0;
+ /**
+ * @brief Visit an SQRT node
+ * @param[in] node SQRT node to visit
+ * @return N/A
+ */
+ virtual void visit(const SQRT::Node &) = 0;
+ /**
+ * @brief Visit a Pad node
+ * @param[in] node Pad node to visit
+ * @return N/A
+ */
+ virtual void visit(const Pad::Node &) = 0;
+ /**
+ * @brief Visit a SpaceToDepth node
+ * @param[in] node SpaceToDepth node to visit
+ * @return N/A
+ */
+ virtual void visit(const SpaceToDepth::Node &) = 0;
+ /**
+ * @brief Visit a SpaceToBatchND node
+ * @param[in] node SpaceToBatchND node to visit
+ * @return N/A
+ */
+ virtual void visit(const SpaceToBatchND::Node &) = 0;
+ /**
+ * @brief Visit an L2Pool2D node with implicit padding
+ * @param[in] node L2Pool2D node to visit
+ * @return N/A
+ */
+ virtual void visit(const L2Pool2D::Implicit::Node &) = 0;
+ /**
+ * @brief Visit an L2Pool2D node with explicit padding
+ * @param[in] node L2Pool2D node to visit
+ * @return N/A
+ */
+ virtual void visit(const L2Pool2D::Explicit::Node &) = 0;
+ /**
+ * @brief Visit an EmbeddingLookup node
+ * @param[in] node EmbeddingLookup node to visit
+ * @return N/A
+ */
+ virtual void visit(const EmbeddingLookup::Node &) = 0;
+ /**
+ * @brief Visit a HashtableLookup node
+ * @param[in] node HashtableLookup node to visit
+ * @return N/A
+ */
+ virtual void visit(const HashtableLookup::Node &) = 0;
+ /**
+ * @brief Visit an L2Normalization node
+ * @param[in] node L2Normalization node to visit
+ * @return N/A
+ */
+ virtual void visit(const L2Normalization::Node &) = 0;
+ /**
+ * @brief Visit a SquaredDifference node
+ * @param[in] node SquaredDifference node to visit
+ * @return N/A
+ */
+ virtual void visit(const SquaredDifference::Node &) = 0;
+ /**
+ * @brief Visit a LocalResponseNormalization node
+ * @param[in] node LocalResponseNormalization node to visit
+ * @return N/A
+ */
+ virtual void visit(const LocalResponseNormalization::Node &) = 0;
+ /**
+ * @brief Visit a DepthToSpace node
+ * @param[in] node DepthToSpace node to visit
+ * @return N/A
+ */
+ virtual void visit(const DepthToSpace::Node &) = 0;
+ /**
+ * @brief Visit a Unpack node
+ * @param[in] node Unpack node to visit
+ * @return N/A
+ */
+ virtual void visit(const Unpack::Node &) = 0;
+ /**
+ * @brief Visit a Neg node
+ * @param[in] node Neg node to visit
+ * @return N/A
+ */
+ virtual void visit(const Neg::Node &) = 0;
+ /**
+ * @brief Visit a Exp node
+ * @param[in] node Exp node to visit
+ * @return N/A
+ */
+ virtual void visit(const Exp::Node &) = 0;
+ /**
+ * @brief Visit a ReduceSum node
+ * @param[in] node ReduceSum node to visit
+ * @return N/A
+ */
+ virtual void visit(const ReduceSum::Node &) = 0;
+ /**
+ * @brief Visit a Equal node
+ * @param[in] node Equal node to visit
+ * @return N/A
+ */
+ virtual void visit(const Equal::Node &) = 0;
+ /**
+ * @brief Visit a BatchToSpaceNd node
+ * @param[in] node BatchToSpaceNd node to visit
+ * @return N/A
+ */
+ virtual void visit(const BatchToSpaceNd::Node &) = 0;
+ /**
+ * @brief Visit a TransposeConv node
+ * @param[in] node TransposeConv node to visit
+ * @return N/A
+ */
+ virtual void visit(const TransposeConv::Node &) = 0;
+ /**
+ * @brief Visit a Pack node
+ * @param[in] node Pack node to visit
+ * @return N/A
+ */
+ virtual void visit(const Pack::Node &) = 0;
+ /**
+ * @brief Visit a Abs node
+ * @param[in] node Abs node to visit
+ * @return N/A
+ */
+ virtual void visit(const Abs::Node &) = 0;
+ /**
+ * @brief Visit a NotEqual node
+ * @param[in] node NotEqual node to visit
+ * @return N/A
+ */
+ virtual void visit(const NotEqual::Node &) = 0;
+ /**
+ * @brief Visit a LogicalAnd node
+ * @param[in] node LogicalAnd node to visit
+ * @return N/A
+ */
+ virtual void visit(const LogicalAnd::Node &) = 0;
+ /**
+ * @brief Visit a LogicalNot node
+ * @param[in] node LogicalNot node to visit
+ * @return N/A
+ */
+ virtual void visit(const LogicalNot::Node &) = 0;
+ /**
+ * @brief Visit a LogicalOr node
+ * @param[in] node LogicalOr node to visit
+ * @return N/A
+ */
+ virtual void visit(const LogicalOr::Node &) = 0;
+};
+
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_NODE_VISITOR_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/NotEqual.cc b/runtime/contrib/pure_arm_compute/src/internal/op/NotEqual.cc
new file mode 100644
index 000000000..2906e214b
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/NotEqual.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/NotEqual.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace NotEqual
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace NotEqual
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace NotEqual
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input1 Tensor Index
+ // 1 -> input2 Tensor Index
+ input1_index = inputs[0];
+ input2_index = inputs[1];
+}
+
+} // namespace NotEqual
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/NotEqual.h b/runtime/contrib/pure_arm_compute/src/internal/op/NotEqual.h
new file mode 100644
index 000000000..0d6130948
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/NotEqual.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_NOT_EQUAL_H__
+#define __INTERNAL_OP_NOT_EQUAL_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace NotEqual
+{
+
+struct Param
+{
+ int32_t output_index;
+
+ int32_t input1_index;
+ int32_t input2_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+} // namespace NotEqual
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace NotEqual
+{
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace NotEqual
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_NOT_EQUAL_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/PReLU.cc b/runtime/contrib/pure_arm_compute/src/internal/op/PReLU.cc
new file mode 100644
index 000000000..25b06505b
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/PReLU.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/PReLU.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace PReLU
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace PReLU
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace PReLU
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input Tensor Index
+ // 1 -> alpha Tensor Index
+ ifm_index = inputs[0];
+ alpha_index = inputs[1];
+}
+
+} // namespace PReLU
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/PReLU.h b/runtime/contrib/pure_arm_compute/src/internal/op/PReLU.h
new file mode 100644
index 000000000..ae754abb4
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/PReLU.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ReLU.h
+ * @brief This file contains accept function and params for ReLU operation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_PRELU_H__
+#define __INTERNAL_OP_PRELU_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace PReLU
+{
+
+/**
+ * @brief Struct of PReLU operation's param
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Output format index */
+
+ int32_t ifm_index; /**< Input format index */
+ int32_t alpha_index; /**< Alpha input index */
+
+ /**
+ * @brief Construct a new Param object for ReLU as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for PReLU with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for PReLU
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for PReLU with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for PReLU
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for PReLU
+ * @return Parameters of PReLU
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for PReLU
+ * @param [in] v Node visitor for invoking visit function of PReLU
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace PReLU
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_PRELU_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Pack.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Pack.cc
new file mode 100644
index 000000000..73f89b840
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Pack.cc
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Pack.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Pack
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Pack
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Pack
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(outputCount == 1);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 .. n - 3 -> Input Tensor Index
+ // n - 2 -> Input Tensor counts (will be ignored)
+ // n - 1 -> Input Axis Index
+ ofm_index = outputs[0];
+ axis_index = inputs[inputCount - 1];
+ // last input is axis along which packing is required
+ for (uint32_t n = 0; n < inputCount - 2; ++n)
+ {
+ ifm_indexes.emplace_back(inputs[n]);
+ }
+}
+
+} // namespace Pack
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Pack.h b/runtime/contrib/pure_arm_compute/src/internal/op/Pack.h
new file mode 100644
index 000000000..c5de01bd8
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Pack.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_PACK_H__
+#define __INTERNAL_OP_PACK_H__
+
+#include "internal/op/Node.h"
+#include <vector>
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Pack
+{
+
+struct Param
+{
+ int32_t ofm_index;
+ // There are N+1 inputs, 0 to N-1 are tensors of same shape
+ // Nth input is axis index along which stack is needed to be done.
+ std::vector<int32_t> ifm_indexes;
+ int32_t axis_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Pack
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_PACK_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Pad.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Pad.cc
new file mode 100644
index 000000000..00938242b
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Pad.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Pad.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Pad
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Pad
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Pad
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input Tensor Index
+ // 1 -> paddings
+ ifm_index = inputs[0];
+ paddings_index = inputs[1];
+}
+} // namespace Pad
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Pad.h b/runtime/contrib/pure_arm_compute/src/internal/op/Pad.h
new file mode 100644
index 000000000..68752a10e
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Pad.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Pad.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines Pad node
+ */
+
+#ifndef __INTERNAL_OP_PAD_H__
+#define __INTERNAL_OP_PAD_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Pad
+{
+
+/**
+ * @brief Struct to manipulate parameter for Pad operation
+ */
+struct Param
+{
+ int32_t ifm_index; //!< index for input
+ int32_t paddings_index; //!< index for padding
+ int32_t ofm_index; //!< index for output
+
+ /**
+ * @brief Default Constructor
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object
+ * @param[in] inputCount the number of inputs
+ * @param[in] inputs pointer for input data
+ * @param[in] outputCount the number of outputs
+ * @param[in] outputs pointer for input data
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define Pad Operation
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new RNN Node object
+ * @param param Parameter for RNN Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Default Destructor
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameter
+ * @return Param reference
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Accept a NodeVisitor so that it can visit this node
+ * @param [in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param; //!< parameter for Pad node
+};
+
+} // namespace Pad
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_PAD_H_
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/RSQRT.cc b/runtime/contrib/pure_arm_compute/src/internal/op/RSQRT.cc
new file mode 100644
index 000000000..d79563d14
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/RSQRT.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/RSQRT.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace RSQRT
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace RSQRT
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace RSQRT
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ // 0 -> input Tensor Index
+ input_index = inputs[0];
+}
+
+} // namespace RSQRT
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/RSQRT.h b/runtime/contrib/pure_arm_compute/src/internal/op/RSQRT.h
new file mode 100644
index 000000000..e39d60241
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/RSQRT.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file RSQRT.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::RSQRT::Param struct
+ * and internal::tflite::op::RSQRT::Node class
+ */
+#ifndef __INTERNAL_OP_RSQRT_H__
+#define __INTERNAL_OP_RSQRT_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace RSQRT
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t output_index; /**< Index of output feature map */
+
+ int32_t input_index; /**< Index of input feature map */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace RSQRT
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_RSQRT_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReLU.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU.cc
new file mode 100644
index 000000000..2f48372af
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/ReLU.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReLU
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace ReLU
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReLU
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input Tensor Index
+ ifm_index = inputs[0];
+}
+
+} // namespace ReLU
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReLU.h b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU.h
new file mode 100644
index 000000000..aaa39b523
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ReLU.h
+ * @brief This file contains accept function and params for ReLU operation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_RELU_H__
+#define __INTERNAL_OP_RELU_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReLU
+{
+
+/**
+ * @brief Struct of ReLU operation's param
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Output format index */
+
+ int32_t ifm_index; /**< Input format index */
+
+ /**
+ * @brief Construct a new Param object for ReLU as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for ReLU with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for ReLU
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for ReLU with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for ReLU
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for ReLU
+ * @return Parameters of ReLU
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for ReLU
+ * @param [in] v Node visitor for invoking visit function of ReLU
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace ReLU
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_RELU_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReLU1.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU1.cc
new file mode 100644
index 000000000..1925ac404
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU1.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/ReLU1.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReLU1
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace ReLU1
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReLU1
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input Tensor Index
+ ifm_index = inputs[0];
+}
+
+} // namespace ReLU1
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReLU1.h b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU1.h
new file mode 100644
index 000000000..330445af8
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU1.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ReLU1.h
+ * @brief This file contains accept function and params for ReLU1 operation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_RELU1_H__
+#define __INTERNAL_OP_RELU1_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReLU1
+{
+
+/**
+ * @brief Struct of ReLU1 operation's param
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Output format index */
+
+ int32_t ifm_index; /**< Input format index */
+
+ /**
+ * @brief Construct a new Param object for ReLU1 as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for ReLU1 with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for ReLU1
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for ReLU1 with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for ReLU1
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for ReLU1
+ * @return Parameters of ReLU1
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for ReLU1
+ * @param [in] v Node visitor for invoking visit function of ReLU1
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace ReLU1
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_RELU1_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReLU6.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU6.cc
new file mode 100644
index 000000000..e94ddcf15
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU6.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/ReLU6.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReLU6
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace ReLU6
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReLU6
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> input Tensor Index
+ ifm_index = inputs[0];
+}
+
+} // namespace ReLU6
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReLU6.h b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU6.h
new file mode 100644
index 000000000..6fc2c24fe
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReLU6.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ReLU6.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::ReLU6 class
+ */
+#ifndef __INTERNAL_OP_RELU6_H__
+#define __INTERNAL_OP_RELU6_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReLU6
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /** Index of output feature map */
+
+ int32_t ifm_index; /** Index of input feature map */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace ReLU6
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_RELU6_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMax.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMax.cc
new file mode 100644
index 000000000..7a337eabf
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMax.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/ReduceMax.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReduceMax
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace ReduceMax
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReduceMax
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Axis Tensor Index
+ ifm_index = inputs[0];
+ axis_index = inputs[1];
+}
+
+} // namespace ReduceMax
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMax.h b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMax.h
new file mode 100644
index 000000000..77d8bd869
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMax.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ReduceMax.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::ReduceMax::Param struct
+ * and internal::tflite::op::ReduceMax::Node class
+ */
+#ifndef __INTERNAL_OP_REDUCEMAX_H__
+#define __INTERNAL_OP_REDUCEMAX_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReduceMax
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Index of output feature map */
+
+ int32_t ifm_index; /**< Index of input feature map */
+ int32_t axis_index; /**< Index of axis */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace ReduceMax
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_REDUCEMAX_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMin.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMin.cc
new file mode 100644
index 000000000..72b6079d4
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMin.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/ReduceMin.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReduceMin
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace ReduceMin
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReduceMin
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Axis Tensor Index
+ ifm_index = inputs[0];
+ axis_index = inputs[1];
+}
+
+} // namespace ReduceMin
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMin.h b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMin.h
new file mode 100644
index 000000000..5dd82ec43
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceMin.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ReduceMin.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::ReduceMin::Param struct
+ * and internal::tflite::op::ReduceMin::Node class
+ */
+#ifndef __INTERNAL_OP_REDUCEMIN_H__
+#define __INTERNAL_OP_REDUCEMIN_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReduceMin
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Index of output feature map */
+
+ int32_t ifm_index; /**< Index of input feature map */
+ int32_t axis_index; /**< Index of axis */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace ReduceMin
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_REDUCEMIN_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReduceSum.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceSum.cc
new file mode 100644
index 000000000..4d83c1734
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceSum.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/ReduceSum.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReduceSum
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace ReduceSum
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReduceSum
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Axis Tensor Index
+ ifm_index = inputs[0];
+ axis_index = inputs[1];
+}
+
+} // namespace ReduceSum
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ReduceSum.h b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceSum.h
new file mode 100644
index 000000000..9c661f63a
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ReduceSum.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_REDUCESUM_H__
+#define __INTERNAL_OP_REDUCESUM_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ReduceSum
+{
+
+struct Param
+{
+ int32_t ofm_index;
+
+ int32_t ifm_index;
+ int32_t axis_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace ReduceSum
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_REDUCESUM_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Reshape.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Reshape.cc
new file mode 100644
index 000000000..862ed30c7
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Reshape.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Reshape.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Reshape
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Reshape
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Reshape
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> A tensor, specifying the tensor to be reshaped.
+ // 1 -> A 1-D tensor of type ANEURALNETWORKS_TENSOR_INT32, defining the shape of the output
+ // tensor
+ input_index = inputs[0];
+ shape_index = inputs[1];
+}
+
+} // namespace Reshape
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Reshape.h b/runtime/contrib/pure_arm_compute/src/internal/op/Reshape.h
new file mode 100644
index 000000000..7152eaece
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Reshape.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Reshape.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines Reshape node
+ */
+
+#ifndef __INTERNAL_OP_RESHAPE_H__
+#define __INTERNAL_OP_RESHAPE_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Reshape
+{
+
+/**
+ * @brief Struct to manipulate parameter for Reshape operation
+ */
+struct Param
+{
+ int32_t output_index; //!< index for output feature map
+
+ int32_t input_index; //!< index for input feature map
+ int32_t shape_index; //!< index for shape
+
+ /**
+ * @brief Default Constructor
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object
+ * @param[in] inputCount the number of inputs
+ * @param[in] inputs pointer for input data
+ * @param[in] outputCount the number of outputs
+ * @param[in] outputs pointer for input data
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define Reshape Operation
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Reshape Node object
+ * @param param Parameter for Reshape Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Default Destructor
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameter
+ * @return Param reference
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Accept a NodeVisitor so that it can visit this node
+ * @param [in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param; //!< parameter for Reshape node
+};
+
+} // namespace Reshape
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_RESHAPE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ResizeBilinear.cc b/runtime/contrib/pure_arm_compute/src/internal/op/ResizeBilinear.cc
new file mode 100644
index 000000000..02ec20cb1
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ResizeBilinear.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/ResizeBilinear.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ResizeBilinear
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace ResizeBilinear
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ResizeBilinear
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 3 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> IFM Index
+ // 1 -> Height Index
+ // 2 -> Width Index
+ ifm_index = inputs[0];
+ height_index = inputs[1];
+ width_index = inputs[2];
+}
+
+} // namespace ResizeBilinear
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/ResizeBilinear.h b/runtime/contrib/pure_arm_compute/src/internal/op/ResizeBilinear.h
new file mode 100644
index 000000000..f2eab4aaf
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/ResizeBilinear.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file ResizeBilinear.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::ResizeBilinear::Param struct
+ * and internal::tflite::op::ResizeBilinear::Node class
+ */
+#ifndef __INTERNAL_OP_RESIZE_BILINEAR_H__
+#define __INTERNAL_OP_RESIZE_BILINEAR_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace ResizeBilinear
+{
+
+/**
+ * @brief Struct to have indexes for ResizeBilinear operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Index of output feature map */
+
+ int32_t ifm_index; /**< Index of input feature map */
+ int32_t height_index; /**< Index of height */
+ int32_t width_index; /**< Index of width */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an ResizeBilinear operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace ResizeBilinear
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_RESIZE_BILINEAR_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Rnn.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Rnn.cc
new file mode 100644
index 000000000..3f19fca3b
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Rnn.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Rnn.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace RNN
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace RNN
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace RNN
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 6 && outputCount == 2);
+
+ output_index = outputs[0];
+ hidden_state_out_index = outputs[1];
+
+ input_index = inputs[0];
+ weights_index = inputs[1];
+ recurrent_weights_index = inputs[2];
+ bias_index = inputs[3];
+ hidden_state_in_index = inputs[4];
+ fused_activation_index = inputs[5];
+}
+
+} // namespace RNN
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Rnn.h b/runtime/contrib/pure_arm_compute/src/internal/op/Rnn.h
new file mode 100644
index 000000000..7b2a10843
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Rnn.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Rnn.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines RNN node
+ */
+
+#ifndef __INTERNAL_OP_RNN_H__
+#define __INTERNAL_OP_RNN_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace RNN
+{
+
+/**
+ * @brief Struct to manipulate parameter for RNN operation
+ */
+struct Param
+{
+ int32_t output_index; //!< index for ouuput
+ int32_t hidden_state_out_index; //!< index for hidden state output
+
+ int32_t input_index; //!< index for input
+ int32_t weights_index; //!< index for weight
+ int32_t recurrent_weights_index; //!< index for recurrent weights
+ int32_t bias_index; //!< index for bias
+ int32_t hidden_state_in_index; //!< index for hidden state input
+ int32_t fused_activation_index; //!< index for fused activation
+
+ /**
+ * @brief Default Constructor
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object
+ * @param[in] inputCount the number of inputs
+ * @param[in] inputs pointer for input data
+ * @param[in] outputCount the number of outputs
+ * @param[in] outputs pointer for input data
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define RNN Operation
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new RNN Node object
+ * @param param Parameter for RNN Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Default Destructor
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameter
+ * @return Param reference
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Accept a NodeVisitor so that it can visit this node
+ * @param [in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param; //!< parameter for RNN node
+};
+
+} // namespace RNN
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_RNN_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SQRT.cc b/runtime/contrib/pure_arm_compute/src/internal/op/SQRT.cc
new file mode 100644
index 000000000..70ce42e9c
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/SQRT.cc
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/SQRT.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace SQRT
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace SQRT
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace SQRT
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ // 0 -> input Tensor Index
+ input_index = inputs[0];
+}
+
+} // namespace SQRT
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SQRT.h b/runtime/contrib/pure_arm_compute/src/internal/op/SQRT.h
new file mode 100644
index 000000000..85dfb97a7
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/SQRT.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file SQRT.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::SQRT::Param struct
+ * and internal::tflite::op::SQRT::Node class
+ */
+#ifndef __INTERNAL_OP_SQRT_H__
+#define __INTERNAL_OP_SQRT_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace SQRT
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t output_index; /**< Index of output feature map */
+
+ int32_t input_index; /**< Index of input feature map */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace SQRT
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_SQRT_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Softmax.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Softmax.cc
new file mode 100644
index 000000000..516a0fa04
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Softmax.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Softmax.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Softmax
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Softmax
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Softmax
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> A 2-D or 4-D tensor, specifying the tensor to be reshaped.
+ // 1 -> FLOAT32 value, specifying the positive scaling factor for the exponent, beta.
+ input_index = inputs[0];
+ scale_index = inputs[1];
+}
+
+} // namespace Softmax
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Softmax.h b/runtime/contrib/pure_arm_compute/src/internal/op/Softmax.h
new file mode 100644
index 000000000..6e631af5f
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Softmax.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Softmax.h
+ * @brief This file contains accept function and params for Softmax operation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_SOFTMAX_H__
+#define __INTERNAL_OP_SOFTMAX_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Softmax
+{
+
+/**
+ * @brief Struct of Softmax operation's param
+ */
+struct Param
+{
+ int32_t output_index; /**< Output index */
+
+ int32_t input_index; /**< Input index */
+ int32_t scale_index; /**< Scale index */
+
+ /**
+ * @brief Construct a new Param object for Softmax as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for Softmax with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for Softmax
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for Softmax with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for Softmax
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for Softmax
+ * @return Parameters of Softmax
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for Softmax
+ * @param [in] v Node visitor for invoking visit function of Softmax
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Softmax
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_SOFTMAX_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToBatchND.cc b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToBatchND.cc
new file mode 100644
index 000000000..9ab026cf4
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToBatchND.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/SpaceToBatchND.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace SpaceToBatchND
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace SpaceToBatchND
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace SpaceToBatchND
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 3 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Block size Index
+ // 2 -> Padding size Index
+ input_index = inputs[0];
+ block_size_index = inputs[1];
+ padding_size_index = inputs[2];
+}
+
+} // namespace SpaceToBatchND
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToBatchND.h b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToBatchND.h
new file mode 100644
index 000000000..650d068f4
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToBatchND.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_SPACETOBATCHND_H__
+#define __INTERNAL_OP_SPACETOBATCHND_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace SpaceToBatchND
+{
+
+struct Param
+{
+ int32_t output_index;
+
+ int32_t input_index;
+ int32_t block_size_index;
+ int32_t padding_size_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace SpaceToBatchND
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_SPACETOBATCHND_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToDepth.cc b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToDepth.cc
new file mode 100644
index 000000000..2fb587be0
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToDepth.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/SpaceToDepth.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace SpaceToDepth
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace SpaceToDepth
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace SpaceToDepth
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ output_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Block size Index
+ input_index = inputs[0];
+ block_size_index = inputs[1];
+}
+
+} // namespace SpaceToDepth
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToDepth.h b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToDepth.h
new file mode 100644
index 000000000..2e624006a
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/SpaceToDepth.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file SpaceToDepth.h
+ * @brief This file contains accept function and params for SpaceToDepth operation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_SPACETODEPTH_H__
+#define __INTERNAL_OP_SPACETODEPTH_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace SpaceToDepth
+{
+
+/**
+ * @brief Struct of SpaceToDepth operation's param
+ */
+struct Param
+{
+ int32_t output_index; /**< Output index */
+
+ int32_t input_index; /**< Input index */
+ int32_t block_size_index; /**< Block size index */
+
+ /**
+ * @brief Construct a new Param object for SpaceToDepth as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for SpaceToDepth with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for SpaceToDepth
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for SpaceToDepth with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for SpaceToDepth
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for SpaceToDepth
+ * @return Parameters of SpaceToDepth
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for SpaceToDepth
+ * @param [in] v Node visitor for invoking visit function of SpaceToDepth
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace SpaceToDepth
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_SPACETODEPTH_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Split.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Split.cc
new file mode 100644
index 000000000..6457a106a
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Split.cc
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Split.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Split
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Split
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Split
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 3);
+
+ // Each input should be interpreted as follows:
+ // 0 -> An n-D tensor, specifying the tensor to be split.
+ // 1 -> A 0-D int32 tensor, indicating the dimension along which to split.
+ // 2 -> A 0-D int32 tensor, indicating the number of outputs
+ // (It can be ignored on pacl becasue pacl don't support dynamic tensor shape,
+ // and can be used for verification only)
+ ifm_index = inputs[0];
+ axis_index = inputs[1];
+
+ // Each output should be interpreted as follow:
+ // [0, outputCount) -> An n-D tensor.
+ for (uint32_t n = 0; n < outputCount; ++n)
+ {
+ ofm_indexes.emplace_back(outputs[n]);
+ }
+}
+
+} // namespace Split
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Split.h b/runtime/contrib/pure_arm_compute/src/internal/op/Split.h
new file mode 100644
index 000000000..cb5f3eb2d
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Split.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Split.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines Split node
+ */
+
+#ifndef __INTERNAL_OP_SPLIT_H__
+#define __INTERNAL_OP_SPLIT_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+#include <vector>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Split
+{
+
+/**
+ * @brief Struct to manipulate parameter for Split operation
+ */
+struct Param
+{
+ int32_t ifm_index; //!< index for input feature map
+ int32_t axis_index; //!< index for axis
+
+ std::vector<int32_t> ofm_indexes; //!< index for output feature map
+
+ /**
+ * @brief Default Constructor
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object
+ * @param[in] inputCount the number of inputs
+ * @param[in] inputs pointer for input data
+ * @param[in] outputCount the number of outputs
+ * @param[in] outputs pointer for input data
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define Split Operation
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Split Node object
+ * @param param Parameter for Split Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Default Destructor
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameter
+ * @return Param reference
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Accept a NodeVisitor so that it can visit this node
+ * @param [in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param; //!< parameter for Split node
+};
+
+} // namespace Split
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_SPLIT_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SquaredDifference.cc b/runtime/contrib/pure_arm_compute/src/internal/op/SquaredDifference.cc
new file mode 100644
index 000000000..f6c8bc5df
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/SquaredDifference.cc
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/SquaredDifference.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace SquaredDifference
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace SquaredDifference
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace SquaredDifference
+{
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> LHS Tensor Index
+ // 1 -> RHS Tensor Index
+ lhs_index = inputs[0];
+ rhs_index = inputs[1];
+}
+
+} // namespace SquaredDifference
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/SquaredDifference.h b/runtime/contrib/pure_arm_compute/src/internal/op/SquaredDifference.h
new file mode 100644
index 000000000..ecbb03209
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/SquaredDifference.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file SquaredDifference.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::SquaredDifference::Param struct
+ * and internal::tflite::op::SquaredDifference::Node class
+ */
+#ifndef __INTERNAL_OP_SQUAREDDIFFERENCE_H__
+#define __INTERNAL_OP_SQUAREDDIFFERENCE_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace SquaredDifference
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Index of output feature map */
+
+ int32_t lhs_index; /**< Index of lhs */
+ int32_t rhs_index; /**< Index of rhs */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace SquaredDifference
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_SQUAREDDIFFERENCE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Squeeze.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Squeeze.cc
new file mode 100644
index 000000000..6e89cd321
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Squeeze.cc
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Squeeze.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Squeeze
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Squeeze
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Squeeze
+{
+// dims_index is optional input
+// if dims_index is not provided, dims_index is set to -1
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 || inputCount == 2);
+ assert(outputCount == 1);
+
+ output_index = outputs[0];
+
+ input_index = inputs[0];
+
+ // dims_index_optional = -1 by default
+ if (inputCount == 2)
+ dims_index_optional = inputs[1];
+}
+
+} // namespace Squeeze
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Squeeze.h b/runtime/contrib/pure_arm_compute/src/internal/op/Squeeze.h
new file mode 100644
index 000000000..d5f36f85f
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Squeeze.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Squeeze.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines internal::tflite::op::Squeeze::Param struct
+ * and internal::tflite::op::Squeeze::Node class
+ */
+#ifndef __INTERNAL_OP_SQUEEZE_H__
+#define __INTERNAL_OP_SQUEEZE_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Squeeze
+{
+
+/**
+ * @brief Struct to have indexes for operation parameter
+ */
+struct Param
+{
+ int32_t output_index; /**< Index of output feature map */
+
+ int32_t input_index; /**< Index of input feature map */
+ // optional param. default is -1
+ int32_t dims_index_optional = -1; /**< Index of dims */
+ /**
+ * @brief Construct as default
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object with params
+ * @param[in] inputCount Count of inputs
+ * @param[in] inputs Pointer of inputs
+ * @param[in] outputCount Count of outputs
+ * @param[in] outputs Pointer of outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to represent an operation of data structure
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object with param
+ * @param[in] param Param object that makes up a Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destruct as default
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get a reference of Param object
+ * @return Reference of Param object
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Visit this Node by NodeVisitor
+ * @param[in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Squeeze
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_SQUEEZE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/StridedSlice.cc b/runtime/contrib/pure_arm_compute/src/internal/op/StridedSlice.cc
new file mode 100644
index 000000000..6e7958954
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/StridedSlice.cc
@@ -0,0 +1,88 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/StridedSlice.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace StridedSlice
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace StridedSlice
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace StridedSlice
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 7 && outputCount == 1);
+
+ outputData_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> An n-D tensor, specifying the tensor to be sliced.
+ // 1 -> A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the starts of
+ // the dimensions of the input tensor to be sliced. The length must be
+ // of rank(input0).
+ // 2 -> A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the ends of
+ // the dimensions of the input tensor to be sliced. The length must be
+ // of rank(input0).
+ // 3 -> A 1-D Tensor of {@link ANEURALNETWORKS_TENSOR_INT32}, the strides of
+ // the dimensions of the input tensor to be sliced. The length must be
+ // of rank(input0).
+ // 4 -> An {@link ANEURALNETWORKS_INT32} scalar, begin_mask. If the ith bit
+ // of begin_mask is set, begin[i] is ignored and the fullest possible
+ // range in that dimension is used instead.
+ // 5 -> An {@link ANEURALNETWORKS_INT32} scalar, end_mask. If the ith bit of
+ // end_mask is set, end[i] is ignored and the fullest possible range in
+ // that dimension is used instead.
+ // 6 -> An {@link ANEURALNETWORKS_INT32} scalar, shrink_axis_mask. An int32
+ // mask. If the ith bit of shrink_axis_mask is set, it implies that the
+ // ith specification shrinks the dimensionality by 1. A slice of size 1
+ // starting from begin[i] in the dimension must be preserved.
+ inputData_index = inputs[0];
+ startData_index = inputs[1];
+ endData_index = inputs[2];
+ stridesData_index = inputs[3];
+ beginMask_index = inputs[4];
+ endMask_index = inputs[5];
+ shrinkAxisMask_index = inputs[6];
+}
+
+} // namespace StridedSlice
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/StridedSlice.h b/runtime/contrib/pure_arm_compute/src/internal/op/StridedSlice.h
new file mode 100644
index 000000000..21dbb9e68
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/StridedSlice.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file StridedSlice.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines StridedSlice node
+ */
+
+#ifndef __INTERNAL_OP_STRIDEDSLICE_H__
+#define __INTERNAL_OP_STRIDEDSLICE_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace StridedSlice
+{
+
+/**
+ * @brief Struct to manipulate parameter for StridedSlice operation
+ */
+struct Param
+{
+ int32_t outputData_index; //!< index for output data
+
+ int32_t inputData_index; //!< index for input data
+ int32_t startData_index; //!< index where slicing start from
+ int32_t endData_index; //!< index where slicing ends to
+ int32_t stridesData_index; //!< index for stride value
+ int32_t beginMask_index; //!< index for beginmask
+ int32_t endMask_index; //!< index for endmask
+ int32_t shrinkAxisMask_index; //!< index for shrink axis
+
+ /**
+ * @brief Default Constructor
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object
+ * @param[in] inputCount the number of inputs
+ * @param[in] inputs pointer for input data
+ * @param[in] outputCount the number of outputs
+ * @param[in] outputs pointer for input data
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define StridedSlice Operation
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new StridedSlice Node object
+ * @param param Parameter for StridedSlice Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Default Destructor
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameter
+ * @return Param reference
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Accept a NodeVisitor so that it can visit this node
+ * @param [in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param; //!< parameter for StridedSlice node
+};
+
+} // namespace StridedSlice
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_STRIDEDSLICE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Sub.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Sub.cc
new file mode 100644
index 000000000..74efe3c3a
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Sub.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Sub.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Sub
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Sub
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Sub
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 3 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> LHS Tensor Index
+ // 1 -> RHS Tensor Index
+ // 2 -> Activation Index
+ lhs_index = inputs[0];
+ rhs_index = inputs[1];
+ activation_index = inputs[2];
+}
+
+} // namespace Sub
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Sub.h b/runtime/contrib/pure_arm_compute/src/internal/op/Sub.h
new file mode 100644
index 000000000..864359d1e
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Sub.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Sub.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines SUB Node
+ */
+
+#ifndef __INTERNAL_OP_SUB_H__
+#define __INTERNAL_OP_SUB_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Sub
+{
+
+/**
+ * @brief Struct to manipulate parameters for SUB
+ */
+struct Param
+{
+ int32_t ofm_index; //!< index for output feature map
+
+ int32_t lhs_index; //!< index for left-hand side
+ int32_t rhs_index; //!< index for right-hand side
+ int32_t activation_index; //!< index for activation function
+
+ /**
+ * @brief Default Constructor
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object
+ * @param[in] inputCount the number of inputs
+ * @param[in] inputs pointer for input data
+ * @param[in] outputCount the number of outputs
+ * @param[in] outputs pointer for input data
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define SUB Operation
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Sub Node object
+ * @param param Parameter for Sub Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Default Destructor
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameter
+ * @return Param reference
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Accept a NodeVisitor so that it can visit this node
+ * @param [in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param; //!< parameter for SUB node
+};
+
+} // namespace Sub
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_SUB_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Tanh.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Tanh.cc
new file mode 100644
index 000000000..fbd72abe4
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Tanh.cc
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Tanh.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Tanh
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Tanh
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Tanh
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 1 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ ifm_index = inputs[0];
+}
+
+} // namespace Tanh
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Tanh.h b/runtime/contrib/pure_arm_compute/src/internal/op/Tanh.h
new file mode 100644
index 000000000..fd87297f1
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Tanh.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Tanh.h
+ * @ingroup COM_AI_RUNTIME
+ * @brief This file defines TANH node
+ */
+
+#ifndef __INTERNAL_OP_TANH_H__
+#define __INTERNAL_OP_TANH_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Tanh
+{
+
+/**
+ * @brief Struct to manipulate parameter for hyperbolic tangent operation
+ */
+struct Param
+{
+ int32_t ofm_index; //!< index for output feature map
+
+ int32_t ifm_index; //!< index for input feature map
+
+ /**
+ * @brief Default Constructor
+ */
+ Param() = default;
+ /**
+ * @brief Construct a new Param object
+ * @param[in] inputCount the number of inputs
+ * @param[in] inputs pointer for input data
+ * @param[in] outputCount the number of outputs
+ * @param[in] outputs pointer for input data
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define Tanh Operation
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Tanh Node object
+ * @param param Parameter for Tanh Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Default Destructor
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameter
+ * @return Param reference
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Accept a NodeVisitor so that it can visit this node
+ * @param [in] v Visitor
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param; //!< parameter for Tanh node
+};
+
+} // namespace Tanh
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_TANH_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/TopKV2.cc b/runtime/contrib/pure_arm_compute/src/internal/op/TopKV2.cc
new file mode 100644
index 000000000..74d9a69d2
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/TopKV2.cc
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/TopKV2.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace TopKV2
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace TopKV2
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace TopKV2
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 2);
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Index for Output Values
+ // 1 -> Index for Output Indices
+ outputValues_index = outputs[0];
+ outputIndices_index = outputs[1];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Index for Input Data
+ // 1 -> Index for K
+ inputData_index = inputs[0];
+ k_index = inputs[1];
+}
+
+} // namespace TopKV2
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/TopKV2.h b/runtime/contrib/pure_arm_compute/src/internal/op/TopKV2.h
new file mode 100644
index 000000000..02b7827e9
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/TopKV2.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file TopKV2.h
+ * @brief This file contains accept function and params for TopKV2 operation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_TOPKV2_H__
+#define __INTERNAL_OP_TOPKV2_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace TopKV2
+{
+
+/**
+ * @brief Struct of TopKV2 operation's param
+ */
+struct Param
+{
+ int32_t outputValues_index; /**< Output values index */
+ int32_t outputIndices_index; /**< Output indices index */
+
+ int32_t inputData_index; /**< Input data index */
+ int32_t k_index; /**< K value index */
+
+ /**
+ * @brief Construct a new Param object for TopKV2 as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for TopKV2 with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for TopKV2
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for TopKV2 with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for TopKV2
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for TopKV2
+ * @return Parameters of TopKV2
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for TopKV2
+ * @param [in] v Node visitor for invoking visit function of TopKV2
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace TopKV2
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_TOPKV2_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Transpose.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Transpose.cc
new file mode 100644
index 000000000..0529e3790
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Transpose.cc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Transpose.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Transpose
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Transpose
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Transpose
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 2 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Input Tensor Index
+ // 1 -> Permutation Tensor Index
+ ifm_index = inputs[0];
+ permu_index = inputs[1];
+}
+
+} // namespace Transpose
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Transpose.h b/runtime/contrib/pure_arm_compute/src/internal/op/Transpose.h
new file mode 100644
index 000000000..bb01bf322
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Transpose.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file Transpose.h
+ * @brief This file contains accept function and params for Transpose operation
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __INTERNAL_OP_TRANSPOSE_H__
+#define __INTERNAL_OP_TRANSPOSE_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Transpose
+{
+
+/**
+ * @brief Struct of Transpose operation's param
+ */
+struct Param
+{
+ int32_t ofm_index; /**< Output format index */
+
+ int32_t ifm_index; /**< Input format index */
+ int32_t permu_index; /**< Permutation index */
+
+ /**
+ * @brief Construct a new Param object for Transpose as default
+ */
+ Param() = default;
+
+ /**
+ * @brief Construct a new Param object for Transpose with params
+ * @param [in] inputCount The number of input
+ * @param [in] inputs Array containing inputs
+ * @param [in] outputCount The number of output
+ * @param [in] outputs Array containing outputs
+ */
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+/**
+ * @brief Class to define operation node for Transpose
+ */
+class Node final : public op::Node
+{
+public:
+ /**
+ * @brief Construct a new Node object for Transpose with param
+ * @param [in] param Parameters for Node
+ */
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ /**
+ * @brief Destroy the Node object for Transpose
+ */
+ virtual ~Node() = default;
+
+public:
+ /**
+ * @brief Get parameters for Transpose
+ * @return Parameters of Transpose
+ */
+ const Param &param(void) const { return _param; }
+
+public:
+ /**
+ * @brief Function for accepting node for Transpose
+ * @param [in] v Node visitor for invoking visit function of Transpose
+ * @return N/A
+ */
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Transpose
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_TRANSPOSE_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/TransposeConv.cc b/runtime/contrib/pure_arm_compute/src/internal/op/TransposeConv.cc
new file mode 100644
index 000000000..502eff525
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/TransposeConv.cc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/TransposeConv.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace TransposeConv
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace TransposeConv
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace TransposeConv
+{
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 6 && outputCount == 1);
+
+ ofm_index = outputs[0];
+
+ // Each input should be interpreted as follows:
+ //
+ // 0 -> Output Shape Index
+ // 1 -> Weights Index
+ // 2 -> Input Tensor Index
+ // 3 -> Padding Type
+ // 4 -> Stride width
+ // 5 -> Stride height
+
+ op_shape_index = inputs[0];
+ ker_index = inputs[1];
+ ifm_index = inputs[2];
+ padding_index = inputs[3];
+ hstride_index = inputs[4];
+ vstride_index = inputs[5];
+}
+
+} // namespace TransposeConv
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/TransposeConv.h b/runtime/contrib/pure_arm_compute/src/internal/op/TransposeConv.h
new file mode 100644
index 000000000..b0122f82d
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/TransposeConv.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_TRANSPOSECONV_H__
+#define __INTERNAL_OP_TRANSPOSECONV_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace TransposeConv
+{
+
+struct Param
+{
+ int32_t ofm_index;
+
+ int32_t op_shape_index;
+ int32_t ker_index;
+ int32_t ifm_index;
+ int32_t padding_index;
+ int32_t hstride_index;
+ int32_t vstride_index;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace TransposeConv
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_TRANSPOSECONV_H__
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Unpack.cc b/runtime/contrib/pure_arm_compute/src/internal/op/Unpack.cc
new file mode 100644
index 000000000..a1be0280c
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Unpack.cc
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "internal/op/Unpack.h"
+#include "internal/op/NodeVisitor.h"
+
+#include <cassert>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Unpack
+{
+
+void Node::accept(NodeVisitor &&v) const { v.visit(*this); }
+
+} // namespace Unpack
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Unpack
+{
+// There are three inputs: tensor which is to be unpacked,
+// axis along which tensor needs to be unpacked
+// and number of splits along the axis.
+
+Param::Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ assert(inputCount == 3);
+
+ ifm_index = inputs[0];
+
+ for (uint32_t n = 0; n < outputCount; ++n)
+ {
+ ofm_indexes.emplace_back(outputs[n]);
+ }
+ num_split_index = inputs[1];
+ axis_index = inputs[2];
+}
+
+} // namespace Unpack
+} // namespace op
+} // namespace tflite
+} // namespace internal
diff --git a/runtime/contrib/pure_arm_compute/src/internal/op/Unpack.h b/runtime/contrib/pure_arm_compute/src/internal/op/Unpack.h
new file mode 100644
index 000000000..575e3d024
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/internal/op/Unpack.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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 __INTERNAL_OP_UNPACK_H__
+#define __INTERNAL_OP_UNPACK_H__
+
+#include "internal/op/Node.h"
+
+#include <cstdint>
+#include <vector>
+
+namespace internal
+{
+namespace tflite
+{
+namespace op
+{
+namespace Unpack
+{
+
+struct Param
+{
+ int32_t ifm_index;
+ int32_t axis_index;
+ int32_t num_split_index;
+ // There are N outputs after Unpacking Input Tensor along axis
+ std::vector<int32_t> ofm_indexes;
+
+ Param() = default;
+ Param(uint32_t inputCount, const uint32_t *inputs, uint32_t outputCount, const uint32_t *outputs);
+};
+
+class Node final : public op::Node
+{
+public:
+ Node(const Param &param) : _param(param)
+ {
+ // DO NOTHING
+ }
+
+public:
+ virtual ~Node() = default;
+
+public:
+ const Param &param(void) const { return _param; }
+
+public:
+ void accept(NodeVisitor &&) const override;
+
+private:
+ const Param _param;
+};
+
+} // namespace Unpack
+} // namespace op
+} // namespace tflite
+} // namespace internal
+
+#endif // __INTERNAL_OP_UNPACK_H__
diff --git a/runtime/contrib/pure_arm_compute/src/library_info.cc b/runtime/contrib/pure_arm_compute/src/library_info.cc
new file mode 100644
index 000000000..02a616094
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/library_info.cc
@@ -0,0 +1,17 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+volatile static const char info[] = "library information : runtime=pure_arm_compute";
diff --git a/runtime/contrib/pure_arm_compute/src/logging.h b/runtime/contrib/pure_arm_compute/src/logging.h
new file mode 100644
index 000000000..447da03e2
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/logging.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file logging.h
+ * @brief This file contains Context class for logging.
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __PURE_ARM_COMPUTE_LOGGING_H__
+#define __PURE_ARM_COMPUTE_LOGGING_H__
+
+#include <iostream>
+
+namespace logging
+{
+
+/**
+ * @brief class to define Context for logging
+ */
+class Context
+{
+public:
+ /**
+ * @brief Construct default
+ */
+ Context() : _enabled{false}
+ {
+ auto env = std::getenv("PURE_ARM_COMPUTE_LOG_ENABLE");
+
+ if (env && std::strtol(env, NULL, 0) > 0)
+ {
+ _enabled = true;
+ }
+ }
+
+public:
+ /**
+ * @brief Get @c true if PURE_ARM_COMPUTE_LOG_ENABLE has been set as environment value, otherwise
+ * @c false
+ * @return @c true if PURE_ARM_COMPUTE_LOG_ENABLE has been set as environment value, otherwise @c
+ * false
+ */
+ bool enabled(void) const { return _enabled; }
+
+private:
+ bool _enabled;
+};
+
+/**
+ * @brief static Context class for logging
+ */
+static Context ctx;
+
+} // namespace logging
+
+#define VERBOSE(name) \
+ if (::logging::ctx.enabled()) \
+ std::cout << "[" << #name << "] "
+
+#endif // __PURE_ARM_COMPUTE_LOGGING_H__
diff --git a/runtime/contrib/pure_arm_compute/src/memory.cc b/runtime/contrib/pure_arm_compute/src/memory.cc
new file mode 100644
index 000000000..9e999661a
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/memory.cc
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <NeuralNetworks.h>
+#include <sys/mman.h>
+#include <memory>
+
+#include "cpp14/memory.h"
+#include "memory.h"
+
+int ANeuralNetworksMemory_createFromFd(size_t size, int protect, int fd, size_t offset,
+ ANeuralNetworksMemory **memory)
+{
+ if (memory == nullptr)
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ // Use unique pointer to avoid memory leak
+ std::unique_ptr<ANeuralNetworksMemory> memory_ptr =
+ nnfw::cpp14::make_unique<ANeuralNetworksMemory>(size, protect, fd, offset);
+ if (memory_ptr == nullptr)
+ {
+ return ANEURALNETWORKS_OUT_OF_MEMORY;
+ }
+ *memory = memory_ptr.release();
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksMemory_free(ANeuralNetworksMemory *memory) { delete memory; }
+
+//
+// ANeuralNetworksMemory
+//
+ANeuralNetworksMemory::ANeuralNetworksMemory(size_t size, int protect, int fd, size_t offset)
+{
+ _base = reinterpret_cast<uint8_t *>(mmap(nullptr, size, protect, MAP_PRIVATE, fd, offset));
+ _size = size;
+}
+
+ANeuralNetworksMemory::~ANeuralNetworksMemory() { munmap(reinterpret_cast<void *>(_base), _size); }
diff --git a/runtime/contrib/pure_arm_compute/src/memory.h b/runtime/contrib/pure_arm_compute/src/memory.h
new file mode 100644
index 000000000..ffac26ef6
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/memory.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file execution.h
+ * @brief This file defines ANeuralNetworksMemory class for handling Memory NNAPI
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __MEMORY_H__
+#define __MEMORY_H__
+
+#include <cstdint>
+
+/**
+ * @brief struct to define Memory NNAPI
+ */
+struct ANeuralNetworksMemory
+{
+public:
+ /**
+ * @brief Constructor with params
+ * @param [in] size The requested size in bytes
+ * @param [in] protect The desired memory protection for the mapping
+ * @param [in] fd The requested file descriptor
+ * @param [in] offset The offset to the beginning of the file of the area to map
+ */
+ ANeuralNetworksMemory(size_t size, int protect, int fd, size_t offset);
+ /**
+ * @brief Destructor default
+ */
+ ~ANeuralNetworksMemory();
+
+public:
+ /**
+ * @brief Get size
+ * @return size
+ */
+ size_t size(void) const { return _size; }
+ /**
+ * @brief Get base pointer
+ * @return base pointer
+ */
+ uint8_t *base(void) { return _base; }
+ /**
+ * @brief Get base pointer
+ * @return const base pointer
+ */
+ const uint8_t *base(void) const { return _base; }
+
+private:
+ size_t _size;
+ uint8_t *_base;
+};
+
+#endif // __MEMORY_H__
diff --git a/runtime/contrib/pure_arm_compute/src/model.cc b/runtime/contrib/pure_arm_compute/src/model.cc
new file mode 100644
index 000000000..ddca589db
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/model.cc
@@ -0,0 +1,1082 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <NeuralNetworks.h>
+#include <NeuralNetworksEx.h>
+
+#include <cassert>
+#include <stdexcept>
+
+#include "model.h"
+#include "memory.h"
+
+int ANeuralNetworksModel_create(ANeuralNetworksModel **model)
+{
+ if (model == nullptr)
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ ANeuralNetworksModel *model_ptr = new ANeuralNetworksModel{};
+
+ if (model_ptr == nullptr)
+ {
+ return ANEURALNETWORKS_OUT_OF_MEMORY;
+ }
+
+ *model = model_ptr;
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+void ANeuralNetworksModel_free(ANeuralNetworksModel *model) { delete model; }
+
+int ANeuralNetworksModel_addOperand(ANeuralNetworksModel *model,
+ const ANeuralNetworksOperandType *type)
+{
+ if ((model == nullptr) || (type == nullptr))
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (model->isFinished())
+ {
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ if (type->type == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM)
+ {
+ // Quantized:
+ // scale: a 32 bit floating point value greater than zero
+ // zeroPoint: a 32 bit integer, in range [0, 255]
+ if (type->scale <= 0.0f)
+ {
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ if (type->zeroPoint < 0 || type->zeroPoint > 255)
+ {
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+ }
+ // NOTE Validation of scale and zeroPoint would be skipped for a while.
+ // We do not know whether scalar type can have scale and zeroPoint.
+ // To pass ValidationTest and GeneratedTest, this validation code
+ // would not be implemented until we can define this issue clearly.
+ //
+ // scale and zeroPoint should be zero for scalars and non-fixed point tensors
+ // else if ((type->scale != 0.0f) || (type->zeroPoint != 0))
+ // {
+ // return ANEURALNETWORKS_BAD_DATA;
+ // }
+
+ // scalar is ANEURALNETWORKS_FLOAT32, ANEURALNETWORKS_INT32 or ANEURALNETWORKS_UINT32.
+ // ANEURALNETWORKS_TENSOR_FLOAT32, ANEURALNETWORKS_TENSOR_INT32 and
+ // ANEURALNETWORKS_TENSOR_QUANT8_ASYMM are not scalar
+ //
+ // dimensionCount should be zero for scalars
+ if (type->dimensionCount != 0 &&
+ (type->type == ANEURALNETWORKS_FLOAT32 || type->type == ANEURALNETWORKS_INT32 ||
+ type->type == ANEURALNETWORKS_UINT32))
+ {
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ // ASSUME A tensor operand should consists of fp32 or int32 values.
+ // NOTE We do not care about scala operands.
+ assert((type->dimensionCount == 0) || (type->type == ANEURALNETWORKS_TENSOR_FLOAT32 ||
+ type->type == ANEURALNETWORKS_TENSOR_INT32 ||
+ type->type == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM));
+
+ internal::tflite::operand::Shape shape(type->dimensionCount);
+
+ for (uint32_t axis = 0; axis < type->dimensionCount; ++axis)
+ {
+ shape.dim(axis) = type->dimensions[axis];
+ }
+
+ model->deref().operands().append(shape, type->type, type->scale, type->zeroPoint);
+
+ // NOTE We do NOT allocate CLTensor here as we do not how to interpret this one.
+ // TensorFlow Lite may interpret a rank-4 tensor either as a feature map (with batch) or
+ // a convolution kernel.
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_setOperandValue(ANeuralNetworksModel *model, int32_t index,
+ const void *buffer, size_t length)
+{
+ if ((model == nullptr) || ((buffer == nullptr) && (length != 0)))
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ const internal::tflite::operand::Index ind{index};
+ auto &obj = model->deref().operands().at(ind);
+
+ if (buffer == nullptr)
+ {
+ using internal::tflite::operand::ExternalData;
+ obj.data<ExternalData>(reinterpret_cast<const uint8_t *>(buffer), length);
+ }
+ else
+ {
+ using internal::tflite::operand::CachedData;
+ obj.data<CachedData>(reinterpret_cast<const uint8_t *>(buffer), length);
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_setOperandValueFromMemory(ANeuralNetworksModel *model, int32_t index,
+ const ANeuralNetworksMemory *memory,
+ size_t offset, size_t length)
+{
+ if ((model == nullptr) || (memory == nullptr))
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ const internal::tflite::operand::Index ind{index};
+ auto &obj = model->deref().operands().at(ind);
+
+ using internal::tflite::operand::ExternalData;
+
+ obj.data<ExternalData>(reinterpret_cast<const uint8_t *>(memory->base() + offset), length);
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_addOperation(ANeuralNetworksModel *model,
+ ANeuralNetworksOperationType type, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ if (model == nullptr || inputs == nullptr || outputs == nullptr)
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (model->isFinished())
+ {
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ if (type < ANEURALNETWORKS_ADD || type > ANEURALNETWORKS_TRANSPOSE)
+ {
+ return ANEURALNETWORKS_BAD_DATA;
+ }
+
+ switch (type)
+ {
+ case ANEURALNETWORKS_ADD:
+ {
+ assert(inputCount == 3);
+ assert(outputCount == 1);
+
+ using internal::tflite::op::Add::Param;
+ using internal::tflite::op::Add::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_SUB:
+ {
+ assert(inputCount == 3);
+ assert(outputCount == 1);
+
+ using internal::tflite::op::Sub::Param;
+ using internal::tflite::op::Sub::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_MUL:
+ {
+ assert(inputCount == 3);
+ assert(outputCount == 1);
+
+ using internal::tflite::op::Mul::Param;
+ using internal::tflite::op::Mul::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_DIV:
+ {
+ assert(inputCount == 3);
+ assert(outputCount == 1);
+
+ using internal::tflite::op::Div::Param;
+ using internal::tflite::op::Div::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_CONV_2D:
+ {
+ // inputCount is either 7 or 10 acccording to NN API specification.
+ // - Padding is implicit when inputCount is 7
+ // - Padding is explicit when inputCount is 10
+ assert(inputCount == 7 || inputCount == 10);
+ assert(outputCount == 1);
+
+ if (inputCount == 7)
+ {
+ using internal::tflite::op::Conv2D::Implicit::Param;
+ using internal::tflite::op::Conv2D::Implicit::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+ }
+ else
+ {
+ using internal::tflite::op::Conv2D::Explicit::Param;
+ using internal::tflite::op::Conv2D::Explicit::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+ }
+
+ break;
+ }
+ case ANEURALNETWORKS_DEPTHWISE_CONV_2D:
+ {
+ // inputCount is either 8 or 11 acccording to NN API specification.
+ // - Padding is implicit when inputCount is 8
+ // - Padding is explicit when inputCount is 11
+ assert(inputCount == 8 || inputCount == 11);
+ assert(outputCount == 1);
+
+ if (inputCount == 8)
+ {
+ using internal::tflite::op::DepthwiseConv2D::Implicit::Param;
+ using internal::tflite::op::DepthwiseConv2D::Implicit::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+ }
+ else
+ {
+ using internal::tflite::op::DepthwiseConv2D::Explicit::Param;
+ using internal::tflite::op::DepthwiseConv2D::Explicit::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+ }
+
+ break;
+ }
+ case ANEURALNETWORKS_MAX_POOL_2D:
+ {
+ // inputCount is either 7 or 10 acccording to NN API specification.
+ // - Padding is implicit when inputCount is 7
+ // - Padding is explicit when inputCount is 10
+ assert(inputCount == 7 || inputCount == 10);
+ assert(outputCount == 1);
+
+ if (inputCount == 7)
+ {
+ using internal::tflite::op::MaxPool2D::Implicit::Param;
+ using internal::tflite::op::MaxPool2D::Implicit::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+ }
+ else
+ {
+ using internal::tflite::op::MaxPool2D::Explicit::Param;
+ using internal::tflite::op::MaxPool2D::Explicit::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+ }
+
+ break;
+ }
+ case ANEURALNETWORKS_DEQUANTIZE:
+ {
+ assert(outputCount == 1 && inputCount == 1);
+ using internal::tflite::op::Dequantize::Param;
+ using internal::tflite::op::Dequantize::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_AVERAGE_POOL_2D:
+ {
+ // inputCount is either 7 or 10 acccording to NN API specification.
+ // - Padding is implicit when inputCount is 7
+ // - Padding is explicit when inputCount is 10
+ assert(inputCount == 7 || inputCount == 10);
+ assert(outputCount == 1);
+
+ if (inputCount == 7)
+ {
+ using internal::tflite::op::AvgPool2D::Implicit::Param;
+ using internal::tflite::op::AvgPool2D::Implicit::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+ }
+ else
+ {
+ using internal::tflite::op::AvgPool2D::Explicit::Param;
+ using internal::tflite::op::AvgPool2D::Explicit::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+ }
+
+ break;
+ }
+ case ANEURALNETWORKS_CONCATENATION:
+ {
+ using internal::tflite::op::Concat::Param;
+ using internal::tflite::op::Concat::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_RESIZE_BILINEAR:
+ {
+ using internal::tflite::op::ResizeBilinear::Param;
+ using internal::tflite::op::ResizeBilinear::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_RESHAPE:
+ {
+ using internal::tflite::op::Reshape::Param;
+ using internal::tflite::op::Reshape::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_SQUEEZE:
+ {
+ using internal::tflite::op::Squeeze::Param;
+ using internal::tflite::op::Squeeze::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_FULLY_CONNECTED:
+ {
+ using internal::tflite::op::FullyConnected::Param;
+ using internal::tflite::op::FullyConnected::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_SOFTMAX:
+ {
+ using internal::tflite::op::Softmax::Param;
+ using internal::tflite::op::Softmax::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_RELU:
+ {
+ using internal::tflite::op::ReLU::Param;
+ using internal::tflite::op::ReLU::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_RELU1:
+ {
+ using internal::tflite::op::ReLU1::Param;
+ using internal::tflite::op::ReLU1::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_RELU6:
+ {
+ using internal::tflite::op::ReLU6::Param;
+ using internal::tflite::op::ReLU6::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_TANH:
+ {
+ using internal::tflite::op::Tanh::Param;
+ using internal::tflite::op::Tanh::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_STRIDED_SLICE:
+ {
+ using internal::tflite::op::StridedSlice::Param;
+ using internal::tflite::op::StridedSlice::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_LOGISTIC:
+ {
+ using internal::tflite::op::Logistic::Param;
+ using internal::tflite::op::Logistic::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_MEAN:
+ {
+ using internal::tflite::op::Mean::Param;
+ using internal::tflite::op::Mean::Node;
+
+ auto &operations = model->deref().operations();
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_RNN:
+ {
+ using internal::tflite::op::RNN::Param;
+ using internal::tflite::op::RNN::Node;
+
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_TRANSPOSE:
+ {
+ using internal::tflite::op::Transpose::Param;
+ using internal::tflite::op::Transpose::Node;
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_LSTM:
+ {
+ using internal::tflite::op::LSTM::Param;
+ using internal::tflite::op::LSTM::Node;
+
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_FLOOR:
+ {
+ using internal::tflite::op::Floor::Param;
+ using internal::tflite::op::Floor::Node;
+
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_PAD:
+ {
+ assert(inputCount == 2 && outputCount == 1);
+
+ using internal::tflite::op::Pad::Param;
+ using internal::tflite::op::Pad::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_SPACE_TO_DEPTH:
+ {
+ using internal::tflite::op::SpaceToDepth::Param;
+ using internal::tflite::op::SpaceToDepth::Node;
+
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_SPACE_TO_BATCH_ND:
+ {
+ using internal::tflite::op::SpaceToBatchND::Param;
+ using internal::tflite::op::SpaceToBatchND::Node;
+
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_BATCH_TO_SPACE_ND:
+ {
+ using internal::tflite::op::BatchToSpaceNd::Param;
+ using internal::tflite::op::BatchToSpaceNd::Node;
+
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_L2_POOL_2D:
+ {
+ // Input count is 7 for Implicit Padding
+ // Input count is 10 for Explicit Padding
+ assert(inputCount == 7 || inputCount == 10);
+ assert(outputCount == 1);
+
+ if (inputCount == 7)
+ {
+ using internal::tflite::op::L2Pool2D::Implicit::Param;
+ using internal::tflite::op::L2Pool2D::Implicit::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+ }
+ else
+ {
+ using internal::tflite::op::L2Pool2D::Explicit::Param;
+ using internal::tflite::op::L2Pool2D::Explicit::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+ }
+
+ break;
+ }
+ case ANEURALNETWORKS_EMBEDDING_LOOKUP:
+ {
+ assert(inputCount == 2);
+ assert(outputCount == 1);
+
+ using internal::tflite::op::EmbeddingLookup::Param;
+ using internal::tflite::op::EmbeddingLookup::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_L2_NORMALIZATION:
+ {
+ assert(inputCount == 1 && outputCount == 1);
+
+ using internal::tflite::op::L2Normalization::Param;
+ using internal::tflite::op::L2Normalization::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_HASHTABLE_LOOKUP:
+ {
+ assert(inputCount == 3);
+ assert(outputCount == 2);
+
+ using internal::tflite::op::HashtableLookup::Param;
+ using internal::tflite::op::HashtableLookup::Node;
+
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_LOCAL_RESPONSE_NORMALIZATION:
+ {
+
+ using internal::tflite::op::LocalResponseNormalization::Param;
+ using internal::tflite::op::LocalResponseNormalization::Node;
+
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_DEPTH_TO_SPACE:
+ {
+ using internal::tflite::op::DepthToSpace::Param;
+ using internal::tflite::op::DepthToSpace::Node;
+
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ default:
+ throw std::runtime_error{"Not supported operation"};
+ };
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_addOperationEx(ANeuralNetworksModel *model,
+ ANeuralNetworksOperationTypeEx type, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ if ((model == nullptr) || (inputs == nullptr) || (outputs == nullptr))
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ switch (type)
+ {
+ case ANEURALNETWORKS_CAST_EX:
+ {
+ using internal::tflite::op::Cast::Param;
+ using internal::tflite::op::Cast::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_REDUCE_MIN_EX:
+ {
+ using internal::tflite::op::ReduceMin::Param;
+ using internal::tflite::op::ReduceMin::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_REDUCE_MAX_EX:
+ {
+ using internal::tflite::op::ReduceMax::Param;
+ using internal::tflite::op::ReduceMax::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_PRELU_EX:
+ {
+ using internal::tflite::op::PReLU::Param;
+ using internal::tflite::op::PReLU::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_TRANSPOSE_CONV_EX:
+ {
+ using internal::tflite::op::TransposeConv::Param;
+ using internal::tflite::op::TransposeConv::Node;
+
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_LOGICAL_AND_EX:
+ {
+ using internal::tflite::op::LogicalAnd::Param;
+ using internal::tflite::op::LogicalAnd::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_LOGICAL_OR_EX:
+ {
+ using internal::tflite::op::LogicalOr::Param;
+ using internal::tflite::op::LogicalOr::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_LOGICAL_NOT_EX:
+ {
+ using internal::tflite::op::LogicalNot::Param;
+ using internal::tflite::op::LogicalNot::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_RSQRT_EX:
+ {
+ using internal::tflite::op::RSQRT::Param;
+ using internal::tflite::op::RSQRT::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_SQRT_EX:
+ {
+ using internal::tflite::op::SQRT::Param;
+ using internal::tflite::op::SQRT::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_EQUAL_EX:
+ {
+ using internal::tflite::op::Equal::Param;
+ using internal::tflite::op::Equal::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_SQUARED_DIFFERENCE_EX:
+ {
+ using internal::tflite::op::SquaredDifference::Param;
+ using internal::tflite::op::SquaredDifference::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_TOPK_V2_EX:
+ {
+ using internal::tflite::op::TopKV2::Param;
+ using internal::tflite::op::TopKV2::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_GATHER_EX:
+ {
+ using internal::tflite::op::Gather::Param;
+ using internal::tflite::op::Gather::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_SPLIT_EX:
+ {
+ using internal::tflite::op::Split::Param;
+ using internal::tflite::op::Split::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_UNPACK_EX:
+ {
+ using internal::tflite::op::Unpack::Param;
+ using internal::tflite::op::Unpack::Node;
+
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_NEG_EX:
+ {
+ using internal::tflite::op::Neg::Param;
+ using internal::tflite::op::Neg::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_EXP_EX:
+ {
+ using internal::tflite::op::Exp::Param;
+ using internal::tflite::op::Exp::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_REDUCE_SUM_EX:
+ {
+ using internal::tflite::op::ReduceSum::Param;
+ using internal::tflite::op::ReduceSum::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_PACK_EX:
+ {
+ using internal::tflite::op::Pack::Param;
+ using internal::tflite::op::Pack::Node;
+
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_ABS_EX:
+ {
+ using internal::tflite::op::Abs::Param;
+ using internal::tflite::op::Abs::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_ARGMAX_EX:
+ {
+ using internal::tflite::op::ArgMax::Param;
+ using internal::tflite::op::ArgMax::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+ case ANEURALNETWORKS_NOT_EQUAL_EX:
+ {
+ using internal::tflite::op::NotEqual::Param;
+ using internal::tflite::op::NotEqual::Node;
+
+ // Add 'operations'
+ auto &operations = model->deref().operations();
+
+ operations.emplace_back<Node>(Param{inputCount, inputs, outputCount, outputs});
+
+ break;
+ }
+
+ default:
+ throw std::runtime_error{"Not supported operation"};
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_identifyInputsAndOutputs(ANeuralNetworksModel *model, uint32_t inputCount,
+ const uint32_t *inputs, uint32_t outputCount,
+ const uint32_t *outputs)
+{
+ if ((model == nullptr) || (inputs == nullptr) || (outputs == nullptr))
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (model->isFinished())
+ {
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ // NOTE ::internal::tflite::operand::Index uses int as its underlying type as various NNAPI
+ // functions such as ANeuralNetworksModel_setOperandValue use int to represent operand index
+ //
+ // ANeuralNetworksModel_identifyInputsAndOutputs, however, uses uint32_t to represent operand
+ // index.
+ //
+ // Below, static_cast<int>(...) is introduced to eliminate compiler warning.
+ for (uint32_t n = 0; n < inputCount; ++n)
+ {
+ const ::internal::tflite::operand::Index ind{static_cast<int>(inputs[n])};
+ model->deref().inputs.emplace_back(ind);
+ }
+
+ for (uint32_t n = 0; n < outputCount; ++n)
+ {
+ const ::internal::tflite::operand::Index ind{static_cast<int>(outputs[n])};
+ model->deref().outputs.emplace_back(ind);
+ }
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+int ANeuralNetworksModel_finish(ANeuralNetworksModel *model)
+{
+ if (model == nullptr)
+ {
+ return ANEURALNETWORKS_UNEXPECTED_NULL;
+ }
+
+ if (model->isFinished())
+ {
+ return ANEURALNETWORKS_BAD_STATE;
+ }
+
+ model->markAsFinished();
+
+ return ANEURALNETWORKS_NO_ERROR;
+}
+
+//
+// ANeuralNetworksModel
+//
+ANeuralNetworksModel::ANeuralNetworksModel() : _model{new internal::tflite::Model}
+{
+ // DO NOTHING
+}
diff --git a/runtime/contrib/pure_arm_compute/src/model.h b/runtime/contrib/pure_arm_compute/src/model.h
new file mode 100644
index 000000000..8acc894f4
--- /dev/null
+++ b/runtime/contrib/pure_arm_compute/src/model.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file model.h
+ * @brief This file contains ANeuralNetworksModel classe for handling Model NNAPI such as
+ * ANeuralNetworksModel_create, ANeuralNetworksModel_addOperand
+ * @ingroup COM_AI_RUNTIME
+ */
+
+#ifndef __MODEL_H__
+#define __MODEL_H__
+
+#include "internal/Model.h"
+
+/**
+ * @brief struct to express Model of NNAPI
+ */
+struct ANeuralNetworksModel
+{
+public:
+ /**
+ * @brief Construct without params
+ */
+ ANeuralNetworksModel();
+
+public:
+ /**
+ * @brief Get reference of internal::tflite::Model
+ * @return Reference of internal::tflite::Model
+ */
+ internal::tflite::Model &deref(void) { return *_model; }
+
+public:
+ /**
+ * @brief Release internal::tflite::Model pointer to param
+ * @param [in] model To get released internal::tflite::Model pointer
+ * @return N/A
+ */
+ void release(std::shared_ptr<const internal::tflite::Model> &model) { model = _model; }
+ /**
+ * @brief Get @c true if ANeuralNetworksModel_finish has been called, otherwise @c false
+ * @return @c true if ANeuralNetworksModel_finish has been called, otherwise @c false
+ */
+ bool isFinished() { return _isFinished == true; }
+ /**
+ * @brief Mark model process finished
+ * @return N/A
+ */
+ void markAsFinished() { _isFinished = true; }
+
+private:
+ std::shared_ptr<internal::tflite::Model> _model;
+ bool _isFinished{false};
+};
+
+#endif // __MODEL_H__