1 /* Tree-dumping functionality for intermediate representation.
2 Copyright (C) 1999, 2000, 2002, 2003 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
24 #include "coretypes.h"
27 #include "splay-tree.h"
28 #include "diagnostic.h"
30 #include "tree-dump.h"
31 #include "langhooks.h"
33 static unsigned int queue
PARAMS ((dump_info_p
, tree
, int));
34 static void dump_index
PARAMS ((dump_info_p
, unsigned int));
35 static void dequeue_and_dump
PARAMS ((dump_info_p
));
36 static void dump_new_line
PARAMS ((dump_info_p
));
37 static void dump_maybe_newline
PARAMS ((dump_info_p
));
38 static void dump_string_field
PARAMS ((dump_info_p
, const char *, const char *));
40 /* Add T to the end of the queue of nodes to dump. Returns the index
53 /* Assign the next available index to T. */
56 /* Obtain a new queue node. */
60 di
->free_list
= dq
->next
;
63 dq
= (dump_queue_p
) xmalloc (sizeof (struct dump_queue
));
65 /* Create a new entry in the splay-tree. */
66 dni
= (dump_node_info_p
) xmalloc (sizeof (struct dump_node_info
));
68 dni
->binfo_p
= ((flags
& DUMP_BINFO
) != 0);
69 dq
->node
= splay_tree_insert (di
->nodes
, (splay_tree_key
) t
,
70 (splay_tree_value
) dni
);
72 /* Add it to the end of the queue. */
77 di
->queue_end
->next
= dq
;
80 /* Return the index. */
85 dump_index (di
, index
)
89 fprintf (di
->stream
, "@%-6u ", index
);
93 /* If T has not already been output, queue it for subsequent output.
94 FIELD is a string to print before printing the index. Then, the
95 index of T is printed. */
98 queue_and_dump_index (di
, field
, t
, flags
)
107 /* If there's no node, just return. This makes for fewer checks in
112 /* See if we've already queued or dumped this node. */
113 n
= splay_tree_lookup (di
->nodes
, (splay_tree_key
) t
);
115 index
= ((dump_node_info_p
) n
->value
)->index
;
117 /* If we haven't, add it to the queue. */
118 index
= queue (di
, t
, flags
);
120 /* Print the index of the node. */
121 dump_maybe_newline (di
);
122 fprintf (di
->stream
, "%-4s: ", field
);
124 dump_index (di
, index
);
127 /* Dump the type of T. */
130 queue_and_dump_type (di
, t
)
134 queue_and_dump_index (di
, "type", TREE_TYPE (t
), DUMP_NONE
);
137 /* Dump column control */
138 #define SOL_COLUMN 25 /* Start of line column. */
139 #define EOL_COLUMN 55 /* End of line column. */
140 #define COLUMN_ALIGNMENT 15 /* Alignment. */
142 /* Insert a new line in the dump output, and indent to an appropriate
143 place to start printing more fields. */
149 fprintf (di
->stream
, "\n%*s", SOL_COLUMN
, "");
150 di
->column
= SOL_COLUMN
;
153 /* If necessary, insert a new line. */
156 dump_maybe_newline (di
)
161 /* See if we need a new line. */
162 if (di
->column
> EOL_COLUMN
)
164 /* See if we need any padding. */
165 else if ((extra
= (di
->column
- SOL_COLUMN
) % COLUMN_ALIGNMENT
) != 0)
167 fprintf (di
->stream
, "%*s", COLUMN_ALIGNMENT
- extra
, "");
168 di
->column
+= COLUMN_ALIGNMENT
- extra
;
172 /* Dump pointer PTR using FIELD to identify it. */
175 dump_pointer (di
, field
, ptr
)
180 dump_maybe_newline (di
);
181 fprintf (di
->stream
, "%-4s: %-8lx ", field
, (long) ptr
);
185 /* Dump integer I using FIELD to identify it. */
188 dump_int (di
, field
, i
)
193 dump_maybe_newline (di
);
194 fprintf (di
->stream
, "%-4s: %-7d ", field
, i
);
198 /* Dump the string S. */
201 dump_string (di
, string
)
205 dump_maybe_newline (di
);
206 fprintf (di
->stream
, "%-13s ", string
);
207 if (strlen (string
) > 13)
208 di
->column
+= strlen (string
) + 1;
213 /* Dump the string field S. */
216 dump_string_field (di
, field
, string
)
221 dump_maybe_newline (di
);
222 fprintf (di
->stream
, "%-4s: %-7s ", field
, string
);
223 if (strlen (string
) > 7)
224 di
->column
+= 6 + strlen (string
) + 1;
229 /* Dump the next node in the queue. */
232 dequeue_and_dump (di
)
237 dump_node_info_p dni
;
242 const char* code_name
;
244 /* Get the next node from the queue. */
248 dni
= (dump_node_info_p
) stn
->value
;
251 /* Remove the node from the queue, and put it on the free list. */
252 di
->queue
= dq
->next
;
255 dq
->next
= di
->free_list
;
258 /* Print the node index. */
259 dump_index (di
, index
);
260 /* And the type of node this is. */
264 code_name
= tree_code_name
[(int) TREE_CODE (t
)];
265 fprintf (di
->stream
, "%-16s ", code_name
);
268 /* Figure out what kind of node this is. */
269 code
= TREE_CODE (t
);
270 code_class
= TREE_CODE_CLASS (code
);
272 /* Although BINFOs are TREE_VECs, we dump them specially so as to be
277 tree bases
= BINFO_BASETYPES (t
);
278 unsigned n_bases
= bases
? TREE_VEC_LENGTH (bases
): 0;
279 tree accesses
= BINFO_BASEACCESSES (t
);
281 dump_child ("type", BINFO_TYPE (t
));
283 if (TREE_VIA_VIRTUAL (t
))
284 dump_string (di
, "virt");
286 dump_int (di
, "bases", n_bases
);
287 for (ix
= 0; ix
!= n_bases
; ix
++)
289 tree base
= TREE_VEC_ELT (bases
, ix
);
290 tree access
= (accesses
? TREE_VEC_ELT (accesses
, ix
)
291 : access_public_node
);
292 const char *string
= NULL
;
294 if (access
== access_public_node
)
296 else if (access
== access_protected_node
)
298 else if (access
== access_private_node
)
303 dump_string (di
, string
);
304 queue_and_dump_index (di
, "binf", base
, DUMP_BINFO
);
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_FIELD_OFFSET (t
))
501 dump_child ("bpos", bit_position (t
));
503 else if (TREE_CODE (t
) == VAR_DECL
504 || TREE_CODE (t
) == PARM_DECL
)
506 dump_int (di
, "used", TREE_USED (t
));
507 if (DECL_REGISTER (t
))
508 dump_string (di
, "register");
513 dump_child ("args", DECL_ARGUMENTS (t
));
514 if (DECL_EXTERNAL (t
))
515 dump_string (di
, "undefined");
517 dump_string (di
, "extern");
519 dump_string (di
, "static");
520 if (DECL_LANG_SPECIFIC (t
) && !dump_flag (di
, TDF_SLIM
, t
))
521 dump_child ("body", DECL_SAVED_TREE (t
));
525 if (TREE_INT_CST_HIGH (t
))
526 dump_int (di
, "high", TREE_INT_CST_HIGH (t
));
527 dump_int (di
, "low", TREE_INT_CST_LOW (t
));
531 fprintf (di
->stream
, "strg: %-7s ", TREE_STRING_POINTER (t
));
532 dump_int (di
, "lngt", TREE_STRING_LENGTH (t
));
538 case CLEANUP_POINT_EXPR
:
540 /* These nodes are unary, but do not have code class `1'. */
541 dump_child ("op 0", TREE_OPERAND (t
, 0));
544 case TRUTH_ANDIF_EXPR
:
545 case TRUTH_ORIF_EXPR
:
551 case PREDECREMENT_EXPR
:
552 case PREINCREMENT_EXPR
:
553 case POSTDECREMENT_EXPR
:
554 case POSTINCREMENT_EXPR
:
555 /* These nodes are binary, but do not have code class `2'. */
556 dump_child ("op 0", TREE_OPERAND (t
, 0));
557 dump_child ("op 1", TREE_OPERAND (t
, 1));
561 dump_child ("op 0", TREE_OPERAND (t
, 0));
562 dump_child ("op 1", TREE_OPERAND (t
, 1));
563 dump_child ("op 2", TREE_OPERAND (t
, 2));
567 dump_child ("fn", TREE_OPERAND (t
, 0));
568 dump_child ("args", TREE_OPERAND (t
, 1));
572 dump_child ("elts", TREE_OPERAND (t
, 1));
576 dump_child ("vars", TREE_OPERAND (t
, 0));
577 dump_child ("body", TREE_OPERAND (t
, 1));
581 dump_child ("body", TREE_OPERAND (t
, 0));
585 dump_child ("cond", TREE_OPERAND (t
, 0));
589 dump_child ("decl", TREE_OPERAND (t
, 0));
590 dump_child ("init", TREE_OPERAND (t
, 1));
591 dump_child ("clnp", TREE_OPERAND (t
, 2));
592 /* There really are two possible places the initializer can be.
593 After RTL expansion, the second operand is moved to the
594 position of the fourth operand, and the second operand
596 dump_child ("init", TREE_OPERAND (t
, 3));
599 case EXPR_WITH_FILE_LOCATION
:
600 dump_child ("expr", EXPR_WFL_NODE (t
));
604 /* There are no additional fields to print. */
609 if (dump_flag (di
, TDF_ADDRESS
, NULL
))
610 dump_pointer (di
, "addr", (void *)t
);
612 /* Terminate the line. */
613 fprintf (di
->stream
, "\n");
616 /* Return nonzero if FLAG has been specified for the dump, and NODE
617 is not the root node of the dump. */
619 int dump_flag (di
, flag
, node
)
624 return (di
->flags
& flag
) && (node
!= di
->node
);
627 /* Dump T, and all its children, on STREAM. */
630 dump_node (t
, flags
, stream
)
637 dump_queue_p next_dq
;
639 /* Initialize the dump-information structure. */
648 di
.nodes
= splay_tree_new (splay_tree_compare_pointers
, 0,
649 (splay_tree_delete_value_fn
) &free
);
651 /* Queue up the first node. */
652 queue (&di
, t
, DUMP_NONE
);
654 /* Until the queue is empty, keep dumping nodes. */
656 dequeue_and_dump (&di
);
659 for (dq
= di
.free_list
; dq
; dq
= next_dq
)
664 splay_tree_delete (di
.nodes
);
667 /* Define a tree dump switch. */
668 struct dump_file_info
670 const char *const suffix
; /* suffix to give output file. */
671 const char *const swtch
; /* command line switch */
672 int flags
; /* user flags */
673 int state
; /* state of play */
676 /* Table of tree dump switches. This must be consistent with the
677 TREE_DUMP_INDEX enumeration in tree.h */
678 static struct dump_file_info dump_files
[TDI_end
] =
680 {".tu", "dump-translation-unit", 0, 0},
681 {".class", "dump-class-hierarchy", 0, 0},
682 {".original", "dump-tree-original", 0, 0},
683 {".optimized", "dump-tree-optimized", 0, 0},
684 {".inlined", "dump-tree-inlined", 0, 0},
687 /* Define a name->number mapping for a dump flag value. */
688 struct dump_option_value_info
690 const char *const name
; /* the name of the value */
691 const int value
; /* the value of the name */
694 /* Table of dump options. This must be consistent with the TDF_* flags
696 static const struct dump_option_value_info dump_options
[] =
698 {"address", TDF_ADDRESS
},
704 /* Begin a tree dump for PHASE. Stores any user supplied flag in
705 *FLAG_PTR and returns a stream to write to. If the dump is not
706 enabled, returns NULL.
707 Multiple calls will reopen and append to the dump file. */
710 dump_begin (phase
, flag_ptr
)
711 enum tree_dump_index phase
;
717 if (!dump_files
[phase
].state
)
720 name
= concat (dump_base_name
, dump_files
[phase
].suffix
, NULL
);
721 stream
= fopen (name
, dump_files
[phase
].state
< 0 ? "w" : "a");
723 error ("could not open dump file `%s'", name
);
725 dump_files
[phase
].state
= 1;
728 *flag_ptr
= dump_files
[phase
].flags
;
733 /* Returns nonzero if tree dump PHASE is enabled. */
736 dump_enabled_p (phase
)
737 enum tree_dump_index phase
;
739 return dump_files
[phase
].state
;
742 /* Returns the switch name of PHASE. */
745 dump_flag_name (phase
)
746 enum tree_dump_index phase
;
748 return dump_files
[phase
].swtch
;
751 /* Finish a tree dump for PHASE. STREAM is the stream created by
755 dump_end (phase
, stream
)
756 enum tree_dump_index phase ATTRIBUTE_UNUSED
;
762 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
763 relevant details in the dump_files array. */
770 const char *option_value
;
772 for (ix
= 0; ix
!= TDI_end
; ix
++)
773 if ((option_value
= skip_leading_substring (arg
, dump_files
[ix
].swtch
)))
775 const char *ptr
= option_value
;
780 const struct dump_option_value_info
*option_ptr
;
786 end_ptr
= strchr (ptr
, '-');
788 end_ptr
= ptr
+ strlen (ptr
);
789 length
= end_ptr
- ptr
;
791 for (option_ptr
= dump_options
; option_ptr
->name
;
793 if (strlen (option_ptr
->name
) == length
794 && !memcmp (option_ptr
->name
, ptr
, length
))
796 flags
|= option_ptr
->value
;
799 warning ("ignoring unknown option `%.*s' in `-f%s'",
800 length
, ptr
, dump_files
[ix
].swtch
);
805 dump_files
[ix
].state
= -1;
806 dump_files
[ix
].flags
= flags
;