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 (dump_info_p
, tree
, int);
34 static void dump_index (dump_info_p
, unsigned int);
35 static void dequeue_and_dump (dump_info_p
);
36 static void dump_new_line (dump_info_p
);
37 static void dump_maybe_newline (dump_info_p
);
38 static void dump_string_field (dump_info_p
, const char *, const char *);
40 /* Add T to the end of the queue of nodes to dump. Returns the index
44 queue (dump_info_p di
, tree t
, int flags
)
50 /* Assign the next available index to T. */
53 /* Obtain a new queue node. */
57 di
->free_list
= dq
->next
;
60 dq
= xmalloc (sizeof (struct dump_queue
));
62 /* Create a new entry in the splay-tree. */
63 dni
= xmalloc (sizeof (struct dump_node_info
));
65 dni
->binfo_p
= ((flags
& DUMP_BINFO
) != 0);
66 dq
->node
= splay_tree_insert (di
->nodes
, (splay_tree_key
) t
,
67 (splay_tree_value
) dni
);
69 /* Add it to the end of the queue. */
74 di
->queue_end
->next
= dq
;
77 /* Return the index. */
82 dump_index (dump_info_p di
, unsigned int index
)
84 fprintf (di
->stream
, "@%-6u ", index
);
88 /* If T has not already been output, queue it for subsequent output.
89 FIELD is a string to print before printing the index. Then, the
90 index of T is printed. */
93 queue_and_dump_index (dump_info_p di
, const char *field
, tree t
, int flags
)
98 /* If there's no node, just return. This makes for fewer checks in
103 /* See if we've already queued or dumped this node. */
104 n
= splay_tree_lookup (di
->nodes
, (splay_tree_key
) t
);
106 index
= ((dump_node_info_p
) n
->value
)->index
;
108 /* If we haven't, add it to the queue. */
109 index
= queue (di
, t
, flags
);
111 /* Print the index of the node. */
112 dump_maybe_newline (di
);
113 fprintf (di
->stream
, "%-4s: ", field
);
115 dump_index (di
, index
);
118 /* Dump the type of T. */
121 queue_and_dump_type (dump_info_p di
, tree t
)
123 queue_and_dump_index (di
, "type", TREE_TYPE (t
), DUMP_NONE
);
126 /* Dump column control */
127 #define SOL_COLUMN 25 /* Start of line column. */
128 #define EOL_COLUMN 55 /* End of line column. */
129 #define COLUMN_ALIGNMENT 15 /* Alignment. */
131 /* Insert a new line in the dump output, and indent to an appropriate
132 place to start printing more fields. */
135 dump_new_line (dump_info_p di
)
137 fprintf (di
->stream
, "\n%*s", SOL_COLUMN
, "");
138 di
->column
= SOL_COLUMN
;
141 /* If necessary, insert a new line. */
144 dump_maybe_newline (dump_info_p di
)
148 /* See if we need a new line. */
149 if (di
->column
> EOL_COLUMN
)
151 /* See if we need any padding. */
152 else if ((extra
= (di
->column
- SOL_COLUMN
) % COLUMN_ALIGNMENT
) != 0)
154 fprintf (di
->stream
, "%*s", COLUMN_ALIGNMENT
- extra
, "");
155 di
->column
+= COLUMN_ALIGNMENT
- extra
;
159 /* Dump pointer PTR using FIELD to identify it. */
162 dump_pointer (dump_info_p di
, const char *field
, void *ptr
)
164 dump_maybe_newline (di
);
165 fprintf (di
->stream
, "%-4s: %-8lx ", field
, (long) ptr
);
169 /* Dump integer I using FIELD to identify it. */
172 dump_int (dump_info_p di
, const char *field
, int i
)
174 dump_maybe_newline (di
);
175 fprintf (di
->stream
, "%-4s: %-7d ", field
, i
);
179 /* Dump the string S. */
182 dump_string (dump_info_p di
, const char *string
)
184 dump_maybe_newline (di
);
185 fprintf (di
->stream
, "%-13s ", string
);
186 if (strlen (string
) > 13)
187 di
->column
+= strlen (string
) + 1;
192 /* Dump the string field S. */
195 dump_string_field (dump_info_p di
, const char *field
, const char *string
)
197 dump_maybe_newline (di
);
198 fprintf (di
->stream
, "%-4s: %-7s ", field
, string
);
199 if (strlen (string
) > 7)
200 di
->column
+= 6 + strlen (string
) + 1;
205 /* Dump the next node in the queue. */
208 dequeue_and_dump (dump_info_p di
)
212 dump_node_info_p dni
;
217 const char* code_name
;
219 /* Get the next node from the queue. */
223 dni
= (dump_node_info_p
) stn
->value
;
226 /* Remove the node from the queue, and put it on the free list. */
227 di
->queue
= dq
->next
;
230 dq
->next
= di
->free_list
;
233 /* Print the node index. */
234 dump_index (di
, index
);
235 /* And the type of node this is. */
239 code_name
= tree_code_name
[(int) TREE_CODE (t
)];
240 fprintf (di
->stream
, "%-16s ", code_name
);
243 /* Figure out what kind of node this is. */
244 code
= TREE_CODE (t
);
245 code_class
= TREE_CODE_CLASS (code
);
247 /* Although BINFOs are TREE_VECs, we dump them specially so as to be
252 tree bases
= BINFO_BASETYPES (t
);
253 unsigned n_bases
= bases
? TREE_VEC_LENGTH (bases
): 0;
254 tree accesses
= BINFO_BASEACCESSES (t
);
256 dump_child ("type", BINFO_TYPE (t
));
258 if (TREE_VIA_VIRTUAL (t
))
259 dump_string (di
, "virt");
261 dump_int (di
, "bases", n_bases
);
262 for (ix
= 0; ix
!= n_bases
; ix
++)
264 tree base
= TREE_VEC_ELT (bases
, ix
);
265 tree access
= (accesses
? TREE_VEC_ELT (accesses
, ix
)
266 : access_public_node
);
267 const char *string
= NULL
;
269 if (access
== access_public_node
)
271 else if (access
== access_protected_node
)
273 else if (access
== access_private_node
)
278 dump_string (di
, string
);
279 queue_and_dump_index (di
, "binf", base
, DUMP_BINFO
);
285 /* We can knock off a bunch of expression nodes in exactly the same
287 if (IS_EXPR_CODE_CLASS (code_class
))
289 /* If we're dumping children, dump them now. */
290 queue_and_dump_type (di
, t
);
295 dump_child ("op 0", TREE_OPERAND (t
, 0));
300 dump_child ("op 0", TREE_OPERAND (t
, 0));
301 dump_child ("op 1", TREE_OPERAND (t
, 1));
305 /* These nodes are handled explicitly below. */
314 /* All declarations have names. */
316 dump_child ("name", DECL_NAME (t
));
317 if (DECL_ASSEMBLER_NAME_SET_P (t
)
318 && DECL_ASSEMBLER_NAME (t
) != DECL_NAME (t
))
319 dump_child ("mngl", DECL_ASSEMBLER_NAME (t
));
321 queue_and_dump_type (di
, t
);
322 dump_child ("scpe", DECL_CONTEXT (t
));
323 /* And a source position. */
324 if (DECL_SOURCE_FILE (t
))
326 const char *filename
= strrchr (DECL_SOURCE_FILE (t
), '/');
328 filename
= DECL_SOURCE_FILE (t
);
330 /* Skip the slash. */
333 dump_maybe_newline (di
);
334 fprintf (di
->stream
, "srcp: %s:%-6d ", filename
,
335 DECL_SOURCE_LINE (t
));
336 di
->column
+= 6 + strlen (filename
) + 8;
338 /* And any declaration can be compiler-generated. */
339 if (DECL_ARTIFICIAL (t
))
340 dump_string (di
, "artificial");
341 if (TREE_CHAIN (t
) && !dump_flag (di
, TDF_SLIM
, NULL
))
342 dump_child ("chan", TREE_CHAIN (t
));
344 else if (code_class
== 't')
346 /* All types have qualifiers. */
347 int quals
= (*lang_hooks
.tree_dump
.type_quals
) (t
);
349 if (quals
!= TYPE_UNQUALIFIED
)
351 fprintf (di
->stream
, "qual: %c%c%c ",
352 (quals
& TYPE_QUAL_CONST
) ? 'c' : ' ',
353 (quals
& TYPE_QUAL_VOLATILE
) ? 'v' : ' ',
354 (quals
& TYPE_QUAL_RESTRICT
) ? 'r' : ' ');
358 /* All types have associated declarations. */
359 dump_child ("name", TYPE_NAME (t
));
361 /* All types have a main variant. */
362 if (TYPE_MAIN_VARIANT (t
) != t
)
363 dump_child ("unql", TYPE_MAIN_VARIANT (t
));
366 dump_child ("size", TYPE_SIZE (t
));
368 /* All types have alignments. */
369 dump_int (di
, "algn", TYPE_ALIGN (t
));
371 else if (code_class
== 'c')
372 /* All constants can have types. */
373 queue_and_dump_type (di
, t
);
375 /* Give the language-specific code a chance to print something. If
376 it's completely taken care of things, don't bother printing
377 anything more ourselves. */
378 if ((*lang_hooks
.tree_dump
.dump_tree
) (di
, t
))
381 /* Now handle the various kinds of nodes. */
386 case IDENTIFIER_NODE
:
387 dump_string_field (di
, "strg", IDENTIFIER_POINTER (t
));
388 dump_int (di
, "lngt", IDENTIFIER_LENGTH (t
));
392 dump_child ("purp", TREE_PURPOSE (t
));
393 dump_child ("valu", TREE_VALUE (t
));
394 dump_child ("chan", TREE_CHAIN (t
));
398 dump_int (di
, "lngt", TREE_VEC_LENGTH (t
));
399 for (i
= 0; i
< TREE_VEC_LENGTH (t
); ++i
)
402 sprintf (buffer
, "%u", i
);
403 dump_child (buffer
, TREE_VEC_ELT (t
, i
));
409 dump_int (di
, "prec", TYPE_PRECISION (t
));
410 if (TREE_UNSIGNED (t
))
411 dump_string (di
, "unsigned");
412 dump_child ("min", TYPE_MIN_VALUE (t
));
413 dump_child ("max", TYPE_MAX_VALUE (t
));
415 if (code
== ENUMERAL_TYPE
)
416 dump_child ("csts", TYPE_VALUES (t
));
420 dump_int (di
, "prec", TYPE_PRECISION (t
));
424 dump_child ("ptd", TREE_TYPE (t
));
428 dump_child ("refd", TREE_TYPE (t
));
432 dump_child ("clas", TYPE_METHOD_BASETYPE (t
));
436 dump_child ("retn", TREE_TYPE (t
));
437 dump_child ("prms", TYPE_ARG_TYPES (t
));
441 dump_child ("elts", TREE_TYPE (t
));
442 dump_child ("domn", TYPE_DOMAIN (t
));
447 if (TREE_CODE (t
) == RECORD_TYPE
)
448 dump_string (di
, "struct");
450 dump_string (di
, "union");
452 dump_child ("flds", TYPE_FIELDS (t
));
453 dump_child ("fncs", TYPE_METHODS (t
));
454 queue_and_dump_index (di
, "binf", TYPE_BINFO (t
),
459 dump_child ("cnst", DECL_INITIAL (t
));
466 if (TREE_CODE (t
) == PARM_DECL
)
467 dump_child ("argt", DECL_ARG_TYPE (t
));
469 dump_child ("init", DECL_INITIAL (t
));
470 dump_child ("size", DECL_SIZE (t
));
471 dump_int (di
, "algn", DECL_ALIGN (t
));
473 if (TREE_CODE (t
) == FIELD_DECL
)
475 if (DECL_FIELD_OFFSET (t
))
476 dump_child ("bpos", bit_position (t
));
478 else if (TREE_CODE (t
) == VAR_DECL
479 || TREE_CODE (t
) == PARM_DECL
)
481 dump_int (di
, "used", TREE_USED (t
));
482 if (DECL_REGISTER (t
))
483 dump_string (di
, "register");
488 dump_child ("args", DECL_ARGUMENTS (t
));
489 if (DECL_EXTERNAL (t
))
490 dump_string (di
, "undefined");
492 dump_string (di
, "extern");
494 dump_string (di
, "static");
495 if (DECL_LANG_SPECIFIC (t
) && !dump_flag (di
, TDF_SLIM
, t
))
496 dump_child ("body", DECL_SAVED_TREE (t
));
500 if (TREE_INT_CST_HIGH (t
))
501 dump_int (di
, "high", TREE_INT_CST_HIGH (t
));
502 dump_int (di
, "low", TREE_INT_CST_LOW (t
));
506 fprintf (di
->stream
, "strg: %-7s ", TREE_STRING_POINTER (t
));
507 dump_int (di
, "lngt", TREE_STRING_LENGTH (t
));
513 case CLEANUP_POINT_EXPR
:
515 /* These nodes are unary, but do not have code class `1'. */
516 dump_child ("op 0", TREE_OPERAND (t
, 0));
519 case TRUTH_ANDIF_EXPR
:
520 case TRUTH_ORIF_EXPR
:
526 case PREDECREMENT_EXPR
:
527 case PREINCREMENT_EXPR
:
528 case POSTDECREMENT_EXPR
:
529 case POSTINCREMENT_EXPR
:
530 /* These nodes are binary, but do not have code class `2'. */
531 dump_child ("op 0", TREE_OPERAND (t
, 0));
532 dump_child ("op 1", TREE_OPERAND (t
, 1));
536 dump_child ("op 0", TREE_OPERAND (t
, 0));
537 dump_child ("op 1", TREE_OPERAND (t
, 1));
538 dump_child ("op 2", TREE_OPERAND (t
, 2));
542 dump_child ("fn", TREE_OPERAND (t
, 0));
543 dump_child ("args", TREE_OPERAND (t
, 1));
547 dump_child ("elts", CONSTRUCTOR_ELTS (t
));
551 dump_child ("vars", TREE_OPERAND (t
, 0));
552 dump_child ("body", TREE_OPERAND (t
, 1));
556 dump_child ("body", TREE_OPERAND (t
, 0));
560 dump_child ("cond", TREE_OPERAND (t
, 0));
564 dump_child ("decl", TREE_OPERAND (t
, 0));
565 dump_child ("init", TREE_OPERAND (t
, 1));
566 dump_child ("clnp", TREE_OPERAND (t
, 2));
567 /* There really are two possible places the initializer can be.
568 After RTL expansion, the second operand is moved to the
569 position of the fourth operand, and the second operand
571 dump_child ("init", TREE_OPERAND (t
, 3));
574 case EXPR_WITH_FILE_LOCATION
:
575 dump_child ("expr", EXPR_WFL_NODE (t
));
579 /* There are no additional fields to print. */
584 if (dump_flag (di
, TDF_ADDRESS
, NULL
))
585 dump_pointer (di
, "addr", (void *)t
);
587 /* Terminate the line. */
588 fprintf (di
->stream
, "\n");
591 /* Return nonzero if FLAG has been specified for the dump, and NODE
592 is not the root node of the dump. */
594 int dump_flag (dump_info_p di
, int flag
, tree node
)
596 return (di
->flags
& flag
) && (node
!= di
->node
);
599 /* Dump T, and all its children, on STREAM. */
602 dump_node (tree t
, int flags
, FILE *stream
)
606 dump_queue_p next_dq
;
608 /* Initialize the dump-information structure. */
617 di
.nodes
= splay_tree_new (splay_tree_compare_pointers
, 0,
618 (splay_tree_delete_value_fn
) &free
);
620 /* Queue up the first node. */
621 queue (&di
, t
, DUMP_NONE
);
623 /* Until the queue is empty, keep dumping nodes. */
625 dequeue_and_dump (&di
);
628 for (dq
= di
.free_list
; dq
; dq
= next_dq
)
633 splay_tree_delete (di
.nodes
);
636 /* Define a tree dump switch. */
637 struct dump_file_info
639 const char *const suffix
; /* suffix to give output file. */
640 const char *const swtch
; /* command line switch */
641 int flags
; /* user flags */
642 int state
; /* state of play */
645 /* Table of tree dump switches. This must be consistent with the
646 TREE_DUMP_INDEX enumeration in tree.h */
647 static struct dump_file_info dump_files
[TDI_end
] =
649 {".tu", "translation-unit", 0, 0},
650 {".class", "class-hierarchy", 0, 0},
651 {".original", "tree-original", 0, 0},
652 {".optimized", "tree-optimized", 0, 0},
653 {".inlined", "tree-inlined", 0, 0},
656 /* Define a name->number mapping for a dump flag value. */
657 struct dump_option_value_info
659 const char *const name
; /* the name of the value */
660 const int value
; /* the value of the name */
663 /* Table of dump options. This must be consistent with the TDF_* flags
665 static const struct dump_option_value_info dump_options
[] =
667 {"address", TDF_ADDRESS
},
673 /* Begin a tree dump for PHASE. Stores any user supplied flag in
674 *FLAG_PTR and returns a stream to write to. If the dump is not
675 enabled, returns NULL.
676 Multiple calls will reopen and append to the dump file. */
679 dump_begin (enum tree_dump_index phase
, int *flag_ptr
)
684 if (!dump_files
[phase
].state
)
687 name
= concat (dump_base_name
, dump_files
[phase
].suffix
, NULL
);
688 stream
= fopen (name
, dump_files
[phase
].state
< 0 ? "w" : "a");
690 error ("could not open dump file `%s'", name
);
692 dump_files
[phase
].state
= 1;
695 *flag_ptr
= dump_files
[phase
].flags
;
700 /* Returns nonzero if tree dump PHASE is enabled. */
703 dump_enabled_p (enum tree_dump_index phase
)
705 return dump_files
[phase
].state
;
708 /* Returns the switch name of PHASE. */
711 dump_flag_name (enum tree_dump_index phase
)
713 return dump_files
[phase
].swtch
;
716 /* Finish a tree dump for PHASE. STREAM is the stream created by
720 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED
, FILE *stream
)
725 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
726 relevant details in the dump_files array. */
729 dump_switch_p (const char *arg
)
732 const char *option_value
;
734 for (ix
= 0; ix
!= TDI_end
; ix
++)
735 if ((option_value
= skip_leading_substring (arg
, dump_files
[ix
].swtch
)))
737 const char *ptr
= option_value
;
742 const struct dump_option_value_info
*option_ptr
;
748 end_ptr
= strchr (ptr
, '-');
750 end_ptr
= ptr
+ strlen (ptr
);
751 length
= end_ptr
- ptr
;
753 for (option_ptr
= dump_options
; option_ptr
->name
;
755 if (strlen (option_ptr
->name
) == length
756 && !memcmp (option_ptr
->name
, ptr
, length
))
758 flags
|= option_ptr
->value
;
761 warning ("ignoring unknown option `%.*s' in `-fdump-%s'",
762 length
, ptr
, dump_files
[ix
].swtch
);
767 dump_files
[ix
].state
= -1;
768 dump_files
[ix
].flags
= flags
;