1/* Instruction scheduling pass.   Log dumping infrastructure.
2   Copyright (C) 2006-2020 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along 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.  */
39static int sel_dump_cfg_flags = SEL_DUMP_CFG_FLAGS;
40static int sel_debug_cfg_flags = SEL_DUMP_CFG_FLAGS;
41
42/* True when a cfg should be dumped.  */
43static bool sel_dump_cfg_p;
44
45/* Variables that are used to build the cfg dump file name.  */
46static const char * const sel_debug_cfg_root = "./";
47static const char * const sel_debug_cfg_root_postfix_default = "";
48static const char *sel_debug_cfg_root_postfix = "";
49static int sel_dump_cfg_fileno = -1;
50static 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.  */
56bool sched_dump_to_dot_p = false;
57
58/* Controls how insns from a fence list should be dumped.  */
59static 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.  */
65static FILE *saved_sched_dump = NULL;
66
67/* Switch sched_dump to TO.  It must not be called twice.  */
68static void
69switch_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.  */
78static void
79restore_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.  */
89static int dump_insn_rtx_flags = DUMP_INSN_RTX_UID | DUMP_INSN_RTX_PATTERN;
90
91/* Default flags for dumping vinsns.  */
92static int dump_vinsn_flags = (DUMP_VINSN_INSN_RTX | DUMP_VINSN_TYPE
93			       | DUMP_VINSN_COUNT);
94
95/* Default flags for dumping expressions.  */
96static int dump_expr_flags = DUMP_EXPR_ALL;
97
98/* Default flags for dumping insns when debugging.  */
99static int debug_insn_rtx_flags = DUMP_INSN_RTX_ALL;
100
101/* Default flags for dumping vinsns when debugging.  */
102static int debug_vinsn_flags = DUMP_VINSN_ALL;
103
104/* Default flags for dumping expressions when debugging.  */
105static int debug_expr_flags = DUMP_EXPR_ALL;
106
107/* Controls how an insn from stream should be dumped when debugging.  */
108static int debug_insn_flags = DUMP_INSN_ALL;
109
110/* Print an rtx X.  */
111void
112sel_print_rtl (rtx x)
113{
114  print_rtl_single (sched_dump, x);
115}
116
117/* Dump insn INSN honoring FLAGS.  */
118void
119dump_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.  */
148void
149dump_insn_rtx (rtx insn)
150{
151  dump_insn_rtx_1 (insn, dump_insn_rtx_flags);
152}
153
154
155/* Dump INSN to stderr.  */
156DEBUG_FUNCTION void
157debug_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.  */
166void
167dump_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.  */
199void
200dump_vinsn (vinsn_t vi)
201{
202  dump_vinsn_1 (vi, dump_vinsn_flags);
203}
204
205DEBUG_FUNCTION void
206debug (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
214DEBUG_FUNCTION void
215debug (vinsn_def *ptr)
216{
217  if (ptr)
218    debug (*ptr);
219  else
220    fprintf (stderr, "<nil>\n");
221}
222
223DEBUG_FUNCTION void
224debug_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
232DEBUG_FUNCTION void
233debug_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.  */
242DEBUG_FUNCTION void
243debug_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.  */
252void
253dump_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.  */
316void
317dump_expr (expr_t expr)
318{
319  dump_expr_1 (expr, dump_expr_flags);
320}
321
322/* Dump expression EXPR to stderr.  */
323DEBUG_FUNCTION void
324debug_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
334DEBUG_FUNCTION void
335debug (expr_def &ref)
336{
337  switch_dump (stderr);
338  dump_expr_1 (&ref, 0);
339  sel_print ("\n");
340  restore_dump ();
341}
342
343DEBUG_FUNCTION void
344debug (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
354DEBUG_FUNCTION void
355debug_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
363DEBUG_FUNCTION void
364debug_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.  */
373void
374dump_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.  */
414void
415dump_insn (insn_t i)
416{
417  dump_insn_1 (i, DUMP_INSN_EXPR | DUMP_INSN_SCHED_CYCLE);
418}
419
420/* Dump INSN to stderr.  */
421DEBUG_FUNCTION void
422debug_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.  */
431void
432dump_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.  */
454void
455dump_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.  */
491static void
492dump_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.  */
502void
503dump_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.  */
516void
517dump_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.  */
528void
529dump_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.  */
542static void
543print_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.  */
557void
558dump_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.  */
564const char *
565sel_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.  */
595static void
596replace_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.  */
636static void
637sel_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.  */
650void
651sel_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.  */
672static void
673sel_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.  */
687static void
688sel_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.  */
717static bool
718has_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.  */
733static void
734sel_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.  */
895static void
896sel_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.  */
928void
929setup_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.  */
937void
938sel_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.  */
953DEBUG_FUNCTION void
954debug_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.  */
963DEBUG_FUNCTION void
964debug_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.  */
973DEBUG_FUNCTION void
974debug_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.  */
983DEBUG_FUNCTION void
984debug_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.  */
993DEBUG_FUNCTION void
994debug_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.  */
1003void
1004sel_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.  */
1010DEBUG_FUNCTION rtx
1011debug_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