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