OSDN Git Service

2006-02-08 Paolo Bonzini <bonzini@gnu.org>
[pf3gnuchains/gcc-fork.git] / gcc / tree-dump.c
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
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 2, or (at your option) any later
11 version.
12
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16 for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING.  If not, write to the Free
20 Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-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
36 static unsigned int queue (dump_info_p, tree, int);
37 static void dump_index (dump_info_p, unsigned int);
38 static void dequeue_and_dump (dump_info_p);
39 static void dump_new_line (dump_info_p);
40 static void dump_maybe_newline (dump_info_p);
41 static 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
46 static unsigned int
47 queue (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 = XNEW (struct dump_queue);
64
65   /* Create a new entry in the splay-tree.  */
66   dni = XNEW (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
84 static void
85 dump_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
95 void
96 queue_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
123 void
124 queue_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
137 static void
138 dump_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
146 static void
147 dump_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
164 void
165 dump_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
174 void
175 dump_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
184 void
185 dump_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
197 void
198 dump_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
210 static void
211 dequeue_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 (CODE_CONTAINS_STRUCT (TREE_CODE (t), TS_DECL_COMMON)
347           && DECL_ARTIFICIAL (t))
348         dump_string_field (di, "note", "artificial");
349       if (TREE_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
350         dump_child ("chan", TREE_CHAIN (t));
351     }
352   else if (code_class == tcc_type)
353     {
354       /* All types have qualifiers.  */
355       int quals = lang_hooks.tree_dump.type_quals (t);
356
357       if (quals != TYPE_UNQUALIFIED)
358         {
359           fprintf (di->stream, "qual: %c%c%c     ",
360                    (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
361                    (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
362                    (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
363           di->column += 14;
364         }
365
366       /* All types have associated declarations.  */
367       dump_child ("name", TYPE_NAME (t));
368
369       /* All types have a main variant.  */
370       if (TYPE_MAIN_VARIANT (t) != t)
371         dump_child ("unql", TYPE_MAIN_VARIANT (t));
372
373       /* And sizes.  */
374       dump_child ("size", TYPE_SIZE (t));
375
376       /* All types have alignments.  */
377       dump_int (di, "algn", TYPE_ALIGN (t));
378     }
379   else if (code_class == tcc_constant)
380     /* All constants can have types.  */
381     queue_and_dump_type (di, t);
382
383   /* Give the language-specific code a chance to print something.  If
384      it's completely taken care of things, don't bother printing
385      anything more ourselves.  */
386   if (lang_hooks.tree_dump.dump_tree (di, t))
387     goto done;
388
389   /* Now handle the various kinds of nodes.  */
390   switch (code)
391     {
392       int i;
393
394     case IDENTIFIER_NODE:
395       dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
396       dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
397       break;
398
399     case TREE_LIST:
400       dump_child ("purp", TREE_PURPOSE (t));
401       dump_child ("valu", TREE_VALUE (t));
402       dump_child ("chan", TREE_CHAIN (t));
403       break;
404
405     case STATEMENT_LIST:
406       {
407         tree_stmt_iterator it;
408         for (i = 0, it = tsi_start (t); !tsi_end_p (it); tsi_next (&it), i++)
409           {
410             char buffer[32];
411             sprintf (buffer, "%u", i);
412             dump_child (buffer, tsi_stmt (it));
413           }
414       }
415       break;
416
417     case TREE_VEC:
418       dump_int (di, "lngt", TREE_VEC_LENGTH (t));
419       for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
420         {
421           char buffer[32];
422           sprintf (buffer, "%u", i);
423           dump_child (buffer, TREE_VEC_ELT (t, i));
424         }
425       break;
426
427     case INTEGER_TYPE:
428     case ENUMERAL_TYPE:
429       dump_int (di, "prec", TYPE_PRECISION (t));
430       dump_string_field (di, "sign", TYPE_UNSIGNED (t) ? "unsigned": "signed");
431       dump_child ("min", TYPE_MIN_VALUE (t));
432       dump_child ("max", TYPE_MAX_VALUE (t));
433
434       if (code == ENUMERAL_TYPE)
435         dump_child ("csts", TYPE_VALUES (t));
436       break;
437
438     case REAL_TYPE:
439       dump_int (di, "prec", TYPE_PRECISION (t));
440       break;
441
442     case POINTER_TYPE:
443       dump_child ("ptd", TREE_TYPE (t));
444       break;
445
446     case REFERENCE_TYPE:
447       dump_child ("refd", TREE_TYPE (t));
448       break;
449
450     case METHOD_TYPE:
451       dump_child ("clas", TYPE_METHOD_BASETYPE (t));
452       /* Fall through.  */
453
454     case FUNCTION_TYPE:
455       dump_child ("retn", TREE_TYPE (t));
456       dump_child ("prms", TYPE_ARG_TYPES (t));
457       break;
458
459     case ARRAY_TYPE:
460       dump_child ("elts", TREE_TYPE (t));
461       dump_child ("domn", TYPE_DOMAIN (t));
462       break;
463
464     case RECORD_TYPE:
465     case UNION_TYPE:
466       if (TREE_CODE (t) == RECORD_TYPE)
467         dump_string_field (di, "tag", "struct");
468       else
469         dump_string_field (di, "tag", "union");
470
471       dump_child ("flds", TYPE_FIELDS (t));
472       dump_child ("fncs", TYPE_METHODS (t));
473       queue_and_dump_index (di, "binf", TYPE_BINFO (t),
474                             DUMP_BINFO);
475       break;
476
477     case CONST_DECL:
478       dump_child ("cnst", DECL_INITIAL (t));
479       break;
480       
481     case TYPE_MEMORY_TAG:
482     case NAME_MEMORY_TAG:
483     case STRUCT_FIELD_TAG:
484       break;
485
486     case VAR_DECL:
487     case PARM_DECL:
488     case FIELD_DECL:
489     case RESULT_DECL:
490       if (TREE_CODE (t) == PARM_DECL)
491         dump_child ("argt", DECL_ARG_TYPE (t));
492       else
493         dump_child ("init", DECL_INITIAL (t));
494       dump_child ("size", DECL_SIZE (t));
495       dump_int (di, "algn", DECL_ALIGN (t));
496
497       if (TREE_CODE (t) == FIELD_DECL)
498         {
499           if (DECL_FIELD_OFFSET (t))
500             dump_child ("bpos", bit_position (t));
501         }
502       else if (TREE_CODE (t) == VAR_DECL
503                || TREE_CODE (t) == PARM_DECL)
504         {
505           dump_int (di, "used", TREE_USED (t));
506           if (DECL_REGISTER (t))
507             dump_string_field (di, "spec", "register");
508         }
509       break;
510
511     case FUNCTION_DECL:
512       dump_child ("args", DECL_ARGUMENTS (t));
513       if (DECL_EXTERNAL (t))
514         dump_string_field (di, "body", "undefined");
515       if (TREE_PUBLIC (t))
516         dump_string_field (di, "link", "extern");
517       else
518         dump_string_field (di, "link", "static");
519       if (DECL_LANG_SPECIFIC (t) && !dump_flag (di, TDF_SLIM, t))
520         dump_child ("body", DECL_SAVED_TREE (t));
521       break;
522
523     case INTEGER_CST:
524       if (TREE_INT_CST_HIGH (t))
525         dump_int (di, "high", TREE_INT_CST_HIGH (t));
526       dump_int (di, "low", TREE_INT_CST_LOW (t));
527       break;
528
529     case STRING_CST:
530       fprintf (di->stream, "strg: %-7s ", TREE_STRING_POINTER (t));
531       dump_int (di, "lngt", TREE_STRING_LENGTH (t));
532       break;
533
534     case TRUTH_NOT_EXPR:
535     case ADDR_EXPR:
536     case INDIRECT_REF:
537     case ALIGN_INDIRECT_REF:
538     case MISALIGNED_INDIRECT_REF:
539     case CLEANUP_POINT_EXPR:
540     case SAVE_EXPR:
541     case REALPART_EXPR:
542     case IMAGPART_EXPR:
543       /* These nodes are unary, but do not have code class `1'.  */
544       dump_child ("op 0", TREE_OPERAND (t, 0));
545       break;
546
547     case TRUTH_ANDIF_EXPR:
548     case TRUTH_ORIF_EXPR:
549     case INIT_EXPR:
550     case MODIFY_EXPR:
551     case COMPOUND_EXPR:
552     case PREDECREMENT_EXPR:
553     case PREINCREMENT_EXPR:
554     case POSTDECREMENT_EXPR:
555     case POSTINCREMENT_EXPR:
556       /* These nodes are binary, but do not have code class `2'.  */
557       dump_child ("op 0", TREE_OPERAND (t, 0));
558       dump_child ("op 1", TREE_OPERAND (t, 1));
559       break;
560
561     case COMPONENT_REF:
562       dump_child ("op 0", TREE_OPERAND (t, 0));
563       dump_child ("op 1", TREE_OPERAND (t, 1));
564       dump_child ("op 2", TREE_OPERAND (t, 2));
565       break;
566
567     case ARRAY_REF:
568     case ARRAY_RANGE_REF:
569       dump_child ("op 0", TREE_OPERAND (t, 0));
570       dump_child ("op 1", TREE_OPERAND (t, 1));
571       dump_child ("op 2", TREE_OPERAND (t, 2));
572       dump_child ("op 3", TREE_OPERAND (t, 3));
573       break;
574
575     case COND_EXPR:
576       dump_child ("op 0", TREE_OPERAND (t, 0));
577       dump_child ("op 1", TREE_OPERAND (t, 1));
578       dump_child ("op 2", TREE_OPERAND (t, 2));
579       break;
580
581     case TRY_FINALLY_EXPR:
582       dump_child ("op 0", TREE_OPERAND (t, 0));
583       dump_child ("op 1", TREE_OPERAND (t, 1));
584       break;
585
586     case CALL_EXPR:
587       dump_child ("fn", TREE_OPERAND (t, 0));
588       dump_child ("args", TREE_OPERAND (t, 1));
589       break;
590
591     case CONSTRUCTOR:
592       {
593         unsigned HOST_WIDE_INT cnt;
594         tree index, value;
595         dump_int (di, "lngt", VEC_length (constructor_elt,
596                                           CONSTRUCTOR_ELTS (t)));
597         FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), cnt, index, value)
598           {
599             dump_child ("idx", index);
600             dump_child ("val", value);
601           }
602       }
603       break;
604
605     case BIND_EXPR:
606       dump_child ("vars", TREE_OPERAND (t, 0));
607       dump_child ("body", TREE_OPERAND (t, 1));
608       break;
609
610     case LOOP_EXPR:
611       dump_child ("body", TREE_OPERAND (t, 0));
612       break;
613
614     case EXIT_EXPR:
615       dump_child ("cond", TREE_OPERAND (t, 0));
616       break;
617
618     case RETURN_EXPR:
619       dump_child ("expr", TREE_OPERAND (t, 0));
620       break;
621
622     case TARGET_EXPR:
623       dump_child ("decl", TREE_OPERAND (t, 0));
624       dump_child ("init", TREE_OPERAND (t, 1));
625       dump_child ("clnp", TREE_OPERAND (t, 2));
626       /* There really are two possible places the initializer can be.
627          After RTL expansion, the second operand is moved to the
628          position of the fourth operand, and the second operand
629          becomes NULL.  */
630       dump_child ("init", TREE_OPERAND (t, 3));
631       break;
632
633     case CASE_LABEL_EXPR:
634       dump_child ("name", CASE_LABEL (t));
635       if (CASE_LOW (t)) {
636         dump_child ("low ", CASE_LOW (t));
637         if (CASE_HIGH (t)) {
638           dump_child ("high", CASE_HIGH (t));
639         }
640       }
641       break;
642     case LABEL_EXPR:
643       dump_child ("name", TREE_OPERAND (t,0));
644       break;
645     case GOTO_EXPR:
646       dump_child ("labl", TREE_OPERAND (t, 0));
647       break;
648     case SWITCH_EXPR:
649       dump_child ("cond", TREE_OPERAND (t, 0));
650       dump_child ("body", TREE_OPERAND (t, 1));
651       if (TREE_OPERAND (t, 2))
652         {
653           dump_child ("labl", TREE_OPERAND (t,2));
654         }
655       break;
656     case OMP_CLAUSE:
657       {
658         int i;
659         fprintf (di->stream, "%s\n", omp_clause_code_name[OMP_CLAUSE_CODE (t)]);
660         for (i = 0; i < omp_clause_num_ops[OMP_CLAUSE_CODE (t)]; i++)
661           dump_child ("op: ", OMP_CLAUSE_OPERAND (t, i));
662       }
663       break;
664     default:
665       /* There are no additional fields to print.  */
666       break;
667     }
668
669  done:
670   if (dump_flag (di, TDF_ADDRESS, NULL))
671     dump_pointer (di, "addr", (void *)t);
672
673   /* Terminate the line.  */
674   fprintf (di->stream, "\n");
675 }
676
677 /* Return nonzero if FLAG has been specified for the dump, and NODE
678    is not the root node of the dump.  */
679
680 int dump_flag (dump_info_p di, int flag, tree node)
681 {
682   return (di->flags & flag) && (node != di->node);
683 }
684
685 /* Dump T, and all its children, on STREAM.  */
686
687 void
688 dump_node (tree t, int flags, FILE *stream)
689 {
690   struct dump_info di;
691   dump_queue_p dq;
692   dump_queue_p next_dq;
693
694   /* Initialize the dump-information structure.  */
695   di.stream = stream;
696   di.index = 0;
697   di.column = 0;
698   di.queue = 0;
699   di.queue_end = 0;
700   di.free_list = 0;
701   di.flags = flags;
702   di.node = t;
703   di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
704                              (splay_tree_delete_value_fn) &free);
705
706   /* Queue up the first node.  */
707   queue (&di, t, DUMP_NONE);
708
709   /* Until the queue is empty, keep dumping nodes.  */
710   while (di.queue)
711     dequeue_and_dump (&di);
712
713   /* Now, clean up.  */
714   for (dq = di.free_list; dq; dq = next_dq)
715     {
716       next_dq = dq->next;
717       free (dq);
718     }
719   splay_tree_delete (di.nodes);
720 }
721 \f
722
723 /* Table of tree dump switches. This must be consistent with the
724    TREE_DUMP_INDEX enumeration in tree.h.  */
725 static struct dump_file_info dump_files[TDI_end] =
726 {
727   {NULL, NULL, NULL, 0, 0, 0, 0},
728   {".cgraph", "ipa-cgraph", NULL, TDF_IPA, 0,  0, 0},
729   {".tu", "translation-unit", NULL, TDF_TREE, 0, 1, 0},
730   {".class", "class-hierarchy", NULL, TDF_TREE, 0, 2, 0},
731   {".original", "tree-original", NULL, TDF_TREE, 0, 3, 0},
732   {".gimple", "tree-gimple", NULL, TDF_TREE, 0, 4, 0},
733   {".nested", "tree-nested", NULL, TDF_TREE, 0, 5, 0},
734   {".inlined", "tree-inlined", NULL, TDF_TREE, 0, 6, 0},
735   {".vcg", "tree-vcg", NULL, TDF_TREE, 0, 7, 0},
736 #define FIRST_AUTO_NUMBERED_DUMP 8
737
738   {NULL, "tree-all", NULL, TDF_TREE, 0, 0, 0},
739   {NULL, "rtl-all", NULL, TDF_RTL, 0, 0, 0},
740   {NULL, "ipa-all", NULL, TDF_IPA, 0, 0, 0},
741 };
742
743 /* Dynamically registered tree dump files and switches.  */
744 static struct dump_file_info *extra_dump_files;
745 static size_t extra_dump_files_in_use;
746 static size_t extra_dump_files_alloced;
747
748 /* Define a name->number mapping for a dump flag value.  */
749 struct dump_option_value_info
750 {
751   const char *const name;       /* the name of the value */
752   const int value;              /* the value of the name */
753 };
754
755 /* Table of dump options. This must be consistent with the TDF_* flags
756    in tree.h */
757 static const struct dump_option_value_info dump_options[] =
758 {
759   {"address", TDF_ADDRESS},
760   {"slim", TDF_SLIM},
761   {"raw", TDF_RAW},
762   {"details", TDF_DETAILS},
763   {"stats", TDF_STATS},
764   {"blocks", TDF_BLOCKS},
765   {"vops", TDF_VOPS},
766   {"lineno", TDF_LINENO},
767   {"uid", TDF_UID},
768   {"stmtaddr", TDF_STMTADDR},
769   {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA 
770             | TDF_STMTADDR | TDF_GRAPH)},
771   {NULL, 0}
772 };
773
774 unsigned int
775 dump_register (const char *suffix, const char *swtch, const char *glob,
776                int flags, int letter)
777 {
778   static int next_dump = FIRST_AUTO_NUMBERED_DUMP;
779   int num = next_dump++;
780
781   size_t this = extra_dump_files_in_use++;
782
783   if (this >= extra_dump_files_alloced)
784     {
785       if (extra_dump_files_alloced == 0)
786         extra_dump_files_alloced = 32;
787       else
788         extra_dump_files_alloced *= 2;
789       extra_dump_files = xrealloc (extra_dump_files,
790                                    sizeof (struct dump_file_info)
791                                    * extra_dump_files_alloced);
792     }
793
794   memset (&extra_dump_files[this], 0, sizeof (struct dump_file_info));
795   extra_dump_files[this].suffix = suffix;
796   extra_dump_files[this].swtch = swtch;
797   extra_dump_files[this].glob = glob;
798   extra_dump_files[this].flags = flags;
799   extra_dump_files[this].num = num;
800   extra_dump_files[this].letter = letter;
801
802   return this + TDI_end;
803 }
804
805
806 /* Return the dump_file_info for the given phase.  */
807
808 struct dump_file_info *
809 get_dump_file_info (enum tree_dump_index phase)
810 {
811   if (phase < TDI_end)
812     return &dump_files[phase];
813   else if (phase - TDI_end >= extra_dump_files_in_use)
814     return NULL;
815   else
816     return extra_dump_files + (phase - TDI_end);
817 }
818
819
820 /* Return the name of the dump file for the given phase.
821    If the dump is not enabled, returns NULL.  */
822
823 char *
824 get_dump_file_name (enum tree_dump_index phase)
825 {
826   char dump_id[10];
827   struct dump_file_info *dfi;
828
829   if (phase == TDI_none)
830     return NULL;
831
832   dfi = get_dump_file_info (phase);
833   if (dfi->state == 0)
834     return NULL;
835
836   if (dfi->num < 0)
837     dump_id[0] = '\0';
838   else
839     {
840       char suffix;
841       if (dfi->flags & TDF_TREE)
842         suffix = 't';
843       else if (dfi->flags & TDF_IPA)
844         suffix = 'i';
845       else
846         suffix = 'r';
847
848       if (snprintf (dump_id, sizeof (dump_id), ".%03d%c", dfi->num, suffix) < 0)
849         dump_id[0] = '\0';
850     }
851
852   return concat (dump_base_name, dump_id, dfi->suffix, NULL);
853 }
854
855 /* Begin a tree dump for PHASE. Stores any user supplied flag in
856    *FLAG_PTR and returns a stream to write to. If the dump is not
857    enabled, returns NULL.
858    Multiple calls will reopen and append to the dump file.  */
859
860 FILE *
861 dump_begin (enum tree_dump_index phase, int *flag_ptr)
862 {
863   char *name;
864   struct dump_file_info *dfi;
865   FILE *stream;
866
867   if (phase == TDI_none || !dump_enabled_p (phase))
868     return NULL;
869
870   name = get_dump_file_name (phase);
871   dfi = get_dump_file_info (phase);
872   stream = fopen (name, dfi->state < 0 ? "w" : "a");
873   if (!stream)
874     error ("could not open dump file %qs: %s", name, strerror (errno));
875   else
876     dfi->state = 1;
877   free (name);
878
879   if (flag_ptr)
880     *flag_ptr = dfi->flags;
881
882   return stream;
883 }
884
885 /* Returns nonzero if tree dump PHASE is enabled.  If PHASE is
886    TDI_tree_all, return nonzero if any dump is enabled.  */
887
888 int
889 dump_enabled_p (enum tree_dump_index phase)
890 {
891   if (phase == TDI_tree_all)
892     {
893       size_t i;
894       for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
895         if (dump_files[i].state)
896           return 1;
897       for (i = 0; i < extra_dump_files_in_use; i++)
898         if (extra_dump_files[i].state)
899           return 1;
900       return 0;
901     }
902   else
903     {
904       struct dump_file_info *dfi = get_dump_file_info (phase);
905       return dfi->state;
906     }
907 }
908
909 /* Returns nonzero if tree dump PHASE has been initialized.  */
910
911 int
912 dump_initialized_p (enum tree_dump_index phase)
913 {
914   struct dump_file_info *dfi = get_dump_file_info (phase);
915   return dfi->state > 0;
916 }
917
918 /* Returns the switch name of PHASE.  */
919
920 const char *
921 dump_flag_name (enum tree_dump_index phase)
922 {
923   struct dump_file_info *dfi = get_dump_file_info (phase);
924   return dfi->swtch;
925 }
926
927 /* Finish a tree dump for PHASE. STREAM is the stream created by
928    dump_begin.  */
929
930 void
931 dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
932 {
933   fclose (stream);
934 }
935
936 /* Enable all tree dumps.  Return number of enabled tree dumps.  */
937
938 static int
939 dump_enable_all (int flags, int letter)
940 {
941   int ir_type = (flags & (TDF_TREE | TDF_RTL | TDF_IPA));
942   int n = 0;
943   size_t i;
944
945   for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
946     if ((dump_files[i].flags & ir_type)
947         && (letter == 0 || letter == dump_files[i].letter))
948       {
949         dump_files[i].state = -1;
950         dump_files[i].flags |= flags;
951         n++;
952       }
953
954   for (i = 0; i < extra_dump_files_in_use; i++)
955     if ((extra_dump_files[i].flags & ir_type)
956         && (letter == 0 || letter == extra_dump_files[i].letter))
957       {
958         extra_dump_files[i].state = -1;
959         extra_dump_files[i].flags |= flags;
960         n++;
961       }
962
963   return n;
964 }
965
966 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
967    relevant details in the dump_files array.  */
968
969 static int
970 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
971 {
972   const char *option_value;
973   const char *ptr;
974   int flags;
975   
976   if (doglob && !dfi->glob)
977     return 0;
978
979   option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
980   if (!option_value)
981     return 0;
982
983   ptr = option_value;
984   flags = 0;
985
986   while (*ptr)
987     {
988       const struct dump_option_value_info *option_ptr;
989       const char *end_ptr;
990       unsigned length;
991
992       while (*ptr == '-')
993         ptr++;
994       end_ptr = strchr (ptr, '-');
995       if (!end_ptr)
996         end_ptr = ptr + strlen (ptr);
997       length = end_ptr - ptr;
998
999       for (option_ptr = dump_options; option_ptr->name; option_ptr++)
1000         if (strlen (option_ptr->name) == length
1001             && !memcmp (option_ptr->name, ptr, length))
1002           {
1003             flags |= option_ptr->value;
1004             goto found;
1005           }
1006       warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
1007                length, ptr, dfi->swtch);
1008     found:;
1009       ptr = end_ptr;
1010     }
1011
1012   dfi->state = -1;
1013   dfi->flags |= flags;
1014
1015   /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
1016      known dumps.  */
1017   if (dfi->suffix == NULL)
1018     dump_enable_all (dfi->flags, 0);
1019
1020   return 1;
1021 }
1022
1023 int
1024 dump_switch_p (const char *arg)
1025 {
1026   size_t i;
1027   int any = 0;
1028
1029   for (i = TDI_none + 1; i != TDI_end; i++)
1030     any |= dump_switch_p_1 (arg, &dump_files[i], false);
1031
1032   /* Don't glob if we got a hit already */
1033   if (!any)
1034     for (i = TDI_none + 1; i != TDI_end; i++)
1035       any |= dump_switch_p_1 (arg, &dump_files[i], true);
1036
1037   for (i = 0; i < extra_dump_files_in_use; i++)
1038     any |= dump_switch_p_1 (arg, &extra_dump_files[i], false);
1039   
1040   if (!any)
1041     for (i = 0; i < extra_dump_files_in_use; i++)
1042       any |= dump_switch_p_1 (arg, &extra_dump_files[i], true);
1043
1044
1045   return any;
1046 }
1047
1048 /* Dump FUNCTION_DECL FN as tree dump PHASE.  */
1049
1050 void
1051 dump_function (enum tree_dump_index phase, tree fn)
1052 {
1053   FILE *stream;
1054   int flags;
1055
1056   stream = dump_begin (phase, &flags);
1057   if (stream)
1058     {
1059       dump_function_to_file (fn, stream, flags);
1060       dump_end (phase, stream);
1061     }
1062 }
1063
1064 bool
1065 enable_rtl_dump_file (int letter)
1066 {
1067   if (letter == 'a')
1068     letter = 0;
1069
1070   return dump_enable_all (TDF_RTL, letter) > 0;
1071 }
1072
1073