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