2003-11-26 Michael Koch <konqueror@gmx.de>
[official-gcc.git] / gcc / tree-dump.c
blobc3696336c4465f6e4e044ba0f916a8ffc4da79ba
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
10 version.
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
15 for more details.
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
20 02111-1307, USA. */
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "tm.h"
26 #include "tree.h"
27 #include "splay-tree.h"
28 #include "diagnostic.h"
29 #include "toplev.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
41 assigned to T. */
43 static unsigned int
44 queue (dump_info_p di, tree t, int flags)
46 dump_queue_p dq;
47 dump_node_info_p dni;
48 unsigned int index;
50 /* Assign the next available index to T. */
51 index = ++di->index;
53 /* Obtain a new queue node. */
54 if (di->free_list)
56 dq = di->free_list;
57 di->free_list = dq->next;
59 else
60 dq = xmalloc (sizeof (struct dump_queue));
62 /* Create a new entry in the splay-tree. */
63 dni = xmalloc (sizeof (struct dump_node_info));
64 dni->index = index;
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. */
70 dq->next = 0;
71 if (!di->queue_end)
72 di->queue = dq;
73 else
74 di->queue_end->next = dq;
75 di->queue_end = dq;
77 /* Return the index. */
78 return index;
81 static void
82 dump_index (dump_info_p di, unsigned int index)
84 fprintf (di->stream, "@%-6u ", index);
85 di->column += 8;
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. */
92 void
93 queue_and_dump_index (dump_info_p di, const char *field, tree t, int flags)
95 unsigned int index;
96 splay_tree_node n;
98 /* If there's no node, just return. This makes for fewer checks in
99 our callers. */
100 if (!t)
101 return;
103 /* See if we've already queued or dumped this node. */
104 n = splay_tree_lookup (di->nodes, (splay_tree_key) t);
105 if (n)
106 index = ((dump_node_info_p) n->value)->index;
107 else
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);
114 di->column += 6;
115 dump_index (di, index);
118 /* Dump the type of T. */
120 void
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. */
134 static void
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. */
143 static void
144 dump_maybe_newline (dump_info_p di)
146 int extra;
148 /* See if we need a new line. */
149 if (di->column > EOL_COLUMN)
150 dump_new_line (di);
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. */
161 void
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);
166 di->column += 15;
169 /* Dump integer I using FIELD to identify it. */
171 void
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);
176 di->column += 14;
179 /* Dump the string S. */
181 void
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;
188 else
189 di->column += 14;
192 /* Dump the string field S. */
194 static void
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;
201 else
202 di->column += 14;
205 /* Dump the next node in the queue. */
207 static void
208 dequeue_and_dump (dump_info_p di)
210 dump_queue_p dq;
211 splay_tree_node stn;
212 dump_node_info_p dni;
213 tree t;
214 unsigned int index;
215 enum tree_code code;
216 char code_class;
217 const char* code_name;
219 /* Get the next node from the queue. */
220 dq = di->queue;
221 stn = dq->node;
222 t = (tree) stn->key;
223 dni = (dump_node_info_p) stn->value;
224 index = dni->index;
226 /* Remove the node from the queue, and put it on the free list. */
227 di->queue = dq->next;
228 if (!di->queue)
229 di->queue_end = 0;
230 dq->next = di->free_list;
231 di->free_list = dq;
233 /* Print the node index. */
234 dump_index (di, index);
235 /* And the type of node this is. */
236 if (dni->binfo_p)
237 code_name = "binfo";
238 else
239 code_name = tree_code_name[(int) TREE_CODE (t)];
240 fprintf (di->stream, "%-16s ", code_name);
241 di->column = 25;
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
248 more informative. */
249 if (dni->binfo_p)
251 unsigned ix;
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)
270 string = "pub";
271 else if (access == access_protected_node)
272 string = "prot";
273 else if (access == access_private_node)
274 string = "priv";
275 else
276 abort ();
278 dump_string (di, string);
279 queue_and_dump_index (di, "binf", base, DUMP_BINFO);
282 goto done;
285 /* We can knock off a bunch of expression nodes in exactly the same
286 way. */
287 if (IS_EXPR_CODE_CLASS (code_class))
289 /* If we're dumping children, dump them now. */
290 queue_and_dump_type (di, t);
292 switch (code_class)
294 case '1':
295 dump_child ("op 0", TREE_OPERAND (t, 0));
296 break;
298 case '2':
299 case '<':
300 dump_child ("op 0", TREE_OPERAND (t, 0));
301 dump_child ("op 1", TREE_OPERAND (t, 1));
302 break;
304 case 'e':
305 /* These nodes are handled explicitly below. */
306 break;
308 default:
309 abort ();
312 else if (DECL_P (t))
314 /* All declarations have names. */
315 if (DECL_NAME (t))
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));
320 /* And types. */
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), '/');
327 if (!filename)
328 filename = DECL_SOURCE_FILE (t);
329 else
330 /* Skip the slash. */
331 ++filename;
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' : ' ');
355 di->column += 14;
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));
365 /* And sizes. */
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))
379 goto done;
381 /* Now handle the various kinds of nodes. */
382 switch (code)
384 int i;
386 case IDENTIFIER_NODE:
387 dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
388 dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
389 break;
391 case TREE_LIST:
392 dump_child ("purp", TREE_PURPOSE (t));
393 dump_child ("valu", TREE_VALUE (t));
394 dump_child ("chan", TREE_CHAIN (t));
395 break;
397 case TREE_VEC:
398 dump_int (di, "lngt", TREE_VEC_LENGTH (t));
399 for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
401 char buffer[32];
402 sprintf (buffer, "%u", i);
403 dump_child (buffer, TREE_VEC_ELT (t, i));
405 break;
407 case INTEGER_TYPE:
408 case ENUMERAL_TYPE:
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));
417 break;
419 case REAL_TYPE:
420 dump_int (di, "prec", TYPE_PRECISION (t));
421 break;
423 case POINTER_TYPE:
424 dump_child ("ptd", TREE_TYPE (t));
425 break;
427 case REFERENCE_TYPE:
428 dump_child ("refd", TREE_TYPE (t));
429 break;
431 case METHOD_TYPE:
432 dump_child ("clas", TYPE_METHOD_BASETYPE (t));
433 /* Fall through. */
435 case FUNCTION_TYPE:
436 dump_child ("retn", TREE_TYPE (t));
437 dump_child ("prms", TYPE_ARG_TYPES (t));
438 break;
440 case ARRAY_TYPE:
441 dump_child ("elts", TREE_TYPE (t));
442 dump_child ("domn", TYPE_DOMAIN (t));
443 break;
445 case RECORD_TYPE:
446 case UNION_TYPE:
447 if (TREE_CODE (t) == RECORD_TYPE)
448 dump_string (di, "struct");
449 else
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),
455 DUMP_BINFO);
456 break;
458 case CONST_DECL:
459 dump_child ("cnst", DECL_INITIAL (t));
460 break;
462 case VAR_DECL:
463 case PARM_DECL:
464 case FIELD_DECL:
465 case RESULT_DECL:
466 if (TREE_CODE (t) == PARM_DECL)
467 dump_child ("argt", DECL_ARG_TYPE (t));
468 else
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");
485 break;
487 case FUNCTION_DECL:
488 dump_child ("args", DECL_ARGUMENTS (t));
489 if (DECL_EXTERNAL (t))
490 dump_string (di, "undefined");
491 if (TREE_PUBLIC (t))
492 dump_string (di, "extern");
493 else
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));
497 break;
499 case INTEGER_CST:
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));
503 break;
505 case STRING_CST:
506 fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
507 dump_int (di, "lngt", TREE_STRING_LENGTH (t));
508 break;
510 case TRUTH_NOT_EXPR:
511 case ADDR_EXPR:
512 case INDIRECT_REF:
513 case CLEANUP_POINT_EXPR:
514 case SAVE_EXPR:
515 /* These nodes are unary, but do not have code class `1'. */
516 dump_child ("op 0", TREE_OPERAND (t, 0));
517 break;
519 case TRUTH_ANDIF_EXPR:
520 case TRUTH_ORIF_EXPR:
521 case INIT_EXPR:
522 case MODIFY_EXPR:
523 case COMPONENT_REF:
524 case COMPOUND_EXPR:
525 case ARRAY_REF:
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));
533 break;
535 case COND_EXPR:
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));
539 break;
541 case CALL_EXPR:
542 dump_child ("fn", TREE_OPERAND (t, 0));
543 dump_child ("args", TREE_OPERAND (t, 1));
544 break;
546 case CONSTRUCTOR:
547 dump_child ("elts", CONSTRUCTOR_ELTS (t));
548 break;
550 case BIND_EXPR:
551 dump_child ("vars", TREE_OPERAND (t, 0));
552 dump_child ("body", TREE_OPERAND (t, 1));
553 break;
555 case LOOP_EXPR:
556 dump_child ("body", TREE_OPERAND (t, 0));
557 break;
559 case EXIT_EXPR:
560 dump_child ("cond", TREE_OPERAND (t, 0));
561 break;
563 case TARGET_EXPR:
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
570 becomes NULL. */
571 dump_child ("init", TREE_OPERAND (t, 3));
572 break;
574 case EXPR_WITH_FILE_LOCATION:
575 dump_child ("expr", EXPR_WFL_NODE (t));
576 break;
578 default:
579 /* There are no additional fields to print. */
580 break;
583 done:
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. */
601 void
602 dump_node (tree t, int flags, FILE *stream)
604 struct dump_info di;
605 dump_queue_p dq;
606 dump_queue_p next_dq;
608 /* Initialize the dump-information structure. */
609 di.stream = stream;
610 di.index = 0;
611 di.column = 0;
612 di.queue = 0;
613 di.queue_end = 0;
614 di.free_list = 0;
615 di.flags = flags;
616 di.node = t;
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. */
624 while (di.queue)
625 dequeue_and_dump (&di);
627 /* Now, clean up. */
628 for (dq = di.free_list; dq; dq = next_dq)
630 next_dq = dq->next;
631 free (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
664 in tree.h */
665 static const struct dump_option_value_info dump_options[] =
667 {"address", TDF_ADDRESS},
668 {"slim", TDF_SLIM},
669 {"all", ~0},
670 {NULL, 0}
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. */
678 FILE *
679 dump_begin (enum tree_dump_index phase, int *flag_ptr)
681 FILE *stream;
682 char *name;
684 if (!dump_files[phase].state)
685 return NULL;
687 name = concat (dump_base_name, dump_files[phase].suffix, NULL);
688 stream = fopen (name, dump_files[phase].state < 0 ? "w" : "a");
689 if (!stream)
690 error ("could not open dump file `%s'", name);
691 else
692 dump_files[phase].state = 1;
693 free (name);
694 if (flag_ptr)
695 *flag_ptr = dump_files[phase].flags;
697 return stream;
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. */
710 const char *
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
717 dump_begin. */
719 void
720 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
722 fclose (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)
731 unsigned ix;
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;
738 int flags = 0;
740 while (*ptr)
742 const struct dump_option_value_info *option_ptr;
743 const char *end_ptr;
744 unsigned length;
746 while (*ptr == '-')
747 ptr++;
748 end_ptr = strchr (ptr, '-');
749 if (!end_ptr)
750 end_ptr = ptr + strlen (ptr);
751 length = end_ptr - ptr;
753 for (option_ptr = dump_options; option_ptr->name;
754 option_ptr++)
755 if (strlen (option_ptr->name) == length
756 && !memcmp (option_ptr->name, ptr, length))
758 flags |= option_ptr->value;
759 goto found;
761 warning ("ignoring unknown option `%.*s' in `-fdump-%s'",
762 length, ptr, dump_files[ix].swtch);
763 found:;
764 ptr = end_ptr;
767 dump_files[ix].state = -1;
768 dump_files[ix].flags = flags;
770 return 1;
772 return 0;