2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / gcc / tree-dump.c
blob6f958cf90fd45feb75429ce66a272e123f991bf4
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 case 'r':
306 case 's':
307 /* These nodes are handled explicitly below. */
308 break;
310 default:
311 abort ();
314 else if (DECL_P (t))
316 /* All declarations have names. */
317 if (DECL_NAME (t))
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));
322 /* And types. */
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), '/');
329 if (!filename)
330 filename = DECL_SOURCE_FILE (t);
331 else
332 /* Skip the slash. */
333 ++filename;
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' : ' ');
357 di->column += 14;
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));
367 /* And sizes. */
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))
381 goto done;
383 /* Now handle the various kinds of nodes. */
384 switch (code)
386 int i;
388 case IDENTIFIER_NODE:
389 dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
390 dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
391 break;
393 case TREE_LIST:
394 dump_child ("purp", TREE_PURPOSE (t));
395 dump_child ("valu", TREE_VALUE (t));
396 dump_child ("chan", TREE_CHAIN (t));
397 break;
399 case TREE_VEC:
400 dump_int (di, "lngt", TREE_VEC_LENGTH (t));
401 for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
403 char buffer[32];
404 sprintf (buffer, "%u", i);
405 dump_child (buffer, TREE_VEC_ELT (t, i));
407 break;
409 case INTEGER_TYPE:
410 case ENUMERAL_TYPE:
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));
419 break;
421 case REAL_TYPE:
422 dump_int (di, "prec", TYPE_PRECISION (t));
423 break;
425 case POINTER_TYPE:
426 dump_child ("ptd", TREE_TYPE (t));
427 break;
429 case REFERENCE_TYPE:
430 dump_child ("refd", TREE_TYPE (t));
431 break;
433 case METHOD_TYPE:
434 dump_child ("clas", TYPE_METHOD_BASETYPE (t));
435 /* Fall through. */
437 case FUNCTION_TYPE:
438 dump_child ("retn", TREE_TYPE (t));
439 dump_child ("prms", TYPE_ARG_TYPES (t));
440 break;
442 case ARRAY_TYPE:
443 dump_child ("elts", TREE_TYPE (t));
444 dump_child ("domn", TYPE_DOMAIN (t));
445 break;
447 case RECORD_TYPE:
448 case UNION_TYPE:
449 if (TREE_CODE (t) == RECORD_TYPE)
450 dump_string (di, "struct");
451 else
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),
457 DUMP_BINFO);
458 break;
460 case CONST_DECL:
461 dump_child ("cnst", DECL_INITIAL (t));
462 break;
464 case VAR_DECL:
465 case PARM_DECL:
466 case FIELD_DECL:
467 case RESULT_DECL:
468 if (TREE_CODE (t) == PARM_DECL)
469 dump_child ("argt", DECL_ARG_TYPE (t));
470 else
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");
487 break;
489 case FUNCTION_DECL:
490 dump_child ("args", DECL_ARGUMENTS (t));
491 if (DECL_EXTERNAL (t))
492 dump_string (di, "undefined");
493 if (TREE_PUBLIC (t))
494 dump_string (di, "extern");
495 else
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));
499 break;
501 case INTEGER_CST:
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));
505 break;
507 case STRING_CST:
508 fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
509 dump_int (di, "lngt", TREE_STRING_LENGTH (t));
510 break;
512 case TRUTH_NOT_EXPR:
513 case ADDR_EXPR:
514 case INDIRECT_REF:
515 case CLEANUP_POINT_EXPR:
516 case SAVE_EXPR:
517 /* These nodes are unary, but do not have code class `1'. */
518 dump_child ("op 0", TREE_OPERAND (t, 0));
519 break;
521 case TRUTH_ANDIF_EXPR:
522 case TRUTH_ORIF_EXPR:
523 case INIT_EXPR:
524 case MODIFY_EXPR:
525 case COMPONENT_REF:
526 case COMPOUND_EXPR:
527 case ARRAY_REF:
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));
535 break;
537 case COND_EXPR:
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));
541 break;
543 case CALL_EXPR:
544 dump_child ("fn", TREE_OPERAND (t, 0));
545 dump_child ("args", TREE_OPERAND (t, 1));
546 break;
548 case CONSTRUCTOR:
549 dump_child ("elts", CONSTRUCTOR_ELTS (t));
550 break;
552 case BIND_EXPR:
553 dump_child ("vars", TREE_OPERAND (t, 0));
554 dump_child ("body", TREE_OPERAND (t, 1));
555 break;
557 case LOOP_EXPR:
558 dump_child ("body", TREE_OPERAND (t, 0));
559 break;
561 case EXIT_EXPR:
562 dump_child ("cond", TREE_OPERAND (t, 0));
563 break;
565 case TARGET_EXPR:
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
572 becomes NULL. */
573 dump_child ("init", TREE_OPERAND (t, 3));
574 break;
576 case EXPR_WITH_FILE_LOCATION:
577 dump_child ("expr", EXPR_WFL_NODE (t));
578 break;
580 default:
581 /* There are no additional fields to print. */
582 break;
585 done:
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. */
603 void
604 dump_node (tree t, int flags, FILE *stream)
606 struct dump_info di;
607 dump_queue_p dq;
608 dump_queue_p next_dq;
610 /* Initialize the dump-information structure. */
611 di.stream = stream;
612 di.index = 0;
613 di.column = 0;
614 di.queue = 0;
615 di.queue_end = 0;
616 di.free_list = 0;
617 di.flags = flags;
618 di.node = t;
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. */
626 while (di.queue)
627 dequeue_and_dump (&di);
629 /* Now, clean up. */
630 for (dq = di.free_list; dq; dq = next_dq)
632 next_dq = dq->next;
633 free (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
666 in tree.h */
667 static const struct dump_option_value_info dump_options[] =
669 {"address", TDF_ADDRESS},
670 {"slim", TDF_SLIM},
671 {"all", ~0},
672 {NULL, 0}
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. */
680 FILE *
681 dump_begin (enum tree_dump_index phase, int *flag_ptr)
683 FILE *stream;
684 char *name;
686 if (!dump_files[phase].state)
687 return NULL;
689 name = concat (dump_base_name, dump_files[phase].suffix, NULL);
690 stream = fopen (name, dump_files[phase].state < 0 ? "w" : "a");
691 if (!stream)
692 error ("could not open dump file `%s'", name);
693 else
694 dump_files[phase].state = 1;
695 free (name);
696 if (flag_ptr)
697 *flag_ptr = dump_files[phase].flags;
699 return stream;
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. */
712 const char *
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
719 dump_begin. */
721 void
722 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
724 fclose (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)
733 unsigned ix;
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;
740 int flags = 0;
742 while (*ptr)
744 const struct dump_option_value_info *option_ptr;
745 const char *end_ptr;
746 unsigned length;
748 while (*ptr == '-')
749 ptr++;
750 end_ptr = strchr (ptr, '-');
751 if (!end_ptr)
752 end_ptr = ptr + strlen (ptr);
753 length = end_ptr - ptr;
755 for (option_ptr = dump_options; option_ptr->name;
756 option_ptr++)
757 if (strlen (option_ptr->name) == length
758 && !memcmp (option_ptr->name, ptr, length))
760 flags |= option_ptr->value;
761 goto found;
763 warning ("ignoring unknown option `%.*s' in `-fdump-%s'",
764 length, ptr, dump_files[ix].swtch);
765 found:;
766 ptr = end_ptr;
769 dump_files[ix].state = -1;
770 dump_files[ix].flags = flags;
772 return 1;
774 return 0;