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