OSDN Git Service

2006-01-16 John David Anglin <dave.anglin@nrc-cnrc.gc.ca>
[pf3gnuchains/gcc-fork.git] / gcc / tree-dump.c
1 /* Tree-dumping functionality for intermediate representation.
2    Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005
3    Free Software Foundation, Inc.
4    Written by Mark Mitchell <mark@codesourcery.com>
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING.  If not, write to the Free
20 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.  */
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "tree.h"
28 #include "splay-tree.h"
29 #include "diagnostic.h"
30 #include "toplev.h"
31 #include "tree-dump.h"
32 #include "tree-pass.h"
33 #include "langhooks.h"
34 #include "tree-iterator.h"
35
36 static unsigned int queue (dump_info_p, tree, int);
37 static void dump_index (dump_info_p, unsigned int);
38 static void dequeue_and_dump (dump_info_p);
39 static void dump_new_line (dump_info_p);
40 static void dump_maybe_newline (dump_info_p);
41 static int dump_enable_all (int, int);
42
43 /* Add T to the end of the queue of nodes to dump.  Returns the index
44    assigned to T.  */
45
46 static unsigned int
47 queue (dump_info_p di, tree t, int flags)
48 {
49   dump_queue_p dq;
50   dump_node_info_p dni;
51   unsigned int index;
52
53   /* Assign the next available index to T.  */
54   index = ++di->index;
55
56   /* Obtain a new queue node.  */
57   if (di->free_list)
58     {
59       dq = di->free_list;
60       di->free_list = dq->next;
61     }
62   else
63     dq = xmalloc (sizeof (struct dump_queue));
64
65   /* Create a new entry in the splay-tree.  */
66   dni = xmalloc (sizeof (struct dump_node_info));
67   dni->index = index;
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);
71
72   /* Add it to the end of the queue.  */
73   dq->next = 0;
74   if (!di->queue_end)
75     di->queue = dq;
76   else
77     di->queue_end->next = dq;
78   di->queue_end = dq;
79
80   /* Return the index.  */
81   return index;
82 }
83
84 static void
85 dump_index (dump_info_p di, unsigned int index)
86 {
87   fprintf (di->stream, "@%-6u ", index);
88   di->column += 8;
89 }
90
91 /* If T has not already been output, queue it for subsequent output.
92    FIELD is a string to print before printing the index.  Then, the
93    index of T is printed.  */
94
95 void
96 queue_and_dump_index (dump_info_p di, const char *field, tree t, int flags)
97 {
98   unsigned int index;
99   splay_tree_node n;
100
101   /* If there's no node, just return.  This makes for fewer checks in
102      our callers.  */
103   if (!t)
104     return;
105
106   /* See if we've already queued or dumped this node.  */
107   n = splay_tree_lookup (di->nodes, (splay_tree_key) t);
108   if (n)
109     index = ((dump_node_info_p) n->value)->index;
110   else
111     /* If we haven't, add it to the queue.  */
112     index = queue (di, t, flags);
113
114   /* Print the index of the node.  */
115   dump_maybe_newline (di);
116   fprintf (di->stream, "%-4s: ", field);
117   di->column += 6;
118   dump_index (di, index);
119 }
120
121 /* Dump the type of T.  */
122
123 void
124 queue_and_dump_type (dump_info_p di, tree t)
125 {
126   queue_and_dump_index (di, "type", TREE_TYPE (t), DUMP_NONE);
127 }
128
129 /* Dump column control */
130 #define SOL_COLUMN 25           /* Start of line column.  */
131 #define EOL_COLUMN 55           /* End of line column.  */
132 #define COLUMN_ALIGNMENT 15     /* Alignment.  */
133
134 /* Insert a new line in the dump output, and indent to an appropriate
135    place to start printing more fields.  */
136
137 static void
138 dump_new_line (dump_info_p di)
139 {
140   fprintf (di->stream, "\n%*s", SOL_COLUMN, "");
141   di->column = SOL_COLUMN;
142 }
143
144 /* If necessary, insert a new line.  */
145
146 static void
147 dump_maybe_newline (dump_info_p di)
148 {
149   int extra;
150
151   /* See if we need a new line.  */
152   if (di->column > EOL_COLUMN)
153     dump_new_line (di);
154   /* See if we need any padding.  */
155   else if ((extra = (di->column - SOL_COLUMN) % COLUMN_ALIGNMENT) != 0)
156     {
157       fprintf (di->stream, "%*s", COLUMN_ALIGNMENT - extra, "");
158       di->column += COLUMN_ALIGNMENT - extra;
159     }
160 }
161
162 /* Dump pointer PTR using FIELD to identify it.  */
163
164 void
165 dump_pointer (dump_info_p di, const char *field, void *ptr)
166 {
167   dump_maybe_newline (di);
168   fprintf (di->stream, "%-4s: %-8lx ", field, (long) ptr);
169   di->column += 15;
170 }
171
172 /* Dump integer I using FIELD to identify it.  */
173
174 void
175 dump_int (dump_info_p di, const char *field, int i)
176 {
177   dump_maybe_newline (di);
178   fprintf (di->stream, "%-4s: %-7d ", field, i);
179   di->column += 14;
180 }
181
182 /* Dump the string S.  */
183
184 void
185 dump_string (dump_info_p di, const char *string)
186 {
187   dump_maybe_newline (di);
188   fprintf (di->stream, "%-13s ", string);
189   if (strlen (string) > 13)
190     di->column += strlen (string) + 1;
191   else
192     di->column += 14;
193 }
194
195 /* Dump the string field S.  */
196
197 void
198 dump_string_field (dump_info_p di, const char *field, const char *string)
199 {
200   dump_maybe_newline (di);
201   fprintf (di->stream, "%-4s: %-7s ", field, string);
202   if (strlen (string) > 7)
203     di->column += 6 + strlen (string) + 1;
204   else
205     di->column += 14;
206 }
207
208 /* Dump the next node in the queue.  */
209
210 static void
211 dequeue_and_dump (dump_info_p di)
212 {
213   dump_queue_p dq;
214   splay_tree_node stn;
215   dump_node_info_p dni;
216   tree t;
217   unsigned int index;
218   enum tree_code code;
219   enum tree_code_class code_class;
220   const char* code_name;
221
222   /* Get the next node from the queue.  */
223   dq = di->queue;
224   stn = dq->node;
225   t = (tree) stn->key;
226   dni = (dump_node_info_p) stn->value;
227   index = dni->index;
228
229   /* Remove the node from the queue, and put it on the free list.  */
230   di->queue = dq->next;
231   if (!di->queue)
232     di->queue_end = 0;
233   dq->next = di->free_list;
234   di->free_list = dq;
235
236   /* Print the node index.  */
237   dump_index (di, index);
238   /* And the type of node this is.  */
239   if (dni->binfo_p)
240     code_name = "binfo";
241   else
242     code_name = tree_code_name[(int) TREE_CODE (t)];
243   fprintf (di->stream, "%-16s ", code_name);
244   di->column = 25;
245
246   /* Figure out what kind of node this is.  */
247   code = TREE_CODE (t);
248   code_class = TREE_CODE_CLASS (code);
249
250   /* Although BINFOs are TREE_VECs, we dump them specially so as to be
251      more informative.  */
252   if (dni->binfo_p)
253     {
254       unsigned ix;
255       tree base;
256       VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (t);
257
258       dump_child ("type", BINFO_TYPE (t));
259
260       if (BINFO_VIRTUAL_P (t))
261         dump_string_field (di, "spec", "virt");
262
263       dump_int (di, "bases", BINFO_N_BASE_BINFOS (t));
264       for (ix = 0; BINFO_BASE_ITERATE (t, ix, base); ix++)
265         {
266           tree access = (accesses ? VEC_index (tree, accesses, ix)
267                          : access_public_node);
268           const char *string = NULL;
269
270           if (access == access_public_node)
271             string = "pub";
272           else if (access == access_protected_node)
273             string = "prot";
274           else if (access == access_private_node)
275             string = "priv";
276           else
277             gcc_unreachable ();
278
279           dump_string_field (di, "accs", string);
280           queue_and_dump_index (di, "binf", base, DUMP_BINFO);
281         }
282
283       goto done;
284     }
285
286   /* We can knock off a bunch of expression nodes in exactly the same
287      way.  */
288   if (IS_EXPR_CODE_CLASS (code_class))
289     {
290       /* If we're dumping children, dump them now.  */
291       queue_and_dump_type (di, t);
292
293       switch (code_class)
294         {
295         case tcc_unary:
296           dump_child ("op 0", TREE_OPERAND (t, 0));
297           break;
298
299         case tcc_binary:
300         case tcc_comparison:
301           dump_child ("op 0", TREE_OPERAND (t, 0));
302           dump_child ("op 1", TREE_OPERAND (t, 1));
303           break;
304
305         case tcc_expression:
306         case tcc_reference:
307         case tcc_statement:
308           /* These nodes are handled explicitly below.  */
309           break;
310
311         default:
312           gcc_unreachable ();
313         }
314     }
315   else if (DECL_P (t))
316     {
317       expanded_location xloc;
318       /* All declarations have names.  */
319       if (DECL_NAME (t))
320         dump_child ("name", DECL_NAME (t));
321       if (DECL_ASSEMBLER_NAME_SET_P (t)
322           && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t))
323         dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
324       if (DECL_ABSTRACT_ORIGIN (t))
325         dump_child ("orig", DECL_ABSTRACT_ORIGIN (t));
326       /* And types.  */
327       queue_and_dump_type (di, t);
328       dump_child ("scpe", DECL_CONTEXT (t));
329       /* And a source position.  */
330       xloc = expand_location (DECL_SOURCE_LOCATION (t));
331       if (xloc.file)
332         {
333           const char *filename = strrchr (xloc.file, '/');
334           if (!filename)
335             filename = xloc.file;
336           else
337             /* Skip the slash.  */
338             ++filename;
339
340           dump_maybe_newline (di);
341           fprintf (di->stream, "srcp: %s:%-6d ", filename,
342                    xloc.line);
343           di->column += 6 + strlen (filename) + 8;
344         }
345       /* And any declaration can be compiler-generated.  */
346       if (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_COMMON)
347           && DECL_ARTIFICIAL (t))
348         dump_string_field (di, "note", "artificial");
349       if (TREE_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
350         dump_child ("chan", TREE_CHAIN (t));
351     }
352   else if (code_class == tcc_type)
353     {
354       /* All types have qualifiers.  */
355       int quals = lang_hooks.tree_dump.type_quals (t);
356
357       if (quals != TYPE_UNQUALIFIED)
358         {
359           fprintf (di->stream, "qual: %c%c%c     ",
360                    (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
361                    (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
362                    (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
363           di->column += 14;
364         }
365
366       /* All types have associated declarations.  */
367       dump_child ("name", TYPE_NAME (t));
368
369       /* All types have a main variant.  */
370       if (TYPE_MAIN_VARIANT (t) != t)
371         dump_child ("unql", TYPE_MAIN_VARIANT (t));
372
373       /* And sizes.  */
374       dump_child ("size", TYPE_SIZE (t));
375
376       /* All types have alignments.  */
377       dump_int (di, "algn", TYPE_ALIGN (t));
378     }
379   else if (code_class == tcc_constant)
380     /* All constants can have types.  */
381     queue_and_dump_type (di, t);
382
383   /* Give the language-specific code a chance to print something.  If
384      it's completely taken care of things, don't bother printing
385      anything more ourselves.  */
386   if (lang_hooks.tree_dump.dump_tree (di, t))
387     goto done;
388
389   /* Now handle the various kinds of nodes.  */
390   switch (code)
391     {
392       int i;
393
394     case IDENTIFIER_NODE:
395       dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
396       dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
397       break;
398
399     case TREE_LIST:
400       dump_child ("purp", TREE_PURPOSE (t));
401       dump_child ("valu", TREE_VALUE (t));
402       dump_child ("chan", TREE_CHAIN (t));
403       break;
404
405     case STATEMENT_LIST:
406       {
407         tree_stmt_iterator it;
408         for (i = 0, it = tsi_start (t); !tsi_end_p (it); tsi_next (&it), i++)
409           {
410             char buffer[32];
411             sprintf (buffer, "%u", i);
412             dump_child (buffer, tsi_stmt (it));
413           }
414       }
415       break;
416
417     case TREE_VEC:
418       dump_int (di, "lngt", TREE_VEC_LENGTH (t));
419       for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
420         {
421           char buffer[32];
422           sprintf (buffer, "%u", i);
423           dump_child (buffer, TREE_VEC_ELT (t, i));
424         }
425       break;
426
427     case INTEGER_TYPE:
428     case ENUMERAL_TYPE:
429       dump_int (di, "prec", TYPE_PRECISION (t));
430       dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed");
431       dump_child ("min", TYPE_MIN_VALUE (t));
432       dump_child ("max", TYPE_MAX_VALUE (t));
433
434       if (code == ENUMERAL_TYPE)
435         dump_child ("csts", TYPE_VALUES (t));
436       break;
437
438     case REAL_TYPE:
439       dump_int (di, "prec", TYPE_PRECISION (t));
440       break;
441
442     case POINTER_TYPE:
443       dump_child ("ptd", TREE_TYPE (t));
444       break;
445
446     case REFERENCE_TYPE:
447       dump_child ("refd", TREE_TYPE (t));
448       break;
449
450     case METHOD_TYPE:
451       dump_child ("clas", TYPE_METHOD_BASETYPE (t));
452       /* Fall through.  */
453
454     case FUNCTION_TYPE:
455       dump_child ("retn", TREE_TYPE (t));
456       dump_child ("prms", TYPE_ARG_TYPES (t));
457       break;
458
459     case ARRAY_TYPE:
460       dump_child ("elts", TREE_TYPE (t));
461       dump_child ("domn", TYPE_DOMAIN (t));
462       break;
463
464     case RECORD_TYPE:
465     case UNION_TYPE:
466       if (TREE_CODE (t) == RECORD_TYPE)
467         dump_string_field (di, "tag", "struct");
468       else
469         dump_string_field (di, "tag", "union");
470
471       dump_child ("flds", TYPE_FIELDS (t));
472       dump_child ("fncs", TYPE_METHODS (t));
473       queue_and_dump_index (di, "binf", TYPE_BINFO (t),
474                             DUMP_BINFO);
475       break;
476
477     case CONST_DECL:
478       dump_child ("cnst", DECL_INITIAL (t));
479       break;
480       
481     case TYPE_MEMORY_TAG:
482     case NAME_MEMORY_TAG:
483     case STRUCT_FIELD_TAG:
484       break;
485
486     case VAR_DECL:
487     case PARM_DECL:
488     case FIELD_DECL:
489     case RESULT_DECL:
490       if (TREE_CODE (t) == PARM_DECL)
491         dump_child ("argt", DECL_ARG_TYPE (t));
492       else
493         dump_child ("init", DECL_INITIAL (t));
494       dump_child ("size", DECL_SIZE (t));
495       dump_int (di, "algn", DECL_ALIGN (t));
496
497       if (TREE_CODE (t) == FIELD_DECL)
498         {
499           if (DECL_FIELD_OFFSET (t))
500             dump_child ("bpos", bit_position (t));
501         }
502       else if (TREE_CODE (t) == VAR_DECL
503                || TREE_CODE (t) == PARM_DECL)
504         {
505           dump_int (di, "used", TREE_USED (t));
506           if (DECL_REGISTER (t))
507             dump_string_field (di, "spec", "register");
508         }
509       break;
510
511     case FUNCTION_DECL:
512       dump_child ("args", DECL_ARGUMENTS (t));
513       if (DECL_EXTERNAL (t))
514         dump_string_field (di, "body", "undefined");
515       if (TREE_PUBLIC (t))
516         dump_string_field (di, "link", "extern");
517       else
518         dump_string_field (di, "link", "static");
519       if (DECL_LANG_SPECIFIC (t) && !dump_flag (di, TDF_SLIM, t))
520         dump_child ("body", DECL_SAVED_TREE (t));
521       break;
522
523     case INTEGER_CST:
524       if (TREE_INT_CST_HIGH (t))
525         dump_int (di, "high", TREE_INT_CST_HIGH (t));
526       dump_int (di, "low", TREE_INT_CST_LOW (t));
527       break;
528
529     case STRING_CST:
530       fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
531       dump_int (di, "lngt", TREE_STRING_LENGTH (t));
532       break;
533
534     case TRUTH_NOT_EXPR:
535     case ADDR_EXPR:
536     case INDIRECT_REF:
537     case ALIGN_INDIRECT_REF:
538     case MISALIGNED_INDIRECT_REF:
539     case CLEANUP_POINT_EXPR:
540     case SAVE_EXPR:
541     case REALPART_EXPR:
542     case IMAGPART_EXPR:
543       /* These nodes are unary, but do not have code class `1'.  */
544       dump_child ("op 0", TREE_OPERAND (t, 0));
545       break;
546
547     case TRUTH_ANDIF_EXPR:
548     case TRUTH_ORIF_EXPR:
549     case INIT_EXPR:
550     case MODIFY_EXPR:
551     case COMPOUND_EXPR:
552     case PREDECREMENT_EXPR:
553     case PREINCREMENT_EXPR:
554     case POSTDECREMENT_EXPR:
555     case POSTINCREMENT_EXPR:
556       /* These nodes are binary, but do not have code class `2'.  */
557       dump_child ("op 0", TREE_OPERAND (t, 0));
558       dump_child ("op 1", TREE_OPERAND (t, 1));
559       break;
560
561     case COMPONENT_REF:
562       dump_child ("op 0", TREE_OPERAND (t, 0));
563       dump_child ("op 1", TREE_OPERAND (t, 1));
564       dump_child ("op 2", TREE_OPERAND (t, 2));
565       break;
566
567     case ARRAY_REF:
568     case ARRAY_RANGE_REF:
569       dump_child ("op 0", TREE_OPERAND (t, 0));
570       dump_child ("op 1", TREE_OPERAND (t, 1));
571       dump_child ("op 2", TREE_OPERAND (t, 2));
572       dump_child ("op 3", TREE_OPERAND (t, 3));
573       break;
574
575     case COND_EXPR:
576       dump_child ("op 0", TREE_OPERAND (t, 0));
577       dump_child ("op 1", TREE_OPERAND (t, 1));
578       dump_child ("op 2", TREE_OPERAND (t, 2));
579       break;
580
581     case TRY_FINALLY_EXPR:
582       dump_child ("op 0", TREE_OPERAND (t, 0));
583       dump_child ("op 1", TREE_OPERAND (t, 1));
584       break;
585
586     case CALL_EXPR:
587       dump_child ("fn", TREE_OPERAND (t, 0));
588       dump_child ("args", TREE_OPERAND (t, 1));
589       break;
590
591     case CONSTRUCTOR:
592       {
593         unsigned HOST_WIDE_INT cnt;
594         tree index, value;
595         dump_int (di, "lngt", VEC_length (constructor_elt,
596                                           CONSTRUCTOR_ELTS (t)));
597         FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), cnt, index, value)
598           {
599             dump_child ("idx", index);
600             dump_child ("val", value);
601           }
602       }
603       break;
604
605     case BIND_EXPR:
606       dump_child ("vars", TREE_OPERAND (t, 0));
607       dump_child ("body", TREE_OPERAND (t, 1));
608       break;
609
610     case LOOP_EXPR:
611       dump_child ("body", TREE_OPERAND (t, 0));
612       break;
613
614     case EXIT_EXPR:
615       dump_child ("cond", TREE_OPERAND (t, 0));
616       break;
617
618     case RETURN_EXPR:
619       dump_child ("expr", TREE_OPERAND (t, 0));
620       break;
621
622     case TARGET_EXPR:
623       dump_child ("decl", TREE_OPERAND (t, 0));
624       dump_child ("init", TREE_OPERAND (t, 1));
625       dump_child ("clnp", TREE_OPERAND (t, 2));
626       /* There really are two possible places the initializer can be.
627          After RTL expansion, the second operand is moved to the
628          position of the fourth operand, and the second operand
629          becomes NULL.  */
630       dump_child ("init", TREE_OPERAND (t, 3));
631       break;
632
633     case CASE_LABEL_EXPR:
634       dump_child ("name", CASE_LABEL (t));
635       if (CASE_LOW (t)) {
636         dump_child ("low ", CASE_LOW (t));
637         if (CASE_HIGH (t)) {
638           dump_child ("high", CASE_HIGH (t));
639         }
640       }
641       break;
642     case LABEL_EXPR:
643       dump_child ("name", TREE_OPERAND (t,0));
644       break;
645     case GOTO_EXPR:
646       dump_child ("labl", TREE_OPERAND (t, 0));
647       break;
648     case SWITCH_EXPR:
649       dump_child ("cond", TREE_OPERAND (t, 0));
650       dump_child ("body", TREE_OPERAND (t, 1));
651       if (TREE_OPERAND (t, 2))
652         {
653           dump_child ("labl", TREE_OPERAND (t,2));
654         }
655       break;
656     default:
657       /* There are no additional fields to print.  */
658       break;
659     }
660
661  done:
662   if (dump_flag (di, TDF_ADDRESS, NULL))
663     dump_pointer (di, "addr", (void *)t);
664
665   /* Terminate the line.  */
666   fprintf (di->stream, "\n");
667 }
668
669 /* Return nonzero if FLAG has been specified for the dump, and NODE
670    is not the root node of the dump.  */
671
672 int dump_flag (dump_info_p di, int flag, tree node)
673 {
674   return (di->flags & flag) && (node != di->node);
675 }
676
677 /* Dump T, and all its children, on STREAM.  */
678
679 void
680 dump_node (tree t, int flags, FILE *stream)
681 {
682   struct dump_info di;
683   dump_queue_p dq;
684   dump_queue_p next_dq;
685
686   /* Initialize the dump-information structure.  */
687   di.stream = stream;
688   di.index = 0;
689   di.column = 0;
690   di.queue = 0;
691   di.queue_end = 0;
692   di.free_list = 0;
693   di.flags = flags;
694   di.node = t;
695   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
696                              (splay_tree_delete_value_fn) &free);
697
698   /* Queue up the first node.  */
699   queue (&di, t, DUMP_NONE);
700
701   /* Until the queue is empty, keep dumping nodes.  */
702   while (di.queue)
703     dequeue_and_dump (&di);
704
705   /* Now, clean up.  */
706   for (dq = di.free_list; dq; dq = next_dq)
707     {
708       next_dq = dq->next;
709       free (dq);
710     }
711   splay_tree_delete (di.nodes);
712 }
713 \f
714
715 /* Table of tree dump switches. This must be consistent with the
716    TREE_DUMP_INDEX enumeration in tree.h */
717 static struct dump_file_info dump_files[TDI_end] =
718 {
719   {NULL, NULL, NULL, 0, 0, 0, 0},
720   {".tu", "translation-unit", NULL, TDF_TREE, 0, 0, 0},
721   {".class", "class-hierarchy", NULL, TDF_TREE, 0, 1, 0},
722   {".original", "tree-original", NULL, TDF_TREE, 0, 2, 0},
723   {".gimple", "tree-gimple", NULL, TDF_TREE, 0, 3, 0},
724   {".nested", "tree-nested", NULL, TDF_TREE, 0, 4, 0},
725   {".inlined", "tree-inlined", NULL, TDF_TREE, 0, 5, 0},
726   {".vcg", "tree-vcg", NULL, TDF_TREE, 0, 6, 0},
727   {NULL, "tree-all", NULL, TDF_TREE, 0, 0, 0},
728   {NULL, "rtl-all", NULL, TDF_RTL, 0, 0, 0},
729   {NULL, "ipa-all", NULL, TDF_IPA, 0, 0, 0},
730
731   { ".cgraph", "ipa-cgraph", NULL,      TDF_IPA, 0,  0, 0},
732 };
733
734 /* Dynamically registered tree dump files and switches.  */
735 static struct dump_file_info *extra_dump_files;
736 static size_t extra_dump_files_in_use;
737 static size_t extra_dump_files_alloced;
738
739 /* Define a name->number mapping for a dump flag value.  */
740 struct dump_option_value_info
741 {
742   const char *const name;       /* the name of the value */
743   const int value;              /* the value of the name */
744 };
745
746 /* Table of dump options. This must be consistent with the TDF_* flags
747    in tree.h */
748 static const struct dump_option_value_info dump_options[] =
749 {
750   {"address", TDF_ADDRESS},
751   {"slim", TDF_SLIM},
752   {"raw", TDF_RAW},
753   {"details", TDF_DETAILS},
754   {"stats", TDF_STATS},
755   {"blocks", TDF_BLOCKS},
756   {"vops", TDF_VOPS},
757   {"lineno", TDF_LINENO},
758   {"uid", TDF_UID},
759   {"stmtaddr", TDF_STMTADDR},
760   {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA 
761             | TDF_STMTADDR | TDF_GRAPH)},
762   {NULL, 0}
763 };
764
765 unsigned int
766 dump_register (const char *suffix, const char *swtch, const char *glob,
767                int flags, unsigned int num, int letter)
768 {
769   size_t this = extra_dump_files_in_use++;
770
771   if (this >= extra_dump_files_alloced)
772     {
773       if (extra_dump_files_alloced == 0)
774         extra_dump_files_alloced = 32;
775       else
776         extra_dump_files_alloced *= 2;
777       extra_dump_files = xrealloc (extra_dump_files,
778                                    sizeof (struct dump_file_info)
779                                    * extra_dump_files_alloced);
780     }
781
782   memset (&extra_dump_files[this], 0, sizeof (struct dump_file_info));
783   extra_dump_files[this].suffix = suffix;
784   extra_dump_files[this].swtch = swtch;
785   extra_dump_files[this].glob = glob;
786   extra_dump_files[this].flags = flags;
787   extra_dump_files[this].num = num;
788   extra_dump_files[this].letter = letter;
789
790   return this + TDI_end;
791 }
792
793
794 /* Return the dump_file_info for the given phase.  */
795
796 struct dump_file_info *
797 get_dump_file_info (enum tree_dump_index phase)
798 {
799   if (phase < TDI_end)
800     return &dump_files[phase];
801   else if (phase - TDI_end >= extra_dump_files_in_use)
802     return NULL;
803   else
804     return extra_dump_files + (phase - TDI_end);
805 }
806
807
808 /* Return the name of the dump file for the given phase.
809    If the dump is not enabled, returns NULL.  */
810
811 char *
812 get_dump_file_name (enum tree_dump_index phase)
813 {
814   char dump_id[7];
815   struct dump_file_info *dfi;
816
817   if (phase == TDI_none)
818     return NULL;
819
820   dfi = get_dump_file_info (phase);
821   if (dfi->state == 0)
822     return NULL;
823
824   if (dfi->num < 0)
825     dump_id[0] = '\0';
826   else
827     {
828       const char *template;
829       if (dfi->flags & TDF_TREE)
830         template = ".t%02d";
831       else if (dfi->flags & TDF_IPA)
832         template = ".i%02d";
833       else
834         template = ".%02d";
835
836       if (snprintf (dump_id, sizeof (dump_id), template, dfi->num) < 0)
837         dump_id[0] = '\0';
838     }
839
840   return concat (dump_base_name, dump_id, dfi->suffix, NULL);
841 }
842
843 /* Begin a tree dump for PHASE. Stores any user supplied flag in
844    *FLAG_PTR and returns a stream to write to. If the dump is not
845    enabled, returns NULL.
846    Multiple calls will reopen and append to the dump file.  */
847
848 FILE *
849 dump_begin (enum tree_dump_index phase, int *flag_ptr)
850 {
851   char *name;
852   struct dump_file_info *dfi;
853   FILE *stream;
854
855   if (phase == TDI_none || !dump_enabled_p (phase))
856     return NULL;
857
858   name = get_dump_file_name (phase);
859   dfi = get_dump_file_info (phase);
860   stream = fopen (name, dfi->state < 0 ? "w" : "a");
861   if (!stream)
862     error ("could not open dump file %qs: %s", name, strerror (errno));
863   else
864     dfi->state = 1;
865   free (name);
866
867   if (flag_ptr)
868     *flag_ptr = dfi->flags;
869
870   return stream;
871 }
872
873 /* Returns nonzero if tree dump PHASE is enabled.  If PHASE is
874    TDI_tree_all, return nonzero if any dump is enabled.  */
875
876 int
877 dump_enabled_p (enum tree_dump_index phase)
878 {
879   if (phase == TDI_tree_all)
880     {
881       size_t i;
882       for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
883         if (dump_files[i].state)
884           return 1;
885       for (i = 0; i < extra_dump_files_in_use; i++)
886         if (extra_dump_files[i].state)
887           return 1;
888       return 0;
889     }
890   else
891     {
892       struct dump_file_info *dfi = get_dump_file_info (phase);
893       return dfi->state;
894     }
895 }
896
897 /* Returns nonzero if tree dump PHASE has been initialized.  */
898
899 int
900 dump_initialized_p (enum tree_dump_index phase)
901 {
902   struct dump_file_info *dfi = get_dump_file_info (phase);
903   return dfi->state > 0;
904 }
905
906 /* Returns the switch name of PHASE.  */
907
908 const char *
909 dump_flag_name (enum tree_dump_index phase)
910 {
911   struct dump_file_info *dfi = get_dump_file_info (phase);
912   return dfi->swtch;
913 }
914
915 /* Finish a tree dump for PHASE. STREAM is the stream created by
916    dump_begin.  */
917
918 void
919 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
920 {
921   fclose (stream);
922 }
923
924 /* Enable all tree dumps.  Return number of enabled tree dumps.  */
925
926 static int
927 dump_enable_all (int flags, int letter)
928 {
929   int n = 0;
930   size_t i;
931
932   for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
933     if ((dump_files[i].flags & flags)
934         && (letter == 0 || letter == dump_files[i].letter))
935       {
936         dump_files[i].state = -1;
937         dump_files[i].flags = flags;
938         n++;
939       }
940
941   for (i = 0; i < extra_dump_files_in_use; i++)
942     if ((extra_dump_files[i].flags & flags)
943         && (letter == 0 || letter == extra_dump_files[i].letter))
944       {
945         extra_dump_files[i].state = -1;
946         extra_dump_files[i].flags = flags;
947         n++;
948       }
949
950   return n;
951 }
952
953 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
954    relevant details in the dump_files array.  */
955
956 static int
957 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
958 {
959   const char *option_value;
960   const char *ptr;
961   int flags;
962   
963   if (doglob && !dfi->glob)
964     return 0;
965
966   option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
967   if (!option_value)
968     return 0;
969
970   ptr = option_value;
971   flags = 0;
972
973   while (*ptr)
974     {
975       const struct dump_option_value_info *option_ptr;
976       const char *end_ptr;
977       unsigned length;
978
979       while (*ptr == '-')
980         ptr++;
981       end_ptr = strchr (ptr, '-');
982       if (!end_ptr)
983         end_ptr = ptr + strlen (ptr);
984       length = end_ptr - ptr;
985
986       for (option_ptr = dump_options; option_ptr->name; option_ptr++)
987         if (strlen (option_ptr->name) == length
988             && !memcmp (option_ptr->name, ptr, length))
989           {
990             flags |= option_ptr->value;
991             goto found;
992           }
993       warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
994                length, ptr, dfi->swtch);
995     found:;
996       ptr = end_ptr;
997     }
998
999   dfi->state = -1;
1000   dfi->flags |= flags;
1001
1002   /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
1003      known dumps.  */
1004   if (dfi->suffix == NULL)
1005     dump_enable_all (dfi->flags, 0);
1006
1007   return 1;
1008 }
1009
1010 int
1011 dump_switch_p (const char *arg)
1012 {
1013   size_t i;
1014   int any = 0;
1015
1016   for (i = TDI_none + 1; i != TDI_end; i++)
1017     any |= dump_switch_p_1 (arg, &dump_files[i], false);
1018
1019   /* Don't glob if we got a hit already */
1020   if (!any)
1021     for (i = TDI_none + 1; i != TDI_end; i++)
1022       any |= dump_switch_p_1 (arg, &dump_files[i], true);
1023
1024   for (i = 0; i < extra_dump_files_in_use; i++)
1025     any |= dump_switch_p_1 (arg, &extra_dump_files[i], false);
1026   
1027   if (!any)
1028     for (i = 0; i < extra_dump_files_in_use; i++)
1029       any |= dump_switch_p_1 (arg, &extra_dump_files[i], true);
1030
1031
1032   return any;
1033 }
1034
1035 /* Dump FUNCTION_DECL FN as tree dump PHASE.  */
1036
1037 void
1038 dump_function (enum tree_dump_index phase, tree fn)
1039 {
1040   FILE *stream;
1041   int flags;
1042
1043   stream = dump_begin (phase, &flags);
1044   if (stream)
1045     {
1046       dump_function_to_file (fn, stream, flags);
1047       dump_end (phase, stream);
1048     }
1049 }
1050
1051 bool
1052 enable_rtl_dump_file (int letter)
1053 {
1054   if (letter == 'a')
1055     letter = 0;
1056
1057   return dump_enable_all (TDF_RTL, letter) > 0;
1058 }
1059
1060