OSDN Git Service

2004-05-13 Benjamin Kosnik <bkoz@redhat.com>
[pf3gnuchains/gcc-fork.git] / gcc / tree-dump.c
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>
4
5 This file is part of GCC.
6
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.
11
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.
16
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.  */
21
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"
32
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 *);
39 static void dump_enable_all (int);
40
41 /* Add T to the end of the queue of nodes to dump.  Returns the index
42    assigned to T.  */
43
44 static unsigned int
45 queue (dump_info_p di, tree t, int flags)
46 {
47   dump_queue_p dq;
48   dump_node_info_p dni;
49   unsigned int index;
50
51   /* Assign the next available index to T.  */
52   index = ++di->index;
53
54   /* Obtain a new queue node.  */
55   if (di->free_list)
56     {
57       dq = di->free_list;
58       di->free_list = dq->next;
59     }
60   else
61     dq = xmalloc (sizeof (struct dump_queue));
62
63   /* Create a new entry in the splay-tree.  */
64   dni = xmalloc (sizeof (struct dump_node_info));
65   dni->index = index;
66   dni->binfo_p = ((flags & DUMP_BINFO) != 0);
67   dq->node = splay_tree_insert (di->nodes, (splay_tree_key) t,
68                                 (splay_tree_value) dni);
69
70   /* Add it to the end of the queue.  */
71   dq->next = 0;
72   if (!di->queue_end)
73     di->queue = dq;
74   else
75     di->queue_end->next = dq;
76   di->queue_end = dq;
77
78   /* Return the index.  */
79   return index;
80 }
81
82 static void
83 dump_index (dump_info_p di, unsigned int index)
84 {
85   fprintf (di->stream, "@%-6u ", index);
86   di->column += 8;
87 }
88
89 /* If T has not already been output, queue it for subsequent output.
90    FIELD is a string to print before printing the index.  Then, the
91    index of T is printed.  */
92
93 void
94 queue_and_dump_index (dump_info_p di, const char *field, tree t, int flags)
95 {
96   unsigned int index;
97   splay_tree_node n;
98
99   /* If there's no node, just return.  This makes for fewer checks in
100      our callers.  */
101   if (!t)
102     return;
103
104   /* See if we've already queued or dumped this node.  */
105   n = splay_tree_lookup (di->nodes, (splay_tree_key) t);
106   if (n)
107     index = ((dump_node_info_p) n->value)->index;
108   else
109     /* If we haven't, add it to the queue.  */
110     index = queue (di, t, flags);
111
112   /* Print the index of the node.  */
113   dump_maybe_newline (di);
114   fprintf (di->stream, "%-4s: ", field);
115   di->column += 6;
116   dump_index (di, index);
117 }
118
119 /* Dump the type of T.  */
120
121 void
122 queue_and_dump_type (dump_info_p di, tree t)
123 {
124   queue_and_dump_index (di, "type", TREE_TYPE (t), DUMP_NONE);
125 }
126
127 /* Dump column control */
128 #define SOL_COLUMN 25           /* Start of line column.  */
129 #define EOL_COLUMN 55           /* End of line column.  */
130 #define COLUMN_ALIGNMENT 15     /* Alignment.  */
131
132 /* Insert a new line in the dump output, and indent to an appropriate
133    place to start printing more fields.  */
134
135 static void
136 dump_new_line (dump_info_p di)
137 {
138   fprintf (di->stream, "\n%*s", SOL_COLUMN, "");
139   di->column = SOL_COLUMN;
140 }
141
142 /* If necessary, insert a new line.  */
143
144 static void
145 dump_maybe_newline (dump_info_p di)
146 {
147   int extra;
148
149   /* See if we need a new line.  */
150   if (di->column > EOL_COLUMN)
151     dump_new_line (di);
152   /* See if we need any padding.  */
153   else if ((extra = (di->column - SOL_COLUMN) % COLUMN_ALIGNMENT) != 0)
154     {
155       fprintf (di->stream, "%*s", COLUMN_ALIGNMENT - extra, "");
156       di->column += COLUMN_ALIGNMENT - extra;
157     }
158 }
159
160 /* Dump pointer PTR using FIELD to identify it.  */
161
162 void
163 dump_pointer (dump_info_p di, const char *field, void *ptr)
164 {
165   dump_maybe_newline (di);
166   fprintf (di->stream, "%-4s: %-8lx ", field, (long) ptr);
167   di->column += 15;
168 }
169
170 /* Dump integer I using FIELD to identify it.  */
171
172 void
173 dump_int (dump_info_p di, const char *field, int i)
174 {
175   dump_maybe_newline (di);
176   fprintf (di->stream, "%-4s: %-7d ", field, i);
177   di->column += 14;
178 }
179
180 /* Dump the string S.  */
181
182 void
183 dump_string (dump_info_p di, const char *string)
184 {
185   dump_maybe_newline (di);
186   fprintf (di->stream, "%-13s ", string);
187   if (strlen (string) > 13)
188     di->column += strlen (string) + 1;
189   else
190     di->column += 14;
191 }
192
193 /* Dump the string field S.  */
194
195 static void
196 dump_string_field (dump_info_p di, const char *field, const char *string)
197 {
198   dump_maybe_newline (di);
199   fprintf (di->stream, "%-4s: %-7s ", field, string);
200   if (strlen (string) > 7)
201     di->column += 6 + strlen (string) + 1;
202   else
203     di->column += 14;
204 }
205
206 /* Dump the next node in the queue.  */
207
208 static void
209 dequeue_and_dump (dump_info_p di)
210 {
211   dump_queue_p dq;
212   splay_tree_node stn;
213   dump_node_info_p dni;
214   tree t;
215   unsigned int index;
216   enum tree_code code;
217   char code_class;
218   const char* code_name;
219
220   /* Get the next node from the queue.  */
221   dq = di->queue;
222   stn = dq->node;
223   t = (tree) stn->key;
224   dni = (dump_node_info_p) stn->value;
225   index = dni->index;
226
227   /* Remove the node from the queue, and put it on the free list.  */
228   di->queue = dq->next;
229   if (!di->queue)
230     di->queue_end = 0;
231   dq->next = di->free_list;
232   di->free_list = dq;
233
234   /* Print the node index.  */
235   dump_index (di, index);
236   /* And the type of node this is.  */
237   if (dni->binfo_p)
238     code_name = "binfo";
239   else
240     code_name = tree_code_name[(int) TREE_CODE (t)];
241   fprintf (di->stream, "%-16s ", code_name);
242   di->column = 25;
243
244   /* Figure out what kind of node this is.  */
245   code = TREE_CODE (t);
246   code_class = TREE_CODE_CLASS (code);
247
248   /* Although BINFOs are TREE_VECs, we dump them specially so as to be
249      more informative.  */
250   if (dni->binfo_p)
251     {
252       unsigned ix;
253       tree bases = BINFO_BASETYPES (t);
254       unsigned n_bases = bases ? TREE_VEC_LENGTH (bases): 0;
255       tree accesses = BINFO_BASEACCESSES (t);
256
257       dump_child ("type", BINFO_TYPE (t));
258
259       if (TREE_VIA_VIRTUAL (t))
260         dump_string (di, "virt");
261
262       dump_int (di, "bases", n_bases);
263       for (ix = 0; ix != n_bases; ix++)
264         {
265           tree base = TREE_VEC_ELT (bases, ix);
266           tree access = (accesses ? TREE_VEC_ELT (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             abort ();
278
279           dump_string (di, 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 '1':
296           dump_child ("op 0", TREE_OPERAND (t, 0));
297           break;
298
299         case '2':
300         case '<':
301           dump_child ("op 0", TREE_OPERAND (t, 0));
302           dump_child ("op 1", TREE_OPERAND (t, 1));
303           break;
304
305         case 'e':
306         case 'r':
307         case 's':
308           /* These nodes are handled explicitly below.  */
309           break;
310
311         default:
312           abort ();
313         }
314     }
315   else if (DECL_P (t))
316     {
317       /* All declarations have names.  */
318       if (DECL_NAME (t))
319         dump_child ("name", DECL_NAME (t));
320       if (DECL_ASSEMBLER_NAME_SET_P (t)
321           && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t))
322         dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
323       /* And types.  */
324       queue_and_dump_type (di, t);
325       dump_child ("scpe", DECL_CONTEXT (t));
326       /* And a source position.  */
327       if (DECL_SOURCE_FILE (t))
328         {
329           const char *filename = strrchr (DECL_SOURCE_FILE (t), '/');
330           if (!filename)
331             filename = DECL_SOURCE_FILE (t);
332           else
333             /* Skip the slash.  */
334             ++filename;
335
336           dump_maybe_newline (di);
337           fprintf (di->stream, "srcp: %s:%-6d ", filename,
338                    DECL_SOURCE_LINE (t));
339           di->column += 6 + strlen (filename) + 8;
340         }
341       /* And any declaration can be compiler-generated.  */
342       if (DECL_ARTIFICIAL (t))
343         dump_string (di, "artificial");
344       if (TREE_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
345         dump_child ("chan", TREE_CHAIN (t));
346     }
347   else if (code_class == 't')
348     {
349       /* All types have qualifiers.  */
350       int quals = lang_hooks.tree_dump.type_quals (t);
351
352       if (quals != TYPE_UNQUALIFIED)
353         {
354           fprintf (di->stream, "qual: %c%c%c     ",
355                    (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
356                    (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
357                    (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
358           di->column += 14;
359         }
360
361       /* All types have associated declarations.  */
362       dump_child ("name", TYPE_NAME (t));
363
364       /* All types have a main variant.  */
365       if (TYPE_MAIN_VARIANT (t) != t)
366         dump_child ("unql", TYPE_MAIN_VARIANT (t));
367
368       /* And sizes.  */
369       dump_child ("size", TYPE_SIZE (t));
370
371       /* All types have alignments.  */
372       dump_int (di, "algn", TYPE_ALIGN (t));
373     }
374   else if (code_class == 'c')
375     /* All constants can have types.  */
376     queue_and_dump_type (di, t);
377
378   /* Give the language-specific code a chance to print something.  If
379      it's completely taken care of things, don't bother printing
380      anything more ourselves.  */
381   if (lang_hooks.tree_dump.dump_tree (di, t))
382     goto done;
383
384   /* Now handle the various kinds of nodes.  */
385   switch (code)
386     {
387       int i;
388
389     case IDENTIFIER_NODE:
390       dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
391       dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
392       break;
393
394     case TREE_LIST:
395       dump_child ("purp", TREE_PURPOSE (t));
396       dump_child ("valu", TREE_VALUE (t));
397       dump_child ("chan", TREE_CHAIN (t));
398       break;
399
400     case TREE_VEC:
401       dump_int (di, "lngt", TREE_VEC_LENGTH (t));
402       for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
403         {
404           char buffer[32];
405           sprintf (buffer, "%u", i);
406           dump_child (buffer, TREE_VEC_ELT (t, i));
407         }
408       break;
409
410     case INTEGER_TYPE:
411     case ENUMERAL_TYPE:
412       dump_int (di, "prec", TYPE_PRECISION (t));
413       if (TYPE_UNSIGNED (t))
414         dump_string (di, "unsigned");
415       dump_child ("min", TYPE_MIN_VALUE (t));
416       dump_child ("max", TYPE_MAX_VALUE (t));
417
418       if (code == ENUMERAL_TYPE)
419         dump_child ("csts", TYPE_VALUES (t));
420       break;
421
422     case REAL_TYPE:
423       dump_int (di, "prec", TYPE_PRECISION (t));
424       break;
425
426     case POINTER_TYPE:
427       dump_child ("ptd", TREE_TYPE (t));
428       break;
429
430     case REFERENCE_TYPE:
431       dump_child ("refd", TREE_TYPE (t));
432       break;
433
434     case METHOD_TYPE:
435       dump_child ("clas", TYPE_METHOD_BASETYPE (t));
436       /* Fall through.  */
437
438     case FUNCTION_TYPE:
439       dump_child ("retn", TREE_TYPE (t));
440       dump_child ("prms", TYPE_ARG_TYPES (t));
441       break;
442
443     case ARRAY_TYPE:
444       dump_child ("elts", TREE_TYPE (t));
445       dump_child ("domn", TYPE_DOMAIN (t));
446       break;
447
448     case RECORD_TYPE:
449     case UNION_TYPE:
450       if (TREE_CODE (t) == RECORD_TYPE)
451         dump_string (di, "struct");
452       else
453         dump_string (di, "union");
454
455       dump_child ("flds", TYPE_FIELDS (t));
456       dump_child ("fncs", TYPE_METHODS (t));
457       queue_and_dump_index (di, "binf", TYPE_BINFO (t),
458                             DUMP_BINFO);
459       break;
460
461     case CONST_DECL:
462       dump_child ("cnst", DECL_INITIAL (t));
463       break;
464
465     case VAR_DECL:
466     case PARM_DECL:
467     case FIELD_DECL:
468     case RESULT_DECL:
469       if (TREE_CODE (t) == PARM_DECL)
470         dump_child ("argt", DECL_ARG_TYPE (t));
471       else
472         dump_child ("init", DECL_INITIAL (t));
473       dump_child ("size", DECL_SIZE (t));
474       dump_int (di, "algn", DECL_ALIGN (t));
475
476       if (TREE_CODE (t) == FIELD_DECL)
477         {
478           if (DECL_FIELD_OFFSET (t))
479             dump_child ("bpos", bit_position (t));
480         }
481       else if (TREE_CODE (t) == VAR_DECL
482                || TREE_CODE (t) == PARM_DECL)
483         {
484           dump_int (di, "used", TREE_USED (t));
485           if (DECL_REGISTER (t))
486             dump_string (di, "register");
487         }
488       break;
489
490     case FUNCTION_DECL:
491       dump_child ("args", DECL_ARGUMENTS (t));
492       if (DECL_EXTERNAL (t))
493         dump_string (di, "undefined");
494       if (TREE_PUBLIC (t))
495         dump_string (di, "extern");
496       else
497         dump_string (di, "static");
498       if (DECL_LANG_SPECIFIC (t) && !dump_flag (di, TDF_SLIM, t))
499         dump_child ("body", DECL_SAVED_TREE (t));
500       break;
501
502     case INTEGER_CST:
503       if (TREE_INT_CST_HIGH (t))
504         dump_int (di, "high", TREE_INT_CST_HIGH (t));
505       dump_int (di, "low", TREE_INT_CST_LOW (t));
506       break;
507
508     case STRING_CST:
509       fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
510       dump_int (di, "lngt", TREE_STRING_LENGTH (t));
511       break;
512
513     case TRUTH_NOT_EXPR:
514     case ADDR_EXPR:
515     case INDIRECT_REF:
516     case CLEANUP_POINT_EXPR:
517     case SAVE_EXPR:
518       /* These nodes are unary, but do not have code class `1'.  */
519       dump_child ("op 0", TREE_OPERAND (t, 0));
520       break;
521
522     case TRUTH_ANDIF_EXPR:
523     case TRUTH_ORIF_EXPR:
524     case INIT_EXPR:
525     case MODIFY_EXPR:
526     case COMPONENT_REF:
527     case COMPOUND_EXPR:
528     case ARRAY_REF:
529     case PREDECREMENT_EXPR:
530     case PREINCREMENT_EXPR:
531     case POSTDECREMENT_EXPR:
532     case POSTINCREMENT_EXPR:
533       /* These nodes are binary, but do not have code class `2'.  */
534       dump_child ("op 0", TREE_OPERAND (t, 0));
535       dump_child ("op 1", TREE_OPERAND (t, 1));
536       break;
537
538     case COND_EXPR:
539       dump_child ("op 0", TREE_OPERAND (t, 0));
540       dump_child ("op 1", TREE_OPERAND (t, 1));
541       dump_child ("op 2", TREE_OPERAND (t, 2));
542       break;
543
544     case CALL_EXPR:
545       dump_child ("fn", TREE_OPERAND (t, 0));
546       dump_child ("args", TREE_OPERAND (t, 1));
547       break;
548
549     case CONSTRUCTOR:
550       dump_child ("elts", CONSTRUCTOR_ELTS (t));
551       break;
552
553     case BIND_EXPR:
554       dump_child ("vars", TREE_OPERAND (t, 0));
555       dump_child ("body", TREE_OPERAND (t, 1));
556       break;
557
558     case LOOP_EXPR:
559       dump_child ("body", TREE_OPERAND (t, 0));
560       break;
561
562     case EXIT_EXPR:
563       dump_child ("cond", TREE_OPERAND (t, 0));
564       break;
565
566     case TARGET_EXPR:
567       dump_child ("decl", TREE_OPERAND (t, 0));
568       dump_child ("init", TREE_OPERAND (t, 1));
569       dump_child ("clnp", TREE_OPERAND (t, 2));
570       /* There really are two possible places the initializer can be.
571          After RTL expansion, the second operand is moved to the
572          position of the fourth operand, and the second operand
573          becomes NULL.  */
574       dump_child ("init", TREE_OPERAND (t, 3));
575       break;
576
577     default:
578       /* There are no additional fields to print.  */
579       break;
580     }
581
582  done:
583   if (dump_flag (di, TDF_ADDRESS, NULL))
584     dump_pointer (di, "addr", (void *)t);
585
586   /* Terminate the line.  */
587   fprintf (di->stream, "\n");
588 }
589
590 /* Return nonzero if FLAG has been specified for the dump, and NODE
591    is not the root node of the dump.  */
592
593 int dump_flag (dump_info_p di, int flag, tree node)
594 {
595   return (di->flags & flag) && (node != di->node);
596 }
597
598 /* Dump T, and all its children, on STREAM.  */
599
600 void
601 dump_node (tree t, int flags, FILE *stream)
602 {
603   struct dump_info di;
604   dump_queue_p dq;
605   dump_queue_p next_dq;
606
607   /* Initialize the dump-information structure.  */
608   di.stream = stream;
609   di.index = 0;
610   di.column = 0;
611   di.queue = 0;
612   di.queue_end = 0;
613   di.free_list = 0;
614   di.flags = flags;
615   di.node = t;
616   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
617                              (splay_tree_delete_value_fn) &free);
618
619   /* Queue up the first node.  */
620   queue (&di, t, DUMP_NONE);
621
622   /* Until the queue is empty, keep dumping nodes.  */
623   while (di.queue)
624     dequeue_and_dump (&di);
625
626   /* Now, clean up.  */
627   for (dq = di.free_list; dq; dq = next_dq)
628     {
629       next_dq = dq->next;
630       free (dq);
631     }
632   splay_tree_delete (di.nodes);
633 }
634
635 /* Define a tree dump switch.  */
636 struct dump_file_info
637 {
638   const char *suffix;           /* suffix to give output file.  */
639   const char *swtch;            /* command line switch */
640   int flags;                    /* user flags */
641   int state;                    /* state of play */
642 };
643
644 /* Table of tree dump switches. This must be consistent with the
645    TREE_DUMP_INDEX enumeration in tree.h */
646 static struct dump_file_info dump_files[TDI_end] =
647 {
648   {NULL, NULL, 0, 0},
649   {".tu", "translation-unit", 0, 0},
650   {".class", "class-hierarchy", 0, 0},
651   {".original", "tree-original", 0, 0},
652   {".generic", "tree-generic", 0, 0},
653   {".nested", "tree-nested", 0, 0},
654   {".inlined", "tree-inlined", 0, 0},
655   {".vcg", "tree-vcg", 0, 0},
656   {".xml", "call-graph", 0, 0},
657   {NULL, "tree-all", 0, 0},
658 };
659
660 /* Dynamically registered tree dump files and switches.  */
661 static struct dump_file_info *extra_dump_files;
662 static size_t extra_dump_files_in_use;
663 static size_t extra_dump_files_alloced;
664
665 /* Define a name->number mapping for a dump flag value.  */
666 struct dump_option_value_info
667 {
668   const char *const name;       /* the name of the value */
669   const int value;              /* the value of the name */
670 };
671
672 /* Table of dump options. This must be consistent with the TDF_* flags
673    in tree.h */
674 static const struct dump_option_value_info dump_options[] =
675 {
676   {"address", TDF_ADDRESS},
677   {"slim", TDF_SLIM},
678   {"raw", TDF_RAW},
679   {"details", TDF_DETAILS},
680   {"stats", TDF_STATS},
681   {"blocks", TDF_BLOCKS},
682   {"vops", TDF_VOPS},
683   {"lineno", TDF_LINENO},
684   {"uid", TDF_UID},
685   {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO)},
686   {NULL, 0}
687 };
688
689 unsigned int
690 dump_register (const char *suffix, const char *swtch)
691 {
692   size_t this = extra_dump_files_in_use++;
693
694   if (this >= extra_dump_files_alloced)
695     {
696       if (extra_dump_files_alloced == 0)
697         extra_dump_files_alloced = 32;
698       else
699         extra_dump_files_alloced *= 2;
700       extra_dump_files = xrealloc (extra_dump_files,
701                                    sizeof (struct dump_file_info)
702                                    * extra_dump_files_alloced);
703     }
704
705   memset (&extra_dump_files[this], 0, sizeof (struct dump_file_info));
706   extra_dump_files[this].suffix = suffix;
707   extra_dump_files[this].swtch = swtch;
708
709   return this + TDI_end;
710 }
711
712 /* Return the dump_file_info for the given phase.  */
713
714 static struct dump_file_info *
715 get_dump_file_info (enum tree_dump_index phase)
716 {
717   if (phase < TDI_end)
718     return &dump_files[phase];
719   else if (phase - TDI_end >= extra_dump_files_in_use)
720     abort ();
721   else
722     return extra_dump_files + (phase - TDI_end);
723 }
724
725
726 /* Begin a tree dump for PHASE. Stores any user supplied flag in
727    *FLAG_PTR and returns a stream to write to. If the dump is not
728    enabled, returns NULL.
729    Multiple calls will reopen and append to the dump file.  */
730
731 FILE *
732 dump_begin (enum tree_dump_index phase, int *flag_ptr)
733 {
734   FILE *stream;
735   char *name;
736   char dump_id[10];
737   struct dump_file_info *dfi;
738
739   if (phase == TDI_none)
740     return NULL;
741
742   dfi = get_dump_file_info (phase);
743   if (dfi->state == 0)
744     return NULL;
745
746   if (snprintf (dump_id, sizeof (dump_id), ".t%02d", phase) < 0)
747     dump_id[0] = '\0';
748
749   name = concat (dump_base_name, dump_id, dfi->suffix, NULL);
750   stream = fopen (name, dfi->state < 0 ? "w" : "a");
751   if (!stream)
752     error ("could not open dump file `%s': %s", name, strerror (errno));
753   else
754     dfi->state = 1;
755   free (name);
756
757   if (flag_ptr)
758     *flag_ptr = dfi->flags;
759
760   return stream;
761 }
762
763 /* Returns nonzero if tree dump PHASE is enabled.  */
764
765 int
766 dump_enabled_p (enum tree_dump_index phase)
767 {
768   struct dump_file_info *dfi = get_dump_file_info (phase);
769   return dfi->state;
770 }
771
772 /* Returns the switch name of PHASE.  */
773
774 const char *
775 dump_flag_name (enum tree_dump_index phase)
776 {
777   struct dump_file_info *dfi = get_dump_file_info (phase);
778   return dfi->swtch;
779 }
780
781 /* Finish a tree dump for PHASE. STREAM is the stream created by
782    dump_begin.  */
783
784 void
785 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
786 {
787   fclose (stream);
788 }
789
790 /* Enable all tree dumps.  */
791
792 static void
793 dump_enable_all (int flags)
794 {
795   size_t i;
796
797   for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
798     {
799       dump_files[i].state = -1;
800       dump_files[i].flags = flags;
801     }
802
803   for (i = 0; i < extra_dump_files_in_use; i++)
804     {
805       extra_dump_files[i].state = -1;
806       extra_dump_files[i].flags = flags;
807     }
808
809   /* FIXME  -fdump-call-graph is broken.  */
810   dump_files[TDI_xml].state = 0;
811   dump_files[TDI_xml].flags = 0;
812 }
813
814 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
815    relevant details in the dump_files array.  */
816
817 static int
818 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi)
819 {
820   const char *option_value;
821   const char *ptr;
822   int flags;
823
824   option_value = skip_leading_substring (arg, dfi->swtch);
825   if (!option_value)
826     return 0;
827
828   ptr = option_value;
829   flags = 0;
830
831   while (*ptr)
832     {
833       const struct dump_option_value_info *option_ptr;
834       const char *end_ptr;
835       unsigned length;
836
837       while (*ptr == '-')
838         ptr++;
839       end_ptr = strchr (ptr, '-');
840       if (!end_ptr)
841         end_ptr = ptr + strlen (ptr);
842       length = end_ptr - ptr;
843
844       for (option_ptr = dump_options; option_ptr->name; option_ptr++)
845         if (strlen (option_ptr->name) == length
846             && !memcmp (option_ptr->name, ptr, length))
847           {
848             flags |= option_ptr->value;
849             goto found;
850           }
851       warning ("ignoring unknown option `%.*s' in `-fdump-%s'",
852                length, ptr, dfi->swtch);
853     found:;
854       ptr = end_ptr;
855     }
856
857   dfi->state = -1;
858   dfi->flags = flags;
859
860   /* Process -fdump-tree-all by enabling all the known dumps.  */
861   if (dfi->suffix == NULL)
862     dump_enable_all (flags);
863
864   return 1;
865 }
866
867 int
868 dump_switch_p (const char *arg)
869 {
870   size_t i;
871   int any = 0;
872
873   for (i = TDI_none + 1; i != TDI_end; i++)
874     any |= dump_switch_p_1 (arg, &dump_files[i]);
875
876   for (i = 0; i < extra_dump_files_in_use; i++)
877     any |= dump_switch_p_1 (arg, &extra_dump_files[i]);
878
879   return any;
880 }
881
882 /* Dump FUNCTION_DECL FN as tree dump PHASE.  */
883
884 void
885 dump_function (enum tree_dump_index phase, tree fn)
886 {
887   FILE *stream;
888   int flags;
889
890   stream = dump_begin (phase, &flags);
891   if (stream)
892     {
893       dump_function_to_file (fn, stream, flags);
894       dump_end (phase, stream);
895     }
896 }