1/* Instruction scheduling pass.   Log dumping infrastructure.
2   Copyright (C) 2006, 2007, 2008, 2010 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 "tm.h"
24#include "toplev.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.  */
45static int sel_dump_cfg_flags = SEL_DUMP_CFG_FLAGS;
46static int sel_debug_cfg_flags = SEL_DUMP_CFG_FLAGS;
47
48/* True when a cfg should be dumped.  */
49static bool sel_dump_cfg_p;
50
51/* Variables that are used to build the cfg dump file name.  */
52static const char * const sel_debug_cfg_root = "./";
53static const char * const sel_debug_cfg_root_postfix_default = "";
54static const char *sel_debug_cfg_root_postfix = "";
55static int sel_dump_cfg_fileno = -1;
56static 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.  */
62bool sched_dump_to_dot_p = false;
63
64/* Controls how insns from a fence list should be dumped.  */
65static 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.  */
71static FILE *saved_sched_dump = NULL;
72
73/* Switch sched_dump to TO.  It must not be called twice.  */
74static void
75switch_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.  */
84static void
85restore_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.  */
95static int dump_insn_rtx_flags = DUMP_INSN_RTX_PATTERN;
96
97/* Default flags for dumping vinsns.  */
98static int dump_vinsn_flags = (DUMP_VINSN_INSN_RTX | DUMP_VINSN_TYPE
99			       | DUMP_VINSN_COUNT);
100
101/* Default flags for dumping expressions.  */
102static int dump_expr_flags = DUMP_EXPR_ALL;
103
104/* Default flags for dumping insns when debugging.  */
105static int debug_insn_rtx_flags = DUMP_INSN_RTX_ALL;
106
107/* Default flags for dumping vinsns when debugging.  */
108static int debug_vinsn_flags = DUMP_VINSN_ALL;
109
110/* Default flags for dumping expressions when debugging.  */
111static int debug_expr_flags = DUMP_EXPR_ALL;
112
113/* Controls how an insn from stream should be dumped when debugging.  */
114static int debug_insn_flags = DUMP_INSN_ALL;
115
116/* Print an rtx X.  */
117void
118sel_print_rtl (rtx x)
119{
120  print_rtl_single (sched_dump, x);
121}
122
123/* Dump insn INSN honoring FLAGS.  */
124void
125dump_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.  */
159void
160dump_insn_rtx (rtx insn)
161{
162  dump_insn_rtx_1 (insn, dump_insn_rtx_flags);
163}
164
165
166/* Dump INSN to stderr.  */
167void
168debug_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.  */
177void
178dump_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.  */
210void
211dump_vinsn (vinsn_t vi)
212{
213  dump_vinsn_1 (vi, dump_vinsn_flags);
214}
215
216/* Dump vinsn VI to stderr.  */
217void
218debug_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.  */
227void
228dump_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.  */
291void
292dump_expr (expr_t expr)
293{
294  dump_expr_1 (expr, dump_expr_flags);
295}
296
297/* Dump expression EXPR to stderr.  */
298void
299debug_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.  */
308void
309dump_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.  */
349void
350dump_insn (insn_t i)
351{
352  dump_insn_1 (i, DUMP_INSN_EXPR | DUMP_INSN_SCHED_CYCLE);
353}
354
355/* Dump INSN to stderr.  */
356void
357debug_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.  */
366void
367dump_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.  */
389void
390dump_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.  */
426static void
427dump_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.  */
437void
438dump_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.  */
451void
452dump_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.  */
463void
464dump_insn_vector (rtx_vec_t succs)
465{
466  int i;
467  rtx succ;
468
469  for (i = 0; VEC_iterate (rtx, succs, i, succ); i++)
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.  */
477static void
478print_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.  */
492void
493dump_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.  */
499const char *
500sel_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.  */
529static void
530replace_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.  */
569static void
570sel_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.  */
583void
584sel_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.  */
605static void
606sel_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.  */
620static void
621sel_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.  */
650static bool
651has_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.  */
666static void
667sel_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.  */
828static void
829sel_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.  */
861void
862setup_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.  */
870void
871sel_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.  */
886void
887debug_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.  */
896void
897debug_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.  */
906void
907debug_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.  */
916void
917debug_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.  */
926void
927debug_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.  */
936void
937debug_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.  */
946void
947sel_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.  */
953rtx
954debug_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))
964    XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0));
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