1 /* Tree-dumping functionality for intermediate representation.
2 Copyright (C) 1999, 2000, 2002 Free Software Foundation, Inc.
3 Written by Mark Mitchell <mark@codesourcery.com>
5 This file is part of GCC.
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 2, or (at your option) any later
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
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING. If not, write to the Free
19 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
25 #include "splay-tree.h"
26 #include "diagnostic.h"
28 #include "tree-dump.h"
29 #include "langhooks.h"
31 static unsigned int queue
PARAMS ((dump_info_p
, tree
, int));
32 static void dump_index
PARAMS ((dump_info_p
, unsigned int));
33 static void dequeue_and_dump
PARAMS ((dump_info_p
));
34 static void dump_new_line
PARAMS ((dump_info_p
));
35 static void dump_maybe_newline
PARAMS ((dump_info_p
));
36 static void dump_string_field
PARAMS ((dump_info_p
, const char *, const char *));
38 /* Add T to the end of the queue of nodes to dump. Returns the index
51 /* Assign the next available index to T. */
54 /* Obtain a new queue node. */
58 di
->free_list
= dq
->next
;
61 dq
= (dump_queue_p
) xmalloc (sizeof (struct dump_queue
));
63 /* Create a new entry in the splay-tree. */
64 dni
= (dump_node_info_p
) xmalloc (sizeof (struct dump_node_info
));
66 dni
->binfo_p
= ((flags
& DUMP_BINFO
) != 0);
67 dq
->node
= splay_tree_insert (di
->nodes
, (splay_tree_key
) t
,
68 (splay_tree_value
) dni
);
70 /* Add it to the end of the queue. */
75 di
->queue_end
->next
= dq
;
78 /* Return the index. */
83 dump_index (di
, index
)
87 fprintf (di
->stream
, "@%-6u ", index
);
91 /* If T has not already been output, queue it for subsequent output.
92 FIELD is a string to print before printing the index. Then, the
93 index of T is printed. */
96 queue_and_dump_index (di
, field
, t
, flags
)
105 /* If there's no node, just return. This makes for fewer checks in
110 /* See if we've already queued or dumped this node. */
111 n
= splay_tree_lookup (di
->nodes
, (splay_tree_key
) t
);
113 index
= ((dump_node_info_p
) n
->value
)->index
;
115 /* If we haven't, add it to the queue. */
116 index
= queue (di
, t
, flags
);
118 /* Print the index of the node. */
119 dump_maybe_newline (di
);
120 fprintf (di
->stream
, "%-4s: ", field
);
122 dump_index (di
, index
);
125 /* Dump the type of T. */
128 queue_and_dump_type (di
, t
)
132 queue_and_dump_index (di
, "type", TREE_TYPE (t
), DUMP_NONE
);
135 /* Dump column control */
136 #define SOL_COLUMN 25 /* Start of line column. */
137 #define EOL_COLUMN 55 /* End of line column. */
138 #define COLUMN_ALIGNMENT 15 /* Alignment. */
140 /* Insert a new line in the dump output, and indent to an appropriate
141 place to start printing more fields. */
147 fprintf (di
->stream
, "\n%*s", SOL_COLUMN
, "");
148 di
->column
= SOL_COLUMN
;
151 /* If necessary, insert a new line. */
154 dump_maybe_newline (di
)
159 /* See if we need a new line. */
160 if (di
->column
> EOL_COLUMN
)
162 /* See if we need any padding. */
163 else if ((extra
= (di
->column
- SOL_COLUMN
) % COLUMN_ALIGNMENT
) != 0)
165 fprintf (di
->stream
, "%*s", COLUMN_ALIGNMENT
- extra
, "");
166 di
->column
+= COLUMN_ALIGNMENT
- extra
;
170 /* Dump pointer PTR using FIELD to identify it. */
173 dump_pointer (di
, field
, ptr
)
178 dump_maybe_newline (di
);
179 fprintf (di
->stream
, "%-4s: %-8lx ", field
, (long) ptr
);
183 /* Dump integer I using FIELD to identify it. */
186 dump_int (di
, field
, i
)
191 dump_maybe_newline (di
);
192 fprintf (di
->stream
, "%-4s: %-7d ", field
, i
);
196 /* Dump the string S. */
199 dump_string (di
, string
)
203 dump_maybe_newline (di
);
204 fprintf (di
->stream
, "%-13s ", string
);
205 if (strlen (string
) > 13)
206 di
->column
+= strlen (string
) + 1;
211 /* Dump the string field S. */
214 dump_string_field (di
, field
, string
)
219 dump_maybe_newline (di
);
220 fprintf (di
->stream
, "%-4s: %-7s ", field
, string
);
221 if (strlen (string
) > 7)
222 di
->column
+= 6 + strlen (string
) + 1;
227 /* Dump the next node in the queue. */
230 dequeue_and_dump (di
)
235 dump_node_info_p dni
;
240 const char* code_name
;
242 /* Get the next node from the queue. */
246 dni
= (dump_node_info_p
) stn
->value
;
249 /* Remove the node from the queue, and put it on the free list. */
250 di
->queue
= dq
->next
;
253 dq
->next
= di
->free_list
;
256 /* Print the node index. */
257 dump_index (di
, index
);
258 /* And the type of node this is. */
262 code_name
= tree_code_name
[(int) TREE_CODE (t
)];
263 fprintf (di
->stream
, "%-16s ", code_name
);
266 /* Figure out what kind of node this is. */
267 code
= TREE_CODE (t
);
268 code_class
= TREE_CODE_CLASS (code
);
270 /* Although BINFOs are TREE_VECs, we dump them specially so as to be
274 if (TREE_VIA_PUBLIC (t
))
275 dump_string (di
, "pub");
276 else if (TREE_VIA_PROTECTED (t
))
277 dump_string (di
, "prot");
278 else if (TREE_VIA_PRIVATE (t
))
279 dump_string (di
, "priv");
280 if (TREE_VIA_VIRTUAL (t
))
281 dump_string (di
, "virt");
283 dump_child ("type", BINFO_TYPE (t
));
284 dump_child ("base", BINFO_BASETYPES (t
));
289 /* We can knock off a bunch of expression nodes in exactly the same
291 if (IS_EXPR_CODE_CLASS (code_class
))
293 /* If we're dumping children, dump them now. */
294 queue_and_dump_type (di
, t
);
299 dump_child ("op 0", TREE_OPERAND (t
, 0));
304 dump_child ("op 0", TREE_OPERAND (t
, 0));
305 dump_child ("op 1", TREE_OPERAND (t
, 1));
309 /* These nodes are handled explicitly below. */
318 /* All declarations have names. */
320 dump_child ("name", DECL_NAME (t
));
321 if (DECL_ASSEMBLER_NAME_SET_P (t
)
322 && DECL_ASSEMBLER_NAME (t
) != DECL_NAME (t
))
323 dump_child ("mngl", DECL_ASSEMBLER_NAME (t
));
325 queue_and_dump_type (di
, t
);
326 dump_child ("scpe", DECL_CONTEXT (t
));
327 /* And a source position. */
328 if (DECL_SOURCE_FILE (t
))
330 const char *filename
= strrchr (DECL_SOURCE_FILE (t
), '/');
332 filename
= DECL_SOURCE_FILE (t
);
334 /* Skip the slash. */
337 dump_maybe_newline (di
);
338 fprintf (di
->stream
, "srcp: %s:%-6d ", filename
,
339 DECL_SOURCE_LINE (t
));
340 di
->column
+= 6 + strlen (filename
) + 8;
342 /* And any declaration can be compiler-generated. */
343 if (DECL_ARTIFICIAL (t
))
344 dump_string (di
, "artificial");
345 if (TREE_CHAIN (t
) && !dump_flag (di
, TDF_SLIM
, NULL
))
346 dump_child ("chan", TREE_CHAIN (t
));
348 else if (code_class
== 't')
350 /* All types have qualifiers. */
351 int quals
= (*lang_hooks
.tree_dump
.type_quals
) (t
);
353 if (quals
!= TYPE_UNQUALIFIED
)
355 fprintf (di
->stream
, "qual: %c%c%c ",
356 (quals
& TYPE_QUAL_CONST
) ? 'c' : ' ',
357 (quals
& TYPE_QUAL_VOLATILE
) ? 'v' : ' ',
358 (quals
& TYPE_QUAL_RESTRICT
) ? 'r' : ' ');
362 /* All types have associated declarations. */
363 dump_child ("name", TYPE_NAME (t
));
365 /* All types have a main variant. */
366 if (TYPE_MAIN_VARIANT (t
) != t
)
367 dump_child ("unql", TYPE_MAIN_VARIANT (t
));
370 dump_child ("size", TYPE_SIZE (t
));
372 /* All types have alignments. */
373 dump_int (di
, "algn", TYPE_ALIGN (t
));
375 else if (code_class
== 'c')
376 /* All constants can have types. */
377 queue_and_dump_type (di
, t
);
379 /* Give the language-specific code a chance to print something. If
380 it's completely taken care of things, don't bother printing
381 anything more ourselves. */
382 if ((*lang_hooks
.tree_dump
.dump_tree
) (di
, t
))
385 /* Now handle the various kinds of nodes. */
390 case IDENTIFIER_NODE
:
391 dump_string_field (di
, "strg", IDENTIFIER_POINTER (t
));
392 dump_int (di
, "lngt", IDENTIFIER_LENGTH (t
));
396 dump_child ("purp", TREE_PURPOSE (t
));
397 dump_child ("valu", TREE_VALUE (t
));
398 dump_child ("chan", TREE_CHAIN (t
));
402 dump_int (di
, "lngt", TREE_VEC_LENGTH (t
));
403 for (i
= 0; i
< TREE_VEC_LENGTH (t
); ++i
)
406 sprintf (buffer
, "%u", i
);
407 dump_child (buffer
, TREE_VEC_ELT (t
, i
));
413 dump_int (di
, "prec", TYPE_PRECISION (t
));
414 if (TREE_UNSIGNED (t
))
415 dump_string (di
, "unsigned");
416 dump_child ("min", TYPE_MIN_VALUE (t
));
417 dump_child ("max", TYPE_MAX_VALUE (t
));
419 if (code
== ENUMERAL_TYPE
)
420 dump_child ("csts", TYPE_VALUES (t
));
424 dump_int (di
, "prec", TYPE_PRECISION (t
));
428 dump_child ("ptd", TREE_TYPE (t
));
432 dump_child ("refd", TREE_TYPE (t
));
436 dump_child ("clas", TYPE_METHOD_BASETYPE (t
));
440 dump_child ("retn", TREE_TYPE (t
));
441 dump_child ("prms", TYPE_ARG_TYPES (t
));
445 dump_child ("elts", TREE_TYPE (t
));
446 dump_child ("domn", TYPE_DOMAIN (t
));
451 if (TREE_CODE (t
) == RECORD_TYPE
)
452 dump_string (di
, "struct");
454 dump_string (di
, "union");
456 dump_child ("flds", TYPE_FIELDS (t
));
457 dump_child ("fncs", TYPE_METHODS (t
));
458 queue_and_dump_index (di
, "binf", TYPE_BINFO (t
),
463 dump_child ("cnst", DECL_INITIAL (t
));
470 if (TREE_CODE (t
) == PARM_DECL
)
471 dump_child ("argt", DECL_ARG_TYPE (t
));
473 dump_child ("init", DECL_INITIAL (t
));
474 dump_child ("size", DECL_SIZE (t
));
475 dump_int (di
, "algn", DECL_ALIGN (t
));
477 if (TREE_CODE (t
) == FIELD_DECL
)
479 if (DECL_FIELD_OFFSET (t
))
480 dump_child ("bpos", bit_position (t
));
482 else if (TREE_CODE (t
) == VAR_DECL
483 || TREE_CODE (t
) == PARM_DECL
)
485 dump_int (di
, "used", TREE_USED (t
));
486 if (DECL_REGISTER (t
))
487 dump_string (di
, "register");
492 dump_child ("args", DECL_ARGUMENTS (t
));
493 if (DECL_EXTERNAL (t
))
494 dump_string (di
, "undefined");
496 dump_string (di
, "extern");
498 dump_string (di
, "static");
499 if (DECL_LANG_SPECIFIC (t
) && !dump_flag (di
, TDF_SLIM
, t
))
500 dump_child ("body", DECL_SAVED_TREE (t
));
504 if (TREE_INT_CST_HIGH (t
))
505 dump_int (di
, "high", TREE_INT_CST_HIGH (t
));
506 dump_int (di
, "low", TREE_INT_CST_LOW (t
));
510 fprintf (di
->stream
, "strg: %-7s ", TREE_STRING_POINTER (t
));
511 dump_int (di
, "lngt", TREE_STRING_LENGTH (t
));
517 case CLEANUP_POINT_EXPR
:
519 /* These nodes are unary, but do not have code class `1'. */
520 dump_child ("op 0", TREE_OPERAND (t
, 0));
523 case TRUTH_ANDIF_EXPR
:
524 case TRUTH_ORIF_EXPR
:
530 case PREDECREMENT_EXPR
:
531 case PREINCREMENT_EXPR
:
532 case POSTDECREMENT_EXPR
:
533 case POSTINCREMENT_EXPR
:
534 /* These nodes are binary, but do not have code class `2'. */
535 dump_child ("op 0", TREE_OPERAND (t
, 0));
536 dump_child ("op 1", TREE_OPERAND (t
, 1));
540 dump_child ("op 0", TREE_OPERAND (t
, 0));
541 dump_child ("op 1", TREE_OPERAND (t
, 1));
542 dump_child ("op 2", TREE_OPERAND (t
, 2));
546 dump_child ("fn", TREE_OPERAND (t
, 0));
547 dump_child ("args", TREE_OPERAND (t
, 1));
551 dump_child ("elts", TREE_OPERAND (t
, 1));
555 dump_child ("vars", TREE_OPERAND (t
, 0));
556 dump_child ("body", TREE_OPERAND (t
, 1));
560 dump_child ("body", TREE_OPERAND (t
, 0));
564 dump_child ("cond", TREE_OPERAND (t
, 0));
568 dump_child ("decl", TREE_OPERAND (t
, 0));
569 dump_child ("init", TREE_OPERAND (t
, 1));
570 dump_child ("clnp", TREE_OPERAND (t
, 2));
571 /* There really are two possible places the initializer can be.
572 After RTL expansion, the second operand is moved to the
573 position of the fourth operand, and the second operand
575 dump_child ("init", TREE_OPERAND (t
, 3));
578 case EXPR_WITH_FILE_LOCATION
:
579 dump_child ("expr", EXPR_WFL_NODE (t
));
583 /* There are no additional fields to print. */
588 if (dump_flag (di
, TDF_ADDRESS
, NULL
))
589 dump_pointer (di
, "addr", (void *)t
);
591 /* Terminate the line. */
592 fprintf (di
->stream
, "\n");
595 /* Return nonzero if FLAG has been specified for the dump, and NODE
596 is not the root node of the dump. */
598 int dump_flag (di
, flag
, node
)
603 return (di
->flags
& flag
) && (node
!= di
->node
);
606 /* Dump T, and all its children, on STREAM. */
609 dump_node (t
, flags
, stream
)
616 dump_queue_p next_dq
;
618 /* Initialize the dump-information structure. */
627 di
.nodes
= splay_tree_new (splay_tree_compare_pointers
, 0,
628 (splay_tree_delete_value_fn
) &free
);
630 /* Queue up the first node. */
631 queue (&di
, t
, DUMP_NONE
);
633 /* Until the queue is empty, keep dumping nodes. */
635 dequeue_and_dump (&di
);
638 for (dq
= di
.free_list
; dq
; dq
= next_dq
)
643 splay_tree_delete (di
.nodes
);
646 /* Define a tree dump switch. */
647 struct dump_file_info
649 const char *const suffix
; /* suffix to give output file. */
650 const char *const swtch
; /* command line switch */
651 int flags
; /* user flags */
652 int state
; /* state of play */
655 /* Table of tree dump switches. This must be consistent with the
656 TREE_DUMP_INDEX enumeration in tree.h */
657 static struct dump_file_info dump_files
[TDI_end
] =
659 {".tu", "dump-translation-unit", 0, 0},
660 {".class", "dump-class-hierarchy", 0, 0},
661 {".original", "dump-tree-original", 0, 0},
662 {".optimized", "dump-tree-optimized", 0, 0},
663 {".inlined", "dump-tree-inlined", 0, 0},
666 /* Define a name->number mapping for a dump flag value. */
667 struct dump_option_value_info
669 const char *const name
; /* the name of the value */
670 const int value
; /* the value of the name */
673 /* Table of dump options. This must be consistent with the TDF_* flags
675 static const struct dump_option_value_info dump_options
[] =
677 {"address", TDF_ADDRESS
},
683 /* Begin a tree dump for PHASE. Stores any user supplied flag in
684 *FLAG_PTR and returns a stream to write to. If the dump is not
685 enabled, returns NULL.
686 Multiple calls will reopen and append to the dump file. */
689 dump_begin (phase
, flag_ptr
)
690 enum tree_dump_index phase
;
696 if (!dump_files
[phase
].state
)
699 name
= concat (dump_base_name
, dump_files
[phase
].suffix
, NULL
);
700 stream
= fopen (name
, dump_files
[phase
].state
< 0 ? "w" : "a");
702 error ("could not open dump file `%s'", name
);
704 dump_files
[phase
].state
= 1;
707 *flag_ptr
= dump_files
[phase
].flags
;
712 /* Returns nonzero if tree dump PHASE is enabled. */
715 dump_enabled_p (phase
)
716 enum tree_dump_index phase
;
718 return dump_files
[phase
].state
;
721 /* Returns the switch name of PHASE. */
724 dump_flag_name (phase
)
725 enum tree_dump_index phase
;
727 return dump_files
[phase
].swtch
;
730 /* Finish a tree dump for PHASE. STREAM is the stream created by
734 dump_end (phase
, stream
)
735 enum tree_dump_index phase ATTRIBUTE_UNUSED
;
741 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
742 relevant details in the dump_files array. */
749 const char *option_value
;
751 for (ix
= 0; ix
!= TDI_end
; ix
++)
752 if ((option_value
= skip_leading_substring (arg
, dump_files
[ix
].swtch
)))
754 const char *ptr
= option_value
;
759 const struct dump_option_value_info
*option_ptr
;
765 end_ptr
= strchr (ptr
, '-');
767 end_ptr
= ptr
+ strlen (ptr
);
768 length
= end_ptr
- ptr
;
770 for (option_ptr
= dump_options
; option_ptr
->name
;
772 if (strlen (option_ptr
->name
) == length
773 && !memcmp (option_ptr
->name
, ptr
, length
))
775 flags
|= option_ptr
->value
;
778 warning ("ignoring unknown option `%.*s' in `-f%s'",
779 length
, ptr
, dump_files
[ix
].swtch
);
784 dump_files
[ix
].state
= -1;
785 dump_files
[ix
].flags
= flags
;