OSDN Git Service

2005-07-05 Paolo Bonzini <bonzini@gnu.org>
[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 (DECL_ARTIFICIAL (t))
347         dump_string_field (di, "note", "artificial");
348       if (TREE_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
349         dump_child ("chan", TREE_CHAIN (t));
350     }
351   else if (code_class == tcc_type)
352     {
353       /* All types have qualifiers.  */
354       int quals = lang_hooks.tree_dump.type_quals (t);
355
356       if (quals != TYPE_UNQUALIFIED)
357         {
358           fprintf (di->stream, "qual: %c%c%c     ",
359                    (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
360                    (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
361                    (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
362           di->column += 14;
363         }
364
365       /* All types have associated declarations.  */
366       dump_child ("name", TYPE_NAME (t));
367
368       /* All types have a main variant.  */
369       if (TYPE_MAIN_VARIANT (t) != t)
370         dump_child ("unql", TYPE_MAIN_VARIANT (t));
371
372       /* And sizes.  */
373       dump_child ("size", TYPE_SIZE (t));
374
375       /* All types have alignments.  */
376       dump_int (di, "algn", TYPE_ALIGN (t));
377     }
378   else if (code_class == tcc_constant)
379     /* All constants can have types.  */
380     queue_and_dump_type (di, t);
381
382   /* Give the language-specific code a chance to print something.  If
383      it's completely taken care of things, don't bother printing
384      anything more ourselves.  */
385   if (lang_hooks.tree_dump.dump_tree (di, t))
386     goto done;
387
388   /* Now handle the various kinds of nodes.  */
389   switch (code)
390     {
391       int i;
392
393     case IDENTIFIER_NODE:
394       dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
395       dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
396       break;
397
398     case TREE_LIST:
399       dump_child ("purp", TREE_PURPOSE (t));
400       dump_child ("valu", TREE_VALUE (t));
401       dump_child ("chan", TREE_CHAIN (t));
402       break;
403
404     case STATEMENT_LIST:
405       {
406         tree_stmt_iterator it;
407         for (i = 0, it = tsi_start (t); !tsi_end_p (it); tsi_next (&it), i++)
408           {
409             char buffer[32];
410             sprintf (buffer, "%u", i);
411             dump_child (buffer, tsi_stmt (it));
412           }
413       }
414       break;
415
416     case TREE_VEC:
417       dump_int (di, "lngt", TREE_VEC_LENGTH (t));
418       for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
419         {
420           char buffer[32];
421           sprintf (buffer, "%u", i);
422           dump_child (buffer, TREE_VEC_ELT (t, i));
423         }
424       break;
425
426     case INTEGER_TYPE:
427     case ENUMERAL_TYPE:
428       dump_int (di, "prec", TYPE_PRECISION (t));
429       dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed");
430       dump_child ("min", TYPE_MIN_VALUE (t));
431       dump_child ("max", TYPE_MAX_VALUE (t));
432
433       if (code == ENUMERAL_TYPE)
434         dump_child ("csts", TYPE_VALUES (t));
435       break;
436
437     case REAL_TYPE:
438       dump_int (di, "prec", TYPE_PRECISION (t));
439       break;
440
441     case POINTER_TYPE:
442       dump_child ("ptd", TREE_TYPE (t));
443       break;
444
445     case REFERENCE_TYPE:
446       dump_child ("refd", TREE_TYPE (t));
447       break;
448
449     case METHOD_TYPE:
450       dump_child ("clas", TYPE_METHOD_BASETYPE (t));
451       /* Fall through.  */
452
453     case FUNCTION_TYPE:
454       dump_child ("retn", TREE_TYPE (t));
455       dump_child ("prms", TYPE_ARG_TYPES (t));
456       break;
457
458     case ARRAY_TYPE:
459       dump_child ("elts", TREE_TYPE (t));
460       dump_child ("domn", TYPE_DOMAIN (t));
461       break;
462
463     case RECORD_TYPE:
464     case UNION_TYPE:
465       if (TREE_CODE (t) == RECORD_TYPE)
466         dump_string_field (di, "tag", "struct");
467       else
468         dump_string_field (di, "tag", "union");
469
470       dump_child ("flds", TYPE_FIELDS (t));
471       dump_child ("fncs", TYPE_METHODS (t));
472       queue_and_dump_index (di, "binf", TYPE_BINFO (t),
473                             DUMP_BINFO);
474       break;
475
476     case CONST_DECL:
477       dump_child ("cnst", DECL_INITIAL (t));
478       break;
479
480     case VAR_DECL:
481     case PARM_DECL:
482     case FIELD_DECL:
483     case RESULT_DECL:
484       if (TREE_CODE (t) == PARM_DECL)
485         dump_child ("argt", DECL_ARG_TYPE (t));
486       else
487         dump_child ("init", DECL_INITIAL (t));
488       dump_child ("size", DECL_SIZE (t));
489       dump_int (di, "algn", DECL_ALIGN (t));
490
491       if (TREE_CODE (t) == FIELD_DECL)
492         {
493           if (DECL_FIELD_OFFSET (t))
494             dump_child ("bpos", bit_position (t));
495         }
496       else if (TREE_CODE (t) == VAR_DECL
497                || TREE_CODE (t) == PARM_DECL)
498         {
499           dump_int (di, "used", TREE_USED (t));
500           if (DECL_REGISTER (t))
501             dump_string_field (di, "spec", "register");
502         }
503       break;
504
505     case FUNCTION_DECL:
506       dump_child ("args", DECL_ARGUMENTS (t));
507       if (DECL_EXTERNAL (t))
508         dump_string_field (di, "body", "undefined");
509       if (TREE_PUBLIC (t))
510         dump_string_field (di, "link", "extern");
511       else
512         dump_string_field (di, "link", "static");
513       if (DECL_LANG_SPECIFIC (t) && !dump_flag (di, TDF_SLIM, t))
514         dump_child ("body", DECL_SAVED_TREE (t));
515       break;
516
517     case INTEGER_CST:
518       if (TREE_INT_CST_HIGH (t))
519         dump_int (di, "high", TREE_INT_CST_HIGH (t));
520       dump_int (di, "low", TREE_INT_CST_LOW (t));
521       break;
522
523     case STRING_CST:
524       fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
525       dump_int (di, "lngt", TREE_STRING_LENGTH (t));
526       break;
527
528     case TRUTH_NOT_EXPR:
529     case ADDR_EXPR:
530     case INDIRECT_REF:
531     case ALIGN_INDIRECT_REF:
532     case MISALIGNED_INDIRECT_REF:
533     case CLEANUP_POINT_EXPR:
534     case SAVE_EXPR:
535     case REALPART_EXPR:
536     case IMAGPART_EXPR:
537       /* These nodes are unary, but do not have code class `1'.  */
538       dump_child ("op 0", TREE_OPERAND (t, 0));
539       break;
540
541     case TRUTH_ANDIF_EXPR:
542     case TRUTH_ORIF_EXPR:
543     case INIT_EXPR:
544     case MODIFY_EXPR:
545     case COMPOUND_EXPR:
546     case PREDECREMENT_EXPR:
547     case PREINCREMENT_EXPR:
548     case POSTDECREMENT_EXPR:
549     case POSTINCREMENT_EXPR:
550       /* These nodes are binary, but do not have code class `2'.  */
551       dump_child ("op 0", TREE_OPERAND (t, 0));
552       dump_child ("op 1", TREE_OPERAND (t, 1));
553       break;
554
555     case COMPONENT_REF:
556       dump_child ("op 0", TREE_OPERAND (t, 0));
557       dump_child ("op 1", TREE_OPERAND (t, 1));
558       dump_child ("op 2", TREE_OPERAND (t, 2));
559       break;
560
561     case ARRAY_REF:
562     case ARRAY_RANGE_REF:
563       dump_child ("op 0", TREE_OPERAND (t, 0));
564       dump_child ("op 1", TREE_OPERAND (t, 1));
565       dump_child ("op 2", TREE_OPERAND (t, 2));
566       dump_child ("op 3", TREE_OPERAND (t, 3));
567       break;
568
569     case COND_EXPR:
570       dump_child ("op 0", TREE_OPERAND (t, 0));
571       dump_child ("op 1", TREE_OPERAND (t, 1));
572       dump_child ("op 2", TREE_OPERAND (t, 2));
573       break;
574
575     case TRY_FINALLY_EXPR:
576       dump_child ("op 0", TREE_OPERAND (t, 0));
577       dump_child ("op 1", TREE_OPERAND (t, 1));
578       break;
579
580     case CALL_EXPR:
581       dump_child ("fn", TREE_OPERAND (t, 0));
582       dump_child ("args", TREE_OPERAND (t, 1));
583       break;
584
585     case CONSTRUCTOR:
586       dump_child ("elts", CONSTRUCTOR_ELTS (t));
587       break;
588
589     case BIND_EXPR:
590       dump_child ("vars", TREE_OPERAND (t, 0));
591       dump_child ("body", TREE_OPERAND (t, 1));
592       break;
593
594     case LOOP_EXPR:
595       dump_child ("body", TREE_OPERAND (t, 0));
596       break;
597
598     case EXIT_EXPR:
599       dump_child ("cond", TREE_OPERAND (t, 0));
600       break;
601
602     case RETURN_EXPR:
603       dump_child ("expr", TREE_OPERAND (t, 0));
604       break;
605
606     case TARGET_EXPR:
607       dump_child ("decl", TREE_OPERAND (t, 0));
608       dump_child ("init", TREE_OPERAND (t, 1));
609       dump_child ("clnp", TREE_OPERAND (t, 2));
610       /* There really are two possible places the initializer can be.
611          After RTL expansion, the second operand is moved to the
612          position of the fourth operand, and the second operand
613          becomes NULL.  */
614       dump_child ("init", TREE_OPERAND (t, 3));
615       break;
616
617     case CASE_LABEL_EXPR:
618       dump_child ("name", CASE_LABEL (t));
619       if (CASE_LOW (t)) {
620         dump_child ("low ", CASE_LOW (t));
621         if (CASE_HIGH (t)) {
622           dump_child ("high", CASE_HIGH (t));
623         }
624       }
625       break;
626     case LABEL_EXPR:
627       dump_child ("name", TREE_OPERAND (t,0));
628       break;
629     case GOTO_EXPR:
630       dump_child ("labl", TREE_OPERAND (t, 0));
631       break;
632     case SWITCH_EXPR:
633       dump_child ("cond", TREE_OPERAND (t, 0));
634       dump_child ("body", TREE_OPERAND (t, 1));
635       if (TREE_OPERAND (t, 2))
636         {
637           dump_child ("labl", TREE_OPERAND (t,2));
638         }
639       break;
640     default:
641       /* There are no additional fields to print.  */
642       break;
643     }
644
645  done:
646   if (dump_flag (di, TDF_ADDRESS, NULL))
647     dump_pointer (di, "addr", (void *)t);
648
649   /* Terminate the line.  */
650   fprintf (di->stream, "\n");
651 }
652
653 /* Return nonzero if FLAG has been specified for the dump, and NODE
654    is not the root node of the dump.  */
655
656 int dump_flag (dump_info_p di, int flag, tree node)
657 {
658   return (di->flags & flag) && (node != di->node);
659 }
660
661 /* Dump T, and all its children, on STREAM.  */
662
663 void
664 dump_node (tree t, int flags, FILE *stream)
665 {
666   struct dump_info di;
667   dump_queue_p dq;
668   dump_queue_p next_dq;
669
670   /* Initialize the dump-information structure.  */
671   di.stream = stream;
672   di.index = 0;
673   di.column = 0;
674   di.queue = 0;
675   di.queue_end = 0;
676   di.free_list = 0;
677   di.flags = flags;
678   di.node = t;
679   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
680                              (splay_tree_delete_value_fn) &free);
681
682   /* Queue up the first node.  */
683   queue (&di, t, DUMP_NONE);
684
685   /* Until the queue is empty, keep dumping nodes.  */
686   while (di.queue)
687     dequeue_and_dump (&di);
688
689   /* Now, clean up.  */
690   for (dq = di.free_list; dq; dq = next_dq)
691     {
692       next_dq = dq->next;
693       free (dq);
694     }
695   splay_tree_delete (di.nodes);
696 }
697 \f
698
699 /* Table of tree dump switches. This must be consistent with the
700    TREE_DUMP_INDEX enumeration in tree.h */
701 static struct dump_file_info dump_files[TDI_end] =
702 {
703   {NULL, NULL, NULL, 0, 0, 0, 0},
704   {".tu", "translation-unit", NULL, TDF_TREE, 0, 0, 0},
705   {".class", "class-hierarchy", NULL, TDF_TREE, 0, 1, 0},
706   {".original", "tree-original", NULL, TDF_TREE, 0, 2, 0},
707   {".gimple", "tree-gimple", NULL, TDF_TREE, 0, 3, 0},
708   {".nested", "tree-nested", NULL, TDF_TREE, 0, 4, 0},
709   {".inlined", "tree-inlined", NULL, TDF_TREE, 0, 5, 0},
710   {".vcg", "tree-vcg", NULL, TDF_TREE, 0, 6, 0},
711   {NULL, "tree-all", NULL, TDF_TREE, 0, 0, 0},
712   {NULL, "rtl-all", NULL, TDF_RTL, 0, 0, 0},
713   {NULL, "ipa-all", NULL, TDF_IPA, 0, 0, 0},
714
715   { ".cgraph", "ipa-cgraph", NULL,      TDF_IPA, 0,  0, 0},
716 };
717
718 /* Dynamically registered tree dump files and switches.  */
719 static struct dump_file_info *extra_dump_files;
720 static size_t extra_dump_files_in_use;
721 static size_t extra_dump_files_alloced;
722
723 /* Define a name->number mapping for a dump flag value.  */
724 struct dump_option_value_info
725 {
726   const char *const name;       /* the name of the value */
727   const int value;              /* the value of the name */
728 };
729
730 /* Table of dump options. This must be consistent with the TDF_* flags
731    in tree.h */
732 static const struct dump_option_value_info dump_options[] =
733 {
734   {"address", TDF_ADDRESS},
735   {"slim", TDF_SLIM},
736   {"raw", TDF_RAW},
737   {"details", TDF_DETAILS},
738   {"stats", TDF_STATS},
739   {"blocks", TDF_BLOCKS},
740   {"vops", TDF_VOPS},
741   {"lineno", TDF_LINENO},
742   {"uid", TDF_UID},
743   {"stmtaddr", TDF_STMTADDR},
744   {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA 
745             | TDF_STMTADDR)},
746   {NULL, 0}
747 };
748
749 unsigned int
750 dump_register (const char *suffix, const char *swtch, const char *glob,
751                int flags, unsigned int num, int letter)
752 {
753   size_t this = extra_dump_files_in_use++;
754
755   if (this >= extra_dump_files_alloced)
756     {
757       if (extra_dump_files_alloced == 0)
758         extra_dump_files_alloced = 32;
759       else
760         extra_dump_files_alloced *= 2;
761       extra_dump_files = xrealloc (extra_dump_files,
762                                    sizeof (struct dump_file_info)
763                                    * extra_dump_files_alloced);
764     }
765
766   memset (&extra_dump_files[this], 0, sizeof (struct dump_file_info));
767   extra_dump_files[this].suffix = suffix;
768   extra_dump_files[this].swtch = swtch;
769   extra_dump_files[this].glob = glob;
770   extra_dump_files[this].flags = flags;
771   extra_dump_files[this].num = num;
772   extra_dump_files[this].letter = letter;
773
774   return this + TDI_end;
775 }
776
777
778 /* Return the dump_file_info for the given phase.  */
779
780 struct dump_file_info *
781 get_dump_file_info (enum tree_dump_index phase)
782 {
783   if (phase < TDI_end)
784     return &dump_files[phase];
785   else if (phase - TDI_end >= extra_dump_files_in_use)
786     return NULL;
787   else
788     return extra_dump_files + (phase - TDI_end);
789 }
790
791
792 /* Return the name of the dump file for the given phase.
793    If the dump is not enabled, returns NULL.  */
794
795 char *
796 get_dump_file_name (enum tree_dump_index phase)
797 {
798   char dump_id[7];
799   struct dump_file_info *dfi;
800
801   if (phase == TDI_none)
802     return NULL;
803
804   dfi = get_dump_file_info (phase);
805   if (dfi->state == 0)
806     return NULL;
807
808   if (dfi->num < 0)
809     dump_id[0] = '\0';
810   else
811     {
812       const char *template;
813       if (dfi->flags & TDF_TREE)
814         template = ".t%02d";
815       else if (dfi->flags & TDF_IPA)
816         template = ".i%02d";
817       else
818         template = ".%02d";
819
820       if (snprintf (dump_id, sizeof (dump_id), template, dfi->num) < 0)
821         dump_id[0] = '\0';
822     }
823
824   return concat (dump_base_name, dump_id, dfi->suffix, NULL);
825 }
826
827 /* Begin a tree dump for PHASE. Stores any user supplied flag in
828    *FLAG_PTR and returns a stream to write to. If the dump is not
829    enabled, returns NULL.
830    Multiple calls will reopen and append to the dump file.  */
831
832 FILE *
833 dump_begin (enum tree_dump_index phase, int *flag_ptr)
834 {
835   char *name;
836   struct dump_file_info *dfi;
837   FILE *stream;
838
839   if (phase == TDI_none || !dump_enabled_p (phase))
840     return NULL;
841
842   name = get_dump_file_name (phase);
843   dfi = get_dump_file_info (phase);
844   stream = fopen (name, dfi->state < 0 ? "w" : "a");
845   if (!stream)
846     error ("could not open dump file %qs: %s", name, strerror (errno));
847   else
848     dfi->state = 1;
849   free (name);
850
851   if (flag_ptr)
852     *flag_ptr = dfi->flags;
853
854   return stream;
855 }
856
857 /* Returns nonzero if tree dump PHASE is enabled.  If PHASE is
858    TDI_tree_all, return nonzero if any dump is enabled.  */
859
860 int
861 dump_enabled_p (enum tree_dump_index phase)
862 {
863   if (phase == TDI_tree_all)
864     {
865       size_t i;
866       for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
867         if (dump_files[i].state)
868           return 1;
869       for (i = 0; i < extra_dump_files_in_use; i++)
870         if (extra_dump_files[i].state)
871           return 1;
872       return 0;
873     }
874   else
875     {
876       struct dump_file_info *dfi = get_dump_file_info (phase);
877       return dfi->state;
878     }
879 }
880
881 /* Returns nonzero if tree dump PHASE has been initialized.  */
882
883 int
884 dump_initialized_p (enum tree_dump_index phase)
885 {
886   struct dump_file_info *dfi = get_dump_file_info (phase);
887   return dfi->state > 0;
888 }
889
890 /* Returns the switch name of PHASE.  */
891
892 const char *
893 dump_flag_name (enum tree_dump_index phase)
894 {
895   struct dump_file_info *dfi = get_dump_file_info (phase);
896   return dfi->swtch;
897 }
898
899 /* Finish a tree dump for PHASE. STREAM is the stream created by
900    dump_begin.  */
901
902 void
903 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
904 {
905   fclose (stream);
906 }
907
908 /* Enable all tree dumps.  Return number of enabled tree dumps.  */
909
910 static int
911 dump_enable_all (int flags, int letter)
912 {
913   int n = 0;
914   size_t i;
915
916   for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
917     if ((dump_files[i].flags & flags)
918         && (letter == 0 || letter == dump_files[i].letter))
919       {
920         dump_files[i].state = -1;
921         dump_files[i].flags = flags;
922         n++;
923       }
924
925   for (i = 0; i < extra_dump_files_in_use; i++)
926     if ((extra_dump_files[i].flags & flags)
927         && (letter == 0 || letter == extra_dump_files[i].letter))
928       {
929         extra_dump_files[i].state = -1;
930         extra_dump_files[i].flags = flags;
931         n++;
932       }
933
934   return n;
935 }
936
937 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
938    relevant details in the dump_files array.  */
939
940 static int
941 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
942 {
943   const char *option_value;
944   const char *ptr;
945   int flags;
946   
947   if (doglob && !dfi->glob)
948     return 0;
949
950   option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
951   if (!option_value)
952     return 0;
953
954   ptr = option_value;
955   flags = 0;
956
957   while (*ptr)
958     {
959       const struct dump_option_value_info *option_ptr;
960       const char *end_ptr;
961       unsigned length;
962
963       while (*ptr == '-')
964         ptr++;
965       end_ptr = strchr (ptr, '-');
966       if (!end_ptr)
967         end_ptr = ptr + strlen (ptr);
968       length = end_ptr - ptr;
969
970       for (option_ptr = dump_options; option_ptr->name; option_ptr++)
971         if (strlen (option_ptr->name) == length
972             && !memcmp (option_ptr->name, ptr, length))
973           {
974             flags |= option_ptr->value;
975             goto found;
976           }
977       warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
978                length, ptr, dfi->swtch);
979     found:;
980       ptr = end_ptr;
981     }
982
983   dfi->state = -1;
984   dfi->flags |= flags;
985
986   /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
987      known dumps.  */
988   if (dfi->suffix == NULL)
989     dump_enable_all (dfi->flags, 0);
990
991   return 1;
992 }
993
994 int
995 dump_switch_p (const char *arg)
996 {
997   size_t i;
998   int any = 0;
999
1000   for (i = TDI_none + 1; i != TDI_end; i++)
1001     any |= dump_switch_p_1 (arg, &dump_files[i], false);
1002
1003   /* Don't glob if we got a hit already */
1004   if (!any)
1005     for (i = TDI_none + 1; i != TDI_end; i++)
1006       any |= dump_switch_p_1 (arg, &dump_files[i], true);
1007
1008   for (i = 0; i < extra_dump_files_in_use; i++)
1009     any |= dump_switch_p_1 (arg, &extra_dump_files[i], false);
1010   
1011   if (!any)
1012     for (i = 0; i < extra_dump_files_in_use; i++)
1013       any |= dump_switch_p_1 (arg, &extra_dump_files[i], true);
1014
1015
1016   return any;
1017 }
1018
1019 /* Dump FUNCTION_DECL FN as tree dump PHASE.  */
1020
1021 void
1022 dump_function (enum tree_dump_index phase, tree fn)
1023 {
1024   FILE *stream;
1025   int flags;
1026
1027   stream = dump_begin (phase, &flags);
1028   if (stream)
1029     {
1030       dump_function_to_file (fn, stream, flags);
1031       dump_end (phase, stream);
1032     }
1033 }
1034
1035 bool
1036 enable_rtl_dump_file (int letter)
1037 {
1038   if (letter == 'a')
1039     letter = 0;
1040
1041   return dump_enable_all (TDF_RTL, letter) > 0;
1042 }
1043
1044