ONE - On-device Neural Engine
Loading...
Searching...
No Matches
enco::CppCode Class Reference

#include <CppCode.h>

Public Member Functions

 CppCode (const std::string &varname, const Code *code)
 
void dump (std::ostream &) const
 

Detailed Description

Definition at line 27 of file CppCode.h.

Constructor & Destructor Documentation

◆ CppCode()

enco::CppCode::CppCode ( const std::string &  varname,
const Code code 
)
inline

Definition at line 30 of file CppCode.h.

30 : _varname{varname}, _code{code}
31 {
32 // DO NOTHING
33 }
Code * code(const SessionID &sess)
Definition Session.cpp:54

Member Function Documentation

◆ dump()

void enco::CppCode::dump ( std::ostream &  os) const

Create a struct for each android NN network of the following form:

struct [Name] { ...

[Name]() // constructor { ... }

~[Name]() // destructor { ... } };

Definition at line 145 of file CppCode.cpp.

146{
147 auto m = _code->module();
148 auto d = _code->data();
149 auto ann_ctx = enco::SubnetManager::context(m);
150
151 NetworkStruct network;
152 InvokeFunction invoke;
153 pp::LinearDocument internal;
154
155 auto data_exp = [this](const GlobalOffset &off) { return pp::fmt(_varname, " + ", off); };
156
157 // Record the subnet information
158 std::map<const ANNBinder *, SubnetInfo> subnet_ctx;
159
179 for (uint32_t n = 0; n < ann_ctx->count(); ++n)
180 {
181 SubnetStructBuilder builder;
182
183 auto subnet_binder = ann_ctx->nth(n);
184 auto subnet_struct_name = pp::fmt("Subnet_", subnet_ctx.size());
185 auto subnet_field_name = pp::fmt("_subnet_", subnet_ctx.size());
186
187 // Create global data variable
188 auto emit_weight = [&](const ann::OperandID &, const ann::Operand *info) {
189 if (info->weight())
190 {
191 auto size = info->weight()->size();
193 auto base_exp = pp::fmt("reinterpret_cast<const void *>(", data_exp(off), ")");
194 auto size_exp = pp::fmt(size);
195
196 builder.expr(info, base_exp, size_exp);
197 }
198 };
199 subnet_binder->module()->operand()->each(emit_weight);
200
201 auto subnet_struct_content = builder.build(subnet_binder);
202
203 // Emit C++ declaration
204 internal.append("struct ", subnet_struct_name);
205 internal.append("{");
206 internal.indent();
207
208 internal.append(subnet_struct_content->def());
209
210 internal.append(subnet_struct_name, "()");
211 internal.append("{");
212 internal.indent();
213 internal.append(subnet_struct_content->ctor());
214 internal.unindent();
215 internal.append("}");
216
217 internal.append("~", subnet_struct_name, "()");
218 internal.append("{");
219 internal.indent();
220 internal.append(subnet_struct_content->dtor());
221 internal.unindent();
222 internal.append("}");
223
224 internal.unindent();
225 internal.append("};");
226
227 // Declare subnet field
228 network.def.append(subnet_struct_name, " ", subnet_field_name, ";");
229
230 // Update subnet context
231 SubnetInfo subnet_info;
232
233 subnet_info.struct_name = subnet_struct_name;
234 subnet_info.compilation_field = subnet_struct_content->compilation();
235 subnet_info.field_name = subnet_field_name;
236
237 assert(subnet_ctx.find(subnet_binder) == subnet_ctx.end());
238 subnet_ctx[subnet_binder] = subnet_info;
239 }
240
241 MemoryContext mem;
242
243 // Set dedicated memory region for network inputs
244 for (uint32_t n = 0; n < m->input()->size(); ++n)
245 {
246 mem.base(m->input()->at(n)->bag(), pp::fmt("net->inputs[", n, "].ptr"));
247 mem.size(m->input()->at(n)->bag(), pp::fmt("net->inputs[", n, "].len"));
248 }
249
250 // Set dedicated memory region for network outputs
251 for (uint32_t n = 0; n < m->output()->size(); ++n)
252 {
253 mem.base(m->output()->at(n)->bag(), pp::fmt("net->outputs[", n, "].ptr"));
254 mem.size(m->output()->at(n)->bag(), pp::fmt("net->outputs[", n, "].len"));
255 }
256
257 // Set dedicated memory region for constant weight values
258 // TODO Support non-constant bags with initial values
259 for (uint32_t n = 0; n < m->entity()->bag()->size(); ++n)
260 {
261 auto bag = m->entity()->bag()->at(n);
262
263 if (!d->allocated(bag))
264 {
265 // Skip if no weight exists
266 continue;
267 }
268
269 // TODO Support non-float(fp32) weight
271
272 auto base_expr = data_exp(offset);
273 auto size_expr = pp::fmt(bag->size() * sizeof(float));
274
275 mem.base(bag, base_expr);
276 mem.size(bag, size_expr);
277 }
278
279 // Set dedicated memory reigion for intermediate buffer(s)
280 for (const auto &bag : hosted(_code))
281 {
282 // Skip if a bag is already allocated
283 if (mem.member(bag))
284 {
285 continue;
286 }
287
288 auto name = invoke.local();
289
290 invoke.head.append("auto ", name, " = new uint8_t[", bag->size() * sizeof(float), "];");
291 invoke.tail.append("delete[] ", name, ";");
292
293 mem.base(bag, name);
294 mem.size(bag, pp::fmt(bag->size() * sizeof(float)));
295 }
296
297 // Create Code Block Builder
298 SubnetBlockCompiler subnet_compiler{mem};
299
300 for (auto it = subnet_ctx.begin(); it != subnet_ctx.end(); ++it)
301 {
302 // Specify how to access ANeuralNetworksCompilation
303 const auto &info = it->second;
304 subnet_compiler.bind(it->first, pp::fmt("net->", info.field_name, ".", info.compilation_field));
305 }
306
307 HostBlockCompiler host_compiler{mem};
308
309 for (auto blk = m->block()->head(); blk; blk = blk->next())
310 {
311 invoke.body.append("{");
312 invoke.body.indent();
313
314 if (auto binder = ann_ctx->find(blk))
315 {
316 // Generate code that invokes Android NN sub-network
317 auto lines = subnet_compiler.compile(binder);
318 invoke.body.append(*lines);
319 }
320 else
321 {
322 // Generate code on-the-fly for Android NN-incompatible blocks
323 auto lines = host_compiler.compile(blk);
324 invoke.body.append(*lines);
325 }
326
327 invoke.body.unindent();
328 invoke.body.append("}");
329 }
330
331 //
332 // Generate full C++ source code with code snippet
333 //
334 const std::string name{"Network"};
335
336 pp::LinearDocument includes;
337 {
338 // Include Android NN API header
339 includes.append("#include <NeuralNetworks.h>");
340 includes.append();
341
342 includes.append("#include <cstdint>");
343 includes.append("#include <cassert>");
344 includes.append("#include <array>");
345 }
346
347 pp::LinearDocument net_def;
348 {
349 net_def.append("struct ", name, " {");
350 net_def.indent();
351 net_def.append("struct Shape { uint32_t rank; const uint32_t *dims; };");
352 net_def.append("struct Input {");
353 net_def.indent();
354 net_def.append("const char *name;");
355 net_def.append("const uint8_t *ptr;");
356 net_def.append("unsigned len;");
357 net_def.append("Shape shape;");
358 net_def.unindent();
359 net_def.append("};");
360 net_def.append("struct Output {");
361 net_def.indent();
362 net_def.append("const char *name;");
363 net_def.append("uint8_t *ptr;");
364 net_def.append("unsigned len;");
365 net_def.append("Shape shape;");
366 net_def.unindent();
367 net_def.append("};");
368 net_def.append();
369 net_def.append(name, "();");
370 net_def.append("~", name, "();");
371
372 net_def.append();
373 net_def.append(network.def);
374 net_def.append();
375
376 net_def.append("std::array<Input, ", m->input()->size(), "> inputs;");
377 net_def.append("std::array<Output, ", m->output()->size(), "> outputs;");
378
379 net_def.unindent();
380 net_def.append("};");
381 }
382
383 pp::LinearDocument net_ctor;
384 {
385 net_ctor.append("Network::Network() {");
386 net_ctor.indent();
387
388 // Initialize input metadata
389 for (uint32_t n = 0; n < m->input()->size(); ++n)
390 {
391 auto input = m->input()->at(n);
392 auto dims = as_dims(input->shape());
393
394 auto name_off = enco::GlobalData::name_offset(input);
395 auto name_exp = pp::fmt("reinterpret_cast<const char *>(", data_exp(name_off), ")");
396 auto dims_off = enco::GlobalData::dims_offset(input);
397 auto dims_exp = pp::fmt("reinterpret_cast<const unsigned *>(", data_exp(dims_off), ")");
398
399 net_ctor.append("inputs.at(", n, ").name = ", name_exp, ";");
400 net_ctor.append("inputs.at(", n, ").shape.rank = ", dims.size(), ";");
401 net_ctor.append("inputs.at(", n, ").shape.dims = ", dims_exp, ";");
402 }
403
404 // Initialize output metadata
405 for (uint32_t n = 0; n < m->output()->size(); ++n)
406 {
407 auto output = m->output()->at(n);
408 auto dims = as_dims(output->shape());
409
410 auto name_off = enco::GlobalData::name_offset(output);
411 auto name_exp = pp::fmt("reinterpret_cast<const char *>(", data_exp(name_off), ")");
412 auto dims_off = enco::GlobalData::dims_offset(output);
413 auto dims_exp = pp::fmt("reinterpret_cast<const unsigned *>(", data_exp(dims_off), ")");
414
415 net_ctor.append("outputs.at(", n, ").name = ", name_exp, ";");
416 net_ctor.append("outputs.at(", n, ").shape.rank = ", dims.size(), ";");
417 net_ctor.append("outputs.at(", n, ").shape.dims = ", dims_exp, ";");
418 }
419
420 // TODO Implement this
421 net_ctor.unindent();
422 net_ctor.append("}");
423 }
424
425 pp::LinearDocument net_dtor;
426 {
427 net_dtor.append("Network::~Network() {");
428 net_dtor.indent();
429 // TODO Implement this
430 net_dtor.unindent();
431 net_dtor.append("}");
432 }
433
434 pp::LinearDocument source;
435
436 source.append(includes);
437 source.append();
438 source.append("extern uint8_t ", _varname, "[];");
439 source.append();
440
441 source.append("namespace");
442 source.append("{");
443 source.append(internal);
444 source.append("} // namespace");
445 source.append();
446 source.append(net_def);
447 source.append();
448 source.append(net_ctor);
449 source.append();
450 source.append(net_dtor);
451
452 source.append();
453 source.append(name, " *", name, "_construct() { return new ", name, "{}; }");
454 source.append("void ", name, "_destruct(", name, " *net) { delete net; }");
455
456 source.append();
457
458 // Emit Network_input_count function
459 source.append("unsigned ", name, "_input_count(const ", name, " *net) {");
460 source.indent();
461 source.append("return net->inputs.size();");
462 source.unindent();
463 source.append("}");
464
465 source.append();
466
467 // Emit Network_input_name function
468 source.append("const char *", name, "_input_name(const ", name, " *net, unsigned n) {");
469 source.indent();
470 source.append("return net->inputs.at(n).name;");
471 source.unindent();
472 source.append("}");
473
474 // Emit Network_input_rank function
475 source.append("unsigned ", name, "_input_rank(const ", name, " *net, unsigned n) {");
476 source.indent();
477 source.append("return net->inputs.at(n).shape.rank;");
478 source.unindent();
479 source.append("}");
480
481 // Emit Network_input_dim function
482 source.append("unsigned ", name, "_input_dim(const ", name, " *net, unsigned n, unsigned axe)");
483 source.append("{");
484 source.indent();
485 source.append("return net->inputs.at(n).shape.dims[axe];");
486 source.unindent();
487 source.append("}");
488
489 // Emit Network_input_bind function
490 source.append("void ", name, "_input_bind(", name,
491 " *net, unsigned n, const void *ptr, unsigned len) {");
492 source.indent();
493 source.append("net->inputs.at(n).ptr = reinterpret_cast<const uint8_t *>(ptr);");
494 source.append("net->inputs.at(n).len = len;");
495 source.unindent();
496 source.append("}");
497
498 source.append();
499
500 // Emit Network_output_count function
501 source.append("unsigned ", name, "_output_count(const ", name, " *net) {");
502 source.indent();
503 source.append("return net->outputs.size();");
504 source.unindent();
505 source.append("}");
506
507 source.append();
508
509 // Emit Network_output_name function
510 source.append("const char *", name, "_output_name(const ", name, " *net, unsigned n) {");
511 source.indent();
512 source.append("return net->outputs.at(n).name;");
513 source.unindent();
514 source.append("}");
515
516 // Emit Network_output_rank function
517 source.append("unsigned ", name, "_output_rank(const ", name, " *net, unsigned n) {");
518 source.indent();
519 source.append("return net->outputs.at(n).shape.rank;");
520 source.unindent();
521 source.append("}");
522
523 // Emit Network_output_dim function
524 source.append("unsigned ", name, "_output_dim(const ", name, " *net, unsigned n, unsigned axe)");
525 source.append("{");
526 source.indent();
527 source.append("return net->outputs.at(n).shape.dims[axe];");
528 source.unindent();
529 source.append("}");
530
531 // Emit Network_output_bind function
532 source.append("void ", name, "_output_bind(", name,
533 " *net, unsigned n, void *ptr, unsigned len) {");
534 source.indent();
535 source.append("net->outputs.at(n).ptr = reinterpret_cast<uint8_t *>(ptr);");
536 source.append("net->outputs.at(n).len = len;");
537 source.unindent();
538 source.append("}");
539
540 source.append();
541
542 source.append("void ", name, "_invoke(", name, " *net) {");
543 source.indent();
544 source.append(invoke.head);
545 source.append(invoke.body);
546 source.append(invoke.tail);
547 source.unindent();
548 source.append("}");
549
550 os << source;
551}
__global uchar * offset(const Image *img, int x, int y)
Definition helpers.h:540
volatile const char info[]
uint32_t GlobalOffset
Dims< uint32_t > as_dims(const nncc::core::ADT::tensor::Shape &)
Definition dims.cpp:24
int32_t size[5]
Definition Slice.cpp:35
coco::Module * module(void) const
Definition Code.h:37
coco::Data * data(void) const
Definition Code.h:38
static GlobalOffset data_offset(const ann::Operand *)
static GlobalOffset name_offset(const coco::Input *)
static GlobalOffset dims_offset(const coco::Input *)
static const ANNContext * context(const coco::Module *m)
Definition Split.cpp:43

References pp::LinearDocument::append(), enco::MemoryContext::base(), enco::SubnetStructBuilder::build(), enco::SubnetManager::context(), enco::Code::data(), enco::GlobalData::data_offset(), enco::GlobalData::dims_offset(), enco::SubnetStructBuilder::expr(), pp::LinearDocument::indent(), info, m, enco::MemoryContext::member(), enco::Code::module(), enco::GlobalData::name_offset(), offset(), enco::MemoryContext::size(), size, and pp::LinearDocument::unindent().


The documentation for this class was generated from the following files: