xref: /netbsd-src/external/gpl3/gcc/dist/gcc/sel-sched-dump.cc (revision b1e838363e3c6fc78a55519254d99869742dd33c)
1 /* Instruction scheduling pass.   Log dumping infrastructure.
2    Copyright (C) 2006-2022 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.cc: 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   for (rtx_insn *succ : succs)
532     if (succ)
533       dump_insn (succ);
534     else
535       sel_print ("NULL ");
536 }
537 
538 /* Dumps a hard reg set SET to FILE using PREFIX.  */
539 static void
print_hard_reg_set(FILE * file,const char * prefix,HARD_REG_SET set)540 print_hard_reg_set (FILE *file, const char *prefix, HARD_REG_SET set)
541 {
542   int i;
543 
544   fprintf (file, "%s{ ", prefix);
545   for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
546     {
547       if (TEST_HARD_REG_BIT (set, i))
548 	fprintf (file, "%d ", i);
549     }
550   fprintf (file, "}\n");
551 }
552 
553 /* Dumps a hard reg set SET using PREFIX.  */
554 void
dump_hard_reg_set(const char * prefix,HARD_REG_SET set)555 dump_hard_reg_set (const char *prefix, HARD_REG_SET set)
556 {
557   print_hard_reg_set (sched_dump, prefix, set);
558 }
559 
560 /* Pretty print INSN.  This is used as a hook.  */
561 const char *
sel_print_insn(const rtx_insn * insn,int aligned ATTRIBUTE_UNUSED)562 sel_print_insn (const rtx_insn *insn, int aligned ATTRIBUTE_UNUSED)
563 {
564   static char buf[80];
565 
566   /* '+' before insn means it is a new cycle start and it's not been
567      scheduled yet.  '>' - has been scheduled.  */
568   if (s_i_d.exists () && INSN_LUID (insn) > 0)
569     if (GET_MODE (insn) == TImode)
570       sprintf (buf, "%s %4d",
571                INSN_SCHED_TIMES (insn) > 0 ? "> " : "< ",
572                INSN_UID (insn));
573     else
574       sprintf (buf, "%s %4d",
575                INSN_SCHED_TIMES (insn) > 0 ? "! " : "  ",
576                INSN_UID (insn));
577   else
578     if (GET_MODE (insn) == TImode)
579       sprintf (buf, "+ %4d", INSN_UID (insn));
580     else
581       sprintf (buf, "  %4d", INSN_UID (insn));
582 
583   return buf;
584 }
585 
586 
587 /* Functions for pretty printing of CFG.  */
588 /* FIXME: Using pretty-print here could simplify this stuff.  */
589 
590 /* Replace all occurencies of STR1 to STR2 in BUF.
591    The BUF must be large enough to hold the result.  */
592 static void
replace_str_in_buf(char * buf,const char * str1,const char * str2)593 replace_str_in_buf (char *buf, const char *str1, const char *str2)
594 {
595   int buf_len = strlen (buf);
596   int str1_len = strlen (str1);
597   int str2_len = strlen (str2);
598   int diff = str2_len - str1_len;
599 
600   char *p = buf;
601   do
602     {
603       p = strstr (p, str1);
604       if (p)
605 	{
606 	  char *p1 = p + str1_len;
607 	  /* Copy the rest of buf and '\0'.  */
608 	  int n = buf + buf_len - p1;
609 	  int i;
610 
611 	  /* Shift str by DIFF chars.  */
612 	  if (diff > 0)
613             for (i = n; i >= 0; i--)
614               p1[i + diff] = p1[i];
615 	  else
616             for (i = 0; i <= n; i++)
617               p1[i + diff] = p1[i];
618 
619 	  /* Copy str2.  */
620 	  for (i = 0; i < str2_len; i++)
621 	    p[i] = str2[i];
622 
623 	  p += str2_len;
624 	  buf_len += diff;
625 	}
626 
627     }
628   while (p);
629 }
630 
631 /* Replace characters in BUF that have special meaning in .dot file.
632    Similar to pp_write_text_as_dot_label_to_stream.  */
633 static void
sel_prepare_string_for_dot_label(char * buf)634 sel_prepare_string_for_dot_label (char *buf)
635 {
636   static char specials_from[7][2] = { "<", ">", "{", "|", "}", "\"",
637                                       "\n" };
638   static char specials_to[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}",
639                                     "\\\"", "\\l" };
640   unsigned i;
641 
642   for (i = 0; i < 7; i++)
643     replace_str_in_buf (buf, specials_from[i], specials_to[i]);
644 }
645 
646 /* This function acts like printf but dumps to the sched_dump file.  */
647 void
sel_print(const char * fmt,...)648 sel_print (const char *fmt, ...)
649 {
650   va_list ap;
651   va_start (ap, fmt);
652   if (sched_dump_to_dot_p)
653     {
654       char *message;
655       if (vasprintf (&message, fmt, ap) >= 0 && message != NULL)
656 	{
657 	  message = (char *) xrealloc (message, 2 * strlen (message) + 1);
658 	  sel_prepare_string_for_dot_label (message);
659 	  fprintf (sched_dump, "%s", message);
660 	  free (message);
661 	}
662     }
663   else
664     vfprintf (sched_dump, fmt, ap);
665   va_end (ap);
666 }
667 
668 /* Dump INSN with FLAGS.  */
669 static void
sel_dump_cfg_insn(insn_t insn,int flags)670 sel_dump_cfg_insn (insn_t insn, int flags)
671 {
672   int insn_flags = DUMP_INSN_UID | DUMP_INSN_PATTERN;
673 
674   if (sched_luids.exists () && INSN_LUID (insn) > 0)
675     {
676       if (flags & SEL_DUMP_CFG_INSN_SEQNO)
677 	insn_flags |= DUMP_INSN_SEQNO | DUMP_INSN_SCHED_CYCLE | DUMP_INSN_EXPR;
678     }
679 
680   dump_insn_1 (insn, insn_flags);
681 }
682 
683 /* Dump E to the dot file F.  */
684 static void
sel_dump_cfg_edge(FILE * f,edge e)685 sel_dump_cfg_edge (FILE *f, edge e)
686 {
687   int w;
688   const char *color;
689 
690   if (e->flags & EDGE_FALLTHRU)
691     {
692       w = 10;
693       color = ", color = red";
694     }
695   else if (e->src->next_bb == e->dest)
696     {
697       w = 3;
698       color = ", color = blue";
699     }
700   else
701     {
702       w = 1;
703       color = "";
704     }
705 
706   fprintf (f, "\tbb%d -> bb%d [weight = %d%s];\n",
707 	   e->src->index, e->dest->index, w, color);
708 }
709 
710 
711 /* Return true if BB has a predesessor from current region.
712    TODO: Either make this function to trace back through empty block
713    or just remove those empty blocks.  */
714 static bool
has_preds_in_current_region_p(basic_block bb)715 has_preds_in_current_region_p (basic_block bb)
716 {
717   edge e;
718   edge_iterator ei;
719 
720   gcc_assert (!in_current_region_p (bb));
721 
722   FOR_EACH_EDGE (e, ei, bb->preds)
723     if (in_current_region_p (e->src))
724       return true;
725 
726   return false;
727 }
728 
729 /* Dump a cfg region to the dot file F honoring FLAGS.  */
730 static void
sel_dump_cfg_2(FILE * f,int flags)731 sel_dump_cfg_2 (FILE *f, int flags)
732 {
733   basic_block bb;
734 
735   sched_dump_to_dot_p = true;
736   switch_dump (f);
737 
738   fprintf (f, "digraph G {\n"
739 	   "\tratio = 2.25;\n"
740 	   "\tnode [shape = record, fontsize = 9];\n");
741 
742   if (flags & SEL_DUMP_CFG_FUNCTION_NAME)
743     fprintf (f, "function [label = \"%s\"];\n", current_function_name ());
744 
745   FOR_EACH_BB_FN (bb, cfun)
746     {
747       insn_t insn = BB_HEAD (bb);
748       insn_t next_tail = NEXT_INSN (BB_END (bb));
749       edge e;
750       edge_iterator ei;
751       bool in_region_p = ((flags & SEL_DUMP_CFG_CURRENT_REGION)
752 			  && in_current_region_p (bb));
753       bool full_p = (!(flags & SEL_DUMP_CFG_CURRENT_REGION)
754 		     || in_region_p);
755       bool some_p = full_p || has_preds_in_current_region_p (bb);
756       const char *color;
757       const char *style;
758 
759       if (!some_p)
760 	continue;
761 
762       if ((flags & SEL_DUMP_CFG_CURRENT_REGION)
763 	  && in_current_region_p (bb)
764 	  && BLOCK_TO_BB (bb->index) == 0)
765 	color = "color = green, ";
766       else
767 	color = "";
768 
769       if ((flags & SEL_DUMP_CFG_FENCES)
770 	  && in_region_p)
771 	{
772 	  style = "";
773 
774 	  if (!sel_bb_empty_p (bb))
775 	    {
776 	      bool first_p = true;
777 	      insn_t tail = BB_END (bb);
778 	      insn_t cur_insn;
779 
780 	      cur_insn = bb_note (bb);
781 
782 	      do
783 		{
784 		  fence_t fence;
785 
786 		  cur_insn = NEXT_INSN (cur_insn);
787 		  fence = flist_lookup (fences, cur_insn);
788 
789 		  if (fence != NULL)
790 		    {
791 		      if (!FENCE_SCHEDULED_P (fence))
792 			{
793 			  if (first_p)
794 			    color = "color = red, ";
795 			  else
796 			    color = "color = yellow, ";
797 			}
798 		      else
799 			color = "color = blue, ";
800 		    }
801 
802 		  first_p = false;
803 		}
804 	      while (cur_insn != tail);
805 	    }
806 	}
807       else if (!full_p)
808 	style = "style = dashed, ";
809       else
810 	style = "";
811 
812       fprintf (f, "\tbb%d [%s%slabel = \"{Basic block %d", bb->index,
813 	       style, color, bb->index);
814 
815       if ((flags & SEL_DUMP_CFG_BB_LOOP)
816 	  && bb->loop_father != NULL)
817 	fprintf (f, ", loop %d", bb->loop_father->num);
818 
819       if (full_p
820 	  && (flags & SEL_DUMP_CFG_BB_NOTES_LIST))
821 	{
822 	  insn_t notes = BB_NOTE_LIST (bb);
823 
824 	  if (notes != NULL_RTX)
825 	    {
826 	      fprintf (f, "|");
827 
828 	      /* For simplicity, we dump notes from note_list in reversed order
829 		 to that what they will appear in the code.  */
830 	      while (notes != NULL_RTX)
831 		{
832 		  sel_dump_cfg_insn (notes, flags);
833 		  fprintf (f, "\\l");
834 
835 		  notes = PREV_INSN (notes);
836 		}
837 	    }
838 	}
839 
840       if (full_p
841 	  && (flags & SEL_DUMP_CFG_AV_SET)
842 	  && in_current_region_p (bb)
843 	  && !sel_bb_empty_p (bb))
844 	{
845 	  fprintf (f, "|");
846 
847 	  if (BB_AV_SET_VALID_P (bb))
848 	    dump_av_set (BB_AV_SET (bb));
849 	  else if (BB_AV_LEVEL (bb) == -1)
850 	    fprintf (f, "AV_SET needs update");
851 	}
852 
853       if ((flags & SEL_DUMP_CFG_LV_SET)
854 	  && !sel_bb_empty_p (bb))
855  	{
856 	  fprintf (f, "|");
857 
858 	  if (BB_LV_SET_VALID_P (bb))
859 	    dump_lv_set (BB_LV_SET (bb));
860 	  else
861 	    fprintf (f, "LV_SET needs update");
862 	}
863 
864       if (full_p
865 	  && (flags & SEL_DUMP_CFG_BB_INSNS))
866 	{
867 	  fprintf (f, "|");
868 	  while (insn != next_tail)
869 	    {
870 	      sel_dump_cfg_insn (insn, flags);
871 	      fprintf (f, "\\l");
872 
873 	      insn = NEXT_INSN (insn);
874 	    }
875 	}
876 
877       fprintf (f, "}\"];\n");
878 
879       FOR_EACH_EDGE (e, ei, bb->succs)
880 	if (full_p || in_current_region_p (e->dest))
881 	  sel_dump_cfg_edge (f, e);
882     }
883 
884   fprintf (f, "}");
885 
886   restore_dump ();
887   sched_dump_to_dot_p = false;
888 }
889 
890 /* Dump a cfg region to the file specified by TAG honoring flags.
891    The file is created by the function.  */
892 static void
sel_dump_cfg_1(const char * tag,int flags)893 sel_dump_cfg_1 (const char *tag, int flags)
894 {
895   char *buf;
896   int i;
897   FILE *f;
898 
899   ++sel_dump_cfg_fileno;
900 
901   if (!sel_dump_cfg_p)
902     return;
903 
904   i = 1 + snprintf (NULL, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root,
905 		    sel_debug_cfg_root_postfix, sel_dump_cfg_fileno, tag);
906   buf = XNEWVEC (char, i);
907   snprintf (buf, i, "%s/%s%05d-%s.dot", sel_debug_cfg_root,
908 	    sel_debug_cfg_root_postfix, sel_dump_cfg_fileno, tag);
909 
910   f = fopen (buf, "w");
911 
912   if (f == NULL)
913     fprintf (stderr, "Can't create file: %s.\n", buf);
914   else
915     {
916       sel_dump_cfg_2 (f, flags);
917 
918       fclose (f);
919     }
920 
921   free (buf);
922 }
923 
924 /* Setup cfg dumping flags.  Used for debugging.  */
925 void
setup_dump_cfg_params(void)926 setup_dump_cfg_params (void)
927 {
928   sel_dump_cfg_flags = SEL_DUMP_CFG_FLAGS;
929   sel_dump_cfg_p = 0;
930   sel_debug_cfg_root_postfix = sel_debug_cfg_root_postfix_default;
931 }
932 
933 /* Debug a cfg region with FLAGS.  */
934 void
sel_debug_cfg_1(int flags)935 sel_debug_cfg_1 (int flags)
936 {
937   bool t1 = sel_dump_cfg_p;
938   int t2 = sel_dump_cfg_fileno;
939 
940   sel_dump_cfg_p = true;
941   sel_dump_cfg_fileno = ++sel_debug_cfg_fileno;
942 
943   sel_dump_cfg_1 ("sel-debug-cfg", flags);
944 
945   sel_dump_cfg_fileno = t2;
946   sel_dump_cfg_p = t1;
947 }
948 
949 /* Dumps av_set AV to stderr.  */
950 DEBUG_FUNCTION void
debug_av_set(av_set_t av)951 debug_av_set (av_set_t av)
952 {
953   switch_dump (stderr);
954   dump_av_set (av);
955   sel_print ("\n");
956   restore_dump ();
957 }
958 
959 /* Dump LV to stderr.  */
960 DEBUG_FUNCTION void
debug_lv_set(regset lv)961 debug_lv_set (regset lv)
962 {
963   switch_dump (stderr);
964   dump_lv_set (lv);
965   sel_print ("\n");
966   restore_dump ();
967 }
968 
969 /* Dump an instruction list P to stderr.  */
970 DEBUG_FUNCTION void
debug_ilist(ilist_t p)971 debug_ilist (ilist_t p)
972 {
973   switch_dump (stderr);
974   dump_ilist (p);
975   sel_print ("\n");
976   restore_dump ();
977 }
978 
979 /* Dump a boundary list BNDS to stderr.  */
980 DEBUG_FUNCTION void
debug_blist(blist_t bnds)981 debug_blist (blist_t bnds)
982 {
983   switch_dump (stderr);
984   dump_blist (bnds);
985   sel_print ("\n");
986   restore_dump ();
987 }
988 
989 /* Dump a hard reg set SET to stderr.  */
990 DEBUG_FUNCTION void
debug_hard_reg_set(HARD_REG_SET set)991 debug_hard_reg_set (HARD_REG_SET set)
992 {
993   switch_dump (stderr);
994   dump_hard_reg_set ("", set);
995   sel_print ("\n");
996   restore_dump ();
997 }
998 
999 /* Debug a cfg region with default flags.  */
1000 void
sel_debug_cfg(void)1001 sel_debug_cfg (void)
1002 {
1003   sel_debug_cfg_1 (sel_debug_cfg_flags);
1004 }
1005 
1006 /* Print a current cselib value for X's address to stderr.  */
1007 DEBUG_FUNCTION rtx
debug_mem_addr_value(rtx x)1008 debug_mem_addr_value (rtx x)
1009 {
1010   rtx t, addr;
1011   machine_mode address_mode;
1012 
1013   gcc_assert (MEM_P (x));
1014   address_mode = get_address_mode (x);
1015 
1016   t = shallow_copy_rtx (x);
1017   if (cselib_lookup (XEXP (t, 0), address_mode, 0, GET_MODE (t)))
1018     XEXP (t, 0) = cselib_subst_to_values (XEXP (t, 0), GET_MODE (t));
1019 
1020   t = canon_rtx (t);
1021   addr = get_addr (XEXP (t, 0));
1022   debug_rtx (t);
1023   debug_rtx (addr);
1024   return t;
1025 }
1026 #endif
1027 
1028