OSDN Git Service

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