1 /* Instruction scheduling pass. Log dumping infrastructure. 2 Copyright (C) 2006-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 "backend.h" 24 #include "rtl.h" 25 #include "df.h" 26 #include "insn-attr.h" 27 #include "cselib.h" 28 29 #ifdef INSN_SCHEDULING 30 #include "regset.h" 31 #include "sched-int.h" 32 #include "cfgloop.h" 33 #include "sel-sched-ir.h" 34 #include "sel-sched-dump.h" 35 #include "print-rtl.h" 36 37 38 /* These variables control high-level pretty printing. */ 39 static int sel_dump_cfg_flags = SEL_DUMP_CFG_FLAGS; 40 static int sel_debug_cfg_flags = SEL_DUMP_CFG_FLAGS; 41 42 /* True when a cfg should be dumped. */ 43 static bool sel_dump_cfg_p; 44 45 /* Variables that are used to build the cfg dump file name. */ 46 static const char * const sel_debug_cfg_root = "./"; 47 static const char * const sel_debug_cfg_root_postfix_default = ""; 48 static const char *sel_debug_cfg_root_postfix = ""; 49 static int sel_dump_cfg_fileno = -1; 50 static int sel_debug_cfg_fileno = -1; 51 52 /* When this flag is on, we are dumping to the .dot file. 53 When it is off, we are dumping to log. 54 This is useful to differentiate formatting between log and .dot 55 files. */ 56 bool sched_dump_to_dot_p = false; 57 58 /* Controls how insns from a fence list should be dumped. */ 59 static int dump_flist_insn_flags = (DUMP_INSN_UID | DUMP_INSN_BBN 60 | DUMP_INSN_SEQNO); 61 62 63 /* The variable used to hold the value of sched_dump when temporarily 64 switching dump output to the other source, e.g. the .dot file. */ 65 static FILE *saved_sched_dump = NULL; 66 67 /* Switch sched_dump to TO. It must not be called twice. */ 68 static void 69 switch_dump (FILE *to) 70 { 71 gcc_assert (saved_sched_dump == NULL); 72 73 saved_sched_dump = sched_dump; 74 sched_dump = to; 75 } 76 77 /* Restore previously switched dump. */ 78 static void 79 restore_dump (void) 80 { 81 sched_dump = saved_sched_dump; 82 saved_sched_dump = NULL; 83 } 84 85 86 /* Functions for dumping instructions, av sets, and exprs. */ 87 88 /* Default flags for dumping insns. */ 89 static int dump_insn_rtx_flags = DUMP_INSN_RTX_UID | DUMP_INSN_RTX_PATTERN; 90 91 /* Default flags for dumping vinsns. */ 92 static int dump_vinsn_flags = (DUMP_VINSN_INSN_RTX | DUMP_VINSN_TYPE 93 | DUMP_VINSN_COUNT); 94 95 /* Default flags for dumping expressions. */ 96 static int dump_expr_flags = DUMP_EXPR_ALL; 97 98 /* Default flags for dumping insns when debugging. */ 99 static int debug_insn_rtx_flags = DUMP_INSN_RTX_ALL; 100 101 /* Default flags for dumping vinsns when debugging. */ 102 static int debug_vinsn_flags = DUMP_VINSN_ALL; 103 104 /* Default flags for dumping expressions when debugging. */ 105 static int debug_expr_flags = DUMP_EXPR_ALL; 106 107 /* Controls how an insn from stream should be dumped when debugging. */ 108 static int debug_insn_flags = DUMP_INSN_ALL; 109 110 /* Print an rtx X. */ 111 void 112 sel_print_rtl (rtx x) 113 { 114 print_rtl_single (sched_dump, x); 115 } 116 117 /* Dump insn INSN honoring FLAGS. */ 118 void 119 dump_insn_rtx_1 (rtx insn, int flags) 120 { 121 int all; 122 123 /* flags == -1 also means dumping all. */ 124 all = (flags & 1); 125 if (all) 126 flags |= DUMP_INSN_RTX_ALL; 127 128 sel_print ("("); 129 130 if (flags & DUMP_INSN_RTX_UID) 131 sel_print ("%d;", INSN_UID (insn)); 132 133 if (flags & DUMP_INSN_RTX_PATTERN) 134 sel_print ("%s;", str_pattern_slim (PATTERN (insn))); 135 136 if (flags & DUMP_INSN_RTX_BBN) 137 { 138 basic_block bb = BLOCK_FOR_INSN (insn); 139 140 sel_print ("bb:%d;", bb != NULL ? bb->index : -1); 141 } 142 143 sel_print (")"); 144 } 145 146 147 /* Dump INSN with default flags. */ 148 void 149 dump_insn_rtx (rtx insn) 150 { 151 dump_insn_rtx_1 (insn, dump_insn_rtx_flags); 152 } 153 154 155 /* Dump INSN to stderr. */ 156 DEBUG_FUNCTION void 157 debug_insn_rtx (rtx insn) 158 { 159 switch_dump (stderr); 160 dump_insn_rtx_1 (insn, debug_insn_rtx_flags); 161 sel_print ("\n"); 162 restore_dump (); 163 } 164 165 /* Dump vinsn VI honoring flags. */ 166 void 167 dump_vinsn_1 (vinsn_t vi, int flags) 168 { 169 int all; 170 171 /* flags == -1 also means dumping all. */ 172 all = flags & 1; 173 if (all) 174 flags |= DUMP_VINSN_ALL; 175 176 sel_print ("("); 177 178 if (flags & DUMP_VINSN_INSN_RTX) 179 dump_insn_rtx_1 (VINSN_INSN_RTX (vi), dump_insn_rtx_flags | all); 180 181 if (flags & DUMP_VINSN_TYPE) 182 sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi))); 183 184 if (flags & DUMP_VINSN_COUNT) 185 sel_print ("count:%d;", VINSN_COUNT (vi)); 186 187 if (flags & DUMP_VINSN_COST) 188 { 189 int cost = vi->cost; 190 191 if (cost != -1) 192 sel_print ("cost:%d;", cost); 193 } 194 195 sel_print (")"); 196 } 197 198 /* Dump vinsn VI with default flags. */ 199 void 200 dump_vinsn (vinsn_t vi) 201 { 202 dump_vinsn_1 (vi, dump_vinsn_flags); 203 } 204 205 DEBUG_FUNCTION void 206 debug (vinsn_def &ref) 207 { 208 switch_dump (stderr); 209 dump_vinsn_1 (&ref, dump_vinsn_flags); 210 sel_print ("\n"); 211 restore_dump (); 212 } 213 214 DEBUG_FUNCTION void 215 debug (vinsn_def *ptr) 216 { 217 if (ptr) 218 debug (*ptr); 219 else 220 fprintf (stderr, "<nil>\n"); 221 } 222 223 DEBUG_FUNCTION void 224 debug_verbose (vinsn_def &ref) 225 { 226 switch_dump (stderr); 227 dump_vinsn_1 (&ref, debug_vinsn_flags); 228 sel_print ("\n"); 229 restore_dump (); 230 } 231 232 DEBUG_FUNCTION void 233 debug_verbose (vinsn_def *ptr) 234 { 235 if (ptr) 236 debug (*ptr); 237 else 238 fprintf (stderr, "<nil>\n"); 239 } 240 241 /* Dump vinsn VI to stderr. */ 242 DEBUG_FUNCTION void 243 debug_vinsn (vinsn_t vi) 244 { 245 switch_dump (stderr); 246 dump_vinsn_1 (vi, debug_vinsn_flags); 247 sel_print ("\n"); 248 restore_dump (); 249 } 250 251 /* Dump EXPR honoring flags. */ 252 void 253 dump_expr_1 (expr_t expr, int flags) 254 { 255 int all; 256 257 /* flags == -1 also means dumping all. */ 258 all = flags & 1; 259 if (all) 260 flags |= DUMP_EXPR_ALL; 261 262 sel_print ("["); 263 264 if (flags & DUMP_EXPR_VINSN) 265 dump_vinsn_1 (EXPR_VINSN (expr), dump_vinsn_flags | all); 266 267 if (flags & DUMP_EXPR_SPEC) 268 { 269 int spec = EXPR_SPEC (expr); 270 271 if (spec != 0) 272 sel_print ("spec:%d;", spec); 273 } 274 275 if (flags & DUMP_EXPR_USEFULNESS) 276 { 277 int use = EXPR_USEFULNESS (expr); 278 279 if (use != REG_BR_PROB_BASE) 280 sel_print ("use:%d;", use); 281 } 282 283 if (flags & DUMP_EXPR_PRIORITY) 284 sel_print ("prio:%d;", EXPR_PRIORITY (expr)); 285 286 if (flags & DUMP_EXPR_SCHED_TIMES) 287 { 288 int times = EXPR_SCHED_TIMES (expr); 289 290 if (times != 0) 291 sel_print ("times:%d;", times); 292 } 293 294 if (flags & DUMP_EXPR_SPEC_DONE_DS) 295 { 296 ds_t spec_done_ds = EXPR_SPEC_DONE_DS (expr); 297 298 if (spec_done_ds != 0) 299 sel_print ("ds:%d;", spec_done_ds); 300 } 301 302 if (flags & DUMP_EXPR_ORIG_BB) 303 { 304 int orig_bb = EXPR_ORIG_BB_INDEX (expr); 305 306 if (orig_bb != 0) 307 sel_print ("orig_bb:%d;", orig_bb); 308 } 309 310 if (EXPR_TARGET_AVAILABLE (expr) < 1) 311 sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr)); 312 sel_print ("]"); 313 } 314 315 /* Dump expression EXPR with default flags. */ 316 void 317 dump_expr (expr_t expr) 318 { 319 dump_expr_1 (expr, dump_expr_flags); 320 } 321 322 /* Dump expression EXPR to stderr. */ 323 DEBUG_FUNCTION void 324 debug_expr (expr_t expr) 325 { 326 switch_dump (stderr); 327 dump_expr_1 (expr, debug_expr_flags); 328 sel_print ("\n"); 329 restore_dump (); 330 } 331 332 /* Dump expression REF. */ 333 334 DEBUG_FUNCTION void 335 debug (expr_def &ref) 336 { 337 switch_dump (stderr); 338 dump_expr_1 (&ref, 0); 339 sel_print ("\n"); 340 restore_dump (); 341 } 342 343 DEBUG_FUNCTION void 344 debug (expr_def *ptr) 345 { 346 if (ptr) 347 debug (*ptr); 348 else 349 fprintf (stderr, "<nil>\n"); 350 } 351 352 /* Dump expression REF verbosely. */ 353 354 DEBUG_FUNCTION void 355 debug_verbose (expr_def &ref) 356 { 357 switch_dump (stderr); 358 dump_expr_1 (&ref, DUMP_EXPR_ALL); 359 sel_print ("\n"); 360 restore_dump (); 361 } 362 363 DEBUG_FUNCTION void 364 debug_verbose (expr_def *ptr) 365 { 366 if (ptr) 367 debug_verbose (*ptr); 368 else 369 fprintf (stderr, "<nil>\n"); 370 } 371 372 /* Dump insn I honoring FLAGS. */ 373 void 374 dump_insn_1 (insn_t i, int flags) 375 { 376 int all; 377 378 all = flags & 1; 379 if (all) 380 flags |= DUMP_INSN_ALL; 381 382 if (!sched_dump_to_dot_p) 383 sel_print ("("); 384 385 if (flags & DUMP_INSN_EXPR) 386 { 387 dump_expr_1 (INSN_EXPR (i), dump_expr_flags | all); 388 sel_print (";"); 389 } 390 else if (flags & DUMP_INSN_PATTERN) 391 { 392 dump_insn_rtx_1 (i, DUMP_INSN_RTX_PATTERN | all); 393 sel_print (";"); 394 } 395 else if (flags & DUMP_INSN_UID) 396 sel_print ("uid:%d;", INSN_UID (i)); 397 398 if (flags & DUMP_INSN_SEQNO) 399 sel_print ("seqno:%d;", INSN_SEQNO (i)); 400 401 if (flags & DUMP_INSN_SCHED_CYCLE) 402 { 403 int cycle = INSN_SCHED_CYCLE (i); 404 405 if (cycle != 0) 406 sel_print ("cycle:%d;", cycle); 407 } 408 409 if (!sched_dump_to_dot_p) 410 sel_print (")"); 411 } 412 413 /* Dump insn I with default flags. */ 414 void 415 dump_insn (insn_t i) 416 { 417 dump_insn_1 (i, DUMP_INSN_EXPR | DUMP_INSN_SCHED_CYCLE); 418 } 419 420 /* Dump INSN to stderr. */ 421 DEBUG_FUNCTION void 422 debug_insn (insn_t insn) 423 { 424 switch_dump (stderr); 425 dump_insn_1 (insn, debug_insn_flags); 426 sel_print ("\n"); 427 restore_dump (); 428 } 429 430 /* Dumps av_set AV. */ 431 void 432 dump_av_set (av_set_t av) 433 { 434 av_set_iterator i; 435 expr_t expr; 436 437 if (!sched_dump_to_dot_p) 438 sel_print ("{"); 439 440 FOR_EACH_EXPR (expr, i, av) 441 { 442 dump_expr (expr); 443 if (!sched_dump_to_dot_p) 444 sel_print (" "); 445 else 446 sel_print ("\n"); 447 } 448 449 if (!sched_dump_to_dot_p) 450 sel_print ("}"); 451 } 452 453 /* Dumps lvset LV. */ 454 void 455 dump_lv_set (regset lv) 456 { 457 sel_print ("{"); 458 459 /* This code was adapted from cfg.c: dump_regset (). */ 460 if (lv == NULL) 461 sel_print ("nil"); 462 else 463 { 464 unsigned i; 465 reg_set_iterator rsi; 466 int count = 0; 467 468 EXECUTE_IF_SET_IN_REG_SET (lv, 0, i, rsi) 469 { 470 sel_print (" %d", i); 471 if (i < FIRST_PSEUDO_REGISTER) 472 { 473 sel_print (" [%s]", reg_names[i]); 474 ++count; 475 } 476 477 ++count; 478 479 if (sched_dump_to_dot_p && count == 12) 480 { 481 count = 0; 482 sel_print ("\n"); 483 } 484 } 485 } 486 487 sel_print ("}\n"); 488 } 489 490 /* Dumps a list of instructions pointed to by P. */ 491 static void 492 dump_ilist (ilist_t p) 493 { 494 while (p) 495 { 496 dump_insn (ILIST_INSN (p)); 497 p = ILIST_NEXT (p); 498 } 499 } 500 501 /* Dumps a list of boundaries pointed to by BNDS. */ 502 void 503 dump_blist (blist_t bnds) 504 { 505 for (; bnds; bnds = BLIST_NEXT (bnds)) 506 { 507 bnd_t bnd = BLIST_BND (bnds); 508 509 sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd))); 510 dump_ilist (BND_PTR (bnd)); 511 sel_print ("] "); 512 } 513 } 514 515 /* Dumps a list of fences pointed to by L. */ 516 void 517 dump_flist (flist_t l) 518 { 519 while (l) 520 { 521 dump_insn_1 (FENCE_INSN (FLIST_FENCE (l)), dump_flist_insn_flags); 522 sel_print (" "); 523 l = FLIST_NEXT (l); 524 } 525 } 526 527 /* Dumps an insn vector SUCCS. */ 528 void 529 dump_insn_vector (rtx_vec_t succs) 530 { 531 int i; 532 rtx_insn *succ; 533 534 FOR_EACH_VEC_ELT (succs, i, succ) 535 if (succ) 536 dump_insn (succ); 537 else 538 sel_print ("NULL "); 539 } 540 541 /* Dumps a hard reg set SET to FILE using PREFIX. */ 542 static void 543 print_hard_reg_set (FILE *file, const char *prefix, HARD_REG_SET set) 544 { 545 int i; 546 547 fprintf (file, "%s{ ", prefix); 548 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) 549 { 550 if (TEST_HARD_REG_BIT (set, i)) 551 fprintf (file, "%d ", i); 552 } 553 fprintf (file, "}\n"); 554 } 555 556 /* Dumps a hard reg set SET using PREFIX. */ 557 void 558 dump_hard_reg_set (const char *prefix, HARD_REG_SET set) 559 { 560 print_hard_reg_set (sched_dump, prefix, set); 561 } 562 563 /* Pretty print INSN. This is used as a hook. */ 564 const char * 565 sel_print_insn (const rtx_insn *insn, int aligned ATTRIBUTE_UNUSED) 566 { 567 static char buf[80]; 568 569 /* '+' before insn means it is a new cycle start and it's not been 570 scheduled yet. '>' - has been scheduled. */ 571 if (s_i_d.exists () && INSN_LUID (insn) > 0) 572 if (GET_MODE (insn) == TImode) 573 sprintf (buf, "%s %4d", 574 INSN_SCHED_TIMES (insn) > 0 ? "> " : "< ", 575 INSN_UID (insn)); 576 else 577 sprintf (buf, "%s %4d", 578 INSN_SCHED_TIMES (insn) > 0 ? "! " : " ", 579 INSN_UID (insn)); 580 else 581 if (GET_MODE (insn) == TImode) 582 sprintf (buf, "+ %4d", INSN_UID (insn)); 583 else 584 sprintf (buf, " %4d", INSN_UID (insn)); 585 586 return buf; 587 } 588 589 590 /* Functions for pretty printing of CFG. */ 591 /* FIXME: Using pretty-print here could simplify this stuff. */ 592 593 /* Replace all occurencies of STR1 to STR2 in BUF. 594 The BUF must be large enough to hold the result. */ 595 static void 596 replace_str_in_buf (char *buf, const char *str1, const char *str2) 597 { 598 int buf_len = strlen (buf); 599 int str1_len = strlen (str1); 600 int str2_len = strlen (str2); 601 int diff = str2_len - str1_len; 602 603 char *p = buf; 604 do 605 { 606 p = strstr (p, str1); 607 if (p) 608 { 609 char *p1 = p + str1_len; 610 /* Copy the rest of buf and '\0'. */ 611 int n = buf + buf_len - p1; 612 int i; 613 614 /* Shift str by DIFF chars. */ 615 if (diff > 0) 616 for (i = n; i >= 0; i--) 617 p1[i + diff] = p1[i]; 618 else 619 for (i = 0; i <= n; i++) 620 p1[i + diff] = p1[i]; 621 622 /* Copy str2. */ 623 for (i = 0; i < str2_len; i++) 624 p[i] = str2[i]; 625 626 p += str2_len; 627 buf_len += diff; 628 } 629 630 } 631 while (p); 632 } 633 634 /* Replace characters in BUF that have special meaning in .dot file. 635 Similar to pp_write_text_as_dot_label_to_stream. */ 636 static void 637 sel_prepare_string_for_dot_label (char *buf) 638 { 639 static char specials_from[7][2] = { "<", ">", "{", "|", "}", "\"", 640 "\n" }; 641 static char specials_to[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}", 642 "\\\"", "\\l" }; 643 unsigned i; 644 645 for (i = 0; i < 7; i++) 646 replace_str_in_buf (buf, specials_from[i], specials_to[i]); 647 } 648 649 /* This function acts like printf but dumps to the sched_dump file. */ 650 void 651 sel_print (const char *fmt, ...) 652 { 653 va_list ap; 654 va_start (ap, fmt); 655 if (sched_dump_to_dot_p) 656 { 657 char *message; 658 if (vasprintf (&message, fmt, ap) >= 0 && message != NULL) 659 { 660 message = (char *) xrealloc (message, 2 * strlen (message) + 1); 661 sel_prepare_string_for_dot_label (message); 662 fprintf (sched_dump, "%s", message); 663 free (message); 664 } 665 } 666 else 667 vfprintf (sched_dump, fmt, ap); 668 va_end (ap); 669 } 670 671 /* Dump INSN with FLAGS. */ 672 static void 673 sel_dump_cfg_insn (insn_t insn, int flags) 674 { 675 int insn_flags = DUMP_INSN_UID | DUMP_INSN_PATTERN; 676 677 if (sched_luids.exists () && INSN_LUID (insn) > 0) 678 { 679 if (flags & SEL_DUMP_CFG_INSN_SEQNO) 680 insn_flags |= DUMP_INSN_SEQNO | DUMP_INSN_SCHED_CYCLE | DUMP_INSN_EXPR; 681 } 682 683 dump_insn_1 (insn, insn_flags); 684 } 685 686 /* Dump E to the dot file F. */ 687 static void 688 sel_dump_cfg_edge (FILE *f, edge e) 689 { 690 int w; 691 const char *color; 692 693 if (e->flags & EDGE_FALLTHRU) 694 { 695 w = 10; 696 color = ", color = red"; 697 } 698 else if (e->src->next_bb == e->dest) 699 { 700 w = 3; 701 color = ", color = blue"; 702 } 703 else 704 { 705 w = 1; 706 color = ""; 707 } 708 709 fprintf (f, "\tbb%d -> bb%d [weight = %d%s];\n", 710 e->src->index, e->dest->index, w, color); 711 } 712 713 714 /* Return true if BB has a predesessor from current region. 715 TODO: Either make this function to trace back through empty block 716 or just remove those empty blocks. */ 717 static bool 718 has_preds_in_current_region_p (basic_block bb) 719 { 720 edge e; 721 edge_iterator ei; 722 723 gcc_assert (!in_current_region_p (bb)); 724 725 FOR_EACH_EDGE (e, ei, bb->preds) 726 if (in_current_region_p (e->src)) 727 return true; 728 729 return false; 730 } 731 732 /* Dump a cfg region to the dot file F honoring FLAGS. */ 733 static void 734 sel_dump_cfg_2 (FILE *f, int flags) 735 { 736 basic_block bb; 737 738 sched_dump_to_dot_p = true; 739 switch_dump (f); 740 741 fprintf (f, "digraph G {\n" 742 "\tratio = 2.25;\n" 743 "\tnode [shape = record, fontsize = 9];\n"); 744 745 if (flags & SEL_DUMP_CFG_FUNCTION_NAME) 746 fprintf (f, "function [label = \"%s\"];\n", current_function_name ()); 747 748 FOR_EACH_BB_FN (bb, cfun) 749 { 750 insn_t insn = BB_HEAD (bb); 751 insn_t next_tail = NEXT_INSN (BB_END (bb)); 752 edge e; 753 edge_iterator ei; 754 bool in_region_p = ((flags & SEL_DUMP_CFG_CURRENT_REGION) 755 && in_current_region_p (bb)); 756 bool full_p = (!(flags & SEL_DUMP_CFG_CURRENT_REGION) 757 || in_region_p); 758 bool some_p = full_p || has_preds_in_current_region_p (bb); 759 const char *color; 760 const char *style; 761 762 if (!some_p) 763 continue; 764 765 if ((flags & SEL_DUMP_CFG_CURRENT_REGION) 766 && in_current_region_p (bb) 767 && BLOCK_TO_BB (bb->index) == 0) 768 color = "color = green, "; 769 else 770 color = ""; 771 772 if ((flags & SEL_DUMP_CFG_FENCES) 773 && in_region_p) 774 { 775 style = ""; 776 777 if (!sel_bb_empty_p (bb)) 778 { 779 bool first_p = true; 780 insn_t tail = BB_END (bb); 781 insn_t cur_insn; 782 783 cur_insn = bb_note (bb); 784 785 do 786 { 787 fence_t fence; 788 789 cur_insn = NEXT_INSN (cur_insn); 790 fence = flist_lookup (fences, cur_insn); 791 792 if (fence != NULL) 793 { 794 if (!FENCE_SCHEDULED_P (fence)) 795 { 796 if (first_p) 797 color = "color = red, "; 798 else 799 color = "color = yellow, "; 800 } 801 else 802 color = "color = blue, "; 803 } 804 805 first_p = false; 806 } 807 while (cur_insn != tail); 808 } 809 } 810 else if (!full_p) 811 style = "style = dashed, "; 812 else 813 style = ""; 814 815 fprintf (f, "\tbb%d [%s%slabel = \"{Basic block %d", bb->index, 816 style, color, bb->index); 817 818 if ((flags & SEL_DUMP_CFG_BB_LOOP) 819 && bb->loop_father != NULL) 820 fprintf (f, ", loop %d", bb->loop_father->num); 821 822 if (full_p 823 && (flags & SEL_DUMP_CFG_BB_NOTES_LIST)) 824 { 825 insn_t notes = BB_NOTE_LIST (bb); 826 827 if (notes != NULL_RTX) 828 { 829 fprintf (f, "|"); 830 831 /* For simplicity, we dump notes from note_list in reversed order 832 to that what they will appear in the code. */ 833 while (notes != NULL_RTX) 834 { 835 sel_dump_cfg_insn (notes, flags); 836 fprintf (f, "\\l"); 837 838 notes = PREV_INSN (notes); 839 } 840 } 841 } 842 843 if (full_p 844 && (flags & SEL_DUMP_CFG_AV_SET) 845 && in_current_region_p (bb) 846 && !sel_bb_empty_p (bb)) 847 { 848 fprintf (f, "|"); 849 850 if (BB_AV_SET_VALID_P (bb)) 851 dump_av_set (BB_AV_SET (bb)); 852 else if (BB_AV_LEVEL (bb) == -1) 853 fprintf (f, "AV_SET needs update"); 854 } 855 856 if ((flags & SEL_DUMP_CFG_LV_SET) 857 && !sel_bb_empty_p (bb)) 858 { 859 fprintf (f, "|"); 860 861 if (BB_LV_SET_VALID_P (bb)) 862 dump_lv_set (BB_LV_SET (bb)); 863 else 864 fprintf (f, "LV_SET needs update"); 865 } 866 867 if (full_p 868 && (flags & SEL_DUMP_CFG_BB_INSNS)) 869 { 870 fprintf (f, "|"); 871 while (insn != next_tail) 872 { 873 sel_dump_cfg_insn (insn, flags); 874 fprintf (f, "\\l"); 875 876 insn = NEXT_INSN (insn); 877 } 878 } 879 880 fprintf (f, "}\"];\n"); 881 882 FOR_EACH_EDGE (e, ei, bb->succs) 883 if (full_p || in_current_region_p (e->dest)) 884 sel_dump_cfg_edge (f, e); 885 } 886 887 fprintf (f, "}"); 888 889 restore_dump (); 890 sched_dump_to_dot_p = false; 891 } 892 893 /* Dump a cfg region to the file specified by TAG honoring flags. 894 The file is created by the function. */ 895 static void 896 sel_dump_cfg_1 (const char *tag, int flags) 897 { 898 char *buf; 899 int i; 900 FILE *f; 901 902 ++sel_dump_cfg_fileno; 903 904 if (!sel_dump_cfg_p) 905 return; 906 907 i = 1 + snprintf (NULL, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root, 908 sel_debug_cfg_root_postfix, sel_dump_cfg_fileno, tag); 909 buf = XNEWVEC (char, i); 910 snprintf (buf, i, "%s/%s%05d-%s.dot", sel_debug_cfg_root, 911 sel_debug_cfg_root_postfix, sel_dump_cfg_fileno, tag); 912 913 f = fopen (buf, "w"); 914 915 if (f == NULL) 916 fprintf (stderr, "Can't create file: %s.\n", buf); 917 else 918 { 919 sel_dump_cfg_2 (f, flags); 920 921 fclose (f); 922 } 923 924 free (buf); 925 } 926 927 /* Setup cfg dumping flags. Used for debugging. */ 928 void 929 setup_dump_cfg_params (void) 930 { 931 sel_dump_cfg_flags = SEL_DUMP_CFG_FLAGS; 932 sel_dump_cfg_p = 0; 933 sel_debug_cfg_root_postfix = sel_debug_cfg_root_postfix_default; 934 } 935 936 /* Debug a cfg region with FLAGS. */ 937 void 938 sel_debug_cfg_1 (int flags) 939 { 940 bool t1 = sel_dump_cfg_p; 941 int t2 = sel_dump_cfg_fileno; 942 943 sel_dump_cfg_p = true; 944 sel_dump_cfg_fileno = ++sel_debug_cfg_fileno; 945 946 sel_dump_cfg_1 ("sel-debug-cfg", flags); 947 948 sel_dump_cfg_fileno = t2; 949 sel_dump_cfg_p = t1; 950 } 951 952 /* Dumps av_set AV to stderr. */ 953 DEBUG_FUNCTION void 954 debug_av_set (av_set_t av) 955 { 956 switch_dump (stderr); 957 dump_av_set (av); 958 sel_print ("\n"); 959 restore_dump (); 960 } 961 962 /* Dump LV to stderr. */ 963 DEBUG_FUNCTION void 964 debug_lv_set (regset lv) 965 { 966 switch_dump (stderr); 967 dump_lv_set (lv); 968 sel_print ("\n"); 969 restore_dump (); 970 } 971 972 /* Dump an instruction list P to stderr. */ 973 DEBUG_FUNCTION void 974 debug_ilist (ilist_t p) 975 { 976 switch_dump (stderr); 977 dump_ilist (p); 978 sel_print ("\n"); 979 restore_dump (); 980 } 981 982 /* Dump a boundary list BNDS to stderr. */ 983 DEBUG_FUNCTION void 984 debug_blist (blist_t bnds) 985 { 986 switch_dump (stderr); 987 dump_blist (bnds); 988 sel_print ("\n"); 989 restore_dump (); 990 } 991 992 /* Dump a hard reg set SET to stderr. */ 993 DEBUG_FUNCTION void 994 debug_hard_reg_set (HARD_REG_SET set) 995 { 996 switch_dump (stderr); 997 dump_hard_reg_set ("", set); 998 sel_print ("\n"); 999 restore_dump (); 1000 } 1001 1002 /* Debug a cfg region with default flags. */ 1003 void 1004 sel_debug_cfg (void) 1005 { 1006 sel_debug_cfg_1 (sel_debug_cfg_flags); 1007 } 1008 1009 /* Print a current cselib value for X's address to stderr. */ 1010 DEBUG_FUNCTION rtx 1011 debug_mem_addr_value (rtx x) 1012 { 1013 rtx t, addr; 1014 machine_mode address_mode; 1015 1016 gcc_assert (MEM_P (x)); 1017 address_mode = get_address_mode (x); 1018 1019 t = shallow_copy_rtx (x); 1020 if (cselib_lookup (XEXP (t, 0), address_mode, 0, GET_MODE (t))) 1021 XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t)); 1022 1023 t = canon_rtx (t); 1024 addr = get_addr (XEXP (t, 0)); 1025 debug_rtx (t); 1026 debug_rtx (addr); 1027 return t; 1028 } 1029 #endif 1030 1031