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