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