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