eecfe81cc8c5b43fff4b12dd96820d1b4630b538
[platform/core/ml/nnfw.git] / runtime / onert / core / src / ir / OperationDumper.cc
1 /*
2  * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
3  *
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
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #include "OperationDumper.h"
18
19 #include <string>
20
21 #include "util/logging.h"
22
23 namespace onert
24 {
25 namespace ir
26 {
27
28 using namespace operation;
29
30 namespace
31 {
32 void dumpUnaryInputOp(const Operation &node, const std::string &adding_input = "")
33 {
34   VERBOSE(LIR) << "* " << node.name() << std::endl;
35   VERBOSE(LIR) << "  - Inputs : Input(" << node.getInputs().at(0) << ") " << adding_input
36                << std::endl;
37   VERBOSE(LIR) << "  - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
38 }
39
40 void dumpBinaryInputOp(const Operation &node, const std::string &adding_input = "")
41 {
42   VERBOSE(LIR) << "* " << node.name() << std::endl;
43   VERBOSE(LIR) << "  - Inputs : Input(" << node.getInputs().at(0) << ", " << node.getInputs().at(1)
44                << ") " << adding_input << std::endl;
45   VERBOSE(LIR) << "  - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
46 }
47
48 void dumpConvOp(const Operation &node, const std::string &padding_type)
49 {
50   VERBOSE(LIR) << "* " << node.name() << "(" << padding_type << ")" << std::endl;
51   VERBOSE(LIR) << "  - Inputs : IFM(" << node.getInputs().at(Conv2D::Input::INPUT) << ") Kernel("
52                << node.getInputs().at(Conv2D::Input::KERNEL) << ") Bias("
53                << node.getInputs().at(Conv2D::Input::BIAS) << ")" << std::endl;
54   VERBOSE(LIR) << "  - Output : OFM(" << node.getOutputs().at(0) << ")" << std::endl;
55 }
56
57 void dumpPackingOp(const Operation &node)
58 {
59   VERBOSE(LIR) << "* " << node.name() << std::endl;
60   std::string inputs;
61   for (auto i : node.getInputs())
62   {
63     inputs += std::to_string(i.value()) + ",";
64   }
65   VERBOSE(LIR) << "  - Inputs : Inputs(" << inputs << ")" << std::endl;
66   VERBOSE(LIR) << "  - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
67 }
68 } // namespace
69
70 OperationDumper::OperationDumper(const std::string &start_msg)
71 {
72   VERBOSE(LIR) << start_msg << std::endl;
73 }
74
75 void OperationDumper::visit(const ArgMax &node) { dumpBinaryInputOp(node); }
76
77 void OperationDumper::visit(const BatchToSpaceND &node)
78 {
79   std::string block_size =
80       "BlockSize(" +
81       std::to_string(node.getInputs().at(BatchToSpaceND::Input::BLOCK_SIZE).value()) + ")";
82   dumpUnaryInputOp(node, block_size);
83 }
84
85 void OperationDumper::visit(const BCQFullyConnected &node)
86 {
87   VERBOSE(LIR) << "* " << node.name() << std::endl;
88   VERBOSE(LIR) << "  - Inputs : IFM(" << node.getInputs().at(BCQFullyConnected::Input::INPUT)
89                << ") WeightsBinary("
90                << node.getInputs().at(BCQFullyConnected::Input::WEIGHTS_BINARY)
91                << ") WeightsScales("
92                << node.getInputs().at(BCQFullyConnected::Input::WEIGHTS_SCALES)
93                << ") WeightsClusters("
94                << node.getInputs().at(BCQFullyConnected::Input::WEIGHTS_CLUSTERS) << ") Bias("
95                << node.getInputs().at(BCQFullyConnected::Input::BIAS) << ")" << std::endl;
96   VERBOSE(LIR) << "  - Output : OFM(" << node.getOutputs().at(0) << ")" << std::endl;
97 }
98
99 void OperationDumper::visit(const BinaryArithmetic &node) { dumpBinaryInputOp(node); }
100
101 void OperationDumper::visit(const operation::BroadcastTo &node) { dumpBinaryInputOp(node); }
102
103 void OperationDumper::visit(const Comparison &node) { dumpBinaryInputOp(node); }
104
105 void OperationDumper::visit(const Concat &node) { dumpPackingOp(node); }
106
107 void OperationDumper::visit(const Conv2D &node)
108 {
109   std::string padding_type =
110       node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit";
111   dumpConvOp(node, padding_type);
112 }
113
114 void OperationDumper::visit(const ConvertFp16ToFp32 &node) { dumpUnaryInputOp(node); }
115
116 void OperationDumper::visit(const ConvertFp32ToFp16 &node) { dumpUnaryInputOp(node); }
117
118 void OperationDumper::visit(const DepthToSpace &node) { dumpUnaryInputOp(node); }
119
120 void OperationDumper::visit(const DepthwiseConv2D &node)
121 {
122   std::string padding_type =
123       node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit";
124   dumpConvOp(node, padding_type);
125 }
126
127 void OperationDumper::visit(const ElementwiseActivation &node)
128 {
129   std::string params;
130   if (node.param().op_type == ElementwiseActivation::Type::RELU)
131   {
132     params = " lower value(" + std::to_string(node.param().alpha) + ") upper value(" +
133              std::to_string(node.param().beta) + ")";
134   }
135   else if (node.param().op_type == ElementwiseActivation::Type::LEAKY_RELU)
136   {
137     params = " alpha value(" + std::to_string(node.param().alpha) + ")";
138   }
139   dumpUnaryInputOp(node, params);
140 }
141
142 void OperationDumper::visit(const ElementwiseBinary &node) { dumpBinaryInputOp(node); }
143
144 void OperationDumper::visit(const ElementwiseUnary &node) { dumpUnaryInputOp(node); }
145
146 void OperationDumper::visit(const EmbeddingLookup &node)
147 {
148   VERBOSE(LIR) << "* " << node.name() << std::endl;
149   VERBOSE(LIR) << "  - Inputs : Lookups(" << node.getInputs().at(EmbeddingLookup::Input::LOOKUPS)
150                << ") VALUES(" << node.getInputs().at(EmbeddingLookup::Input::VALUES) << ")"
151                << std::endl;
152   VERBOSE(LIR) << "  - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
153 }
154
155 void OperationDumper::visit(const ExpandDims &node)
156 {
157   std::string axis =
158       "AXIS(" + std::to_string(node.getInputs().at(ExpandDims::Input::AXIS).value()) + ")";
159   dumpUnaryInputOp(node, axis);
160 }
161
162 void OperationDumper::visit(const FullyConnected &node)
163 {
164   std::string inputs =
165       "Weight(" + std::to_string(node.getInputs().at(FullyConnected::Input::WEIGHT).value()) +
166       ") Bias(" + std::to_string(node.getInputs().at(FullyConnected::Input::BIAS).value()) + ")";
167   dumpUnaryInputOp(node, inputs);
168 }
169
170 void OperationDumper::visit(const Gather &node)
171 {
172   std::string indices =
173       "Indices(" + std::to_string(node.getInputs().at(Gather::Input::INDICES).value()) + ")";
174   dumpUnaryInputOp(node, indices);
175 }
176
177 void OperationDumper::visit(const HashtableLookup &node)
178 {
179   VERBOSE(LIR) << "* HashTableLookup" << std::endl;
180   VERBOSE(LIR) << "  - Inputs : Lookups(" << node.getInputs().at(HashtableLookup::Input::LOOKUPS)
181                << ") Keys(" << node.getInputs().at(HashtableLookup::Input::KEYS) << ") Values("
182                << node.getInputs().at(HashtableLookup::Input::VALUES) << ")" << std::endl;
183   VERBOSE(LIR) << "  - Outputs : Output(" << node.getInputs().at(HashtableLookup::Output::OUTPUT)
184                << ") Hits(" << node.getInputs().at(HashtableLookup::Output::HITS) << ")"
185                << std::endl;
186 }
187
188 void OperationDumper::visit(const InstanceNorm &node)
189 {
190   std::string inputs =
191       "Gamma(" + std::to_string(node.getInputs().at(InstanceNorm::Input::GAMMA).value()) +
192       ") Beta(" + std::to_string(node.getInputs().at(InstanceNorm::Input::BETA).value()) + ")";
193   dumpUnaryInputOp(node, inputs);
194 }
195
196 void OperationDumper::visit(const L2Normalization &node) { dumpUnaryInputOp(node); }
197
198 void OperationDumper::visit(const LocalResponseNormalization &node) { dumpUnaryInputOp(node); }
199
200 void OperationDumper::visit(const LSTM &node)
201 {
202   VERBOSE(LIR) << "* " << node.name() << std::endl;
203   VERBOSE(LIR)
204       << "  - Inputs : Input(" << node.getInputs().at(LSTM::Input::INPUT)
205       << ") Input To Input Weights(" << node.getInputs().at(LSTM::Input::INPUT_TO_INPUT_WEIGHTS)
206       << ") Input To Forget Weights(" << node.getInputs().at(LSTM::Input::INPUT_TO_FORGET_WEIGHTS)
207       << ") Input To Cell Weights(" << node.getInputs().at(LSTM::Input::INPUT_TO_CELL_WEIGHTS)
208       << ") Input To Output Weights(" << node.getInputs().at(LSTM::Input::INPUT_TO_OUTPUT_WEIGHTS)
209       << ") Recurrent To Input Weights("
210       << node.getInputs().at(LSTM::Input::RECURRENT_TO_INPUT_WEIGHTS)
211       << ") Recurrent To Forget Weights("
212       << node.getInputs().at(LSTM::Input::RECURRENT_TO_FORGET_WEIGHTS)
213       << ") Recurrent To Cell Weights("
214       << node.getInputs().at(LSTM::Input::RECURRENT_TO_CELL_WEIGHTS)
215       << ") Recurrent To Output Weights("
216       << node.getInputs().at(LSTM::Input::RECURRENT_TO_OUTPUT_WEIGHTS) << ") Cell To Input Weights("
217       << node.getInputs().at(LSTM::Input::CELL_TO_INPUT_WEIGHTS) << ") Cell To Forget Weights("
218       << node.getInputs().at(LSTM::Input::CELL_TO_FORGET_WEIGHTS) << ") Cell To OUTPUT Weights("
219       << node.getInputs().at(LSTM::Input::CELL_TO_OUTPUT_WEIGHTS) << ") Input Gate Bias("
220       << node.getInputs().at(LSTM::Input::INPUT_GATE_BIAS) << ") Forget Gate Bias("
221       << node.getInputs().at(LSTM::Input::FORGET_GATE_BIAS) << ") Cell Bias("
222       << node.getInputs().at(LSTM::Input::CELL_BIAS) << ") Output Gate Bias("
223       << node.getInputs().at(LSTM::Input::OUTPUT_GATE_BIAS) << ") Projection Weights("
224       << node.getInputs().at(LSTM::Input::PROJECTION_WEIGHTS) << ") Projection Bias("
225       << node.getInputs().at(LSTM::Input::PROJECTION_BIAS) << ") Output State In("
226       << node.getInputs().at(LSTM::Input::OUTPUT_STATE_IN) << ") Cell State In("
227       << node.getInputs().at(LSTM::Input::CELL_STATE_IN);
228   if (node.getInputs().size() == 24)
229   {
230     VERBOSE(LIR) << ") Input Layer Normalization Weights("
231                  << node.getInputs().at(LSTM::Input::INPUT_LAYER_NORMALIZATION_WEIGHTS)
232                  << ") Forget Layer Normalization Weights("
233                  << node.getInputs().at(LSTM::Input::FORGET_LAYER_NORMALIZATION_WEIGHTS)
234                  << ") Cell Layer Normalization Weights("
235                  << node.getInputs().at(LSTM::Input::CELL_LAYER_NORMALIZATION_WEIGHTS)
236                  << ") Ouput Layer Normalization Weights("
237                  << node.getInputs().at(LSTM::Input::OUTPUT_LAYER_NORMALIZATION_WEIGHTS);
238   }
239   VERBOSE(LIR) << ")" << std::endl;
240   VERBOSE(LIR) << "  - Output : Scratch Buffer("
241                << node.getOutputs().at(LSTM::Output::SCRATCH_BUFFER) << ") Output State Out("
242                << node.getOutputs().at(LSTM::Output::OUTPUT_STATE_OUT) << ") Cell State Out("
243                << node.getOutputs().at(LSTM::Output::CELL_STATE_OUT) << ") Output("
244                << node.getOutputs().at(LSTM::Output::OUTPUT) << ")" << std::endl;
245 }
246
247 void OperationDumper::visit(const Pack &node) { dumpPackingOp(node); }
248
249 void OperationDumper::visit(const Pad &node)
250 {
251   std::string pad = "Pad(" + std::to_string(node.getInputs().at(Pad::Input::PAD).value()) + ")";
252   dumpUnaryInputOp(node, pad);
253 }
254
255 void OperationDumper::visit(const Permute &node)
256 {
257   std::string permute_type = "Unknown";
258   switch (node.getPermuteType())
259   {
260     case Permute::Type::COPY:
261       permute_type = "Copy";
262       break;
263     case Permute::Type::NHWC_TO_NCHW:
264       permute_type = "NHWC to NCHW";
265       break;
266     case Permute::Type::NCHW_TO_NHWC:
267       permute_type = "NCHW to NHWC";
268       break;
269   }
270
271   VERBOSE(LIR) << "* Permute(" + permute_type + ")" << std::endl;
272   VERBOSE(LIR) << "  - Inputs : Input(" << node.getInputs().at(0) << ")" << std::endl;
273   VERBOSE(LIR) << "  - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
274 }
275
276 void OperationDumper::visit(const Pool2D &node)
277 {
278   std::string padding_type =
279       node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit";
280   VERBOSE(LIR) << "* " << node.name() << "(" << padding_type << ")" << std::endl;
281   VERBOSE(LIR) << "  - Inputs : IFM(" << node.getInputs().at(Pool2D::Input::INPUT) << ")"
282                << std::endl;
283   VERBOSE(LIR) << "  - Output : OFM(" << node.getOutputs().at(0) << ")" << std::endl;
284 }
285
286 void OperationDumper::visit(const Pow &node) { dumpBinaryInputOp(node); }
287
288 void OperationDumper::visit(const PReLU &node)
289 {
290   std::string alpha =
291       "Alpha(" + std::to_string(node.getInputs().at(PReLU::Input::ALPHA).value()) + ")";
292   dumpUnaryInputOp(node, alpha);
293 }
294
295 void OperationDumper::visit(const Rank &node) { dumpUnaryInputOp(node); }
296
297 void OperationDumper::visit(const Reduce &node) { dumpUnaryInputOp(node); }
298
299 void OperationDumper::visit(const Reshape &node)
300 {
301   // optional param
302   std::string shape =
303       node.getInputs().size() == 2
304           ? "Shape(" + std::to_string(node.getInputs().at(Reshape::Input::SHAPE).value()) + ")"
305           : "Shape(not provided)";
306   dumpUnaryInputOp(node, shape);
307 }
308
309 void OperationDumper::visit(const ResizeBilinear &node)
310 {
311   if (node.getInputs().size() == 1)
312   {
313     dumpUnaryInputOp(node);
314   }
315   else if (node.getInputs().size() == 2)
316   {
317     dumpBinaryInputOp(node);
318   }
319   else
320   {
321     VERBOSE(LIR) << "* " << node.name() << " is set wrong" << std::endl;
322   }
323 }
324
325 void OperationDumper::visit(const ResizeNearestNeighbor &node)
326 {
327   if (node.getInputs().size() == 1)
328   {
329     dumpUnaryInputOp(node);
330   }
331   else if (node.getInputs().size() == 2)
332   {
333     dumpBinaryInputOp(node);
334   }
335   else
336   {
337     VERBOSE(LIR) << "* " << node.name() << " is set wrong" << std::endl;
338   }
339 }
340
341 void OperationDumper::visit(const Reverse &node)
342 {
343   std::string axis =
344       "Axis(" + std::to_string(node.getInputs().at(Reverse::Input::AXIS).value()) + ")";
345   dumpUnaryInputOp(node, axis);
346 }
347
348 void OperationDumper::visit(const RNN &node)
349 {
350   VERBOSE(LIR) << "* RNN" << std::endl;
351   VERBOSE(LIR) << "  - Inputs : Input(" << node.getInputs().at(RNN::Input::INPUT) << ") Weights("
352                << node.getInputs().at(RNN::Input::WEIGHTS) << ") Recurrent Weights("
353                << node.getInputs().at(RNN::Input::RECURRENT_WEIGHTS) << ") Bias("
354                << node.getInputs().at(RNN::Input::BIAS) << ") Hidden State("
355                << node.getInputs().at(RNN::Input::HIDDEN_STATE_IN) << ")" << std::endl;
356   VERBOSE(LIR) << "  - Output : Output(" << node.getOutputs().at(RNN::Output::OUTPUT)
357                << ") Hidden State(" << node.getInputs().at(RNN::Output::HIDDEN_STATE_OUT) << ")"
358                << std::endl;
359 }
360
361 void OperationDumper::visit(const Range &node)
362 {
363   VERBOSE(LIR) << "* Range" << std::endl;
364   VERBOSE(LIR) << "  - Inputs : Start(" << node.getInputs().at(Range::Input::START) << ")"
365                << " Limit(" << node.getInputs().at(Range::Input::LIMIT) << ")"
366                << " Delta(" << node.getInputs().at(Range::Input::DELTA) << ")" << std::endl;
367   VERBOSE(LIR) << "  - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
368 }
369
370 void OperationDumper::visit(const Select &node)
371 {
372   VERBOSE(LIR) << "* Select" << std::endl;
373   VERBOSE(LIR) << "  - Inputs : Condition(" << node.getInputs().at(Select::Input::CONDITION) << ")"
374                << " Input_X(" << node.getInputs().at(Select::Input::INPUT_TRUE) << ")"
375                << " Input_Y(" << node.getInputs().at(Select::Input::INPUT_FALSE) << ")"
376                << std::endl;
377   VERBOSE(LIR) << "  - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
378 }
379
380 void OperationDumper::visit(const ir::operation::Shape &node) { dumpUnaryInputOp(node); }
381
382 void OperationDumper::visit(const Softmax &node) { dumpUnaryInputOp(node); }
383
384 void OperationDumper::visit(const SpaceToBatchND &node)
385 {
386   std::string inputs =
387       "BlockSize(" +
388       std::to_string(node.getInputs().at(SpaceToBatchND::Input::BLOCK_SIZE).value()) +
389       ") Paddings(" + std::to_string(node.getInputs().at(SpaceToBatchND::Input::PADDINGS).value()) +
390       ")";
391   dumpUnaryInputOp(node, inputs);
392 }
393
394 void OperationDumper::visit(const SpaceToDepth &node) { dumpUnaryInputOp(node); }
395
396 void OperationDumper::visit(const Split &node) { dumpBinaryInputOp(node); }
397
398 void OperationDumper::visit(const SquaredDifference &node) { dumpBinaryInputOp(node); }
399
400 void OperationDumper::visit(const StatelessRandomUniform &node)
401 {
402   VERBOSE(LIR) << "* StatelessRandomUniform" << std::endl;
403   VERBOSE(LIR) << "  - Inputs : Shape(" << node.getInputs().at(StatelessRandomUniform::Input::SHAPE)
404                << " Seed(" << node.getInputs().at(StatelessRandomUniform::Input::SEED) << ")"
405                << std::endl;
406   VERBOSE(LIR) << "  - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
407 }
408
409 void OperationDumper::visit(const Squeeze &node) { dumpUnaryInputOp(node); }
410
411 void OperationDumper::visit(const Slice &node) { dumpUnaryInputOp(node); }
412
413 void OperationDumper::visit(const StridedSlice &node) { dumpUnaryInputOp(node); }
414
415 void OperationDumper::visit(const Tile &node)
416 {
417   std::string multiples =
418       "Multiples(" + std::to_string(node.getInputs().at(Tile::Input::MULTIPLES).value()) + ")";
419   dumpUnaryInputOp(node, multiples);
420 }
421
422 void OperationDumper::visit(const TopKV2 &node)
423 {
424   VERBOSE(LIR) << "* TopKV2" << std::endl;
425   VERBOSE(LIR) << "  - Inputs : Input(" << node.getInputs().at(TopKV2::Input::INPUT) << ")"
426                << std::endl;
427   VERBOSE(LIR) << "  - Outputs : Values(" << node.getOutputs().at(TopKV2::Output::OUTPUT_VALUES)
428                << ") Indices(" << node.getOutputs().at(TopKV2::Output::OUTPUT_INDICES) << ")"
429                << std::endl;
430 }
431
432 void OperationDumper::visit(const TransposeConv &node)
433 {
434   std::string padding_type =
435       node.param().padding.type == PaddingType::EXPLICIT ? "Explicit" : "Implicit";
436   VERBOSE(LIR) << "* TransposeConv(" << padding_type << ")" << std::endl;
437   VERBOSE(LIR) << "  - Inputs : Output Shape("
438                << node.getInputs().at(TransposeConv::Input::OUTPUT_SHAPE) << ") KERNEL("
439                << node.getInputs().at(TransposeConv::Input::KERNEL) << ") IFM("
440                << node.getInputs().at(TransposeConv::Input::INPUT) << ")" << std::endl;
441   VERBOSE(LIR) << "  - Output : OFM(" << node.getOutputs().at(0) << ")" << std::endl;
442 }
443
444 void OperationDumper::visit(const Transpose &node) { dumpBinaryInputOp(node); }
445
446 void OperationDumper::visit(const Unpack &node)
447 {
448   VERBOSE(LIR) << "* " << node.name() << std::endl;
449   VERBOSE(LIR) << "  - Inputs : Input(" << node.getInputs().at(Unpack::Input::INPUT) << ")"
450                << std::endl;
451   std::string outputs;
452   const auto &output_indices = node.getOutputs();
453   for (auto it = std::begin(output_indices); it != std::end(output_indices); ++it)
454   {
455     outputs += std::to_string(it->value());
456     if (std::next(it) != std::end(output_indices))
457       outputs += ", ";
458   }
459   VERBOSE(LIR) << "  - Outputs : Outputs(" << outputs << ")" << std::endl;
460 }
461
462 void OperationDumper::visit(const OneHot &node)
463 {
464   VERBOSE(LIR) << "* " << node.name() << std::endl;
465   VERBOSE(LIR) << "  - Inputs : "
466                << "Indices(" << node.getInputs().at(OneHot::Input::INDICES) << ") " << std::endl;
467   VERBOSE(LIR) << "  - Output : Output(" << node.getOutputs().at(0) << ")" << std::endl;
468 }
469
470 void OperationDumper::visit(const If &node)
471 {
472   VERBOSE(LIR) << "* " << node.name() << std::endl;
473   std::string inputs;
474   const auto &input_indices = node.getInputs();
475   for (auto it = std::begin(input_indices); it != std::end(input_indices); ++it)
476   {
477     inputs += std::to_string(it->value());
478     if (std::next(it) != std::end(input_indices))
479       inputs += ", ";
480   }
481   VERBOSE(LIR) << "  - Inputs : "
482                << "Then subgraph (" << node.param().then_subg_index << ") Else subgraph ("
483                << node.param().else_subg_index << ") Inputs(" << inputs << ")" << std::endl;
484   std::string outputs;
485   const auto &output_indices = node.getOutputs();
486   for (auto it = std::begin(output_indices); it != std::end(output_indices); ++it)
487   {
488     outputs += std::to_string(it->value());
489     if (std::next(it) != std::end(output_indices))
490       outputs += ", ";
491   }
492   VERBOSE(LIR) << "  - Output : Outputs(" << outputs << ")" << std::endl;
493 }
494
495 void OperationDumper::visit(const While &node)
496 {
497   VERBOSE(LIR) << "* " << node.name() << std::endl;
498   std::string inputs;
499   const auto &input_indices = node.getInputs();
500   for (auto it = std::begin(input_indices); it != std::end(input_indices); ++it)
501   {
502     inputs += std::to_string(it->value());
503     if (std::next(it) != std::end(input_indices))
504       inputs += ", ";
505   }
506   VERBOSE(LIR) << "  - Inputs : "
507                << "Cond subgraph (" << node.param().cond_subg_index << ") Body subgraph ("
508                << node.param().cond_subg_index << ") Inputs(" << inputs << ")" << std::endl;
509   std::string outputs;
510   const auto &output_indices = node.getOutputs();
511   for (auto it = std::begin(output_indices); it != std::end(output_indices); ++it)
512   {
513     outputs += std::to_string(it->value());
514     if (std::next(it) != std::end(output_indices))
515       outputs += ", ";
516   }
517   VERBOSE(LIR) << "  - Output : Outputs(" << outputs << ")" << std::endl;
518 }
519
520 } // namespace ir
521 } // namespace onert