GCC47: Add local modifications
[dragonfly.git] / contrib / gcc-4.1 / gcc / tree-dump.c
1 /* Tree-dumping functionality for intermediate representation.
2    Copyright (C) 1999, 2000, 2002, 2003, 2004, 2005
3    Free Software Foundation, Inc.
4    Written by Mark Mitchell <mark@codesourcery.com>
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING.  If not, write to the Free
20 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.  */
22
23 #include "config.h"
24 #include "system.h"
25 #include "coretypes.h"
26 #include "tm.h"
27 #include "tree.h"
28 #include "splay-tree.h"
29 #include "diagnostic.h"
30 #include "toplev.h"
31 #include "tree-dump.h"
32 #include "tree-pass.h"
33 #include "langhooks.h"
34 #include "tree-iterator.h"
35
36 static unsigned int queue (dump_info_p, tree, int);
37 static void dump_index (dump_info_p, unsigned int);
38 static void dequeue_and_dump (dump_info_p);
39 static void dump_new_line (dump_info_p);
40 static void dump_maybe_newline (dump_info_p);
41 static int dump_enable_all (int, int);
42
43 /* Add T to the end of the queue of nodes to dump.  Returns the index
44    assigned to T.  */
45
46 static unsigned int
47 queue (dump_info_p di, tree t, int flags)
48 {
49   dump_queue_p dq;
50   dump_node_info_p dni;
51   unsigned int index;
52
53   /* Assign the next available index to T.  */
54   index = ++di->index;
55
56   /* Obtain a new queue node.  */
57   if (di->free_list)
58     {
59       dq = di->free_list;
60       di->free_list = dq->next;
61     }
62   else
63     dq = xmalloc (sizeof (struct dump_queue));
64
65   /* Create a new entry in the splay-tree.  */
66   dni = xmalloc (sizeof (struct dump_node_info));
67   dni->index = index;
68   dni->binfo_p = ((flags & DUMP_BINFO) != 0);
69   dq->node = splay_tree_insert (di->nodes, (splay_tree_key) t,
70                                 (splay_tree_value) dni);
71
72   /* Add it to the end of the queue.  */
73   dq->next = 0;
74   if (!di->queue_end)
75     di->queue = dq;
76   else
77     di->queue_end->next = dq;
78   di->queue_end = dq;
79
80   /* Return the index.  */
81   return index;
82 }
83
84 static void
85 dump_index (dump_info_p di, unsigned int index)
86 {
87   fprintf (di->stream, "@%-6u ", index);
88   di->column += 8;
89 }
90
91 /* If T has not already been output, queue it for subsequent output.
92    FIELD is a string to print before printing the index.  Then, the
93    index of T is printed.  */
94
95 void
96 queue_and_dump_index (dump_info_p di, const char *field, tree t, int flags)
97 {
98   unsigned int index;
99   splay_tree_node n;
100
101   /* If there's no node, just return.  This makes for fewer checks in
102      our callers.  */
103   if (!t)
104     return;
105
106   /* See if we've already queued or dumped this node.  */
107   n = splay_tree_lookup (di->nodes, (splay_tree_key) t);
108   if (n)
109     index = ((dump_node_info_p) n->value)->index;
110   else
111     /* If we haven't, add it to the queue.  */
112     index = queue (di, t, flags);
113
114   /* Print the index of the node.  */
115   dump_maybe_newline (di);
116   fprintf (di->stream, "%-4s: ", field);
117   di->column += 6;
118   dump_index (di, index);
119 }
120
121 /* Dump the type of T.  */
122
123 void
124 queue_and_dump_type (dump_info_p di, tree t)
125 {
126   queue_and_dump_index (di, "type", TREE_TYPE (t), DUMP_NONE);
127 }
128
129 /* Dump column control */
130 #define SOL_COLUMN 25           /* Start of line column.  */
131 #define EOL_COLUMN 55           /* End of line column.  */
132 #define COLUMN_ALIGNMENT 15     /* Alignment.  */
133
134 /* Insert a new line in the dump output, and indent to an appropriate
135    place to start printing more fields.  */
136
137 static void
138 dump_new_line (dump_info_p di)
139 {
140   fprintf (di->stream, "\n%*s", SOL_COLUMN, "");
141   di->column = SOL_COLUMN;
142 }
143
144 /* If necessary, insert a new line.  */
145
146 static void
147 dump_maybe_newline (dump_info_p di)
148 {
149   int extra;
150
151   /* See if we need a new line.  */
152   if (di->column > EOL_COLUMN)
153     dump_new_line (di);
154   /* See if we need any padding.  */
155   else if ((extra = (di->column - SOL_COLUMN) % COLUMN_ALIGNMENT) != 0)
156     {
157       fprintf (di->stream, "%*s", COLUMN_ALIGNMENT - extra, "");
158       di->column += COLUMN_ALIGNMENT - extra;
159     }
160 }
161
162 /* Dump pointer PTR using FIELD to identify it.  */
163
164 void
165 dump_pointer (dump_info_p di, const char *field, void *ptr)
166 {
167   dump_maybe_newline (di);
168   fprintf (di->stream, "%-4s: %-8lx ", field, (long) ptr);
169   di->column += 15;
170 }
171
172 /* Dump integer I using FIELD to identify it.  */
173
174 void
175 dump_int (dump_info_p di, const char *field, int i)
176 {
177   dump_maybe_newline (di);
178   fprintf (di->stream, "%-4s: %-7d ", field, i);
179   di->column += 14;
180 }
181
182 /* Dump the string S.  */
183
184 void
185 dump_string (dump_info_p di, const char *string)
186 {
187   dump_maybe_newline (di);
188   fprintf (di->stream, "%-13s ", string);
189   if (strlen (string) > 13)
190     di->column += strlen (string) + 1;
191   else
192     di->column += 14;
193 }
194
195 /* Dump the string field S.  */
196
197 void
198 dump_string_field (dump_info_p di, const char *field, const char *string)
199 {
200   dump_maybe_newline (di);
201   fprintf (di->stream, "%-4s: %-7s ", field, string);
202   if (strlen (string) > 7)
203     di->column += 6 + strlen (string) + 1;
204   else
205     di->column += 14;
206 }
207
208 /* Dump the next node in the queue.  */
209
210 static void
211 dequeue_and_dump (dump_info_p di)
212 {
213   dump_queue_p dq;
214   splay_tree_node stn;
215   dump_node_info_p dni;
216   tree t;
217   unsigned int index;
218   enum tree_code code;
219   enum tree_code_class code_class;
220   const char* code_name;
221
222   /* Get the next node from the queue.  */
223   dq = di->queue;
224   stn = dq->node;
225   t = (tree) stn->key;
226   dni = (dump_node_info_p) stn->value;
227   index = dni->index;
228
229   /* Remove the node from the queue, and put it on the free list.  */
230   di->queue = dq->next;
231   if (!di->queue)
232     di->queue_end = 0;
233   dq->next = di->free_list;
234   di->free_list = dq;
235
236   /* Print the node index.  */
237   dump_index (di, index);
238   /* And the type of node this is.  */
239   if (dni->binfo_p)
240     code_name = "binfo";
241   else
242     code_name = tree_code_name[(int) TREE_CODE (t)];
243   fprintf (di->stream, "%-16s ", code_name);
244   di->column = 25;
245
246   /* Figure out what kind of node this is.  */
247   code = TREE_CODE (t);
248   code_class = TREE_CODE_CLASS (code);
249
250   /* Although BINFOs are TREE_VECs, we dump them specially so as to be
251      more informative.  */
252   if (dni->binfo_p)
253     {
254       unsigned ix;
255       tree base;
256       VEC(tree,gc) *accesses = BINFO_BASE_ACCESSES (t);
257
258       dump_child ("type", BINFO_TYPE (t));
259
260       if (BINFO_VIRTUAL_P (t))
261         dump_string_field (di, "spec", "virt");
262
263       dump_int (di, "bases", BINFO_N_BASE_BINFOS (t));
264       for (ix = 0; BINFO_BASE_ITERATE (t, ix, base); ix++)
265         {
266           tree access = (accesses ? VEC_index (tree, accesses, ix)
267                          : access_public_node);
268           const char *string = NULL;
269
270           if (access == access_public_node)
271             string = "pub";
272           else if (access == access_protected_node)
273             string = "prot";
274           else if (access == access_private_node)
275             string = "priv";
276           else
277             gcc_unreachable ();
278
279           dump_string_field (di, "accs", string);
280           queue_and_dump_index (di, "binf", base, DUMP_BINFO);
281         }
282
283       goto done;
284     }
285
286   /* We can knock off a bunch of expression nodes in exactly the same
287      way.  */
288   if (IS_EXPR_CODE_CLASS (code_class))
289     {
290       /* If we're dumping children, dump them now.  */
291       queue_and_dump_type (di, t);
292
293       switch (code_class)
294         {
295         case tcc_unary:
296           dump_child ("op 0", TREE_OPERAND (t, 0));
297           break;
298
299         case tcc_binary:
300         case tcc_comparison:
301           dump_child ("op 0", TREE_OPERAND (t, 0));
302           dump_child ("op 1", TREE_OPERAND (t, 1));
303           break;
304
305         case tcc_expression:
306         case tcc_reference:
307         case tcc_statement:
308           /* These nodes are handled explicitly below.  */
309           break;
310
311         default:
312           gcc_unreachable ();
313         }
314     }
315   else if (DECL_P (t))
316     {
317       expanded_location xloc;
318       /* All declarations have names.  */
319       if (DECL_NAME (t))
320         dump_child ("name", DECL_NAME (t));
321       if (DECL_ASSEMBLER_NAME_SET_P (t)
322           && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t))
323         dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
324       if (DECL_ABSTRACT_ORIGIN (t))
325         dump_child ("orig", DECL_ABSTRACT_ORIGIN (t));
326       /* And types.  */
327       queue_and_dump_type (di, t);
328       dump_child ("scpe", DECL_CONTEXT (t));
329       /* And a source position.  */
330       xloc = expand_location (DECL_SOURCE_LOCATION (t));
331       if (xloc.file)
332         {
333           const char *filename = strrchr (xloc.file, '/');
334           if (!filename)
335             filename = xloc.file;
336           else
337             /* Skip the slash.  */
338             ++filename;
339
340           dump_maybe_newline (di);
341           fprintf (di->stream, "srcp: %s:%-6d ", filename,
342                    xloc.line);
343           di->column += 6 + strlen (filename) + 8;
344         }
345       /* And any declaration can be compiler-generated.  */
346       if (DECL_ARTIFICIAL (t))
347         dump_string_field (di, "note", "artificial");
348       if (TREE_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
349         dump_child ("chan", TREE_CHAIN (t));
350     }
351   else if (code_class == tcc_type)
352     {
353       /* All types have qualifiers.  */
354       int quals = lang_hooks.tree_dump.type_quals (t);
355
356       if (quals != TYPE_UNQUALIFIED)
357         {
358           fprintf (di->stream, "qual: %c%c%c     ",
359                    (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
360                    (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
361                    (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
362           di->column += 14;
363         }
364
365       /* All types have associated declarations.  */
366       dump_child ("name", TYPE_NAME (t));
367
368       /* All types have a main variant.  */
369       if (TYPE_MAIN_VARIANT (t) != t)
370         dump_child ("unql", TYPE_MAIN_VARIANT (t));
371
372       /* And sizes.  */
373       dump_child ("size", TYPE_SIZE (t));
374
375       /* All types have alignments.  */
376       dump_int (di, "algn", TYPE_ALIGN (t));
377     }
378   else if (code_class == tcc_constant)
379     /* All constants can have types.  */
380     queue_and_dump_type (di, t);
381
382   /* Give the language-specific code a chance to print something.  If
383      it's completely taken care of things, don't bother printing
384      anything more ourselves.  */
385   if (lang_hooks.tree_dump.dump_tree (di, t))
386     goto done;
387
388   /* Now handle the various kinds of nodes.  */
389   switch (code)
390     {
391       int i;
392
393     case IDENTIFIER_NODE:
394       dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
395       dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
396       break;
397
398     case TREE_LIST:
399       dump_child ("purp", TREE_PURPOSE (t));
400       dump_child ("valu", TREE_VALUE (t));
401       dump_child ("chan", TREE_CHAIN (t));
402       break;
403
404     case STATEMENT_LIST:
405       {
406         tree_stmt_iterator it;
407         for (i = 0, it = tsi_start (t); !tsi_end_p (it); tsi_next (&it), i++)
408           {
409             char buffer[32];
410             sprintf (buffer, "%u", i);
411             dump_child (buffer, tsi_stmt (it));
412           }
413       }
414       break;
415
416     case TREE_VEC:
417       dump_int (di, "lngt", TREE_VEC_LENGTH (t));
418       for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
419         {
420           char buffer[32];
421           sprintf (buffer, "%u", i);
422           dump_child (buffer, TREE_VEC_ELT (t, i));
423         }
424       break;
425
426     case INTEGER_TYPE:
427     case ENUMERAL_TYPE:
428       dump_int (di, "prec", TYPE_PRECISION (t));
429       dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed");
430       dump_child ("min", TYPE_MIN_VALUE (t));
431       dump_child ("max", TYPE_MAX_VALUE (t));
432
433       if (code == ENUMERAL_TYPE)
434         dump_child ("csts", TYPE_VALUES (t));
435       break;
436
437     case REAL_TYPE:
438       dump_int (di, "prec", TYPE_PRECISION (t));
439       break;
440
441     case POINTER_TYPE:
442       dump_child ("ptd", TREE_TYPE (t));
443       break;
444
445     case REFERENCE_TYPE:
446       dump_child ("refd", TREE_TYPE (t));
447       break;
448
449     case METHOD_TYPE:
450       dump_child ("clas", TYPE_METHOD_BASETYPE (t));
451       /* Fall through.  */
452
453     case FUNCTION_TYPE:
454       dump_child ("retn", TREE_TYPE (t));
455       dump_child ("prms", TYPE_ARG_TYPES (t));
456       break;
457
458     case ARRAY_TYPE:
459       dump_child ("elts", TREE_TYPE (t));
460       dump_child ("domn", TYPE_DOMAIN (t));
461       break;
462
463     case RECORD_TYPE:
464     case UNION_TYPE:
465       if (TREE_CODE (t) == RECORD_TYPE)
466         dump_string_field (di, "tag", "struct");
467       else
468         dump_string_field (di, "tag", "union");
469
470       dump_child ("flds", TYPE_FIELDS (t));
471       dump_child ("fncs", TYPE_METHODS (t));
472       queue_and_dump_index (di, "binf", TYPE_BINFO (t),
473                             DUMP_BINFO);
474       break;
475
476     case CONST_DECL:
477       dump_child ("cnst", DECL_INITIAL (t));
478       break;
479
480     case VAR_DECL:
481     case PARM_DECL:
482     case FIELD_DECL:
483     case RESULT_DECL:
484       if (TREE_CODE (t) == PARM_DECL)
485         dump_child ("argt", DECL_ARG_TYPE (t));
486       else
487         dump_child ("init", DECL_INITIAL (t));
488       dump_child ("size", DECL_SIZE (t));
489       dump_int (di, "algn", DECL_ALIGN (t));
490
491       if (TREE_CODE (t) == FIELD_DECL)
492         {
493           if (DECL_FIELD_OFFSET (t))
494             dump_child ("bpos", bit_position (t));
495         }
496       else if (TREE_CODE (t) == VAR_DECL
497                || TREE_CODE (t) == PARM_DECL)
498         {
499           dump_int (di, "used", TREE_USED (t));
500           if (DECL_REGISTER (t))
501             dump_string_field (di, "spec", "register");
502         }
503       break;
504
505     case FUNCTION_DECL:
506       dump_child ("args", DECL_ARGUMENTS (t));
507       if (DECL_EXTERNAL (t))
508         dump_string_field (di, "body", "undefined");
509       if (TREE_PUBLIC (t))
510         dump_string_field (di, "link", "extern");
511       else
512         dump_string_field (di, "link", "static");
513       if (DECL_LANG_SPECIFIC (t) && !dump_flag (di, TDF_SLIM, t))
514         dump_child ("body", DECL_SAVED_TREE (t));
515       break;
516
517     case INTEGER_CST:
518       if (TREE_INT_CST_HIGH (t))
519         dump_int (di, "high", TREE_INT_CST_HIGH (t));
520       dump_int (di, "low", TREE_INT_CST_LOW (t));
521       break;
522
523     case STRING_CST:
524       fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
525       dump_int (di, "lngt", TREE_STRING_LENGTH (t));
526       break;
527
528     case TRUTH_NOT_EXPR:
529     case ADDR_EXPR:
530     case INDIRECT_REF:
531     case ALIGN_INDIRECT_REF:
532     case MISALIGNED_INDIRECT_REF:
533     case CLEANUP_POINT_EXPR:
534     case SAVE_EXPR:
535     case REALPART_EXPR:
536     case IMAGPART_EXPR:
537       /* These nodes are unary, but do not have code class `1'.  */
538       dump_child ("op 0", TREE_OPERAND (t, 0));
539       break;
540
541     case TRUTH_ANDIF_EXPR:
542     case TRUTH_ORIF_EXPR:
543     case INIT_EXPR:
544     case MODIFY_EXPR:
545     case COMPOUND_EXPR:
546     case PREDECREMENT_EXPR:
547     case PREINCREMENT_EXPR:
548     case POSTDECREMENT_EXPR:
549     case POSTINCREMENT_EXPR:
550       /* These nodes are binary, but do not have code class `2'.  */
551       dump_child ("op 0", TREE_OPERAND (t, 0));
552       dump_child ("op 1", TREE_OPERAND (t, 1));
553       break;
554
555     case COMPONENT_REF:
556       dump_child ("op 0", TREE_OPERAND (t, 0));
557       dump_child ("op 1", TREE_OPERAND (t, 1));
558       dump_child ("op 2", TREE_OPERAND (t, 2));
559       break;
560
561     case ARRAY_REF:
562     case ARRAY_RANGE_REF:
563       dump_child ("op 0", TREE_OPERAND (t, 0));
564       dump_child ("op 1", TREE_OPERAND (t, 1));
565       dump_child ("op 2", TREE_OPERAND (t, 2));
566       dump_child ("op 3", TREE_OPERAND (t, 3));
567       break;
568
569     case COND_EXPR:
570       dump_child ("op 0", TREE_OPERAND (t, 0));
571       dump_child ("op 1", TREE_OPERAND (t, 1));
572       dump_child ("op 2", TREE_OPERAND (t, 2));
573       break;
574
575     case TRY_FINALLY_EXPR:
576       dump_child ("op 0", TREE_OPERAND (t, 0));
577       dump_child ("op 1", TREE_OPERAND (t, 1));
578       break;
579
580     case CALL_EXPR:
581       dump_child ("fn", TREE_OPERAND (t, 0));
582       dump_child ("args", TREE_OPERAND (t, 1));
583       break;
584
585     case CONSTRUCTOR:
586       {
587         unsigned HOST_WIDE_INT cnt;
588         tree index, value;
589         dump_int (di, "lngt", VEC_length (constructor_elt,
590                                           CONSTRUCTOR_ELTS (t)));
591         FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), cnt, index, value)
592           {
593             dump_child ("idx", index);
594             dump_child ("val", value);
595           }
596       }
597       break;
598
599     case BIND_EXPR:
600       dump_child ("vars", TREE_OPERAND (t, 0));
601       dump_child ("body", TREE_OPERAND (t, 1));
602       break;
603
604     case LOOP_EXPR:
605       dump_child ("body", TREE_OPERAND (t, 0));
606       break;
607
608     case EXIT_EXPR:
609       dump_child ("cond", TREE_OPERAND (t, 0));
610       break;
611
612     case RETURN_EXPR:
613       dump_child ("expr", TREE_OPERAND (t, 0));
614       break;
615
616     case TARGET_EXPR:
617       dump_child ("decl", TREE_OPERAND (t, 0));
618       dump_child ("init", TREE_OPERAND (t, 1));
619       dump_child ("clnp", TREE_OPERAND (t, 2));
620       /* There really are two possible places the initializer can be.
621          After RTL expansion, the second operand is moved to the
622          position of the fourth operand, and the second operand
623          becomes NULL.  */
624       dump_child ("init", TREE_OPERAND (t, 3));
625       break;
626
627     case CASE_LABEL_EXPR:
628       dump_child ("name", CASE_LABEL (t));
629       if (CASE_LOW (t)) {
630         dump_child ("low ", CASE_LOW (t));
631         if (CASE_HIGH (t)) {
632           dump_child ("high", CASE_HIGH (t));
633         }
634       }
635       break;
636     case LABEL_EXPR:
637       dump_child ("name", TREE_OPERAND (t,0));
638       break;
639     case GOTO_EXPR:
640       dump_child ("labl", TREE_OPERAND (t, 0));
641       break;
642     case SWITCH_EXPR:
643       dump_child ("cond", TREE_OPERAND (t, 0));
644       dump_child ("body", TREE_OPERAND (t, 1));
645       if (TREE_OPERAND (t, 2))
646         {
647           dump_child ("labl", TREE_OPERAND (t,2));
648         }
649       break;
650     default:
651       /* There are no additional fields to print.  */
652       break;
653     }
654
655  done:
656   if (dump_flag (di, TDF_ADDRESS, NULL))
657     dump_pointer (di, "addr", (void *)t);
658
659   /* Terminate the line.  */
660   fprintf (di->stream, "\n");
661 }
662
663 /* Return nonzero if FLAG has been specified for the dump, and NODE
664    is not the root node of the dump.  */
665
666 int dump_flag (dump_info_p di, int flag, tree node)
667 {
668   return (di->flags & flag) && (node != di->node);
669 }
670
671 /* Dump T, and all its children, on STREAM.  */
672
673 void
674 dump_node (tree t, int flags, FILE *stream)
675 {
676   struct dump_info di;
677   dump_queue_p dq;
678   dump_queue_p next_dq;
679
680   /* Initialize the dump-information structure.  */
681   di.stream = stream;
682   di.index = 0;
683   di.column = 0;
684   di.queue = 0;
685   di.queue_end = 0;
686   di.free_list = 0;
687   di.flags = flags;
688   di.node = t;
689   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
690                              (splay_tree_delete_value_fn) &free);
691
692   /* Queue up the first node.  */
693   queue (&di, t, DUMP_NONE);
694
695   /* Until the queue is empty, keep dumping nodes.  */
696   while (di.queue)
697     dequeue_and_dump (&di);
698
699   /* Now, clean up.  */
700   for (dq = di.free_list; dq; dq = next_dq)
701     {
702       next_dq = dq->next;
703       free (dq);
704     }
705   splay_tree_delete (di.nodes);
706 }
707 \f
708
709 /* Table of tree dump switches. This must be consistent with the
710    TREE_DUMP_INDEX enumeration in tree.h */
711 static struct dump_file_info dump_files[TDI_end] =
712 {
713   {NULL, NULL, NULL, 0, 0, 0, 0},
714   {".tu", "translation-unit", NULL, TDF_TREE, 0, 0, 0},
715   {".class", "class-hierarchy", NULL, TDF_TREE, 0, 1, 0},
716   {".original", "tree-original", NULL, TDF_TREE, 0, 2, 0},
717   {".gimple", "tree-gimple", NULL, TDF_TREE, 0, 3, 0},
718   {".nested", "tree-nested", NULL, TDF_TREE, 0, 4, 0},
719   {".inlined", "tree-inlined", NULL, TDF_TREE, 0, 5, 0},
720   {".vcg", "tree-vcg", NULL, TDF_TREE, 0, 6, 0},
721   {NULL, "tree-all", NULL, TDF_TREE, 0, 0, 0},
722   {NULL, "rtl-all", NULL, TDF_RTL, 0, 0, 0},
723   {NULL, "ipa-all", NULL, TDF_IPA, 0, 0, 0},
724
725   { ".cgraph", "ipa-cgraph", NULL,      TDF_IPA, 0,  0, 0},
726 };
727
728 /* Dynamically registered tree dump files and switches.  */
729 static struct dump_file_info *extra_dump_files;
730 static size_t extra_dump_files_in_use;
731 static size_t extra_dump_files_alloced;
732
733 /* Define a name->number mapping for a dump flag value.  */
734 struct dump_option_value_info
735 {
736   const char *const name;       /* the name of the value */
737   const int value;              /* the value of the name */
738 };
739
740 /* Table of dump options. This must be consistent with the TDF_* flags
741    in tree.h */
742 static const struct dump_option_value_info dump_options[] =
743 {
744   {"address", TDF_ADDRESS},
745   {"slim", TDF_SLIM},
746   {"raw", TDF_RAW},
747   {"details", TDF_DETAILS},
748   {"stats", TDF_STATS},
749   {"blocks", TDF_BLOCKS},
750   {"vops", TDF_VOPS},
751   {"lineno", TDF_LINENO},
752   {"uid", TDF_UID},
753   {"stmtaddr", TDF_STMTADDR},
754   {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA 
755             | TDF_STMTADDR | TDF_GRAPH)},
756   {NULL, 0}
757 };
758
759 unsigned int
760 dump_register (const char *suffix, const char *swtch, const char *glob,
761                int flags, unsigned int num, int letter)
762 {
763   size_t this = extra_dump_files_in_use++;
764
765   if (this >= extra_dump_files_alloced)
766     {
767       if (extra_dump_files_alloced == 0)
768         extra_dump_files_alloced = 32;
769       else
770         extra_dump_files_alloced *= 2;
771       extra_dump_files = xrealloc (extra_dump_files,
772                                    sizeof (struct dump_file_info)
773                                    * extra_dump_files_alloced);
774     }
775
776   memset (&extra_dump_files[this], 0, sizeof (struct dump_file_info));
777   extra_dump_files[this].suffix = suffix;
778   extra_dump_files[this].swtch = swtch;
779   extra_dump_files[this].glob = glob;
780   extra_dump_files[this].flags = flags;
781   extra_dump_files[this].num = num;
782   extra_dump_files[this].letter = letter;
783
784   return this + TDI_end;
785 }
786
787
788 /* Return the dump_file_info for the given phase.  */
789
790 struct dump_file_info *
791 get_dump_file_info (enum tree_dump_index phase)
792 {
793   if (phase < TDI_end)
794     return &dump_files[phase];
795   else if (phase - TDI_end >= extra_dump_files_in_use)
796     return NULL;
797   else
798     return extra_dump_files + (phase - TDI_end);
799 }
800
801
802 /* Return the name of the dump file for the given phase.
803    If the dump is not enabled, returns NULL.  */
804
805 char *
806 get_dump_file_name (enum tree_dump_index phase)
807 {
808   char dump_id[7];
809   struct dump_file_info *dfi;
810
811   if (phase == TDI_none)
812     return NULL;
813
814   dfi = get_dump_file_info (phase);
815   if (dfi->state == 0)
816     return NULL;
817
818   if (dfi->num < 0)
819     dump_id[0] = '\0';
820   else
821     {
822       const char *template;
823       if (dfi->flags & TDF_TREE)
824         template = ".t%02d";
825       else if (dfi->flags & TDF_IPA)
826         template = ".i%02d";
827       else
828         template = ".%02d";
829
830       if (snprintf (dump_id, sizeof (dump_id), template, dfi->num) < 0)
831         dump_id[0] = '\0';
832     }
833
834   return concat (dump_base_name, dump_id, dfi->suffix, NULL);
835 }
836
837 /* Begin a tree dump for PHASE. Stores any user supplied flag in
838    *FLAG_PTR and returns a stream to write to. If the dump is not
839    enabled, returns NULL.
840    Multiple calls will reopen and append to the dump file.  */
841
842 FILE *
843 dump_begin (enum tree_dump_index phase, int *flag_ptr)
844 {
845   char *name;
846   struct dump_file_info *dfi;
847   FILE *stream;
848
849   if (phase == TDI_none || !dump_enabled_p (phase))
850     return NULL;
851
852   name = get_dump_file_name (phase);
853   dfi = get_dump_file_info (phase);
854   stream = fopen (name, dfi->state < 0 ? "w" : "a");
855   if (!stream)
856     error ("could not open dump file %qs: %s", name, strerror (errno));
857   else
858     dfi->state = 1;
859   free (name);
860
861   if (flag_ptr)
862     *flag_ptr = dfi->flags;
863
864   return stream;
865 }
866
867 /* Returns nonzero if tree dump PHASE is enabled.  If PHASE is
868    TDI_tree_all, return nonzero if any dump is enabled.  */
869
870 int
871 dump_enabled_p (enum tree_dump_index phase)
872 {
873   if (phase == TDI_tree_all)
874     {
875       size_t i;
876       for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
877         if (dump_files[i].state)
878           return 1;
879       for (i = 0; i < extra_dump_files_in_use; i++)
880         if (extra_dump_files[i].state)
881           return 1;
882       return 0;
883     }
884   else
885     {
886       struct dump_file_info *dfi = get_dump_file_info (phase);
887       return dfi->state;
888     }
889 }
890
891 /* Returns nonzero if tree dump PHASE has been initialized.  */
892
893 int
894 dump_initialized_p (enum tree_dump_index phase)
895 {
896   struct dump_file_info *dfi = get_dump_file_info (phase);
897   return dfi->state > 0;
898 }
899
900 /* Returns the switch name of PHASE.  */
901
902 const char *
903 dump_flag_name (enum tree_dump_index phase)
904 {
905   struct dump_file_info *dfi = get_dump_file_info (phase);
906   return dfi->swtch;
907 }
908
909 /* Finish a tree dump for PHASE. STREAM is the stream created by
910    dump_begin.  */
911
912 void
913 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
914 {
915   fclose (stream);
916 }
917
918 /* Enable all tree dumps.  Return number of enabled tree dumps.  */
919
920 static int
921 dump_enable_all (int flags, int letter)
922 {
923   int n = 0;
924   size_t i;
925
926   for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
927     if ((dump_files[i].flags & flags)
928         && (letter == 0 || letter == dump_files[i].letter))
929       {
930         dump_files[i].state = -1;
931         dump_files[i].flags = flags;
932         n++;
933       }
934
935   for (i = 0; i < extra_dump_files_in_use; i++)
936     if ((extra_dump_files[i].flags & flags)
937         && (letter == 0 || letter == extra_dump_files[i].letter))
938       {
939         extra_dump_files[i].state = -1;
940         extra_dump_files[i].flags = flags;
941         n++;
942       }
943
944   return n;
945 }
946
947 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
948    relevant details in the dump_files array.  */
949
950 static int
951 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
952 {
953   const char *option_value;
954   const char *ptr;
955   int flags;
956   
957   if (doglob && !dfi->glob)
958     return 0;
959
960   option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
961   if (!option_value)
962     return 0;
963
964   ptr = option_value;
965   flags = 0;
966
967   while (*ptr)
968     {
969       const struct dump_option_value_info *option_ptr;
970       const char *end_ptr;
971       unsigned length;
972
973       while (*ptr == '-')
974         ptr++;
975       end_ptr = strchr (ptr, '-');
976       if (!end_ptr)
977         end_ptr = ptr + strlen (ptr);
978       length = end_ptr - ptr;
979
980       for (option_ptr = dump_options; option_ptr->name; option_ptr++)
981         if (strlen (option_ptr->name) == length
982             && !memcmp (option_ptr->name, ptr, length))
983           {
984             flags |= option_ptr->value;
985             goto found;
986           }
987       warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
988                length, ptr, dfi->swtch);
989     found:;
990       ptr = end_ptr;
991     }
992
993   dfi->state = -1;
994   dfi->flags |= flags;
995
996   /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
997      known dumps.  */
998   if (dfi->suffix == NULL)
999     dump_enable_all (dfi->flags, 0);
1000
1001   return 1;
1002 }
1003
1004 int
1005 dump_switch_p (const char *arg)
1006 {
1007   size_t i;
1008   int any = 0;
1009
1010   for (i = TDI_none + 1; i != TDI_end; i++)
1011     any |= dump_switch_p_1 (arg, &dump_files[i], false);
1012
1013   /* Don't glob if we got a hit already */
1014   if (!any)
1015     for (i = TDI_none + 1; i != TDI_end; i++)
1016       any |= dump_switch_p_1 (arg, &dump_files[i], true);
1017
1018   for (i = 0; i < extra_dump_files_in_use; i++)
1019     any |= dump_switch_p_1 (arg, &extra_dump_files[i], false);
1020   
1021   if (!any)
1022     for (i = 0; i < extra_dump_files_in_use; i++)
1023       any |= dump_switch_p_1 (arg, &extra_dump_files[i], true);
1024
1025
1026   return any;
1027 }
1028
1029 /* Dump FUNCTION_DECL FN as tree dump PHASE.  */
1030
1031 void
1032 dump_function (enum tree_dump_index phase, tree fn)
1033 {
1034   FILE *stream;
1035   int flags;
1036
1037   stream = dump_begin (phase, &flags);
1038   if (stream)
1039     {
1040       dump_function_to_file (fn, stream, flags);
1041       dump_end (phase, stream);
1042     }
1043 }
1044
1045 bool
1046 enable_rtl_dump_file (int letter)
1047 {
1048   if (letter == 'a')
1049     letter = 0;
1050
1051   return dump_enable_all (TDF_RTL, letter) > 0;
1052 }
1053
1054