OSDN Git Service

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