Imported Upstream version 1.7.0
[platform/core/ml/nnfw.git] / runtime / onert / core / src / exec / Sink.h
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef __ONERT_EXEC_SINK_H__
18 #define __ONERT_EXEC_SINK_H__
19
20 #include "feature/nchw/Reader.h"
21 #include "feature/nchw/View.h"
22 #include "feature/nhwc/Reader.h"
23 #include "feature/nhwc/View.h"
24
25 #include <cassert>
26 #include <memory>
27 #include "util/Utils.h"
28 #include <misc/feature/IndexIterator.h>
29
30 namespace onert
31 {
32 namespace exec
33 {
34 struct ISink
35 {
36   virtual ~ISink() = default;
37
38   virtual void pull(::onert::backend::ITensor &tensor) const = 0;
39 };
40
41 // Create second lever inheritance: the first lever is used as a reference type in use-case places
42 template <typename T> class ITemplSink : public ISink
43 {
44 public:
45   ITemplSink(void *output_buffer, const size_t &output_size, const ir::Shape &shape,
46              const bool copy, ir::Layout io_layout)
47       : _output_buffer{reinterpret_cast<T *>(output_buffer)}, _output_size{output_size},
48         _shape{shape}, _copy{copy}, _io_layout{io_layout}
49   {
50   }
51
52 protected:
53   void pullUnif(onert::backend::ITensor &tensor) const
54   {
55     assert(((_io_layout == ir::Layout::NHWC && tensor.layout() == ir::Layout::NCHW) ||
56             (_io_layout == ir::Layout::NCHW && tensor.layout() == ir::Layout::NHWC)) ||
57            _copy);
58     auto input_buffer = tensor.buffer();
59     auto rank = _shape.rank();
60
61     if (!tensor.has_padding() && rank < 4 + _copy)
62     {
63       memcpy(_output_buffer, input_buffer, _output_size);
64       return;
65     }
66
67     switch (rank)
68     {
69       case 0:
70       case 1:
71       {
72         memcpy(_output_buffer, input_buffer, _output_size);
73         break;
74       }
75       case 2:
76       {
77         const int32_t copy_len = _shape.dim(1);
78
79         for (auto i = 0; i < _shape.dim(0); ++i)
80         {
81           ir::Coordinates coords{i, 0};
82           memcpy(_output_buffer + i * copy_len, input_buffer + tensor.calcOffset(coords),
83                  copy_len * sizeof(T));
84         }
85         break;
86       }
87       case 3:
88       {
89         const int32_t dim1 = _shape.dim(1);
90         const int32_t dim2 = _shape.dim(2);
91
92         for (auto i = 0; i < _shape.dim(0); ++i)
93         {
94           for (auto j = 0; j < _shape.dim(1); ++j)
95           {
96             ir::Coordinates coords{i, j, 0};
97             memcpy(_output_buffer + i * dim1 * dim2 + j * dim2,
98                    input_buffer + tensor.calcOffset(coords), dim2 * sizeof(T));
99           }
100         }
101         break;
102       }
103       case 4:
104       {
105         if (_copy)
106         {
107           const int32_t dim1 = _shape.dim(1);
108           const int32_t dim2 = _shape.dim(2);
109           const int32_t dim3 = _shape.dim(3);
110
111           for (auto i = 0; i < _shape.dim(0); ++i)
112           {
113             for (auto j = 0; j < _shape.dim(1); ++j)
114             {
115               for (auto k = 0; k < _shape.dim(2); ++k)
116               {
117                 ir::Coordinates coords{i, j, k, 0};
118                 memcpy(_output_buffer + i * dim1 * dim2 * dim3 + j * dim2 * dim3 + k * dim3,
119                        input_buffer + tensor.calcOffset(coords), dim3 * sizeof(T));
120               }
121             }
122           }
123         }
124         else
125         {
126           const auto shape = _shape.asFeature(_io_layout);
127
128           if (_io_layout == ir::Layout::NHWC)
129           {
130             const exec::feature::nchw::Reader<T> from(&tensor);
131             exec::feature::nhwc::View<T> into(shape, _output_buffer, _output_size);
132             feature::iterate(shape)
133                 << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
134                      const auto value = from.at(batch, ch, row, col);
135                      into.at(batch, row, col, ch) = value;
136                    };
137           }
138           else if (_io_layout == ir::Layout::NCHW)
139           {
140             const exec::feature::nhwc::Reader<T> from(&tensor);
141             exec::feature::nchw::View<T> into(shape, _output_buffer, _output_size);
142             feature::iterate(shape)
143                 << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
144                      const auto value = from.at(batch, row, col, ch);
145                      into.at(batch, ch, row, col) = value;
146                    };
147           }
148           else
149           {
150             throw std::runtime_error("Wrong Layout");
151           }
152         }
153         break;
154       }
155       default:
156         throw std::runtime_error("NYI: rank > 4");
157         break;
158     }
159   }
160
161 private:
162   T *_output_buffer;
163   const size_t _output_size;
164   const ir::Shape _shape;
165   const bool _copy;
166   const ir::Layout _io_layout;
167 };
168
169 template <typename T> class PermutateSink final : public ITemplSink<T>
170 {
171 public:
172   PermutateSink(void *output_buffer, const size_t &output_size, const ir::Shape &shape,
173                 ir::Layout io_layout)
174       : ITemplSink<T>(output_buffer, output_size, shape, false, io_layout)
175   {
176   }
177
178 public:
179   void pull(onert::backend::ITensor &tensor) const override { ITemplSink<T>::pullUnif(tensor); }
180 };
181
182 // Only supports NHWC format front-end(NNAPI) now
183 template <typename T> class CopySink final : public ITemplSink<T>
184 {
185 public:
186   CopySink(void *output_buffer, const size_t &output_size, const ir::Shape &shape,
187            ir::Layout io_layout = ir::Layout::UNKNOWN)
188       : ITemplSink<T>(output_buffer, output_size, shape, true, io_layout)
189   {
190   }
191
192 public:
193   void pull(onert::backend::ITensor &tensor) const override { ITemplSink<T>::pullUnif(tensor); }
194 };
195
196 } // namespace exec
197 } // namespace onert
198
199 #endif // __ONERT_EXEC_SINK_H__