OSDN Git Service

* g++.dg/lookup/new1.C: Fix dg-excess-error syntax.
[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 "langhooks.h"
32 #include "tree-iterator.h"
33
34 static unsigned int queue (dump_info_p, tree, int);
35 static void dump_index (dump_info_p, unsigned int);
36 static void dequeue_and_dump (dump_info_p);
37 static void dump_new_line (dump_info_p);
38 static void dump_maybe_newline (dump_info_p);
39 static void dump_string_field (dump_info_p, const char *, const char *);
40 static void dump_enable_all (int);
41
42 /* Add T to the end of the queue of nodes to dump.  Returns the index
43    assigned to T.  */
44
45 static unsigned int
46 queue (dump_info_p di, tree t, int flags)
47 {
48   dump_queue_p dq;
49   dump_node_info_p dni;
50   unsigned int index;
51
52   /* Assign the next available index to T.  */
53   index = ++di->index;
54
55   /* Obtain a new queue node.  */
56   if (di->free_list)
57     {
58       dq = di->free_list;
59       di->free_list = dq->next;
60     }
61   else
62     dq = xmalloc (sizeof (struct dump_queue));
63
64   /* Create a new entry in the splay-tree.  */
65   dni = xmalloc (sizeof (struct dump_node_info));
66   dni->index = index;
67   dni->binfo_p = ((flags & DUMP_BINFO) != 0);
68   dq->node = splay_tree_insert (di->nodes, (splay_tree_key) t,
69                                 (splay_tree_value) dni);
70
71   /* Add it to the end of the queue.  */
72   dq->next = 0;
73   if (!di->queue_end)
74     di->queue = dq;
75   else
76     di->queue_end->next = dq;
77   di->queue_end = dq;
78
79   /* Return the index.  */
80   return index;
81 }
82
83 static void
84 dump_index (dump_info_p di, unsigned int index)
85 {
86   fprintf (di->stream, "@%-6u ", index);
87   di->column += 8;
88 }
89
90 /* If T has not already been output, queue it for subsequent output.
91    FIELD is a string to print before printing the index.  Then, the
92    index of T is printed.  */
93
94 void
95 queue_and_dump_index (dump_info_p di, const char *field, tree t, int flags)
96 {
97   unsigned int index;
98   splay_tree_node n;
99
100   /* If there's no node, just return.  This makes for fewer checks in
101      our callers.  */
102   if (!t)
103     return;
104
105   /* See if we've already queued or dumped this node.  */
106   n = splay_tree_lookup (di->nodes, (splay_tree_key) t);
107   if (n)
108     index = ((dump_node_info_p) n->value)->index;
109   else
110     /* If we haven't, add it to the queue.  */
111     index = queue (di, t, flags);
112
113   /* Print the index of the node.  */
114   dump_maybe_newline (di);
115   fprintf (di->stream, "%-4s: ", field);
116   di->column += 6;
117   dump_index (di, index);
118 }
119
120 /* Dump the type of T.  */
121
122 void
123 queue_and_dump_type (dump_info_p di, tree t)
124 {
125   queue_and_dump_index (di, "type", TREE_TYPE (t), DUMP_NONE);
126 }
127
128 /* Dump column control */
129 #define SOL_COLUMN 25           /* Start of line column.  */
130 #define EOL_COLUMN 55           /* End of line column.  */
131 #define COLUMN_ALIGNMENT 15     /* Alignment.  */
132
133 /* Insert a new line in the dump output, and indent to an appropriate
134    place to start printing more fields.  */
135
136 static void
137 dump_new_line (dump_info_p di)
138 {
139   fprintf (di->stream, "\n%*s", SOL_COLUMN, "");
140   di->column = SOL_COLUMN;
141 }
142
143 /* If necessary, insert a new line.  */
144
145 static void
146 dump_maybe_newline (dump_info_p di)
147 {
148   int extra;
149
150   /* See if we need a new line.  */
151   if (di->column > EOL_COLUMN)
152     dump_new_line (di);
153   /* See if we need any padding.  */
154   else if ((extra = (di->column - SOL_COLUMN) % COLUMN_ALIGNMENT) != 0)
155     {
156       fprintf (di->stream, "%*s", COLUMN_ALIGNMENT - extra, "");
157       di->column += COLUMN_ALIGNMENT - extra;
158     }
159 }
160
161 /* Dump pointer PTR using FIELD to identify it.  */
162
163 void
164 dump_pointer (dump_info_p di, const char *field, void *ptr)
165 {
166   dump_maybe_newline (di);
167   fprintf (di->stream, "%-4s: %-8lx ", field, (long) ptr);
168   di->column += 15;
169 }
170
171 /* Dump integer I using FIELD to identify it.  */
172
173 void
174 dump_int (dump_info_p di, const char *field, int i)
175 {
176   dump_maybe_newline (di);
177   fprintf (di->stream, "%-4s: %-7d ", field, i);
178   di->column += 14;
179 }
180
181 /* Dump the string S.  */
182
183 void
184 dump_string (dump_info_p di, const char *string)
185 {
186   dump_maybe_newline (di);
187   fprintf (di->stream, "%-13s ", string);
188   if (strlen (string) > 13)
189     di->column += strlen (string) + 1;
190   else
191     di->column += 14;
192 }
193
194 /* Dump the string field S.  */
195
196 static void
197 dump_string_field (dump_info_p di, const char *field, const char *string)
198 {
199   dump_maybe_newline (di);
200   fprintf (di->stream, "%-4s: %-7s ", field, string);
201   if (strlen (string) > 7)
202     di->column += 6 + strlen (string) + 1;
203   else
204     di->column += 14;
205 }
206
207 /* Dump the next node in the queue.  */
208
209 static void
210 dequeue_and_dump (dump_info_p di)
211 {
212   dump_queue_p dq;
213   splay_tree_node stn;
214   dump_node_info_p dni;
215   tree t;
216   unsigned int index;
217   enum tree_code code;
218   char code_class;
219   const char* code_name;
220
221   /* Get the next node from the queue.  */
222   dq = di->queue;
223   stn = dq->node;
224   t = (tree) stn->key;
225   dni = (dump_node_info_p) stn->value;
226   index = dni->index;
227
228   /* Remove the node from the queue, and put it on the free list.  */
229   di->queue = dq->next;
230   if (!di->queue)
231     di->queue_end = 0;
232   dq->next = di->free_list;
233   di->free_list = dq;
234
235   /* Print the node index.  */
236   dump_index (di, index);
237   /* And the type of node this is.  */
238   if (dni->binfo_p)
239     code_name = "binfo";
240   else
241     code_name = tree_code_name[(int) TREE_CODE (t)];
242   fprintf (di->stream, "%-16s ", code_name);
243   di->column = 25;
244
245   /* Figure out what kind of node this is.  */
246   code = TREE_CODE (t);
247   code_class = TREE_CODE_CLASS (code);
248
249   /* Although BINFOs are TREE_VECs, we dump them specially so as to be
250      more informative.  */
251   if (dni->binfo_p)
252     {
253       unsigned ix;
254       tree bases = BINFO_BASE_BINFOS (t);
255       unsigned n_bases = bases ? TREE_VEC_LENGTH (bases): 0;
256       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", n_bases);
264       for (ix = 0; ix != n_bases; ix++)
265         {
266           tree base = TREE_VEC_ELT (bases, ix);
267           tree access = (accesses ? TREE_VEC_ELT (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             abort ();
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 '1':
297           dump_child ("op 0", TREE_OPERAND (t, 0));
298           break;
299
300         case '2':
301         case '<':
302           dump_child ("op 0", TREE_OPERAND (t, 0));
303           dump_child ("op 1", TREE_OPERAND (t, 1));
304           break;
305
306         case 'e':
307         case 'r':
308         case 's':
309           /* These nodes are handled explicitly below.  */
310           break;
311
312         default:
313           abort ();
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 == 't')
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 == 'c')
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 CLEANUP_POINT_EXPR:
532     case SAVE_EXPR:
533     case REALPART_EXPR:
534     case IMAGPART_EXPR:
535       /* These nodes are unary, but do not have code class `1'.  */
536       dump_child ("op 0", TREE_OPERAND (t, 0));
537       break;
538
539     case TRUTH_ANDIF_EXPR:
540     case TRUTH_ORIF_EXPR:
541     case INIT_EXPR:
542     case MODIFY_EXPR:
543     case COMPOUND_EXPR:
544     case PREDECREMENT_EXPR:
545     case PREINCREMENT_EXPR:
546     case POSTDECREMENT_EXPR:
547     case POSTINCREMENT_EXPR:
548       /* These nodes are binary, but do not have code class `2'.  */
549       dump_child ("op 0", TREE_OPERAND (t, 0));
550       dump_child ("op 1", TREE_OPERAND (t, 1));
551       break;
552
553     case COMPONENT_REF:
554       dump_child ("op 0", TREE_OPERAND (t, 0));
555       dump_child ("op 1", TREE_OPERAND (t, 1));
556       dump_child ("op 2", TREE_OPERAND (t, 2));
557       break;
558
559     case ARRAY_REF:
560     case ARRAY_RANGE_REF:
561       dump_child ("op 0", TREE_OPERAND (t, 0));
562       dump_child ("op 1", TREE_OPERAND (t, 1));
563       dump_child ("op 2", TREE_OPERAND (t, 2));
564       dump_child ("op 3", TREE_OPERAND (t, 3));
565       break;
566
567     case COND_EXPR:
568       dump_child ("op 0", TREE_OPERAND (t, 0));
569       dump_child ("op 1", TREE_OPERAND (t, 1));
570       dump_child ("op 2", TREE_OPERAND (t, 2));
571       break;
572
573     case CALL_EXPR:
574       dump_child ("fn", TREE_OPERAND (t, 0));
575       dump_child ("args", TREE_OPERAND (t, 1));
576       break;
577
578     case CONSTRUCTOR:
579       dump_child ("elts", CONSTRUCTOR_ELTS (t));
580       break;
581
582     case BIND_EXPR:
583       dump_child ("vars", TREE_OPERAND (t, 0));
584       dump_child ("body", TREE_OPERAND (t, 1));
585       break;
586
587     case LOOP_EXPR:
588       dump_child ("body", TREE_OPERAND (t, 0));
589       break;
590
591     case EXIT_EXPR:
592       dump_child ("cond", TREE_OPERAND (t, 0));
593       break;
594
595     case TARGET_EXPR:
596       dump_child ("decl", TREE_OPERAND (t, 0));
597       dump_child ("init", TREE_OPERAND (t, 1));
598       dump_child ("clnp", TREE_OPERAND (t, 2));
599       /* There really are two possible places the initializer can be.
600          After RTL expansion, the second operand is moved to the
601          position of the fourth operand, and the second operand
602          becomes NULL.  */
603       dump_child ("init", TREE_OPERAND (t, 3));
604       break;
605
606     default:
607       /* There are no additional fields to print.  */
608       break;
609     }
610
611  done:
612   if (dump_flag (di, TDF_ADDRESS, NULL))
613     dump_pointer (di, "addr", (void *)t);
614
615   /* Terminate the line.  */
616   fprintf (di->stream, "\n");
617 }
618
619 /* Return nonzero if FLAG has been specified for the dump, and NODE
620    is not the root node of the dump.  */
621
622 int dump_flag (dump_info_p di, int flag, tree node)
623 {
624   return (di->flags & flag) && (node != di->node);
625 }
626
627 /* Dump T, and all its children, on STREAM.  */
628
629 void
630 dump_node (tree t, int flags, FILE *stream)
631 {
632   struct dump_info di;
633   dump_queue_p dq;
634   dump_queue_p next_dq;
635
636   /* Initialize the dump-information structure.  */
637   di.stream = stream;
638   di.index = 0;
639   di.column = 0;
640   di.queue = 0;
641   di.queue_end = 0;
642   di.free_list = 0;
643   di.flags = flags;
644   di.node = t;
645   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
646                              (splay_tree_delete_value_fn) &free);
647
648   /* Queue up the first node.  */
649   queue (&di, t, DUMP_NONE);
650
651   /* Until the queue is empty, keep dumping nodes.  */
652   while (di.queue)
653     dequeue_and_dump (&di);
654
655   /* Now, clean up.  */
656   for (dq = di.free_list; dq; dq = next_dq)
657     {
658       next_dq = dq->next;
659       free (dq);
660     }
661   splay_tree_delete (di.nodes);
662 }
663
664 /* Define a tree dump switch.  */
665 struct dump_file_info
666 {
667   const char *suffix;           /* suffix to give output file.  */
668   const char *swtch;            /* command line switch */
669   int flags;                    /* user flags */
670   int state;                    /* state of play */
671 };
672
673 /* Table of tree dump switches. This must be consistent with the
674    TREE_DUMP_INDEX enumeration in tree.h */
675 static struct dump_file_info dump_files[TDI_end] =
676 {
677   {NULL, NULL, 0, 0},
678   {".tu", "translation-unit", 0, 0},
679   {".class", "class-hierarchy", 0, 0},
680   {".original", "tree-original", 0, 0},
681   {".generic", "tree-generic", 0, 0},
682   {".nested", "tree-nested", 0, 0},
683   {".inlined", "tree-inlined", 0, 0},
684   {".vcg", "tree-vcg", 0, 0},
685   {".xml", "call-graph", 0, 0},
686   {NULL, "tree-all", 0, 0},
687 };
688
689 /* Dynamically registered tree dump files and switches.  */
690 static struct dump_file_info *extra_dump_files;
691 static size_t extra_dump_files_in_use;
692 static size_t extra_dump_files_alloced;
693
694 /* Define a name->number mapping for a dump flag value.  */
695 struct dump_option_value_info
696 {
697   const char *const name;       /* the name of the value */
698   const int value;              /* the value of the name */
699 };
700
701 /* Table of dump options. This must be consistent with the TDF_* flags
702    in tree.h */
703 static const struct dump_option_value_info dump_options[] =
704 {
705   {"address", TDF_ADDRESS},
706   {"slim", TDF_SLIM},
707   {"raw", TDF_RAW},
708   {"details", TDF_DETAILS},
709   {"stats", TDF_STATS},
710   {"blocks", TDF_BLOCKS},
711   {"vops", TDF_VOPS},
712   {"lineno", TDF_LINENO},
713   {"uid", TDF_UID},
714   {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO)},
715   {NULL, 0}
716 };
717
718 unsigned int
719 dump_register (const char *suffix, const char *swtch)
720 {
721   size_t this = extra_dump_files_in_use++;
722
723   if (this >= extra_dump_files_alloced)
724     {
725       if (extra_dump_files_alloced == 0)
726         extra_dump_files_alloced = 32;
727       else
728         extra_dump_files_alloced *= 2;
729       extra_dump_files = xrealloc (extra_dump_files,
730                                    sizeof (struct dump_file_info)
731                                    * extra_dump_files_alloced);
732     }
733
734   memset (&extra_dump_files[this], 0, sizeof (struct dump_file_info));
735   extra_dump_files[this].suffix = suffix;
736   extra_dump_files[this].swtch = swtch;
737
738   return this + TDI_end;
739 }
740
741 /* Return the dump_file_info for the given phase.  */
742
743 static struct dump_file_info *
744 get_dump_file_info (enum tree_dump_index phase)
745 {
746   if (phase < TDI_end)
747     return &dump_files[phase];
748   else if (phase - TDI_end >= extra_dump_files_in_use)
749     abort ();
750   else
751     return extra_dump_files + (phase - TDI_end);
752 }
753
754
755 /* Begin a tree dump for PHASE. Stores any user supplied flag in
756    *FLAG_PTR and returns a stream to write to. If the dump is not
757    enabled, returns NULL.
758    Multiple calls will reopen and append to the dump file.  */
759
760 FILE *
761 dump_begin (enum tree_dump_index phase, int *flag_ptr)
762 {
763   FILE *stream;
764   char *name;
765   char dump_id[10];
766   struct dump_file_info *dfi;
767
768   if (phase == TDI_none)
769     return NULL;
770
771   dfi = get_dump_file_info (phase);
772   if (dfi->state == 0)
773     return NULL;
774
775   if (snprintf (dump_id, sizeof (dump_id), ".t%02d", phase) < 0)
776     dump_id[0] = '\0';
777
778   name = concat (dump_base_name, dump_id, dfi->suffix, NULL);
779   stream = fopen (name, dfi->state < 0 ? "w" : "a");
780   if (!stream)
781     error ("could not open dump file `%s': %s", name, strerror (errno));
782   else
783     dfi->state = 1;
784   free (name);
785
786   if (flag_ptr)
787     *flag_ptr = dfi->flags;
788
789   return stream;
790 }
791
792 /* Returns nonzero if tree dump PHASE is enabled.  */
793
794 int
795 dump_enabled_p (enum tree_dump_index phase)
796 {
797   struct dump_file_info *dfi = get_dump_file_info (phase);
798   return dfi->state;
799 }
800
801 /* Returns the switch name of PHASE.  */
802
803 const char *
804 dump_flag_name (enum tree_dump_index phase)
805 {
806   struct dump_file_info *dfi = get_dump_file_info (phase);
807   return dfi->swtch;
808 }
809
810 /* Finish a tree dump for PHASE. STREAM is the stream created by
811    dump_begin.  */
812
813 void
814 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
815 {
816   fclose (stream);
817 }
818
819 /* Enable all tree dumps.  */
820
821 static void
822 dump_enable_all (int flags)
823 {
824   size_t i;
825
826   for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
827     {
828       dump_files[i].state = -1;
829       dump_files[i].flags = flags;
830     }
831
832   for (i = 0; i < extra_dump_files_in_use; i++)
833     {
834       extra_dump_files[i].state = -1;
835       extra_dump_files[i].flags = flags;
836     }
837
838   /* FIXME  -fdump-call-graph is broken.  */
839   dump_files[TDI_xml].state = 0;
840   dump_files[TDI_xml].flags = 0;
841 }
842
843 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
844    relevant details in the dump_files array.  */
845
846 static int
847 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi)
848 {
849   const char *option_value;
850   const char *ptr;
851   int flags;
852
853   option_value = skip_leading_substring (arg, dfi->swtch);
854   if (!option_value)
855     return 0;
856
857   ptr = option_value;
858   flags = 0;
859
860   while (*ptr)
861     {
862       const struct dump_option_value_info *option_ptr;
863       const char *end_ptr;
864       unsigned length;
865
866       while (*ptr == '-')
867         ptr++;
868       end_ptr = strchr (ptr, '-');
869       if (!end_ptr)
870         end_ptr = ptr + strlen (ptr);
871       length = end_ptr - ptr;
872
873       for (option_ptr = dump_options; option_ptr->name; option_ptr++)
874         if (strlen (option_ptr->name) == length
875             && !memcmp (option_ptr->name, ptr, length))
876           {
877             flags |= option_ptr->value;
878             goto found;
879           }
880       warning ("ignoring unknown option `%.*s' in `-fdump-%s'",
881                length, ptr, dfi->swtch);
882     found:;
883       ptr = end_ptr;
884     }
885
886   dfi->state = -1;
887   dfi->flags = flags;
888
889   /* Process -fdump-tree-all by enabling all the known dumps.  */
890   if (dfi->suffix == NULL)
891     dump_enable_all (flags);
892
893   return 1;
894 }
895
896 int
897 dump_switch_p (const char *arg)
898 {
899   size_t i;
900   int any = 0;
901
902   for (i = TDI_none + 1; i != TDI_end; i++)
903     any |= dump_switch_p_1 (arg, &dump_files[i]);
904
905   for (i = 0; i < extra_dump_files_in_use; i++)
906     any |= dump_switch_p_1 (arg, &extra_dump_files[i]);
907
908   return any;
909 }
910
911 /* Dump FUNCTION_DECL FN as tree dump PHASE.  */
912
913 void
914 dump_function (enum tree_dump_index phase, tree fn)
915 {
916   FILE *stream;
917   int flags;
918
919   stream = dump_begin (phase, &flags);
920   if (stream)
921     {
922       dump_function_to_file (fn, stream, flags);
923       dump_end (phase, stream);
924     }
925 }