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