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