OSDN Git Service

23fbf07103a1cafdde6d0a824fb4a73a7b48729f
[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   { ".sibling", "rtl-sibling", NULL,    TDF_RTL, 0,  1, 'i'},
718   { ".eh", "rtl-eh", NULL,              TDF_RTL, 0,  2, 'h'},
719   { ".jump", "rtl-jump", NULL,          TDF_RTL, 0,  3, 'j'},
720   { ".cse", "rtl-cse", NULL,             TDF_RTL, 0,  4, 's'},
721   { ".gcse", "rtl-gcse", NULL,          TDF_RTL, 0,  5, 'G'},
722   { ".loop", "rtl-loop", NULL,          TDF_RTL, 0,  6, 'L'},
723   { ".bypass", "rtl-bypass", NULL,              TDF_RTL, 0,  7, 'G'},
724   { ".cfg", "rtl-cfg", NULL,                    TDF_RTL, 0,  8, 'f'},
725   { ".bp", "rtl-bp", NULL,                      TDF_RTL, 0,  9, 'b'},
726   { ".vpt", "rtl-vpt", NULL,                    TDF_RTL, 0, 10, 'V'},
727   { ".ce1", "rtl-ce1", NULL,                    TDF_RTL, 0, 11, 'C'},
728   { ".tracer", "rtl-tracer", NULL,              TDF_RTL, 0, 12, 'T'},
729   { ".loop2", "rtl-loop2", NULL,                TDF_RTL, 0, 13, 'L'},
730   { ".web", "rtl-web", NULL,                    TDF_RTL, 0, 14, 'Z'},
731   { ".cse2", "rtl-cse2", NULL,          TDF_RTL, 0, 15, 't'},
732   { ".life", "rtl-life", NULL,          TDF_RTL, 0, 16, 'f'},
733   { ".combine", "rtl-combine", NULL,            TDF_RTL, 0, 17, 'c'},
734   { ".ce2", "rtl-ce2", NULL,                    TDF_RTL, 0, 18, 'C'},
735   { ".regmove", "rtl-regmove", NULL,            TDF_RTL, 0, 19, 'N'},
736   { ".sms", "rtl-sms", NULL,                    TDF_RTL, 0, 20, 'm'},
737   { ".sched", "rtl-sched", NULL,                TDF_RTL, 0, 21, 'S'},
738   { ".lreg", "rtl-lreg", NULL,          TDF_RTL, 0, 22, 'l'},
739   { ".greg", "rtl-greg", NULL,          TDF_RTL, 0, 23, 'g'},
740   { ".postreload", "rtl-postreload", NULL,      TDF_RTL, 0, 24, 'o'},
741   { ".gcse2", "rtl-gcse2", NULL,                TDF_RTL, 0, 25, 'J'},
742   { ".flow2", "rtl-flow2", NULL,                TDF_RTL, 0, 26, 'w'},
743   { ".peephole2", "rtl-peephole2", NULL,        TDF_RTL, 0, 27, 'z'},
744   { ".ce3", "rtl-ce3", NULL,                    TDF_RTL, 0, 28, 'E'},
745   { ".rnreg", "rtl-rnreg", NULL,                TDF_RTL, 0, 29, 'n'},
746   { ".bbro", "rtl-bbro", NULL,          TDF_RTL, 0, 30, 'B'},
747   { ".btl", "rtl-btl", NULL,                    TDF_RTL, 0, 31, 'd'},
748   { ".sched2", "rtl-sched2", NULL,              TDF_RTL, 0, 32, 'R'},
749   { ".stack", "rtl-stack", NULL,                TDF_RTL, 0, 33, 'k'},
750   { ".vartrack", "rtl-vartrack", NULL,  TDF_RTL, 0, 34, 'V'},
751   { ".mach", "rtl-mach", NULL,          TDF_RTL, 0, 35, 'M'},
752   { ".dbr", "rtl-dbr", NULL,                    TDF_RTL, 0, 36, 'd'}
753 };
754
755 /* Dynamically registered tree dump files and switches.  */
756 static struct dump_file_info *extra_dump_files;
757 static size_t extra_dump_files_in_use;
758 static size_t extra_dump_files_alloced;
759
760 /* Define a name->number mapping for a dump flag value.  */
761 struct dump_option_value_info
762 {
763   const char *const name;       /* the name of the value */
764   const int value;              /* the value of the name */
765 };
766
767 /* Table of dump options. This must be consistent with the TDF_* flags
768    in tree.h */
769 static const struct dump_option_value_info dump_options[] =
770 {
771   {"address", TDF_ADDRESS},
772   {"slim", TDF_SLIM},
773   {"raw", TDF_RAW},
774   {"details", TDF_DETAILS},
775   {"stats", TDF_STATS},
776   {"blocks", TDF_BLOCKS},
777   {"vops", TDF_VOPS},
778   {"lineno", TDF_LINENO},
779   {"uid", TDF_UID},
780   {"stmtaddr", TDF_STMTADDR},
781   {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA 
782             | TDF_STMTADDR)},
783   {NULL, 0}
784 };
785
786 unsigned int
787 dump_register (const char *suffix, const char *swtch, const char *glob,
788                int flags, unsigned int num, int letter)
789 {
790   size_t this = extra_dump_files_in_use++;
791
792   if (this >= extra_dump_files_alloced)
793     {
794       if (extra_dump_files_alloced == 0)
795         extra_dump_files_alloced = 32;
796       else
797         extra_dump_files_alloced *= 2;
798       extra_dump_files = xrealloc (extra_dump_files,
799                                    sizeof (struct dump_file_info)
800                                    * extra_dump_files_alloced);
801     }
802
803   memset (&extra_dump_files[this], 0, sizeof (struct dump_file_info));
804   extra_dump_files[this].suffix = suffix;
805   extra_dump_files[this].swtch = swtch;
806   extra_dump_files[this].glob = glob;
807   extra_dump_files[this].flags = flags;
808   extra_dump_files[this].num = num;
809   extra_dump_files[this].letter = letter;
810
811   return this + TDI_end;
812 }
813
814
815 /* Return the dump_file_info for the given phase.  */
816
817 struct dump_file_info *
818 get_dump_file_info (enum tree_dump_index phase)
819 {
820   if (phase < TDI_end)
821     return &dump_files[phase];
822   else if (phase - TDI_end >= extra_dump_files_in_use)
823     return NULL;
824   else
825     return extra_dump_files + (phase - TDI_end);
826 }
827
828
829 /* Return the name of the dump file for the given phase.
830    If the dump is not enabled, returns NULL.  */
831
832 char *
833 get_dump_file_name (enum tree_dump_index phase)
834 {
835   char dump_id[7];
836   struct dump_file_info *dfi;
837
838   if (phase == TDI_none)
839     return NULL;
840
841   dfi = get_dump_file_info (phase);
842   if (dfi->state == 0)
843     return NULL;
844
845   if (dfi->num < 0)
846     dump_id[0] = '\0';
847   else
848     {
849       const char *template;
850       if (dfi->flags & TDF_TREE)
851         template = ".t%02d";
852       else if (dfi->flags & TDF_IPA)
853         template = ".i%02d";
854       else
855         template = ".%02d";
856
857       if (snprintf (dump_id, sizeof (dump_id), template, dfi->num) < 0)
858         dump_id[0] = '\0';
859     }
860
861   return concat (dump_base_name, dump_id, dfi->suffix, NULL);
862 }
863
864 /* Begin a tree dump for PHASE. Stores any user supplied flag in
865    *FLAG_PTR and returns a stream to write to. If the dump is not
866    enabled, returns NULL.
867    Multiple calls will reopen and append to the dump file.  */
868
869 FILE *
870 dump_begin (enum tree_dump_index phase, int *flag_ptr)
871 {
872   char *name;
873   struct dump_file_info *dfi;
874   FILE *stream;
875
876   if (phase == TDI_none || !dump_enabled_p (phase))
877     return NULL;
878
879   name = get_dump_file_name (phase);
880   dfi = get_dump_file_info (phase);
881   stream = fopen (name, dfi->state < 0 ? "w" : "a");
882   if (!stream)
883     error ("could not open dump file %qs: %s", name, strerror (errno));
884   else
885     dfi->state = 1;
886   free (name);
887
888   if (flag_ptr)
889     *flag_ptr = dfi->flags;
890
891   return stream;
892 }
893
894 /* Returns nonzero if tree dump PHASE is enabled.  If PHASE is
895    TDI_tree_all, return nonzero if any dump is enabled.  */
896
897 int
898 dump_enabled_p (enum tree_dump_index phase)
899 {
900   if (phase == TDI_tree_all)
901     {
902       size_t i;
903       for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
904         if (dump_files[i].state)
905           return 1;
906       for (i = 0; i < extra_dump_files_in_use; i++)
907         if (extra_dump_files[i].state)
908           return 1;
909       return 0;
910     }
911   else
912     {
913       struct dump_file_info *dfi = get_dump_file_info (phase);
914       return dfi->state;
915     }
916 }
917
918 /* Returns nonzero if tree dump PHASE has been initialized.  */
919
920 int
921 dump_initialized_p (enum tree_dump_index phase)
922 {
923   struct dump_file_info *dfi = get_dump_file_info (phase);
924   return dfi->state > 0;
925 }
926
927 /* Returns the switch name of PHASE.  */
928
929 const char *
930 dump_flag_name (enum tree_dump_index phase)
931 {
932   struct dump_file_info *dfi = get_dump_file_info (phase);
933   return dfi->swtch;
934 }
935
936 /* Finish a tree dump for PHASE. STREAM is the stream created by
937    dump_begin.  */
938
939 void
940 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
941 {
942   fclose (stream);
943 }
944
945 /* Enable all tree dumps.  Return number of enabled tree dumps.  */
946
947 static int
948 dump_enable_all (int flags, int letter)
949 {
950   int n = 0;
951   size_t i;
952
953   for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
954     if ((dump_files[i].flags & flags)
955         && (letter == 0 || letter == dump_files[i].letter))
956       {
957         dump_files[i].state = -1;
958         dump_files[i].flags = flags;
959         n++;
960       }
961
962   for (i = 0; i < extra_dump_files_in_use; i++)
963     if ((extra_dump_files[i].flags & flags)
964         && (letter == 0 || letter == extra_dump_files[i].letter))
965       {
966         extra_dump_files[i].state = -1;
967         extra_dump_files[i].flags = flags;
968         n++;
969       }
970
971   return n;
972 }
973
974 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
975    relevant details in the dump_files array.  */
976
977 static int
978 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
979 {
980   const char *option_value;
981   const char *ptr;
982   int flags;
983   
984   if (doglob && !dfi->glob)
985     return 0;
986
987   option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
988   if (!option_value)
989     return 0;
990
991   ptr = option_value;
992   flags = 0;
993
994   while (*ptr)
995     {
996       const struct dump_option_value_info *option_ptr;
997       const char *end_ptr;
998       unsigned length;
999
1000       while (*ptr == '-')
1001         ptr++;
1002       end_ptr = strchr (ptr, '-');
1003       if (!end_ptr)
1004         end_ptr = ptr + strlen (ptr);
1005       length = end_ptr - ptr;
1006
1007       for (option_ptr = dump_options; option_ptr->name; option_ptr++)
1008         if (strlen (option_ptr->name) == length
1009             && !memcmp (option_ptr->name, ptr, length))
1010           {
1011             flags |= option_ptr->value;
1012             goto found;
1013           }
1014       warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
1015                length, ptr, dfi->swtch);
1016     found:;
1017       ptr = end_ptr;
1018     }
1019
1020   dfi->state = -1;
1021   dfi->flags |= flags;
1022
1023   /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
1024      known dumps.  */
1025   if (dfi->suffix == NULL)
1026     dump_enable_all (dfi->flags, 0);
1027
1028   return 1;
1029 }
1030
1031 int
1032 dump_switch_p (const char *arg)
1033 {
1034   size_t i;
1035   int any = 0;
1036
1037   for (i = TDI_none + 1; i != TDI_end; i++)
1038     any |= dump_switch_p_1 (arg, &dump_files[i], false);
1039
1040   /* Don't glob if we got a hit already */
1041   if (!any)
1042     for (i = TDI_none + 1; i != TDI_end; i++)
1043       any |= dump_switch_p_1 (arg, &dump_files[i], true);
1044
1045   for (i = 0; i < extra_dump_files_in_use; i++)
1046     any |= dump_switch_p_1 (arg, &extra_dump_files[i], false);
1047   
1048   if (!any)
1049     for (i = 0; i < extra_dump_files_in_use; i++)
1050       any |= dump_switch_p_1 (arg, &extra_dump_files[i], true);
1051
1052
1053   return any;
1054 }
1055
1056 /* Dump FUNCTION_DECL FN as tree dump PHASE.  */
1057
1058 void
1059 dump_function (enum tree_dump_index phase, tree fn)
1060 {
1061   FILE *stream;
1062   int flags;
1063
1064   stream = dump_begin (phase, &flags);
1065   if (stream)
1066     {
1067       dump_function_to_file (fn, stream, flags);
1068       dump_end (phase, stream);
1069     }
1070 }
1071
1072 bool
1073 enable_rtl_dump_file (int letter)
1074 {
1075   if (letter == 'a')
1076     letter = 0;
1077
1078   return dump_enable_all (TDF_RTL, letter) > 0;
1079 }
1080
1081