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;
41 class OperationExporter final : public luci::CircleNodeMutableVisitor<void>,
42 public loco::CanonicalNodeMutableVisitor<void>
45 OperationExporter(FlatBufferBuilder &fbb, SerializedModelData &m, SerializedGraphData &g)
46 : builder{fbb}, md{m}, gd{g}
52 void visit(luci::CircleAbs *) final;
53 void visit(luci::CircleAdd *) final;
54 void visit(luci::CircleAddN *) final;
55 void visit(luci::CircleArgMax *) final;
56 void visit(luci::CircleArgMin *) final;
57 void visit(luci::CircleAveragePool2D *) final;
58 void visit(luci::CircleBatchMatMul *) final;
59 void visit(luci::CircleBatchToSpaceND *) final;
60 void visit(luci::CircleCast *) final;
61 void visit(luci::CircleCeil *) final;
62 void visit(luci::CircleConcatenation *) final;
63 void visit(luci::CircleConst *) final{/* skip, everything is done in exportOpDefinedTensors */};
64 void visit(luci::CircleConv2D *) final;
65 void visit(luci::CircleCos *) final;
66 void visit(luci::CircleCustom *) final;
67 void visit(luci::CircleDepthToSpace *) final;
68 void visit(luci::CircleDepthwiseConv2D *) final;
69 void visit(luci::CircleDiv *) final;
70 void visit(luci::CircleElu *) final;
71 void visit(luci::CircleEqual *) final;
72 void visit(luci::CircleExp *) final;
73 void visit(luci::CircleExpandDims *) final;
74 void visit(luci::CircleFill *) final;
75 void visit(luci::CircleFloor *) final;
76 void visit(luci::CircleFloorDiv *) final;
77 void visit(luci::CircleFloorMod *) final;
78 void visit(luci::CircleFullyConnected *) final;
79 void visit(luci::CircleGather *) final;
80 void visit(luci::CircleGatherNd *) final;
81 void visit(luci::CircleGreater *) final;
82 void visit(luci::CircleGreaterEqual *) final;
83 void visit(luci::CircleIf *) final;
84 void visit(luci::CircleL2Normalize *) final;
85 void visit(luci::CircleL2Pool2D *) final;
86 void visit(luci::CircleLeakyRelu *) final;
87 void visit(luci::CircleLess *) final;
88 void visit(luci::CircleLessEqual *) final;
89 void visit(luci::CircleLocalResponseNormalization *) final;
90 void visit(luci::CircleLog *) final;
91 void visit(luci::CircleLogicalAnd *) final;
92 void visit(luci::CircleLogicalNot *) final;
93 void visit(luci::CircleLogicalOr *) final;
94 void visit(luci::CircleLogistic *) final;
95 void visit(luci::CircleLogSoftmax *) final;
96 void visit(luci::CircleMatrixDiag *) final;
97 void visit(luci::CircleMatrixSetDiag *) final;
98 void visit(luci::CircleMaximum *) final;
99 void visit(luci::CircleMaxPool2D *) final;
100 void visit(luci::CircleMean *) final;
101 void visit(luci::CircleMinimum *) final;
102 void visit(luci::CircleMirrorPad *) final;
103 void visit(luci::CircleMul *) final;
104 void visit(luci::CircleNeg *) final;
105 void visit(luci::CircleNonMaxSuppressionV4 *) final;
106 void visit(luci::CircleNotEqual *) final;
107 void visit(luci::CircleOneHot *) final;
108 void visit(luci::CirclePack *) final;
109 void visit(luci::CirclePad *) final;
110 void visit(luci::CirclePow *) final;
111 void visit(luci::CirclePRelu *) final;
112 void visit(luci::CircleRange *) final;
113 void visit(luci::CircleRank *) final;
114 void visit(luci::CircleReduceAny *) final;
115 void visit(luci::CircleReduceMax *) final;
116 void visit(luci::CircleReduceMin *) final;
117 void visit(luci::CircleReduceProd *) final;
118 void visit(luci::CircleRelu *) final;
119 void visit(luci::CircleRelu6 *) final;
120 void visit(luci::CircleReluN1To1 *) final;
121 void visit(luci::CircleReshape *) final;
122 void visit(luci::CircleResizeBilinear *) final;
123 void visit(luci::CircleResizeNearestNeighbor *) final;
124 void visit(luci::CircleReverseSequence *) final;
125 void visit(luci::CircleReverseV2 *) final;
126 void visit(luci::CircleRound *) final;
127 void visit(luci::CircleRsqrt *) final;
128 void visit(luci::CircleScatterNd *) final;
129 void visit(luci::CircleSegmentSum *) final;
130 void visit(luci::CircleSelect *) final;
131 void visit(luci::CircleSelectV2 *) final;
132 void visit(luci::CircleShape *) final;
133 void visit(luci::CircleSin *) final;
134 void visit(luci::CircleSlice *) final;
135 void visit(luci::CircleSoftmax *) final;
136 void visit(luci::CircleSpaceToBatchND *) final;
137 void visit(luci::CircleSpaceToDepth *) final;
138 void visit(luci::CircleSparseToDense *) final;
139 void visit(luci::CircleSplit *) final;
140 void visit(luci::CircleSplitV *) final;
141 void visit(luci::CircleSqrt *) final;
142 void visit(luci::CircleSquare *) final;
143 void visit(luci::CircleSquaredDifference *) final;
144 void visit(luci::CircleSqueeze *) final;
145 void visit(luci::CircleStridedSlice *) final;
146 void visit(luci::CircleSub *) final;
147 void visit(luci::CircleSum *) final;
148 void visit(luci::CircleTanh *) final;
149 void visit(luci::CircleTile *) final;
150 void visit(luci::CircleTopKV2 *) final;
151 void visit(luci::CircleTranspose *) final;
152 void visit(luci::CircleTransposeConv *) final;
153 void visit(luci::CircleUnique *) final;
154 void visit(luci::CircleUnpack *) final;
155 void visit(luci::CircleWhere *) final;
156 void visit(luci::CircleWhile *) final;
157 void visit(luci::CircleZerosLike *) final;
159 void visit(luci::CircleBCQFullyConnected *) final;
160 void visit(luci::CircleBCQGather *) final;
161 void visit(luci::CircleInstanceNorm *) final;
163 void visit(luci::CircleInput *) final {}
164 void visit(luci::CircleOutput *) final {}
165 void visit(luci::CircleOutputDummy *) final {}
166 void visit(luci::CircleOutputExclude *) final {}
167 // Virtual for multiple-outputs
168 void visit(luci::CircleCustomOut *) final {}
169 void visit(luci::CircleIfOut *) final {}
170 void visit(luci::CircleNonMaxSuppressionV4Out *) final {}
171 void visit(luci::CircleSplitOut *) final {}
172 void visit(luci::CircleSplitVOut *) final {}
173 void visit(luci::CircleTopKV2Out *) final {}
174 void visit(luci::CircleUniqueOut *) final {}
175 void visit(luci::CircleUnpackOut *) final {}
176 void visit(luci::CircleWhileOut *) final {}
180 * @brief Exports CircleMaxPool2D or CircleAveragePool2D
182 * @note CirclePool2D should be one of CircleMaxPool2D or CircleAveragePool2D
184 template <class CirclePool2D>
185 void export_pool_2d(CirclePool2D *node, circle::BuiltinOperator builtin_op);
188 * @brief export simple nodes
190 void export_simple(loco::Node *node, circle::BuiltinOperator bop, circle::BuiltinOptions bot,
191 flatbuffers::Offset<void> options_offset);
194 * @brief export simple nodes having void options
196 void export_simple(loco::Node *node, circle::BuiltinOperator bop);
199 FlatBufferBuilder &builder;
200 SerializedModelData &md;
201 SerializedGraphData &gd;
204 template <class CirclePool2D>
205 void OperationExporter::export_pool_2d(CirclePool2D *node, circle::BuiltinOperator builtin_op)
207 LUCI_ASSERT(builtin_op == circle::BuiltinOperator_MAX_POOL_2D ||
208 builtin_op == circle::BuiltinOperator_L2_POOL_2D ||
209 builtin_op == circle::BuiltinOperator_AVERAGE_POOL_2D,
210 "Should be L2Pool, MaxPool or AvgPool");
211 LUCI_ASSERT(node->padding() != luci::Padding::UNDEFINED, "Padding is not set");
213 uint32_t op_idx = md.registerBuiltinOpcode(builtin_op, node->op_version());
214 std::vector<int32_t> inputs_vec{get_tensor_index(node->value())};
215 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
216 auto inputs = builder.CreateVector(inputs_vec);
217 auto outputs = builder.CreateVector(outputs_vec);
219 circle::Padding padding = getOpPadding(node->padding());
221 auto options = CreatePool2DOptions(builder, padding, node->stride()->w(), node->stride()->h(),
222 node->filter()->w(), node->filter()->h(),
223 to_circle_actfunc(node->fusedActivationFunction()));
224 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
225 circle::BuiltinOptions_Pool2DOptions, options.Union());
226 gd._operators.push_back(op_offset);
229 void OperationExporter::export_simple(loco::Node *node, circle::BuiltinOperator bop,
230 circle::BuiltinOptions bot,
231 flatbuffers::Offset<void> options_offset)
234 md.registerBuiltinOpcode(bop, loco::must_cast<luci::CircleNode *>(node)->op_version());
235 std::vector<int32_t> inputs_vec;
236 std::vector<int32_t> outputs_vec{get_tensor_index(node)};
237 for (uint32_t i = 0; i < node->arity(); ++i)
238 inputs_vec.push_back(get_tensor_index(node->arg(i)));
239 auto inputs = builder.CreateVector(inputs_vec);
240 auto outputs = builder.CreateVector(outputs_vec);
241 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, bot, options_offset);
242 gd._operators.push_back(op_offset);
245 void OperationExporter::export_simple(loco::Node *node, circle::BuiltinOperator bop)
248 md.registerBuiltinOpcode(bop, loco::must_cast<luci::CircleNode *>(node)->op_version());
249 std::vector<int32_t> inputs_vec;
250 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
251 for (uint32_t i = 0; i < node->arity(); ++i)
252 inputs_vec.push_back(get_tensor_index(node->arg(i)));
253 auto inputs = builder.CreateVector(inputs_vec);
254 auto outputs = builder.CreateVector(outputs_vec);
255 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs);
256 gd._operators.push_back(op_offset);
259 void OperationExporter::visit(luci::CircleAbs *node)
261 export_simple(node, circle::BuiltinOperator_ABS, circle::BuiltinOptions_AbsOptions,
262 CreateAbsOptions(builder).Union());
265 void OperationExporter::visit(luci::CircleAdd *node)
268 node, circle::BuiltinOperator_ADD, circle::BuiltinOptions_AddOptions,
269 CreateAddOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
272 void OperationExporter::visit(luci::CircleAddN *node)
274 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_ADD_N, node->op_version());
275 std::vector<int32_t> inputs_vec;
276 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
278 for (uint32_t i = 0; i < node->arity(); ++i)
279 inputs_vec.push_back(get_tensor_index(node->inputs(i)));
281 auto inputs = builder.CreateVector(inputs_vec);
282 auto outputs = builder.CreateVector(outputs_vec);
283 auto options = CreateAddNOptions(builder);
284 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
285 circle::BuiltinOptions_AddNOptions, options.Union());
286 gd._operators.push_back(op_offset);
289 void OperationExporter::visit(luci::CircleArgMax *node)
291 export_simple(node, circle::BuiltinOperator_ARG_MAX, circle::BuiltinOptions_ArgMaxOptions,
292 CreateArgMaxOptions(builder, to_circle_tensortype(node->output_type())).Union());
295 void OperationExporter::visit(luci::CircleArgMin *node)
297 export_simple(node, circle::BuiltinOperator_ARG_MIN, circle::BuiltinOptions_ArgMinOptions,
298 CreateArgMinOptions(builder, to_circle_tensortype(node->output_type())).Union());
301 void OperationExporter::visit(luci::CircleAveragePool2D *node)
303 export_pool_2d<luci::CircleAveragePool2D>(node, circle::BuiltinOperator_AVERAGE_POOL_2D);
306 void OperationExporter::visit(luci::CircleBatchMatMul *node)
308 export_simple(node, circle::BuiltinOperator_BATCH_MATMUL,
309 circle::BuiltinOptions_BatchMatMulOptions,
310 CreateBatchMatMulOptions(builder, node->adj_x(), node->adj_y()).Union());
313 void OperationExporter::visit(luci::CircleCast *node)
315 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_CAST, node->op_version());
316 std::vector<int32_t> inputs_vec{get_tensor_index(node->x())};
317 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
318 auto inputs = builder.CreateVector(inputs_vec);
319 auto outputs = builder.CreateVector(outputs_vec);
321 flatbuffers::Offset<Operator> op_offset;
322 if (node->out_data_type() != loco::DataType::Unknown)
324 auto options = CreateCastOptions(builder, to_circle_tensortype(node->in_data_type()),
325 to_circle_tensortype(node->out_data_type()));
326 op_offset = CreateOperator(builder, op_idx, inputs, outputs, circle::BuiltinOptions_CastOptions,
331 op_offset = CreateOperator(builder, op_idx, inputs, outputs);
333 gd._operators.push_back(op_offset);
336 void OperationExporter::visit(luci::CircleCeil *node)
338 export_simple(node, circle::BuiltinOperator_CEIL);
341 void OperationExporter::visit(luci::CircleConcatenation *node)
344 md.registerBuiltinOpcode(circle::BuiltinOperator_CONCATENATION, node->op_version());
345 std::vector<int32_t> inputs_vec;
346 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
348 for (uint32_t i = 0; i < node->numValues(); ++i)
349 inputs_vec.push_back(get_tensor_index(node->values(i)));
351 auto inputs = builder.CreateVector(inputs_vec);
352 auto outputs = builder.CreateVector(outputs_vec);
353 auto options = CreateConcatenationOptions(builder, node->axis(),
354 to_circle_actfunc(node->fusedActivationFunction()));
355 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
356 circle::BuiltinOptions_ConcatenationOptions, options.Union());
357 gd._operators.push_back(op_offset);
360 void OperationExporter::visit(luci::CircleBatchToSpaceND *node)
362 export_simple(node, circle::BuiltinOperator_BATCH_TO_SPACE_ND,
363 circle::BuiltinOptions_BatchToSpaceNDOptions,
364 CreateBatchToSpaceNDOptions(builder).Union());
367 void OperationExporter::visit(luci::CircleConv2D *node)
369 export_simple(node, circle::BuiltinOperator_CONV_2D, circle::BuiltinOptions_Conv2DOptions,
370 CreateConv2DOptions(builder, getOpPadding(node->padding()), node->stride()->w(),
372 to_circle_actfunc(node->fusedActivationFunction()),
373 node->dilation()->w(), node->dilation()->h())
377 void OperationExporter::visit(luci::CircleCos *node)
379 export_simple(node, circle::BuiltinOperator_COS, circle::BuiltinOptions_CosOptions,
380 CreateCosOptions(builder).Union());
383 void OperationExporter::visit(luci::CircleCustom *node)
385 auto custom_outputs = loco::succs(node);
387 uint32_t op_idx = md.registerCustomOpcode(node->custom_code());
388 std::vector<int32_t> inputs_vec;
389 std::vector<int32_t> outputs_vec;
391 for (uint32_t index = 0; index < node->numInputs(); index++)
393 inputs_vec.push_back(get_tensor_index(node->inputs(index)));
395 for (uint32_t index = 0; index < custom_outputs.size(); index++)
397 // store in order of index
399 for (auto out : custom_outputs)
401 auto custom_out = loco::must_cast<luci::CircleCustomOut *>(out);
402 if (custom_out->index() == static_cast<int32_t>(index))
404 outputs_vec.push_back(get_tensor_index(custom_out));
411 INTERNAL_EXN("Invalid Custom output");
415 auto inputs = builder.CreateVector(inputs_vec);
416 auto outputs = builder.CreateVector(outputs_vec);
417 flatbuffers::Offset<flatbuffers::Vector<uint8_t>> circle_custom_options;
418 std::vector<uint8_t> custom_options_vec{node->custom_options().begin(),
419 node->custom_options().end()};
420 circle_custom_options = builder.CreateVector(custom_options_vec);
421 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs, circle::BuiltinOptions_NONE,
422 flatbuffers::Offset<void>(), circle_custom_options);
423 gd._operators.push_back(op_offset);
426 void OperationExporter::visit(luci::CircleDepthToSpace *node)
428 export_simple(node, circle::BuiltinOperator_DEPTH_TO_SPACE,
429 circle::BuiltinOptions_DepthToSpaceOptions,
430 CreateDepthToSpaceOptions(builder, node->block_size()).Union());
433 void OperationExporter::visit(luci::CircleDepthwiseConv2D *node)
435 export_simple(node, circle::BuiltinOperator_DEPTHWISE_CONV_2D,
436 circle::BuiltinOptions_DepthwiseConv2DOptions,
437 CreateDepthwiseConv2DOptions(builder, getOpPadding(node->padding()),
438 node->stride()->w(), node->stride()->h(),
439 node->depthMultiplier(),
440 to_circle_actfunc(node->fusedActivationFunction()),
441 node->dilation()->w(), node->dilation()->h())
445 void OperationExporter::visit(luci::CircleDiv *node)
448 node, circle::BuiltinOperator_DIV, circle::BuiltinOptions_DivOptions,
449 CreateDivOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
452 void OperationExporter::visit(luci::CircleElu *node)
454 export_simple(node, circle::BuiltinOperator_ELU);
457 void OperationExporter::visit(luci::CircleEqual *node)
459 export_simple(node, circle::BuiltinOperator_EQUAL, circle::BuiltinOptions_EqualOptions,
460 CreateEqualOptions(builder).Union());
463 void OperationExporter::visit(luci::CircleExp *node)
465 export_simple(node, circle::BuiltinOperator_EXP, circle::BuiltinOptions_ExpOptions,
466 CreateExpOptions(builder).Union());
469 void OperationExporter::visit(luci::CircleExpandDims *node)
471 export_simple(node, circle::BuiltinOperator_EXPAND_DIMS, circle::BuiltinOptions_ExpandDimsOptions,
472 CreateExpandDimsOptions(builder).Union());
475 void OperationExporter::visit(luci::CircleFill *node)
477 export_simple(node, circle::BuiltinOperator_FILL, circle::BuiltinOptions_FillOptions,
478 CreateFillOptions(builder).Union());
481 void OperationExporter::visit(luci::CircleFloor *node)
483 export_simple(node, circle::BuiltinOperator_FLOOR);
486 void OperationExporter::visit(luci::CircleFloorDiv *node)
488 export_simple(node, circle::BuiltinOperator_FLOOR_DIV, circle::BuiltinOptions_FloorDivOptions,
489 CreateFloorDivOptions(builder).Union());
492 void OperationExporter::visit(luci::CircleFloorMod *node)
494 export_simple(node, circle::BuiltinOperator_FLOOR_MOD, circle::BuiltinOptions_FloorModOptions,
495 CreateFloorModOptions(builder).Union());
498 void OperationExporter::visit(luci::CircleFullyConnected *node)
501 node, circle::BuiltinOperator_FULLY_CONNECTED, circle::BuiltinOptions_FullyConnectedOptions,
502 CreateFullyConnectedOptions(builder, to_circle_actfunc(node->fusedActivationFunction()))
506 void OperationExporter::visit(luci::CircleGather *node)
508 export_simple(node, circle::BuiltinOperator_GATHER, circle::BuiltinOptions_GatherOptions,
509 CreateGatherOptions(builder, node->axis()).Union());
512 void OperationExporter::visit(luci::CircleGatherNd *node)
514 export_simple(node, circle::BuiltinOperator_GATHER_ND, circle::BuiltinOptions_GatherNdOptions,
515 CreateGatherNdOptions(builder).Union());
518 void OperationExporter::visit(luci::CircleGreater *node)
520 export_simple(node, circle::BuiltinOperator_GREATER, circle::BuiltinOptions_GreaterOptions,
521 CreateGreaterOptions(builder).Union());
524 void OperationExporter::visit(luci::CircleGreaterEqual *node)
526 export_simple(node, circle::BuiltinOperator_GREATER_EQUAL,
527 circle::BuiltinOptions_GreaterEqualOptions,
528 CreateGreaterEqualOptions(builder).Union());
531 void OperationExporter::visit(luci::CircleIf *node)
533 auto if_outs = loco::succs(node);
534 assert(if_outs.size() == node->output_count());
536 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_IF, node->op_version());
537 std::vector<int32_t> inputs_vec;
538 std::vector<int32_t> outputs_vec;
540 inputs_vec.push_back(get_tensor_index(node->cond()));
541 for (uint32_t idx = 0; idx < node->input_count(); ++idx)
542 inputs_vec.push_back(get_tensor_index(node->input(idx)));
544 for (uint32_t idx = 0; idx < node->output_count(); ++idx)
546 // store in order of index
548 for (auto out : if_outs)
550 auto if_out = loco::must_cast<luci::CircleIfOut *>(out);
551 if (if_out->index() == static_cast<int32_t>(idx))
553 outputs_vec.push_back(get_tensor_index(if_out));
560 INTERNAL_EXN("Invalid CircleIf output");
564 auto inputs = builder.CreateVector(inputs_vec);
565 auto outputs = builder.CreateVector(outputs_vec);
566 auto options = CreateIfOptions(builder, node->then_branch(), node->else_branch());
567 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
568 circle::BuiltinOptions_IfOptions, options.Union());
569 gd._operators.push_back(op_offset);
572 void OperationExporter::visit(luci::CircleL2Normalize *node)
575 node, circle::BuiltinOperator_L2_NORMALIZATION, circle::BuiltinOptions_L2NormOptions,
576 CreateL2NormOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
579 void OperationExporter::visit(luci::CircleL2Pool2D *node)
581 export_pool_2d<luci::CircleL2Pool2D>(node, circle::BuiltinOperator_L2_POOL_2D);
584 void OperationExporter::visit(luci::CircleLeakyRelu *node)
586 export_simple(node, circle::BuiltinOperator_LEAKY_RELU, circle::BuiltinOptions_LeakyReluOptions,
587 CreateLeakyReluOptions(builder, node->alpha()).Union());
590 void OperationExporter::visit(luci::CircleLess *node)
592 export_simple(node, circle::BuiltinOperator_LESS, circle::BuiltinOptions_LessOptions,
593 CreateLessOptions(builder).Union());
596 void OperationExporter::visit(luci::CircleLessEqual *node)
598 export_simple(node, circle::BuiltinOperator_LESS_EQUAL, circle::BuiltinOptions_LessEqualOptions,
599 CreateLessEqualOptions(builder).Union());
602 void OperationExporter::visit(luci::CircleLocalResponseNormalization *node)
604 export_simple(node, circle::BuiltinOperator_LOCAL_RESPONSE_NORMALIZATION,
605 circle::BuiltinOptions_LocalResponseNormalizationOptions,
606 CreateLocalResponseNormalizationOptions(builder, node->radius(), node->bias(),
607 node->alpha(), node->beta())
611 void OperationExporter::visit(luci::CircleLog *node)
613 export_simple(node, circle::BuiltinOperator_LOG);
616 void OperationExporter::visit(luci::CircleLogicalAnd *node)
618 export_simple(node, circle::BuiltinOperator_LOGICAL_AND, circle::BuiltinOptions_LogicalAndOptions,
619 CreateLogicalAndOptions(builder).Union());
622 void OperationExporter::visit(luci::CircleLogicalNot *node)
624 export_simple(node, circle::BuiltinOperator_LOGICAL_NOT, circle::BuiltinOptions_LogicalNotOptions,
625 CreateLogicalNotOptions(builder).Union());
628 void OperationExporter::visit(luci::CircleLogicalOr *node)
630 export_simple(node, circle::BuiltinOperator_LOGICAL_OR, circle::BuiltinOptions_LogicalOrOptions,
631 CreateLogicalOrOptions(builder).Union());
634 void OperationExporter::visit(luci::CircleLogistic *node)
636 export_simple(node, circle::BuiltinOperator_LOGISTIC);
639 void OperationExporter::visit(luci::CircleLogSoftmax *node)
641 export_simple(node, circle::BuiltinOperator_LOG_SOFTMAX, circle::BuiltinOptions_LogSoftmaxOptions,
642 CreateLogSoftmaxOptions(builder).Union());
645 void OperationExporter::visit(luci::CircleMatrixDiag *node)
647 export_simple(node, circle::BuiltinOperator_MATRIX_DIAG, circle::BuiltinOptions_MatrixDiagOptions,
648 CreateMatrixDiagOptions(builder).Union());
651 void OperationExporter::visit(luci::CircleMatrixSetDiag *node)
653 export_simple(node, circle::BuiltinOperator_MATRIX_SET_DIAG,
654 circle::BuiltinOptions_MatrixSetDiagOptions,
655 CreateMatrixSetDiagOptions(builder).Union());
658 void OperationExporter::visit(luci::CircleMaximum *node)
660 export_simple(node, circle::BuiltinOperator_MAXIMUM, circle::BuiltinOptions_MaximumMinimumOptions,
661 CreateMaximumMinimumOptions(builder).Union());
664 void OperationExporter::visit(luci::CircleMaxPool2D *node)
666 export_pool_2d<luci::CircleMaxPool2D>(node, circle::BuiltinOperator_MAX_POOL_2D);
669 void OperationExporter::visit(luci::CircleMean *node)
671 export_simple(node, circle::BuiltinOperator_MEAN, circle::BuiltinOptions_ReducerOptions,
672 CreateReducerOptions(builder, node->keep_dims()).Union());
675 void OperationExporter::visit(luci::CircleMinimum *node)
677 export_simple(node, circle::BuiltinOperator_MINIMUM, circle::BuiltinOptions_MaximumMinimumOptions,
678 CreateMaximumMinimumOptions(builder).Union());
681 void OperationExporter::visit(luci::CircleMirrorPad *node)
683 export_simple(node, circle::BuiltinOperator_MIRROR_PAD, circle::BuiltinOptions_MirrorPadOptions,
684 CreateMirrorPadOptions(builder, to_circle_mirrorpadmode(node->mode())).Union());
687 void OperationExporter::visit(luci::CircleMul *node)
690 node, circle::BuiltinOperator_MUL, circle::BuiltinOptions_MulOptions,
691 CreateMulOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
694 void OperationExporter::visit(luci::CircleNeg *node)
696 export_simple(node, circle::BuiltinOperator_NEG, circle::BuiltinOptions_NegOptions,
697 CreateNegOptions(builder).Union());
700 void OperationExporter::visit(luci::CircleNonMaxSuppressionV4 *node)
702 auto nms_outs = loco::succs(node);
703 assert(nms_outs.size() == 2);
706 md.registerBuiltinOpcode(circle::BuiltinOperator_NON_MAX_SUPPRESSION_V4, node->op_version());
707 std::vector<int32_t> inputs_vec{
708 get_tensor_index(node->boxes()), get_tensor_index(node->scores()),
709 get_tensor_index(node->max_output_size()), get_tensor_index(node->iou_threshold()),
710 get_tensor_index(node->score_threshold()),
712 std::vector<int32_t> outputs_vec;
714 for (uint32_t idx = 0; idx < nms_outs.size(); ++idx)
716 // store in order of index
718 for (auto out : nms_outs)
720 auto nms_out = loco::must_cast<luci::CircleNonMaxSuppressionV4Out *>(out);
721 if (nms_out->index() == static_cast<int32_t>(idx))
723 outputs_vec.push_back(get_tensor_index(nms_out));
730 INTERNAL_EXN("Invalid NonMaxSuppressionV4 output");
734 auto inputs = builder.CreateVector(inputs_vec);
735 auto outputs = builder.CreateVector(outputs_vec);
736 auto options = CreateNonMaxSuppressionV4Options(builder);
738 CreateOperator(builder, op_idx, inputs, outputs,
739 circle::BuiltinOptions_NonMaxSuppressionV4Options, options.Union());
740 gd._operators.push_back(op_offset);
743 void OperationExporter::visit(luci::CircleNotEqual *node)
745 export_simple(node, circle::BuiltinOperator_NOT_EQUAL, circle::BuiltinOptions_NotEqualOptions,
746 CreateNotEqualOptions(builder).Union());
749 void OperationExporter::visit(luci::CircleOneHot *node)
751 export_simple(node, circle::BuiltinOperator_ONE_HOT, circle::BuiltinOptions_OneHotOptions,
752 CreateOneHotOptions(builder, node->axis()).Union());
755 void OperationExporter::visit(luci::CirclePack *node)
757 export_simple(node, circle::BuiltinOperator_PACK, circle::BuiltinOptions_PackOptions,
758 CreatePackOptions(builder, node->values_count(), node->axis()).Union());
761 void OperationExporter::visit(luci::CirclePad *node)
763 export_simple(node, circle::BuiltinOperator_PAD, circle::BuiltinOptions_PadOptions,
764 CreatePadOptions(builder).Union());
767 void OperationExporter::visit(luci::CirclePow *node)
769 export_simple(node, circle::BuiltinOperator_POW, circle::BuiltinOptions_PowOptions,
770 CreatePowOptions(builder).Union());
773 void OperationExporter::visit(luci::CirclePRelu *node)
775 export_simple(node, circle::BuiltinOperator_PRELU);
778 void OperationExporter::visit(luci::CircleRange *node)
780 export_simple(node, circle::BuiltinOperator_RANGE, circle::BuiltinOptions_RangeOptions,
781 CreateRangeOptions(builder).Union());
784 void OperationExporter::visit(luci::CircleRank *node)
786 export_simple(node, circle::BuiltinOperator_RANK, circle::BuiltinOptions_RankOptions,
787 CreateRankOptions(builder).Union());
790 void OperationExporter::visit(luci::CircleReduceAny *node)
792 export_simple(node, circle::BuiltinOperator_REDUCE_ANY, circle::BuiltinOptions_ReducerOptions,
793 CreateReducerOptions(builder, node->keep_dims()).Union());
796 void OperationExporter::visit(luci::CircleReduceMax *node)
798 export_simple(node, circle::BuiltinOperator_REDUCE_MAX, circle::BuiltinOptions_ReducerOptions,
799 CreateReducerOptions(builder, node->keep_dims()).Union());
802 void OperationExporter::visit(luci::CircleReduceMin *node)
804 export_simple(node, circle::BuiltinOperator_REDUCE_MIN, circle::BuiltinOptions_ReducerOptions,
805 CreateReducerOptions(builder, node->keep_dims()).Union());
808 void OperationExporter::visit(luci::CircleReduceProd *node)
810 export_simple(node, circle::BuiltinOperator_REDUCE_PROD, circle::BuiltinOptions_ReducerOptions,
811 CreateReducerOptions(builder, node->keep_dims()).Union());
814 void OperationExporter::visit(luci::CircleRelu *node)
816 export_simple(node, circle::BuiltinOperator_RELU);
819 void OperationExporter::visit(luci::CircleRelu6 *node)
821 export_simple(node, circle::BuiltinOperator_RELU6);
824 void OperationExporter::visit(luci::CircleReluN1To1 *node)
826 export_simple(node, circle::BuiltinOperator_RELU_N1_TO_1);
829 void OperationExporter::visit(luci::CircleReshape *node)
831 auto new_shape = builder.CreateVector<int32_t>(
832 node->newShape()->rank(), [node](size_t i) { return node->newShape()->dim(i); });
834 export_simple(node, circle::BuiltinOperator_RESHAPE, circle::BuiltinOptions_ReshapeOptions,
835 CreateReshapeOptions(builder, new_shape).Union());
838 void OperationExporter::visit(luci::CircleResizeBilinear *node)
841 node, circle::BuiltinOperator_RESIZE_BILINEAR, circle::BuiltinOptions_ResizeBilinearOptions,
842 CreateResizeBilinearOptions(builder, node->align_corners(), node->half_pixel_centers())
846 void OperationExporter::visit(luci::CircleResizeNearestNeighbor *node)
848 export_simple(node, circle::BuiltinOperator_RESIZE_NEAREST_NEIGHBOR,
849 circle::BuiltinOptions_ResizeNearestNeighborOptions,
850 CreateResizeNearestNeighborOptions(builder, node->align_corners()).Union());
853 void OperationExporter::visit(luci::CircleReverseSequence *node)
856 node, circle::BuiltinOperator_REVERSE_SEQUENCE, circle::BuiltinOptions_ReverseSequenceOptions,
857 CreateReverseSequenceOptions(builder, node->seq_axis(), node->batch_axis()).Union());
860 void OperationExporter::visit(luci::CircleReverseV2 *node)
863 md.registerBuiltinOpcode(circle::BuiltinOperator_REVERSE_V2, node->op_version());
864 std::vector<int32_t> inputs_vec{get_tensor_index(node->tensor()), get_tensor_index(node->axis())};
865 std::vector<int32_t> outputs_vec{get_tensor_index(static_cast<loco::Node *>(node))};
866 auto inputs = builder.CreateVector(inputs_vec);
867 auto outputs = builder.CreateVector(outputs_vec);
868 auto options = CreateReverseV2Options(builder);
869 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
870 circle::BuiltinOptions_ReverseSequenceOptions, options.Union());
871 gd._operators.push_back(op_offset);
874 void OperationExporter::visit(luci::CircleRound *node)
876 export_simple(node, circle::BuiltinOperator_ROUND);
879 void OperationExporter::visit(luci::CircleRsqrt *node)
881 export_simple(node, circle::BuiltinOperator_RSQRT);
884 void OperationExporter::visit(luci::CircleScatterNd *node)
886 export_simple(node, circle::BuiltinOperator_SCATTER_ND, circle::BuiltinOptions_ScatterNdOptions,
887 CreateScatterNdOptions(builder).Union());
890 void OperationExporter::visit(luci::CircleSegmentSum *node)
892 export_simple(node, circle::BuiltinOperator_SEGMENT_SUM, circle::BuiltinOptions_SegmentSumOptions,
893 CreateSegmentSumOptions(builder).Union());
896 void OperationExporter::visit(luci::CircleSelect *node)
898 export_simple(node, circle::BuiltinOperator_SELECT, circle::BuiltinOptions_SelectOptions,
899 CreateSelectOptions(builder).Union());
902 void OperationExporter::visit(luci::CircleSelectV2 *node)
904 export_simple(node, circle::BuiltinOperator_SELECT_V2, circle::BuiltinOptions_SelectV2Options,
905 CreateSelectV2Options(builder).Union());
908 void OperationExporter::visit(luci::CircleShape *node)
910 export_simple(node, circle::BuiltinOperator_SHAPE, circle::BuiltinOptions_ShapeOptions,
911 CreateShapeOptions(builder, to_circle_tensortype(node->out_type())).Union());
914 void OperationExporter::visit(luci::CircleSin *node)
916 export_simple(node, circle::BuiltinOperator_SIN);
919 void OperationExporter::visit(luci::CircleSlice *node)
921 export_simple(node, circle::BuiltinOperator_SLICE, circle::BuiltinOptions_SliceOptions,
922 CreateSliceOptions(builder).Union());
925 void OperationExporter::visit(luci::CircleSoftmax *node)
927 export_simple(node, circle::BuiltinOperator_SOFTMAX, circle::BuiltinOptions_SoftmaxOptions,
928 CreateSoftmaxOptions(builder, node->beta()).Union());
931 void OperationExporter::visit(luci::CircleSpaceToBatchND *node)
933 export_simple(node, circle::BuiltinOperator_SPACE_TO_BATCH_ND,
934 circle::BuiltinOptions_SpaceToBatchNDOptions,
935 CreateSpaceToBatchNDOptions(builder).Union());
938 void OperationExporter::visit(luci::CircleSpaceToDepth *node)
940 export_simple(node, circle::BuiltinOperator_SPACE_TO_DEPTH,
941 circle::BuiltinOptions_SpaceToDepthOptions,
942 CreateSpaceToDepthOptions(builder, node->block_size()).Union());
945 void OperationExporter::visit(luci::CircleSparseToDense *node)
947 export_simple(node, circle::BuiltinOperator_SPARSE_TO_DENSE,
948 circle::BuiltinOptions_SparseToDenseOptions,
949 CreateSparseToDenseOptions(builder, node->validate_indices()).Union());
952 void OperationExporter::visit(luci::CircleSplit *node)
954 auto split_outs = loco::succs(node);
955 assert(int32_t(split_outs.size()) == node->num_split());
957 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SPLIT, node->op_version());
958 // NOTE BuiltinOperator_SPLIT input is placed at second position
959 std::vector<int32_t> inputs_vec{get_tensor_index(node->split_dim()),
960 get_tensor_index(node->input())};
961 std::vector<int32_t> outputs_vec;
963 for (int32_t index = 0; index < node->num_split(); index++)
965 // store in order of index
967 for (auto out : split_outs)
969 auto split_out = loco::must_cast<luci::CircleSplitOut *>(out);
970 if (split_out->index() == index)
972 outputs_vec.push_back(get_tensor_index(split_out));
979 INTERNAL_EXN("Invalid Split output");
983 auto inputs = builder.CreateVector(inputs_vec);
984 auto outputs = builder.CreateVector(outputs_vec);
985 auto options = CreateSplitOptions(builder, node->num_split());
986 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
987 circle::BuiltinOptions_SplitOptions, options.Union());
988 gd._operators.push_back(op_offset);
991 void OperationExporter::visit(luci::CircleSplitV *node)
993 auto split_outs = loco::succs(node);
994 assert(int32_t(split_outs.size()) == node->num_split());
996 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_SPLIT_V, node->op_version());
997 std::vector<int32_t> inputs_vec{get_tensor_index(node->input()),
998 get_tensor_index(node->size_splits()),
999 get_tensor_index(node->split_dim())};
1000 std::vector<int32_t> outputs_vec;
1002 for (int32_t index = 0; index < node->num_split(); index++)
1004 // store in order of index
1006 for (auto out : split_outs)
1008 auto split_out = loco::must_cast<luci::CircleSplitVOut *>(out);
1009 if (split_out->index() == index)
1011 outputs_vec.push_back(get_tensor_index(split_out));
1018 INTERNAL_EXN("Invalid SplitV output");
1022 auto inputs = builder.CreateVector(inputs_vec);
1023 auto outputs = builder.CreateVector(outputs_vec);
1024 auto options = CreateSplitVOptions(builder, node->num_split());
1025 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
1026 circle::BuiltinOptions_SplitVOptions, options.Union());
1027 gd._operators.push_back(op_offset);
1030 void OperationExporter::visit(luci::CircleSqrt *node)
1032 export_simple(node, circle::BuiltinOperator_SQRT);
1035 void OperationExporter::visit(luci::CircleSquare *node)
1037 export_simple(node, circle::BuiltinOperator_SQUARE, circle::BuiltinOptions_SquareOptions,
1038 CreateSquareOptions(builder).Union());
1041 void OperationExporter::visit(luci::CircleSquaredDifference *node)
1043 export_simple(node, circle::BuiltinOperator_SQUARED_DIFFERENCE,
1044 circle::BuiltinOptions_SquaredDifferenceOptions,
1045 CreateSquaredDifferenceOptions(builder).Union());
1048 void OperationExporter::visit(luci::CircleSqueeze *node)
1050 auto squeeze_dims = builder.CreateVector<int32_t>(node->squeeze_dims());
1051 export_simple(node, circle::BuiltinOperator_SQUEEZE, circle::BuiltinOptions_SqueezeOptions,
1052 CreateSqueezeOptions(builder, squeeze_dims).Union());
1055 void OperationExporter::visit(luci::CircleStridedSlice *node)
1057 export_simple(node, circle::BuiltinOperator_STRIDED_SLICE,
1058 circle::BuiltinOptions_StridedSliceOptions,
1059 CreateStridedSliceOptions(builder, node->begin_mask(), node->end_mask(),
1060 node->ellipsis_mask(), node->new_axis_mask(),
1061 node->shrink_axis_mask())
1065 void OperationExporter::visit(luci::CircleSub *node)
1068 node, circle::BuiltinOperator_SUB, circle::BuiltinOptions_SubOptions,
1069 CreateSubOptions(builder, to_circle_actfunc(node->fusedActivationFunction())).Union());
1072 void OperationExporter::visit(luci::CircleSum *node)
1074 export_simple(node, circle::BuiltinOperator_SUM, circle::BuiltinOptions_ReducerOptions,
1075 CreateReducerOptions(builder, node->keep_dims()).Union());
1078 void OperationExporter::visit(luci::CircleTanh *node)
1080 export_simple(node, circle::BuiltinOperator_TANH);
1083 void OperationExporter::visit(luci::CircleTile *node)
1085 export_simple(node, circle::BuiltinOperator_TILE, circle::BuiltinOptions_TileOptions,
1086 CreateTileOptions(builder).Union());
1089 void OperationExporter::visit(luci::CircleTopKV2 *node)
1091 auto topkv2_outs = loco::succs(node);
1092 int outs_count = int32_t(topkv2_outs.size());
1093 assert(outs_count == 2);
1095 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_TOPK_V2, node->op_version());
1096 std::vector<int32_t> inputs_vec{get_tensor_index(node->input()), get_tensor_index(node->k())};
1097 std::vector<int32_t> outputs_vec;
1099 for (int32_t index = 0; index < outs_count; index++)
1101 // store in order of index
1103 for (auto out : topkv2_outs)
1105 auto topkv2_out = loco::must_cast<luci::CircleTopKV2Out *>(out);
1106 if (topkv2_out->index() == index)
1108 outputs_vec.push_back(get_tensor_index(topkv2_out));
1115 INTERNAL_EXN("Invalid TopKV2 output");
1119 auto inputs = builder.CreateVector(inputs_vec);
1120 auto outputs = builder.CreateVector(outputs_vec);
1121 auto options = CreateTopKV2Options(builder);
1122 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
1123 circle::BuiltinOptions_TopKV2Options, options.Union());
1124 gd._operators.push_back(op_offset);
1127 void OperationExporter::visit(luci::CircleTranspose *node)
1129 export_simple(node, circle::BuiltinOperator_TRANSPOSE, circle::BuiltinOptions_TransposeOptions,
1130 CreateTransposeOptions(builder).Union());
1133 void OperationExporter::visit(luci::CircleTransposeConv *node)
1135 export_simple(node, circle::BuiltinOperator_TRANSPOSE_CONV,
1136 circle::BuiltinOptions_TransposeConvOptions,
1137 CreateTransposeConvOptions(builder, getOpPadding(node->padding()),
1138 node->stride()->w(), node->stride()->h())
1142 void OperationExporter::visit(luci::CircleUnique *node)
1144 auto unique_outs = loco::succs(node);
1145 assert(int32_t(unique_outs.size()) == 2);
1146 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_UNIQUE, node->op_version());
1148 std::vector<int32_t> inputs_vec{get_tensor_index(node->input())};
1149 std::vector<int32_t> outputs_vec;
1151 for (int32_t index = 0; index < 2; index++)
1153 // store in order of index
1155 for (auto out : unique_outs)
1157 auto unique_out = loco::must_cast<luci::CircleUniqueOut *>(out);
1158 if (unique_out->index() == index)
1160 outputs_vec.push_back(get_tensor_index(unique_out));
1167 INTERNAL_EXN("Invalid Unique output");
1171 auto inputs = builder.CreateVector(inputs_vec);
1172 auto outputs = builder.CreateVector(outputs_vec);
1173 auto options = CreateUniqueOptions(builder, to_circle_tensortype(node->idx_out_type()));
1174 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
1175 circle::BuiltinOptions_UniqueOptions, options.Union());
1176 gd._operators.push_back(op_offset);
1179 void OperationExporter::visit(luci::CircleUnpack *node)
1182 auto settings = luci::UserSettings::settings();
1184 auto unpack_outs = loco::succs(node);
1185 // NOTE real models may not use all of the outputs
1186 if (static_cast<int32_t>(unpack_outs.size()) != node->num())
1188 if (settings->get(luci::UserSettings::Key::DisableValidation))
1190 WARN(l) << "Warning: export Unpack(" << node->name() << ") 'num' not same as outputs";
1196 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_UNPACK, node->op_version());
1197 std::vector<int32_t> inputs_vec{get_tensor_index(node->value())};
1198 std::vector<int32_t> outputs_vec;
1200 for (int32_t index = 0; index < node->num(); index++)
1202 // store in order of index
1204 for (auto out : unpack_outs)
1206 auto unpack_out = loco::must_cast<luci::CircleUnpackOut *>(out);
1207 if (unpack_out->index() == index)
1209 outputs_vec.push_back(get_tensor_index(unpack_out));
1214 // NOTE real models may not use all of the outputs
1217 if (settings->get(luci::UserSettings::Key::DisableValidation))
1219 WARN(l) << "Warning: export Unpack(" << node->name() << ") output " << index << " not used";
1226 auto inputs = builder.CreateVector(inputs_vec);
1227 auto outputs = builder.CreateVector(outputs_vec);
1228 auto options = CreateUnpackOptions(builder, node->num(), node->axis());
1229 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
1230 circle::BuiltinOptions_UnpackOptions, options.Union());
1231 gd._operators.push_back(op_offset);
1234 void OperationExporter::visit(luci::CircleWhere *node)
1236 export_simple(node, circle::BuiltinOperator_WHERE, circle::BuiltinOptions_WhereOptions,
1237 CreateWhereOptions(builder).Union());
1240 void OperationExporter::visit(luci::CircleWhile *node)
1242 auto while_outs = loco::succs(node);
1243 assert(while_outs.size() == node->output_count());
1245 uint32_t op_idx = md.registerBuiltinOpcode(circle::BuiltinOperator_WHILE, node->op_version());
1246 std::vector<int32_t> inputs_vec;
1247 std::vector<int32_t> outputs_vec;
1249 for (uint32_t idx = 0; idx < node->input_count(); ++idx)
1250 inputs_vec.push_back(get_tensor_index(node->input(idx)));
1252 for (uint32_t idx = 0; idx < node->output_count(); ++idx)
1254 // store in order of index
1256 for (auto out : while_outs)
1258 auto while_out = loco::must_cast<luci::CircleWhileOut *>(out);
1259 if (while_out->index() == static_cast<int32_t>(idx))
1261 outputs_vec.push_back(get_tensor_index(while_out));
1268 INTERNAL_EXN("Invalid CircleWhile output");
1272 auto inputs = builder.CreateVector(inputs_vec);
1273 auto outputs = builder.CreateVector(outputs_vec);
1274 auto options = CreateWhileOptions(builder, node->cond_branch(), node->body_branch());
1275 auto op_offset = CreateOperator(builder, op_idx, inputs, outputs,
1276 circle::BuiltinOptions_WhileOptions, options.Union());
1277 gd._operators.push_back(op_offset);
1280 void OperationExporter::visit(luci::CircleZerosLike *node)
1282 export_simple(node, circle::BuiltinOperator_ZEROS_LIKE, circle::BuiltinOptions_ZerosLikeOptions,
1283 CreateZerosLikeOptions(builder).Union());
1286 void OperationExporter::visit(luci::CircleBCQFullyConnected *node)
1288 export_simple(node, circle::BuiltinOperator_BCQ_FULLY_CONNECTED,
1289 circle::BuiltinOptions_BCQFullyConnectedOptions,
1290 CreateBCQFullyConnectedOptions(builder, node->weights_hidden_size(),
1291 to_circle_actfunc(node->fusedActivationFunction()))
1295 void OperationExporter::visit(luci::CircleBCQGather *node)
1297 export_simple(node, circle::BuiltinOperator_BCQ_GATHER, circle::BuiltinOptions_BCQGatherOptions,
1298 CreateBCQGatherOptions(builder, node->input_hidden_size(), node->axis()).Union());
1301 void OperationExporter::visit(luci::CircleInstanceNorm *node)
1303 export_simple(node, circle::BuiltinOperator_INSTANCE_NORM,
1304 circle::BuiltinOptions_InstanceNormOptions,
1305 CreateInstanceNormOptions(builder, node->epsilon(),
1306 to_circle_actfunc(node->fusedActivationFunction()))
1310 void exportNode(loco::Node *node, flatbuffers::FlatBufferBuilder &builder, SerializedModelData &md,
1311 SerializedGraphData &gd)
1313 if (auto circle_node = dynamic_cast<luci::CircleNode *>(node))
1315 OperationExporter exporter{builder, md, gd};
1316 circle_node->accept(&exporter);
1320 INTERNAL_EXN("Node with unsupported dialect found");
1329 void exportNodes(loco::Graph *g, FlatBufferBuilder &builder, SerializedModelData &md,
1330 SerializedGraphData &gd)
1332 for (auto node : loco::postorder_traversal(loco::output_nodes(g)))
1334 exportNode(node, builder, md, gd);