]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/tree-dump.c
Revert:
[thirdparty/gcc.git] / gcc / tree-dump.c
CommitLineData
74338ff6 1/* Tree-dumping functionality for intermediate representation.
dc24ddbd 2 Copyright (C) 1999, 2000, 2002, 2003, 2004 Free Software Foundation, Inc.
74338ff6 3 Written by Mark Mitchell <mark@codesourcery.com>
4
5This file is part of GCC.
6
7GCC is free software; you can redistribute it and/or modify it under
8the terms of the GNU General Public License as published by the Free
9Software Foundation; either version 2, or (at your option) any later
10version.
11
12GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13WARRANTY; without even the implied warranty of MERCHANTABILITY or
14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15for more details.
16
17You should have received a copy of the GNU General Public License
18along with GCC; see the file COPYING. If not, write to the Free
19Software Foundation, 59 Temple Place - Suite 330, Boston, MA
2002111-1307, USA. */
21
22#include "config.h"
23#include "system.h"
805e22b2 24#include "coretypes.h"
25#include "tm.h"
74338ff6 26#include "tree.h"
74338ff6 27#include "splay-tree.h"
28#include "diagnostic.h"
29#include "toplev.h"
3119c950 30#include "tree-dump.h"
74338ff6 31#include "langhooks.h"
e8c5dd3c 32#include "tree-iterator.h"
74338ff6 33
d598ad0d 34static unsigned int queue (dump_info_p, tree, int);
35static void dump_index (dump_info_p, unsigned int);
36static void dequeue_and_dump (dump_info_p);
37static void dump_new_line (dump_info_p);
38static void dump_maybe_newline (dump_info_p);
39static void dump_string_field (dump_info_p, const char *, const char *);
4ee9c684 40static void dump_enable_all (int);
74338ff6 41
42/* Add T to the end of the queue of nodes to dump. Returns the index
43 assigned to T. */
44
45static unsigned int
d598ad0d 46queue (dump_info_p di, tree t, int flags)
74338ff6 47{
48 dump_queue_p dq;
49 dump_node_info_p dni;
50 unsigned int index;
51
52 /* Assign the next available index to T. */
53 index = ++di->index;
54
55 /* Obtain a new queue node. */
56 if (di->free_list)
57 {
58 dq = di->free_list;
59 di->free_list = dq->next;
60 }
61 else
f0af5a88 62 dq = xmalloc (sizeof (struct dump_queue));
74338ff6 63
64 /* Create a new entry in the splay-tree. */
f0af5a88 65 dni = xmalloc (sizeof (struct dump_node_info));
74338ff6 66 dni->index = index;
67 dni->binfo_p = ((flags & DUMP_BINFO) != 0);
40570cc2 68 dq->node = splay_tree_insert (di->nodes, (splay_tree_key) t,
74338ff6 69 (splay_tree_value) dni);
70
71 /* Add it to the end of the queue. */
72 dq->next = 0;
73 if (!di->queue_end)
74 di->queue = dq;
75 else
76 di->queue_end->next = dq;
77 di->queue_end = dq;
78
79 /* Return the index. */
80 return index;
81}
82
83static void
d598ad0d 84dump_index (dump_info_p di, unsigned int index)
74338ff6 85{
86 fprintf (di->stream, "@%-6u ", index);
87 di->column += 8;
88}
89
90/* If T has not already been output, queue it for subsequent output.
91 FIELD is a string to print before printing the index. Then, the
92 index of T is printed. */
93
94void
d598ad0d 95queue_and_dump_index (dump_info_p di, const char *field, tree t, int flags)
74338ff6 96{
97 unsigned int index;
98 splay_tree_node n;
99
100 /* If there's no node, just return. This makes for fewer checks in
101 our callers. */
102 if (!t)
103 return;
104
105 /* See if we've already queued or dumped this node. */
106 n = splay_tree_lookup (di->nodes, (splay_tree_key) t);
107 if (n)
108 index = ((dump_node_info_p) n->value)->index;
109 else
110 /* If we haven't, add it to the queue. */
111 index = queue (di, t, flags);
112
113 /* Print the index of the node. */
114 dump_maybe_newline (di);
115 fprintf (di->stream, "%-4s: ", field);
116 di->column += 6;
117 dump_index (di, index);
118}
119
120/* Dump the type of T. */
121
122void
d598ad0d 123queue_and_dump_type (dump_info_p di, tree t)
74338ff6 124{
125 queue_and_dump_index (di, "type", TREE_TYPE (t), DUMP_NONE);
126}
127
128/* Dump column control */
129#define SOL_COLUMN 25 /* Start of line column. */
130#define EOL_COLUMN 55 /* End of line column. */
131#define COLUMN_ALIGNMENT 15 /* Alignment. */
132
133/* Insert a new line in the dump output, and indent to an appropriate
134 place to start printing more fields. */
135
136static void
d598ad0d 137dump_new_line (dump_info_p di)
74338ff6 138{
139 fprintf (di->stream, "\n%*s", SOL_COLUMN, "");
140 di->column = SOL_COLUMN;
141}
142
143/* If necessary, insert a new line. */
144
145static void
d598ad0d 146dump_maybe_newline (dump_info_p di)
74338ff6 147{
148 int extra;
40570cc2 149
74338ff6 150 /* See if we need a new line. */
151 if (di->column > EOL_COLUMN)
152 dump_new_line (di);
153 /* See if we need any padding. */
154 else if ((extra = (di->column - SOL_COLUMN) % COLUMN_ALIGNMENT) != 0)
155 {
156 fprintf (di->stream, "%*s", COLUMN_ALIGNMENT - extra, "");
157 di->column += COLUMN_ALIGNMENT - extra;
158 }
159}
160
161/* Dump pointer PTR using FIELD to identify it. */
162
163void
d598ad0d 164dump_pointer (dump_info_p di, const char *field, void *ptr)
74338ff6 165{
166 dump_maybe_newline (di);
167 fprintf (di->stream, "%-4s: %-8lx ", field, (long) ptr);
168 di->column += 15;
169}
170
171/* Dump integer I using FIELD to identify it. */
172
173void
d598ad0d 174dump_int (dump_info_p di, const char *field, int i)
74338ff6 175{
176 dump_maybe_newline (di);
177 fprintf (di->stream, "%-4s: %-7d ", field, i);
178 di->column += 14;
179}
180
181/* Dump the string S. */
182
183void
d598ad0d 184dump_string (dump_info_p di, const char *string)
74338ff6 185{
186 dump_maybe_newline (di);
187 fprintf (di->stream, "%-13s ", string);
188 if (strlen (string) > 13)
189 di->column += strlen (string) + 1;
190 else
191 di->column += 14;
192}
193
194/* Dump the string field S. */
195
196static void
d598ad0d 197dump_string_field (dump_info_p di, const char *field, const char *string)
74338ff6 198{
199 dump_maybe_newline (di);
200 fprintf (di->stream, "%-4s: %-7s ", field, string);
201 if (strlen (string) > 7)
202 di->column += 6 + strlen (string) + 1;
203 else
204 di->column += 14;
205}
206
74338ff6 207/* Dump the next node in the queue. */
208
40570cc2 209static void
d598ad0d 210dequeue_and_dump (dump_info_p di)
74338ff6 211{
212 dump_queue_p dq;
213 splay_tree_node stn;
214 dump_node_info_p dni;
215 tree t;
216 unsigned int index;
217 enum tree_code code;
218 char code_class;
219 const char* code_name;
220
221 /* Get the next node from the queue. */
222 dq = di->queue;
223 stn = dq->node;
224 t = (tree) stn->key;
225 dni = (dump_node_info_p) stn->value;
226 index = dni->index;
227
228 /* Remove the node from the queue, and put it on the free list. */
229 di->queue = dq->next;
230 if (!di->queue)
231 di->queue_end = 0;
232 dq->next = di->free_list;
233 di->free_list = dq;
234
235 /* Print the node index. */
236 dump_index (di, index);
237 /* And the type of node this is. */
238 if (dni->binfo_p)
239 code_name = "binfo";
240 else
241 code_name = tree_code_name[(int) TREE_CODE (t)];
242 fprintf (di->stream, "%-16s ", code_name);
243 di->column = 25;
244
245 /* Figure out what kind of node this is. */
246 code = TREE_CODE (t);
247 code_class = TREE_CODE_CLASS (code);
248
249 /* Although BINFOs are TREE_VECs, we dump them specially so as to be
250 more informative. */
251 if (dni->binfo_p)
252 {
95f3173a 253 unsigned ix;
254 tree bases = BINFO_BASETYPES (t);
255 unsigned n_bases = bases ? TREE_VEC_LENGTH (bases): 0;
256 tree accesses = BINFO_BASEACCESSES (t);
d598ad0d 257
95f3173a 258 dump_child ("type", BINFO_TYPE (t));
259
74338ff6 260 if (TREE_VIA_VIRTUAL (t))
261 dump_string (di, "virt");
40570cc2 262
95f3173a 263 dump_int (di, "bases", n_bases);
264 for (ix = 0; ix != n_bases; ix++)
265 {
266 tree base = TREE_VEC_ELT (bases, ix);
267 tree access = (accesses ? TREE_VEC_ELT (accesses, ix)
268 : access_public_node);
269 const char *string = NULL;
270
271 if (access == access_public_node)
272 string = "pub";
273 else if (access == access_protected_node)
274 string = "prot";
275 else if (access == access_private_node)
276 string = "priv";
277 else
278 abort ();
d598ad0d 279
95f3173a 280 dump_string (di, string);
281 queue_and_dump_index (di, "binf", base, DUMP_BINFO);
282 }
d598ad0d 283
74338ff6 284 goto done;
285 }
286
287 /* We can knock off a bunch of expression nodes in exactly the same
288 way. */
289 if (IS_EXPR_CODE_CLASS (code_class))
290 {
291 /* If we're dumping children, dump them now. */
292 queue_and_dump_type (di, t);
293
294 switch (code_class)
295 {
296 case '1':
297 dump_child ("op 0", TREE_OPERAND (t, 0));
298 break;
40570cc2 299
74338ff6 300 case '2':
301 case '<':
302 dump_child ("op 0", TREE_OPERAND (t, 0));
303 dump_child ("op 1", TREE_OPERAND (t, 1));
304 break;
40570cc2 305
74338ff6 306 case 'e':
d91287a4 307 case 'r':
308 case 's':
74338ff6 309 /* These nodes are handled explicitly below. */
310 break;
40570cc2 311
74338ff6 312 default:
ac0c7fb1 313 abort ();
74338ff6 314 }
315 }
316 else if (DECL_P (t))
317 {
2ed8b5d0 318 expanded_location xloc;
74338ff6 319 /* All declarations have names. */
320 if (DECL_NAME (t))
321 dump_child ("name", DECL_NAME (t));
40570cc2 322 if (DECL_ASSEMBLER_NAME_SET_P (t)
74338ff6 323 && DECL_ASSEMBLER_NAME (t) != DECL_NAME (t))
324 dump_child ("mngl", DECL_ASSEMBLER_NAME (t));
325 /* And types. */
326 queue_and_dump_type (di, t);
327 dump_child ("scpe", DECL_CONTEXT (t));
328 /* And a source position. */
2ed8b5d0 329 xloc = expand_location (DECL_SOURCE_LOCATION (t));
330 if (xloc.file)
74338ff6 331 {
2ed8b5d0 332 const char *filename = strrchr (xloc.file, '/');
74338ff6 333 if (!filename)
2ed8b5d0 334 filename = xloc.file;
74338ff6 335 else
336 /* Skip the slash. */
337 ++filename;
338
339 dump_maybe_newline (di);
40570cc2 340 fprintf (di->stream, "srcp: %s:%-6d ", filename,
2ed8b5d0 341 xloc.line);
74338ff6 342 di->column += 6 + strlen (filename) + 8;
343 }
344 /* And any declaration can be compiler-generated. */
345 if (DECL_ARTIFICIAL (t))
346 dump_string (di, "artificial");
347 if (TREE_CHAIN (t) && !dump_flag (di, TDF_SLIM, NULL))
348 dump_child ("chan", TREE_CHAIN (t));
349 }
350 else if (code_class == 't')
351 {
352 /* All types have qualifiers. */
dc24ddbd 353 int quals = lang_hooks.tree_dump.type_quals (t);
40570cc2 354
74338ff6 355 if (quals != TYPE_UNQUALIFIED)
356 {
357 fprintf (di->stream, "qual: %c%c%c ",
358 (quals & TYPE_QUAL_CONST) ? 'c' : ' ',
359 (quals & TYPE_QUAL_VOLATILE) ? 'v' : ' ',
360 (quals & TYPE_QUAL_RESTRICT) ? 'r' : ' ');
361 di->column += 14;
362 }
363
364 /* All types have associated declarations. */
365 dump_child ("name", TYPE_NAME (t));
366
367 /* All types have a main variant. */
368 if (TYPE_MAIN_VARIANT (t) != t)
369 dump_child ("unql", TYPE_MAIN_VARIANT (t));
40570cc2 370
74338ff6 371 /* And sizes. */
372 dump_child ("size", TYPE_SIZE (t));
373
374 /* All types have alignments. */
375 dump_int (di, "algn", TYPE_ALIGN (t));
376 }
377 else if (code_class == 'c')
378 /* All constants can have types. */
379 queue_and_dump_type (di, t);
380
381 /* Give the language-specific code a chance to print something. If
382 it's completely taken care of things, don't bother printing
383 anything more ourselves. */
dc24ddbd 384 if (lang_hooks.tree_dump.dump_tree (di, t))
74338ff6 385 goto done;
386
387 /* Now handle the various kinds of nodes. */
388 switch (code)
389 {
390 int i;
391
392 case IDENTIFIER_NODE:
393 dump_string_field (di, "strg", IDENTIFIER_POINTER (t));
394 dump_int (di, "lngt", IDENTIFIER_LENGTH (t));
395 break;
396
397 case TREE_LIST:
398 dump_child ("purp", TREE_PURPOSE (t));
399 dump_child ("valu", TREE_VALUE (t));
400 dump_child ("chan", TREE_CHAIN (t));
401 break;
402
e8c5dd3c 403 case STATEMENT_LIST:
404 {
405 tree_stmt_iterator it;
406 for (i = 0, it = tsi_start (t); !tsi_end_p (it); tsi_next (&it), i++)
407 {
408 char buffer[32];
409 sprintf (buffer, "%u", i);
410 dump_child (buffer, tsi_stmt (it));
411 }
412 }
413 break;
414
74338ff6 415 case TREE_VEC:
416 dump_int (di, "lngt", TREE_VEC_LENGTH (t));
417 for (i = 0; i < TREE_VEC_LENGTH (t); ++i)
418 {
419 char buffer[32];
420 sprintf (buffer, "%u", i);
421 dump_child (buffer, TREE_VEC_ELT (t, i));
422 }
423 break;
424
425 case INTEGER_TYPE:
426 case ENUMERAL_TYPE:
427 dump_int (di, "prec", TYPE_PRECISION (t));
78a8ed03 428 if (TYPE_UNSIGNED (t))
74338ff6 429 dump_string (di, "unsigned");
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 (di, "struct");
467 else
468 dump_string (di, "union");
40570cc2 469
74338ff6 470 dump_child ("flds", TYPE_FIELDS (t));
471 dump_child ("fncs", TYPE_METHODS (t));
40570cc2 472 queue_and_dump_index (di, "binf", TYPE_BINFO (t),
74338ff6 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 {
74338ff6 493 if (DECL_FIELD_OFFSET (t))
494 dump_child ("bpos", bit_position (t));
495 }
40570cc2 496 else if (TREE_CODE (t) == VAR_DECL
74338ff6 497 || TREE_CODE (t) == PARM_DECL)
498 {
499 dump_int (di, "used", TREE_USED (t));
500 if (DECL_REGISTER (t))
501 dump_string (di, "register");
502 }
503 break;
504
505 case FUNCTION_DECL:
506 dump_child ("args", DECL_ARGUMENTS (t));
507 if (DECL_EXTERNAL (t))
508 dump_string (di, "undefined");
509 if (TREE_PUBLIC (t))
510 dump_string (di, "extern");
511 else
512 dump_string (di, "static");
513 if (DECL_LANG_SPECIFIC (t) && !dump_flag (di, TDF_SLIM, t))
514 dump_child ("body", DECL_SAVED_TREE (t));
515 break;
516
74338ff6 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 CLEANUP_POINT_EXPR:
532 case SAVE_EXPR:
b25de375 533 case REALPART_EXPR:
534 case IMAGPART_EXPR:
74338ff6 535 /* These nodes are unary, but do not have code class `1'. */
536 dump_child ("op 0", TREE_OPERAND (t, 0));
537 break;
538
539 case TRUTH_ANDIF_EXPR:
540 case TRUTH_ORIF_EXPR:
541 case INIT_EXPR:
542 case MODIFY_EXPR:
74338ff6 543 case COMPOUND_EXPR:
74338ff6 544 case PREDECREMENT_EXPR:
545 case PREINCREMENT_EXPR:
546 case POSTDECREMENT_EXPR:
547 case POSTINCREMENT_EXPR:
548 /* These nodes are binary, but do not have code class `2'. */
549 dump_child ("op 0", TREE_OPERAND (t, 0));
550 dump_child ("op 1", TREE_OPERAND (t, 1));
551 break;
552
6374121b 553 case COMPONENT_REF:
554 dump_child ("op 0", TREE_OPERAND (t, 0));
555 dump_child ("op 1", TREE_OPERAND (t, 1));
556 dump_child ("op 2", TREE_OPERAND (t, 2));
557 break;
558
559 case ARRAY_REF:
560 case ARRAY_RANGE_REF:
561 dump_child ("op 0", TREE_OPERAND (t, 0));
562 dump_child ("op 1", TREE_OPERAND (t, 1));
563 dump_child ("op 2", TREE_OPERAND (t, 2));
564 dump_child ("op 3", TREE_OPERAND (t, 3));
565 break;
566
74338ff6 567 case COND_EXPR:
568 dump_child ("op 0", TREE_OPERAND (t, 0));
569 dump_child ("op 1", TREE_OPERAND (t, 1));
570 dump_child ("op 2", TREE_OPERAND (t, 2));
571 break;
572
573 case CALL_EXPR:
574 dump_child ("fn", TREE_OPERAND (t, 0));
575 dump_child ("args", TREE_OPERAND (t, 1));
576 break;
577
578 case CONSTRUCTOR:
3ad60ec8 579 dump_child ("elts", CONSTRUCTOR_ELTS (t));
74338ff6 580 break;
581
74338ff6 582 case BIND_EXPR:
583 dump_child ("vars", TREE_OPERAND (t, 0));
584 dump_child ("body", TREE_OPERAND (t, 1));
585 break;
586
587 case LOOP_EXPR:
588 dump_child ("body", TREE_OPERAND (t, 0));
589 break;
590
591 case EXIT_EXPR:
592 dump_child ("cond", TREE_OPERAND (t, 0));
593 break;
594
595 case TARGET_EXPR:
596 dump_child ("decl", TREE_OPERAND (t, 0));
597 dump_child ("init", TREE_OPERAND (t, 1));
598 dump_child ("clnp", TREE_OPERAND (t, 2));
599 /* There really are two possible places the initializer can be.
600 After RTL expansion, the second operand is moved to the
601 position of the fourth operand, and the second operand
602 becomes NULL. */
603 dump_child ("init", TREE_OPERAND (t, 3));
604 break;
40570cc2 605
74338ff6 606 default:
607 /* There are no additional fields to print. */
608 break;
609 }
610
611 done:
612 if (dump_flag (di, TDF_ADDRESS, NULL))
613 dump_pointer (di, "addr", (void *)t);
40570cc2 614
74338ff6 615 /* Terminate the line. */
616 fprintf (di->stream, "\n");
617}
618
f712a0dc 619/* Return nonzero if FLAG has been specified for the dump, and NODE
74338ff6 620 is not the root node of the dump. */
621
d598ad0d 622int dump_flag (dump_info_p di, int flag, tree node)
74338ff6 623{
624 return (di->flags & flag) && (node != di->node);
625}
626
627/* Dump T, and all its children, on STREAM. */
628
629void
d598ad0d 630dump_node (tree t, int flags, FILE *stream)
74338ff6 631{
632 struct dump_info di;
633 dump_queue_p dq;
634 dump_queue_p next_dq;
635
636 /* Initialize the dump-information structure. */
637 di.stream = stream;
638 di.index = 0;
639 di.column = 0;
640 di.queue = 0;
641 di.queue_end = 0;
642 di.free_list = 0;
643 di.flags = flags;
644 di.node = t;
40570cc2 645 di.nodes = splay_tree_new (splay_tree_compare_pointers, 0,
74338ff6 646 (splay_tree_delete_value_fn) &free);
647
648 /* Queue up the first node. */
649 queue (&di, t, DUMP_NONE);
650
651 /* Until the queue is empty, keep dumping nodes. */
652 while (di.queue)
653 dequeue_and_dump (&di);
654
655 /* Now, clean up. */
656 for (dq = di.free_list; dq; dq = next_dq)
657 {
658 next_dq = dq->next;
659 free (dq);
660 }
661 splay_tree_delete (di.nodes);
662}
663
664/* Define a tree dump switch. */
665struct dump_file_info
666{
4ee9c684 667 const char *suffix; /* suffix to give output file. */
668 const char *swtch; /* command line switch */
74338ff6 669 int flags; /* user flags */
670 int state; /* state of play */
671};
672
673/* Table of tree dump switches. This must be consistent with the
674 TREE_DUMP_INDEX enumeration in tree.h */
675static struct dump_file_info dump_files[TDI_end] =
676{
4ee9c684 677 {NULL, NULL, 0, 0},
ffbc8512 678 {".tu", "translation-unit", 0, 0},
679 {".class", "class-hierarchy", 0, 0},
680 {".original", "tree-original", 0, 0},
4ee9c684 681 {".generic", "tree-generic", 0, 0},
682 {".nested", "tree-nested", 0, 0},
ffbc8512 683 {".inlined", "tree-inlined", 0, 0},
4ee9c684 684 {".vcg", "tree-vcg", 0, 0},
685 {".xml", "call-graph", 0, 0},
686 {NULL, "tree-all", 0, 0},
74338ff6 687};
688
4ee9c684 689/* Dynamically registered tree dump files and switches. */
690static struct dump_file_info *extra_dump_files;
691static size_t extra_dump_files_in_use;
692static size_t extra_dump_files_alloced;
693
74338ff6 694/* Define a name->number mapping for a dump flag value. */
695struct dump_option_value_info
696{
697 const char *const name; /* the name of the value */
698 const int value; /* the value of the name */
699};
700
701/* Table of dump options. This must be consistent with the TDF_* flags
702 in tree.h */
703static const struct dump_option_value_info dump_options[] =
704{
705 {"address", TDF_ADDRESS},
706 {"slim", TDF_SLIM},
4ee9c684 707 {"raw", TDF_RAW},
708 {"details", TDF_DETAILS},
709 {"stats", TDF_STATS},
710 {"blocks", TDF_BLOCKS},
711 {"vops", TDF_VOPS},
712 {"lineno", TDF_LINENO},
713 {"uid", TDF_UID},
714 {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO)},
74338ff6 715 {NULL, 0}
716};
717
4ee9c684 718unsigned int
719dump_register (const char *suffix, const char *swtch)
720{
721 size_t this = extra_dump_files_in_use++;
722
723 if (this >= extra_dump_files_alloced)
724 {
725 if (extra_dump_files_alloced == 0)
726 extra_dump_files_alloced = 32;
727 else
728 extra_dump_files_alloced *= 2;
729 extra_dump_files = xrealloc (extra_dump_files,
730 sizeof (struct dump_file_info)
731 * extra_dump_files_alloced);
732 }
733
734 memset (&extra_dump_files[this], 0, sizeof (struct dump_file_info));
735 extra_dump_files[this].suffix = suffix;
736 extra_dump_files[this].swtch = swtch;
737
738 return this + TDI_end;
739}
740
741/* Return the dump_file_info for the given phase. */
742
743static struct dump_file_info *
744get_dump_file_info (enum tree_dump_index phase)
745{
746 if (phase < TDI_end)
747 return &dump_files[phase];
748 else if (phase - TDI_end >= extra_dump_files_in_use)
749 abort ();
750 else
751 return extra_dump_files + (phase - TDI_end);
752}
753
754
74338ff6 755/* Begin a tree dump for PHASE. Stores any user supplied flag in
756 *FLAG_PTR and returns a stream to write to. If the dump is not
757 enabled, returns NULL.
758 Multiple calls will reopen and append to the dump file. */
759
760FILE *
d598ad0d 761dump_begin (enum tree_dump_index phase, int *flag_ptr)
74338ff6 762{
763 FILE *stream;
764 char *name;
4ee9c684 765 char dump_id[10];
766 struct dump_file_info *dfi;
40570cc2 767
4ee9c684 768 if (phase == TDI_none)
74338ff6 769 return NULL;
40570cc2 770
4ee9c684 771 dfi = get_dump_file_info (phase);
772 if (dfi->state == 0)
773 return NULL;
774
775 if (snprintf (dump_id, sizeof (dump_id), ".t%02d", phase) < 0)
776 dump_id[0] = '\0';
777
778 name = concat (dump_base_name, dump_id, dfi->suffix, NULL);
779 stream = fopen (name, dfi->state < 0 ? "w" : "a");
74338ff6 780 if (!stream)
4ee9c684 781 error ("could not open dump file `%s': %s", name, strerror (errno));
74338ff6 782 else
4ee9c684 783 dfi->state = 1;
74338ff6 784 free (name);
4ee9c684 785
74338ff6 786 if (flag_ptr)
4ee9c684 787 *flag_ptr = dfi->flags;
40570cc2 788
74338ff6 789 return stream;
790}
791
f712a0dc 792/* Returns nonzero if tree dump PHASE is enabled. */
74338ff6 793
794int
d598ad0d 795dump_enabled_p (enum tree_dump_index phase)
74338ff6 796{
4ee9c684 797 struct dump_file_info *dfi = get_dump_file_info (phase);
798 return dfi->state;
74338ff6 799}
800
801/* Returns the switch name of PHASE. */
802
803const char *
d598ad0d 804dump_flag_name (enum tree_dump_index phase)
74338ff6 805{
4ee9c684 806 struct dump_file_info *dfi = get_dump_file_info (phase);
807 return dfi->swtch;
74338ff6 808}
809
810/* Finish a tree dump for PHASE. STREAM is the stream created by
811 dump_begin. */
812
813void
d598ad0d 814dump_end (enum tree_dump_index phase ATTRIBUTE_UNUSED, FILE *stream)
74338ff6 815{
816 fclose (stream);
817}
818
4ee9c684 819/* Enable all tree dumps. */
820
821static void
822dump_enable_all (int flags)
823{
824 size_t i;
825
826 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
827 {
828 dump_files[i].state = -1;
829 dump_files[i].flags = flags;
830 }
831
832 for (i = 0; i < extra_dump_files_in_use; i++)
833 {
834 extra_dump_files[i].state = -1;
835 extra_dump_files[i].flags = flags;
836 }
837
838 /* FIXME -fdump-call-graph is broken. */
839 dump_files[TDI_xml].state = 0;
840 dump_files[TDI_xml].flags = 0;
841}
842
f712a0dc 843/* Parse ARG as a dump switch. Return nonzero if it is, and store the
74338ff6 844 relevant details in the dump_files array. */
845
4ee9c684 846static int
847dump_switch_p_1 (const char *arg, struct dump_file_info *dfi)
74338ff6 848{
74338ff6 849 const char *option_value;
4ee9c684 850 const char *ptr;
851 int flags;
40570cc2 852
4ee9c684 853 option_value = skip_leading_substring (arg, dfi->swtch);
854 if (!option_value)
855 return 0;
40570cc2 856
4ee9c684 857 ptr = option_value;
858 flags = 0;
859
860 while (*ptr)
861 {
862 const struct dump_option_value_info *option_ptr;
863 const char *end_ptr;
864 unsigned length;
865
866 while (*ptr == '-')
867 ptr++;
868 end_ptr = strchr (ptr, '-');
869 if (!end_ptr)
870 end_ptr = ptr + strlen (ptr);
871 length = end_ptr - ptr;
872
873 for (option_ptr = dump_options; option_ptr->name; option_ptr++)
874 if (strlen (option_ptr->name) == length
875 && !memcmp (option_ptr->name, ptr, length))
74338ff6 876 {
4ee9c684 877 flags |= option_ptr->value;
878 goto found;
74338ff6 879 }
4ee9c684 880 warning ("ignoring unknown option `%.*s' in `-fdump-%s'",
881 length, ptr, dfi->swtch);
882 found:;
883 ptr = end_ptr;
884 }
885
886 dfi->state = -1;
887 dfi->flags = flags;
888
889 /* Process -fdump-tree-all by enabling all the known dumps. */
890 if (dfi->suffix == NULL)
891 dump_enable_all (flags);
892
893 return 1;
894}
40570cc2 895
4ee9c684 896int
897dump_switch_p (const char *arg)
898{
899 size_t i;
900 int any = 0;
901
902 for (i = TDI_none + 1; i != TDI_end; i++)
903 any |= dump_switch_p_1 (arg, &dump_files[i]);
904
905 for (i = 0; i < extra_dump_files_in_use; i++)
906 any |= dump_switch_p_1 (arg, &extra_dump_files[i]);
907
908 return any;
909}
40570cc2 910
4ee9c684 911/* Dump FUNCTION_DECL FN as tree dump PHASE. */
912
913void
914dump_function (enum tree_dump_index phase, tree fn)
915{
916 FILE *stream;
917 int flags;
918
919 stream = dump_begin (phase, &flags);
920 if (stream)
921 {
922 dump_function_to_file (fn, stream, flags);
923 dump_end (phase, stream);
924 }
74338ff6 925}