2 * Copyright (c) 2018 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 #include "DataLayoutConversion.h"
20 #include <coco/IR/FeatureLayouts.h>
21 #include <coco/IR/KernelLayouts.h>
23 #include <nncc/core/ADT/feature/Layout.h>
24 #include <nncc/core/ADT/kernel/Layout.h>
26 #include <nncc/core/ADT/feature/HWCLayout.h>
27 #include <nncc/core/ADT/kernel/NHWCLayout.h>
29 #include <nncc/foundation/Memory.h>
33 using nncc::foundation::make_unique;
38 coco::Copy *make_copy(coco::FeatureObject *from, coco::FeatureObject *into)
40 auto m = from->module();
42 assert(from->module() == into->module());
44 auto copy = m->entity()->instr()->create<coco::Copy>();
52 coco::FeatureObject *clone_feature(const coco::FeatureObject *oldobj)
54 auto module = oldobj->module();
55 auto newobj = module->entity()->object()->create(oldobj->shape());
56 newobj->layout(coco::FeatureLayouts::BHWC::create(oldobj->shape()));
58 if (auto oldbag = oldobj->bag())
60 assert(oldbag->module() == module);
61 // Clone bag only when there is a backing bag for a given feature object
62 auto newbag = module->entity()->bag()->create(oldbag->size());
70 * @brief Insert Copy before Load if necessary
72 void insert_copy_before_load(coco::Load *load)
74 if (auto obj = load->object())
76 if (auto ifm = obj->asFeature())
78 if (ifm->layout()->id() != coco::FeatureLayouts::BHWC::uid())
81 auto newobj = clone_feature(oldobj);
85 auto copy = make_copy(oldobj, newobj);
86 copy->insertBefore(load->parent());
93 * @brief Insert Copy after Eval if necessary
95 void insert_copy_after_eval(coco::Eval *eval)
97 if (auto out = eval->out())
99 if (auto ofm = out->asFeature())
101 if (ofm->layout()->id() != coco::FeatureLayouts::BHWC::uid())
104 auto newobj = clone_feature(oldobj);
108 auto copy = make_copy(newobj, oldobj);
109 copy->insertAfter(eval);
116 * @brief Update convolution kernel data layout
118 void change_conv2d_kernel_layout(coco::Conv2D *conv)
120 auto m = conv->module();
121 assert(m != nullptr);
122 auto d = enco::data(enco::session(m));
123 assert(d != nullptr);
125 auto old_obj = conv->ker();
126 assert(old_obj != nullptr);
127 auto old_bag = old_obj->bag();
128 assert(old_bag != nullptr);
130 if (old_obj->layout()->id() == coco::KernelLayouts::NHWC::uid())
132 // Skip if kernel already uses NHWC layout
136 const auto &ker_shape = old_obj->shape();
138 assert(d->allocated(old_bag));
140 auto new_bag = m->entity()->bag()->create(old_bag->size());
141 auto new_obj = m->entity()->object()->create<coco::KernelObject>();
143 new_obj->bag(new_bag);
144 new_obj->layout(coco::KernelLayouts::NHWC::create(ker_shape));
146 d->f32()->allocate(new_obj);
148 auto src = d->f32()->read(old_obj);
149 auto dst = d->f32()->access(new_obj);
151 const auto ker_N = ker_shape.count();
152 const auto ker_C = ker_shape.depth();
153 const auto ker_H = ker_shape.height();
154 const auto ker_W = ker_shape.width();
156 for (uint32_t n = 0; n < ker_N; ++n)
158 for (uint32_t ch = 0; ch < ker_C; ++ch)
160 for (uint32_t row = 0; row < ker_H; ++row)
162 for (uint32_t col = 0; col < ker_W; ++col)
164 dst->at(n, ch, row, col) = src->at(n, ch, row, col);
180 * @brief Return the set of all of allocated Load Op(s) in a given module
182 std::set<coco::Load *> loads(coco::Module *m)
184 std::set<coco::Load *> res;
186 for (uint32_t n = 0; n < m->entity()->op()->size(); ++n)
188 if (auto load = m->entity()->op()->at(n)->asLoad())
198 * @brief Return the set of every (allocated) Eval instruction in a given module
200 std::set<coco::Eval *> evals(coco::Module *m)
202 std::set<coco::Eval *> res;
204 for (uint32_t n = 0; n < m->entity()->instr()->size(); ++n)
206 if (auto eval = m->entity()->instr()->at(n)->asEval())
216 * @brief Return the set of allocated Conv2D op in a given module
218 std::set<coco::Conv2D *> convs(coco::Module *m)
220 std::set<coco::Conv2D *> res;
222 for (uint32_t n = 0; n < m->entity()->op()->size(); ++n)
224 if (auto op = m->entity()->op()->at(n)->asConv2D())
236 void runOnModule(coco::Module *m) const;
239 void runOnCode(enco::Code *) const;
242 void NormalizePass::runOnModule(coco::Module *m) const
244 // Insert Copy before all Load Op (if necessary)
245 for (auto load : loads(m))
247 insert_copy_before_load(load);
250 // Insert Copy after all Eval Instr (if necessary)
251 for (auto eval : evals(m))
253 insert_copy_after_eval(eval);
256 // Change Kernel Layout of Conv2D opertion (if necessary)
257 for (auto conv : convs(m))
259 change_conv2d_kernel_layout(conv);
263 void NormalizePass::runOnCode(enco::Code *code) const { runOnModule(code->module()); }
270 void convert_data_layout(enco::Code *code)
273 pass.runOnCode(code);