OSDN Git Service

Update email address for self.
[pf3gnuchains/gcc-fork.git] / gcc / tree-dump.c
1 /* Tree-dumping functionality for intermediate representation.
2    Copyright (C) 1999, 2000, 2002 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 "tree.h"
25 #include "c-tree.h"
26 #include "splay-tree.h"
27 #include "diagnostic.h"
28 #include "toplev.h"
29 #include "tree-dump.h"
30 #include "langhooks.h"
31
32 static unsigned int queue PARAMS ((dump_info_p, tree, int));
33 static void dump_index PARAMS ((dump_info_p, unsigned int));
34 static void dequeue_and_dump PARAMS ((dump_info_p));
35 static void dump_new_line PARAMS ((dump_info_p));
36 static void dump_maybe_newline PARAMS ((dump_info_p));
37 static void dump_string_field PARAMS ((dump_info_p, const char *, const char *));
38
39 /* Add T to the end of the queue of nodes to dump.  Returns the index
40    assigned to T.  */
41
42 static unsigned int
43 queue (di, t, flags)
44      dump_info_p di;
45      tree t;
46      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 = (dump_queue_p) xmalloc (sizeof (struct dump_queue));
63
64   /* Create a new entry in the splay-tree.  */
65   dni = (dump_node_info_p) 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 (di, index)
85      dump_info_p di;
86      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 (di, field, t, flags)
98      dump_info_p di;
99      const char *field;
100      tree t;
101      int flags;
102 {
103   unsigned int index;
104   splay_tree_node n;
105
106   /* If there's no node, just return.  This makes for fewer checks in
107      our callers.  */
108   if (!t)
109     return;
110
111   /* See if we've already queued or dumped this node.  */
112   n = splay_tree_lookup (di->nodes, (splay_tree_key) t);
113   if (n)
114     index = ((dump_node_info_p) n->value)->index;
115   else
116     /* If we haven't, add it to the queue.  */
117     index = queue (di, t, flags);
118
119   /* Print the index of the node.  */
120   dump_maybe_newline (di);
121   fprintf (di->stream, "%-4s: ", field);
122   di->column += 6;
123   dump_index (di, index);
124 }
125
126 /* Dump the type of T.  */
127
128 void
129 queue_and_dump_type (di, t)
130      dump_info_p di;
131      tree t;
132 {
133   queue_and_dump_index (di, "type", TREE_TYPE (t), DUMP_NONE);
134 }
135
136 /* Dump column control */
137 #define SOL_COLUMN 25           /* Start of line column.  */
138 #define EOL_COLUMN 55           /* End of line column.  */
139 #define COLUMN_ALIGNMENT 15     /* Alignment.  */
140
141 /* Insert a new line in the dump output, and indent to an appropriate
142    place to start printing more fields.  */
143
144 static void
145 dump_new_line (di)
146      dump_info_p di;
147 {
148   fprintf (di->stream, "\n%*s", SOL_COLUMN, "");
149   di->column = SOL_COLUMN;
150 }
151
152 /* If necessary, insert a new line.  */
153
154 static void
155 dump_maybe_newline (di)
156      dump_info_p di;
157 {
158   int extra;
159
160   /* See if we need a new line.  */
161   if (di->column > EOL_COLUMN)
162     dump_new_line (di);
163   /* See if we need any padding.  */
164   else if ((extra = (di->column - SOL_COLUMN) % COLUMN_ALIGNMENT) != 0)
165     {
166       fprintf (di->stream, "%*s", COLUMN_ALIGNMENT - extra, "");
167       di->column += COLUMN_ALIGNMENT - extra;
168     }
169 }
170
171 /* Dump pointer PTR using FIELD to identify it.  */
172
173 void
174 dump_pointer (di, field, ptr)
175      dump_info_p di;
176      const char *field;
177      void *ptr;
178 {
179   dump_maybe_newline (di);
180   fprintf (di->stream, "%-4s: %-8lx ", field, (long) ptr);
181   di->column += 15;
182 }
183
184 /* Dump integer I using FIELD to identify it.  */
185
186 void
187 dump_int (di, field, i)
188      dump_info_p di;
189      const char *field;
190      int i;
191 {
192   dump_maybe_newline (di);
193   fprintf (di->stream, "%-4s: %-7d ", field, i);
194   di->column += 14;
195 }
196
197 /* Dump the string S.  */
198
199 void
200 dump_string (di, string)
201      dump_info_p di;
202      const char *string;
203 {
204   dump_maybe_newline (di);
205   fprintf (di->stream, "%-13s ", string);
206   if (strlen (string) > 13)
207     di->column += strlen (string) + 1;
208   else
209     di->column += 14;
210 }
211
212 /* Dump the string field S.  */
213
214 static void
215 dump_string_field (di, field, string)
216      dump_info_p di;
217      const char *field;
218      const char *string;
219 {
220   dump_maybe_newline (di);
221   fprintf (di->stream, "%-4s: %-7s ", field, string);
222   if (strlen (string) > 7)
223     di->column += 6 + strlen (string) + 1;
224   else
225     di->column += 14;
226 }
227
228 /* Dump information common to statements from STMT.  */
229
230 void
231 dump_stmt (di, t)
232      dump_info_p di;
233      tree t;
234 {
235   dump_int (di, "line", STMT_LINENO (t));
236 }
237
238 /* Dump the next statement after STMT.  */
239
240 void
241 dump_next_stmt (di, t)
242      dump_info_p di;
243      tree t;
244 {
245   dump_child ("next", TREE_CHAIN (t));
246 }
247
248 /* Dump the next node in the queue.  */
249
250 static void
251 dequeue_and_dump (di)
252      dump_info_p di;
253 {
254   dump_queue_p dq;
255   splay_tree_node stn;
256   dump_node_info_p dni;
257   tree t;
258   unsigned int index;
259   enum tree_code code;
260   char code_class;
261   const char* code_name;
262
263   /* Get the next node from the queue.  */
264   dq = di->queue;
265   stn = dq->node;
266   t = (tree) stn->key;
267   dni = (dump_node_info_p) stn->value;
268   index = dni->index;
269
270   /* Remove the node from the queue, and put it on the free list.  */
271   di->queue = dq->next;
272   if (!di->queue)
273     di->queue_end = 0;
274   dq->next = di->free_list;
275   di->free_list = dq;
276
277   /* Print the node index.  */
278   dump_index (di, index);
279   /* And the type of node this is.  */
280   if (dni->binfo_p)
281     code_name = "binfo";
282   else
283     code_name = tree_code_name[(int) TREE_CODE (t)];
284   fprintf (di->stream, "%-16s ", code_name);
285   di->column = 25;
286
287   /* Figure out what kind of node this is.  */
288   code = TREE_CODE (t);
289   code_class = TREE_CODE_CLASS (code);
290
291   /* Although BINFOs are TREE_VECs, we dump them specially so as to be
292      more informative.  */
293   if (dni->binfo_p)
294     {
295       if (TREE_VIA_PUBLIC (t))
296         dump_string (di, "pub");
297       else if (TREE_VIA_PROTECTED (t))
298         dump_string (di, "prot");
299       else if (TREE_VIA_PRIVATE (t))
300         dump_string (di, "priv");
301       if (TREE_VIA_VIRTUAL (t))
302         dump_string (di, "virt");
303
304       dump_child ("type", BINFO_TYPE (t));
305       dump_child ("base", BINFO_BASETYPES (t));
306
307       goto done;
308     }
309
310   /* We can knock off a bunch of expression nodes in exactly the same
311      way.  */
312   if (IS_EXPR_CODE_CLASS (code_class))
313     {
314       /* If we're dumping children, dump them now.  */
315       queue_and_dump_type (di, t);
316
317       switch (code_class)
318         {
319         case '1':
320           dump_child ("op 0", TREE_OPERAND (t, 0));
321           break;
322
323         case '2':
324         case '<':
325           dump_child ("op 0", TREE_OPERAND (t, 0));
326           dump_child ("op 1", TREE_OPERAND (t, 1));
327           break;
328
329         case 'e':
330           /* These nodes are handled explicitly below.  */
331           break;
332
333         default:
334           abort ();
335         }
336     }
337   else if (DECL_P (t))
338     {
339       /* All declarations have names.  */
340       if (DECL_NAME (t))
341         dump_child ("name", DECL_NAME (t));
342       if (DECL_ASSEMBLER_NAME_SET_P (t)
343           && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t))
344         dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
345       /* And types.  */
346       queue_and_dump_type (di, t);
347       dump_child ("scpe", DECL_CONTEXT (t));
348       /* And a source position.  */
349       if (DECL_SOURCE_FILE (t))
350         {
351           const char *filename = strrchr (DECL_SOURCE_FILE (t), '/');
352           if (!filename)
353             filename = DECL_SOURCE_FILE (t);
354           else
355             /* Skip the slash.  */
356             ++filename;
357
358           dump_maybe_newline (di);
359           fprintf (di->stream, "srcp: %s:%-6d ", filename,
360                    DECL_SOURCE_LINE (t));
361           di->column += 6 + strlen (filename) + 8;
362         }
363       /* And any declaration can be compiler-generated.  */
364       if (DECL_ARTIFICIAL (t))
365         dump_string (di, "artificial");
366       if (TREE_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
367         dump_child ("chan", TREE_CHAIN (t));
368     }
369   else if (code_class == 't')
370     {
371       /* All types have qualifiers.  */
372       int quals = (*lang_hooks.tree_dump.type_quals) (t);
373
374       if (quals != TYPE_UNQUALIFIED)
375         {
376           fprintf (di->stream, "qual: %c%c%c     ",
377                    (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
378                    (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
379                    (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
380           di->column += 14;
381         }
382
383       /* All types have associated declarations.  */
384       dump_child ("name", TYPE_NAME (t));
385
386       /* All types have a main variant.  */
387       if (TYPE_MAIN_VARIANT (t) != t)
388         dump_child ("unql", TYPE_MAIN_VARIANT (t));
389
390       /* And sizes.  */
391       dump_child ("size", TYPE_SIZE (t));
392
393       /* All types have alignments.  */
394       dump_int (di, "algn", TYPE_ALIGN (t));
395     }
396   else if (code_class == 'c')
397     /* All constants can have types.  */
398     queue_and_dump_type (di, t);
399
400   /* Give the language-specific code a chance to print something.  If
401      it's completely taken care of things, don't bother printing
402      anything more ourselves.  */
403   if ((*lang_hooks.tree_dump.dump_tree) (di, t))
404     goto done;
405
406   /* Now handle the various kinds of nodes.  */
407   switch (code)
408     {
409       int i;
410
411     case IDENTIFIER_NODE:
412       dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
413       dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
414       break;
415
416     case TREE_LIST:
417       dump_child ("purp", TREE_PURPOSE (t));
418       dump_child ("valu", TREE_VALUE (t));
419       dump_child ("chan", TREE_CHAIN (t));
420       break;
421
422     case TREE_VEC:
423       dump_int (di, "lngt", TREE_VEC_LENGTH (t));
424       for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
425         {
426           char buffer[32];
427           sprintf (buffer, "%u", i);
428           dump_child (buffer, TREE_VEC_ELT (t, i));
429         }
430       break;
431
432     case INTEGER_TYPE:
433     case ENUMERAL_TYPE:
434       dump_int (di, "prec", TYPE_PRECISION (t));
435       if (TREE_UNSIGNED (t))
436         dump_string (di, "unsigned");
437       dump_child ("min", TYPE_MIN_VALUE (t));
438       dump_child ("max", TYPE_MAX_VALUE (t));
439
440       if (code == ENUMERAL_TYPE)
441         dump_child ("csts", TYPE_VALUES (t));
442       break;
443
444     case REAL_TYPE:
445       dump_int (di, "prec", TYPE_PRECISION (t));
446       break;
447
448     case POINTER_TYPE:
449       dump_child ("ptd", TREE_TYPE (t));
450       break;
451
452     case REFERENCE_TYPE:
453       dump_child ("refd", TREE_TYPE (t));
454       break;
455
456     case METHOD_TYPE:
457       dump_child ("clas", TYPE_METHOD_BASETYPE (t));
458       /* Fall through.  */
459
460     case FUNCTION_TYPE:
461       dump_child ("retn", TREE_TYPE (t));
462       dump_child ("prms", TYPE_ARG_TYPES (t));
463       break;
464
465     case ARRAY_TYPE:
466       dump_child ("elts", TREE_TYPE (t));
467       dump_child ("domn", TYPE_DOMAIN (t));
468       break;
469
470     case RECORD_TYPE:
471     case UNION_TYPE:
472       if (TREE_CODE (t) == RECORD_TYPE)
473         dump_string (di, "struct");
474       else
475         dump_string (di, "union");
476
477       dump_child ("flds", TYPE_FIELDS (t));
478       dump_child ("fncs", TYPE_METHODS (t));
479       queue_and_dump_index (di, "binf", TYPE_BINFO (t),
480                             DUMP_BINFO);
481       break;
482
483     case CONST_DECL:
484       dump_child ("cnst", DECL_INITIAL (t));
485       break;
486
487     case VAR_DECL:
488     case PARM_DECL:
489     case FIELD_DECL:
490     case RESULT_DECL:
491       if (TREE_CODE (t) == PARM_DECL)
492         dump_child ("argt", DECL_ARG_TYPE (t));
493       else
494         dump_child ("init", DECL_INITIAL (t));
495       dump_child ("size", DECL_SIZE (t));
496       dump_int (di, "algn", DECL_ALIGN (t));
497
498       if (TREE_CODE (t) == FIELD_DECL)
499         {
500           if (DECL_C_BIT_FIELD (t))
501             dump_string (di, "bitfield");
502           if (DECL_FIELD_OFFSET (t))
503             dump_child ("bpos", bit_position (t));
504         }
505       else if (TREE_CODE (t) == VAR_DECL
506                || TREE_CODE (t) == PARM_DECL)
507         {
508           dump_int (di, "used", TREE_USED (t));
509           if (DECL_REGISTER (t))
510             dump_string (di, "register");
511         }
512       break;
513
514     case FUNCTION_DECL:
515       dump_child ("args", DECL_ARGUMENTS (t));
516       if (DECL_EXTERNAL (t))
517         dump_string (di, "undefined");
518       if (TREE_PUBLIC (t))
519         dump_string (di, "extern");
520       else
521         dump_string (di, "static");
522       if (DECL_LANG_SPECIFIC (t) && !dump_flag (di, TDF_SLIM, t))
523         dump_child ("body", DECL_SAVED_TREE (t));
524       break;
525
526     case ASM_STMT:
527       dump_stmt (di, t);
528       if (ASM_VOLATILE_P (t))
529         dump_string (di, "volatile");
530       dump_child ("strg", ASM_STRING (t));
531       dump_child ("outs", ASM_OUTPUTS (t));
532       dump_child ("ins", ASM_INPUTS (t));
533       dump_child ("clbr", ASM_CLOBBERS (t));
534       dump_next_stmt (di, t);
535       break;
536
537     case BREAK_STMT:
538     case CONTINUE_STMT:
539       dump_stmt (di, t);
540       dump_next_stmt (di, t);
541       break;
542
543     case CASE_LABEL:
544       /* Note that a case label is not like other statements; there is
545          no way to get the line-number of a case label.  */
546       dump_child ("low", CASE_LOW (t));
547       dump_child ("high", CASE_HIGH (t));
548       dump_next_stmt (di, t);
549       break;
550
551     case CLEANUP_STMT:
552       dump_stmt (di, t);
553       dump_child ("decl", CLEANUP_DECL (t));
554       dump_child ("expr", CLEANUP_EXPR (t));
555       dump_next_stmt (di, t);
556       break;
557
558     case COMPOUND_STMT:
559       dump_stmt (di, t);
560       dump_child ("body", COMPOUND_BODY (t));
561       dump_next_stmt (di, t);
562       break;
563
564     case DECL_STMT:
565       dump_stmt (di, t);
566       dump_child ("decl", DECL_STMT_DECL (t));
567       dump_next_stmt (di, t);
568       break;
569
570     case DO_STMT:
571       dump_stmt (di, t);
572       dump_child ("body", DO_BODY (t));
573       dump_child ("cond", DO_COND (t));
574       dump_next_stmt (di, t);
575       break;
576
577     case EXPR_STMT:
578       dump_stmt (di, t);
579       dump_child ("expr", EXPR_STMT_EXPR (t));
580       dump_next_stmt (di, t);
581       break;
582
583     case FOR_STMT:
584       dump_stmt (di, t);
585       dump_child ("init", FOR_INIT_STMT (t));
586       dump_child ("cond", FOR_COND (t));
587       dump_child ("expr", FOR_EXPR (t));
588       dump_child ("body", FOR_BODY (t));
589       dump_next_stmt (di, t);
590       break;
591
592     case GOTO_STMT:
593       dump_stmt (di, t);
594       dump_child ("dest", GOTO_DESTINATION (t));
595       dump_next_stmt (di, t);
596       break;
597
598     case IF_STMT:
599       dump_stmt (di, t);
600       dump_child ("cond", IF_COND (t));
601       dump_child ("then", THEN_CLAUSE (t));
602       dump_child ("else", ELSE_CLAUSE (t));
603       dump_next_stmt (di, t);
604       break;
605
606     case LABEL_STMT:
607       dump_stmt (di, t);
608       dump_child ("labl", LABEL_STMT_LABEL (t));
609       dump_next_stmt (di, t);
610       break;
611
612     case RETURN_STMT:
613       dump_stmt (di, t);
614       dump_child ("expr", RETURN_EXPR (t));
615       dump_next_stmt (di, t);
616       break;
617
618     case SWITCH_STMT:
619       dump_stmt (di, t);
620       dump_child ("cond", SWITCH_COND (t));
621       dump_child ("body", SWITCH_BODY (t));
622       dump_next_stmt (di, t);
623       break;
624
625     case WHILE_STMT:
626       dump_stmt (di, t);
627       dump_child ("cond", WHILE_COND (t));
628       dump_child ("body", WHILE_BODY (t));
629       dump_next_stmt (di, t);
630       break;
631
632     case SCOPE_STMT:
633       dump_stmt (di, t);
634       if (SCOPE_BEGIN_P (t))
635         dump_string (di, "begn");
636       else
637         dump_string (di, "end");
638       if (SCOPE_NULLIFIED_P (t))
639         dump_string (di, "null");
640       if (!SCOPE_NO_CLEANUPS_P (t))
641         dump_string (di, "clnp");
642       dump_next_stmt (di, t);
643       break;
644
645     case INTEGER_CST:
646       if (TREE_INT_CST_HIGH (t))
647         dump_int (di, "high", TREE_INT_CST_HIGH (t));
648       dump_int (di, "low", TREE_INT_CST_LOW (t));
649       break;
650
651     case STRING_CST:
652       fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
653       dump_int (di, "lngt", TREE_STRING_LENGTH (t));
654       break;
655
656     case TRUTH_NOT_EXPR:
657     case ADDR_EXPR:
658     case INDIRECT_REF:
659     case CLEANUP_POINT_EXPR:
660     case SAVE_EXPR:
661       /* These nodes are unary, but do not have code class `1'.  */
662       dump_child ("op 0", TREE_OPERAND (t, 0));
663       break;
664
665     case TRUTH_ANDIF_EXPR:
666     case TRUTH_ORIF_EXPR:
667     case INIT_EXPR:
668     case MODIFY_EXPR:
669     case COMPONENT_REF:
670     case COMPOUND_EXPR:
671     case ARRAY_REF:
672     case PREDECREMENT_EXPR:
673     case PREINCREMENT_EXPR:
674     case POSTDECREMENT_EXPR:
675     case POSTINCREMENT_EXPR:
676       /* These nodes are binary, but do not have code class `2'.  */
677       dump_child ("op 0", TREE_OPERAND (t, 0));
678       dump_child ("op 1", TREE_OPERAND (t, 1));
679       break;
680
681     case COND_EXPR:
682       dump_child ("op 0", TREE_OPERAND (t, 0));
683       dump_child ("op 1", TREE_OPERAND (t, 1));
684       dump_child ("op 2", TREE_OPERAND (t, 2));
685       break;
686
687     case CALL_EXPR:
688       dump_child ("fn", TREE_OPERAND (t, 0));
689       dump_child ("args", TREE_OPERAND (t, 1));
690       break;
691
692     case CONSTRUCTOR:
693       dump_child ("elts", TREE_OPERAND (t, 1));
694       break;
695
696     case STMT_EXPR:
697       dump_child ("stmt", STMT_EXPR_STMT (t));
698       break;
699
700     case BIND_EXPR:
701       dump_child ("vars", TREE_OPERAND (t, 0));
702       dump_child ("body", TREE_OPERAND (t, 1));
703       break;
704
705     case LOOP_EXPR:
706       dump_child ("body", TREE_OPERAND (t, 0));
707       break;
708
709     case EXIT_EXPR:
710       dump_child ("cond", TREE_OPERAND (t, 0));
711       break;
712
713     case TARGET_EXPR:
714       dump_child ("decl", TREE_OPERAND (t, 0));
715       dump_child ("init", TREE_OPERAND (t, 1));
716       dump_child ("clnp", TREE_OPERAND (t, 2));
717       /* There really are two possible places the initializer can be.
718          After RTL expansion, the second operand is moved to the
719          position of the fourth operand, and the second operand
720          becomes NULL.  */
721       dump_child ("init", TREE_OPERAND (t, 3));
722       break;
723
724     case EXPR_WITH_FILE_LOCATION:
725       dump_child ("expr", EXPR_WFL_NODE (t));
726       break;
727
728     default:
729       /* There are no additional fields to print.  */
730       break;
731     }
732
733  done:
734   if (dump_flag (di, TDF_ADDRESS, NULL))
735     dump_pointer (di, "addr", (void *)t);
736
737   /* Terminate the line.  */
738   fprintf (di->stream, "\n");
739 }
740
741 /* Return non-zero if FLAG has been specified for the dump, and NODE
742    is not the root node of the dump.  */
743
744 int dump_flag (di, flag, node)
745      dump_info_p di;
746      int flag;
747      tree node;
748 {
749   return (di->flags & flag) && (node != di->node);
750 }
751
752 /* Dump T, and all its children, on STREAM.  */
753
754 void
755 dump_node (t, flags, stream)
756      tree t;
757      int flags;
758      FILE *stream;
759 {
760   struct dump_info di;
761   dump_queue_p dq;
762   dump_queue_p next_dq;
763
764   /* Initialize the dump-information structure.  */
765   di.stream = stream;
766   di.index = 0;
767   di.column = 0;
768   di.queue = 0;
769   di.queue_end = 0;
770   di.free_list = 0;
771   di.flags = flags;
772   di.node = t;
773   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
774                              (splay_tree_delete_value_fn) &free);
775
776   /* Queue up the first node.  */
777   queue (&di, t, DUMP_NONE);
778
779   /* Until the queue is empty, keep dumping nodes.  */
780   while (di.queue)
781     dequeue_and_dump (&di);
782
783   /* Now, clean up.  */
784   for (dq = di.free_list; dq; dq = next_dq)
785     {
786       next_dq = dq->next;
787       free (dq);
788     }
789   splay_tree_delete (di.nodes);
790 }
791
792 /* Define a tree dump switch.  */
793 struct dump_file_info
794 {
795   const char *const suffix;     /* suffix to give output file.  */
796   const char *const swtch;      /* command line switch */
797   int flags;                    /* user flags */
798   int state;                    /* state of play */
799 };
800
801 /* Table of tree dump switches. This must be consistent with the
802    TREE_DUMP_INDEX enumeration in tree.h */
803 static struct dump_file_info dump_files[TDI_end] =
804 {
805   {".tu", "dump-translation-unit", 0, 0},
806   {".class", "dump-class-hierarchy", 0, 0},
807   {".original", "dump-tree-original", 0, 0},
808   {".optimized", "dump-tree-optimized", 0, 0},
809   {".inlined", "dump-tree-inlined", 0, 0},
810 };
811
812 /* Define a name->number mapping for a dump flag value.  */
813 struct dump_option_value_info
814 {
815   const char *const name;       /* the name of the value */
816   const int value;              /* the value of the name */
817 };
818
819 /* Table of dump options. This must be consistent with the TDF_* flags
820    in tree.h */
821 static const struct dump_option_value_info dump_options[] =
822 {
823   {"address", TDF_ADDRESS},
824   {"slim", TDF_SLIM},
825   {"all", ~0},
826   {NULL, 0}
827 };
828
829 /* Begin a tree dump for PHASE. Stores any user supplied flag in
830    *FLAG_PTR and returns a stream to write to. If the dump is not
831    enabled, returns NULL.
832    Multiple calls will reopen and append to the dump file.  */
833
834 FILE *
835 dump_begin (phase, flag_ptr)
836      enum tree_dump_index phase;
837      int *flag_ptr;
838 {
839   FILE *stream;
840   char *name;
841
842   if (!dump_files[phase].state)
843     return NULL;
844
845   name = concat (dump_base_name, dump_files[phase].suffix, NULL);
846   stream = fopen (name, dump_files[phase].state < 0 ? "w" : "a");
847   if (!stream)
848     error ("could not open dump file `%s'", name);
849   else
850     dump_files[phase].state = 1;
851   free (name);
852   if (flag_ptr)
853     *flag_ptr = dump_files[phase].flags;
854
855   return stream;
856 }
857
858 /* Returns non-zero if tree dump PHASE is enabled.  */
859
860 int
861 dump_enabled_p (phase)
862      enum tree_dump_index phase;
863 {
864   return dump_files[phase].state;
865 }
866
867 /* Returns the switch name of PHASE.  */
868
869 const char *
870 dump_flag_name (phase)
871      enum tree_dump_index phase;
872 {
873   return dump_files[phase].swtch;
874 }
875
876 /* Finish a tree dump for PHASE. STREAM is the stream created by
877    dump_begin.  */
878
879 void
880 dump_end (phase, stream)
881      enum tree_dump_index phase ATTRIBUTE_UNUSED;
882      FILE *stream;
883 {
884   fclose (stream);
885 }
886
887 /* Parse ARG as a dump switch. Return non-zero if it is, and store the
888    relevant details in the dump_files array.  */
889
890 int
891 dump_switch_p (arg)
892      const char *arg;
893 {
894   unsigned ix;
895   const char *option_value;
896
897   for (ix = 0; ix != TDI_end; ix++)
898     if ((option_value = skip_leading_substring (arg, dump_files[ix].swtch)))
899       {
900         const char *ptr = option_value;
901         int flags = 0;
902
903         while (*ptr)
904           {
905             const struct dump_option_value_info *option_ptr;
906             const char *end_ptr;
907             unsigned length;
908
909             while (*ptr == '-')
910               ptr++;
911             end_ptr = strchr (ptr, '-');
912             if (!end_ptr)
913               end_ptr = ptr + strlen (ptr);
914             length = end_ptr - ptr;
915
916             for (option_ptr = dump_options; option_ptr->name;
917                  option_ptr++)
918               if (strlen (option_ptr->name) == length
919                   && !memcmp (option_ptr->name, ptr, length))
920                 {
921                   flags |= option_ptr->value;
922                   goto found;
923                 }
924             warning ("ignoring unknown option `%.*s' in `-f%s'",
925                      length, ptr, dump_files[ix].swtch);
926           found:;
927             ptr = end_ptr;
928           }
929
930         dump_files[ix].state = -1;
931         dump_files[ix].flags = flags;
932
933         return 1;
934       }
935   return 0;
936 }