Imported Upstream version 1.7.0
[platform/core/ml/nnfw.git] / runtime / onert / core / src / exec / Source.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_SOURCE_H__
18 #define __ONERT_EXEC_SOURCE_H__
19
20 #include "feature/IndexIterator.h"
21 #include "feature/nchw/Reader.h"
22 #include "feature/nchw/View.h"
23 #include "feature/nhwc/Reader.h"
24 #include "feature/nhwc/View.h"
25
26 #include <cassert>
27 #include <memory>
28 #include "util/Utils.h"
29 #include <ir/Layout.h>
30 #include "ir/Shape.h"
31
32 namespace onert
33 {
34 namespace exec
35 {
36
37 struct ISource
38 {
39   virtual ~ISource() = default;
40
41   virtual void push(::onert::backend::ITensor &tensor) const = 0;
42 };
43
44 // Create second lever inheritance: the first lever is used as a reference type in use-case places
45 template <typename T> class ITemplSource : public ISource
46 {
47 public:
48   ITemplSource(const void *input_buffer, const size_t &input_size, const ir::Shape &shape,
49                const bool copy, ir::Layout io_layout)
50       : _input_buffer{reinterpret_cast<const T *>(input_buffer)}, _input_size{input_size},
51         _shape{shape}, _copy(copy), _io_layout{io_layout}
52   {
53   }
54
55   virtual void push(::onert::backend::ITensor &tensor) const = 0;
56
57 protected:
58   void pushUnif(onert::backend::ITensor &tensor) const
59   {
60     assert(((_io_layout == ir::Layout::NHWC && tensor.layout() == ir::Layout::NCHW) ||
61             (_io_layout == ir::Layout::NCHW && tensor.layout() == ir::Layout::NHWC)) ||
62            _copy);
63     auto output_buffer = tensor.buffer();
64     auto rank = _shape.rank();
65
66     if (!tensor.has_padding() && rank < 4 + _copy)
67     {
68       memcpy(output_buffer, _input_buffer, _input_size);
69       return;
70     }
71
72     switch (rank)
73     {
74       case 0:
75       case 1:
76       {
77         memcpy(output_buffer, _input_buffer, _input_size);
78         break;
79       }
80       case 2:
81       {
82         const int32_t copy_len = _shape.dim(1);
83
84         for (auto i = 0; i < _shape.dim(0); ++i)
85         {
86           ir::Coordinates coords{i, 0};
87           memcpy(output_buffer + tensor.calcOffset(coords), _input_buffer + i * copy_len,
88                  copy_len * sizeof(T));
89         }
90         break;
91       }
92       case 3:
93       {
94         const int32_t dim1 = _shape.dim(1);
95         const int32_t dim2 = _shape.dim(2);
96
97         for (auto i = 0; i < _shape.dim(0); ++i)
98         {
99           for (auto j = 0; j < _shape.dim(1); ++j)
100           {
101             ir::Coordinates coords{i, j, 0};
102             memcpy(output_buffer + tensor.calcOffset(coords),
103                    _input_buffer + i * dim1 * dim2 + j * dim2, dim2 * sizeof(T));
104           }
105         }
106         break;
107       }
108       case 4:
109       {
110         if (_copy)
111         {
112           const int32_t dim1 = _shape.dim(1);
113           const int32_t dim2 = _shape.dim(2);
114           const int32_t dim3 = _shape.dim(3);
115           for (auto i = 0; i < _shape.dim(0); ++i)
116           {
117             for (auto j = 0; j < _shape.dim(1); ++j)
118             {
119               for (auto k = 0; k < _shape.dim(2); ++k)
120               {
121                 ir::Coordinates coords{i, j, k, 0};
122                 memcpy(output_buffer + tensor.calcOffset(coords),
123                        _input_buffer + i * dim1 * dim2 * dim3 + j * dim2 * dim3 + k * dim3,
124                        dim3 * sizeof(T));
125               }
126             }
127           }
128         }
129         else
130         {
131           const auto shape = _shape.asFeature(_io_layout);
132
133           if (_io_layout == ir::Layout::NCHW)
134           {
135             const exec::feature::nchw::Reader<T> from(shape, _input_buffer, _input_size);
136             exec::feature::nhwc::View<T> into(&tensor);
137             feature::iterate(shape)
138                 << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
139                      const auto value = from.at(batch, ch, row, col);
140                      into.at(batch, row, col, ch) = value;
141                    };
142           }
143           else if (_io_layout == ir::Layout::NHWC)
144           {
145             const exec::feature::nhwc::Reader<T> from(shape, _input_buffer, _input_size);
146             exec::feature::nchw::View<T> into(&tensor);
147             feature::iterate(shape)
148                 << [&](uint32_t batch, uint32_t ch, uint32_t row, uint32_t col) {
149                      const auto value = from.at(batch, row, col, ch);
150                      into.at(batch, ch, row, col) = value;
151                    };
152           }
153           else
154           {
155             throw std::runtime_error("Wrong Layout");
156           }
157         }
158
159         break;
160       }
161       default:
162         throw std::runtime_error("NYI: rank > 4");
163         break;
164     }
165   }
166
167 private:
168   const T *_input_buffer;
169   const size_t _input_size;
170   const ir::Shape _shape;
171   const bool _copy;
172   const ir::Layout _io_layout;
173 };
174
175 template <typename T> class PermutateSource final : public ITemplSource<T>
176 {
177 public:
178   PermutateSource(const void *input_buffer, const size_t &input_size, const ir::Shape &shape,
179                   ir::Layout io_layout)
180       : ITemplSource<T>(input_buffer, input_size, shape, false, io_layout)
181   {
182   }
183
184 public:
185   void push(onert::backend::ITensor &tensor) const override
186   {
187     // do NHWC_TO_NCHW or NCHW_TO_NHWC permutation
188     ITemplSource<T>::pushUnif(tensor);
189   }
190 };
191
192 template <typename T> class CopySource final : public ITemplSource<T>
193 {
194 public:
195   CopySource(const void *input_buffer, const size_t &input_size, const ir::Shape &shape,
196              ir::Layout io_layout = ir::Layout::UNKNOWN)
197       : ITemplSource<T>(input_buffer, input_size, shape, true, io_layout)
198   {
199   }
200
201 public:
202   void push(onert::backend::ITensor &tensor) const override { ITemplSource<T>::pushUnif(tensor); }
203 };
204
205 } // namespace exec
206 } // namespace onert
207
208 #endif // __ONERT_EXEC_SOURCE_H__