1 /* Tree-dumping functionality for intermediate representation.
2 Copyright (C) 1999, 2000 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
26 #include "splay-tree.h"
27 #include "diagnostic.h"
29 #include "tree-dump.h"
30 #include "langhooks.h"
32 static unsigned int queue
PARAMS ((dump_info_p
, tree
, int));
33 static void dump_index
PARAMS ((dump_info_p
, unsigned int));
34 static void dequeue_and_dump
PARAMS ((dump_info_p
));
35 static void dump_new_line
PARAMS ((dump_info_p
));
36 static void dump_maybe_newline
PARAMS ((dump_info_p
));
37 static void dump_string_field
PARAMS ((dump_info_p
, const char *, const char *));
39 /* Add T to the end of the queue of nodes to dump. Returns the index
52 /* Assign the next available index to T. */
55 /* Obtain a new queue node. */
59 di
->free_list
= dq
->next
;
62 dq
= (dump_queue_p
) xmalloc (sizeof (struct dump_queue
));
64 /* Create a new entry in the splay-tree. */
65 dni
= (dump_node_info_p
) xmalloc (sizeof (struct dump_node_info
));
67 dni
->binfo_p
= ((flags
& DUMP_BINFO
) != 0);
68 dq
->node
= splay_tree_insert (di
->nodes
, (splay_tree_key
) t
,
69 (splay_tree_value
) dni
);
71 /* Add it to the end of the queue. */
76 di
->queue_end
->next
= dq
;
79 /* Return the index. */
84 dump_index (di
, index
)
88 fprintf (di
->stream
, "@%-6u ", index
);
92 /* If T has not already been output, queue it for subsequent output.
93 FIELD is a string to print before printing the index. Then, the
94 index of T is printed. */
97 queue_and_dump_index (di
, field
, t
, flags
)
106 /* If there's no node, just return. This makes for fewer checks in
111 /* See if we've already queued or dumped this node. */
112 n
= splay_tree_lookup (di
->nodes
, (splay_tree_key
) t
);
114 index
= ((dump_node_info_p
) n
->value
)->index
;
116 /* If we haven't, add it to the queue. */
117 index
= queue (di
, t
, flags
);
119 /* Print the index of the node. */
120 dump_maybe_newline (di
);
121 fprintf (di
->stream
, "%-4s: ", field
);
123 dump_index (di
, index
);
126 /* Dump the type of T. */
129 queue_and_dump_type (di
, t
)
133 queue_and_dump_index (di
, "type", TREE_TYPE (t
), DUMP_NONE
);
136 /* Dump column control */
137 #define SOL_COLUMN 25 /* Start of line column. */
138 #define EOL_COLUMN 55 /* End of line column. */
139 #define COLUMN_ALIGNMENT 15 /* Alignment. */
141 /* Insert a new line in the dump output, and indent to an appropriate
142 place to start printing more fields. */
148 fprintf (di
->stream
, "\n%*s", SOL_COLUMN
, "");
149 di
->column
= SOL_COLUMN
;
152 /* If necessary, insert a new line. */
155 dump_maybe_newline (di
)
160 /* See if we need a new line. */
161 if (di
->column
> EOL_COLUMN
)
163 /* See if we need any padding. */
164 else if ((extra
= (di
->column
- SOL_COLUMN
) % COLUMN_ALIGNMENT
) != 0)
166 fprintf (di
->stream
, "%*s", COLUMN_ALIGNMENT
- extra
, "");
167 di
->column
+= COLUMN_ALIGNMENT
- extra
;
171 /* Dump pointer PTR using FIELD to identify it. */
174 dump_pointer (di
, field
, ptr
)
179 dump_maybe_newline (di
);
180 fprintf (di
->stream
, "%-4s: %-8lx ", field
, (long) ptr
);
184 /* Dump integer I using FIELD to identify it. */
187 dump_int (di
, field
, i
)
192 dump_maybe_newline (di
);
193 fprintf (di
->stream
, "%-4s: %-7d ", field
, i
);
197 /* Dump the string S. */
200 dump_string (di
, string
)
204 dump_maybe_newline (di
);
205 fprintf (di
->stream
, "%-13s ", string
);
206 if (strlen (string
) > 13)
207 di
->column
+= strlen (string
) + 1;
212 /* Dump the string field S. */
215 dump_string_field (di
, field
, string
)
220 dump_maybe_newline (di
);
221 fprintf (di
->stream
, "%-4s: %-7s ", field
, string
);
222 if (strlen (string
) > 7)
223 di
->column
+= 6 + strlen (string
) + 1;
228 /* Dump information common to statements from STMT. */
235 dump_int (di
, "line", STMT_LINENO (t
));
238 /* Dump the next statement after STMT. */
241 dump_next_stmt (di
, t
)
245 dump_child ("next", TREE_CHAIN (t
));
248 /* Dump the next node in the queue. */
251 dequeue_and_dump (di
)
256 dump_node_info_p dni
;
261 const char* code_name
;
263 /* Get the next node from the queue. */
267 dni
= (dump_node_info_p
) stn
->value
;
270 /* Remove the node from the queue, and put it on the free list. */
271 di
->queue
= dq
->next
;
274 dq
->next
= di
->free_list
;
277 /* Print the node index. */
278 dump_index (di
, index
);
279 /* And the type of node this is. */
283 code_name
= tree_code_name
[(int) TREE_CODE (t
)];
284 fprintf (di
->stream
, "%-16s ", code_name
);
287 /* Figure out what kind of node this is. */
288 code
= TREE_CODE (t
);
289 code_class
= TREE_CODE_CLASS (code
);
291 /* Although BINFOs are TREE_VECs, we dump them specially so as to be
295 if (TREE_VIA_PUBLIC (t
))
296 dump_string (di
, "pub");
297 else if (TREE_VIA_PROTECTED (t
))
298 dump_string (di
, "prot");
299 else if (TREE_VIA_PRIVATE (t
))
300 dump_string (di
, "priv");
301 if (TREE_VIA_VIRTUAL (t
))
302 dump_string (di
, "virt");
304 dump_child ("type", BINFO_TYPE (t
));
305 dump_child ("base", BINFO_BASETYPES (t
));
310 /* We can knock off a bunch of expression nodes in exactly the same
312 if (IS_EXPR_CODE_CLASS (code_class
))
314 /* If we're dumping children, dump them now. */
315 queue_and_dump_type (di
, t
);
320 dump_child ("op 0", TREE_OPERAND (t
, 0));
325 dump_child ("op 0", TREE_OPERAND (t
, 0));
326 dump_child ("op 1", TREE_OPERAND (t
, 1));
330 /* These nodes are handled explicitly below. */
339 /* All declarations have names. */
341 dump_child ("name", DECL_NAME (t
));
342 if (DECL_ASSEMBLER_NAME_SET_P (t
)
343 && DECL_ASSEMBLER_NAME (t
) != DECL_NAME (t
))
344 dump_child ("mngl", DECL_ASSEMBLER_NAME (t
));
346 queue_and_dump_type (di
, t
);
347 dump_child ("scpe", DECL_CONTEXT (t
));
348 /* And a source position. */
349 if (DECL_SOURCE_FILE (t
))
351 const char *filename
= strrchr (DECL_SOURCE_FILE (t
), '/');
353 filename
= DECL_SOURCE_FILE (t
);
355 /* Skip the slash. */
358 dump_maybe_newline (di
);
359 fprintf (di
->stream
, "srcp: %s:%-6d ", filename
,
360 DECL_SOURCE_LINE (t
));
361 di
->column
+= 6 + strlen (filename
) + 8;
363 /* And any declaration can be compiler-generated. */
364 if (DECL_ARTIFICIAL (t
))
365 dump_string (di
, "artificial");
366 if (TREE_CHAIN (t
) && !dump_flag (di
, TDF_SLIM
, NULL
))
367 dump_child ("chan", TREE_CHAIN (t
));
369 else if (code_class
== 't')
371 /* All types have qualifiers. */
372 int quals
= (*lang_hooks
.tree_dump
.type_quals
) (t
);
374 if (quals
!= TYPE_UNQUALIFIED
)
376 fprintf (di
->stream
, "qual: %c%c%c ",
377 (quals
& TYPE_QUAL_CONST
) ? 'c' : ' ',
378 (quals
& TYPE_QUAL_VOLATILE
) ? 'v' : ' ',
379 (quals
& TYPE_QUAL_RESTRICT
) ? 'r' : ' ');
383 /* All types have associated declarations. */
384 dump_child ("name", TYPE_NAME (t
));
386 /* All types have a main variant. */
387 if (TYPE_MAIN_VARIANT (t
) != t
)
388 dump_child ("unql", TYPE_MAIN_VARIANT (t
));
391 dump_child ("size", TYPE_SIZE (t
));
393 /* All types have alignments. */
394 dump_int (di
, "algn", TYPE_ALIGN (t
));
396 else if (code_class
== 'c')
397 /* All constants can have types. */
398 queue_and_dump_type (di
, t
);
400 /* Give the language-specific code a chance to print something. If
401 it's completely taken care of things, don't bother printing
402 anything more ourselves. */
403 if ((*lang_hooks
.tree_dump
.dump_tree
) (di
, t
))
406 /* Now handle the various kinds of nodes. */
411 case IDENTIFIER_NODE
:
412 dump_string_field (di
, "strg", IDENTIFIER_POINTER (t
));
413 dump_int (di
, "lngt", IDENTIFIER_LENGTH (t
));
417 dump_child ("purp", TREE_PURPOSE (t
));
418 dump_child ("valu", TREE_VALUE (t
));
419 dump_child ("chan", TREE_CHAIN (t
));
423 dump_int (di
, "lngt", TREE_VEC_LENGTH (t
));
424 for (i
= 0; i
< TREE_VEC_LENGTH (t
); ++i
)
427 sprintf (buffer
, "%u", i
);
428 dump_child (buffer
, TREE_VEC_ELT (t
, i
));
434 dump_int (di
, "prec", TYPE_PRECISION (t
));
435 if (TREE_UNSIGNED (t
))
436 dump_string (di
, "unsigned");
437 dump_child ("min", TYPE_MIN_VALUE (t
));
438 dump_child ("max", TYPE_MAX_VALUE (t
));
440 if (code
== ENUMERAL_TYPE
)
441 dump_child ("csts", TYPE_VALUES (t
));
445 dump_int (di
, "prec", TYPE_PRECISION (t
));
449 dump_child ("ptd", TREE_TYPE (t
));
453 dump_child ("refd", TREE_TYPE (t
));
457 dump_child ("clas", TYPE_METHOD_BASETYPE (t
));
461 dump_child ("retn", TREE_TYPE (t
));
462 dump_child ("prms", TYPE_ARG_TYPES (t
));
466 dump_child ("elts", TREE_TYPE (t
));
467 dump_child ("domn", TYPE_DOMAIN (t
));
472 if (TREE_CODE (t
) == RECORD_TYPE
)
473 dump_string (di
, "struct");
475 dump_string (di
, "union");
477 dump_child ("flds", TYPE_FIELDS (t
));
478 dump_child ("fncs", TYPE_METHODS (t
));
479 queue_and_dump_index (di
, "binf", TYPE_BINFO (t
),
484 dump_child ("cnst", DECL_INITIAL (t
));
491 if (TREE_CODE (t
) == PARM_DECL
)
492 dump_child ("argt", DECL_ARG_TYPE (t
));
494 dump_child ("init", DECL_INITIAL (t
));
495 dump_child ("size", DECL_SIZE (t
));
496 dump_int (di
, "algn", DECL_ALIGN (t
));
498 if (TREE_CODE (t
) == FIELD_DECL
)
500 if (DECL_C_BIT_FIELD (t
))
501 dump_string (di
, "bitfield");
502 if (DECL_FIELD_OFFSET (t
))
503 dump_child ("bpos", bit_position (t
));
505 else if (TREE_CODE (t
) == VAR_DECL
506 || TREE_CODE (t
) == PARM_DECL
)
508 dump_int (di
, "used", TREE_USED (t
));
509 if (DECL_REGISTER (t
))
510 dump_string (di
, "register");
515 dump_child ("args", DECL_ARGUMENTS (t
));
516 if (DECL_EXTERNAL (t
))
517 dump_string (di
, "undefined");
519 dump_string (di
, "extern");
521 dump_string (di
, "static");
522 if (DECL_LANG_SPECIFIC (t
) && !dump_flag (di
, TDF_SLIM
, t
))
523 dump_child ("body", DECL_SAVED_TREE (t
));
528 if (ASM_VOLATILE_P (t
))
529 dump_string (di
, "volatile");
530 dump_child ("strg", ASM_STRING (t
));
531 dump_child ("outs", ASM_OUTPUTS (t
));
532 dump_child ("ins", ASM_INPUTS (t
));
533 dump_child ("clbr", ASM_CLOBBERS (t
));
534 dump_next_stmt (di
, t
);
540 dump_next_stmt (di
, t
);
544 /* Note that a case label is not like other statements; there is
545 no way to get the line-number of a case label. */
546 dump_child ("low", CASE_LOW (t
));
547 dump_child ("high", CASE_HIGH (t
));
548 dump_next_stmt (di
, t
);
553 dump_child ("body", COMPOUND_BODY (t
));
554 dump_next_stmt (di
, t
);
559 dump_child ("decl", DECL_STMT_DECL (t
));
560 dump_next_stmt (di
, t
);
565 dump_child ("body", DO_BODY (t
));
566 dump_child ("cond", DO_COND (t
));
567 dump_next_stmt (di
, t
);
572 dump_child ("expr", EXPR_STMT_EXPR (t
));
573 dump_next_stmt (di
, t
);
578 dump_child ("init", FOR_INIT_STMT (t
));
579 dump_child ("cond", FOR_COND (t
));
580 dump_child ("expr", FOR_EXPR (t
));
581 dump_child ("body", FOR_BODY (t
));
582 dump_next_stmt (di
, t
);
587 dump_child ("dest", GOTO_DESTINATION (t
));
588 dump_next_stmt (di
, t
);
593 dump_child ("cond", IF_COND (t
));
594 dump_child ("then", THEN_CLAUSE (t
));
595 dump_child ("else", ELSE_CLAUSE (t
));
596 dump_next_stmt (di
, t
);
601 dump_child ("labl", LABEL_STMT_LABEL (t
));
602 dump_next_stmt (di
, t
);
607 dump_child ("expr", RETURN_EXPR (t
));
608 dump_next_stmt (di
, t
);
613 dump_child ("cond", SWITCH_COND (t
));
614 dump_child ("body", SWITCH_BODY (t
));
615 dump_next_stmt (di
, t
);
620 dump_child ("cond", WHILE_COND (t
));
621 dump_child ("body", WHILE_BODY (t
));
622 dump_next_stmt (di
, t
);
627 if (SCOPE_BEGIN_P (t
))
628 dump_string (di
, "begn");
630 dump_string (di
, "end");
631 if (SCOPE_NULLIFIED_P (t
))
632 dump_string (di
, "null");
633 if (!SCOPE_NO_CLEANUPS_P (t
))
634 dump_string (di
, "clnp");
635 dump_next_stmt (di
, t
);
639 if (TREE_INT_CST_HIGH (t
))
640 dump_int (di
, "high", TREE_INT_CST_HIGH (t
));
641 dump_int (di
, "low", TREE_INT_CST_LOW (t
));
645 fprintf (di
->stream
, "strg: %-7s ", TREE_STRING_POINTER (t
));
646 dump_int (di
, "lngt", TREE_STRING_LENGTH (t
));
652 case CLEANUP_POINT_EXPR
:
654 /* These nodes are unary, but do not have code class `1'. */
655 dump_child ("op 0", TREE_OPERAND (t
, 0));
658 case TRUTH_ANDIF_EXPR
:
659 case TRUTH_ORIF_EXPR
:
665 case PREDECREMENT_EXPR
:
666 case PREINCREMENT_EXPR
:
667 case POSTDECREMENT_EXPR
:
668 case POSTINCREMENT_EXPR
:
669 /* These nodes are binary, but do not have code class `2'. */
670 dump_child ("op 0", TREE_OPERAND (t
, 0));
671 dump_child ("op 1", TREE_OPERAND (t
, 1));
675 dump_child ("op 0", TREE_OPERAND (t
, 0));
676 dump_child ("op 1", TREE_OPERAND (t
, 1));
677 dump_child ("op 2", TREE_OPERAND (t
, 2));
681 dump_child ("fn", TREE_OPERAND (t
, 0));
682 dump_child ("args", TREE_OPERAND (t
, 1));
686 dump_child ("elts", TREE_OPERAND (t
, 1));
690 dump_child ("stmt", STMT_EXPR_STMT (t
));
694 dump_child ("vars", TREE_OPERAND (t
, 0));
695 dump_child ("body", TREE_OPERAND (t
, 1));
699 dump_child ("body", TREE_OPERAND (t
, 0));
703 dump_child ("cond", TREE_OPERAND (t
, 0));
707 dump_child ("decl", TREE_OPERAND (t
, 0));
708 dump_child ("init", TREE_OPERAND (t
, 1));
709 dump_child ("clnp", TREE_OPERAND (t
, 2));
710 /* There really are two possible places the initializer can be.
711 After RTL expansion, the second operand is moved to the
712 position of the fourth operand, and the second operand
714 dump_child ("init", TREE_OPERAND (t
, 3));
717 case EXPR_WITH_FILE_LOCATION
:
718 dump_child ("expr", EXPR_WFL_NODE (t
));
722 /* There are no additional fields to print. */
727 if (dump_flag (di
, TDF_ADDRESS
, NULL
))
728 dump_pointer (di
, "addr", (void *)t
);
730 /* Terminate the line. */
731 fprintf (di
->stream
, "\n");
734 /* Return non-zero if FLAG has been specified for the dump, and NODE
735 is not the root node of the dump. */
737 int dump_flag (di
, flag
, node
)
742 return (di
->flags
& flag
) && (node
!= di
->node
);
745 /* Dump T, and all its children, on STREAM. */
748 dump_node (t
, flags
, stream
)
755 dump_queue_p next_dq
;
757 /* Initialize the dump-information structure. */
766 di
.nodes
= splay_tree_new (splay_tree_compare_pointers
, 0,
767 (splay_tree_delete_value_fn
) &free
);
769 /* Queue up the first node. */
770 queue (&di
, t
, DUMP_NONE
);
772 /* Until the queue is empty, keep dumping nodes. */
774 dequeue_and_dump (&di
);
777 for (dq
= di
.free_list
; dq
; dq
= next_dq
)
782 splay_tree_delete (di
.nodes
);
785 /* Define a tree dump switch. */
786 struct dump_file_info
788 const char *const suffix
; /* suffix to give output file. */
789 const char *const swtch
; /* command line switch */
790 int flags
; /* user flags */
791 int state
; /* state of play */
794 /* Table of tree dump switches. This must be consistent with the
795 TREE_DUMP_INDEX enumeration in tree.h */
796 static struct dump_file_info dump_files
[TDI_end
] =
798 {".tu", "dump-translation-unit", 0, 0},
799 {".class", "dump-class-hierarchy", 0, 0},
800 {".original", "dump-tree-original", 0, 0},
801 {".optimized", "dump-tree-optimized", 0, 0},
802 {".inlined", "dump-tree-inlined", 0, 0},
805 /* Define a name->number mapping for a dump flag value. */
806 struct dump_option_value_info
808 const char *const name
; /* the name of the value */
809 const int value
; /* the value of the name */
812 /* Table of dump options. This must be consistent with the TDF_* flags
814 static const struct dump_option_value_info dump_options
[] =
816 {"address", TDF_ADDRESS
},
822 /* Begin a tree dump for PHASE. Stores any user supplied flag in
823 *FLAG_PTR and returns a stream to write to. If the dump is not
824 enabled, returns NULL.
825 Multiple calls will reopen and append to the dump file. */
828 dump_begin (phase
, flag_ptr
)
829 enum tree_dump_index phase
;
835 if (!dump_files
[phase
].state
)
838 name
= concat (dump_base_name
, dump_files
[phase
].suffix
, NULL
);
839 stream
= fopen (name
, dump_files
[phase
].state
< 0 ? "w" : "a");
841 error ("could not open dump file `%s'", name
);
843 dump_files
[phase
].state
= 1;
846 *flag_ptr
= dump_files
[phase
].flags
;
851 /* Returns non-zero if tree dump PHASE is enabled. */
854 dump_enabled_p (phase
)
855 enum tree_dump_index phase
;
857 return dump_files
[phase
].state
;
860 /* Returns the switch name of PHASE. */
863 dump_flag_name (phase
)
864 enum tree_dump_index phase
;
866 return dump_files
[phase
].swtch
;
869 /* Finish a tree dump for PHASE. STREAM is the stream created by
873 dump_end (phase
, stream
)
874 enum tree_dump_index phase ATTRIBUTE_UNUSED
;
880 /* Parse ARG as a dump switch. Return non-zero if it is, and store the
881 relevant details in the dump_files array. */
888 const char *option_value
;
890 for (ix
= 0; ix
!= TDI_end
; ix
++)
891 if ((option_value
= skip_leading_substring (arg
, dump_files
[ix
].swtch
)))
893 const char *ptr
= option_value
;
898 const struct dump_option_value_info
*option_ptr
;
904 end_ptr
= strchr (ptr
, '-');
906 end_ptr
= ptr
+ strlen (ptr
);
907 length
= end_ptr
- ptr
;
909 for (option_ptr
= dump_options
; option_ptr
->name
;
911 if (strlen (option_ptr
->name
) == length
912 && !memcmp (option_ptr
->name
, ptr
, length
))
914 flags
|= option_ptr
->value
;
917 warning ("ignoring unknown option `%.*s' in `-f%s'",
918 length
, ptr
, dump_files
[ix
].swtch
);
923 dump_files
[ix
].state
= -1;
924 dump_files
[ix
].flags
= flags
;