Imported Upstream version 1.25.0
[platform/core/ml/nnfw.git] / onert-micro / luci-interpreter / src / kernels / Slice.cpp
index 7ae24bb..34e5498 100644 (file)
@@ -1,6 +1,5 @@
 /*
  * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
- * Copyright 2019 The TensorFlow Authors. All Rights Reserved.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * limitations under the License.
  */
 
-#include "kernels/Slice.h"
-#include "Utils.h"
-#include "PALSlice.h"
+#include "Builders.h"
+#include "kernels/Utils.h"
+#include "MISOKernel.h"
 
 #include <cassert>
-#include <cstring>
 
 namespace luci_interpreter
 {
 
-namespace kernels
+namespace
 {
-const int max_dim = 4;
+const int max_dim = 5;
 
-Slice::Slice(const Tensor *input, const Tensor *begin, const Tensor *size, Tensor *output)
-  : Kernel({input, begin, size}, {output})
+struct SliceParams
 {
-}
+  int8_t begin_count;
+  int32_t begin[5];
+  int8_t size_count;
+  int32_t size[5];
+};
 
 template <typename T>
-Shape calculateOutputShape(const Tensor *input, const Tensor *begin, const Tensor *size)
+inline void slice(const luci_interpreter::SliceParams &op_params,
+                  const luci_interpreter::RuntimeShape &input_shape, const T *input_data,
+                  const luci_interpreter::RuntimeShape &output_shape, T *output_data)
 {
-  Shape output_shape = Shape(input->shape().num_dims());
-  for (int idx = 0; idx < input->shape().num_dims(); idx++)
+  const luci_interpreter::RuntimeShape ext_shape =
+    luci_interpreter::RuntimeShape::extendedShape(5, input_shape);
+  const int begin_count = op_params.begin_count;
+  const int size_count = op_params.size_count;
+  // We front-pad the begin and size vectors.
+  int start[5];
+  int stop[5];
+  for (int i = 0; i < 5; ++i)
   {
-    T size_value = getTensorData<T>(size)[idx];
-    if (size_value < 0)
-    {
-      if (size_value != -1)
-      {
-        assert(false && "Invalid size.");
-      }
-      size_value = input->shape().dim(idx) - getTensorData<T>(begin)[idx];
-    }
-    else
+    int padded_i = 5 - i;
+    start[i] = begin_count < padded_i ? 0 : op_params.begin[begin_count - padded_i];
+    stop[i] = (size_count < padded_i || op_params.size[size_count - padded_i] == -1)
+                ? ext_shape.dims(i)
+                : start[i] + op_params.size[size_count - padded_i];
+  }
+
+  for (int i0 = start[0]; i0 < stop[0]; ++i0)
+  {
+    for (int i1 = start[1]; i1 < stop[1]; ++i1)
     {
-      if (input->shape().dim(idx) < getTensorData<T>(begin)[idx] + size_value)
+      for (int i2 = start[2]; i2 < stop[2]; ++i2)
       {
-        assert(false && "Invalid begin and size.");
+        for (int i3 = start[3]; i3 < stop[3]; ++i3)
+        {
+          for (int i4 = start[4]; i4 < stop[4]; ++i4)
+          {
+            auto position =
+              (((i0 * ext_shape.dims(1) + i1) * ext_shape.dims(2) + i2) * ext_shape.dims(3) + i3) *
+                ext_shape.dims(4) +
+              i4;
+            *output_data++ = input_data[position];
+          }
+        }
       }
     }
-    output_shape.dim(idx) = static_cast<int>(size_value);
   }
-  return output_shape;
 }
 
 template <typename T>
-void getBeginAndSizeVectors(int dimensions, const Tensor *begin, const Tensor *size,
-                            std::vector<int> *begins, std::vector<int> *sizes)
+void getBeginAndSizeVectors(int dimensions, const uint8_t *begin_data, const uint8_t *size_data,
+                            int32_t *begins, int32_t *sizes)
 {
-  for (int idx = dimensions - 1; idx >= 0; --idx)
+  int offset = max_dim - dimensions;
+  for (int idx = 0; idx < dimensions; ++idx)
   {
-    begins->push_back(getTensorData<T>(begin)[idx]);
-    sizes->push_back(getTensorData<T>(size)[idx]);
+    begins[offset + idx] = kernels::getTensorData<T>(begin_data)[idx];
+    sizes[offset + idx] = kernels::getTensorData<T>(size_data)[idx];
   }
 }
+} // namespace
 
-void Slice::configure()
+void configure_kernel_CircleSlice(const circle::Operator *cur_op, BaseRuntimeGraph *runtime_graph)
 {
-  assert(input()->element_type() == output()->element_type());
-  assert(begin()->element_type() == DataType::S32 || begin()->element_type() == DataType::S64);
-  assert(size()->element_type() == DataType::S32 || size()->element_type() == DataType::S64);
-  assert(begin()->shape().num_dims() == 1);
-  assert(size()->shape().num_dims() == 1);
-  assert(input()->shape().num_dims() <= max_dim);
-  // TODO: enable it only if kernel with dynamic shapes
-  if (begin()->element_type() == DataType::S32)
+  kernels::MISOKernel kernel(cur_op, runtime_graph);
+
+  LUCI_INTERPRETER_CHECK(Tensor::element_type(kernel.input1()) ==
+                         Tensor::element_type(kernel.output()));
+  LUCI_INTERPRETER_CHECK(Tensor::element_type(kernel.input2()) == DataType::S32 ||
+                         Tensor::element_type(kernel.input2()) == DataType::S64);
+  LUCI_INTERPRETER_CHECK(Tensor::element_type(kernel.input3()) == DataType::S32 ||
+                         Tensor::element_type(kernel.input3()) == DataType::S64);
+  LUCI_INTERPRETER_CHECK(Tensor::num_dims(kernel.input2()) == 1);
+  LUCI_INTERPRETER_CHECK(Tensor::num_dims(kernel.input3()) == 1);
+  LUCI_INTERPRETER_CHECK(Tensor::num_dims(kernel.input1()) <= max_dim);
+}
+
+void execute_kernel_CircleSlice(const circle::Operator *cur_op, BaseRuntimeGraph *runtime_graph)
+{
+  kernels::MISOKernel kernel(cur_op, runtime_graph);
+
+  bool is_dynamic_shapes = false;
+
+  const circle::Tensor *input = kernel.input1();
+  const circle::Tensor *begin = kernel.input2();
+  const circle::Tensor *size_tensor = kernel.input3();
+  const circle::Tensor *output = kernel.output();
+
+  const auto *input_data = runtime_graph->getDataByTensor(input);
+  if (input_data == nullptr)
+    input_data = runtime_graph->getConstDataByTensor(input);
+  assert(input_data);
+
+  const auto *begin_data = runtime_graph->getDataByTensor(begin);
+  if (begin_data == nullptr)
   {
-    output()->resize(calculateOutputShape<int32_t>(input(), begin(), size()));
+    begin_data = runtime_graph->getConstDataByTensor(begin);
+    is_dynamic_shapes = true;
   }
-  else if (begin()->element_type() == DataType::S64)
+  assert(begin_data);
+
+  const auto *size_data = runtime_graph->getDataByTensor(size_tensor);
+  if (size_data == nullptr)
   {
-    output()->resize(calculateOutputShape<int64_t>(input(), begin(), size()));
+    size_data = runtime_graph->getConstDataByTensor(size_tensor);
+    is_dynamic_shapes = true;
   }
-  else
+  assert(size_data);
+
+  auto *output_data = runtime_graph->getDataByTensor(output);
+  assert(output_data);
+
+  SliceParams op_params{};
+  op_params.begin_count = max_dim;
+  op_params.size_count = max_dim;
+  for (int i = 0; i < max_dim; i++)
   {
-    assert(false && "Unsupported type.");
+    op_params.begin[i] = 0;
+    op_params.size[i] = 1;
   }
-}
+  auto num_dim = Tensor::num_dims(input);
 
-void Slice::execute() const
-{
-  std::vector<int> begins;
-  begins.reserve(max_dim);
-  std::vector<int> sizes;
-  sizes.reserve(max_dim);
-  if (begin()->element_type() == DataType::S32)
+  if (Tensor::element_type(begin) == DataType::S32)
   {
-    getBeginAndSizeVectors<int32_t>(input()->shape().num_dims(), begin(), size(), &begins, &sizes);
+    getBeginAndSizeVectors<int32_t>(num_dim, begin_data, size_data, op_params.begin,
+                                    op_params.size);
   }
-  else if (begin()->element_type() == DataType::S64)
+  else if (Tensor::element_type(begin) == DataType::S64)
   {
-    getBeginAndSizeVectors<int64_t>(input()->shape().num_dims(), begin(), size(), &begins, &sizes);
+    getBeginAndSizeVectors<int64_t>(num_dim, begin_data, size_data, op_params.begin,
+                                    op_params.size);
   }
   else
   {
-    assert(false && "Unsupported begin type.");
-  }
-  for (int i = input()->shape().num_dims(); i < max_dim; ++i)
-  {
-    begins.push_back(0);
-    sizes.push_back(1);
+    assert(false && "Unsupported type");
   }
 
-  assert(begins.size() == 4);
-  assert(sizes.size() == 4);
-  tflite::SliceParams op_params{};
-  op_params.begin_count = 4;
-  op_params.size_count = 4;
-  for (int i = 0; i < 4; i++)
+#ifndef DIS_DYN_SHAPES
+  if (is_dynamic_shapes)
   {
-    op_params.begin[i] = begins[3 - i];
-    op_params.size[i] = sizes[3 - i];
+    int32_t data_size = 1;
+    luci_interpreter::RuntimeShape dynamic_shapes(max_dim - num_dim + 1);
+    int offset = max_dim - Tensor::num_dims(input);
+    for (int i = 0; i <= max_dim - num_dim; ++i)
+    {
+      if (i + offset > 4)
+        return;
+      auto cur_size = op_params.size[i + offset] != -1
+                        ? op_params.size[i + offset]
+                        : Tensor::dim(input, i) - op_params.begin[i + offset];
+      data_size *= cur_size;
+
+      dynamic_shapes.setDim(i, cur_size);
+    }
+    data_size *= size(Tensor::element_type(output));
+
+    runtime_graph->addDynamicShapeTensor(output, std::move(dynamic_shapes));
+
+    if (data_size == 0)
+    {
+      runtime_graph->resetTensorData(nullptr, output);
+      return;
+    }
+
+    auto new_output_data = new uint8_t[data_size];
+    output_data = new_output_data;
+    runtime_graph->resetTensorData(new_output_data, output);
   }
-  switch (input()->element_type())
+#else
+  assert(is_dynamic_shapes == false);
+#endif // DIS_DYN_SHAPES
+
+  switch (Tensor::element_type(input))
   {
+#ifndef DIS_FLOAT
     case DataType::FLOAT32:
-      luci_interpreter_pal::Slice(op_params, getTensorShape(input()), getTensorData<float>(input()),
-                                  getTensorShape(output()), getTensorData<float>(output()));
+      slice<float>(op_params, kernels::getTensorShape(input),
+                   kernels::getTensorData<float>(input_data), kernels::getTensorShape(output),
+                   kernels::getTensorData<float>(output_data));
       break;
+#endif // DIS_FLOAT
+#ifndef DIS_QUANT
     case DataType::U8:
-      luci_interpreter_pal::Slice(op_params, getTensorShape(input()),
-                                  getTensorData<uint8_t>(input()), getTensorShape(output()),
-                                  getTensorData<uint8_t>(output()));
+      slice<uint8_t>(op_params, kernels::getTensorShape(input),
+                     kernels::getTensorData<uint8_t>(input_data), kernels::getTensorShape(output),
+                     kernels::getTensorData<uint8_t>(output_data));
       break;
     case DataType::S8:
-      luci_interpreter_pal::Slice(op_params, getTensorShape(input()),
-                                  getTensorData<int8_t>(input()), getTensorShape(output()),
-                                  getTensorData<int8_t>(output()));
+      slice<int8_t>(op_params, kernels::getTensorShape(input),
+                    kernels::getTensorData<int8_t>(input_data), kernels::getTensorShape(output),
+                    kernels::getTensorData<int8_t>(output_data));
+      break;
+    case DataType::S16:
+      slice<int16_t>(op_params, kernels::getTensorShape(input),
+                     kernels::getTensorData<int16_t>(input_data), kernels::getTensorShape(output),
+                     kernels::getTensorData<int16_t>(output_data));
       break;
+#endif // DIS_QUANT
     default:
       assert(false && "Unsupported input type.");
   }
 }
 
-} // namespace kernels
 } // namespace luci_interpreter