OSDN Git Service

dfe2ebbae6e6713f2c8ace553d375dd57b3337f9
[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             abort ();
278
279           dump_string (di, string);
280           queue_and_dump_index (di, "binf", base, DUMP_BINFO);
281         }
282
283       goto done;
284     }
285
286   /* We can knock off a bunch of expression nodes in exactly the same
287      way.  */
288   if (IS_EXPR_CODE_CLASS (code_class))
289     {
290       /* If we're dumping children, dump them now.  */
291       queue_and_dump_type (di, t);
292
293       switch (code_class)
294         {
295         case '1':
296           dump_child ("op 0", TREE_OPERAND (t, 0));
297           break;
298
299         case '2':
300         case '<':
301           dump_child ("op 0", TREE_OPERAND (t, 0));
302           dump_child ("op 1", TREE_OPERAND (t, 1));
303           break;
304
305         case 'e':
306         case 'r':
307         case 's':
308           /* These nodes are handled explicitly below.  */
309           break;
310
311         default:
312           abort ();
313         }
314     }
315   else if (DECL_P (t))
316     {
317       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   /* FIXME  -fdump-call-graph is broken.  Set TDF_TREE when it is fixed.  */
677   {".xml", "call-graph", 0, 0, 7, 0},
678   {NULL, "tree-all", TDF_TREE, 0, 0, 0},
679   {NULL, "rtl-all", TDF_RTL, 0, 0, 0},
680
681   { ".sibling", "rtl-sibling",          TDF_RTL, 0,  1, 'i'},
682   { ".eh", "rtl-eh",                    TDF_RTL, 0,  2, 'h'},
683   { ".jump", "rtl-jump",                TDF_RTL, 0,  3, 'j'},
684   { ".cse", "rtl-cse",                  TDF_RTL, 0,  4, 's'},
685   { ".gcse", "rtl-gcse",                TDF_RTL, 0,  5, 'G'},
686   { ".loop", "rtl-loop",                TDF_RTL, 0,  6, 'L'},
687   { ".bypass", "rtl-bypass",            TDF_RTL, 0,  7, 'G'},
688   { ".cfg", "rtl-cfg",                  TDF_RTL, 0,  8, 'f'},
689   { ".bp", "rtl-bp",                    TDF_RTL, 0,  9, 'b'},
690   { ".vpt", "rtl-vpt",                  TDF_RTL, 0, 10, 'V'},
691   { ".ce1", "rtl-ce1",                  TDF_RTL, 0, 11, 'C'},
692   { ".tracer", "rtl-tracer",            TDF_RTL, 0, 12, 'T'},
693   { ".loop2", "rtl-loop2",              TDF_RTL, 0, 13, 'L'},
694   { ".web", "rtl-web",                  TDF_RTL, 0, 14, 'Z'},
695   { ".cse2", "rtl-cse2",                TDF_RTL, 0, 15, 't'},
696   { ".life", "rtl-life",                TDF_RTL, 0, 16, 'f'},
697   { ".combine", "rtl-combine",          TDF_RTL, 0, 17, 'c'},
698   { ".ce2", "rtl-ce2",                  TDF_RTL, 0, 18, 'C'},
699   { ".regmove", "rtl-regmove",          TDF_RTL, 0, 19, 'N'},
700   { ".sms", "rtl-sms",                  TDF_RTL, 0, 20, 'm'},
701   { ".sched", "rtl-sched",              TDF_RTL, 0, 21, 'S'},
702   { ".lreg", "rtl-lreg",                TDF_RTL, 0, 22, 'l'},
703   { ".greg", "rtl-greg",                TDF_RTL, 0, 23, 'g'},
704   { ".postreload", "rtl-postreload",    TDF_RTL, 0, 24, 'o'},
705   { ".gcse2", "rtl-gcse2",              TDF_RTL, 0, 25, 'J'},
706   { ".flow2", "rtl-flow2",              TDF_RTL, 0, 26, 'w'},
707   { ".peephole2", "rtl-peephole2",      TDF_RTL, 0, 27, 'z'},
708   { ".ce3", "rtl-ce3",                  TDF_RTL, 0, 28, 'E'},
709   { ".rnreg", "rtl-rnreg",              TDF_RTL, 0, 29, 'n'},
710   { ".bbro", "rtl-bbro",                TDF_RTL, 0, 30, 'B'},
711   { ".btl", "rtl-btl",                  TDF_RTL, 0, 31, 'd'},
712   { ".sched2", "rtl-sched2",            TDF_RTL, 0, 32, 'R'},
713   { ".stack", "rtl-stack",              TDF_RTL, 0, 33, 'k'},
714   { ".vartrack", "rtl-vartrack",        TDF_RTL, 0, 34, 'V'},
715   { ".mach", "rtl-mach",                TDF_RTL, 0, 35, 'M'},
716   { ".dbr", "rtl-dbr",                  TDF_RTL, 0, 36, 'd'}
717 };
718
719 /* Dynamically registered tree dump files and switches.  */
720 static struct dump_file_info *extra_dump_files;
721 static size_t extra_dump_files_in_use;
722 static size_t extra_dump_files_alloced;
723
724 /* Define a name->number mapping for a dump flag value.  */
725 struct dump_option_value_info
726 {
727   const char *const name;       /* the name of the value */
728   const int value;              /* the value of the name */
729 };
730
731 /* Table of dump options. This must be consistent with the TDF_* flags
732    in tree.h */
733 static const struct dump_option_value_info dump_options[] =
734 {
735   {"address", TDF_ADDRESS},
736   {"slim", TDF_SLIM},
737   {"raw", TDF_RAW},
738   {"details", TDF_DETAILS},
739   {"stats", TDF_STATS},
740   {"blocks", TDF_BLOCKS},
741   {"vops", TDF_VOPS},
742   {"lineno", TDF_LINENO},
743   {"uid", TDF_UID},
744   {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO)},
745   {NULL, 0}
746 };
747
748 unsigned int
749 dump_register (const char *suffix, const char *swtch, int flags,
750                unsigned int num, int letter)
751 {
752   size_t this = extra_dump_files_in_use++;
753
754   if (this >= extra_dump_files_alloced)
755     {
756       if (extra_dump_files_alloced == 0)
757         extra_dump_files_alloced = 32;
758       else
759         extra_dump_files_alloced *= 2;
760       extra_dump_files = xrealloc (extra_dump_files,
761                                    sizeof (struct dump_file_info)
762                                    * extra_dump_files_alloced);
763     }
764
765   memset (&extra_dump_files[this], 0, sizeof (struct dump_file_info));
766   extra_dump_files[this].suffix = suffix;
767   extra_dump_files[this].swtch = swtch;
768   extra_dump_files[this].flags = flags;
769   extra_dump_files[this].num = num;
770   extra_dump_files[this].letter = letter;
771
772   return this + TDI_end;
773 }
774
775
776 /* Return the dump_file_info for the given phase.  */
777
778 struct dump_file_info *
779 get_dump_file_info (enum tree_dump_index phase)
780 {
781   if (phase < TDI_end)
782     return &dump_files[phase];
783   else if (phase - TDI_end >= extra_dump_files_in_use)
784     return NULL;
785   else
786     return extra_dump_files + (phase - TDI_end);
787 }
788
789
790 /* Return the name of the dump file for the given phase.
791    If the dump is not enabled, returns NULL.  */
792
793 char *
794 get_dump_file_name (enum tree_dump_index phase)
795 {
796   char dump_id[7];
797   struct dump_file_info *dfi;
798
799   if (phase == TDI_none)
800     return NULL;
801
802   dfi = get_dump_file_info (phase);
803   if (dfi->state == 0)
804     return NULL;
805
806   if (dfi->num < 0
807       || snprintf (dump_id, sizeof (dump_id), ".%s%02d",
808                    (dfi->flags & TDF_TREE) ? "t" : "", dfi->num) < 0)
809     dump_id[0] = '\0';
810
811   return concat (dump_base_name, dump_id, dfi->suffix, NULL);
812 }
813
814 /* Begin a tree dump for PHASE. Stores any user supplied flag in
815    *FLAG_PTR and returns a stream to write to. If the dump is not
816    enabled, returns NULL.
817    Multiple calls will reopen and append to the dump file.  */
818
819 FILE *
820 dump_begin (enum tree_dump_index phase, int *flag_ptr)
821 {
822   char *name;
823   struct dump_file_info *dfi;
824   FILE *stream;
825
826   if (phase == TDI_none || !dump_enabled_p (phase))
827     return NULL;
828
829   name = get_dump_file_name (phase);
830   dfi = get_dump_file_info (phase);
831   stream = fopen (name, dfi->state < 0 ? "w" : "a");
832   if (!stream)
833     error ("could not open dump file `%s': %s", name, strerror (errno));
834   else
835     dfi->state = 1;
836   free (name);
837
838   if (flag_ptr)
839     *flag_ptr = dfi->flags;
840
841   return stream;
842 }
843
844 /* Returns nonzero if tree dump PHASE is enabled.  */
845
846 int
847 dump_enabled_p (enum tree_dump_index phase)
848 {
849   struct dump_file_info *dfi = get_dump_file_info (phase);
850   return dfi->state;
851 }
852
853 /* Returns nonzero if tree dump PHASE has been initialized.  */
854
855 int
856 dump_initialized_p (enum tree_dump_index phase)
857 {
858   struct dump_file_info *dfi = get_dump_file_info (phase);
859   return dfi->state > 0;
860 }
861
862 /* Returns the switch name of PHASE.  */
863
864 const char *
865 dump_flag_name (enum tree_dump_index phase)
866 {
867   struct dump_file_info *dfi = get_dump_file_info (phase);
868   return dfi->swtch;
869 }
870
871 /* Finish a tree dump for PHASE. STREAM is the stream created by
872    dump_begin.  */
873
874 void
875 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
876 {
877   fclose (stream);
878 }
879
880 /* Enable all tree dumps.  Return number of enabled tree dumps.  */
881
882 static int
883 dump_enable_all (int flags, int letter)
884 {
885   int n = 0;
886   size_t i;
887
888   for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
889     if ((dump_files[i].flags & flags)
890         && (letter == 0 || letter == dump_files[i].letter))
891       {
892         dump_files[i].state = -1;
893         dump_files[i].flags = flags;
894         n++;
895       }
896
897   for (i = 0; i < extra_dump_files_in_use; i++)
898     if ((extra_dump_files[i].flags & flags)
899         && (letter == 0 || letter == extra_dump_files[i].letter))
900       {
901         extra_dump_files[i].state = -1;
902         extra_dump_files[i].flags = flags;
903         n++;
904       }
905
906   return n;
907 }
908
909 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
910    relevant details in the dump_files array.  */
911
912 static int
913 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi)
914 {
915   const char *option_value;
916   const char *ptr;
917   int flags;
918
919   option_value = skip_leading_substring (arg, dfi->swtch);
920   if (!option_value)
921     return 0;
922
923   ptr = option_value;
924   flags = 0;
925
926   while (*ptr)
927     {
928       const struct dump_option_value_info *option_ptr;
929       const char *end_ptr;
930       unsigned length;
931
932       while (*ptr == '-')
933         ptr++;
934       end_ptr = strchr (ptr, '-');
935       if (!end_ptr)
936         end_ptr = ptr + strlen (ptr);
937       length = end_ptr - ptr;
938
939       for (option_ptr = dump_options; option_ptr->name; option_ptr++)
940         if (strlen (option_ptr->name) == length
941             && !memcmp (option_ptr->name, ptr, length))
942           {
943             flags |= option_ptr->value;
944             goto found;
945           }
946       warning ("ignoring unknown option `%.*s' in `-fdump-%s'",
947                length, ptr, dfi->swtch);
948     found:;
949       ptr = end_ptr;
950     }
951
952   dfi->state = -1;
953   dfi->flags |= flags;
954
955   /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
956      known dumps.  */
957   if (dfi->suffix == NULL)
958     dump_enable_all (dfi->flags, 0);
959
960   return 1;
961 }
962
963 int
964 dump_switch_p (const char *arg)
965 {
966   size_t i;
967   int any = 0;
968
969   for (i = TDI_none + 1; i != TDI_end; i++)
970     any |= dump_switch_p_1 (arg, &dump_files[i]);
971
972   for (i = 0; i < extra_dump_files_in_use; i++)
973     any |= dump_switch_p_1 (arg, &extra_dump_files[i]);
974
975   return any;
976 }
977
978 /* Dump FUNCTION_DECL FN as tree dump PHASE.  */
979
980 void
981 dump_function (enum tree_dump_index phase, tree fn)
982 {
983   FILE *stream;
984   int flags;
985
986   stream = dump_begin (phase, &flags);
987   if (stream)
988     {
989       dump_function_to_file (fn, stream, flags);
990       dump_end (phase, stream);
991     }
992 }
993
994 bool
995 enable_rtl_dump_file (int letter)
996 {
997   if (letter == 'a')
998     letter = 0;
999
1000   return dump_enable_all (TDF_RTL, letter) > 0;
1001 }
1002
1003