OSDN Git Service

Fix install doc problems reported by Jean-Paul Rigault
[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, 59 Temple Place - Suite 330, Boston, MA
21 02111-1307, 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 void dump_string_field (dump_info_p, const char *, const char *);
42 static int dump_enable_all (int, int);
43
44 /* Add T to the end of the queue of nodes to dump.  Returns the index
45    assigned to T.  */
46
47 static unsigned int
48 queue (dump_info_p di, tree t, int flags)
49 {
50   dump_queue_p dq;
51   dump_node_info_p dni;
52   unsigned int index;
53
54   /* Assign the next available index to T.  */
55   index = ++di->index;
56
57   /* Obtain a new queue node.  */
58   if (di->free_list)
59     {
60       dq = di->free_list;
61       di->free_list = dq->next;
62     }
63   else
64     dq = xmalloc (sizeof (struct dump_queue));
65
66   /* Create a new entry in the splay-tree.  */
67   dni = xmalloc (sizeof (struct dump_node_info));
68   dni->index = index;
69   dni->binfo_p = ((flags & DUMP_BINFO) != 0);
70   dq->node = splay_tree_insert (di->nodes, (splay_tree_key) t,
71                                 (splay_tree_value) dni);
72
73   /* Add it to the end of the queue.  */
74   dq->next = 0;
75   if (!di->queue_end)
76     di->queue = dq;
77   else
78     di->queue_end->next = dq;
79   di->queue_end = dq;
80
81   /* Return the index.  */
82   return index;
83 }
84
85 static void
86 dump_index (dump_info_p di, unsigned int index)
87 {
88   fprintf (di->stream, "@%-6u ", index);
89   di->column += 8;
90 }
91
92 /* If T has not already been output, queue it for subsequent output.
93    FIELD is a string to print before printing the index.  Then, the
94    index of T is printed.  */
95
96 void
97 queue_and_dump_index (dump_info_p di, const char *field, tree t, int flags)
98 {
99   unsigned int index;
100   splay_tree_node n;
101
102   /* If there's no node, just return.  This makes for fewer checks in
103      our callers.  */
104   if (!t)
105     return;
106
107   /* See if we've already queued or dumped this node.  */
108   n = splay_tree_lookup (di->nodes, (splay_tree_key) t);
109   if (n)
110     index = ((dump_node_info_p) n->value)->index;
111   else
112     /* If we haven't, add it to the queue.  */
113     index = queue (di, t, flags);
114
115   /* Print the index of the node.  */
116   dump_maybe_newline (di);
117   fprintf (di->stream, "%-4s: ", field);
118   di->column += 6;
119   dump_index (di, index);
120 }
121
122 /* Dump the type of T.  */
123
124 void
125 queue_and_dump_type (dump_info_p di, tree t)
126 {
127   queue_and_dump_index (di, "type", TREE_TYPE (t), DUMP_NONE);
128 }
129
130 /* Dump column control */
131 #define SOL_COLUMN 25           /* Start of line column.  */
132 #define EOL_COLUMN 55           /* End of line column.  */
133 #define COLUMN_ALIGNMENT 15     /* Alignment.  */
134
135 /* Insert a new line in the dump output, and indent to an appropriate
136    place to start printing more fields.  */
137
138 static void
139 dump_new_line (dump_info_p di)
140 {
141   fprintf (di->stream, "\n%*s", SOL_COLUMN, "");
142   di->column = SOL_COLUMN;
143 }
144
145 /* If necessary, insert a new line.  */
146
147 static void
148 dump_maybe_newline (dump_info_p di)
149 {
150   int extra;
151
152   /* See if we need a new line.  */
153   if (di->column > EOL_COLUMN)
154     dump_new_line (di);
155   /* See if we need any padding.  */
156   else if ((extra = (di->column - SOL_COLUMN) % COLUMN_ALIGNMENT) != 0)
157     {
158       fprintf (di->stream, "%*s", COLUMN_ALIGNMENT - extra, "");
159       di->column += COLUMN_ALIGNMENT - extra;
160     }
161 }
162
163 /* Dump pointer PTR using FIELD to identify it.  */
164
165 void
166 dump_pointer (dump_info_p di, const char *field, void *ptr)
167 {
168   dump_maybe_newline (di);
169   fprintf (di->stream, "%-4s: %-8lx ", field, (long) ptr);
170   di->column += 15;
171 }
172
173 /* Dump integer I using FIELD to identify it.  */
174
175 void
176 dump_int (dump_info_p di, const char *field, int i)
177 {
178   dump_maybe_newline (di);
179   fprintf (di->stream, "%-4s: %-7d ", field, i);
180   di->column += 14;
181 }
182
183 /* Dump the string S.  */
184
185 void
186 dump_string (dump_info_p di, const char *string)
187 {
188   dump_maybe_newline (di);
189   fprintf (di->stream, "%-13s ", string);
190   if (strlen (string) > 13)
191     di->column += strlen (string) + 1;
192   else
193     di->column += 14;
194 }
195
196 /* Dump the string field S.  */
197
198 static void
199 dump_string_field (dump_info_p di, const char *field, const char *string)
200 {
201   dump_maybe_newline (di);
202   fprintf (di->stream, "%-4s: %-7s ", field, string);
203   if (strlen (string) > 7)
204     di->column += 6 + strlen (string) + 1;
205   else
206     di->column += 14;
207 }
208
209 /* Dump the next node in the queue.  */
210
211 static void
212 dequeue_and_dump (dump_info_p di)
213 {
214   dump_queue_p dq;
215   splay_tree_node stn;
216   dump_node_info_p dni;
217   tree t;
218   unsigned int index;
219   enum tree_code code;
220   enum tree_code_class code_class;
221   const char* code_name;
222
223   /* Get the next node from the queue.  */
224   dq = di->queue;
225   stn = dq->node;
226   t = (tree) stn->key;
227   dni = (dump_node_info_p) stn->value;
228   index = dni->index;
229
230   /* Remove the node from the queue, and put it on the free list.  */
231   di->queue = dq->next;
232   if (!di->queue)
233     di->queue_end = 0;
234   dq->next = di->free_list;
235   di->free_list = dq;
236
237   /* Print the node index.  */
238   dump_index (di, index);
239   /* And the type of node this is.  */
240   if (dni->binfo_p)
241     code_name = "binfo";
242   else
243     code_name = tree_code_name[(int) TREE_CODE (t)];
244   fprintf (di->stream, "%-16s ", code_name);
245   di->column = 25;
246
247   /* Figure out what kind of node this is.  */
248   code = TREE_CODE (t);
249   code_class = TREE_CODE_CLASS (code);
250
251   /* Although BINFOs are TREE_VECs, we dump them specially so as to be
252      more informative.  */
253   if (dni->binfo_p)
254     {
255       unsigned ix;
256       tree base;
257       VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (t);
258
259       dump_child ("type", BINFO_TYPE (t));
260
261       if (BINFO_VIRTUAL_P (t))
262         dump_string (di, "virt");
263
264       dump_int (di, "bases", BINFO_N_BASE_BINFOS (t));
265       for (ix = 0; BINFO_BASE_ITERATE (t, ix, base); ix++)
266         {
267           tree access = (accesses ? VEC_index (tree, accesses, ix)
268                          : access_public_node);
269           const char *string = NULL;
270
271           if (access == access_public_node)
272             string = "pub";
273           else if (access == access_protected_node)
274             string = "prot";
275           else if (access == access_private_node)
276             string = "priv";
277           else
278             gcc_unreachable ();
279
280           dump_string (di, string);
281           queue_and_dump_index (di, "binf", base, DUMP_BINFO);
282         }
283
284       goto done;
285     }
286
287   /* We can knock off a bunch of expression nodes in exactly the same
288      way.  */
289   if (IS_EXPR_CODE_CLASS (code_class))
290     {
291       /* If we're dumping children, dump them now.  */
292       queue_and_dump_type (di, t);
293
294       switch (code_class)
295         {
296         case tcc_unary:
297           dump_child ("op 0", TREE_OPERAND (t, 0));
298           break;
299
300         case tcc_binary:
301         case tcc_comparison:
302           dump_child ("op 0", TREE_OPERAND (t, 0));
303           dump_child ("op 1", TREE_OPERAND (t, 1));
304           break;
305
306         case tcc_expression:
307         case tcc_reference:
308         case tcc_statement:
309           /* These nodes are handled explicitly below.  */
310           break;
311
312         default:
313           gcc_unreachable ();
314         }
315     }
316   else if (DECL_P (t))
317     {
318       expanded_location xloc;
319       /* All declarations have names.  */
320       if (DECL_NAME (t))
321         dump_child ("name", DECL_NAME (t));
322       if (DECL_ASSEMBLER_NAME_SET_P (t)
323           && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t))
324         dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
325       /* And types.  */
326       queue_and_dump_type (di, t);
327       dump_child ("scpe", DECL_CONTEXT (t));
328       /* And a source position.  */
329       xloc = expand_location (DECL_SOURCE_LOCATION (t));
330       if (xloc.file)
331         {
332           const char *filename = strrchr (xloc.file, '/');
333           if (!filename)
334             filename = xloc.file;
335           else
336             /* Skip the slash.  */
337             ++filename;
338
339           dump_maybe_newline (di);
340           fprintf (di->stream, "srcp: %s:%-6d ", filename,
341                    xloc.line);
342           di->column += 6 + strlen (filename) + 8;
343         }
344       /* And any declaration can be compiler-generated.  */
345       if (DECL_ARTIFICIAL (t))
346         dump_string (di, "artificial");
347       if (TREE_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
348         dump_child ("chan", TREE_CHAIN (t));
349     }
350   else if (code_class == tcc_type)
351     {
352       /* All types have qualifiers.  */
353       int quals = lang_hooks.tree_dump.type_quals (t);
354
355       if (quals != TYPE_UNQUALIFIED)
356         {
357           fprintf (di->stream, "qual: %c%c%c     ",
358                    (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
359                    (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
360                    (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
361           di->column += 14;
362         }
363
364       /* All types have associated declarations.  */
365       dump_child ("name", TYPE_NAME (t));
366
367       /* All types have a main variant.  */
368       if (TYPE_MAIN_VARIANT (t) != t)
369         dump_child ("unql", TYPE_MAIN_VARIANT (t));
370
371       /* And sizes.  */
372       dump_child ("size", TYPE_SIZE (t));
373
374       /* All types have alignments.  */
375       dump_int (di, "algn", TYPE_ALIGN (t));
376     }
377   else if (code_class == tcc_constant)
378     /* All constants can have types.  */
379     queue_and_dump_type (di, t);
380
381   /* Give the language-specific code a chance to print something.  If
382      it's completely taken care of things, don't bother printing
383      anything more ourselves.  */
384   if (lang_hooks.tree_dump.dump_tree (di, t))
385     goto done;
386
387   /* Now handle the various kinds of nodes.  */
388   switch (code)
389     {
390       int i;
391
392     case IDENTIFIER_NODE:
393       dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
394       dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
395       break;
396
397     case TREE_LIST:
398       dump_child ("purp", TREE_PURPOSE (t));
399       dump_child ("valu", TREE_VALUE (t));
400       dump_child ("chan", TREE_CHAIN (t));
401       break;
402
403     case STATEMENT_LIST:
404       {
405         tree_stmt_iterator it;
406         for (i = 0, it = tsi_start (t); !tsi_end_p (it); tsi_next (&it), i++)
407           {
408             char buffer[32];
409             sprintf (buffer, "%u", i);
410             dump_child (buffer, tsi_stmt (it));
411           }
412       }
413       break;
414
415     case TREE_VEC:
416       dump_int (di, "lngt", TREE_VEC_LENGTH (t));
417       for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
418         {
419           char buffer[32];
420           sprintf (buffer, "%u", i);
421           dump_child (buffer, TREE_VEC_ELT (t, i));
422         }
423       break;
424
425     case INTEGER_TYPE:
426     case ENUMERAL_TYPE:
427       dump_int (di, "prec", TYPE_PRECISION (t));
428       if (TYPE_UNSIGNED (t))
429         dump_string (di, "unsigned");
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 (di, "struct");
467       else
468         dump_string (di, "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 (di, "register");
502         }
503       break;
504
505     case FUNCTION_DECL:
506       dump_child ("args", DECL_ARGUMENTS (t));
507       if (DECL_EXTERNAL (t))
508         dump_string (di, "undefined");
509       if (TREE_PUBLIC (t))
510         dump_string (di, "extern");
511       else
512         dump_string (di, "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 CALL_EXPR:
576       dump_child ("fn", TREE_OPERAND (t, 0));
577       dump_child ("args", TREE_OPERAND (t, 1));
578       break;
579
580     case CONSTRUCTOR:
581       dump_child ("elts", CONSTRUCTOR_ELTS (t));
582       break;
583
584     case BIND_EXPR:
585       dump_child ("vars", TREE_OPERAND (t, 0));
586       dump_child ("body", TREE_OPERAND (t, 1));
587       break;
588
589     case LOOP_EXPR:
590       dump_child ("body", TREE_OPERAND (t, 0));
591       break;
592
593     case EXIT_EXPR:
594       dump_child ("cond", TREE_OPERAND (t, 0));
595       break;
596
597     case TARGET_EXPR:
598       dump_child ("decl", TREE_OPERAND (t, 0));
599       dump_child ("init", TREE_OPERAND (t, 1));
600       dump_child ("clnp", TREE_OPERAND (t, 2));
601       /* There really are two possible places the initializer can be.
602          After RTL expansion, the second operand is moved to the
603          position of the fourth operand, and the second operand
604          becomes NULL.  */
605       dump_child ("init", TREE_OPERAND (t, 3));
606       break;
607
608     default:
609       /* There are no additional fields to print.  */
610       break;
611     }
612
613  done:
614   if (dump_flag (di, TDF_ADDRESS, NULL))
615     dump_pointer (di, "addr", (void *)t);
616
617   /* Terminate the line.  */
618   fprintf (di->stream, "\n");
619 }
620
621 /* Return nonzero if FLAG has been specified for the dump, and NODE
622    is not the root node of the dump.  */
623
624 int dump_flag (dump_info_p di, int flag, tree node)
625 {
626   return (di->flags & flag) && (node != di->node);
627 }
628
629 /* Dump T, and all its children, on STREAM.  */
630
631 void
632 dump_node (tree t, int flags, FILE *stream)
633 {
634   struct dump_info di;
635   dump_queue_p dq;
636   dump_queue_p next_dq;
637
638   /* Initialize the dump-information structure.  */
639   di.stream = stream;
640   di.index = 0;
641   di.column = 0;
642   di.queue = 0;
643   di.queue_end = 0;
644   di.free_list = 0;
645   di.flags = flags;
646   di.node = t;
647   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
648                              (splay_tree_delete_value_fn) &free);
649
650   /* Queue up the first node.  */
651   queue (&di, t, DUMP_NONE);
652
653   /* Until the queue is empty, keep dumping nodes.  */
654   while (di.queue)
655     dequeue_and_dump (&di);
656
657   /* Now, clean up.  */
658   for (dq = di.free_list; dq; dq = next_dq)
659     {
660       next_dq = dq->next;
661       free (dq);
662     }
663   splay_tree_delete (di.nodes);
664 }
665 \f
666
667 /* Table of tree dump switches. This must be consistent with the
668    TREE_DUMP_INDEX enumeration in tree.h */
669 static struct dump_file_info dump_files[TDI_end] =
670 {
671   {NULL, NULL, NULL, 0, 0, 0, 0},
672   {".tu", "translation-unit", NULL, TDF_TREE, 0, 0, 0},
673   {".class", "class-hierarchy", NULL, TDF_TREE, 0, 1, 0},
674   {".original", "tree-original", NULL, TDF_TREE, 0, 2, 0},
675   {".generic", "tree-generic", NULL, TDF_TREE, 0, 3, 0},
676   {".nested", "tree-nested", NULL, TDF_TREE, 0, 4, 0},
677   {".inlined", "tree-inlined", NULL, TDF_TREE, 0, 5, 0},
678   {".vcg", "tree-vcg", NULL, TDF_TREE, 0, 6, 0},
679   {NULL, "tree-all", NULL, TDF_TREE, 0, 0, 0},
680   {NULL, "rtl-all", NULL, TDF_RTL, 0, 0, 0},
681   {NULL, "ipa-all", NULL, TDF_IPA, 0, 0, 0},
682
683   { ".cgraph", "ipa-cgraph", NULL,      TDF_IPA, 0,  1, 0},
684
685   { ".sibling", "rtl-sibling", NULL,    TDF_RTL, 0,  1, 'i'},
686   { ".eh", "rtl-eh", NULL,              TDF_RTL, 0,  2, 'h'},
687   { ".jump", "rtl-jump", NULL,          TDF_RTL, 0,  3, 'j'},
688   { ".cse", "rtl-cse", NULL,             TDF_RTL, 0,  4, 's'},
689   { ".gcse", "rtl-gcse", NULL,          TDF_RTL, 0,  5, 'G'},
690   { ".loop", "rtl-loop", NULL,          TDF_RTL, 0,  6, 'L'},
691   { ".bypass", "rtl-bypass", NULL,              TDF_RTL, 0,  7, 'G'},
692   { ".cfg", "rtl-cfg", NULL,                    TDF_RTL, 0,  8, 'f'},
693   { ".bp", "rtl-bp", NULL,                      TDF_RTL, 0,  9, 'b'},
694   { ".vpt", "rtl-vpt", NULL,                    TDF_RTL, 0, 10, 'V'},
695   { ".ce1", "rtl-ce1", NULL,                    TDF_RTL, 0, 11, 'C'},
696   { ".tracer", "rtl-tracer", NULL,              TDF_RTL, 0, 12, 'T'},
697   { ".loop2", "rtl-loop2", NULL,                TDF_RTL, 0, 13, 'L'},
698   { ".web", "rtl-web", NULL,                    TDF_RTL, 0, 14, 'Z'},
699   { ".cse2", "rtl-cse2", NULL,          TDF_RTL, 0, 15, 't'},
700   { ".life", "rtl-life", NULL,          TDF_RTL, 0, 16, 'f'},
701   { ".combine", "rtl-combine", NULL,            TDF_RTL, 0, 17, 'c'},
702   { ".ce2", "rtl-ce2", NULL,                    TDF_RTL, 0, 18, 'C'},
703   { ".regmove", "rtl-regmove", NULL,            TDF_RTL, 0, 19, 'N'},
704   { ".sms", "rtl-sms", NULL,                    TDF_RTL, 0, 20, 'm'},
705   { ".sched", "rtl-sched", NULL,                TDF_RTL, 0, 21, 'S'},
706   { ".lreg", "rtl-lreg", NULL,          TDF_RTL, 0, 22, 'l'},
707   { ".greg", "rtl-greg", NULL,          TDF_RTL, 0, 23, 'g'},
708   { ".postreload", "rtl-postreload", NULL,      TDF_RTL, 0, 24, 'o'},
709   { ".gcse2", "rtl-gcse2", NULL,                TDF_RTL, 0, 25, 'J'},
710   { ".flow2", "rtl-flow2", NULL,                TDF_RTL, 0, 26, 'w'},
711   { ".peephole2", "rtl-peephole2", NULL,        TDF_RTL, 0, 27, 'z'},
712   { ".ce3", "rtl-ce3", NULL,                    TDF_RTL, 0, 28, 'E'},
713   { ".rnreg", "rtl-rnreg", NULL,                TDF_RTL, 0, 29, 'n'},
714   { ".bbro", "rtl-bbro", NULL,          TDF_RTL, 0, 30, 'B'},
715   { ".btl", "rtl-btl", NULL,                    TDF_RTL, 0, 31, 'd'},
716   { ".sched2", "rtl-sched2", NULL,              TDF_RTL, 0, 32, 'R'},
717   { ".stack", "rtl-stack", NULL,                TDF_RTL, 0, 33, 'k'},
718   { ".vartrack", "rtl-vartrack", NULL,  TDF_RTL, 0, 34, 'V'},
719   { ".mach", "rtl-mach", NULL,          TDF_RTL, 0, 35, 'M'},
720   { ".dbr", "rtl-dbr", NULL,                    TDF_RTL, 0, 36, 'd'}
721 };
722
723 /* Dynamically registered tree dump files and switches.  */
724 static struct dump_file_info *extra_dump_files;
725 static size_t extra_dump_files_in_use;
726 static size_t extra_dump_files_alloced;
727
728 /* Define a name->number mapping for a dump flag value.  */
729 struct dump_option_value_info
730 {
731   const char *const name;       /* the name of the value */
732   const int value;              /* the value of the name */
733 };
734
735 /* Table of dump options. This must be consistent with the TDF_* flags
736    in tree.h */
737 static const struct dump_option_value_info dump_options[] =
738 {
739   {"address", TDF_ADDRESS},
740   {"slim", TDF_SLIM},
741   {"raw", TDF_RAW},
742   {"details", TDF_DETAILS},
743   {"stats", TDF_STATS},
744   {"blocks", TDF_BLOCKS},
745   {"vops", TDF_VOPS},
746   {"lineno", TDF_LINENO},
747   {"uid", TDF_UID},
748   {"stmtaddr", TDF_STMTADDR},
749   {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA 
750             | TDF_STMTADDR)},
751   {NULL, 0}
752 };
753
754 unsigned int
755 dump_register (const char *suffix, const char *swtch, const char *glob,
756                int flags, unsigned int num, int letter)
757 {
758   size_t this = extra_dump_files_in_use++;
759
760   if (this >= extra_dump_files_alloced)
761     {
762       if (extra_dump_files_alloced == 0)
763         extra_dump_files_alloced = 32;
764       else
765         extra_dump_files_alloced *= 2;
766       extra_dump_files = xrealloc (extra_dump_files,
767                                    sizeof (struct dump_file_info)
768                                    * extra_dump_files_alloced);
769     }
770
771   memset (&extra_dump_files[this], 0, sizeof (struct dump_file_info));
772   extra_dump_files[this].suffix = suffix;
773   extra_dump_files[this].swtch = swtch;
774   extra_dump_files[this].glob = glob;
775   extra_dump_files[this].flags = flags;
776   extra_dump_files[this].num = num;
777   extra_dump_files[this].letter = letter;
778
779   return this + TDI_end;
780 }
781
782
783 /* Return the dump_file_info for the given phase.  */
784
785 struct dump_file_info *
786 get_dump_file_info (enum tree_dump_index phase)
787 {
788   if (phase < TDI_end)
789     return &dump_files[phase];
790   else if (phase - TDI_end >= extra_dump_files_in_use)
791     return NULL;
792   else
793     return extra_dump_files + (phase - TDI_end);
794 }
795
796
797 /* Return the name of the dump file for the given phase.
798    If the dump is not enabled, returns NULL.  */
799
800 char *
801 get_dump_file_name (enum tree_dump_index phase)
802 {
803   char dump_id[7];
804   struct dump_file_info *dfi;
805
806   if (phase == TDI_none)
807     return NULL;
808
809   dfi = get_dump_file_info (phase);
810   if (dfi->state == 0)
811     return NULL;
812
813   if (dfi->num < 0)
814     dump_id[0] = '\0';
815   else
816     {
817       const char *template;
818       if (dfi->flags & TDF_TREE)
819         template = ".t%02d";
820       else if (dfi->flags & TDF_IPA)
821         template = ".i%02d";
822       else
823         template = ".%02d";
824
825       if (snprintf (dump_id, sizeof (dump_id), template, dfi->num) < 0)
826         dump_id[0] = '\0';
827     }
828
829   return concat (dump_base_name, dump_id, dfi->suffix, NULL);
830 }
831
832 /* Begin a tree dump for PHASE. Stores any user supplied flag in
833    *FLAG_PTR and returns a stream to write to. If the dump is not
834    enabled, returns NULL.
835    Multiple calls will reopen and append to the dump file.  */
836
837 FILE *
838 dump_begin (enum tree_dump_index phase, int *flag_ptr)
839 {
840   char *name;
841   struct dump_file_info *dfi;
842   FILE *stream;
843
844   if (phase == TDI_none || !dump_enabled_p (phase))
845     return NULL;
846
847   name = get_dump_file_name (phase);
848   dfi = get_dump_file_info (phase);
849   stream = fopen (name, dfi->state < 0 ? "w" : "a");
850   if (!stream)
851     error ("could not open dump file %qs: %s", name, strerror (errno));
852   else
853     dfi->state = 1;
854   free (name);
855
856   if (flag_ptr)
857     *flag_ptr = dfi->flags;
858
859   return stream;
860 }
861
862 /* Returns nonzero if tree dump PHASE is enabled.  */
863
864 int
865 dump_enabled_p (enum tree_dump_index phase)
866 {
867   struct dump_file_info *dfi = get_dump_file_info (phase);
868   return dfi->state;
869 }
870
871 /* Returns nonzero if tree dump PHASE has been initialized.  */
872
873 int
874 dump_initialized_p (enum tree_dump_index phase)
875 {
876   struct dump_file_info *dfi = get_dump_file_info (phase);
877   return dfi->state > 0;
878 }
879
880 /* Returns the switch name of PHASE.  */
881
882 const char *
883 dump_flag_name (enum tree_dump_index phase)
884 {
885   struct dump_file_info *dfi = get_dump_file_info (phase);
886   return dfi->swtch;
887 }
888
889 /* Finish a tree dump for PHASE. STREAM is the stream created by
890    dump_begin.  */
891
892 void
893 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
894 {
895   fclose (stream);
896 }
897
898 /* Enable all tree dumps.  Return number of enabled tree dumps.  */
899
900 static int
901 dump_enable_all (int flags, int letter)
902 {
903   int n = 0;
904   size_t i;
905
906   for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
907     if ((dump_files[i].flags & flags)
908         && (letter == 0 || letter == dump_files[i].letter))
909       {
910         dump_files[i].state = -1;
911         dump_files[i].flags = flags;
912         n++;
913       }
914
915   for (i = 0; i < extra_dump_files_in_use; i++)
916     if ((extra_dump_files[i].flags & flags)
917         && (letter == 0 || letter == extra_dump_files[i].letter))
918       {
919         extra_dump_files[i].state = -1;
920         extra_dump_files[i].flags = flags;
921         n++;
922       }
923
924   return n;
925 }
926
927 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
928    relevant details in the dump_files array.  */
929
930 static int
931 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
932 {
933   const char *option_value;
934   const char *ptr;
935   int flags;
936   
937   if (doglob && !dfi->glob)
938     return 0;
939
940   option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
941   if (!option_value)
942     return 0;
943
944   ptr = option_value;
945   flags = 0;
946
947   while (*ptr)
948     {
949       const struct dump_option_value_info *option_ptr;
950       const char *end_ptr;
951       unsigned length;
952
953       while (*ptr == '-')
954         ptr++;
955       end_ptr = strchr (ptr, '-');
956       if (!end_ptr)
957         end_ptr = ptr + strlen (ptr);
958       length = end_ptr - ptr;
959
960       for (option_ptr = dump_options; option_ptr->name; option_ptr++)
961         if (strlen (option_ptr->name) == length
962             && !memcmp (option_ptr->name, ptr, length))
963           {
964             flags |= option_ptr->value;
965             goto found;
966           }
967       warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
968                length, ptr, dfi->swtch);
969     found:;
970       ptr = end_ptr;
971     }
972
973   dfi->state = -1;
974   dfi->flags |= flags;
975
976   /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
977      known dumps.  */
978   if (dfi->suffix == NULL)
979     dump_enable_all (dfi->flags, 0);
980
981   return 1;
982 }
983
984 int
985 dump_switch_p (const char *arg)
986 {
987   size_t i;
988   int any = 0;
989
990   for (i = TDI_none + 1; i != TDI_end; i++)
991     any |= dump_switch_p_1 (arg, &dump_files[i], false);
992
993   /* Don't glob if we got a hit already */
994   if (!any)
995     for (i = TDI_none + 1; i != TDI_end; i++)
996       any |= dump_switch_p_1 (arg, &dump_files[i], true);
997
998   for (i = 0; i < extra_dump_files_in_use; i++)
999     any |= dump_switch_p_1 (arg, &extra_dump_files[i], false);
1000   
1001   if (!any)
1002     for (i = 0; i < extra_dump_files_in_use; i++)
1003       any |= dump_switch_p_1 (arg, &extra_dump_files[i], true);
1004
1005
1006   return any;
1007 }
1008
1009 /* Dump FUNCTION_DECL FN as tree dump PHASE.  */
1010
1011 void
1012 dump_function (enum tree_dump_index phase, tree fn)
1013 {
1014   FILE *stream;
1015   int flags;
1016
1017   stream = dump_begin (phase, &flags);
1018   if (stream)
1019     {
1020       dump_function_to_file (fn, stream, flags);
1021       dump_end (phase, stream);
1022     }
1023 }
1024
1025 bool
1026 enable_rtl_dump_file (int letter)
1027 {
1028   if (letter == 'a')
1029     letter = 0;
1030
1031   return dump_enable_all (TDF_RTL, letter) > 0;
1032 }
1033
1034