1 /* Tree-dumping functionality for intermediate representation.
2 Copyright (C) 1999, 2000, 2002, 2003, 2004 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));
307 /* These nodes are handled explicitly below. */
316 /* All declarations have names. */
318 dump_child ("name", DECL_NAME (t
));
319 if (DECL_ASSEMBLER_NAME_SET_P (t
)
320 && DECL_ASSEMBLER_NAME (t
) != DECL_NAME (t
))
321 dump_child ("mngl", DECL_ASSEMBLER_NAME (t
));
323 queue_and_dump_type (di
, t
);
324 dump_child ("scpe", DECL_CONTEXT (t
));
325 /* And a source position. */
326 if (DECL_SOURCE_FILE (t
))
328 const char *filename
= strrchr (DECL_SOURCE_FILE (t
), '/');
330 filename
= DECL_SOURCE_FILE (t
);
332 /* Skip the slash. */
335 dump_maybe_newline (di
);
336 fprintf (di
->stream
, "srcp: %s:%-6d ", filename
,
337 DECL_SOURCE_LINE (t
));
338 di
->column
+= 6 + strlen (filename
) + 8;
340 /* And any declaration can be compiler-generated. */
341 if (DECL_ARTIFICIAL (t
))
342 dump_string (di
, "artificial");
343 if (TREE_CHAIN (t
) && !dump_flag (di
, TDF_SLIM
, NULL
))
344 dump_child ("chan", TREE_CHAIN (t
));
346 else if (code_class
== 't')
348 /* All types have qualifiers. */
349 int quals
= lang_hooks
.tree_dump
.type_quals (t
);
351 if (quals
!= TYPE_UNQUALIFIED
)
353 fprintf (di
->stream
, "qual: %c%c%c ",
354 (quals
& TYPE_QUAL_CONST
) ? 'c' : ' ',
355 (quals
& TYPE_QUAL_VOLATILE
) ? 'v' : ' ',
356 (quals
& TYPE_QUAL_RESTRICT
) ? 'r' : ' ');
360 /* All types have associated declarations. */
361 dump_child ("name", TYPE_NAME (t
));
363 /* All types have a main variant. */
364 if (TYPE_MAIN_VARIANT (t
) != t
)
365 dump_child ("unql", TYPE_MAIN_VARIANT (t
));
368 dump_child ("size", TYPE_SIZE (t
));
370 /* All types have alignments. */
371 dump_int (di
, "algn", TYPE_ALIGN (t
));
373 else if (code_class
== 'c')
374 /* All constants can have types. */
375 queue_and_dump_type (di
, t
);
377 /* Give the language-specific code a chance to print something. If
378 it's completely taken care of things, don't bother printing
379 anything more ourselves. */
380 if (lang_hooks
.tree_dump
.dump_tree (di
, t
))
383 /* Now handle the various kinds of nodes. */
388 case IDENTIFIER_NODE
:
389 dump_string_field (di
, "strg", IDENTIFIER_POINTER (t
));
390 dump_int (di
, "lngt", IDENTIFIER_LENGTH (t
));
394 dump_child ("purp", TREE_PURPOSE (t
));
395 dump_child ("valu", TREE_VALUE (t
));
396 dump_child ("chan", TREE_CHAIN (t
));
400 dump_int (di
, "lngt", TREE_VEC_LENGTH (t
));
401 for (i
= 0; i
< TREE_VEC_LENGTH (t
); ++i
)
404 sprintf (buffer
, "%u", i
);
405 dump_child (buffer
, TREE_VEC_ELT (t
, i
));
411 dump_int (di
, "prec", TYPE_PRECISION (t
));
412 if (TREE_UNSIGNED (t
))
413 dump_string (di
, "unsigned");
414 dump_child ("min", TYPE_MIN_VALUE (t
));
415 dump_child ("max", TYPE_MAX_VALUE (t
));
417 if (code
== ENUMERAL_TYPE
)
418 dump_child ("csts", TYPE_VALUES (t
));
422 dump_int (di
, "prec", TYPE_PRECISION (t
));
426 dump_child ("ptd", TREE_TYPE (t
));
430 dump_child ("refd", TREE_TYPE (t
));
434 dump_child ("clas", TYPE_METHOD_BASETYPE (t
));
438 dump_child ("retn", TREE_TYPE (t
));
439 dump_child ("prms", TYPE_ARG_TYPES (t
));
443 dump_child ("elts", TREE_TYPE (t
));
444 dump_child ("domn", TYPE_DOMAIN (t
));
449 if (TREE_CODE (t
) == RECORD_TYPE
)
450 dump_string (di
, "struct");
452 dump_string (di
, "union");
454 dump_child ("flds", TYPE_FIELDS (t
));
455 dump_child ("fncs", TYPE_METHODS (t
));
456 queue_and_dump_index (di
, "binf", TYPE_BINFO (t
),
461 dump_child ("cnst", DECL_INITIAL (t
));
468 if (TREE_CODE (t
) == PARM_DECL
)
469 dump_child ("argt", DECL_ARG_TYPE (t
));
471 dump_child ("init", DECL_INITIAL (t
));
472 dump_child ("size", DECL_SIZE (t
));
473 dump_int (di
, "algn", DECL_ALIGN (t
));
475 if (TREE_CODE (t
) == FIELD_DECL
)
477 if (DECL_FIELD_OFFSET (t
))
478 dump_child ("bpos", bit_position (t
));
480 else if (TREE_CODE (t
) == VAR_DECL
481 || TREE_CODE (t
) == PARM_DECL
)
483 dump_int (di
, "used", TREE_USED (t
));
484 if (DECL_REGISTER (t
))
485 dump_string (di
, "register");
490 dump_child ("args", DECL_ARGUMENTS (t
));
491 if (DECL_EXTERNAL (t
))
492 dump_string (di
, "undefined");
494 dump_string (di
, "extern");
496 dump_string (di
, "static");
497 if (DECL_LANG_SPECIFIC (t
) && !dump_flag (di
, TDF_SLIM
, t
))
498 dump_child ("body", DECL_SAVED_TREE (t
));
502 if (TREE_INT_CST_HIGH (t
))
503 dump_int (di
, "high", TREE_INT_CST_HIGH (t
));
504 dump_int (di
, "low", TREE_INT_CST_LOW (t
));
508 fprintf (di
->stream
, "strg: %-7s ", TREE_STRING_POINTER (t
));
509 dump_int (di
, "lngt", TREE_STRING_LENGTH (t
));
515 case CLEANUP_POINT_EXPR
:
517 /* These nodes are unary, but do not have code class `1'. */
518 dump_child ("op 0", TREE_OPERAND (t
, 0));
521 case TRUTH_ANDIF_EXPR
:
522 case TRUTH_ORIF_EXPR
:
528 case PREDECREMENT_EXPR
:
529 case PREINCREMENT_EXPR
:
530 case POSTDECREMENT_EXPR
:
531 case POSTINCREMENT_EXPR
:
532 /* These nodes are binary, but do not have code class `2'. */
533 dump_child ("op 0", TREE_OPERAND (t
, 0));
534 dump_child ("op 1", TREE_OPERAND (t
, 1));
538 dump_child ("op 0", TREE_OPERAND (t
, 0));
539 dump_child ("op 1", TREE_OPERAND (t
, 1));
540 dump_child ("op 2", TREE_OPERAND (t
, 2));
544 dump_child ("fn", TREE_OPERAND (t
, 0));
545 dump_child ("args", TREE_OPERAND (t
, 1));
549 dump_child ("elts", CONSTRUCTOR_ELTS (t
));
553 dump_child ("vars", TREE_OPERAND (t
, 0));
554 dump_child ("body", TREE_OPERAND (t
, 1));
558 dump_child ("body", TREE_OPERAND (t
, 0));
562 dump_child ("cond", TREE_OPERAND (t
, 0));
566 dump_child ("decl", TREE_OPERAND (t
, 0));
567 dump_child ("init", TREE_OPERAND (t
, 1));
568 dump_child ("clnp", TREE_OPERAND (t
, 2));
569 /* There really are two possible places the initializer can be.
570 After RTL expansion, the second operand is moved to the
571 position of the fourth operand, and the second operand
573 dump_child ("init", TREE_OPERAND (t
, 3));
576 case EXPR_WITH_FILE_LOCATION
:
577 dump_child ("expr", EXPR_WFL_NODE (t
));
581 /* There are no additional fields to print. */
586 if (dump_flag (di
, TDF_ADDRESS
, NULL
))
587 dump_pointer (di
, "addr", (void *)t
);
589 /* Terminate the line. */
590 fprintf (di
->stream
, "\n");
593 /* Return nonzero if FLAG has been specified for the dump, and NODE
594 is not the root node of the dump. */
596 int dump_flag (dump_info_p di
, int flag
, tree node
)
598 return (di
->flags
& flag
) && (node
!= di
->node
);
601 /* Dump T, and all its children, on STREAM. */
604 dump_node (tree t
, int flags
, FILE *stream
)
608 dump_queue_p next_dq
;
610 /* Initialize the dump-information structure. */
619 di
.nodes
= splay_tree_new (splay_tree_compare_pointers
, 0,
620 (splay_tree_delete_value_fn
) &free
);
622 /* Queue up the first node. */
623 queue (&di
, t
, DUMP_NONE
);
625 /* Until the queue is empty, keep dumping nodes. */
627 dequeue_and_dump (&di
);
630 for (dq
= di
.free_list
; dq
; dq
= next_dq
)
635 splay_tree_delete (di
.nodes
);
638 /* Define a tree dump switch. */
639 struct dump_file_info
641 const char *const suffix
; /* suffix to give output file. */
642 const char *const swtch
; /* command line switch */
643 int flags
; /* user flags */
644 int state
; /* state of play */
647 /* Table of tree dump switches. This must be consistent with the
648 TREE_DUMP_INDEX enumeration in tree.h */
649 static struct dump_file_info dump_files
[TDI_end
] =
651 {".tu", "translation-unit", 0, 0},
652 {".class", "class-hierarchy", 0, 0},
653 {".original", "tree-original", 0, 0},
654 {".optimized", "tree-optimized", 0, 0},
655 {".inlined", "tree-inlined", 0, 0},
658 /* Define a name->number mapping for a dump flag value. */
659 struct dump_option_value_info
661 const char *const name
; /* the name of the value */
662 const int value
; /* the value of the name */
665 /* Table of dump options. This must be consistent with the TDF_* flags
667 static const struct dump_option_value_info dump_options
[] =
669 {"address", TDF_ADDRESS
},
675 /* Begin a tree dump for PHASE. Stores any user supplied flag in
676 *FLAG_PTR and returns a stream to write to. If the dump is not
677 enabled, returns NULL.
678 Multiple calls will reopen and append to the dump file. */
681 dump_begin (enum tree_dump_index phase
, int *flag_ptr
)
686 if (!dump_files
[phase
].state
)
689 name
= concat (dump_base_name
, dump_files
[phase
].suffix
, NULL
);
690 stream
= fopen (name
, dump_files
[phase
].state
< 0 ? "w" : "a");
692 error ("could not open dump file `%s'", name
);
694 dump_files
[phase
].state
= 1;
697 *flag_ptr
= dump_files
[phase
].flags
;
702 /* Returns nonzero if tree dump PHASE is enabled. */
705 dump_enabled_p (enum tree_dump_index phase
)
707 return dump_files
[phase
].state
;
710 /* Returns the switch name of PHASE. */
713 dump_flag_name (enum tree_dump_index phase
)
715 return dump_files
[phase
].swtch
;
718 /* Finish a tree dump for PHASE. STREAM is the stream created by
722 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED
, FILE *stream
)
727 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
728 relevant details in the dump_files array. */
731 dump_switch_p (const char *arg
)
734 const char *option_value
;
736 for (ix
= 0; ix
!= TDI_end
; ix
++)
737 if ((option_value
= skip_leading_substring (arg
, dump_files
[ix
].swtch
)))
739 const char *ptr
= option_value
;
744 const struct dump_option_value_info
*option_ptr
;
750 end_ptr
= strchr (ptr
, '-');
752 end_ptr
= ptr
+ strlen (ptr
);
753 length
= end_ptr
- ptr
;
755 for (option_ptr
= dump_options
; option_ptr
->name
;
757 if (strlen (option_ptr
->name
) == length
758 && !memcmp (option_ptr
->name
, ptr
, length
))
760 flags
|= option_ptr
->value
;
763 warning ("ignoring unknown option `%.*s' in `-fdump-%s'",
764 length
, ptr
, dump_files
[ix
].swtch
);
769 dump_files
[ix
].state
= -1;
770 dump_files
[ix
].flags
= flags
;