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