1 | /* Tree-dumping functionality for intermediate representation. |
2 | Copyright (C) 1999-2023 Free Software Foundation, Inc. |
3 | Written by Mark Mitchell <mark@codesourcery.com> |
4 | |
5 | This file is part of GCC. |
6 | |
7 | GCC is free software; you can redistribute it and/or modify it under |
8 | the terms of the GNU General Public License as published by the Free |
9 | Software Foundation; either version 3, or (at your option) any later |
10 | version. |
11 | |
12 | GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
13 | WARRANTY; without even the implied warranty of MERCHANTABILITY or |
14 | FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
15 | for more details. |
16 | |
17 | You should have received a copy of the GNU General Public License |
18 | along with GCC; see the file COPYING3. If not see |
19 | <http://www.gnu.org/licenses/>. */ |
20 | |
21 | #include "config.h" |
22 | #include "system.h" |
23 | #include "coretypes.h" |
24 | #include "tree.h" |
25 | #include "tree-pretty-print.h" |
26 | #include "tree-dump.h" |
27 | #include "langhooks.h" |
28 | #include "tree-iterator.h" |
29 | |
30 | static unsigned int queue (dump_info_p, const_tree, int); |
31 | static void dump_index (dump_info_p, unsigned int); |
32 | static void dequeue_and_dump (dump_info_p); |
33 | static void dump_new_line (dump_info_p); |
34 | static void dump_maybe_newline (dump_info_p); |
35 | |
36 | /* Add T to the end of the queue of nodes to dump. Returns the index |
37 | assigned to T. */ |
38 | |
39 | static unsigned int |
40 | queue (dump_info_p di, const_tree t, int flags) |
41 | { |
42 | dump_queue_p dq; |
43 | dump_node_info_p dni; |
44 | unsigned int index; |
45 | |
46 | /* Assign the next available index to T. */ |
47 | index = ++di->index; |
48 | |
49 | /* Obtain a new queue node. */ |
50 | if (di->free_list) |
51 | { |
52 | dq = di->free_list; |
53 | di->free_list = dq->next; |
54 | } |
55 | else |
56 | dq = XNEW (struct dump_queue); |
57 | |
58 | /* Create a new entry in the splay-tree. */ |
59 | dni = XNEW (struct dump_node_info); |
60 | dni->index = index; |
61 | dni->binfo_p = ((flags & DUMP_BINFO) != 0); |
62 | dq->node = splay_tree_insert (di->nodes, (splay_tree_key) t, |
63 | (splay_tree_value) dni); |
64 | |
65 | /* Add it to the end of the queue. */ |
66 | dq->next = 0; |
67 | if (!di->queue_end) |
68 | di->queue = dq; |
69 | else |
70 | di->queue_end->next = dq; |
71 | di->queue_end = dq; |
72 | |
73 | /* Return the index. */ |
74 | return index; |
75 | } |
76 | |
77 | static void |
78 | dump_index (dump_info_p di, unsigned int index) |
79 | { |
80 | fprintf (stream: di->stream, format: "@%-6u " , index); |
81 | di->column += 8; |
82 | } |
83 | |
84 | /* If T has not already been output, queue it for subsequent output. |
85 | FIELD is a string to print before printing the index. Then, the |
86 | index of T is printed. */ |
87 | |
88 | void |
89 | queue_and_dump_index (dump_info_p di, const char *field, const_tree t, int flags) |
90 | { |
91 | unsigned int index; |
92 | splay_tree_node n; |
93 | |
94 | /* If there's no node, just return. This makes for fewer checks in |
95 | our callers. */ |
96 | if (!t) |
97 | return; |
98 | |
99 | /* See if we've already queued or dumped this node. */ |
100 | n = splay_tree_lookup (di->nodes, (splay_tree_key) t); |
101 | if (n) |
102 | index = ((dump_node_info_p) n->value)->index; |
103 | else |
104 | /* If we haven't, add it to the queue. */ |
105 | index = queue (di, t, flags); |
106 | |
107 | /* Print the index of the node. */ |
108 | dump_maybe_newline (di); |
109 | fprintf (stream: di->stream, format: "%-4s: " , field); |
110 | di->column += 6; |
111 | dump_index (di, index); |
112 | } |
113 | |
114 | /* Dump the type of T. */ |
115 | |
116 | void |
117 | queue_and_dump_type (dump_info_p di, const_tree t) |
118 | { |
119 | queue_and_dump_index (di, field: "type" , TREE_TYPE (t), DUMP_NONE); |
120 | } |
121 | |
122 | /* Dump column control */ |
123 | #define SOL_COLUMN 25 /* Start of line column. */ |
124 | #define EOL_COLUMN 55 /* End of line column. */ |
125 | #define COLUMN_ALIGNMENT 15 /* Alignment. */ |
126 | |
127 | /* Insert a new line in the dump output, and indent to an appropriate |
128 | place to start printing more fields. */ |
129 | |
130 | static void |
131 | dump_new_line (dump_info_p di) |
132 | { |
133 | fprintf (stream: di->stream, format: "\n%*s" , SOL_COLUMN, "" ); |
134 | di->column = SOL_COLUMN; |
135 | } |
136 | |
137 | /* If necessary, insert a new line. */ |
138 | |
139 | static void |
140 | dump_maybe_newline (dump_info_p di) |
141 | { |
142 | int ; |
143 | |
144 | /* See if we need a new line. */ |
145 | if (di->column > EOL_COLUMN) |
146 | dump_new_line (di); |
147 | /* See if we need any padding. */ |
148 | else if ((extra = (di->column - SOL_COLUMN) % COLUMN_ALIGNMENT) != 0) |
149 | { |
150 | fprintf (stream: di->stream, format: "%*s" , COLUMN_ALIGNMENT - extra, "" ); |
151 | di->column += COLUMN_ALIGNMENT - extra; |
152 | } |
153 | } |
154 | |
155 | /* Dump pointer PTR using FIELD to identify it. */ |
156 | |
157 | void |
158 | dump_pointer (dump_info_p di, const char *field, void *ptr) |
159 | { |
160 | dump_maybe_newline (di); |
161 | fprintf (stream: di->stream, format: "%-4s: %-8" HOST_WIDE_INT_PRINT "x " , field, |
162 | (unsigned HOST_WIDE_INT) (uintptr_t) ptr); |
163 | di->column += 15; |
164 | } |
165 | |
166 | /* Dump integer I using FIELD to identify it. */ |
167 | |
168 | void |
169 | dump_int (dump_info_p di, const char *field, int i) |
170 | { |
171 | dump_maybe_newline (di); |
172 | fprintf (stream: di->stream, format: "%-4s: %-7d " , field, i); |
173 | di->column += 14; |
174 | } |
175 | |
176 | /* Dump the floating point value R, using FIELD to identify it. */ |
177 | |
178 | static void |
179 | dump_real (dump_info_p di, const char *field, const REAL_VALUE_TYPE *r) |
180 | { |
181 | char buf[32]; |
182 | real_to_decimal (buf, r, sizeof (buf), 0, true); |
183 | dump_maybe_newline (di); |
184 | fprintf (stream: di->stream, format: "%-4s: %s " , field, buf); |
185 | di->column += strlen (s: buf) + 7; |
186 | } |
187 | |
188 | /* Dump the fixed-point value F, using FIELD to identify it. */ |
189 | |
190 | static void |
191 | dump_fixed (dump_info_p di, const char *field, const FIXED_VALUE_TYPE *f) |
192 | { |
193 | char buf[32]; |
194 | fixed_to_decimal (str: buf, f, sizeof (buf)); |
195 | dump_maybe_newline (di); |
196 | fprintf (stream: di->stream, format: "%-4s: %s " , field, buf); |
197 | di->column += strlen (s: buf) + 7; |
198 | } |
199 | |
200 | |
201 | /* Dump the string S. */ |
202 | |
203 | void |
204 | dump_string (dump_info_p di, const char *string) |
205 | { |
206 | dump_maybe_newline (di); |
207 | fprintf (stream: di->stream, format: "%-13s " , string); |
208 | if (strlen (s: string) > 13) |
209 | di->column += strlen (s: string) + 1; |
210 | else |
211 | di->column += 14; |
212 | } |
213 | |
214 | /* Dump the string field S. */ |
215 | |
216 | void |
217 | dump_string_field (dump_info_p di, const char *field, const char *string) |
218 | { |
219 | dump_maybe_newline (di); |
220 | fprintf (stream: di->stream, format: "%-4s: %-7s " , field, string); |
221 | if (strlen (s: string) > 7) |
222 | di->column += 6 + strlen (s: string) + 1; |
223 | else |
224 | di->column += 14; |
225 | } |
226 | |
227 | /* Dump the next node in the queue. */ |
228 | |
229 | static void |
230 | dequeue_and_dump (dump_info_p di) |
231 | { |
232 | dump_queue_p dq; |
233 | splay_tree_node stn; |
234 | dump_node_info_p dni; |
235 | tree t; |
236 | unsigned int index; |
237 | enum tree_code code; |
238 | enum tree_code_class code_class; |
239 | const char* code_name; |
240 | |
241 | /* Get the next node from the queue. */ |
242 | dq = di->queue; |
243 | stn = dq->node; |
244 | t = (tree) stn->key; |
245 | dni = (dump_node_info_p) stn->value; |
246 | index = dni->index; |
247 | |
248 | /* Remove the node from the queue, and put it on the free list. */ |
249 | di->queue = dq->next; |
250 | if (!di->queue) |
251 | di->queue_end = 0; |
252 | dq->next = di->free_list; |
253 | di->free_list = dq; |
254 | |
255 | /* Print the node index. */ |
256 | dump_index (di, index); |
257 | /* And the type of node this is. */ |
258 | if (dni->binfo_p) |
259 | code_name = "binfo" ; |
260 | else |
261 | code_name = get_tree_code_name (TREE_CODE (t)); |
262 | fprintf (stream: di->stream, format: "%-16s " , code_name); |
263 | di->column = 25; |
264 | |
265 | /* Figure out what kind of node this is. */ |
266 | code = TREE_CODE (t); |
267 | code_class = TREE_CODE_CLASS (code); |
268 | |
269 | /* Although BINFOs are TREE_VECs, we dump them specially so as to be |
270 | more informative. */ |
271 | if (dni->binfo_p) |
272 | { |
273 | unsigned ix; |
274 | tree base; |
275 | vec<tree, va_gc> *accesses = BINFO_BASE_ACCESSES (t); |
276 | |
277 | dump_child ("type" , BINFO_TYPE (t)); |
278 | |
279 | if (BINFO_VIRTUAL_P (t)) |
280 | dump_string_field (di, field: "spec" , string: "virt" ); |
281 | |
282 | dump_int (di, field: "bases" , BINFO_N_BASE_BINFOS (t)); |
283 | for (ix = 0; BINFO_BASE_ITERATE (t, ix, base); ix++) |
284 | { |
285 | tree access = (accesses ? (*accesses)[ix] : access_public_node); |
286 | const char *string = NULL; |
287 | |
288 | if (access == access_public_node) |
289 | string = "pub" ; |
290 | else if (access == access_protected_node) |
291 | string = "prot" ; |
292 | else if (access == access_private_node) |
293 | string = "priv" ; |
294 | else |
295 | gcc_unreachable (); |
296 | |
297 | dump_string_field (di, field: "accs" , string); |
298 | queue_and_dump_index (di, field: "binf" , t: base, DUMP_BINFO); |
299 | } |
300 | |
301 | goto done; |
302 | } |
303 | |
304 | /* We can knock off a bunch of expression nodes in exactly the same |
305 | way. */ |
306 | if (IS_EXPR_CODE_CLASS (code_class)) |
307 | { |
308 | /* If we're dumping children, dump them now. */ |
309 | queue_and_dump_type (di, t); |
310 | |
311 | switch (code_class) |
312 | { |
313 | case tcc_unary: |
314 | dump_child ("op 0" , TREE_OPERAND (t, 0)); |
315 | break; |
316 | |
317 | case tcc_binary: |
318 | case tcc_comparison: |
319 | dump_child ("op 0" , TREE_OPERAND (t, 0)); |
320 | dump_child ("op 1" , TREE_OPERAND (t, 1)); |
321 | break; |
322 | |
323 | case tcc_expression: |
324 | case tcc_reference: |
325 | case tcc_statement: |
326 | case tcc_vl_exp: |
327 | /* These nodes are handled explicitly below. */ |
328 | break; |
329 | |
330 | default: |
331 | gcc_unreachable (); |
332 | } |
333 | } |
334 | else if (DECL_P (t)) |
335 | { |
336 | expanded_location xloc; |
337 | /* All declarations have names. */ |
338 | if (DECL_NAME (t)) |
339 | dump_child ("name" , DECL_NAME (t)); |
340 | if (HAS_DECL_ASSEMBLER_NAME_P (t) |
341 | && DECL_ASSEMBLER_NAME_SET_P (t) |
342 | && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t)) |
343 | dump_child ("mngl" , DECL_ASSEMBLER_NAME (t)); |
344 | if (DECL_ABSTRACT_ORIGIN (t)) |
345 | dump_child ("orig" , DECL_ABSTRACT_ORIGIN (t)); |
346 | /* And types. */ |
347 | queue_and_dump_type (di, t); |
348 | dump_child ("scpe" , DECL_CONTEXT (t)); |
349 | /* And a source position. */ |
350 | xloc = expand_location (DECL_SOURCE_LOCATION (t)); |
351 | if (xloc.file) |
352 | { |
353 | const char *filename = lbasename (xloc.file); |
354 | |
355 | dump_maybe_newline (di); |
356 | fprintf (stream: di->stream, format: "srcp: %s:%-6d " , filename, |
357 | xloc.line); |
358 | di->column += 6 + strlen (s: filename) + 8; |
359 | } |
360 | /* And any declaration can be compiler-generated. */ |
361 | if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_COMMON) |
362 | && DECL_ARTIFICIAL (t)) |
363 | dump_string_field (di, field: "note" , string: "artificial" ); |
364 | if (DECL_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL)) |
365 | dump_child ("chain" , DECL_CHAIN (t)); |
366 | } |
367 | else if (code_class == tcc_type) |
368 | { |
369 | /* All types have qualifiers. */ |
370 | int quals = lang_hooks.tree_dump.type_quals (t); |
371 | |
372 | if (quals != TYPE_UNQUALIFIED) |
373 | { |
374 | fprintf (stream: di->stream, format: "qual: %c%c%c " , |
375 | (quals & TYPE_QUAL_CONST) ? 'c' : ' ', |
376 | (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ', |
377 | (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' '); |
378 | di->column += 14; |
379 | } |
380 | |
381 | /* All types have associated declarations. */ |
382 | dump_child ("name" , TYPE_NAME (t)); |
383 | |
384 | /* All types have a main variant. */ |
385 | if (TYPE_MAIN_VARIANT (t) != t) |
386 | dump_child ("unql" , TYPE_MAIN_VARIANT (t)); |
387 | |
388 | /* And sizes. */ |
389 | dump_child ("size" , TYPE_SIZE (t)); |
390 | |
391 | /* All types have alignments. */ |
392 | dump_int (di, field: "algn" , TYPE_ALIGN (t)); |
393 | } |
394 | else if (code_class == tcc_constant) |
395 | /* All constants can have types. */ |
396 | queue_and_dump_type (di, t); |
397 | |
398 | /* Give the language-specific code a chance to print something. If |
399 | it's completely taken care of things, don't bother printing |
400 | anything more ourselves. */ |
401 | if (lang_hooks.tree_dump.dump_tree (di, t)) |
402 | goto done; |
403 | |
404 | /* Now handle the various kinds of nodes. */ |
405 | switch (code) |
406 | { |
407 | int i; |
408 | |
409 | case IDENTIFIER_NODE: |
410 | dump_string_field (di, field: "strg" , IDENTIFIER_POINTER (t)); |
411 | dump_int (di, field: "lngt" , IDENTIFIER_LENGTH (t)); |
412 | break; |
413 | |
414 | case TREE_LIST: |
415 | dump_child ("purp" , TREE_PURPOSE (t)); |
416 | dump_child ("valu" , TREE_VALUE (t)); |
417 | dump_child ("chan" , TREE_CHAIN (t)); |
418 | break; |
419 | |
420 | case STATEMENT_LIST: |
421 | { |
422 | tree_stmt_iterator it; |
423 | for (i = 0, it = tsi_start (t); !tsi_end_p (i: it); tsi_next (i: &it), i++) |
424 | { |
425 | char buffer[32]; |
426 | sprintf (s: buffer, format: "%u" , i); |
427 | dump_child (buffer, tsi_stmt (it)); |
428 | } |
429 | } |
430 | break; |
431 | |
432 | case TREE_VEC: |
433 | dump_int (di, field: "lngt" , TREE_VEC_LENGTH (t)); |
434 | for (i = 0; i < TREE_VEC_LENGTH (t); ++i) |
435 | { |
436 | char buffer[32]; |
437 | sprintf (s: buffer, format: "%u" , i); |
438 | dump_child (buffer, TREE_VEC_ELT (t, i)); |
439 | } |
440 | break; |
441 | |
442 | case INTEGER_TYPE: |
443 | case ENUMERAL_TYPE: |
444 | dump_int (di, field: "prec" , TYPE_PRECISION (t)); |
445 | dump_string_field (di, field: "sign" , TYPE_UNSIGNED (t) ? "unsigned" : "signed" ); |
446 | dump_child ("min" , TYPE_MIN_VALUE (t)); |
447 | dump_child ("max" , TYPE_MAX_VALUE (t)); |
448 | |
449 | if (code == ENUMERAL_TYPE) |
450 | dump_child ("csts" , TYPE_VALUES (t)); |
451 | break; |
452 | |
453 | case REAL_TYPE: |
454 | dump_int (di, field: "prec" , TYPE_PRECISION (t)); |
455 | break; |
456 | |
457 | case FIXED_POINT_TYPE: |
458 | dump_int (di, field: "prec" , TYPE_PRECISION (t)); |
459 | dump_string_field (di, field: "sign" , TYPE_UNSIGNED (t) ? "unsigned" : "signed" ); |
460 | dump_string_field (di, field: "saturating" , |
461 | TYPE_SATURATING (t) ? "saturating" : "non-saturating" ); |
462 | break; |
463 | |
464 | case POINTER_TYPE: |
465 | dump_child ("ptd" , TREE_TYPE (t)); |
466 | break; |
467 | |
468 | case REFERENCE_TYPE: |
469 | dump_child ("refd" , TREE_TYPE (t)); |
470 | break; |
471 | |
472 | case METHOD_TYPE: |
473 | dump_child ("clas" , TYPE_METHOD_BASETYPE (t)); |
474 | /* Fall through. */ |
475 | |
476 | case FUNCTION_TYPE: |
477 | dump_child ("retn" , TREE_TYPE (t)); |
478 | dump_child ("prms" , TYPE_ARG_TYPES (t)); |
479 | break; |
480 | |
481 | case ARRAY_TYPE: |
482 | dump_child ("elts" , TREE_TYPE (t)); |
483 | dump_child ("domn" , TYPE_DOMAIN (t)); |
484 | break; |
485 | |
486 | case RECORD_TYPE: |
487 | case UNION_TYPE: |
488 | if (TREE_CODE (t) == RECORD_TYPE) |
489 | dump_string_field (di, field: "tag" , string: "struct" ); |
490 | else |
491 | dump_string_field (di, field: "tag" , string: "union" ); |
492 | |
493 | dump_child ("flds" , TYPE_FIELDS (t)); |
494 | queue_and_dump_index (di, field: "binf" , TYPE_BINFO (t), |
495 | DUMP_BINFO); |
496 | break; |
497 | |
498 | case CONST_DECL: |
499 | dump_child ("cnst" , DECL_INITIAL (t)); |
500 | break; |
501 | |
502 | case DEBUG_EXPR_DECL: |
503 | dump_int (di, field: "-uid" , DEBUG_TEMP_UID (t)); |
504 | /* Fall through. */ |
505 | |
506 | case VAR_DECL: |
507 | case PARM_DECL: |
508 | case FIELD_DECL: |
509 | case RESULT_DECL: |
510 | if (TREE_CODE (t) == PARM_DECL) |
511 | dump_child ("argt" , DECL_ARG_TYPE (t)); |
512 | else |
513 | dump_child ("init" , DECL_INITIAL (t)); |
514 | dump_child ("size" , DECL_SIZE (t)); |
515 | dump_int (di, field: "algn" , DECL_ALIGN (t)); |
516 | |
517 | if (TREE_CODE (t) == FIELD_DECL) |
518 | { |
519 | if (DECL_FIELD_OFFSET (t)) |
520 | dump_child ("bpos" , bit_position (t)); |
521 | } |
522 | else if (VAR_P (t) || TREE_CODE (t) == PARM_DECL) |
523 | { |
524 | dump_int (di, field: "used" , TREE_USED (t)); |
525 | if (DECL_REGISTER (t)) |
526 | dump_string_field (di, field: "spec" , string: "register" ); |
527 | } |
528 | break; |
529 | |
530 | case FUNCTION_DECL: |
531 | dump_child ("args" , DECL_ARGUMENTS (t)); |
532 | if (DECL_EXTERNAL (t)) |
533 | dump_string_field (di, field: "body" , string: "undefined" ); |
534 | if (TREE_PUBLIC (t)) |
535 | dump_string_field (di, field: "link" , string: "extern" ); |
536 | else |
537 | dump_string_field (di, field: "link" , string: "static" ); |
538 | if (DECL_SAVED_TREE (t) && !dump_flag (di, TDF_SLIM, t)) |
539 | dump_child ("body" , DECL_SAVED_TREE (t)); |
540 | break; |
541 | |
542 | case INTEGER_CST: |
543 | fprintf (stream: di->stream, format: "int: " ); |
544 | print_decs (wi: wi::to_wide (t), file: di->stream); |
545 | break; |
546 | |
547 | case STRING_CST: |
548 | fprintf (stream: di->stream, format: "strg: %-7s " , TREE_STRING_POINTER (t)); |
549 | dump_int (di, field: "lngt" , TREE_STRING_LENGTH (t)); |
550 | break; |
551 | |
552 | case REAL_CST: |
553 | dump_real (di, field: "valu" , TREE_REAL_CST_PTR (t)); |
554 | break; |
555 | |
556 | case FIXED_CST: |
557 | dump_fixed (di, field: "valu" , TREE_FIXED_CST_PTR (t)); |
558 | break; |
559 | |
560 | case TRUTH_NOT_EXPR: |
561 | case ADDR_EXPR: |
562 | case INDIRECT_REF: |
563 | case CLEANUP_POINT_EXPR: |
564 | case VIEW_CONVERT_EXPR: |
565 | case SAVE_EXPR: |
566 | case REALPART_EXPR: |
567 | case IMAGPART_EXPR: |
568 | /* These nodes are unary, but do not have code class `1'. */ |
569 | dump_child ("op 0" , TREE_OPERAND (t, 0)); |
570 | break; |
571 | |
572 | case TRUTH_ANDIF_EXPR: |
573 | case TRUTH_ORIF_EXPR: |
574 | case INIT_EXPR: |
575 | case MODIFY_EXPR: |
576 | case COMPOUND_EXPR: |
577 | case PREDECREMENT_EXPR: |
578 | case PREINCREMENT_EXPR: |
579 | case POSTDECREMENT_EXPR: |
580 | case POSTINCREMENT_EXPR: |
581 | /* These nodes are binary, but do not have code class `2'. */ |
582 | dump_child ("op 0" , TREE_OPERAND (t, 0)); |
583 | dump_child ("op 1" , TREE_OPERAND (t, 1)); |
584 | break; |
585 | |
586 | case COMPONENT_REF: |
587 | case BIT_FIELD_REF: |
588 | dump_child ("op 0" , TREE_OPERAND (t, 0)); |
589 | dump_child ("op 1" , TREE_OPERAND (t, 1)); |
590 | dump_child ("op 2" , TREE_OPERAND (t, 2)); |
591 | break; |
592 | |
593 | case ARRAY_REF: |
594 | case ARRAY_RANGE_REF: |
595 | dump_child ("op 0" , TREE_OPERAND (t, 0)); |
596 | dump_child ("op 1" , TREE_OPERAND (t, 1)); |
597 | dump_child ("op 2" , TREE_OPERAND (t, 2)); |
598 | dump_child ("op 3" , TREE_OPERAND (t, 3)); |
599 | break; |
600 | |
601 | case COND_EXPR: |
602 | dump_child ("op 0" , TREE_OPERAND (t, 0)); |
603 | dump_child ("op 1" , TREE_OPERAND (t, 1)); |
604 | dump_child ("op 2" , TREE_OPERAND (t, 2)); |
605 | break; |
606 | |
607 | case TRY_FINALLY_EXPR: |
608 | case EH_ELSE_EXPR: |
609 | dump_child ("op 0" , TREE_OPERAND (t, 0)); |
610 | dump_child ("op 1" , TREE_OPERAND (t, 1)); |
611 | break; |
612 | |
613 | case CALL_EXPR: |
614 | { |
615 | int i = 0; |
616 | tree arg; |
617 | call_expr_arg_iterator iter; |
618 | dump_child ("fn" , CALL_EXPR_FN (t)); |
619 | FOR_EACH_CALL_EXPR_ARG (arg, iter, t) |
620 | { |
621 | char buffer[32]; |
622 | sprintf (s: buffer, format: "%u" , i); |
623 | dump_child (buffer, arg); |
624 | i++; |
625 | } |
626 | } |
627 | break; |
628 | |
629 | case CONSTRUCTOR: |
630 | { |
631 | unsigned HOST_WIDE_INT cnt; |
632 | tree index, value; |
633 | dump_int (di, field: "lngt" , CONSTRUCTOR_NELTS (t)); |
634 | FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), cnt, index, value) |
635 | { |
636 | dump_child ("idx" , index); |
637 | dump_child ("val" , value); |
638 | } |
639 | } |
640 | break; |
641 | |
642 | case BIND_EXPR: |
643 | dump_child ("vars" , TREE_OPERAND (t, 0)); |
644 | dump_child ("body" , TREE_OPERAND (t, 1)); |
645 | break; |
646 | |
647 | case LOOP_EXPR: |
648 | dump_child ("body" , TREE_OPERAND (t, 0)); |
649 | break; |
650 | |
651 | case EXIT_EXPR: |
652 | dump_child ("cond" , TREE_OPERAND (t, 0)); |
653 | break; |
654 | |
655 | case RETURN_EXPR: |
656 | dump_child ("expr" , TREE_OPERAND (t, 0)); |
657 | break; |
658 | |
659 | case TARGET_EXPR: |
660 | dump_child ("decl" , TREE_OPERAND (t, 0)); |
661 | dump_child ("init" , TREE_OPERAND (t, 1)); |
662 | dump_child ("clnp" , TREE_OPERAND (t, 2)); |
663 | /* There really are two possible places the initializer can be. |
664 | After RTL expansion, the second operand is moved to the |
665 | position of the fourth operand, and the second operand |
666 | becomes NULL. */ |
667 | dump_child ("init" , TREE_OPERAND (t, 3)); |
668 | break; |
669 | |
670 | case CASE_LABEL_EXPR: |
671 | dump_child ("name" , CASE_LABEL (t)); |
672 | if (CASE_LOW (t)) |
673 | { |
674 | dump_child ("low " , CASE_LOW (t)); |
675 | if (CASE_HIGH (t)) |
676 | dump_child ("high" , CASE_HIGH (t)); |
677 | } |
678 | break; |
679 | case LABEL_EXPR: |
680 | dump_child ("name" , TREE_OPERAND (t,0)); |
681 | break; |
682 | case GOTO_EXPR: |
683 | dump_child ("labl" , TREE_OPERAND (t, 0)); |
684 | break; |
685 | case SWITCH_EXPR: |
686 | dump_child ("cond" , TREE_OPERAND (t, 0)); |
687 | dump_child ("body" , TREE_OPERAND (t, 1)); |
688 | break; |
689 | case OMP_CLAUSE: |
690 | { |
691 | int i; |
692 | fprintf (stream: di->stream, format: "%s\n" , omp_clause_code_name[OMP_CLAUSE_CODE (t)]); |
693 | for (i = 0; i < omp_clause_num_ops[OMP_CLAUSE_CODE (t)]; i++) |
694 | dump_child ("op: " , OMP_CLAUSE_OPERAND (t, i)); |
695 | } |
696 | break; |
697 | default: |
698 | /* There are no additional fields to print. */ |
699 | break; |
700 | } |
701 | |
702 | done: |
703 | if (dump_flag (di, TDF_ADDRESS, NULL)) |
704 | dump_pointer (di, field: "addr" , ptr: (void *)t); |
705 | |
706 | /* Terminate the line. */ |
707 | fprintf (stream: di->stream, format: "\n" ); |
708 | } |
709 | |
710 | /* Return nonzero if FLAG has been specified for the dump, and NODE |
711 | is not the root node of the dump. */ |
712 | |
713 | int dump_flag (dump_info_p di, dump_flags_t flag, const_tree node) |
714 | { |
715 | return (di->flags & flag) && (node != di->node); |
716 | } |
717 | |
718 | /* Dump T, and all its children, on STREAM. */ |
719 | |
720 | void |
721 | dump_node (const_tree t, dump_flags_t flags, FILE *stream) |
722 | { |
723 | struct dump_info di; |
724 | dump_queue_p dq; |
725 | dump_queue_p next_dq; |
726 | |
727 | /* Initialize the dump-information structure. */ |
728 | di.stream = stream; |
729 | di.index = 0; |
730 | di.column = 0; |
731 | di.queue = 0; |
732 | di.queue_end = 0; |
733 | di.free_list = 0; |
734 | di.flags = flags; |
735 | di.node = t; |
736 | di.nodes = splay_tree_new (splay_tree_compare_pointers, 0, |
737 | splay_tree_delete_pointers); |
738 | |
739 | /* Queue up the first node. */ |
740 | queue (di: &di, t, DUMP_NONE); |
741 | |
742 | /* Until the queue is empty, keep dumping nodes. */ |
743 | while (di.queue) |
744 | dequeue_and_dump (di: &di); |
745 | |
746 | /* Now, clean up. */ |
747 | for (dq = di.free_list; dq; dq = next_dq) |
748 | { |
749 | next_dq = dq->next; |
750 | free (ptr: dq); |
751 | } |
752 | splay_tree_delete (di.nodes); |
753 | } |
754 | |