1/* Dump infrastructure for optimizations and intermediate representation. 2 Copyright (C) 2012-2015 Free Software Foundation, Inc. 3 4This file is part of GCC. 5 6GCC is free software; you can redistribute it and/or modify it under 7the terms of the GNU General Public License as published by the Free 8Software Foundation; either version 3, or (at your option) any later 9version. 10 11GCC is distributed in the hope that it will be useful, but WITHOUT ANY 12WARRANTY; without even the implied warranty of MERCHANTABILITY or 13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14for more details. 15 16You should have received a copy of the GNU General Public License 17along with GCC; see the file COPYING3. If not see 18<http://www.gnu.org/licenses/>. */ 19 20#include "config.h" 21#include "system.h" 22#include "coretypes.h" 23#include "diagnostic-core.h" 24#include "dumpfile.h" 25#include "hash-set.h" 26#include "machmode.h" 27#include "vec.h" 28#include "double-int.h" 29#include "input.h" 30#include "alias.h" 31#include "symtab.h" 32#include "options.h" 33#include "wide-int.h" 34#include "inchash.h" 35#include "real.h" 36#include "tree.h" 37#include "gimple-pretty-print.h" 38#include "context.h" 39 40/* If non-NULL, return one past-the-end of the matching SUBPART of 41 the WHOLE string. */ 42#define skip_leading_substring(whole, part) \ 43 (strncmp (whole, part, strlen (part)) ? NULL : whole + strlen (part)) 44 45static int pflags; /* current dump_flags */ 46static int alt_flags; /* current opt_info flags */ 47 48static void dump_loc (int, FILE *, source_location); 49static FILE *dump_open_alternate_stream (struct dump_file_info *); 50 51/* These are currently used for communicating between passes. 52 However, instead of accessing them directly, the passes can use 53 dump_printf () for dumps. */ 54FILE *dump_file = NULL; 55FILE *alt_dump_file = NULL; 56const char *dump_file_name; 57int dump_flags; 58 59/* Table of tree dump switches. This must be consistent with the 60 TREE_DUMP_INDEX enumeration in dumpfile.h. */ 61static struct dump_file_info dump_files[TDI_end] = 62{ 63 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, false}, 64 {".cgraph", "ipa-cgraph", NULL, NULL, NULL, NULL, NULL, TDF_IPA, 65 0, 0, 0, 0, 0, false}, 66 {".type-inheritance", "ipa-type-inheritance", NULL, NULL, NULL, NULL, NULL, TDF_IPA, 67 0, 0, 0, 0, 0, false}, 68 {".tu", "translation-unit", NULL, NULL, NULL, NULL, NULL, TDF_TREE, 69 0, 0, 0, 0, 1, false}, 70 {".class", "class-hierarchy", NULL, NULL, NULL, NULL, NULL, TDF_TREE, 71 0, 0, 0, 0, 2, false}, 72 {".original", "tree-original", NULL, NULL, NULL, NULL, NULL, TDF_TREE, 73 0, 0, 0, 0, 3, false}, 74 {".gimple", "tree-gimple", NULL, NULL, NULL, NULL, NULL, TDF_TREE, 75 0, 0, 0, 0, 4, false}, 76 {".nested", "tree-nested", NULL, NULL, NULL, NULL, NULL, TDF_TREE, 77 0, 0, 0, 0, 5, false}, 78#define FIRST_AUTO_NUMBERED_DUMP 6 79 80 {NULL, "tree-all", NULL, NULL, NULL, NULL, NULL, TDF_TREE, 81 0, 0, 0, 0, 0, false}, 82 {NULL, "rtl-all", NULL, NULL, NULL, NULL, NULL, TDF_RTL, 83 0, 0, 0, 0, 0, false}, 84 {NULL, "ipa-all", NULL, NULL, NULL, NULL, NULL, TDF_IPA, 85 0, 0, 0, 0, 0, false}, 86}; 87 88/* Define a name->number mapping for a dump flag value. */ 89struct dump_option_value_info 90{ 91 const char *const name; /* the name of the value */ 92 const int value; /* the value of the name */ 93}; 94 95/* Table of dump options. This must be consistent with the TDF_* flags 96 in dumpfile.h and opt_info_options below. */ 97static const struct dump_option_value_info dump_options[] = 98{ 99 {"address", TDF_ADDRESS}, 100 {"asmname", TDF_ASMNAME}, 101 {"slim", TDF_SLIM}, 102 {"raw", TDF_RAW}, 103 {"graph", TDF_GRAPH}, 104 {"details", (TDF_DETAILS | MSG_OPTIMIZED_LOCATIONS 105 | MSG_MISSED_OPTIMIZATION 106 | MSG_NOTE)}, 107 {"cselib", TDF_CSELIB}, 108 {"stats", TDF_STATS}, 109 {"blocks", TDF_BLOCKS}, 110 {"vops", TDF_VOPS}, 111 {"lineno", TDF_LINENO}, 112 {"uid", TDF_UID}, 113 {"stmtaddr", TDF_STMTADDR}, 114 {"memsyms", TDF_MEMSYMS}, 115 {"verbose", TDF_VERBOSE}, 116 {"eh", TDF_EH}, 117 {"alias", TDF_ALIAS}, 118 {"nouid", TDF_NOUID}, 119 {"enumerate_locals", TDF_ENUMERATE_LOCALS}, 120 {"scev", TDF_SCEV}, 121 {"optimized", MSG_OPTIMIZED_LOCATIONS}, 122 {"missed", MSG_MISSED_OPTIMIZATION}, 123 {"note", MSG_NOTE}, 124 {"optall", MSG_ALL}, 125 {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA 126 | TDF_STMTADDR | TDF_GRAPH | TDF_DIAGNOSTIC | TDF_VERBOSE 127 | TDF_RHS_ONLY | TDF_NOUID | TDF_ENUMERATE_LOCALS | TDF_SCEV)}, 128 {NULL, 0} 129}; 130 131/* A subset of the dump_options table which is used for -fopt-info 132 types. This must be consistent with the MSG_* flags in dumpfile.h. 133 */ 134static const struct dump_option_value_info optinfo_verbosity_options[] = 135{ 136 {"optimized", MSG_OPTIMIZED_LOCATIONS}, 137 {"missed", MSG_MISSED_OPTIMIZATION}, 138 {"note", MSG_NOTE}, 139 {"all", MSG_ALL}, 140 {NULL, 0} 141}; 142 143/* Flags used for -fopt-info groups. */ 144static const struct dump_option_value_info optgroup_options[] = 145{ 146 {"ipa", OPTGROUP_IPA}, 147 {"loop", OPTGROUP_LOOP}, 148 {"inline", OPTGROUP_INLINE}, 149 {"vec", OPTGROUP_VEC}, 150 {"optall", OPTGROUP_ALL}, 151 {NULL, 0} 152}; 153 154gcc::dump_manager::dump_manager (): 155 m_next_dump (FIRST_AUTO_NUMBERED_DUMP), 156 m_extra_dump_files (NULL), 157 m_extra_dump_files_in_use (0), 158 m_extra_dump_files_alloced (0) 159{ 160} 161 162gcc::dump_manager::~dump_manager () 163{ 164 for (size_t i = 0; i < m_extra_dump_files_in_use; i++) 165 { 166 dump_file_info *dfi = &m_extra_dump_files[i]; 167 /* suffix, swtch, glob are statically allocated for the entries 168 in dump_files, and for statistics, but are dynamically allocated 169 for those for passes. */ 170 if (dfi->owns_strings) 171 { 172 XDELETEVEC (const_cast <char *> (dfi->suffix)); 173 XDELETEVEC (const_cast <char *> (dfi->swtch)); 174 XDELETEVEC (const_cast <char *> (dfi->glob)); 175 } 176 /* These, if non-NULL, are always dynamically allocated. */ 177 XDELETEVEC (const_cast <char *> (dfi->pfilename)); 178 XDELETEVEC (const_cast <char *> (dfi->alt_filename)); 179 } 180 XDELETEVEC (m_extra_dump_files); 181} 182 183unsigned int 184gcc::dump_manager:: 185dump_register (const char *suffix, const char *swtch, const char *glob, 186 int flags, int optgroup_flags, 187 bool take_ownership) 188{ 189 int num = m_next_dump++; 190 191 size_t count = m_extra_dump_files_in_use++; 192 193 if (count >= m_extra_dump_files_alloced) 194 { 195 if (m_extra_dump_files_alloced == 0) 196 m_extra_dump_files_alloced = 32; 197 else 198 m_extra_dump_files_alloced *= 2; 199 m_extra_dump_files = XRESIZEVEC (struct dump_file_info, 200 m_extra_dump_files, 201 m_extra_dump_files_alloced); 202 } 203 204 memset (&m_extra_dump_files[count], 0, sizeof (struct dump_file_info)); 205 m_extra_dump_files[count].suffix = suffix; 206 m_extra_dump_files[count].swtch = swtch; 207 m_extra_dump_files[count].glob = glob; 208 m_extra_dump_files[count].pflags = flags; 209 m_extra_dump_files[count].optgroup_flags = optgroup_flags; 210 m_extra_dump_files[count].num = num; 211 m_extra_dump_files[count].owns_strings = take_ownership; 212 213 return count + TDI_end; 214} 215 216 217/* Return the dump_file_info for the given phase. */ 218 219struct dump_file_info * 220gcc::dump_manager:: 221get_dump_file_info (int phase) const 222{ 223 if (phase < TDI_end) 224 return &dump_files[phase]; 225 else if ((size_t) (phase - TDI_end) >= m_extra_dump_files_in_use) 226 return NULL; 227 else 228 return m_extra_dump_files + (phase - TDI_end); 229} 230 231/* Locate the dump_file_info with swtch equal to SWTCH, 232 or return NULL if no such dump_file_info exists. */ 233 234struct dump_file_info * 235gcc::dump_manager:: 236get_dump_file_info_by_switch (const char *swtch) const 237{ 238 for (unsigned i = 0; i < m_extra_dump_files_in_use; i++) 239 if (0 == strcmp (m_extra_dump_files[i].swtch, swtch)) 240 return &m_extra_dump_files[i]; 241 242 /* Not found. */ 243 return NULL; 244} 245 246 247/* Return the name of the dump file for the given phase. 248 The caller is responsible for calling free on the returned 249 buffer. 250 If the dump is not enabled, returns NULL. */ 251 252char * 253gcc::dump_manager:: 254get_dump_file_name (int phase) const 255{ 256 struct dump_file_info *dfi; 257 258 if (phase == TDI_none) 259 return NULL; 260 261 dfi = get_dump_file_info (phase); 262 263 return get_dump_file_name (dfi); 264} 265 266/* Return the name of the dump file for the given dump_file_info. 267 The caller is responsible for calling free on the returned 268 buffer. 269 If the dump is not enabled, returns NULL. */ 270 271char * 272gcc::dump_manager:: 273get_dump_file_name (struct dump_file_info *dfi) const 274{ 275 char dump_id[10]; 276 277 gcc_assert (dfi); 278 279 if (dfi->pstate == 0) 280 return NULL; 281 282 /* If available, use the command line dump filename. */ 283 if (dfi->pfilename) 284 return xstrdup (dfi->pfilename); 285 286 if (dfi->num < 0) 287 dump_id[0] = '\0'; 288 else 289 { 290 char suffix; 291 if (dfi->pflags & TDF_TREE) 292 suffix = 't'; 293 else if (dfi->pflags & TDF_IPA) 294 suffix = 'i'; 295 else 296 suffix = 'r'; 297 298 if (snprintf (dump_id, sizeof (dump_id), ".%03d%c", dfi->num, suffix) < 0) 299 dump_id[0] = '\0'; 300 } 301 302 return concat (dump_base_name, dump_id, dfi->suffix, NULL); 303} 304 305/* For a given DFI, open an alternate dump filename (which could also 306 be a standard stream such as stdout/stderr). If the alternate dump 307 file cannot be opened, return NULL. */ 308 309static FILE * 310dump_open_alternate_stream (struct dump_file_info *dfi) 311{ 312 FILE *stream ; 313 if (!dfi->alt_filename) 314 return NULL; 315 316 if (dfi->alt_stream) 317 return dfi->alt_stream; 318 319 stream = strcmp ("stderr", dfi->alt_filename) == 0 320 ? stderr 321 : strcmp ("stdout", dfi->alt_filename) == 0 322 ? stdout 323 : fopen (dfi->alt_filename, dfi->alt_state < 0 ? "w" : "a"); 324 325 if (!stream) 326 error ("could not open dump file %qs: %m", dfi->alt_filename); 327 else 328 dfi->alt_state = 1; 329 330 return stream; 331} 332 333/* Print source location on DFILE if enabled. */ 334 335void 336dump_loc (int dump_kind, FILE *dfile, source_location loc) 337{ 338 if (dump_kind) 339 { 340 if (LOCATION_LOCUS (loc) > BUILTINS_LOCATION) 341 fprintf (dfile, "%s:%d:%d: note: ", LOCATION_FILE (loc), 342 LOCATION_LINE (loc), LOCATION_COLUMN (loc)); 343 else if (current_function_decl) 344 fprintf (dfile, "%s:%d:%d: note: ", 345 DECL_SOURCE_FILE (current_function_decl), 346 DECL_SOURCE_LINE (current_function_decl), 347 DECL_SOURCE_COLUMN (current_function_decl)); 348 } 349} 350 351/* Dump gimple statement GS with SPC indentation spaces and 352 EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled. */ 353 354void 355dump_gimple_stmt (int dump_kind, int extra_dump_flags, gimple gs, int spc) 356{ 357 if (dump_file && (dump_kind & pflags)) 358 print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags); 359 360 if (alt_dump_file && (dump_kind & alt_flags)) 361 print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags); 362} 363 364/* Similar to dump_gimple_stmt, except additionally print source location. */ 365 366void 367dump_gimple_stmt_loc (int dump_kind, source_location loc, int extra_dump_flags, 368 gimple gs, int spc) 369{ 370 if (dump_file && (dump_kind & pflags)) 371 { 372 dump_loc (dump_kind, dump_file, loc); 373 print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags); 374 } 375 376 if (alt_dump_file && (dump_kind & alt_flags)) 377 { 378 dump_loc (dump_kind, alt_dump_file, loc); 379 print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags); 380 } 381} 382 383/* Dump expression tree T using EXTRA_DUMP_FLAGS on dump streams if 384 DUMP_KIND is enabled. */ 385 386void 387dump_generic_expr (int dump_kind, int extra_dump_flags, tree t) 388{ 389 if (dump_file && (dump_kind & pflags)) 390 print_generic_expr (dump_file, t, dump_flags | extra_dump_flags); 391 392 if (alt_dump_file && (dump_kind & alt_flags)) 393 print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags); 394} 395 396 397/* Similar to dump_generic_expr, except additionally print the source 398 location. */ 399 400void 401dump_generic_expr_loc (int dump_kind, source_location loc, 402 int extra_dump_flags, tree t) 403{ 404 if (dump_file && (dump_kind & pflags)) 405 { 406 dump_loc (dump_kind, dump_file, loc); 407 print_generic_expr (dump_file, t, dump_flags | extra_dump_flags); 408 } 409 410 if (alt_dump_file && (dump_kind & alt_flags)) 411 { 412 dump_loc (dump_kind, alt_dump_file, loc); 413 print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags); 414 } 415} 416 417/* Output a formatted message using FORMAT on appropriate dump streams. */ 418 419void 420dump_printf (int dump_kind, const char *format, ...) 421{ 422 if (dump_file && (dump_kind & pflags)) 423 { 424 va_list ap; 425 va_start (ap, format); 426 vfprintf (dump_file, format, ap); 427 va_end (ap); 428 } 429 430 if (alt_dump_file && (dump_kind & alt_flags)) 431 { 432 va_list ap; 433 va_start (ap, format); 434 vfprintf (alt_dump_file, format, ap); 435 va_end (ap); 436 } 437} 438 439/* Similar to dump_printf, except source location is also printed. */ 440 441void 442dump_printf_loc (int dump_kind, source_location loc, const char *format, ...) 443{ 444 if (dump_file && (dump_kind & pflags)) 445 { 446 va_list ap; 447 dump_loc (dump_kind, dump_file, loc); 448 va_start (ap, format); 449 vfprintf (dump_file, format, ap); 450 va_end (ap); 451 } 452 453 if (alt_dump_file && (dump_kind & alt_flags)) 454 { 455 va_list ap; 456 dump_loc (dump_kind, alt_dump_file, loc); 457 va_start (ap, format); 458 vfprintf (alt_dump_file, format, ap); 459 va_end (ap); 460 } 461} 462 463/* Start a dump for PHASE. Store user-supplied dump flags in 464 *FLAG_PTR. Return the number of streams opened. Set globals 465 DUMP_FILE, and ALT_DUMP_FILE to point to the opened streams, and 466 set dump_flags appropriately for both pass dump stream and 467 -fopt-info stream. */ 468 469int 470gcc::dump_manager:: 471dump_start (int phase, int *flag_ptr) 472{ 473 int count = 0; 474 char *name; 475 struct dump_file_info *dfi; 476 FILE *stream; 477 if (phase == TDI_none || !dump_phase_enabled_p (phase)) 478 return 0; 479 480 dfi = get_dump_file_info (phase); 481 name = get_dump_file_name (phase); 482 if (name) 483 { 484 stream = strcmp ("stderr", name) == 0 485 ? stderr 486 : strcmp ("stdout", name) == 0 487 ? stdout 488 : fopen (name, dfi->pstate < 0 ? "w" : "a"); 489 if (!stream) 490 error ("could not open dump file %qs: %m", name); 491 else 492 { 493 dfi->pstate = 1; 494 count++; 495 } 496 free (name); 497 dfi->pstream = stream; 498 dump_file = dfi->pstream; 499 /* Initialize current dump flags. */ 500 pflags = dfi->pflags; 501 } 502 503 stream = dump_open_alternate_stream (dfi); 504 if (stream) 505 { 506 dfi->alt_stream = stream; 507 count++; 508 alt_dump_file = dfi->alt_stream; 509 /* Initialize current -fopt-info flags. */ 510 alt_flags = dfi->alt_flags; 511 } 512 513 if (flag_ptr) 514 *flag_ptr = dfi->pflags; 515 516 return count; 517} 518 519/* Finish a tree dump for PHASE and close associated dump streams. Also 520 reset the globals DUMP_FILE, ALT_DUMP_FILE, and DUMP_FLAGS. */ 521 522void 523gcc::dump_manager:: 524dump_finish (int phase) 525{ 526 struct dump_file_info *dfi; 527 528 if (phase < 0) 529 return; 530 dfi = get_dump_file_info (phase); 531 if (dfi->pstream && (!dfi->pfilename 532 || (strcmp ("stderr", dfi->pfilename) != 0 533 && strcmp ("stdout", dfi->pfilename) != 0))) 534 fclose (dfi->pstream); 535 536 if (dfi->alt_stream && strcmp ("stderr", dfi->alt_filename) != 0 537 && strcmp ("stdout", dfi->alt_filename) != 0) 538 fclose (dfi->alt_stream); 539 540 dfi->alt_stream = NULL; 541 dfi->pstream = NULL; 542 dump_file = NULL; 543 alt_dump_file = NULL; 544 dump_flags = TDI_none; 545 alt_flags = 0; 546 pflags = 0; 547} 548 549/* Begin a tree dump for PHASE. Stores any user supplied flag in 550 *FLAG_PTR and returns a stream to write to. If the dump is not 551 enabled, returns NULL. 552 Multiple calls will reopen and append to the dump file. */ 553 554FILE * 555dump_begin (int phase, int *flag_ptr) 556{ 557 return g->get_dumps ()->dump_begin (phase, flag_ptr); 558} 559 560FILE * 561gcc::dump_manager:: 562dump_begin (int phase, int *flag_ptr) 563{ 564 char *name; 565 struct dump_file_info *dfi; 566 FILE *stream; 567 568 if (phase == TDI_none || !dump_phase_enabled_p (phase)) 569 return NULL; 570 571 name = get_dump_file_name (phase); 572 if (!name) 573 return NULL; 574 dfi = get_dump_file_info (phase); 575 576 stream = strcmp ("stderr", name) == 0 577 ? stderr 578 : strcmp ("stdout", name) == 0 579 ? stdout 580 : fopen (name, dfi->pstate < 0 ? "w" : "a"); 581 582 if (!stream) 583 error ("could not open dump file %qs: %m", name); 584 else 585 dfi->pstate = 1; 586 free (name); 587 588 if (flag_ptr) 589 *flag_ptr = dfi->pflags; 590 591 /* Initialize current flags */ 592 pflags = dfi->pflags; 593 return stream; 594} 595 596/* Returns nonzero if dump PHASE is enabled for at least one stream. 597 If PHASE is TDI_tree_all, return nonzero if any dump is enabled for 598 any phase. */ 599 600int 601gcc::dump_manager:: 602dump_phase_enabled_p (int phase) const 603{ 604 if (phase == TDI_tree_all) 605 { 606 size_t i; 607 for (i = TDI_none + 1; i < (size_t) TDI_end; i++) 608 if (dump_files[i].pstate || dump_files[i].alt_state) 609 return 1; 610 for (i = 0; i < m_extra_dump_files_in_use; i++) 611 if (m_extra_dump_files[i].pstate || m_extra_dump_files[i].alt_state) 612 return 1; 613 return 0; 614 } 615 else 616 { 617 struct dump_file_info *dfi = get_dump_file_info (phase); 618 return dfi->pstate || dfi->alt_state; 619 } 620} 621 622/* Returns nonzero if tree dump PHASE has been initialized. */ 623 624int 625gcc::dump_manager:: 626dump_initialized_p (int phase) const 627{ 628 struct dump_file_info *dfi = get_dump_file_info (phase); 629 return dfi->pstate > 0 || dfi->alt_state > 0; 630} 631 632/* Returns the switch name of PHASE. */ 633 634const char * 635dump_flag_name (int phase) 636{ 637 return g->get_dumps ()->dump_flag_name (phase); 638} 639 640const char * 641gcc::dump_manager:: 642dump_flag_name (int phase) const 643{ 644 struct dump_file_info *dfi = get_dump_file_info (phase); 645 return dfi->swtch; 646} 647 648/* Finish a tree dump for PHASE. STREAM is the stream created by 649 dump_begin. */ 650 651void 652dump_end (int phase ATTRIBUTE_UNUSED, FILE *stream) 653{ 654 if (stream != stderr && stream != stdout) 655 fclose (stream); 656} 657 658/* Enable all tree dumps with FLAGS on FILENAME. Return number of 659 enabled tree dumps. */ 660 661int 662gcc::dump_manager:: 663dump_enable_all (int flags, const char *filename) 664{ 665 int ir_dump_type = (flags & (TDF_TREE | TDF_RTL | TDF_IPA)); 666 int n = 0; 667 size_t i; 668 669 for (i = TDI_none + 1; i < (size_t) TDI_end; i++) 670 { 671 if ((dump_files[i].pflags & ir_dump_type)) 672 { 673 const char *old_filename = dump_files[i].pfilename; 674 dump_files[i].pstate = -1; 675 dump_files[i].pflags |= flags; 676 n++; 677 /* Override the existing filename. */ 678 if (filename) 679 { 680 dump_files[i].pfilename = xstrdup (filename); 681 /* Since it is a command-line provided file, which is 682 common to all the phases, use it in append mode. */ 683 dump_files[i].pstate = 1; 684 } 685 if (old_filename && filename != old_filename) 686 free (CONST_CAST (char *, old_filename)); 687 } 688 } 689 690 for (i = 0; i < m_extra_dump_files_in_use; i++) 691 { 692 if ((m_extra_dump_files[i].pflags & ir_dump_type)) 693 { 694 const char *old_filename = m_extra_dump_files[i].pfilename; 695 m_extra_dump_files[i].pstate = -1; 696 m_extra_dump_files[i].pflags |= flags; 697 n++; 698 /* Override the existing filename. */ 699 if (filename) 700 { 701 m_extra_dump_files[i].pfilename = xstrdup (filename); 702 /* Since it is a command-line provided file, which is 703 common to all the phases, use it in append mode. */ 704 m_extra_dump_files[i].pstate = 1; 705 } 706 if (old_filename && filename != old_filename) 707 free (CONST_CAST (char *, old_filename)); 708 } 709 } 710 711 return n; 712} 713 714/* Enable -fopt-info dumps on all dump files matching OPTGROUP_FLAGS. 715 Enable dumps with FLAGS on FILENAME. Return the number of enabled 716 dumps. */ 717 718int 719gcc::dump_manager:: 720opt_info_enable_passes (int optgroup_flags, int flags, const char *filename) 721{ 722 int n = 0; 723 size_t i; 724 725 for (i = TDI_none + 1; i < (size_t) TDI_end; i++) 726 { 727 if ((dump_files[i].optgroup_flags & optgroup_flags)) 728 { 729 const char *old_filename = dump_files[i].alt_filename; 730 /* Since this file is shared among different passes, it 731 should be opened in append mode. */ 732 dump_files[i].alt_state = 1; 733 dump_files[i].alt_flags |= flags; 734 n++; 735 /* Override the existing filename. */ 736 if (filename) 737 dump_files[i].alt_filename = xstrdup (filename); 738 if (old_filename && filename != old_filename) 739 free (CONST_CAST (char *, old_filename)); 740 } 741 } 742 743 for (i = 0; i < m_extra_dump_files_in_use; i++) 744 { 745 if ((m_extra_dump_files[i].optgroup_flags & optgroup_flags)) 746 { 747 const char *old_filename = m_extra_dump_files[i].alt_filename; 748 /* Since this file is shared among different passes, it 749 should be opened in append mode. */ 750 m_extra_dump_files[i].alt_state = 1; 751 m_extra_dump_files[i].alt_flags |= flags; 752 n++; 753 /* Override the existing filename. */ 754 if (filename) 755 m_extra_dump_files[i].alt_filename = xstrdup (filename); 756 if (old_filename && filename != old_filename) 757 free (CONST_CAST (char *, old_filename)); 758 } 759 } 760 761 return n; 762} 763 764/* Parse ARG as a dump switch. Return nonzero if it is, and store the 765 relevant details in the dump_files array. */ 766 767int 768gcc::dump_manager:: 769dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob) 770{ 771 const char *option_value; 772 const char *ptr; 773 int flags; 774 775 if (doglob && !dfi->glob) 776 return 0; 777 778 option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch); 779 if (!option_value) 780 return 0; 781 782 if (*option_value && *option_value != '-' && *option_value != '=') 783 return 0; 784 785 ptr = option_value; 786 flags = 0; 787 788 while (*ptr) 789 { 790 const struct dump_option_value_info *option_ptr; 791 const char *end_ptr; 792 const char *eq_ptr; 793 unsigned length; 794 795 while (*ptr == '-') 796 ptr++; 797 end_ptr = strchr (ptr, '-'); 798 eq_ptr = strchr (ptr, '='); 799 800 if (eq_ptr && !end_ptr) 801 end_ptr = eq_ptr; 802 803 if (!end_ptr) 804 end_ptr = ptr + strlen (ptr); 805 length = end_ptr - ptr; 806 807 for (option_ptr = dump_options; option_ptr->name; option_ptr++) 808 if (strlen (option_ptr->name) == length 809 && !memcmp (option_ptr->name, ptr, length)) 810 { 811 flags |= option_ptr->value; 812 goto found; 813 } 814 815 if (*ptr == '=') 816 { 817 /* Interpret rest of the argument as a dump filename. This 818 filename overrides other command line filenames. */ 819 if (dfi->pfilename) 820 free (CONST_CAST (char *, dfi->pfilename)); 821 dfi->pfilename = xstrdup (ptr + 1); 822 break; 823 } 824 else 825 warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>", 826 length, ptr, dfi->swtch); 827 found:; 828 ptr = end_ptr; 829 } 830 831 dfi->pstate = -1; 832 dfi->pflags |= flags; 833 834 /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the 835 known dumps. */ 836 if (dfi->suffix == NULL) 837 dump_enable_all (dfi->pflags, dfi->pfilename); 838 839 return 1; 840} 841 842int 843gcc::dump_manager:: 844dump_switch_p (const char *arg) 845{ 846 size_t i; 847 int any = 0; 848 849 for (i = TDI_none + 1; i != TDI_end; i++) 850 any |= dump_switch_p_1 (arg, &dump_files[i], false); 851 852 /* Don't glob if we got a hit already */ 853 if (!any) 854 for (i = TDI_none + 1; i != TDI_end; i++) 855 any |= dump_switch_p_1 (arg, &dump_files[i], true); 856 857 for (i = 0; i < m_extra_dump_files_in_use; i++) 858 any |= dump_switch_p_1 (arg, &m_extra_dump_files[i], false); 859 860 if (!any) 861 for (i = 0; i < m_extra_dump_files_in_use; i++) 862 any |= dump_switch_p_1 (arg, &m_extra_dump_files[i], true); 863 864 865 return any; 866} 867 868/* Parse ARG as a -fopt-info switch and store flags, optgroup_flags 869 and filename. Return non-zero if it is a recognized switch. */ 870 871static int 872opt_info_switch_p_1 (const char *arg, int *flags, int *optgroup_flags, 873 char **filename) 874{ 875 const char *option_value; 876 const char *ptr; 877 878 option_value = arg; 879 ptr = option_value; 880 881 *filename = NULL; 882 *flags = 0; 883 *optgroup_flags = 0; 884 885 if (!ptr) 886 return 1; /* Handle '-fopt-info' without any additional options. */ 887 888 while (*ptr) 889 { 890 const struct dump_option_value_info *option_ptr; 891 const char *end_ptr; 892 const char *eq_ptr; 893 unsigned length; 894 895 while (*ptr == '-') 896 ptr++; 897 end_ptr = strchr (ptr, '-'); 898 eq_ptr = strchr (ptr, '='); 899 900 if (eq_ptr && !end_ptr) 901 end_ptr = eq_ptr; 902 903 if (!end_ptr) 904 end_ptr = ptr + strlen (ptr); 905 length = end_ptr - ptr; 906 907 for (option_ptr = optinfo_verbosity_options; option_ptr->name; 908 option_ptr++) 909 if (strlen (option_ptr->name) == length 910 && !memcmp (option_ptr->name, ptr, length)) 911 { 912 *flags |= option_ptr->value; 913 goto found; 914 } 915 916 for (option_ptr = optgroup_options; option_ptr->name; option_ptr++) 917 if (strlen (option_ptr->name) == length 918 && !memcmp (option_ptr->name, ptr, length)) 919 { 920 *optgroup_flags |= option_ptr->value; 921 goto found; 922 } 923 924 if (*ptr == '=') 925 { 926 /* Interpret rest of the argument as a dump filename. This 927 filename overrides other command line filenames. */ 928 *filename = xstrdup (ptr + 1); 929 break; 930 } 931 else 932 { 933 warning (0, "unknown option %q.*s in %<-fopt-info-%s%>", 934 length, ptr, arg); 935 return 0; 936 } 937 found:; 938 ptr = end_ptr; 939 } 940 941 return 1; 942} 943 944/* Return non-zero if ARG is a recognized switch for 945 -fopt-info. Return zero otherwise. */ 946 947int 948opt_info_switch_p (const char *arg) 949{ 950 int flags; 951 int optgroup_flags; 952 char *filename; 953 static char *file_seen = NULL; 954 gcc::dump_manager *dumps = g->get_dumps (); 955 956 if (!opt_info_switch_p_1 (arg, &flags, &optgroup_flags, &filename)) 957 return 0; 958 959 if (!filename) 960 filename = xstrdup ("stderr"); 961 962 /* Bail out if a different filename has been specified. */ 963 if (file_seen && strcmp (file_seen, filename)) 964 { 965 warning (0, "ignoring possibly conflicting option %<-fopt-info-%s%>", 966 arg); 967 return 1; 968 } 969 970 file_seen = xstrdup (filename); 971 if (!flags) 972 flags = MSG_OPTIMIZED_LOCATIONS; 973 if (!optgroup_flags) 974 optgroup_flags = OPTGROUP_ALL; 975 976 return dumps->opt_info_enable_passes (optgroup_flags, flags, filename); 977} 978 979/* Print basic block on the dump streams. */ 980 981void 982dump_basic_block (int dump_kind, basic_block bb, int indent) 983{ 984 if (dump_file && (dump_kind & pflags)) 985 dump_bb (dump_file, bb, indent, TDF_DETAILS); 986 if (alt_dump_file && (dump_kind & alt_flags)) 987 dump_bb (alt_dump_file, bb, indent, TDF_DETAILS); 988} 989 990/* Print information from the combine pass on dump_file. */ 991 992void 993print_combine_total_stats (void) 994{ 995 if (dump_file) 996 dump_combine_total_stats (dump_file); 997} 998 999/* Enable RTL dump for all the RTL passes. */ 1000 1001bool 1002enable_rtl_dump_file (void) 1003{ 1004 gcc::dump_manager *dumps = g->get_dumps (); 1005 int num_enabled = 1006 dumps->dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS, NULL); 1007 return num_enabled > 0; 1008} 1009