ONE - On-device Neural Engine
Loading...
Searching...
No Matches
enco Namespace Reference

Data Structures

class  AsmCode
 
struct  AvgPoolLoweringPass
 
struct  Backend
 
struct  BagDuplicationPass
 
class  Bundle
 
struct  BypassGenerationPass
 
struct  Code
 
struct  ConcatLoweringPass
 
struct  ConstantFoldingPass
 
struct  CopyLoweringPass
 
class  CppCode
 
struct  DataLayoutConversionPass
 
struct  DeadBagEliminationPass
 
struct  DeadObjectEliminationPass
 
struct  DuplicatedObjectReductionPass
 
struct  FeatureUnificationPass
 
struct  FreeInstrEliminationPass
 
struct  FreeOpEliminationPass
 
struct  Frontend
 
struct  GlobalData
 
class  HostBlockCompiler
 
struct  IdenticalObjectReductionPass
 
struct  IndirectCopyEliminationPass
 
struct  IntrinsicSelectionPass
 
class  MemoryContext
 Record C/C++ expression that denotes the base and size of memory region dedicated to each bag. More...
 
class  Pass
 
struct  PhaseConstructionPass
 
class  Pipeline
 
class  SubnetBlockCompiler
 Generate C++ code that invokes Android NN subnet. More...
 
struct  SubnetManager
 
struct  SubnetStruct
 A C++ struct that provides Android NN model & compilation. More...
 
class  SubnetStructBuilder
 

Typedefs

using SessionID = uint32_t
 
using GlobalOffset = uint32_t
 

Functions

void subst (coco::Object *from, coco::Object *into)
 Substitute all the USE occurrences of an object with another object.
 
std::vector< coco::Instr * > instr_sequence (coco::Module *m)
 Return instructions in execution order.
 
coco::FeatureShape output_shape (coco::Conv2D *conv2D)
 
bool validate_output_shape (Code *code)
 
bool validate (Code *code)
 
SessionID make_session (coco::Module *m, coco::Data *d)
 
SessionID session (const coco::Module *m)
 
SessionID session (const coco::Data *d)
 
coco::Modulemodule (const SessionID &sess)
 
coco::Datadata (const SessionID &sess)
 
Codecode (const SessionID &sess)
 
template<typename It >
void concat (std::ostream &os, const std::string &sep, It beg, It end)
 
template<typename It >
std::string concat (const std::string &sep, It beg, It end)
 
void lower_avgpool (enco::Code *)
 Rewrite NN API-incompatible average pooling.
 
void lower_concat (enco::Code *code)
 Lower eval(Concat(...)) as a sequence of shuffle instructions.
 
void fold_constants (enco::Code *)
 Evaluate "constant" expressions at compile time.
 
void lower_copy (enco::Code *code)
 Lower copy(...) instruction into shuffle(...)
 
void convert_data_layout (enco::Code *code)
 Insert data reordering if necessary.
 
void eliminate_dead_bag (enco::Code *code)
 Eliminate dead bags.
 
void eliminate_dead_object (enco::Code *code)
 Eliminate dead objects in IR.
 
void duplicate_inout_bag (enco::Code *code)
 Eliminate in/out bags by duplication.
 
void reduce_duplicated_object (enco::Code *code)
 Reduce duplicated feature objects as its dominating feature object.
 
void eliminate_free_instr (coco::Module *mod)
 Eliminate free instructions.
 
void eliminate_free_op (coco::Module *mod)
 Eliminate free op.
 
void generate_global_data (std::ostream &, enco::Code *)
 Generate 'Global' weight array.
 
void reduce_identical_object (enco::Code *code)
 Reduce identically copied objects as its original object.
 
void eliminate_indirect_copy (enco::Code *code)
 Convert all the indirect copies as a direct copy.
 
void select_intrinsic (enco::Code *)
 Select Intricsic (API) to be used.
 
void generate_bypass_shuffle (enco::Code *code)
 Add a bypass Shuffle if two continued Shuffles map same from-into.
 
void hoist_object (enco::Code *code)
 Update the base bag of each object if possible.
 
void split_into_phases (enco::Code *code)
 Split instructions into a set of phases.
 
std::set< coco::Block * > readers (const coco::Bag *bag)
 Returns the set of blocks that reads a given bag.
 
std::set< coco::Block * > updaters (const coco::Bag *bag)
 Return the set of blocks that updates a given bag.
 

Typedef Documentation

◆ GlobalOffset

using enco::GlobalOffset = typedef uint32_t

Definition at line 27 of file GlobalDataGeneration.h.

◆ SessionID

using enco::SessionID = typedef uint32_t

Definition at line 26 of file Session.h.

Function Documentation

◆ code()

◆ concat() [1/2]

template<typename It >
std::string enco::concat ( const std::string &  sep,
It  beg,
It  end 
)

Definition at line 48 of file String.h.

49{
50 std::stringstream ss;
51 concat(ss, sep, beg, end);
52 return ss.str();
53}
void concat(std::ostream &os, const std::string &sep, It beg, It end)
Definition String.h:31

References concat().

◆ concat() [2/2]

template<typename It >
void enco::concat ( std::ostream &  os,
const std::string &  sep,
It  beg,
It  end 
)

Definition at line 31 of file String.h.

32{
33 uint32_t count = 0;
34
35 for (auto it = beg; it != end; ++it, ++count)
36 {
37 if (count == 0)
38 {
39 os << *it;
40 }
41 else
42 {
43 os << sep << *it;
44 }
45 }
46}

References concat().

Referenced by concat(), and concat().

◆ convert_data_layout()

void enco::convert_data_layout ( enco::Code code)

Insert data reordering if necessary.

Definition at line 377 of file DataLayoutConversion.cpp.

378{
379 NormalizePass pass;
380 pass.runOnCode(code);
381}

References code().

Referenced by enco::DataLayoutConversionPass::run().

◆ data()

coco::Data * enco::data ( const SessionID sess)

Definition at line 52 of file Session.cpp.

52{ return sess_to_code.at(sess)->data(); }

◆ duplicate_inout_bag()

void enco::duplicate_inout_bag ( enco::Code code)

Eliminate in/out bags by duplication.

Definition at line 129 of file Duplicate.cpp.

130{
131 DuplicatePass duplicate;
132 duplicate.runOnCode(code);
133}

References code().

Referenced by enco::BagDuplicationPass::run().

◆ eliminate_dead_bag()

void enco::eliminate_dead_bag ( enco::Code code)

Eliminate dead bags.

A bag is referred to as dead if it is neither input nor output, and has no read. If a bag is dead, it is unnecessary to updates its values as these values are never used.

"eliminate_dead_bag" removes all the dead bags and its updaters from IR.

Definition at line 50 of file DeadBagElimination.cpp.

51{
52 auto m = code->module();
53
54 // Destroy a dead bag and its updaters
55 for (auto bag : dead_bags(m))
56 {
57 for (auto updater : coco::updaters(bag))
58 {
59 auto ins = updater->loc();
60
61 assert(ins != nullptr);
62
63 ins->detach();
64 m->entity()->instr()->destroy(ins);
65 }
66
67 bag->replaceWith(nullptr);
68 m->entity()->bag()->destroy(bag);
69 }
70}
Code * code(const SessionID &sess)
Definition Session.cpp:54
coco::Module * module(void) const
Definition Code.h:37

References code(), m, enco::Code::module(), and coco::updaters().

Referenced by enco::DeadBagEliminationPass::run().

◆ eliminate_dead_object()

void enco::eliminate_dead_object ( enco::Code code)

Eliminate dead objects in IR.

An object whose backing bag is unused is referred to as a dead object.

Dead Object Elimination (DOE) eliminates such dead objects along with their producer.

Definition at line 57 of file DeadObjectElimination.cpp.

58{
59 auto m = code->module();
60
61 // Destroy a dead object and its producer
62 for (auto obj : dead_objects(m))
63 {
64 if (auto producer = coco::producer(obj))
65 {
66 auto ins = producer->loc();
67 assert(ins != nullptr);
68
69 ins->detach();
70 m->entity()->instr()->destroy(ins);
71 }
72
73 m->entity()->object()->destroy(obj);
74 }
75}
Object::Producer * producer(const Object *)
Return the producer of a given object if it exists.
Definition Object.cpp:55

References code(), m, enco::Code::module(), and coco::producer().

Referenced by enco::DeadObjectEliminationPass::run().

◆ eliminate_free_instr()

void enco::eliminate_free_instr ( coco::Module mod)

Eliminate free instructions.

An instruction is referred to as "free" if it is not bound to any "block"

Definition at line 57 of file FreeInstrElimination.cpp.

58{
59 for (auto ins : free_instrs(m))
60 {
61 destroy(ins);
62 }
63}

References m.

Referenced by enco::FreeInstrEliminationPass::run().

◆ eliminate_free_op()

void enco::eliminate_free_op ( coco::Module mod)

Eliminate free op.

An op is referred to as "free" if it is not bound to any "instruction"

Definition at line 51 of file FreeOpElimination.cpp.

52{
53 for (auto op : candidates(m))
54 {
55 m->entity()->op()->destroy_all(op);
56 }
57}

References m.

Referenced by enco::FreeOpEliminationPass::run().

◆ eliminate_indirect_copy()

void enco::eliminate_indirect_copy ( enco::Code code)

Convert all the indirect copies as a direct copy.

‍BEFORE <<<

obj_0 = ... obj_1 = ... obj_2 = ...

copy(from: obj_0, into: obj_1) copy(from: obj_1, into: obj_2)

‍AFTER <<<

obj_0 = ... obj_1 = ... obj_2 = ...

copy(from: obj_0, into: obj_1) copy(from: obj_0, into: obj_2)

Definition at line 55 of file IndirectCopyElimination.cpp.

56{
57 auto m = code->module();
58
59 for (auto child : linked_copy_instrs(m))
60 {
61 auto from = child->from();
62 assert(from != nullptr);
63
64 // Find the irreducible origin
65 while (true)
66 {
67 if (auto producer = coco::producer(from))
68 {
69 if (auto parent = as_copy(producer->loc()))
70 {
71 assert(parent->from() != nullptr);
72 from = parent->from();
73 continue;
74 }
75 }
76
77 break;
78 }
79
80 child->from(from);
81 }
82}

References code(), m, enco::Code::module(), and coco::producer().

Referenced by enco::IndirectCopyEliminationPass::run().

◆ fold_constants()

void enco::fold_constants ( enco::Code code)

Evaluate "constant" expressions at compile time.

Definition at line 419 of file ConstantFolding.cpp.

420{
421 std::queue<coco::Bag *> q;
422
423 // Collect the initial set of "constant" bag
424 constant_bag_enumerator(code) << [&q](coco::Bag *bag) { q.push(bag); };
425
426 while (!q.empty())
427 {
428 auto candidate_bag = take(q);
429
430 // Scan the readers of each candidate bag
431 for (auto reader : coco::readers(candidate_bag))
432 {
433 // TODO Decide how to handle the reader with unknown instruction
434 if (auto ins = reader->loc())
435 {
436 fold_constant(q, ins);
437 }
438 }
439 }
440}
A collection of (abstracted) elements of the same type.
Definition Bag.h:48

References code(), and coco::readers().

Referenced by enco::ConstantFoldingPass::run().

◆ generate_bypass_shuffle()

void enco::generate_bypass_shuffle ( enco::Code code)

Add a bypass Shuffle if two continued Shuffles map same from-into.

bag_1 = Bag(size: N) bag_2 = Bag(size: N) bag_3 = Bag(size: N)

‍BEFORE <<<

Shuffle(from: bag_1, into: bag_2, [0 -> 0]) Shuffle(from: bag_2, into: bag_3, [0 -> 0])

Let's refer to the former shuffle as Shuffle 1 and the latter one as Shuffle 2. We can replace Shuffle 2 with new Shuffle 3 as follows when Shuffle 1 and Shuffle 2 map to the same position.

‍AFTER <<<

Shuffle(from: bag_1, into: bag_2, [0 -> 0]) <- Shuffle 1 Shuffle(from: bag_1, into: bag_3, [0 -> 0]) <- Shuffle 3

Note that Shuffle 1 can be eliminated when bag_2 is not used

Definition at line 25 of file Optimizations.cpp.

26{
27 auto m = code->module();
28
29 for (uint32_t n = 0; n < m->entity()->bag()->size(); ++n)
30 {
31 auto bag = m->entity()->bag()->at(n);
32
33 // NOTE The current implementation assumes that all the updates occurs before the first read
34 // TODO Remove this assumption
35 for (auto u : coco::updaters(bag))
36 {
37 if ((u->loc() == nullptr) || (u->loc()->asShuffle() == nullptr))
38 {
39 // Skip if updater is not a Shuffle instruction
40 continue;
41 }
42
43 for (auto r : coco::readers(bag))
44 {
45 if ((r->loc() == nullptr) || (r->loc()->asShuffle() == nullptr))
46 {
47 // Skip if reader is not a Shuffle instruction
48 continue;
49 }
50
51 auto shuffle_1 = u->loc()->asShuffle();
52 auto shuffle_2 = r->loc()->asShuffle();
53
54 // Construct a shuffle instruction
55 auto shuffle_3 = m->entity()->instr()->create<coco::Shuffle>();
56
57 shuffle_3->from(shuffle_1->from());
58 shuffle_3->into(shuffle_2->into());
59
60 // Attempt to construct a valid bypass shuffle instruction
61 bool valid = true;
62
63 for (const auto &C : shuffle_2->range())
64 {
65 auto B = shuffle_2->at(C);
66
67 if (!shuffle_1->defined(B))
68 {
69 valid = false;
70 break;
71 }
72
73 auto A = shuffle_1->at(B);
74
75 shuffle_3->insert(A, C);
76 }
77
78 if (valid)
79 {
80 // Insert shuffle_3 before shuffle_2 if shuffle_3 is a valid bypass of shuffle_2
81 shuffle_3->insertBefore(shuffle_2);
82
83 // NOTE shuffle_2 SHOULD BE detached and destroyed after shuffle_3 is inserted
84 shuffle_2->detach();
85 m->entity()->instr()->destroy(shuffle_2);
86 }
87 else
88 {
89 // Destroy shuffle_3 (bypass shuffle) if it is invalid
90 m->entity()->instr()->destroy(shuffle_3);
91 }
92 }
93 }
94 }
95}
virtual EntityManager * entity(void)=0
T * at(uint32_t n) const
Definition PtrManager.h:35
Generic element transfer.
Definition Instrs.h:116
Bag * from(void) const
Definition Instrs.h:131
bool valid(const Fildes &)
Definition Fildes.cpp:98
int32_t size[5]
Definition Slice.cpp:35
virtual BagManager * bag(void)=0

References coco::PtrManager< T >::at(), coco::EntityManager::bag(), code(), coco::Module::entity(), coco::Shuffle::from(), m, enco::Code::module(), coco::readers(), size, and coco::updaters().

Referenced by enco::BypassGenerationPass::run().

◆ generate_global_data()

void enco::generate_global_data ( std::ostream &  ,
enco::Code  
)

Generate 'Global' weight array.

NOTE Succeeding passes can access offsets via "GlobalData"

Definition at line 109 of file GlobalDataGeneration.cpp.

110{
111 auto m = code->module();
112 auto d = code->data();
113
114 auto ann_ctx = enco::SubnetManager::context(m);
115
116 auto global = make_unique<Global>(os);
117
118 //
119 // Emit Bag's weight
120 //
121 for (uint32_t n = 0; n < m->entity()->bag()->size(); ++n)
122 {
123 auto bag = m->entity()->bag()->at(n);
124
125 if (!d->allocated(bag))
126 {
127 // Skip if the weight value does not exist for a given bag
128 continue;
129 }
130
131 // NOTE The current implementation assumes that all the values are of float(fp32) type
132 // TODO Support non-float values
133 auto span = d->f32()->weight(bag);
134
135 assert(span.data() != nullptr);
136 assert(span.size() > 0);
137
138 auto const base = reinterpret_cast<const uint8_t *>(span.data());
139 uint32_t const size = span.size() * sizeof(float);
140
141 assert(bag_data_offset_ctx.find(bag) == bag_data_offset_ctx.end());
142 bag_data_offset_ctx[bag] = global->constant(base, size);
143 }
144
145 for (uint32_t n = 0; n < ann_ctx->count(); ++n)
146 {
147 auto binder = ann_ctx->nth(n);
148
149 auto emit = [&](const ann::OperandID & /*id*/, const ann::Operand *info) {
150 if (info->weight())
151 {
152 auto base = info->weight()->base();
153 auto size = info->weight()->size();
154
155 data_offset_ctx[info] = global->constant(base, size);
156 }
157 };
158 binder->module()->operand()->each(emit);
159 }
160
161 for (uint32_t n = 0; n < m->input()->size(); ++n)
162 {
163 auto input = m->input()->at(n);
164 auto dims = as_dims(input->shape());
165
166 name_offset_ctx[input] = global->constant(input->name());
167 dims_offset_ctx[input] = global->constant<uint32_t>(dims);
168 }
169
170 for (uint32_t n = 0; n < m->output()->size(); ++n)
171 {
172 auto output = m->output()->at(n);
173 auto dims = as_dims(output->shape());
174
175 name_offset_ctx[output] = global->constant(output->name());
176 dims_offset_ctx[output] = global->constant<uint32_t>(dims);
177 }
178}
volatile const char info[]
Dims< uint32_t > as_dims(const nncc::core::ADT::tensor::Shape &)
Definition dims.cpp:24
coco::Data * data(void) const
Definition Code.h:38
static const ANNContext * context(const coco::Module *m)
Definition Split.cpp:43

References code(), enco::SubnetManager::context(), enco::Code::data(), info, m, enco::Code::module(), and size.

◆ hoist_object()

void enco::hoist_object ( enco::Code code)

Update the base bag of each object if possible.

— Case 1 — Let us consider the following code:

bag_1 = Bag(size: 4) bag_2 = Bag(size: 1)

obj_1 = ... at bag_1 obj_2 = ... at bag_2

... Shuffle(from: bag_1, into: bag_2, [0 -> 0]) <- shuffle ...

Note that the content of bag_2 after shuffle is identical to a part of bag_1, so the following code is identical to the above code

bag_1 = Bag(size: 4) bag_2 = Bag(size: 1)

obj_1 = ... at bag_1 obj_2 = ... at bag_1

... Shuffle(from: bag_1, into: bag_2, [0 -> 0]) ...

— Case 2 — Let us consider the following code:

bag_1 = Bag(size: 4) bag_2 = Bag(size: 1) bag_3 = Bag(size: 1)

obj_1 = ... at bag_2 obj_2 = ... at bag_3

Shuffle(from: bag_1, into: bag_2, [0 -> 0]) <- shuffle_1 Shuffle(from: bag_1, into: bag_3, [0 -> 0]) <- shuffle_2

Note that the content of bag_3 after shuffle_2 is identical to that of bag_2 after shuffle_1, so the following code is identical to the above one:

bag_1 = Bag(size: 4) bag_2 = Bag(size: 1) bag_3 = Bag(size: 1)

obj_1 = ... at bag_2 obj_2 = ... at bag_2 <- HERE

Shuffle(from: bag_1, into: bag_2, [0 -> 0]) <- shuffle_1 Shuffle(from: bag_1, into: bag_3, [0 -> 0]) <- shuffle_2

"hoist_object" optimization rewrites the former code as the latter one.

NOTE "hoist_object" DOES NOT change any instruction. It just updates the base bag of objects of interest.

Definition at line 175 of file Optimizations.cpp.

176{
177 auto m = code->module();
178
179 //
180 // Case 1
181 //
182 for (uint32_t n = 0; n < m->entity()->instr()->size(); ++n)
183 {
184 if (auto shuffle = m->entity()->instr()->at(n)->asShuffle())
185 {
186 if (shuffle->parent() == nullptr)
187 {
188 continue;
189 }
190
191 if (hoistable(shuffle))
192 {
193 auto from = shuffle->from();
194 auto into = shuffle->into();
195
196 into->replaceAllDepsWith(from);
197 }
198 }
199 }
200
201 //
202 // Case 2
203 //
204 for (uint32_t n = 0; n < m->entity()->bag()->size(); ++n)
205 {
206 auto bag = m->entity()->bag()->at(n);
207
208 std::map<CodeIndex, coco::Shuffle *> collected;
209
210 for (auto reader : coco::readers(bag))
211 {
212 if (auto ins = reader->loc())
213 {
214 if (auto shuffle = ins->asShuffle())
215 {
216 collected[code_index(shuffle)] = shuffle;
217 }
218 }
219 }
220
221 std::vector<coco::Shuffle *> sorted;
222
223 for (auto it = collected.begin(); it != collected.end(); ++it)
224 {
225 sorted.emplace_back(it->second);
226 }
227
228 for (uint32_t curr = 0; curr < sorted.size(); ++curr)
229 {
230 auto const curr_ins = sorted.at(curr);
231 auto const curr_bag = curr_ins->into();
232
233 if (!complete(curr_ins))
234 {
235 continue;
236 }
237
238 for (uint32_t next = curr + 1; next < sorted.size(); ++next)
239 {
240 auto const next_ins = sorted.at(next);
241 auto const next_bag = next_ins->into();
242
243 if (!complete(next_ins))
244 {
245 continue;
246 }
247
248 if (compatible(curr_ins, next_ins))
249 {
250 next_bag->replaceAllDepsWith(curr_bag);
251 }
252 }
253 }
254 }
255}
void replaceAllDepsWith(Bag *)
Replace all the occurence of a bag in Object with another bag.
Definition Bag.cpp:76
Bag::ReaderSet readers(const Bag *)
Return a set of readers that reads a given bag.
Definition Bag.cpp:102

References coco::Shuffle::asShuffle(), coco::Shuffle::at(), code(), coco::Shuffle::from(), coco::Shuffle::into(), m, enco::Code::module(), coco::DLinkedList< Child, Parent >::Node::parent(), coco::readers(), coco::Bag::replaceAllDepsWith(), and size.

◆ instr_sequence()

std::vector< coco::Instr * > enco::instr_sequence ( coco::Module m)

Return instructions in execution order.

Definition at line 50 of file IRUtils.cpp.

51{
52 std::vector<coco::Instr *> res;
53
54 for (auto B = m->block()->head(); B; B = B->next())
55 {
56 for (auto I = B->instr()->head(); I; I = I->next())
57 {
58 res.emplace_back(I);
59 }
60 }
61
62 return res;
63}

References m.

Referenced by reduce_identical_object().

◆ lower_avgpool()

void enco::lower_avgpool ( enco::Code code)

Rewrite NN API-incompatible average pooling.

Definition at line 223 of file AvgPoolLowering.cpp.

224{
225 AvgPoolRewritePass pass;
226 pass.runOnCode(code);
227}

References code().

Referenced by enco::AvgPoolLoweringPass::run().

◆ lower_concat()

void enco::lower_concat ( enco::Code code)

Lower eval(Concat(...)) as a sequence of shuffle instructions.

Definition at line 101 of file ConcatLowering.cpp.

102{
103 auto m = code->module();
104
105 for (auto eval : candidates(m))
106 {
107 auto concat_f = eval->op()->asConcatF();
108 assert(concat_f != nullptr);
109
110 auto left_feature = concat_f->left()->asLoad()->object()->asFeature();
111 assert(left_feature != nullptr);
112 auto left_shape = as_tensor_shape(left_feature->layout());
113
114 auto right_feature = concat_f->right()->asLoad()->object()->asFeature();
115 assert(right_feature != nullptr);
116 auto right_shape = as_tensor_shape(right_feature->layout());
117
118 auto out_feature = eval->out()->asFeature();
119 assert(out_feature != nullptr);
120 auto out_shape = as_tensor_shape(out_feature->layout());
121
122 auto concat_axe = as_tensor_axis(concat_f->axis());
123
124 // Lower: Left -> Output
125 {
126 auto src_feature = left_feature;
127 auto src_shape = left_shape;
128
129 auto ins = m->entity()->instr()->create<coco::Shuffle>();
130
131 assert(src_feature->bag() != nullptr);
132 assert(out_feature->bag() != nullptr);
133
134 ins->from(src_feature->bag());
135 ins->into(out_feature->bag());
136
137 for (tensor::IndexEnumerator e{src_shape}; e.valid(); e.advance())
138 {
139 tensor::Index src_index = e.current();
140 tensor::Index out_index = e.current();
141
142 auto from = as_element_index(src_feature->layout(), src_index);
143 auto into = as_element_index(out_feature->layout(), out_index);
144
145 ins->insert(from, into);
146 }
147
148 ins->insertAfter(eval);
149 }
150
151 // Lower: Right -> Output
152 {
153 auto src_feature = right_feature;
154 auto src_shape = right_shape;
155
156 auto ins = m->entity()->instr()->create<coco::Shuffle>();
157
158 assert(src_feature->bag() != nullptr);
159 assert(out_feature->bag() != nullptr);
160
161 ins->from(src_feature->bag());
162 ins->into(out_feature->bag());
163
164 for (tensor::IndexEnumerator e{src_shape}; e.valid(); e.advance())
165 {
166 tensor::Index src_index = e.current();
167 tensor::Index out_index = e.current();
168
169 out_index.at(concat_axe) = out_index.at(concat_axe) + left_shape.dim(concat_axe);
170
171 auto from = as_element_index(src_feature->layout(), src_index);
172 auto into = as_element_index(out_feature->layout(), out_index);
173
174 ins->insert(from, into);
175 }
176
177 ins->insertAfter(eval);
178 }
179
180 // Unlink "Eval" and "ConcatF" op tree
181 eval->op(nullptr);
182
183 // Delete "Concat" op tree
184 m->entity()->op()->destroy(concat_f->left());
185 m->entity()->op()->destroy(concat_f->right());
186 m->entity()->op()->destroy(concat_f);
187
188 // Deatch "Eval" instruction from the block
189 eval->detach();
190
191 // Delete "Eval" instruction
192 m->entity()->instr()->destroy(eval);
193 }
194}
uint32_t & at(uint32_t axis)
Definition Index.cpp:49

References nncc::core::ADT::tensor::Index::at(), code(), m, enco::Code::module(), and nncc::core::ADT::tensor::IndexEnumerator::valid().

Referenced by enco::ConcatLoweringPass::run().

◆ lower_copy()

void enco::lower_copy ( enco::Code code)

Lower copy(...) instruction into shuffle(...)

Definition at line 28 of file CopyLowering.cpp.

29{
30 auto m = code->module();
31
32 std::set<coco::Copy *> lowered_copies;
33
34 for (uint32_t n = 0; n < m->entity()->instr()->size(); ++n)
35 {
36 auto ins = m->entity()->instr()->at(n);
37
38 assert(ins != nullptr);
39
40 if (ins->parent() == nullptr)
41 {
42 // Skip if instruction does not belong to a list
43 continue;
44 }
45
46 auto copy = ins->asCopy();
47
48 if (copy == nullptr)
49 {
50 // Skip if instruction is not a copy
51 continue;
52 }
53
54 // TODO Support non-Feature objects
55 auto ifm = copy->from()->asFeature();
56 auto ofm = copy->into()->asFeature();
57
58 if ((ifm == nullptr) || (ofm == nullptr))
59 {
60 continue;
61 }
62
63 assert(ifm->layout()->batch() == ofm->layout()->batch());
64 assert(ifm->layout()->shape() == ofm->layout()->shape());
65
66 auto shuffle = m->entity()->instr()->create<coco::Shuffle>();
67
68 shuffle->from(ifm->bag());
69 shuffle->into(ofm->bag());
70
71 const uint32_t B = ifm->layout()->batch();
72 const uint32_t C = ifm->layout()->shape().depth();
73 const uint32_t H = ifm->layout()->shape().height();
74 const uint32_t W = ifm->layout()->shape().width();
75
76 for (uint32_t b = 0; b < B; ++b)
77 {
78 for (uint32_t ch = 0; ch < C; ++ch)
79 {
80 for (uint32_t row = 0; row < H; ++row)
81 {
82 for (uint32_t col = 0; col < W; ++col)
83 {
84 const auto from = ifm->layout()->at(b, ch, row, col);
85 const auto into = ofm->layout()->at(b, ch, row, col);
86
87 shuffle->insert(from, into);
88 }
89 }
90 }
91 }
92
93 shuffle->insertBefore(copy);
94 lowered_copies.insert(copy);
95 }
96
97 // Destroy lowered copy
98 for (const auto &copy : lowered_copies)
99 {
100 copy->detach();
101 m->entity()->instr()->destroy(copy);
102 }
103}
C
Definition infer.py:52
virtual InstrManager * instr(void)=0

References coco::PtrManager< T >::at(), code(), coco::Module::entity(), coco::Shuffle::from(), coco::EntityManager::instr(), m, enco::Code::module(), and size.

Referenced by enco::CopyLoweringPass::run().

◆ make_session()

SessionID enco::make_session ( coco::Module m,
coco::Data d 
)

Definition at line 36 of file Session.cpp.

37{
38 static uint32_t sess = 0;
39 SessionID curr{sess++};
40
41 sess_to_code[curr] = make_unique<Code>(m, d);
42 module_to_sess[m] = curr;
43 data_to_sess[d] = curr;
44
45 return curr;
46}
uint32_t SessionID
Definition Session.h:26

References m.

◆ module()

coco::Module * enco::module ( const SessionID sess)

Definition at line 51 of file Session.cpp.

51{ return sess_to_code.at(sess)->module(); }

Referenced by validate_output_shape().

◆ output_shape()

coco::FeatureShape enco::output_shape ( coco::Conv2D conv2D)

Definition at line 24 of file IRValidator.cpp.

25{
26 auto load = conv2D->arg()->asLoad();
27 assert(load);
28
29 auto ifm = load->object()->asFeature();
30 assert(ifm);
31
32 auto ker = conv2D->ker();
33 auto stride = conv2D->stride();
34 auto pad = conv2D->pad();
35
36 auto striding_width = ifm->shape().width() + pad->left() + pad->right() - ker->shape().width();
37 auto striding_height = ifm->shape().height() + pad->top() + pad->bottom() - ker->shape().height();
38
39 // Normally the formula is round(striding_width)/stride->horizontal.
40 // in coco IR, striding_width should be a multiple of stride->horizontal(), so round(...) was
41 // removed. So does striding_height.
42 assert(striding_width % stride->horizontal() == 0);
43 assert(striding_height % stride->vertical() == 0);
44
45 auto ofm_width = striding_width / stride->horizontal() + 1;
46 auto ofm_height = striding_height / stride->vertical() + 1;
47
48 return coco::FeatureShape(ifm->shape().batch(), ker->shape().count(), ofm_height, ofm_width);
49}
Padding2D * pad(void)
Definition Ops.h:120
KernelObject * ker(void) const
Definition Conv2D.cpp:64
Stride2D * stride(void)
Definition Ops.h:124
Op * arg(uint32_t n) const final
Return N-th argument.
The shape of a feature map.
uint32_t left(void) const
Definition Padding2D.h:49

References coco::Conv2D::arg(), coco::Conv2D::ker(), coco::Padding2D::left(), coco::Conv2D::pad(), and coco::Conv2D::stride().

◆ readers()

std::set< coco::Block * > enco::readers ( const coco::Bag bag)

Returns the set of blocks that reads a given bag.

Definition at line 22 of file Usage.cpp.

23{
24 std::set<coco::Block *> res;
25
26 for (auto read : coco::readers(bag))
27 {
28 assert(read != nullptr);
29 auto instr = read->loc();
30 assert(instr != nullptr);
31 auto block = instr->parent();
32 assert(block != nullptr);
33
34 res.insert(block);
35 }
36
37 return res;
38}

References coco::readers().

◆ reduce_duplicated_object()

void enco::reduce_duplicated_object ( enco::Code code)

Reduce duplicated feature objects as its dominating feature object.

‍BEFORE <<<

obj_0 = Feature(layout: ???) at ... obj_1 = Feature(layout: BHWC) at ... obj_2 = Feature(layout: BHWC) at ...

copy(from: obj_0, into: obj_1) copy(from: obj_0, into: obj_2)

... Use(obj_1) Use(obj_2) ...

‍AFTER <<<

obj_0 = Feature(layout: ???) at ... obj_1 = Feature(layout: BHWC) at ... obj_2 = Feature(layout: BHWC) at ...

copy(from: obj_0, into: obj_1) copy(from: obj_0, into: obj_2)

... Use(obj_1) Use(obj_1) <– CHANGED ...

NOTE Given a set of feature objects, a feature object referred to as a dominating feature object if its producer proceeds the producer of every feature object in the given set

Definition at line 81 of file DuplicatedObjectReduction.cpp.

82{
83 auto m = code->module();
84
85 for (const auto &src : features(m))
86 {
87 auto copied = candidates(src);
88
89 if (copied.size() <= 1)
90 {
91 continue;
92 }
93
94 // Find the dominator
95 coco::FeatureObject *dominator = nullptr;
96
97 for (auto candidate : copied)
98 {
99 if (dominator == nullptr)
100 {
101 dominator = candidate;
102 }
103 else if (code_index(coco::producer(candidate)) < code_index(coco::producer(dominator)))
104 {
105 dominator = candidate;
106 }
107 }
108
109 // Replace all the occurunce of dominated objects with its dominator
110 copied.erase(dominator);
111
112 for (auto dominatee : copied)
113 {
114 subst(dominatee, dominator);
115 }
116 }
117}
FeatureMap values (used in CNN)
void subst(coco::Object *from, coco::Object *into)
Substitute all the USE occurrences of an object with another object.
Definition IRUtils.cpp:38

References code(), m, enco::Code::module(), coco::producer(), and subst().

Referenced by enco::DuplicatedObjectReductionPass::run().

◆ reduce_identical_object()

void enco::reduce_identical_object ( enco::Code code)

Reduce identically copied objects as its original object.

‍BEFORE <<<

bag_0 = Bag(size: N) bag_1 = Bag(size: N)

obj_0 = Feature(layout: BHWC) at bag_0 obj_1 = Feature(layout: BHWC) at bag_1

copy(from: obj_0, into: obj_1) ... Use(obj_0) Use(obj_1) ...

‍AFTER <<<

bag_0 = Bag(size: N) bag_1 = Bag(size: N)

obj_0 = Feature(layout: BHWC) at bag_0 obj_1 = Feature(layout: BHWC) at bag_1

copy(from: obj_0, into: obj_1) ... Use(obj_0) Use(obj_0) <- obj_1 is replaced ...

Definition at line 25 of file IdenticalObjectReduction.cpp.

26{
27 auto m = code->module();
28
29 std::set<coco::Copy *> detached;
30
31 // Preceding optimizations may generate "free" instructions.
32 // - i.e. an instruction not linked to a block
33 //
34 // Let's iterate over only a sequence of "bounded" instructions.
35 for (auto ins : instr_sequence(m))
36 {
37 assert(ins != nullptr);
38 assert(ins->parent() != nullptr);
39
40 auto copy = ins->asCopy();
41
42 if (copy == nullptr)
43 {
44 // Skip if instruction is not a copy
45 continue;
46 }
47
48 // TODO Support non-Feature Objects
49 auto ifm = copy->from()->asFeature();
50 auto ofm = copy->into()->asFeature();
51
52 assert(ofm->bag() != nullptr);
53
54 if (ifm->layout()->id() != ofm->layout()->id())
55 {
56 continue;
57 }
58
59 if (ifm->layout()->id() != coco::FeatureLayouts::BHWC::uid())
60 {
61 continue;
62 }
63
64 // Skip if this copy produces network output
65 if (ofm->bag()->output())
66 {
67 // TODO Optimize this case
68 //
69 // Note that the code under optimization is of the following form:
70 //
71 // %ifm <- Instr(...)
72 // %ofm <- Copy(%ifm)
73 //
74 // Let's assume that "Copy" is the only reader of %ifm (to be precise, its bag).
75 //
76 // Then, it is possible to rewrite the above fragment as follows:
77 //
78 // %ofm <- Instr(...)
79 //
80 continue;
81 }
82
83 if (ofm->bag()->reads()->size() > 0)
84 {
85 // Let us consider the following code:
86 //
87 // Bag:
88 // %bag_0 = Bag(...)
89 // %bag_1 = Bag(...)
90 // %bag_2 = Bag(...)
91 //
92 // Object:
93 // %obj_0 = FeatureObject(bag: %bag_0)
94 // %obj_1 = FeatureObject(bag: %bag_1)
95 //
96 // Instr:
97 // copy an object from %obj_0 into %obj_1
98 // shuffle values from %bag_1 into %bag_2
99 // eval Conv2D with %obj_1
100 //
101 // Identical Object Reduction (IOR) tries to eliminate the first copy via
102 // substitution (substitute all the occurrence of %obj_1 as use with %obj_0).
103 //
104 // Here is the code transformed by IOR:
105 //
106 // Bag:
107 // %bag_0 = Bag(...)
108 // %bag_1 = Bag(...)
109 // %bag_2 = Bag(...)
110 //
111 // Object:
112 // %obj_0 = FeatureObject(bag: %bag_0)
113 // %obj_1 = FeatureObject(bag: %bag_1)
114 //
115 // Instr:
116 // shuffle values from %bag_1 into %bag_2
117 // eval Conv2D with %obj_0
118 //
119 // Note that there is no updater of %bag_1 after IOR, and thus the behavior
120 // of the first shuffle instruction has changed.
121 //
122 // This examples shows that it is impossible to simply substitute %obj_1
123 // with %obj_0 in the presence of readers over its backing bag.
124 continue;
125 }
126
127 subst(copy->into(), copy->from());
128
129 copy->detach();
130 detached.insert(copy);
131 }
132
133 for (auto copy : detached)
134 {
135 m->entity()->instr()->destroy(copy);
136 }
137}
static const FeatureLayout::ID * uid(void)
std::vector< coco::Instr * > instr_sequence(coco::Module *m)
Return instructions in execution order.
Definition IRUtils.cpp:50

References code(), instr_sequence(), m, enco::Code::module(), subst(), and coco::FeatureLayouts::BHWC::uid().

Referenced by enco::IdenticalObjectReductionPass::run().

◆ select_intrinsic()

void enco::select_intrinsic ( enco::Code )

Select Intricsic (API) to be used.

This pass is analogue of "Instruction Selection" pass. This "Intrisic Selection" pass will replace a general coco IR instruction into a backend-specific coco (extended) IR instruction.

Definition at line 77 of file IntrinsicSelection.cpp.

78{
79 auto m = code->module();
80
81 for (auto blk = m->block()->head(); blk; blk = blk->next())
82 {
83 auto ins = blk->instr()->head();
84
85 while (ins)
86 {
87 if (auto rewritten_ins = rewrite(ins))
88 {
89 rewritten_ins->insertBefore(ins);
90 ins->detach();
91
92 ins = rewritten_ins;
93 }
94
95 ins = ins->next();
96 }
97 }
98}

References code(), m, and enco::Code::module().

Referenced by enco::IntrinsicSelectionPass::run().

◆ session() [1/2]

SessionID enco::session ( const coco::Data d)

Definition at line 49 of file Session.cpp.

49{ return data_to_sess.at(d); }

◆ session() [2/2]

SessionID enco::session ( const coco::Module m)

Definition at line 48 of file Session.cpp.

48{ return module_to_sess.at(m); }

References m.

◆ split_into_phases()

void enco::split_into_phases ( enco::Code code)

Split instructions into a set of phases.

Definition at line 1227 of file Split.cpp.

1228{
1229 SplitPass split;
1230 split.runOnCode(code);
1231}

References code().

Referenced by enco::PhaseConstructionPass::run().

◆ subst()

void enco::subst ( coco::Object from,
coco::Object into 
)

Substitute all the USE occurrences of an object with another object.

Replace all the "USE" of 'from' with 'into'.

Parameters
fromObject to be replaced
intoObject to be used instead NOTE This maybe used when something like – 'from' will be removed so we need to replace object Consumers that use 'from' to 'into' EXAMPLE { subst(child, bigone); m->entity()->object()->destroy(child); } This code will change all the Consumers that use 'child' to 'bigone' and destroy the 'child' object.

NOTE subst(from, into) WILL NOT update 'DEF'

Definition at line 38 of file IRUtils.cpp.

39{
40 assert(from != into);
41
42 while (!from->uses()->empty())
43 {
44 auto use = *(from->uses()->begin());
45
46 use->value(into);
47 }
48}
const UseSet * uses(void) const
Definition Object.cpp:52

References coco::Object::uses().

Referenced by reduce_duplicated_object(), and reduce_identical_object().

◆ updaters()

std::set< coco::Block * > enco::updaters ( const coco::Bag bag)

Return the set of blocks that updates a given bag.

Definition at line 40 of file Usage.cpp.

41{
42 std::set<coco::Block *> res;
43
44 for (auto update : coco::updaters(bag))
45 {
46 assert(update != nullptr);
47 auto instr = update->loc();
48 assert(instr != nullptr);
49 auto block = instr->parent();
50 assert(block != nullptr);
51
52 res.insert(block);
53 }
54
55 return res;
56}

References coco::updaters().

◆ validate()

bool enco::validate ( Code code)

Definition at line 83 of file IRValidator.cpp.

83{ return validate_output_shape(code); }
bool validate_output_shape(Code *code)

References code(), validate(), and validate_output_shape().

Referenced by validate().

◆ validate_output_shape()

bool enco::validate_output_shape ( Code code)

Definition at line 51 of file IRValidator.cpp.

52{
53 auto module = code->module();
54
55 // for each eval ( conv2d ( ... ) ), check the output shape of conv2D matches output of eval
56 for (auto blk = module->block()->head(); blk; blk = blk->next())
57 {
58 for (auto instr = blk->instr()->head(); instr; instr = instr->next())
59 {
60 auto eval = instr->asEval();
61 if (eval == nullptr)
62 continue;
63
64 auto op = eval->op();
65 if (!op->asConv2D())
66 continue;
67
68 auto conv2D = op->asConv2D();
69 auto expected_shape = output_shape(conv2D);
70
71 auto eval_out = eval->out()->asFeature();
72 assert(eval_out);
73
74 auto actual_shape = eval_out->shape();
75
76 if (actual_shape != expected_shape)
77 return false;
78 }
79 }
80 return true;
81}
const luci_interpreter::RuntimeShape output_shape

References coco::Module::block(), coco::DLinkedList< Child, Parent >::Head::head(), module(), and output_shape.

Referenced by validate().