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 #include "CircleOperationExporter.h"
18 #include "CircleExporterUtils.h"
21 #include <luci/IR/CircleNode.h>
22 #include <luci/IR/CircleNodes.h>
23 #include <luci/IR/CircleNodeVisitor.h>
24 #include <luci/Service/CircleShapeInference.h>
25 #include <luci/UserSettings.h>
28 #include <loco/IR/CanonicalNodeVisitor.h>
29 #include <oops/InternalExn.h>
31 #include <flatbuffers/flexbuffers.h>
33 using namespace flatbuffers;
34 using namespace circle;
43 FlatBufferBuilder &builder;
44 SerializedModelData &md;
45 SerializedGraphData &gd;
49 * @brief Exports CircleMaxPool2D or CircleAveragePool2D
51 * @note CirclePool2D should be one of CircleMaxPool2D or CircleAveragePool2D
53 template <class CirclePool2D>
54 void export_pool_2d(ExportContext &ctx, CirclePool2D *node, circle::BuiltinOperator builtin_op)
56 LUCI_ASSERT(builtin_op == circle::BuiltinOperator_MAX_POOL_2D ||
57 builtin_op == circle::BuiltinOperator_L2_POOL_2D ||
58 builtin_op == circle::BuiltinOperator_AVERAGE_POOL_2D,
59 "Should be L2Pool, MaxPool or AvgPool");
60 LUCI_ASSERT(node->padding() != luci::Padding::UNDEFINED, "Padding is not set");
62 uint32_t op_idx = ctx.md.registerBuiltinOpcode(builtin_op, node->op_version());
63 std::vector<int32_t> inputs_vec{get_tensor_index(node->value())};
64 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
65 auto inputs = ctx.builder.CreateVector(inputs_vec);
66 auto outputs = ctx.builder.CreateVector(outputs_vec);
68 circle::Padding padding = getOpPadding(node->padding());
70 auto options = CreatePool2DOptions(ctx.builder, padding, node->stride()->w(), node->stride()->h(),
71 node->filter()->w(), node->filter()->h(),
72 to_circle_actfunc(node->fusedActivationFunction()));
73 auto op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs,
74 circle::BuiltinOptions_Pool2DOptions, options.Union());
75 ctx.gd._operators.push_back(op_offset);
79 * @brief export simple nodes
81 void export_node(ExportContext &ctx, loco::Node *node, circle::BuiltinOperator bop,
82 circle::BuiltinOptions bot, flatbuffers::Offset<void> options_offset)
85 ctx.md.registerBuiltinOpcode(bop, loco::must_cast<luci::CircleNode *>(node)->op_version());
86 std::vector<int32_t> inputs_vec;
87 std::vector<int32_t> outputs_vec{get_tensor_index(node)};
88 for (uint32_t i = 0; i < node->arity(); ++i)
89 inputs_vec.push_back(get_tensor_index(node->arg(i)));
90 auto inputs = ctx.builder.CreateVector(inputs_vec);
91 auto outputs = ctx.builder.CreateVector(outputs_vec);
92 auto op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs, bot, options_offset);
93 ctx.gd._operators.push_back(op_offset);
97 * @brief export simple nodes having void options
99 void export_node(ExportContext &ctx, loco::Node *node, circle::BuiltinOperator bop)
102 ctx.md.registerBuiltinOpcode(bop, loco::must_cast<luci::CircleNode *>(node)->op_version());
103 std::vector<int32_t> inputs_vec;
104 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
105 for (uint32_t i = 0; i < node->arity(); ++i)
106 inputs_vec.push_back(get_tensor_index(node->arg(i)));
107 auto inputs = ctx.builder.CreateVector(inputs_vec);
108 auto outputs = ctx.builder.CreateVector(outputs_vec);
109 auto op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs);
110 ctx.gd._operators.push_back(op_offset);
113 void export_node(ExportContext &ctx, luci::CircleAddN *node)
115 uint32_t op_idx = ctx.md.registerBuiltinOpcode(circle::BuiltinOperator_ADD_N, node->op_version());
116 std::vector<int32_t> inputs_vec;
117 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
119 for (uint32_t i = 0; i < node->arity(); ++i)
120 inputs_vec.push_back(get_tensor_index(node->inputs(i)));
122 auto inputs = ctx.builder.CreateVector(inputs_vec);
123 auto outputs = ctx.builder.CreateVector(outputs_vec);
124 auto options = CreateAddNOptions(ctx.builder);
125 auto op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs,
126 circle::BuiltinOptions_AddNOptions, options.Union());
127 ctx.gd._operators.push_back(op_offset);
130 void export_node(ExportContext &ctx, luci::CircleCast *node)
132 uint32_t op_idx = ctx.md.registerBuiltinOpcode(circle::BuiltinOperator_CAST, node->op_version());
133 std::vector<int32_t> inputs_vec{get_tensor_index(node->x())};
134 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
135 auto inputs = ctx.builder.CreateVector(inputs_vec);
136 auto outputs = ctx.builder.CreateVector(outputs_vec);
138 flatbuffers::Offset<Operator> op_offset;
139 if (node->out_data_type() != loco::DataType::Unknown)
141 auto options = CreateCastOptions(ctx.builder, to_circle_tensortype(node->in_data_type()),
142 to_circle_tensortype(node->out_data_type()));
143 op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs,
144 circle::BuiltinOptions_CastOptions, options.Union());
148 op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs);
150 ctx.gd._operators.push_back(op_offset);
153 void export_node(ExportContext &ctx, luci::CircleConcatenation *node)
156 ctx.md.registerBuiltinOpcode(circle::BuiltinOperator_CONCATENATION, node->op_version());
157 std::vector<int32_t> inputs_vec;
158 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
160 for (uint32_t i = 0; i < node->numValues(); ++i)
161 inputs_vec.push_back(get_tensor_index(node->values(i)));
163 auto inputs = ctx.builder.CreateVector(inputs_vec);
164 auto outputs = ctx.builder.CreateVector(outputs_vec);
165 auto options = CreateConcatenationOptions(ctx.builder, node->axis(),
166 to_circle_actfunc(node->fusedActivationFunction()));
167 auto op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs,
168 circle::BuiltinOptions_ConcatenationOptions, options.Union());
169 ctx.gd._operators.push_back(op_offset);
172 void export_node(ExportContext &ctx, luci::CircleCustom *node)
174 auto custom_outputs = loco::succs(node);
176 uint32_t op_idx = ctx.md.registerCustomOpcode(node->custom_code());
177 std::vector<int32_t> inputs_vec;
178 std::vector<int32_t> outputs_vec;
180 for (uint32_t index = 0; index < node->numInputs(); index++)
182 inputs_vec.push_back(get_tensor_index(node->inputs(index)));
184 for (uint32_t index = 0; index < custom_outputs.size(); index++)
186 // store in order of index
188 for (auto out : custom_outputs)
190 auto custom_out = loco::must_cast<luci::CircleCustomOut *>(out);
191 if (custom_out->index() == static_cast<int32_t>(index))
193 outputs_vec.push_back(get_tensor_index(custom_out));
200 INTERNAL_EXN("Invalid Custom output");
204 auto inputs = ctx.builder.CreateVector(inputs_vec);
205 auto outputs = ctx.builder.CreateVector(outputs_vec);
206 flatbuffers::Offset<flatbuffers::Vector<uint8_t>> circle_custom_options;
207 std::vector<uint8_t> custom_options_vec{node->custom_options().begin(),
208 node->custom_options().end()};
209 circle_custom_options = ctx.builder.CreateVector(custom_options_vec);
210 auto op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs, circle::BuiltinOptions_NONE,
211 flatbuffers::Offset<void>(), circle_custom_options);
212 ctx.gd._operators.push_back(op_offset);
215 void export_node(ExportContext &ctx, luci::CircleIf *node)
217 auto if_outs = loco::succs(node);
218 assert(if_outs.size() == node->output_count());
220 uint32_t op_idx = ctx.md.registerBuiltinOpcode(circle::BuiltinOperator_IF, node->op_version());
221 std::vector<int32_t> inputs_vec;
222 std::vector<int32_t> outputs_vec;
224 inputs_vec.push_back(get_tensor_index(node->cond()));
225 for (uint32_t idx = 0; idx < node->input_count(); ++idx)
226 inputs_vec.push_back(get_tensor_index(node->input(idx)));
228 for (uint32_t idx = 0; idx < node->output_count(); ++idx)
230 // store in order of index
232 for (auto out : if_outs)
234 auto if_out = loco::must_cast<luci::CircleIfOut *>(out);
235 if (if_out->index() == static_cast<int32_t>(idx))
237 outputs_vec.push_back(get_tensor_index(if_out));
244 INTERNAL_EXN("Invalid CircleIf output");
248 auto inputs = ctx.builder.CreateVector(inputs_vec);
249 auto outputs = ctx.builder.CreateVector(outputs_vec);
250 auto options = CreateIfOptions(ctx.builder, node->then_branch(), node->else_branch());
251 auto op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs,
252 circle::BuiltinOptions_IfOptions, options.Union());
253 ctx.gd._operators.push_back(op_offset);
256 void export_node(ExportContext &ctx, luci::CircleNonMaxSuppressionV4 *node)
258 auto nms_outs = loco::succs(node);
259 assert(nms_outs.size() == 2);
261 uint32_t op_idx = ctx.md.registerBuiltinOpcode(circle::BuiltinOperator_NON_MAX_SUPPRESSION_V4,
263 std::vector<int32_t> inputs_vec{
264 get_tensor_index(node->boxes()), get_tensor_index(node->scores()),
265 get_tensor_index(node->max_output_size()), get_tensor_index(node->iou_threshold()),
266 get_tensor_index(node->score_threshold()),
268 std::vector<int32_t> outputs_vec;
270 for (uint32_t idx = 0; idx < nms_outs.size(); ++idx)
272 // store in order of index
274 for (auto out : nms_outs)
276 auto nms_out = loco::must_cast<luci::CircleNonMaxSuppressionV4Out *>(out);
277 if (nms_out->index() == static_cast<int32_t>(idx))
279 outputs_vec.push_back(get_tensor_index(nms_out));
286 INTERNAL_EXN("Invalid NonMaxSuppressionV4 output");
290 auto inputs = ctx.builder.CreateVector(inputs_vec);
291 auto outputs = ctx.builder.CreateVector(outputs_vec);
292 auto options = CreateNonMaxSuppressionV4Options(ctx.builder);
294 CreateOperator(ctx.builder, op_idx, inputs, outputs,
295 circle::BuiltinOptions_NonMaxSuppressionV4Options, options.Union());
296 ctx.gd._operators.push_back(op_offset);
299 void export_node(ExportContext &ctx, luci::CircleNonMaxSuppressionV5 *node)
301 auto nms_outs = loco::succs(node);
302 assert(nms_outs.size() == 3);
304 uint32_t op_idx = ctx.md.registerBuiltinOpcode(circle::BuiltinOperator_NON_MAX_SUPPRESSION_V5,
306 std::vector<int32_t> inputs_vec{
307 get_tensor_index(node->boxes()), get_tensor_index(node->scores()),
308 get_tensor_index(node->max_output_size()), get_tensor_index(node->iou_threshold()),
309 get_tensor_index(node->score_threshold()), get_tensor_index(node->soft_nms_sigma()),
311 std::vector<int32_t> outputs_vec;
313 for (uint32_t idx = 0; idx < nms_outs.size(); ++idx)
315 // store in order of index
317 for (auto out : nms_outs)
319 auto nms_out = loco::must_cast<luci::CircleNonMaxSuppressionV5Out *>(out);
320 if (nms_out->index() == static_cast<int32_t>(idx))
322 outputs_vec.push_back(get_tensor_index(nms_out));
329 INTERNAL_EXN("Invalid NonMaxSuppressionV5 output");
333 auto inputs = ctx.builder.CreateVector(inputs_vec);
334 auto outputs = ctx.builder.CreateVector(outputs_vec);
335 auto options = CreateNonMaxSuppressionV5Options(ctx.builder);
337 CreateOperator(ctx.builder, op_idx, inputs, outputs,
338 circle::BuiltinOptions_NonMaxSuppressionV5Options, options.Union());
339 ctx.gd._operators.push_back(op_offset);
342 void export_node(ExportContext &ctx, luci::CircleReverseV2 *node)
345 ctx.md.registerBuiltinOpcode(circle::BuiltinOperator_REVERSE_V2, node->op_version());
346 std::vector<int32_t> inputs_vec{get_tensor_index(node->tensor()), get_tensor_index(node->axis())};
347 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
348 auto inputs = ctx.builder.CreateVector(inputs_vec);
349 auto outputs = ctx.builder.CreateVector(outputs_vec);
350 auto options = CreateReverseV2Options(ctx.builder);
351 auto op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs,
352 circle::BuiltinOptions_ReverseSequenceOptions, options.Union());
353 ctx.gd._operators.push_back(op_offset);
356 void export_node(ExportContext &ctx, luci::CircleSplit *node)
358 auto split_outs = loco::succs(node);
359 assert(int32_t(split_outs.size()) == node->num_split());
361 uint32_t op_idx = ctx.md.registerBuiltinOpcode(circle::BuiltinOperator_SPLIT, node->op_version());
362 // NOTE BuiltinOperator_SPLIT input is placed at second position
363 std::vector<int32_t> inputs_vec{get_tensor_index(node->split_dim()),
364 get_tensor_index(node->input())};
365 std::vector<int32_t> outputs_vec;
367 for (int32_t index = 0; index < node->num_split(); index++)
369 // store in order of index
371 for (auto out : split_outs)
373 auto split_out = loco::must_cast<luci::CircleSplitOut *>(out);
374 if (split_out->index() == index)
376 outputs_vec.push_back(get_tensor_index(split_out));
383 INTERNAL_EXN("Invalid Split output");
387 auto inputs = ctx.builder.CreateVector(inputs_vec);
388 auto outputs = ctx.builder.CreateVector(outputs_vec);
389 auto options = CreateSplitOptions(ctx.builder, node->num_split());
390 auto op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs,
391 circle::BuiltinOptions_SplitOptions, options.Union());
392 ctx.gd._operators.push_back(op_offset);
395 void export_node(ExportContext &ctx, luci::CircleSplitV *node)
397 auto split_outs = loco::succs(node);
398 assert(int32_t(split_outs.size()) == node->num_split());
401 ctx.md.registerBuiltinOpcode(circle::BuiltinOperator_SPLIT_V, node->op_version());
402 std::vector<int32_t> inputs_vec{get_tensor_index(node->input()),
403 get_tensor_index(node->size_splits()),
404 get_tensor_index(node->split_dim())};
405 std::vector<int32_t> outputs_vec;
407 for (int32_t index = 0; index < node->num_split(); index++)
409 // store in order of index
411 for (auto out : split_outs)
413 auto split_out = loco::must_cast<luci::CircleSplitVOut *>(out);
414 if (split_out->index() == index)
416 outputs_vec.push_back(get_tensor_index(split_out));
423 INTERNAL_EXN("Invalid SplitV output");
427 auto inputs = ctx.builder.CreateVector(inputs_vec);
428 auto outputs = ctx.builder.CreateVector(outputs_vec);
429 auto options = CreateSplitVOptions(ctx.builder, node->num_split());
430 auto op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs,
431 circle::BuiltinOptions_SplitVOptions, options.Union());
432 ctx.gd._operators.push_back(op_offset);
435 void export_node(ExportContext &ctx, luci::CircleTopKV2 *node)
437 auto topkv2_outs = loco::succs(node);
438 int outs_count = int32_t(topkv2_outs.size());
439 assert(outs_count == 2);
442 ctx.md.registerBuiltinOpcode(circle::BuiltinOperator_TOPK_V2, node->op_version());
443 std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), get_tensor_index(node->k())};
444 std::vector<int32_t> outputs_vec;
446 for (int32_t index = 0; index < outs_count; index++)
448 // store in order of index
450 for (auto out : topkv2_outs)
452 auto topkv2_out = loco::must_cast<luci::CircleTopKV2Out *>(out);
453 if (topkv2_out->index() == index)
455 outputs_vec.push_back(get_tensor_index(topkv2_out));
462 INTERNAL_EXN("Invalid TopKV2 output");
466 auto inputs = ctx.builder.CreateVector(inputs_vec);
467 auto outputs = ctx.builder.CreateVector(outputs_vec);
468 auto options = CreateTopKV2Options(ctx.builder);
469 auto op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs,
470 circle::BuiltinOptions_TopKV2Options, options.Union());
471 ctx.gd._operators.push_back(op_offset);
474 void export_node(ExportContext &ctx, luci::CircleUnique *node)
476 auto unique_outs = loco::succs(node);
477 assert(int32_t(unique_outs.size()) == 2);
479 ctx.md.registerBuiltinOpcode(circle::BuiltinOperator_UNIQUE, node->op_version());
481 std::vector<int32_t> inputs_vec{get_tensor_index(node->input())};
482 std::vector<int32_t> outputs_vec;
484 for (int32_t index = 0; index < 2; index++)
486 // store in order of index
488 for (auto out : unique_outs)
490 auto unique_out = loco::must_cast<luci::CircleUniqueOut *>(out);
491 if (unique_out->index() == index)
493 outputs_vec.push_back(get_tensor_index(unique_out));
500 INTERNAL_EXN("Invalid Unique output");
504 auto inputs = ctx.builder.CreateVector(inputs_vec);
505 auto outputs = ctx.builder.CreateVector(outputs_vec);
506 auto options = CreateUniqueOptions(ctx.builder, to_circle_tensortype(node->idx_out_type()));
507 auto op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs,
508 circle::BuiltinOptions_UniqueOptions, options.Union());
509 ctx.gd._operators.push_back(op_offset);
512 void export_node(ExportContext &ctx, luci::CircleUnpack *node)
515 auto settings = luci::UserSettings::settings();
517 auto unpack_outs = loco::succs(node);
518 // NOTE real models may not use all of the outputs
519 if (static_cast<int32_t>(unpack_outs.size()) != node->num())
521 if (settings->get(luci::UserSettings::Key::DisableValidation))
523 WARN(l) << "Warning: export Unpack(" << node->name() << ") 'num' not same as outputs";
530 ctx.md.registerBuiltinOpcode(circle::BuiltinOperator_UNPACK, node->op_version());
531 std::vector<int32_t> inputs_vec{get_tensor_index(node->value())};
532 std::vector<int32_t> outputs_vec;
534 for (int32_t index = 0; index < node->num(); index++)
536 // store in order of index
538 for (auto out : unpack_outs)
540 auto unpack_out = loco::must_cast<luci::CircleUnpackOut *>(out);
541 if (unpack_out->index() == index)
543 outputs_vec.push_back(get_tensor_index(unpack_out));
548 // NOTE real models may not use all of the outputs
551 if (settings->get(luci::UserSettings::Key::DisableValidation))
553 WARN(l) << "Warning: export Unpack(" << node->name() << ") output " << index << " not used";
560 auto inputs = ctx.builder.CreateVector(inputs_vec);
561 auto outputs = ctx.builder.CreateVector(outputs_vec);
562 auto options = CreateUnpackOptions(ctx.builder, node->num(), node->axis());
563 auto op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs,
564 circle::BuiltinOptions_UnpackOptions, options.Union());
565 ctx.gd._operators.push_back(op_offset);
568 void export_node(ExportContext &ctx, luci::CircleWhile *node)
570 auto while_outs = loco::succs(node);
571 assert(while_outs.size() == node->output_count());
573 uint32_t op_idx = ctx.md.registerBuiltinOpcode(circle::BuiltinOperator_WHILE, node->op_version());
574 std::vector<int32_t> inputs_vec;
575 std::vector<int32_t> outputs_vec;
577 for (uint32_t idx = 0; idx < node->input_count(); ++idx)
578 inputs_vec.push_back(get_tensor_index(node->input(idx)));
580 for (uint32_t idx = 0; idx < node->output_count(); ++idx)
582 // store in order of index
584 for (auto out : while_outs)
586 auto while_out = loco::must_cast<luci::CircleWhileOut *>(out);
587 if (while_out->index() == static_cast<int32_t>(idx))
589 outputs_vec.push_back(get_tensor_index(while_out));
596 INTERNAL_EXN("Invalid CircleWhile output");
600 auto inputs = ctx.builder.CreateVector(inputs_vec);
601 auto outputs = ctx.builder.CreateVector(outputs_vec);
602 auto options = CreateWhileOptions(ctx.builder, node->cond_branch(), node->body_branch());
603 auto op_offset = CreateOperator(ctx.builder, op_idx, inputs, outputs,
604 circle::BuiltinOptions_WhileOptions, options.Union());
605 ctx.gd._operators.push_back(op_offset);
608 class OperationExporter final : public luci::CircleNodeMutableVisitor<void>,
609 public loco::CanonicalNodeMutableVisitor<void>
612 OperationExporter(ExportContext &ctx) : _ctx{ctx}
618 void visit(luci::CircleAbs *) final;
619 void visit(luci::CircleAdd *) final;
620 void visit(luci::CircleAddN *) final;
621 void visit(luci::CircleArgMax *) final;
622 void visit(luci::CircleArgMin *) final;
623 void visit(luci::CircleAveragePool2D *) final;
624 void visit(luci::CircleBatchMatMul *) final;
625 void visit(luci::CircleBatchToSpaceND *) final;
626 void visit(luci::CircleCast *) final;
627 void visit(luci::CircleCeil *) final;
628 void visit(luci::CircleConcatenation *) final;
629 void visit(luci::CircleConst *) final{/* skip, everything is done in exportOpDefinedTensors */};
630 void visit(luci::CircleConv2D *) final;
631 void visit(luci::CircleCos *) final;
632 void visit(luci::CircleCustom *) final;
633 void visit(luci::CircleDepthToSpace *) final;
634 void visit(luci::CircleDepthwiseConv2D *) final;
635 void visit(luci::CircleDequantize *) final;
636 void visit(luci::CircleDiv *) final;
637 void visit(luci::CircleElu *) final;
638 void visit(luci::CircleEqual *) final;
639 void visit(luci::CircleExp *) final;
640 void visit(luci::CircleExpandDims *) final;
641 void visit(luci::CircleFill *) final;
642 void visit(luci::CircleFloor *) final;
643 void visit(luci::CircleFloorDiv *) final;
644 void visit(luci::CircleFloorMod *) final;
645 void visit(luci::CircleFullyConnected *) final;
646 void visit(luci::CircleGather *) final;
647 void visit(luci::CircleGatherNd *) final;
648 void visit(luci::CircleGreater *) final;
649 void visit(luci::CircleGreaterEqual *) final;
650 void visit(luci::CircleIf *) final;
651 void visit(luci::CircleL2Normalize *) final;
652 void visit(luci::CircleL2Pool2D *) final;
653 void visit(luci::CircleLeakyRelu *) final;
654 void visit(luci::CircleLess *) final;
655 void visit(luci::CircleLessEqual *) final;
656 void visit(luci::CircleLocalResponseNormalization *) final;
657 void visit(luci::CircleLog *) final;
658 void visit(luci::CircleLogicalAnd *) final;
659 void visit(luci::CircleLogicalNot *) final;
660 void visit(luci::CircleLogicalOr *) final;
661 void visit(luci::CircleLogistic *) final;
662 void visit(luci::CircleLogSoftmax *) final;
663 void visit(luci::CircleMatrixDiag *) final;
664 void visit(luci::CircleMatrixSetDiag *) final;
665 void visit(luci::CircleMaximum *) final;
666 void visit(luci::CircleMaxPool2D *) final;
667 void visit(luci::CircleMean *) final;
668 void visit(luci::CircleMinimum *) final;
669 void visit(luci::CircleMirrorPad *) final;
670 void visit(luci::CircleMul *) final;
671 void visit(luci::CircleNeg *) final;
672 void visit(luci::CircleNonMaxSuppressionV4 *) final;
673 void visit(luci::CircleNonMaxSuppressionV5 *) final;
674 void visit(luci::CircleNotEqual *) final;
675 void visit(luci::CircleOneHot *) final;
676 void visit(luci::CirclePack *) final;
677 void visit(luci::CirclePad *) final;
678 void visit(luci::CirclePadV2 *) final;
679 void visit(luci::CirclePow *) final;
680 void visit(luci::CirclePRelu *) final;
681 void visit(luci::CircleRange *) final;
682 void visit(luci::CircleRank *) final;
683 void visit(luci::CircleReduceAny *) final;
684 void visit(luci::CircleReduceMax *) final;
685 void visit(luci::CircleReduceMin *) final;
686 void visit(luci::CircleReduceProd *) final;
687 void visit(luci::CircleRelu *) final;
688 void visit(luci::CircleRelu6 *) final;
689 void visit(luci::CircleReluN1To1 *) final;
690 void visit(luci::CircleReshape *) final;
691 void visit(luci::CircleResizeBilinear *) final;
692 void visit(luci::CircleResizeNearestNeighbor *) final;
693 void visit(luci::CircleReverseSequence *) final;
694 void visit(luci::CircleReverseV2 *) final;
695 void visit(luci::CircleRound *) final;
696 void visit(luci::CircleRsqrt *) final;
697 void visit(luci::CircleScatterNd *) final;
698 void visit(luci::CircleSegmentSum *) final;
699 void visit(luci::CircleSelect *) final;
700 void visit(luci::CircleSelectV2 *) final;
701 void visit(luci::CircleShape *) final;
702 void visit(luci::CircleSin *) final;
703 void visit(luci::CircleSlice *) final;
704 void visit(luci::CircleSoftmax *) final;
705 void visit(luci::CircleSpaceToBatchND *) final;
706 void visit(luci::CircleSpaceToDepth *) final;
707 void visit(luci::CircleSparseToDense *) final;
708 void visit(luci::CircleSplit *) final;
709 void visit(luci::CircleSplitV *) final;
710 void visit(luci::CircleSqrt *) final;
711 void visit(luci::CircleSquare *) final;
712 void visit(luci::CircleSquaredDifference *) final;
713 void visit(luci::CircleSqueeze *) final;
714 void visit(luci::CircleStridedSlice *) final;
715 void visit(luci::CircleSub *) final;
716 void visit(luci::CircleSum *) final;
717 void visit(luci::CircleTanh *) final;
718 void visit(luci::CircleTile *) final;
719 void visit(luci::CircleTopKV2 *) final;
720 void visit(luci::CircleTranspose *) final;
721 void visit(luci::CircleTransposeConv *) final;
722 void visit(luci::CircleUnidirectionalSequenceLSTM *) final;
723 void visit(luci::CircleUnique *) final;
724 void visit(luci::CircleUnpack *) final;
725 void visit(luci::CircleWhere *) final;
726 void visit(luci::CircleWhile *) final;
727 void visit(luci::CircleZerosLike *) final;
729 void visit(luci::CircleBCQFullyConnected *) final;
730 void visit(luci::CircleBCQGather *) final;
731 void visit(luci::CircleInstanceNorm *) final;
733 void visit(luci::CircleInput *) final {}
734 void visit(luci::CircleOutput *) final {}
735 void visit(luci::CircleOutputDummy *) final {}
736 void visit(luci::CircleOutputExclude *) final {}
737 // Virtual for multiple-outputs
738 void visit(luci::CircleCustomOut *) final {}
739 void visit(luci::CircleIfOut *) final {}
740 void visit(luci::CircleNonMaxSuppressionV4Out *) final {}
741 void visit(luci::CircleNonMaxSuppressionV5Out *) final {}
742 void visit(luci::CircleSplitOut *) final {}
743 void visit(luci::CircleSplitVOut *) final {}
744 void visit(luci::CircleTopKV2Out *) final {}
745 void visit(luci::CircleUniqueOut *) final {}
746 void visit(luci::CircleUnpackOut *) final {}
747 void visit(luci::CircleWhileOut *) final {}
751 * @brief export simple nodes
753 void export_simple(loco::Node *node, circle::BuiltinOperator bop, circle::BuiltinOptions bot,
754 flatbuffers::Offset<void> options_offset);
757 * @brief export simple nodes having void options
759 void export_simple(loco::Node *node, circle::BuiltinOperator bop);
765 void OperationExporter::export_simple(loco::Node *node, circle::BuiltinOperator bop,
766 circle::BuiltinOptions bot,
767 flatbuffers::Offset<void> options_offset)
769 export_node(_ctx, node, bop, bot, options_offset);
772 void OperationExporter::export_simple(loco::Node *node, circle::BuiltinOperator bop)
774 export_node(_ctx, node, bop);
777 void OperationExporter::visit(luci::CircleAbs *node)
779 export_simple(node, circle::BuiltinOperator_ABS, circle::BuiltinOptions_AbsOptions,
780 CreateAbsOptions(_ctx.builder).Union());
783 void OperationExporter::visit(luci::CircleAdd *node)
786 node, circle::BuiltinOperator_ADD, circle::BuiltinOptions_AddOptions,
787 CreateAddOptions(_ctx.builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
790 void OperationExporter::visit(luci::CircleAddN *node) { export_node(_ctx, node); }
792 void OperationExporter::visit(luci::CircleArgMax *node)
795 node, circle::BuiltinOperator_ARG_MAX, circle::BuiltinOptions_ArgMaxOptions,
796 CreateArgMaxOptions(_ctx.builder, to_circle_tensortype(node->output_type())).Union());
799 void OperationExporter::visit(luci::CircleArgMin *node)
802 node, circle::BuiltinOperator_ARG_MIN, circle::BuiltinOptions_ArgMinOptions,
803 CreateArgMinOptions(_ctx.builder, to_circle_tensortype(node->output_type())).Union());
806 void OperationExporter::visit(luci::CircleAveragePool2D *node)
808 export_pool_2d<luci::CircleAveragePool2D>(_ctx, node, circle::BuiltinOperator_AVERAGE_POOL_2D);
811 void OperationExporter::visit(luci::CircleBatchMatMul *node)
813 export_simple(node, circle::BuiltinOperator_BATCH_MATMUL,
814 circle::BuiltinOptions_BatchMatMulOptions,
815 CreateBatchMatMulOptions(_ctx.builder, node->adj_x(), node->adj_y()).Union());
818 void OperationExporter::visit(luci::CircleCast *node) { export_node(_ctx, node); }
820 void OperationExporter::visit(luci::CircleCeil *node)
822 export_simple(node, circle::BuiltinOperator_CEIL);
825 void OperationExporter::visit(luci::CircleConcatenation *node) { export_node(_ctx, node); }
827 void OperationExporter::visit(luci::CircleBatchToSpaceND *node)
829 export_simple(node, circle::BuiltinOperator_BATCH_TO_SPACE_ND,
830 circle::BuiltinOptions_BatchToSpaceNDOptions,
831 CreateBatchToSpaceNDOptions(_ctx.builder).Union());
834 void OperationExporter::visit(luci::CircleConv2D *node)
836 export_simple(node, circle::BuiltinOperator_CONV_2D, circle::BuiltinOptions_Conv2DOptions,
837 CreateConv2DOptions(_ctx.builder, getOpPadding(node->padding()),
838 node->stride()->w(), node->stride()->h(),
839 to_circle_actfunc(node->fusedActivationFunction()),
840 node->dilation()->w(), node->dilation()->h())
844 void OperationExporter::visit(luci::CircleCos *node)
846 export_simple(node, circle::BuiltinOperator_COS, circle::BuiltinOptions_CosOptions,
847 CreateCosOptions(_ctx.builder).Union());
850 void OperationExporter::visit(luci::CircleCustom *node) { export_node(_ctx, node); }
852 void OperationExporter::visit(luci::CircleDepthToSpace *node)
854 export_simple(node, circle::BuiltinOperator_DEPTH_TO_SPACE,
855 circle::BuiltinOptions_DepthToSpaceOptions,
856 CreateDepthToSpaceOptions(_ctx.builder, node->block_size()).Union());
859 void OperationExporter::visit(luci::CircleDepthwiseConv2D *node)
861 export_simple(node, circle::BuiltinOperator_DEPTHWISE_CONV_2D,
862 circle::BuiltinOptions_DepthwiseConv2DOptions,
863 CreateDepthwiseConv2DOptions(_ctx.builder, getOpPadding(node->padding()),
864 node->stride()->w(), node->stride()->h(),
865 node->depthMultiplier(),
866 to_circle_actfunc(node->fusedActivationFunction()),
867 node->dilation()->w(), node->dilation()->h())
871 void OperationExporter::visit(luci::CircleDequantize *node)
873 export_simple(node, circle::BuiltinOperator_DEQUANTIZE);
876 void OperationExporter::visit(luci::CircleDiv *node)
879 node, circle::BuiltinOperator_DIV, circle::BuiltinOptions_DivOptions,
880 CreateDivOptions(_ctx.builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
883 void OperationExporter::visit(luci::CircleElu *node)
885 export_simple(node, circle::BuiltinOperator_ELU);
888 void OperationExporter::visit(luci::CircleEqual *node)
890 export_simple(node, circle::BuiltinOperator_EQUAL, circle::BuiltinOptions_EqualOptions,
891 CreateEqualOptions(_ctx.builder).Union());
894 void OperationExporter::visit(luci::CircleExp *node)
896 export_simple(node, circle::BuiltinOperator_EXP, circle::BuiltinOptions_ExpOptions,
897 CreateExpOptions(_ctx.builder).Union());
900 void OperationExporter::visit(luci::CircleExpandDims *node)
902 export_simple(node, circle::BuiltinOperator_EXPAND_DIMS, circle::BuiltinOptions_ExpandDimsOptions,
903 CreateExpandDimsOptions(_ctx.builder).Union());
906 void OperationExporter::visit(luci::CircleFill *node)
908 export_simple(node, circle::BuiltinOperator_FILL, circle::BuiltinOptions_FillOptions,
909 CreateFillOptions(_ctx.builder).Union());
912 void OperationExporter::visit(luci::CircleFloor *node)
914 export_simple(node, circle::BuiltinOperator_FLOOR);
917 void OperationExporter::visit(luci::CircleFloorDiv *node)
919 export_simple(node, circle::BuiltinOperator_FLOOR_DIV, circle::BuiltinOptions_FloorDivOptions,
920 CreateFloorDivOptions(_ctx.builder).Union());
923 void OperationExporter::visit(luci::CircleFloorMod *node)
925 export_simple(node, circle::BuiltinOperator_FLOOR_MOD, circle::BuiltinOptions_FloorModOptions,
926 CreateFloorModOptions(_ctx.builder).Union());
929 void OperationExporter::visit(luci::CircleFullyConnected *node)
932 node, circle::BuiltinOperator_FULLY_CONNECTED, circle::BuiltinOptions_FullyConnectedOptions,
933 CreateFullyConnectedOptions(_ctx.builder, to_circle_actfunc(node->fusedActivationFunction()))
937 void OperationExporter::visit(luci::CircleGather *node)
939 export_simple(node, circle::BuiltinOperator_GATHER, circle::BuiltinOptions_GatherOptions,
940 CreateGatherOptions(_ctx.builder, node->axis()).Union());
943 void OperationExporter::visit(luci::CircleGatherNd *node)
945 export_simple(node, circle::BuiltinOperator_GATHER_ND, circle::BuiltinOptions_GatherNdOptions,
946 CreateGatherNdOptions(_ctx.builder).Union());
949 void OperationExporter::visit(luci::CircleGreater *node)
951 export_simple(node, circle::BuiltinOperator_GREATER, circle::BuiltinOptions_GreaterOptions,
952 CreateGreaterOptions(_ctx.builder).Union());
955 void OperationExporter::visit(luci::CircleGreaterEqual *node)
957 export_simple(node, circle::BuiltinOperator_GREATER_EQUAL,
958 circle::BuiltinOptions_GreaterEqualOptions,
959 CreateGreaterEqualOptions(_ctx.builder).Union());
962 void OperationExporter::visit(luci::CircleIf *node) { export_node(_ctx, node); }
964 void OperationExporter::visit(luci::CircleL2Normalize *node)
967 node, circle::BuiltinOperator_L2_NORMALIZATION, circle::BuiltinOptions_L2NormOptions,
968 CreateL2NormOptions(_ctx.builder, to_circle_actfunc(node->fusedActivationFunction()))
972 void OperationExporter::visit(luci::CircleL2Pool2D *node)
974 export_pool_2d<luci::CircleL2Pool2D>(_ctx, node, circle::BuiltinOperator_L2_POOL_2D);
977 void OperationExporter::visit(luci::CircleLeakyRelu *node)
979 export_simple(node, circle::BuiltinOperator_LEAKY_RELU, circle::BuiltinOptions_LeakyReluOptions,
980 CreateLeakyReluOptions(_ctx.builder, node->alpha()).Union());
983 void OperationExporter::visit(luci::CircleLess *node)
985 export_simple(node, circle::BuiltinOperator_LESS, circle::BuiltinOptions_LessOptions,
986 CreateLessOptions(_ctx.builder).Union());
989 void OperationExporter::visit(luci::CircleLessEqual *node)
991 export_simple(node, circle::BuiltinOperator_LESS_EQUAL, circle::BuiltinOptions_LessEqualOptions,
992 CreateLessEqualOptions(_ctx.builder).Union());
995 void OperationExporter::visit(luci::CircleLocalResponseNormalization *node)
997 export_simple(node, circle::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION,
998 circle::BuiltinOptions_LocalResponseNormalizationOptions,
999 CreateLocalResponseNormalizationOptions(_ctx.builder, node->radius(), node->bias(),
1000 node->alpha(), node->beta())
1004 void OperationExporter::visit(luci::CircleLog *node)
1006 export_simple(node, circle::BuiltinOperator_LOG);
1009 void OperationExporter::visit(luci::CircleLogicalAnd *node)
1011 export_simple(node, circle::BuiltinOperator_LOGICAL_AND, circle::BuiltinOptions_LogicalAndOptions,
1012 CreateLogicalAndOptions(_ctx.builder).Union());
1015 void OperationExporter::visit(luci::CircleLogicalNot *node)
1017 export_simple(node, circle::BuiltinOperator_LOGICAL_NOT, circle::BuiltinOptions_LogicalNotOptions,
1018 CreateLogicalNotOptions(_ctx.builder).Union());
1021 void OperationExporter::visit(luci::CircleLogicalOr *node)
1023 export_simple(node, circle::BuiltinOperator_LOGICAL_OR, circle::BuiltinOptions_LogicalOrOptions,
1024 CreateLogicalOrOptions(_ctx.builder).Union());
1027 void OperationExporter::visit(luci::CircleLogistic *node)
1029 export_simple(node, circle::BuiltinOperator_LOGISTIC);
1032 void OperationExporter::visit(luci::CircleLogSoftmax *node)
1034 export_simple(node, circle::BuiltinOperator_LOG_SOFTMAX, circle::BuiltinOptions_LogSoftmaxOptions,
1035 CreateLogSoftmaxOptions(_ctx.builder).Union());
1038 void OperationExporter::visit(luci::CircleMatrixDiag *node)
1040 export_simple(node, circle::BuiltinOperator_MATRIX_DIAG, circle::BuiltinOptions_MatrixDiagOptions,
1041 CreateMatrixDiagOptions(_ctx.builder).Union());
1044 void OperationExporter::visit(luci::CircleMatrixSetDiag *node)
1046 export_simple(node, circle::BuiltinOperator_MATRIX_SET_DIAG,
1047 circle::BuiltinOptions_MatrixSetDiagOptions,
1048 CreateMatrixSetDiagOptions(_ctx.builder).Union());
1051 void OperationExporter::visit(luci::CircleMaximum *node)
1053 export_simple(node, circle::BuiltinOperator_MAXIMUM, circle::BuiltinOptions_MaximumMinimumOptions,
1054 CreateMaximumMinimumOptions(_ctx.builder).Union());
1057 void OperationExporter::visit(luci::CircleMaxPool2D *node)
1059 export_pool_2d<luci::CircleMaxPool2D>(_ctx, node, circle::BuiltinOperator_MAX_POOL_2D);
1062 void OperationExporter::visit(luci::CircleMean *node)
1064 export_simple(node, circle::BuiltinOperator_MEAN, circle::BuiltinOptions_ReducerOptions,
1065 CreateReducerOptions(_ctx.builder, node->keep_dims()).Union());
1068 void OperationExporter::visit(luci::CircleMinimum *node)
1070 export_simple(node, circle::BuiltinOperator_MINIMUM, circle::BuiltinOptions_MaximumMinimumOptions,
1071 CreateMaximumMinimumOptions(_ctx.builder).Union());
1074 void OperationExporter::visit(luci::CircleMirrorPad *node)
1077 node, circle::BuiltinOperator_MIRROR_PAD, circle::BuiltinOptions_MirrorPadOptions,
1078 CreateMirrorPadOptions(_ctx.builder, to_circle_mirrorpadmode(node->mode())).Union());
1081 void OperationExporter::visit(luci::CircleMul *node)
1084 node, circle::BuiltinOperator_MUL, circle::BuiltinOptions_MulOptions,
1085 CreateMulOptions(_ctx.builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
1088 void OperationExporter::visit(luci::CircleNeg *node)
1090 export_simple(node, circle::BuiltinOperator_NEG, circle::BuiltinOptions_NegOptions,
1091 CreateNegOptions(_ctx.builder).Union());
1094 void OperationExporter::visit(luci::CircleNonMaxSuppressionV4 *node) { export_node(_ctx, node); }
1096 void OperationExporter::visit(luci::CircleNonMaxSuppressionV5 *node) { export_node(_ctx, node); }
1098 void OperationExporter::visit(luci::CircleNotEqual *node)
1100 export_simple(node, circle::BuiltinOperator_NOT_EQUAL, circle::BuiltinOptions_NotEqualOptions,
1101 CreateNotEqualOptions(_ctx.builder).Union());
1104 void OperationExporter::visit(luci::CircleOneHot *node)
1106 export_simple(node, circle::BuiltinOperator_ONE_HOT, circle::BuiltinOptions_OneHotOptions,
1107 CreateOneHotOptions(_ctx.builder, node->axis()).Union());
1110 void OperationExporter::visit(luci::CirclePack *node)
1112 export_simple(node, circle::BuiltinOperator_PACK, circle::BuiltinOptions_PackOptions,
1113 CreatePackOptions(_ctx.builder, node->values_count(), node->axis()).Union());
1116 void OperationExporter::visit(luci::CirclePad *node)
1118 export_simple(node, circle::BuiltinOperator_PAD, circle::BuiltinOptions_PadOptions,
1119 CreatePadOptions(_ctx.builder).Union());
1122 void OperationExporter::visit(luci::CirclePadV2 *node)
1124 export_simple(node, circle::BuiltinOperator_PADV2, circle::BuiltinOptions_PadV2Options,
1125 CreatePadV2Options(_ctx.builder).Union());
1128 void OperationExporter::visit(luci::CirclePow *node)
1130 export_simple(node, circle::BuiltinOperator_POW, circle::BuiltinOptions_PowOptions,
1131 CreatePowOptions(_ctx.builder).Union());
1134 void OperationExporter::visit(luci::CirclePRelu *node)
1136 export_simple(node, circle::BuiltinOperator_PRELU);
1139 void OperationExporter::visit(luci::CircleRange *node)
1141 export_simple(node, circle::BuiltinOperator_RANGE, circle::BuiltinOptions_RangeOptions,
1142 CreateRangeOptions(_ctx.builder).Union());
1145 void OperationExporter::visit(luci::CircleRank *node)
1147 export_simple(node, circle::BuiltinOperator_RANK, circle::BuiltinOptions_RankOptions,
1148 CreateRankOptions(_ctx.builder).Union());
1151 void OperationExporter::visit(luci::CircleReduceAny *node)
1153 export_simple(node, circle::BuiltinOperator_REDUCE_ANY, circle::BuiltinOptions_ReducerOptions,
1154 CreateReducerOptions(_ctx.builder, node->keep_dims()).Union());
1157 void OperationExporter::visit(luci::CircleReduceMax *node)
1159 export_simple(node, circle::BuiltinOperator_REDUCE_MAX, circle::BuiltinOptions_ReducerOptions,
1160 CreateReducerOptions(_ctx.builder, node->keep_dims()).Union());
1163 void OperationExporter::visit(luci::CircleReduceMin *node)
1165 export_simple(node, circle::BuiltinOperator_REDUCE_MIN, circle::BuiltinOptions_ReducerOptions,
1166 CreateReducerOptions(_ctx.builder, node->keep_dims()).Union());
1169 void OperationExporter::visit(luci::CircleReduceProd *node)
1171 export_simple(node, circle::BuiltinOperator_REDUCE_PROD, circle::BuiltinOptions_ReducerOptions,
1172 CreateReducerOptions(_ctx.builder, node->keep_dims()).Union());
1175 void OperationExporter::visit(luci::CircleRelu *node)
1177 export_simple(node, circle::BuiltinOperator_RELU);
1180 void OperationExporter::visit(luci::CircleRelu6 *node)
1182 export_simple(node, circle::BuiltinOperator_RELU6);
1185 void OperationExporter::visit(luci::CircleReluN1To1 *node)
1187 export_simple(node, circle::BuiltinOperator_RELU_N1_TO_1);
1190 void OperationExporter::visit(luci::CircleReshape *node)
1192 auto new_shape = _ctx.builder.CreateVector<int32_t>(
1193 node->newShape()->rank(), [node](size_t i) { return node->newShape()->dim(i); });
1195 export_simple(node, circle::BuiltinOperator_RESHAPE, circle::BuiltinOptions_ReshapeOptions,
1196 CreateReshapeOptions(_ctx.builder, new_shape).Union());
1199 void OperationExporter::visit(luci::CircleResizeBilinear *node)
1202 node, circle::BuiltinOperator_RESIZE_BILINEAR, circle::BuiltinOptions_ResizeBilinearOptions,
1203 CreateResizeBilinearOptions(_ctx.builder, node->align_corners(), node->half_pixel_centers())
1207 void OperationExporter::visit(luci::CircleResizeNearestNeighbor *node)
1209 export_simple(node, circle::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR,
1210 circle::BuiltinOptions_ResizeNearestNeighborOptions,
1211 CreateResizeNearestNeighborOptions(_ctx.builder, node->align_corners()).Union());
1214 void OperationExporter::visit(luci::CircleReverseSequence *node)
1217 node, circle::BuiltinOperator_REVERSE_SEQUENCE, circle::BuiltinOptions_ReverseSequenceOptions,
1218 CreateReverseSequenceOptions(_ctx.builder, node->seq_axis(), node->batch_axis()).Union());
1221 void OperationExporter::visit(luci::CircleReverseV2 *node) { export_node(_ctx, node); }
1223 void OperationExporter::visit(luci::CircleRound *node)
1225 export_simple(node, circle::BuiltinOperator_ROUND);
1228 void OperationExporter::visit(luci::CircleRsqrt *node)
1230 export_simple(node, circle::BuiltinOperator_RSQRT);
1233 void OperationExporter::visit(luci::CircleScatterNd *node)
1235 export_simple(node, circle::BuiltinOperator_SCATTER_ND, circle::BuiltinOptions_ScatterNdOptions,
1236 CreateScatterNdOptions(_ctx.builder).Union());
1239 void OperationExporter::visit(luci::CircleSegmentSum *node)
1241 export_simple(node, circle::BuiltinOperator_SEGMENT_SUM, circle::BuiltinOptions_SegmentSumOptions,
1242 CreateSegmentSumOptions(_ctx.builder).Union());
1245 void OperationExporter::visit(luci::CircleSelect *node)
1247 export_simple(node, circle::BuiltinOperator_SELECT, circle::BuiltinOptions_SelectOptions,
1248 CreateSelectOptions(_ctx.builder).Union());
1251 void OperationExporter::visit(luci::CircleSelectV2 *node)
1253 export_simple(node, circle::BuiltinOperator_SELECT_V2, circle::BuiltinOptions_SelectV2Options,
1254 CreateSelectV2Options(_ctx.builder).Union());
1257 void OperationExporter::visit(luci::CircleShape *node)
1259 export_simple(node, circle::BuiltinOperator_SHAPE, circle::BuiltinOptions_ShapeOptions,
1260 CreateShapeOptions(_ctx.builder, to_circle_tensortype(node->out_type())).Union());
1263 void OperationExporter::visit(luci::CircleSin *node)
1265 export_simple(node, circle::BuiltinOperator_SIN);
1268 void OperationExporter::visit(luci::CircleSlice *node)
1270 export_simple(node, circle::BuiltinOperator_SLICE, circle::BuiltinOptions_SliceOptions,
1271 CreateSliceOptions(_ctx.builder).Union());
1274 void OperationExporter::visit(luci::CircleSoftmax *node)
1276 export_simple(node, circle::BuiltinOperator_SOFTMAX, circle::BuiltinOptions_SoftmaxOptions,
1277 CreateSoftmaxOptions(_ctx.builder, node->beta()).Union());
1280 void OperationExporter::visit(luci::CircleSpaceToBatchND *node)
1282 export_simple(node, circle::BuiltinOperator_SPACE_TO_BATCH_ND,
1283 circle::BuiltinOptions_SpaceToBatchNDOptions,
1284 CreateSpaceToBatchNDOptions(_ctx.builder).Union());
1287 void OperationExporter::visit(luci::CircleSpaceToDepth *node)
1289 export_simple(node, circle::BuiltinOperator_SPACE_TO_DEPTH,
1290 circle::BuiltinOptions_SpaceToDepthOptions,
1291 CreateSpaceToDepthOptions(_ctx.builder, node->block_size()).Union());
1294 void OperationExporter::visit(luci::CircleSparseToDense *node)
1296 export_simple(node, circle::BuiltinOperator_SPARSE_TO_DENSE,
1297 circle::BuiltinOptions_SparseToDenseOptions,
1298 CreateSparseToDenseOptions(_ctx.builder, node->validate_indices()).Union());
1301 void OperationExporter::visit(luci::CircleSplit *node) { export_node(_ctx, node); }
1303 void OperationExporter::visit(luci::CircleSplitV *node) { export_node(_ctx, node); }
1305 void OperationExporter::visit(luci::CircleSqrt *node)
1307 export_simple(node, circle::BuiltinOperator_SQRT);
1310 void OperationExporter::visit(luci::CircleSquare *node)
1312 export_simple(node, circle::BuiltinOperator_SQUARE, circle::BuiltinOptions_SquareOptions,
1313 CreateSquareOptions(_ctx.builder).Union());
1316 void OperationExporter::visit(luci::CircleSquaredDifference *node)
1318 export_simple(node, circle::BuiltinOperator_SQUARED_DIFFERENCE,
1319 circle::BuiltinOptions_SquaredDifferenceOptions,
1320 CreateSquaredDifferenceOptions(_ctx.builder).Union());
1323 void OperationExporter::visit(luci::CircleSqueeze *node)
1325 auto squeeze_dims = _ctx.builder.CreateVector<int32_t>(node->squeeze_dims());
1326 export_simple(node, circle::BuiltinOperator_SQUEEZE, circle::BuiltinOptions_SqueezeOptions,
1327 CreateSqueezeOptions(_ctx.builder, squeeze_dims).Union());
1330 void OperationExporter::visit(luci::CircleStridedSlice *node)
1332 export_simple(node, circle::BuiltinOperator_STRIDED_SLICE,
1333 circle::BuiltinOptions_StridedSliceOptions,
1334 CreateStridedSliceOptions(_ctx.builder, node->begin_mask(), node->end_mask(),
1335 node->ellipsis_mask(), node->new_axis_mask(),
1336 node->shrink_axis_mask())
1340 void OperationExporter::visit(luci::CircleSub *node)
1343 node, circle::BuiltinOperator_SUB, circle::BuiltinOptions_SubOptions,
1344 CreateSubOptions(_ctx.builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
1347 void OperationExporter::visit(luci::CircleSum *node)
1349 export_simple(node, circle::BuiltinOperator_SUM, circle::BuiltinOptions_ReducerOptions,
1350 CreateReducerOptions(_ctx.builder, node->keep_dims()).Union());
1353 void OperationExporter::visit(luci::CircleTanh *node)
1355 export_simple(node, circle::BuiltinOperator_TANH);
1358 void OperationExporter::visit(luci::CircleTile *node)
1360 export_simple(node, circle::BuiltinOperator_TILE, circle::BuiltinOptions_TileOptions,
1361 CreateTileOptions(_ctx.builder).Union());
1364 void OperationExporter::visit(luci::CircleTopKV2 *node) { export_node(_ctx, node); }
1366 void OperationExporter::visit(luci::CircleTranspose *node)
1368 export_simple(node, circle::BuiltinOperator_TRANSPOSE, circle::BuiltinOptions_TransposeOptions,
1369 CreateTransposeOptions(_ctx.builder).Union());
1372 void OperationExporter::visit(luci::CircleTransposeConv *node)
1374 export_simple(node, circle::BuiltinOperator_TRANSPOSE_CONV,
1375 circle::BuiltinOptions_TransposeConvOptions,
1376 CreateTransposeConvOptions(_ctx.builder, getOpPadding(node->padding()),
1377 node->stride()->w(), node->stride()->h())
1381 void OperationExporter::visit(luci::CircleUnidirectionalSequenceLSTM *node)
1383 export_simple(node, circle::BuiltinOperator_UNIDIRECTIONAL_SEQUENCE_LSTM,
1384 circle::BuiltinOptions_UnidirectionalSequenceLSTMOptions,
1385 CreateUnidirectionalSequenceLSTMOptions(
1386 _ctx.builder, to_circle_actfunc(node->fusedActivationFunction()),
1387 node->cell_clip(), node->proj_clip(), node->time_major(),
1388 node->asymmetric_quantize_inputs())
1392 void OperationExporter::visit(luci::CircleUnique *node) { export_node(_ctx, node); }
1394 void OperationExporter::visit(luci::CircleUnpack *node) { export_node(_ctx, node); }
1396 void OperationExporter::visit(luci::CircleWhere *node)
1398 export_simple(node, circle::BuiltinOperator_WHERE, circle::BuiltinOptions_WhereOptions,
1399 CreateWhereOptions(_ctx.builder).Union());
1402 void OperationExporter::visit(luci::CircleWhile *node) { export_node(_ctx, node); }
1404 void OperationExporter::visit(luci::CircleZerosLike *node)
1406 export_simple(node, circle::BuiltinOperator_ZEROS_LIKE, circle::BuiltinOptions_ZerosLikeOptions,
1407 CreateZerosLikeOptions(_ctx.builder).Union());
1410 void OperationExporter::visit(luci::CircleBCQFullyConnected *node)
1412 export_simple(node, circle::BuiltinOperator_BCQ_FULLY_CONNECTED,
1413 circle::BuiltinOptions_BCQFullyConnectedOptions,
1414 CreateBCQFullyConnectedOptions(_ctx.builder, node->weights_hidden_size(),
1415 to_circle_actfunc(node->fusedActivationFunction()))
1419 void OperationExporter::visit(luci::CircleBCQGather *node)
1422 node, circle::BuiltinOperator_BCQ_GATHER, circle::BuiltinOptions_BCQGatherOptions,
1423 CreateBCQGatherOptions(_ctx.builder, node->input_hidden_size(), node->axis()).Union());
1426 void OperationExporter::visit(luci::CircleInstanceNorm *node)
1428 export_simple(node, circle::BuiltinOperator_INSTANCE_NORM,
1429 circle::BuiltinOptions_InstanceNormOptions,
1430 CreateInstanceNormOptions(_ctx.builder, node->epsilon(),
1431 to_circle_actfunc(node->fusedActivationFunction()))
1435 void exportNode(loco::Node *node, flatbuffers::FlatBufferBuilder &builder, SerializedModelData &md,
1436 SerializedGraphData &gd)
1438 if (auto circle_node = dynamic_cast<luci::CircleNode *>(node))
1440 ExportContext ctx{builder, md, gd};
1441 OperationExporter exporter{ctx};
1442 circle_node->accept(&exporter);
1446 INTERNAL_EXN("Node with unsupported dialect found");
1455 void exportNodes(loco::Graph *g, FlatBufferBuilder &builder, SerializedModelData &md,
1456 SerializedGraphData &gd)
1458 for (auto node : loco::postorder_traversal(loco::output_nodes(g)))
1460 exportNode(node, builder, md, gd);