tree-dump.c revision 90075
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
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING.  If not, write to the Free
19Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2002111-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
32static unsigned int queue PARAMS ((dump_info_p, tree, int));
33static void dump_index PARAMS ((dump_info_p, unsigned int));
34static void dequeue_and_dump PARAMS ((dump_info_p));
35static void dump_new_line PARAMS ((dump_info_p));
36static void dump_maybe_newline PARAMS ((dump_info_p));
37static 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
42static unsigned int
43queue (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
83static void
84dump_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
96void
97queue_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
128void
129queue_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
144static void
145dump_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
154static void
155dump_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
173void
174dump_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
186void
187dump_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
199void
200dump_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
214static void
215dump_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
230void
231dump_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
240void
241dump_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
250static void
251dequeue_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 COMPOUND_STMT:
552      dump_stmt (di, t);
553      dump_child ("body", COMPOUND_BODY (t));
554      dump_next_stmt (di, t);
555      break;
556
557    case DECL_STMT:
558      dump_stmt (di, t);
559      dump_child ("decl", DECL_STMT_DECL (t));
560      dump_next_stmt (di, t);
561      break;
562
563    case DO_STMT:
564      dump_stmt (di, t);
565      dump_child ("body", DO_BODY (t));
566      dump_child ("cond", DO_COND (t));
567      dump_next_stmt (di, t);
568      break;
569
570    case EXPR_STMT:
571      dump_stmt (di, t);
572      dump_child ("expr", EXPR_STMT_EXPR (t));
573      dump_next_stmt (di, t);
574      break;
575
576    case FOR_STMT:
577      dump_stmt (di, t);
578      dump_child ("init", FOR_INIT_STMT (t));
579      dump_child ("cond", FOR_COND (t));
580      dump_child ("expr", FOR_EXPR (t));
581      dump_child ("body", FOR_BODY (t));
582      dump_next_stmt (di, t);
583      break;
584
585    case GOTO_STMT:
586      dump_stmt (di, t);
587      dump_child ("dest", GOTO_DESTINATION (t));
588      dump_next_stmt (di, t);
589      break;
590
591    case IF_STMT:
592      dump_stmt (di, t);
593      dump_child ("cond", IF_COND (t));
594      dump_child ("then", THEN_CLAUSE (t));
595      dump_child ("else", ELSE_CLAUSE (t));
596      dump_next_stmt (di, t);
597      break;
598
599    case LABEL_STMT:
600      dump_stmt (di, t);
601      dump_child ("labl", LABEL_STMT_LABEL (t));
602      dump_next_stmt (di, t);
603      break;
604
605    case RETURN_STMT:
606      dump_stmt (di, t);
607      dump_child ("expr", RETURN_EXPR (t));
608      dump_next_stmt (di, t);
609      break;
610
611    case SWITCH_STMT:
612      dump_stmt (di, t);
613      dump_child ("cond", SWITCH_COND (t));
614      dump_child ("body", SWITCH_BODY (t));
615      dump_next_stmt (di, t);
616      break;
617
618    case WHILE_STMT:
619      dump_stmt (di, t);
620      dump_child ("cond", WHILE_COND (t));
621      dump_child ("body", WHILE_BODY (t));
622      dump_next_stmt (di, t);
623      break;
624
625    case SCOPE_STMT:
626      dump_stmt (di, t);
627      if (SCOPE_BEGIN_P (t))
628	dump_string (di, "begn");
629      else
630	dump_string (di, "end");
631      if (SCOPE_NULLIFIED_P (t))
632	dump_string (di, "null");
633      if (!SCOPE_NO_CLEANUPS_P (t))
634	dump_string (di, "clnp");
635      dump_next_stmt (di, t);
636      break;
637
638    case INTEGER_CST:
639      if (TREE_INT_CST_HIGH (t))
640	dump_int (di, "high", TREE_INT_CST_HIGH (t));
641      dump_int (di, "low", TREE_INT_CST_LOW (t));
642      break;
643
644    case STRING_CST:
645      fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
646      dump_int (di, "lngt", TREE_STRING_LENGTH (t));
647      break;
648
649    case TRUTH_NOT_EXPR:
650    case ADDR_EXPR:
651    case INDIRECT_REF:
652    case CLEANUP_POINT_EXPR:
653    case SAVE_EXPR:
654      /* These nodes are unary, but do not have code class `1'.  */
655      dump_child ("op 0", TREE_OPERAND (t, 0));
656      break;
657
658    case TRUTH_ANDIF_EXPR:
659    case TRUTH_ORIF_EXPR:
660    case INIT_EXPR:
661    case MODIFY_EXPR:
662    case COMPONENT_REF:
663    case COMPOUND_EXPR:
664    case ARRAY_REF:
665    case PREDECREMENT_EXPR:
666    case PREINCREMENT_EXPR:
667    case POSTDECREMENT_EXPR:
668    case POSTINCREMENT_EXPR:
669      /* These nodes are binary, but do not have code class `2'.  */
670      dump_child ("op 0", TREE_OPERAND (t, 0));
671      dump_child ("op 1", TREE_OPERAND (t, 1));
672      break;
673
674    case COND_EXPR:
675      dump_child ("op 0", TREE_OPERAND (t, 0));
676      dump_child ("op 1", TREE_OPERAND (t, 1));
677      dump_child ("op 2", TREE_OPERAND (t, 2));
678      break;
679
680    case CALL_EXPR:
681      dump_child ("fn", TREE_OPERAND (t, 0));
682      dump_child ("args", TREE_OPERAND (t, 1));
683      break;
684
685    case CONSTRUCTOR:
686      dump_child ("elts", TREE_OPERAND (t, 1));
687      break;
688
689    case STMT_EXPR:
690      dump_child ("stmt", STMT_EXPR_STMT (t));
691      break;
692
693    case BIND_EXPR:
694      dump_child ("vars", TREE_OPERAND (t, 0));
695      dump_child ("body", TREE_OPERAND (t, 1));
696      break;
697
698    case LOOP_EXPR:
699      dump_child ("body", TREE_OPERAND (t, 0));
700      break;
701
702    case EXIT_EXPR:
703      dump_child ("cond", TREE_OPERAND (t, 0));
704      break;
705
706    case TARGET_EXPR:
707      dump_child ("decl", TREE_OPERAND (t, 0));
708      dump_child ("init", TREE_OPERAND (t, 1));
709      dump_child ("clnp", TREE_OPERAND (t, 2));
710      /* There really are two possible places the initializer can be.
711	 After RTL expansion, the second operand is moved to the
712	 position of the fourth operand, and the second operand
713	 becomes NULL.  */
714      dump_child ("init", TREE_OPERAND (t, 3));
715      break;
716
717    case EXPR_WITH_FILE_LOCATION:
718      dump_child ("expr", EXPR_WFL_NODE (t));
719      break;
720
721    default:
722      /* There are no additional fields to print.  */
723      break;
724    }
725
726 done:
727  if (dump_flag (di, TDF_ADDRESS, NULL))
728    dump_pointer (di, "addr", (void *)t);
729
730  /* Terminate the line.  */
731  fprintf (di->stream, "\n");
732}
733
734/* Return non-zero if FLAG has been specified for the dump, and NODE
735   is not the root node of the dump.  */
736
737int dump_flag (di, flag, node)
738     dump_info_p di;
739     int flag;
740     tree node;
741{
742  return (di->flags & flag) && (node != di->node);
743}
744
745/* Dump T, and all its children, on STREAM.  */
746
747void
748dump_node (t, flags, stream)
749     tree t;
750     int flags;
751     FILE *stream;
752{
753  struct dump_info di;
754  dump_queue_p dq;
755  dump_queue_p next_dq;
756
757  /* Initialize the dump-information structure.  */
758  di.stream = stream;
759  di.index = 0;
760  di.column = 0;
761  di.queue = 0;
762  di.queue_end = 0;
763  di.free_list = 0;
764  di.flags = flags;
765  di.node = t;
766  di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
767			     (splay_tree_delete_value_fn) &free);
768
769  /* Queue up the first node.  */
770  queue (&di, t, DUMP_NONE);
771
772  /* Until the queue is empty, keep dumping nodes.  */
773  while (di.queue)
774    dequeue_and_dump (&di);
775
776  /* Now, clean up.  */
777  for (dq = di.free_list; dq; dq = next_dq)
778    {
779      next_dq = dq->next;
780      free (dq);
781    }
782  splay_tree_delete (di.nodes);
783}
784
785/* Define a tree dump switch.  */
786struct dump_file_info
787{
788  const char *const suffix;	/* suffix to give output file.  */
789  const char *const swtch;	/* command line switch */
790  int flags;			/* user flags */
791  int state;			/* state of play */
792};
793
794/* Table of tree dump switches. This must be consistent with the
795   TREE_DUMP_INDEX enumeration in tree.h */
796static struct dump_file_info dump_files[TDI_end] =
797{
798  {".tu", "dump-translation-unit", 0, 0},
799  {".class", "dump-class-hierarchy", 0, 0},
800  {".original", "dump-tree-original", 0, 0},
801  {".optimized", "dump-tree-optimized", 0, 0},
802  {".inlined", "dump-tree-inlined", 0, 0},
803};
804
805/* Define a name->number mapping for a dump flag value.  */
806struct dump_option_value_info
807{
808  const char *const name;	/* the name of the value */
809  const int value;		/* the value of the name */
810};
811
812/* Table of dump options. This must be consistent with the TDF_* flags
813   in tree.h */
814static const struct dump_option_value_info dump_options[] =
815{
816  {"address", TDF_ADDRESS},
817  {"slim", TDF_SLIM},
818  {"all", ~0},
819  {NULL, 0}
820};
821
822/* Begin a tree dump for PHASE. Stores any user supplied flag in
823   *FLAG_PTR and returns a stream to write to. If the dump is not
824   enabled, returns NULL.
825   Multiple calls will reopen and append to the dump file.  */
826
827FILE *
828dump_begin (phase, flag_ptr)
829     enum tree_dump_index phase;
830     int *flag_ptr;
831{
832  FILE *stream;
833  char *name;
834
835  if (!dump_files[phase].state)
836    return NULL;
837
838  name = concat (dump_base_name, dump_files[phase].suffix, NULL);
839  stream = fopen (name, dump_files[phase].state < 0 ? "w" : "a");
840  if (!stream)
841    error ("could not open dump file `%s'", name);
842  else
843    dump_files[phase].state = 1;
844  free (name);
845  if (flag_ptr)
846    *flag_ptr = dump_files[phase].flags;
847
848  return stream;
849}
850
851/* Returns non-zero if tree dump PHASE is enabled.  */
852
853int
854dump_enabled_p (phase)
855     enum tree_dump_index phase;
856{
857  return dump_files[phase].state;
858}
859
860/* Returns the switch name of PHASE.  */
861
862const char *
863dump_flag_name (phase)
864     enum tree_dump_index phase;
865{
866  return dump_files[phase].swtch;
867}
868
869/* Finish a tree dump for PHASE. STREAM is the stream created by
870   dump_begin.  */
871
872void
873dump_end (phase, stream)
874     enum tree_dump_index phase ATTRIBUTE_UNUSED;
875     FILE *stream;
876{
877  fclose (stream);
878}
879
880/* Parse ARG as a dump switch. Return non-zero if it is, and store the
881   relevant details in the dump_files array.  */
882
883int
884dump_switch_p (arg)
885     const char *arg;
886{
887  unsigned ix;
888  const char *option_value;
889
890  for (ix = 0; ix != TDI_end; ix++)
891    if ((option_value = skip_leading_substring (arg, dump_files[ix].swtch)))
892      {
893	const char *ptr = option_value;
894	int flags = 0;
895
896	while (*ptr)
897	  {
898	    const struct dump_option_value_info *option_ptr;
899	    const char *end_ptr;
900	    unsigned length;
901
902	    while (*ptr == '-')
903	      ptr++;
904	    end_ptr = strchr (ptr, '-');
905	    if (!end_ptr)
906	      end_ptr = ptr + strlen (ptr);
907	    length = end_ptr - ptr;
908
909	    for (option_ptr = dump_options; option_ptr->name;
910		 option_ptr++)
911	      if (strlen (option_ptr->name) == length
912		  && !memcmp (option_ptr->name, ptr, length))
913		{
914		  flags |= option_ptr->value;
915		  goto found;
916		}
917	    warning ("ignoring unknown option `%.*s' in `-f%s'",
918		     length, ptr, dump_files[ix].swtch);
919	  found:;
920	    ptr = end_ptr;
921	  }
922
923	dump_files[ix].state = -1;
924	dump_files[ix].flags = flags;
925
926	return 1;
927      }
928  return 0;
929}
930