OSDN Git Service

2004-12-02 H.J. Lu <hongjiu.lu@intel.com>
[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   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) *accesses = BINFO_BASE_ACCESSES (t);
257
258       dump_child ("type", BINFO_TYPE (t));
259
260       if (BINFO_VIRTUAL_P (t))
261         dump_string (di, "virt");
262
263       dump_int (di, "bases", BINFO_N_BASE_BINFOS (t));
264       for (ix = 0; BINFO_BASE_ITERATE (t, ix, base); ix++)
265         {
266           tree access = (accesses ? VEC_index (tree, accesses, ix)
267                          : access_public_node);
268           const char *string = NULL;
269
270           if (access == access_public_node)
271             string = "pub";
272           else if (access == access_protected_node)
273             string = "prot";
274           else if (access == access_private_node)
275             string = "priv";
276           else
277             gcc_unreachable ();
278
279           dump_string (di, string);
280           queue_and_dump_index (di, "binf", base, DUMP_BINFO);
281         }
282
283       goto done;
284     }
285
286   /* We can knock off a bunch of expression nodes in exactly the same
287      way.  */
288   if (IS_EXPR_CODE_CLASS (code_class))
289     {
290       /* If we're dumping children, dump them now.  */
291       queue_and_dump_type (di, t);
292
293       switch (code_class)
294         {
295         case 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       /* 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 == tcc_type)
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 == tcc_constant)
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 ALIGN_INDIRECT_REF:
531     case MISALIGNED_INDIRECT_REF:
532     case CLEANUP_POINT_EXPR:
533     case SAVE_EXPR:
534     case REALPART_EXPR:
535     case IMAGPART_EXPR:
536       /* These nodes are unary, but do not have code class `1'.  */
537       dump_child ("op 0", TREE_OPERAND (t, 0));
538       break;
539
540     case TRUTH_ANDIF_EXPR:
541     case TRUTH_ORIF_EXPR:
542     case INIT_EXPR:
543     case MODIFY_EXPR:
544     case COMPOUND_EXPR:
545     case PREDECREMENT_EXPR:
546     case PREINCREMENT_EXPR:
547     case POSTDECREMENT_EXPR:
548     case POSTINCREMENT_EXPR:
549       /* These nodes are binary, but do not have code class `2'.  */
550       dump_child ("op 0", TREE_OPERAND (t, 0));
551       dump_child ("op 1", TREE_OPERAND (t, 1));
552       break;
553
554     case COMPONENT_REF:
555       dump_child ("op 0", TREE_OPERAND (t, 0));
556       dump_child ("op 1", TREE_OPERAND (t, 1));
557       dump_child ("op 2", TREE_OPERAND (t, 2));
558       break;
559
560     case ARRAY_REF:
561     case ARRAY_RANGE_REF:
562       dump_child ("op 0", TREE_OPERAND (t, 0));
563       dump_child ("op 1", TREE_OPERAND (t, 1));
564       dump_child ("op 2", TREE_OPERAND (t, 2));
565       dump_child ("op 3", TREE_OPERAND (t, 3));
566       break;
567
568     case COND_EXPR:
569       dump_child ("op 0", TREE_OPERAND (t, 0));
570       dump_child ("op 1", TREE_OPERAND (t, 1));
571       dump_child ("op 2", TREE_OPERAND (t, 2));
572       break;
573
574     case CALL_EXPR:
575       dump_child ("fn", TREE_OPERAND (t, 0));
576       dump_child ("args", TREE_OPERAND (t, 1));
577       break;
578
579     case CONSTRUCTOR:
580       dump_child ("elts", CONSTRUCTOR_ELTS (t));
581       break;
582
583     case BIND_EXPR:
584       dump_child ("vars", TREE_OPERAND (t, 0));
585       dump_child ("body", TREE_OPERAND (t, 1));
586       break;
587
588     case LOOP_EXPR:
589       dump_child ("body", TREE_OPERAND (t, 0));
590       break;
591
592     case EXIT_EXPR:
593       dump_child ("cond", TREE_OPERAND (t, 0));
594       break;
595
596     case TARGET_EXPR:
597       dump_child ("decl", TREE_OPERAND (t, 0));
598       dump_child ("init", TREE_OPERAND (t, 1));
599       dump_child ("clnp", TREE_OPERAND (t, 2));
600       /* There really are two possible places the initializer can be.
601          After RTL expansion, the second operand is moved to the
602          position of the fourth operand, and the second operand
603          becomes NULL.  */
604       dump_child ("init", TREE_OPERAND (t, 3));
605       break;
606
607     default:
608       /* There are no additional fields to print.  */
609       break;
610     }
611
612  done:
613   if (dump_flag (di, TDF_ADDRESS, NULL))
614     dump_pointer (di, "addr", (void *)t);
615
616   /* Terminate the line.  */
617   fprintf (di->stream, "\n");
618 }
619
620 /* Return nonzero if FLAG has been specified for the dump, and NODE
621    is not the root node of the dump.  */
622
623 int dump_flag (dump_info_p di, int flag, tree node)
624 {
625   return (di->flags & flag) && (node != di->node);
626 }
627
628 /* Dump T, and all its children, on STREAM.  */
629
630 void
631 dump_node (tree t, int flags, FILE *stream)
632 {
633   struct dump_info di;
634   dump_queue_p dq;
635   dump_queue_p next_dq;
636
637   /* Initialize the dump-information structure.  */
638   di.stream = stream;
639   di.index = 0;
640   di.column = 0;
641   di.queue = 0;
642   di.queue_end = 0;
643   di.free_list = 0;
644   di.flags = flags;
645   di.node = t;
646   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
647                              (splay_tree_delete_value_fn) &free);
648
649   /* Queue up the first node.  */
650   queue (&di, t, DUMP_NONE);
651
652   /* Until the queue is empty, keep dumping nodes.  */
653   while (di.queue)
654     dequeue_and_dump (&di);
655
656   /* Now, clean up.  */
657   for (dq = di.free_list; dq; dq = next_dq)
658     {
659       next_dq = dq->next;
660       free (dq);
661     }
662   splay_tree_delete (di.nodes);
663 }
664 \f
665
666 /* Table of tree dump switches. This must be consistent with the
667    TREE_DUMP_INDEX enumeration in tree.h */
668 static struct dump_file_info dump_files[TDI_end] =
669 {
670   {NULL, NULL, 0, 0, 0, 0},
671   {".tu", "translation-unit", TDF_TREE, 0, 0, 0},
672   {".class", "class-hierarchy", TDF_TREE, 0, 1, 0},
673   {".original", "tree-original", TDF_TREE, 0, 2, 0},
674   {".generic", "tree-generic", TDF_TREE, 0, 3, 0},
675   {".nested", "tree-nested", TDF_TREE, 0, 4, 0},
676   {".inlined", "tree-inlined", TDF_TREE, 0, 5, 0},
677   {".vcg", "tree-vcg", TDF_TREE, 0, 6, 0},
678   {NULL, "tree-all", TDF_TREE, 0, 0, 0},
679   {NULL, "rtl-all", TDF_RTL, 0, 0, 0},
680   {NULL, "ipa-all", TDF_IPA, 0, 0, 0},
681
682   { ".cgraph", "ipa-cgraph",            TDF_IPA, 0,  1, 0},
683
684   { ".sibling", "rtl-sibling",          TDF_RTL, 0,  1, 'i'},
685   { ".eh", "rtl-eh",                    TDF_RTL, 0,  2, 'h'},
686   { ".jump", "rtl-jump",                TDF_RTL, 0,  3, 'j'},
687   { ".cse", "rtl-cse",                  TDF_RTL, 0,  4, 's'},
688   { ".gcse", "rtl-gcse",                TDF_RTL, 0,  5, 'G'},
689   { ".loop", "rtl-loop",                TDF_RTL, 0,  6, 'L'},
690   { ".bypass", "rtl-bypass",            TDF_RTL, 0,  7, 'G'},
691   { ".cfg", "rtl-cfg",                  TDF_RTL, 0,  8, 'f'},
692   { ".bp", "rtl-bp",                    TDF_RTL, 0,  9, 'b'},
693   { ".vpt", "rtl-vpt",                  TDF_RTL, 0, 10, 'V'},
694   { ".ce1", "rtl-ce1",                  TDF_RTL, 0, 11, 'C'},
695   { ".tracer", "rtl-tracer",            TDF_RTL, 0, 12, 'T'},
696   { ".loop2", "rtl-loop2",              TDF_RTL, 0, 13, 'L'},
697   { ".web", "rtl-web",                  TDF_RTL, 0, 14, 'Z'},
698   { ".cse2", "rtl-cse2",                TDF_RTL, 0, 15, 't'},
699   { ".life", "rtl-life",                TDF_RTL, 0, 16, 'f'},
700   { ".combine", "rtl-combine",          TDF_RTL, 0, 17, 'c'},
701   { ".ce2", "rtl-ce2",                  TDF_RTL, 0, 18, 'C'},
702   { ".regmove", "rtl-regmove",          TDF_RTL, 0, 19, 'N'},
703   { ".sms", "rtl-sms",                  TDF_RTL, 0, 20, 'm'},
704   { ".sched", "rtl-sched",              TDF_RTL, 0, 21, 'S'},
705   { ".lreg", "rtl-lreg",                TDF_RTL, 0, 22, 'l'},
706   { ".greg", "rtl-greg",                TDF_RTL, 0, 23, 'g'},
707   { ".postreload", "rtl-postreload",    TDF_RTL, 0, 24, 'o'},
708   { ".gcse2", "rtl-gcse2",              TDF_RTL, 0, 25, 'J'},
709   { ".flow2", "rtl-flow2",              TDF_RTL, 0, 26, 'w'},
710   { ".peephole2", "rtl-peephole2",      TDF_RTL, 0, 27, 'z'},
711   { ".ce3", "rtl-ce3",                  TDF_RTL, 0, 28, 'E'},
712   { ".rnreg", "rtl-rnreg",              TDF_RTL, 0, 29, 'n'},
713   { ".bbro", "rtl-bbro",                TDF_RTL, 0, 30, 'B'},
714   { ".btl", "rtl-btl",                  TDF_RTL, 0, 31, 'd'},
715   { ".sched2", "rtl-sched2",            TDF_RTL, 0, 32, 'R'},
716   { ".stack", "rtl-stack",              TDF_RTL, 0, 33, 'k'},
717   { ".vartrack", "rtl-vartrack",        TDF_RTL, 0, 34, 'V'},
718   { ".mach", "rtl-mach",                TDF_RTL, 0, 35, 'M'},
719   { ".dbr", "rtl-dbr",                  TDF_RTL, 0, 36, 'd'}
720 };
721
722 /* Dynamically registered tree dump files and switches.  */
723 static struct dump_file_info *extra_dump_files;
724 static size_t extra_dump_files_in_use;
725 static size_t extra_dump_files_alloced;
726
727 /* Define a name->number mapping for a dump flag value.  */
728 struct dump_option_value_info
729 {
730   const char *const name;       /* the name of the value */
731   const int value;              /* the value of the name */
732 };
733
734 /* Table of dump options. This must be consistent with the TDF_* flags
735    in tree.h */
736 static const struct dump_option_value_info dump_options[] =
737 {
738   {"address", TDF_ADDRESS},
739   {"slim", TDF_SLIM},
740   {"raw", TDF_RAW},
741   {"details", TDF_DETAILS},
742   {"stats", TDF_STATS},
743   {"blocks", TDF_BLOCKS},
744   {"vops", TDF_VOPS},
745   {"lineno", TDF_LINENO},
746   {"uid", TDF_UID},
747   {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA)},
748   {NULL, 0}
749 };
750
751 unsigned int
752 dump_register (const char *suffix, const char *swtch, int flags,
753                unsigned int num, int letter)
754 {
755   size_t this = extra_dump_files_in_use++;
756
757   if (this >= extra_dump_files_alloced)
758     {
759       if (extra_dump_files_alloced == 0)
760         extra_dump_files_alloced = 32;
761       else
762         extra_dump_files_alloced *= 2;
763       extra_dump_files = xrealloc (extra_dump_files,
764                                    sizeof (struct dump_file_info)
765                                    * extra_dump_files_alloced);
766     }
767
768   memset (&extra_dump_files[this], 0, sizeof (struct dump_file_info));
769   extra_dump_files[this].suffix = suffix;
770   extra_dump_files[this].swtch = swtch;
771   extra_dump_files[this].flags = flags;
772   extra_dump_files[this].num = num;
773   extra_dump_files[this].letter = letter;
774
775   return this + TDI_end;
776 }
777
778
779 /* Return the dump_file_info for the given phase.  */
780
781 struct dump_file_info *
782 get_dump_file_info (enum tree_dump_index phase)
783 {
784   if (phase < TDI_end)
785     return &dump_files[phase];
786   else if (phase - TDI_end >= extra_dump_files_in_use)
787     return NULL;
788   else
789     return extra_dump_files + (phase - TDI_end);
790 }
791
792
793 /* Return the name of the dump file for the given phase.
794    If the dump is not enabled, returns NULL.  */
795
796 char *
797 get_dump_file_name (enum tree_dump_index phase)
798 {
799   char dump_id[7];
800   struct dump_file_info *dfi;
801
802   if (phase == TDI_none)
803     return NULL;
804
805   dfi = get_dump_file_info (phase);
806   if (dfi->state == 0)
807     return NULL;
808
809   if (dfi->num < 0)
810     dump_id[0] = '\0';
811   else
812     {
813       const char *template;
814       if (dfi->flags & TDF_TREE)
815         template = ".t%02d";
816       else if (dfi->flags & TDF_IPA)
817         template = ".i%02d";
818       else
819         template = ".%02d";
820
821       if (snprintf (dump_id, sizeof (dump_id), template, dfi->num) < 0)
822         dump_id[0] = '\0';
823     }
824
825   return concat (dump_base_name, dump_id, dfi->suffix, NULL);
826 }
827
828 /* Begin a tree dump for PHASE. Stores any user supplied flag in
829    *FLAG_PTR and returns a stream to write to. If the dump is not
830    enabled, returns NULL.
831    Multiple calls will reopen and append to the dump file.  */
832
833 FILE *
834 dump_begin (enum tree_dump_index phase, int *flag_ptr)
835 {
836   char *name;
837   struct dump_file_info *dfi;
838   FILE *stream;
839
840   if (phase == TDI_none || !dump_enabled_p (phase))
841     return NULL;
842
843   name = get_dump_file_name (phase);
844   dfi = get_dump_file_info (phase);
845   stream = fopen (name, dfi->state < 0 ? "w" : "a");
846   if (!stream)
847     error ("could not open dump file %qs: %s", name, strerror (errno));
848   else
849     dfi->state = 1;
850   free (name);
851
852   if (flag_ptr)
853     *flag_ptr = dfi->flags;
854
855   return stream;
856 }
857
858 /* Returns nonzero if tree dump PHASE is enabled.  */
859
860 int
861 dump_enabled_p (enum tree_dump_index phase)
862 {
863   struct dump_file_info *dfi = get_dump_file_info (phase);
864   return dfi->state;
865 }
866
867 /* Returns nonzero if tree dump PHASE has been initialized.  */
868
869 int
870 dump_initialized_p (enum tree_dump_index phase)
871 {
872   struct dump_file_info *dfi = get_dump_file_info (phase);
873   return dfi->state > 0;
874 }
875
876 /* Returns the switch name of PHASE.  */
877
878 const char *
879 dump_flag_name (enum tree_dump_index phase)
880 {
881   struct dump_file_info *dfi = get_dump_file_info (phase);
882   return dfi->swtch;
883 }
884
885 /* Finish a tree dump for PHASE. STREAM is the stream created by
886    dump_begin.  */
887
888 void
889 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
890 {
891   fclose (stream);
892 }
893
894 /* Enable all tree dumps.  Return number of enabled tree dumps.  */
895
896 static int
897 dump_enable_all (int flags, int letter)
898 {
899   int n = 0;
900   size_t i;
901
902   for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
903     if ((dump_files[i].flags & flags)
904         && (letter == 0 || letter == dump_files[i].letter))
905       {
906         dump_files[i].state = -1;
907         dump_files[i].flags = flags;
908         n++;
909       }
910
911   for (i = 0; i < extra_dump_files_in_use; i++)
912     if ((extra_dump_files[i].flags & flags)
913         && (letter == 0 || letter == extra_dump_files[i].letter))
914       {
915         extra_dump_files[i].state = -1;
916         extra_dump_files[i].flags = flags;
917         n++;
918       }
919
920   return n;
921 }
922
923 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
924    relevant details in the dump_files array.  */
925
926 static int
927 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi)
928 {
929   const char *option_value;
930   const char *ptr;
931   int flags;
932
933   option_value = skip_leading_substring (arg, dfi->swtch);
934   if (!option_value)
935     return 0;
936
937   ptr = option_value;
938   flags = 0;
939
940   while (*ptr)
941     {
942       const struct dump_option_value_info *option_ptr;
943       const char *end_ptr;
944       unsigned length;
945
946       while (*ptr == '-')
947         ptr++;
948       end_ptr = strchr (ptr, '-');
949       if (!end_ptr)
950         end_ptr = ptr + strlen (ptr);
951       length = end_ptr - ptr;
952
953       for (option_ptr = dump_options; option_ptr->name; option_ptr++)
954         if (strlen (option_ptr->name) == length
955             && !memcmp (option_ptr->name, ptr, length))
956           {
957             flags |= option_ptr->value;
958             goto found;
959           }
960       warning ("ignoring unknown option %q.*s in %<-fdump-%s%>",
961                length, ptr, dfi->swtch);
962     found:;
963       ptr = end_ptr;
964     }
965
966   dfi->state = -1;
967   dfi->flags |= flags;
968
969   /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
970      known dumps.  */
971   if (dfi->suffix == NULL)
972     dump_enable_all (dfi->flags, 0);
973
974   return 1;
975 }
976
977 int
978 dump_switch_p (const char *arg)
979 {
980   size_t i;
981   int any = 0;
982
983   for (i = TDI_none + 1; i != TDI_end; i++)
984     any |= dump_switch_p_1 (arg, &dump_files[i]);
985
986   for (i = 0; i < extra_dump_files_in_use; i++)
987     any |= dump_switch_p_1 (arg, &extra_dump_files[i]);
988
989   return any;
990 }
991
992 /* Dump FUNCTION_DECL FN as tree dump PHASE.  */
993
994 void
995 dump_function (enum tree_dump_index phase, tree fn)
996 {
997   FILE *stream;
998   int flags;
999
1000   stream = dump_begin (phase, &flags);
1001   if (stream)
1002     {
1003       dump_function_to_file (fn, stream, flags);
1004       dump_end (phase, stream);
1005     }
1006 }
1007
1008 bool
1009 enable_rtl_dump_file (int letter)
1010 {
1011   if (letter == 'a')
1012     letter = 0;
1013
1014   return dump_enable_all (TDF_RTL, letter) > 0;
1015 }
1016
1017