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