2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #ifndef __ONERT_BACKEND_CONTROLFLOW_KERNEL_PERMUTELAYER_H__
18 #define __ONERT_BACKEND_CONTROLFLOW_KERNEL_PERMUTELAYER_H__
20 #include "backend/ITensorBuilder.h"
21 #include "exec/IPermuteFunction.h"
22 #include "exec/IExecutor.h"
23 #include "../ExternalContext.h"
24 #include "ruy/thread_pool.h" // from @ruy
35 class PermuteLayer : public onert::exec::IPermuteFunction
38 PermuteLayer(const std::vector<ITensor *> &src_tensors, const std::vector<ITensor *> &dst_tensors,
39 const std::shared_ptr<ExternalContext> &external_context);
41 void optimize() override;
46 std::shared_ptr<ExternalContext> _external_context;
49 void appendPermuteTasks(const ITensor *src_tensor, ITensor *dst_tensor,
50 const ir::Shape &loop_shape, size_t size);
52 void runPermuteTasks(backend::ITensor *src, uint8_t *dst_buffer);
54 struct PermuteWorkerTask : ruy::Task
56 using Strides = ir::Coordinates;
58 PermuteWorkerTask(const ITensor &src_tensor, ITensor &dst_tensor,
59 const ir::Coordinates &start_coords, const ir::Shape &loop_shape, size_t size)
60 : _src_buffer{src_tensor.buffer()}, _dst_buffer{dst_tensor.buffer()},
61 _src_start_offset{src_tensor.calcOffset(start_coords)},
62 _dst_start_offset{dst_tensor.calcOffset(start_coords)}, _src_strides{}, _dst_strides{},
63 _loop_shape{loop_shape}, _size{size}, _src_layout{src_tensor.layout()},
64 _dst_layout{dst_tensor.layout()}, _is_permutation{true}
67 setStrides(src_tensor, &_src_strides);
68 setStrides(dst_tensor, &_dst_strides);
70 _is_permutation = (_src_layout != _dst_layout && loop_shape.rank() == 4);
72 // Constructor for a copy
73 PermuteWorkerTask(const uint8_t *src_buffer, uint8_t *dst_buffer, uint32_t src_start_offset,
74 uint32_t dst_start_offset, size_t size)
75 : _src_buffer{src_buffer}, _dst_buffer{dst_buffer}, _src_start_offset{src_start_offset},
76 _dst_start_offset{dst_start_offset}, _src_strides{0}, _dst_strides{0}, _loop_shape{1},
77 _size{size}, _src_layout{}, _dst_layout{}, _is_permutation{false}
81 void setBuffers(const uint8_t *src_buffer, uint8_t *dst_buffer)
83 _src_buffer = src_buffer;
84 _dst_buffer = dst_buffer;
88 ShapeLoop(_loop_shape, [&](const onert::ir::Coordinates &coords) {
89 size_t src_offset = _src_start_offset;
90 size_t dst_offset = _dst_start_offset;
91 assert(static_cast<size_t>(_loop_shape.rank()) == coords.size());
92 ir::Coordinates dst_coords = coords;
95 dst_coords = ir::convertCoordinates(coords, _src_layout, _dst_layout);
97 for (auto i = 0; i < _loop_shape.rank(); ++i)
99 assert(coords[i] >= 0 && dst_coords[i] >= 0);
100 src_offset += coords[i] * _src_strides[i];
101 dst_offset += dst_coords[i] * _dst_strides[i];
103 memcpy(_dst_buffer + dst_offset, _src_buffer + src_offset, _size);
108 void setStrides(const ITensor &tensor, Strides *strides)
110 const size_t rank = tensor.num_dimensions();
111 for (size_t i = 0; i < rank; ++i)
113 ir::Coordinates no_step(rank), one_step(rank);
115 if (tensor.dimension(i) > 1)
117 strides->set(i, tensor.calcOffset(one_step) - tensor.calcOffset(no_step));
121 // If dimension value is 0 or 1, the stride of the dimension will be not used
122 // Do not call calcOffset() with coordinate value that is greater than dimension value
125 assert((*strides)[i] >= 0);
130 const uint8_t *_src_buffer;
131 uint8_t *_dst_buffer;
132 size_t _src_start_offset;
133 size_t _dst_start_offset;
134 Strides _src_strides;
135 Strides _dst_strides;
136 const ir::Shape _loop_shape;
138 const ir::Layout _src_layout;
139 const ir::Layout _dst_layout;
140 bool _is_permutation;
142 std::unordered_map<const ITensor *, std::vector<PermuteWorkerTask>> _tasks_map;
145 } // namespace kernel
146 } // namespace controlflow
147 } // namespace backend
150 #endif // __ONERT_BACKEND_CONTROLFLOW_KERNEL_PERMUTELAYER_H__