sel-sched-dump.c 21.3 KB
Newer Older
1
/* Instruction scheduling pass.   Log dumping infrastructure.
2
   Copyright (C) 2006-2019 Free Software Foundation, Inc.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.

GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.  */

#include "config.h"
#include "system.h"
#include "coretypes.h"
23
#include "backend.h"
24
#include "rtl.h"
25
#include "df.h"
26 27
#include "insn-attr.h"
#include "cselib.h"
28 29

#ifdef INSN_SCHEDULING
30 31 32
#include "regset.h"
#include "sched-int.h"
#include "cfgloop.h"
33 34
#include "sel-sched-ir.h"
#include "sel-sched-dump.h"
35
#include "print-rtl.h"
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71


/* These variables control high-level pretty printing.  */
static int sel_dump_cfg_flags = SEL_DUMP_CFG_FLAGS;
static int sel_debug_cfg_flags = SEL_DUMP_CFG_FLAGS;

/* True when a cfg should be dumped.  */
static bool sel_dump_cfg_p;

/* Variables that are used to build the cfg dump file name.  */
static const char * const sel_debug_cfg_root = "./";
static const char * const sel_debug_cfg_root_postfix_default = "";
static const char *sel_debug_cfg_root_postfix = "";
static int sel_dump_cfg_fileno = -1;
static int sel_debug_cfg_fileno = -1;

/* When this flag is on, we are dumping to the .dot file.
   When it is off, we are dumping to log.
   This is useful to differentiate formatting between log and .dot
   files.  */
bool sched_dump_to_dot_p = false;

/* Controls how insns from a fence list should be dumped.  */
static int dump_flist_insn_flags = (DUMP_INSN_UID | DUMP_INSN_BBN
                                    | DUMP_INSN_SEQNO);


/* The variable used to hold the value of sched_dump when temporarily
   switching dump output to the other source, e.g. the .dot file.  */
static FILE *saved_sched_dump = NULL;

/* Switch sched_dump to TO.  It must not be called twice.  */
static void
switch_dump (FILE *to)
{
  gcc_assert (saved_sched_dump == NULL);
H.J. Lu committed
72

73 74 75 76 77 78 79 80 81 82 83 84 85
  saved_sched_dump = sched_dump;
  sched_dump = to;
}

/* Restore previously switched dump.  */
static void
restore_dump (void)
{
  sched_dump = saved_sched_dump;
  saved_sched_dump = NULL;
}


H.J. Lu committed
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 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123

/* Default flags for dumping vinsns.  */
static int dump_vinsn_flags = (DUMP_VINSN_INSN_RTX | DUMP_VINSN_TYPE
			       | DUMP_VINSN_COUNT);

/* Default flags for dumping expressions.  */
static int dump_expr_flags = DUMP_EXPR_ALL;

/* Default flags for dumping insns when debugging.  */
static int debug_insn_rtx_flags = DUMP_INSN_RTX_ALL;

/* Default flags for dumping vinsns when debugging.  */
static int debug_vinsn_flags = DUMP_VINSN_ALL;

/* Default flags for dumping expressions when debugging.  */
static int debug_expr_flags = DUMP_EXPR_ALL;

/* Controls how an insn from stream should be dumped when debugging.  */
static int debug_insn_flags = DUMP_INSN_ALL;

/* Print an rtx X.  */
void
sel_print_rtl (rtx x)
{
  print_rtl_single (sched_dump, x);
}

/* Dump insn INSN honoring FLAGS.  */
void
dump_insn_rtx_1 (rtx insn, int flags)
{
  int all;

  /* flags == -1 also means dumping all.  */
124
  all = (flags & 1);
125 126 127 128 129 130 131 132 133
  if (all)
    flags |= DUMP_INSN_RTX_ALL;

  sel_print ("(");

  if (flags & DUMP_INSN_RTX_UID)
    sel_print ("%d;", INSN_UID (insn));

  if (flags & DUMP_INSN_RTX_PATTERN)
134
    sel_print ("%s;", str_pattern_slim (PATTERN (insn)));
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155

  if (flags & DUMP_INSN_RTX_BBN)
    {
      basic_block bb = BLOCK_FOR_INSN (insn);

      sel_print ("bb:%d;", bb != NULL ? bb->index : -1);
    }

  sel_print (")");
}


/* Dump INSN with default flags.  */
void
dump_insn_rtx (rtx insn)
{
  dump_insn_rtx_1 (insn, dump_insn_rtx_flags);
}


/* Dump INSN to stderr.  */
156
DEBUG_FUNCTION void
157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204
debug_insn_rtx (rtx insn)
{
  switch_dump (stderr);
  dump_insn_rtx_1 (insn, debug_insn_rtx_flags);
  sel_print ("\n");
  restore_dump ();
}

/* Dump vinsn VI honoring flags.  */
void
dump_vinsn_1 (vinsn_t vi, int flags)
{
  int all;

  /* flags == -1 also means dumping all.  */
  all = flags & 1;
  if (all)
    flags |= DUMP_VINSN_ALL;

  sel_print ("(");

  if (flags & DUMP_VINSN_INSN_RTX)
    dump_insn_rtx_1 (VINSN_INSN_RTX (vi), dump_insn_rtx_flags | all);

  if (flags & DUMP_VINSN_TYPE)
    sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi)));

  if (flags & DUMP_VINSN_COUNT)
    sel_print ("count:%d;", VINSN_COUNT (vi));

  if (flags & DUMP_VINSN_COST)
    {
      int cost = vi->cost;

      if (cost != -1)
	sel_print ("cost:%d;", cost);
    }

  sel_print (")");
}

/* Dump vinsn VI with default flags.  */
void
dump_vinsn (vinsn_t vi)
{
  dump_vinsn_1 (vi, dump_vinsn_flags);
}

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240
DEBUG_FUNCTION void
debug (vinsn_def &ref)
{
  switch_dump (stderr);
  dump_vinsn_1 (&ref, dump_vinsn_flags);
  sel_print ("\n");
  restore_dump ();
}

DEBUG_FUNCTION void
debug (vinsn_def *ptr)
{
  if (ptr)
    debug (*ptr);
  else
    fprintf (stderr, "<nil>\n");
}

DEBUG_FUNCTION void
debug_verbose (vinsn_def &ref)
{
  switch_dump (stderr);
  dump_vinsn_1 (&ref, debug_vinsn_flags);
  sel_print ("\n");
  restore_dump ();
}

DEBUG_FUNCTION void
debug_verbose (vinsn_def *ptr)
{
  if (ptr)
    debug (*ptr);
  else
    fprintf (stderr, "<nil>\n");
}

241
/* Dump vinsn VI to stderr.  */
242
DEBUG_FUNCTION void
243 244 245 246
debug_vinsn (vinsn_t vi)
{
  switch_dump (stderr);
  dump_vinsn_1 (vi, debug_vinsn_flags);
H.J. Lu committed
247
  sel_print ("\n");
248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
  restore_dump ();
}

/* Dump EXPR honoring flags.  */
void
dump_expr_1 (expr_t expr, int flags)
{
  int all;

  /* flags == -1 also means dumping all.  */
  all = flags & 1;
  if (all)
    flags |= DUMP_EXPR_ALL;

  sel_print ("[");

  if (flags & DUMP_EXPR_VINSN)
    dump_vinsn_1 (EXPR_VINSN (expr), dump_vinsn_flags | all);

  if (flags & DUMP_EXPR_SPEC)
    {
      int spec = EXPR_SPEC (expr);

      if (spec != 0)
	sel_print ("spec:%d;", spec);
    }

  if (flags & DUMP_EXPR_USEFULNESS)
    {
      int use = EXPR_USEFULNESS (expr);

      if (use != REG_BR_PROB_BASE)
        sel_print ("use:%d;", use);
    }

  if (flags & DUMP_EXPR_PRIORITY)
    sel_print ("prio:%d;", EXPR_PRIORITY (expr));

  if (flags & DUMP_EXPR_SCHED_TIMES)
    {
      int times = EXPR_SCHED_TIMES (expr);

      if (times != 0)
	sel_print ("times:%d;", times);
    }

  if (flags & DUMP_EXPR_SPEC_DONE_DS)
    {
      ds_t spec_done_ds = EXPR_SPEC_DONE_DS (expr);

      if (spec_done_ds != 0)
	sel_print ("ds:%d;", spec_done_ds);
    }

  if (flags & DUMP_EXPR_ORIG_BB)
    {
      int orig_bb = EXPR_ORIG_BB_INDEX (expr);

      if (orig_bb != 0)
	sel_print ("orig_bb:%d;", orig_bb);
    }
H.J. Lu committed
309

310 311 312 313 314 315 316 317 318 319 320 321 322
  if (EXPR_TARGET_AVAILABLE (expr) < 1)
    sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr));
  sel_print ("]");
}

/* Dump expression EXPR with default flags.  */
void
dump_expr (expr_t expr)
{
  dump_expr_1 (expr, dump_expr_flags);
}

/* Dump expression EXPR to stderr.  */
323
DEBUG_FUNCTION void
324 325 326 327 328 329 330 331
debug_expr (expr_t expr)
{
  switch_dump (stderr);
  dump_expr_1 (expr, debug_expr_flags);
  sel_print ("\n");
  restore_dump ();
}

332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
/* Dump expression REF.  */

DEBUG_FUNCTION void
debug (expr_def &ref)
{
  switch_dump (stderr);
  dump_expr_1 (&ref, 0);
  sel_print ("\n");
  restore_dump ();
}

DEBUG_FUNCTION void
debug (expr_def *ptr)
{
  if (ptr)
    debug (*ptr);
  else
    fprintf (stderr, "<nil>\n");
}

/* Dump expression REF verbosely.  */

DEBUG_FUNCTION void
debug_verbose (expr_def &ref)
{
  switch_dump (stderr);
  dump_expr_1 (&ref, DUMP_EXPR_ALL);
  sel_print ("\n");
  restore_dump ();
}

DEBUG_FUNCTION void
debug_verbose (expr_def *ptr)
{
  if (ptr)
    debug_verbose (*ptr);
  else
    fprintf (stderr, "<nil>\n");
}

372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420
/* Dump insn I honoring FLAGS.  */
void
dump_insn_1 (insn_t i, int flags)
{
  int all;

  all = flags & 1;
  if (all)
    flags |= DUMP_INSN_ALL;

  if (!sched_dump_to_dot_p)
    sel_print ("(");

  if (flags & DUMP_INSN_EXPR)
    {
      dump_expr_1 (INSN_EXPR (i), dump_expr_flags | all);
      sel_print (";");
    }
  else if (flags & DUMP_INSN_PATTERN)
    {
      dump_insn_rtx_1 (i, DUMP_INSN_RTX_PATTERN | all);
      sel_print (";");
    }
  else if (flags & DUMP_INSN_UID)
    sel_print ("uid:%d;", INSN_UID (i));

  if (flags & DUMP_INSN_SEQNO)
    sel_print ("seqno:%d;", INSN_SEQNO (i));

  if (flags & DUMP_INSN_SCHED_CYCLE)
    {
      int cycle = INSN_SCHED_CYCLE (i);

      if (cycle != 0)
	sel_print ("cycle:%d;", cycle);
    }

  if (!sched_dump_to_dot_p)
    sel_print (")");
}

/* Dump insn I with default flags.  */
void
dump_insn (insn_t i)
{
  dump_insn_1 (i, DUMP_INSN_EXPR | DUMP_INSN_SCHED_CYCLE);
}

/* Dump INSN to stderr.  */
421
DEBUG_FUNCTION void
422 423 424 425 426 427 428 429 430 431 432 433 434 435
debug_insn (insn_t insn)
{
  switch_dump (stderr);
  dump_insn_1 (insn, debug_insn_flags);
  sel_print ("\n");
  restore_dump ();
}

/* Dumps av_set AV.  */
void
dump_av_set (av_set_t av)
{
  av_set_iterator i;
  expr_t expr;
H.J. Lu committed
436

437 438
  if (!sched_dump_to_dot_p)
    sel_print ("{");
H.J. Lu committed
439

440 441 442 443 444 445 446 447
  FOR_EACH_EXPR (expr, i, av)
    {
      dump_expr (expr);
      if (!sched_dump_to_dot_p)
        sel_print (" ");
      else
        sel_print ("\n");
    }
H.J. Lu committed
448

449 450 451 452 453 454 455 456 457 458
  if (!sched_dump_to_dot_p)
    sel_print ("}");
}

/* Dumps lvset LV.  */
void
dump_lv_set (regset lv)
{
  sel_print ("{");

459
  /* This code was adapted from cfg.c: dump_regset ().  */
460 461 462 463 464 465 466
  if (lv == NULL)
    sel_print ("nil");
  else
    {
      unsigned i;
      reg_set_iterator rsi;
      int count = 0;
H.J. Lu committed
467

468 469 470 471 472 473 474 475
      EXECUTE_IF_SET_IN_REG_SET (lv, 0, i, rsi)
        {
          sel_print (" %d", i);
          if (i < FIRST_PSEUDO_REGISTER)
            {
              sel_print (" [%s]", reg_names[i]);
              ++count;
            }
H.J. Lu committed
476

477
          ++count;
H.J. Lu committed
478

479 480 481 482 483 484 485
          if (sched_dump_to_dot_p && count == 12)
            {
              count = 0;
              sel_print ("\n");
            }
        }
    }
H.J. Lu committed
486

487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
  sel_print ("}\n");
}

/* Dumps a list of instructions pointed to by P.  */
static void
dump_ilist (ilist_t p)
{
  while (p)
    {
      dump_insn (ILIST_INSN (p));
      p = ILIST_NEXT (p);
    }
}

/* Dumps a list of boundaries pointed to by BNDS.  */
void
dump_blist (blist_t bnds)
{
  for (; bnds; bnds = BLIST_NEXT (bnds))
    {
      bnd_t bnd = BLIST_BND (bnds);
H.J. Lu committed
508

509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
      sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd)));
      dump_ilist (BND_PTR (bnd));
      sel_print ("] ");
    }
}

/* Dumps a list of fences pointed to by L.  */
void
dump_flist (flist_t l)
{
  while (l)
    {
      dump_insn_1 (FENCE_INSN (FLIST_FENCE (l)), dump_flist_insn_flags);
      sel_print (" ");
      l = FLIST_NEXT (l);
    }
}

/* Dumps an insn vector SUCCS.  */
void
dump_insn_vector (rtx_vec_t succs)
{
  int i;
532
  rtx_insn *succ;
H.J. Lu committed
533

534
  FOR_EACH_VEC_ELT (succs, i, succ)
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
    if (succ)
      dump_insn (succ);
    else
      sel_print ("NULL ");
}

/* Dumps a hard reg set SET to FILE using PREFIX.  */
static void
print_hard_reg_set (FILE *file, const char *prefix, HARD_REG_SET set)
{
  int i;

  fprintf (file, "%s{ ", prefix);
  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
    {
      if (TEST_HARD_REG_BIT (set, i))
	fprintf (file, "%d ", i);
    }
  fprintf (file, "}\n");
}

/* Dumps a hard reg set SET using PREFIX.  */
void
dump_hard_reg_set (const char *prefix, HARD_REG_SET set)
{
  print_hard_reg_set (sched_dump, prefix, set);
}

/* Pretty print INSN.  This is used as a hook.  */
const char *
565
sel_print_insn (const rtx_insn *insn, int aligned ATTRIBUTE_UNUSED)
566 567 568
{
  static char buf[80];

H.J. Lu committed
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)
H.J. Lu committed
573 574
      sprintf (buf, "%s %4d",
               INSN_SCHED_TIMES (insn) > 0 ? "> " : "< ",
575 576
               INSN_UID (insn));
    else
H.J. Lu committed
577 578
      sprintf (buf, "%s %4d",
               INSN_SCHED_TIMES (insn) > 0 ? "! " : "  ",
579 580 581 582 583 584 585 586 587 588 589 590
               INSN_UID (insn));
  else
    if (GET_MODE (insn) == TImode)
      sprintf (buf, "+ %4d", INSN_UID (insn));
    else
      sprintf (buf, "  %4d", INSN_UID (insn));

  return buf;
}


/* Functions for pretty printing of CFG.  */
591
/* FIXME: Using pretty-print here could simplify this stuff.  */
592 593 594 595 596 597 598 599 600 601 602 603 604 605 606

/* Replace all occurencies of STR1 to STR2 in BUF.
   The BUF must be large enough to hold the result.  */
static void
replace_str_in_buf (char *buf, const char *str1, const char *str2)
{
  int buf_len = strlen (buf);
  int str1_len = strlen (str1);
  int str2_len = strlen (str2);
  int diff = str2_len - str1_len;

  char *p = buf;
  do
    {
      p = strstr (p, str1);
H.J. Lu committed
607
      if (p)
608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624
	{
	  char *p1 = p + str1_len;
	  /* Copy the rest of buf and '\0'.  */
	  int n = buf + buf_len - p1;
	  int i;

	  /* Shift str by DIFF chars.  */
	  if (diff > 0)
            for (i = n; i >= 0; i--)
              p1[i + diff] = p1[i];
	  else
            for (i = 0; i <= n; i++)
              p1[i + diff] = p1[i];

	  /* Copy str2.  */
	  for (i = 0; i < str2_len; i++)
	    p[i] = str2[i];
H.J. Lu committed
625

626 627 628 629 630 631 632 633
	  p += str2_len;
	  buf_len += diff;
	}

    }
  while (p);
}

634 635
/* Replace characters in BUF that have special meaning in .dot file.
   Similar to pp_write_text_as_dot_label_to_stream.  */
636
static void
637 638 639 640
sel_prepare_string_for_dot_label (char *buf)
{
  static char specials_from[7][2] = { "<", ">", "{", "|", "}", "\"",
                                      "\n" };
H.J. Lu committed
641
  static char specials_to[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}",
642 643 644 645 646 647 648
                                    "\\\"", "\\l" };
  unsigned i;

  for (i = 0; i < 7; i++)
    replace_str_in_buf (buf, specials_from[i], specials_to[i]);
}

649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
/* This function acts like printf but dumps to the sched_dump file.  */
void
sel_print (const char *fmt, ...)
{
  va_list ap;
  va_start (ap, fmt);
  if (sched_dump_to_dot_p)
    {
      char *message;
      if (vasprintf (&message, fmt, ap) >= 0 && message != NULL)
	{
	  message = (char *) xrealloc (message, 2 * strlen (message) + 1);
	  sel_prepare_string_for_dot_label (message);
	  fprintf (sched_dump, "%s", message);
	  free (message);
	}
    }
  else
    vfprintf (sched_dump, fmt, ap);
  va_end (ap);
}

671 672 673 674 675 676
/* Dump INSN with FLAGS.  */
static void
sel_dump_cfg_insn (insn_t insn, int flags)
{
  int insn_flags = DUMP_INSN_UID | DUMP_INSN_PATTERN;

677
  if (sched_luids.exists () && INSN_LUID (insn) > 0)
678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747
    {
      if (flags & SEL_DUMP_CFG_INSN_SEQNO)
	insn_flags |= DUMP_INSN_SEQNO | DUMP_INSN_SCHED_CYCLE | DUMP_INSN_EXPR;
    }

  dump_insn_1 (insn, insn_flags);
}

/* Dump E to the dot file F.  */
static void
sel_dump_cfg_edge (FILE *f, edge e)
{
  int w;
  const char *color;

  if (e->flags & EDGE_FALLTHRU)
    {
      w = 10;
      color = ", color = red";
    }
  else if (e->src->next_bb == e->dest)
    {
      w = 3;
      color = ", color = blue";
    }
  else
    {
      w = 1;
      color = "";
    }

  fprintf (f, "\tbb%d -> bb%d [weight = %d%s];\n",
	   e->src->index, e->dest->index, w, color);
}


/* Return true if BB has a predesessor from current region.
   TODO: Either make this function to trace back through empty block
   or just remove those empty blocks.  */
static bool
has_preds_in_current_region_p (basic_block bb)
{
  edge e;
  edge_iterator ei;

  gcc_assert (!in_current_region_p (bb));

  FOR_EACH_EDGE (e, ei, bb->preds)
    if (in_current_region_p (e->src))
      return true;

  return false;
}

/* Dump a cfg region to the dot file F honoring FLAGS.  */
static void
sel_dump_cfg_2 (FILE *f, int flags)
{
  basic_block bb;

  sched_dump_to_dot_p = true;
  switch_dump (f);

  fprintf (f, "digraph G {\n"
	   "\tratio = 2.25;\n"
	   "\tnode [shape = record, fontsize = 9];\n");

  if (flags & SEL_DUMP_CFG_FUNCTION_NAME)
    fprintf (f, "function [label = \"%s\"];\n", current_function_name ());

748
  FOR_EACH_BB_FN (bb, cfun)
749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892
    {
      insn_t insn = BB_HEAD (bb);
      insn_t next_tail = NEXT_INSN (BB_END (bb));
      edge e;
      edge_iterator ei;
      bool in_region_p = ((flags & SEL_DUMP_CFG_CURRENT_REGION)
			  && in_current_region_p (bb));
      bool full_p = (!(flags & SEL_DUMP_CFG_CURRENT_REGION)
		     || in_region_p);
      bool some_p = full_p || has_preds_in_current_region_p (bb);
      const char *color;
      const char *style;

      if (!some_p)
	continue;

      if ((flags & SEL_DUMP_CFG_CURRENT_REGION)
	  && in_current_region_p (bb)
	  && BLOCK_TO_BB (bb->index) == 0)
	color = "color = green, ";
      else
	color = "";

      if ((flags & SEL_DUMP_CFG_FENCES)
	  && in_region_p)
	{
	  style = "";

	  if (!sel_bb_empty_p (bb))
	    {
	      bool first_p = true;
	      insn_t tail = BB_END (bb);
	      insn_t cur_insn;

	      cur_insn = bb_note (bb);

	      do
		{
		  fence_t fence;

		  cur_insn = NEXT_INSN (cur_insn);
		  fence = flist_lookup (fences, cur_insn);

		  if (fence != NULL)
		    {
		      if (!FENCE_SCHEDULED_P (fence))
			{
			  if (first_p)
			    color = "color = red, ";
			  else
			    color = "color = yellow, ";
			}
		      else
			color = "color = blue, ";
		    }

		  first_p = false;
		}
	      while (cur_insn != tail);
	    }
	}
      else if (!full_p)
	style = "style = dashed, ";
      else
	style = "";

      fprintf (f, "\tbb%d [%s%slabel = \"{Basic block %d", bb->index,
	       style, color, bb->index);

      if ((flags & SEL_DUMP_CFG_BB_LOOP)
	  && bb->loop_father != NULL)
	fprintf (f, ", loop %d", bb->loop_father->num);

      if (full_p
	  && (flags & SEL_DUMP_CFG_BB_NOTES_LIST))
	{
	  insn_t notes = BB_NOTE_LIST (bb);

	  if (notes != NULL_RTX)
	    {
	      fprintf (f, "|");

	      /* For simplicity, we dump notes from note_list in reversed order
		 to that what they will appear in the code.  */
	      while (notes != NULL_RTX)
		{
		  sel_dump_cfg_insn (notes, flags);
		  fprintf (f, "\\l");

		  notes = PREV_INSN (notes);
		}
	    }
	}

      if (full_p
	  && (flags & SEL_DUMP_CFG_AV_SET)
	  && in_current_region_p (bb)
	  && !sel_bb_empty_p (bb))
	{
	  fprintf (f, "|");

	  if (BB_AV_SET_VALID_P (bb))
	    dump_av_set (BB_AV_SET (bb));
	  else if (BB_AV_LEVEL (bb) == -1)
	    fprintf (f, "AV_SET needs update");
	}

      if ((flags & SEL_DUMP_CFG_LV_SET)
	  && !sel_bb_empty_p (bb))
 	{
	  fprintf (f, "|");

	  if (BB_LV_SET_VALID_P (bb))
	    dump_lv_set (BB_LV_SET (bb));
	  else
	    fprintf (f, "LV_SET needs update");
	}

      if (full_p
	  && (flags & SEL_DUMP_CFG_BB_INSNS))
	{
	  fprintf (f, "|");
	  while (insn != next_tail)
	    {
	      sel_dump_cfg_insn (insn, flags);
	      fprintf (f, "\\l");

	      insn = NEXT_INSN (insn);
	    }
	}

      fprintf (f, "}\"];\n");

      FOR_EACH_EDGE (e, ei, bb->succs)
	if (full_p || in_current_region_p (e->dest))
	  sel_dump_cfg_edge (f, e);
    }

  fprintf (f, "}");

  restore_dump ();
  sched_dump_to_dot_p = false;
}

H.J. Lu committed
893
/* Dump a cfg region to the file specified by TAG honoring flags.
894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952
   The file is created by the function.  */
static void
sel_dump_cfg_1 (const char *tag, int flags)
{
  char *buf;
  int i;
  FILE *f;

  ++sel_dump_cfg_fileno;

  if (!sel_dump_cfg_p)
    return;

  i = 1 + snprintf (NULL, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root,
		    sel_debug_cfg_root_postfix, sel_dump_cfg_fileno, tag);
  buf = XNEWVEC (char, i);
  snprintf (buf, i, "%s/%s%05d-%s.dot", sel_debug_cfg_root,
	    sel_debug_cfg_root_postfix, sel_dump_cfg_fileno, tag);

  f = fopen (buf, "w");

  if (f == NULL)
    fprintf (stderr, "Can't create file: %s.\n", buf);
  else
    {
      sel_dump_cfg_2 (f, flags);

      fclose (f);
    }

  free (buf);
}

/* Setup cfg dumping flags.  Used for debugging.  */
void
setup_dump_cfg_params (void)
{
  sel_dump_cfg_flags = SEL_DUMP_CFG_FLAGS;
  sel_dump_cfg_p = 0;
  sel_debug_cfg_root_postfix = sel_debug_cfg_root_postfix_default;
}

/* Debug a cfg region with FLAGS.  */
void
sel_debug_cfg_1 (int flags)
{
  bool t1 = sel_dump_cfg_p;
  int t2 = sel_dump_cfg_fileno;

  sel_dump_cfg_p = true;
  sel_dump_cfg_fileno = ++sel_debug_cfg_fileno;

  sel_dump_cfg_1 ("sel-debug-cfg", flags);

  sel_dump_cfg_fileno = t2;
  sel_dump_cfg_p = t1;
}

/* Dumps av_set AV to stderr.  */
953
DEBUG_FUNCTION void
954 955 956 957 958 959 960 961 962
debug_av_set (av_set_t av)
{
  switch_dump (stderr);
  dump_av_set (av);
  sel_print ("\n");
  restore_dump ();
}

/* Dump LV to stderr.  */
963
DEBUG_FUNCTION void
964 965 966 967 968 969 970 971 972
debug_lv_set (regset lv)
{
  switch_dump (stderr);
  dump_lv_set (lv);
  sel_print ("\n");
  restore_dump ();
}

/* Dump an instruction list P to stderr.  */
973
DEBUG_FUNCTION void
974 975 976 977 978 979 980 981 982
debug_ilist (ilist_t p)
{
  switch_dump (stderr);
  dump_ilist (p);
  sel_print ("\n");
  restore_dump ();
}

/* Dump a boundary list BNDS to stderr.  */
983
DEBUG_FUNCTION void
984 985 986 987 988 989 990 991 992
debug_blist (blist_t bnds)
{
  switch_dump (stderr);
  dump_blist (bnds);
  sel_print ("\n");
  restore_dump ();
}

/* Dump a hard reg set SET to stderr.  */
993
DEBUG_FUNCTION void
994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009
debug_hard_reg_set (HARD_REG_SET set)
{
  switch_dump (stderr);
  dump_hard_reg_set ("", set);
  sel_print ("\n");
  restore_dump ();
}

/* Debug a cfg region with default flags.  */
void
sel_debug_cfg (void)
{
  sel_debug_cfg_1 (sel_debug_cfg_flags);
}

/* Print a current cselib value for X's address to stderr.  */
1010
DEBUG_FUNCTION rtx
1011 1012 1013
debug_mem_addr_value (rtx x)
{
  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 1021
  if (cselib_lookup (XEXP (t, 0), address_mode, 0, GET_MODE (t)))
    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t));
1022 1023 1024 1025 1026 1027 1028

  t = canon_rtx (t);
  addr = get_addr (XEXP (t, 0));
  debug_rtx (t);
  debug_rtx (addr);
  return t;
}
1029
#endif
1030