1 /* Instruction scheduling pass. Log dumping infrastructure.
2 Copyright (C) 2006-2020 Free Software Foundation, Inc.
4 This file is part of GCC.
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
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
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/>. */
22 #include "coretypes.h"
26 #include "insn-attr.h"
29 #ifdef INSN_SCHEDULING
31 #include "sched-int.h"
33 #include "sel-sched-ir.h"
34 #include "sel-sched-dump.h"
35 #include "print-rtl.h"
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
;
42 /* True when a cfg should be dumped. */
43 static bool sel_dump_cfg_p
;
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;
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
56 bool sched_dump_to_dot_p
= false;
58 /* Controls how insns from a fence list should be dumped. */
59 static int dump_flist_insn_flags
= (DUMP_INSN_UID
| DUMP_INSN_BBN
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
;
67 /* Switch sched_dump to TO. It must not be called twice. */
69 switch_dump (FILE *to
)
71 gcc_assert (saved_sched_dump
== NULL
);
73 saved_sched_dump
= sched_dump
;
77 /* Restore previously switched dump. */
81 sched_dump
= saved_sched_dump
;
82 saved_sched_dump
= NULL
;
86 /* Functions for dumping instructions, av sets, and exprs. */
88 /* Default flags for dumping insns. */
89 static int dump_insn_rtx_flags
= DUMP_INSN_RTX_UID
| DUMP_INSN_RTX_PATTERN
;
91 /* Default flags for dumping vinsns. */
92 static int dump_vinsn_flags
= (DUMP_VINSN_INSN_RTX
| DUMP_VINSN_TYPE
95 /* Default flags for dumping expressions. */
96 static int dump_expr_flags
= DUMP_EXPR_ALL
;
98 /* Default flags for dumping insns when debugging. */
99 static int debug_insn_rtx_flags
= DUMP_INSN_RTX_ALL
;
101 /* Default flags for dumping vinsns when debugging. */
102 static int debug_vinsn_flags
= DUMP_VINSN_ALL
;
104 /* Default flags for dumping expressions when debugging. */
105 static int debug_expr_flags
= DUMP_EXPR_ALL
;
107 /* Controls how an insn from stream should be dumped when debugging. */
108 static int debug_insn_flags
= DUMP_INSN_ALL
;
110 /* Print an rtx X. */
112 sel_print_rtl (rtx x
)
114 print_rtl_single (sched_dump
, x
);
117 /* Dump insn INSN honoring FLAGS. */
119 dump_insn_rtx_1 (rtx insn
, int flags
)
123 /* flags == -1 also means dumping all. */
126 flags
|= DUMP_INSN_RTX_ALL
;
130 if (flags
& DUMP_INSN_RTX_UID
)
131 sel_print ("%d;", INSN_UID (insn
));
133 if (flags
& DUMP_INSN_RTX_PATTERN
)
134 sel_print ("%s;", str_pattern_slim (PATTERN (insn
)));
136 if (flags
& DUMP_INSN_RTX_BBN
)
138 basic_block bb
= BLOCK_FOR_INSN (insn
);
140 sel_print ("bb:%d;", bb
!= NULL
? bb
->index
: -1);
147 /* Dump INSN with default flags. */
149 dump_insn_rtx (rtx insn
)
151 dump_insn_rtx_1 (insn
, dump_insn_rtx_flags
);
155 /* Dump INSN to stderr. */
157 debug_insn_rtx (rtx insn
)
159 switch_dump (stderr
);
160 dump_insn_rtx_1 (insn
, debug_insn_rtx_flags
);
165 /* Dump vinsn VI honoring flags. */
167 dump_vinsn_1 (vinsn_t vi
, int flags
)
171 /* flags == -1 also means dumping all. */
174 flags
|= DUMP_VINSN_ALL
;
178 if (flags
& DUMP_VINSN_INSN_RTX
)
179 dump_insn_rtx_1 (VINSN_INSN_RTX (vi
), dump_insn_rtx_flags
| all
);
181 if (flags
& DUMP_VINSN_TYPE
)
182 sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi
)));
184 if (flags
& DUMP_VINSN_COUNT
)
185 sel_print ("count:%d;", VINSN_COUNT (vi
));
187 if (flags
& DUMP_VINSN_COST
)
192 sel_print ("cost:%d;", cost
);
198 /* Dump vinsn VI with default flags. */
200 dump_vinsn (vinsn_t vi
)
202 dump_vinsn_1 (vi
, dump_vinsn_flags
);
206 debug (vinsn_def
&ref
)
208 switch_dump (stderr
);
209 dump_vinsn_1 (&ref
, dump_vinsn_flags
);
215 debug (vinsn_def
*ptr
)
220 fprintf (stderr
, "<nil>\n");
224 debug_verbose (vinsn_def
&ref
)
226 switch_dump (stderr
);
227 dump_vinsn_1 (&ref
, debug_vinsn_flags
);
233 debug_verbose (vinsn_def
*ptr
)
238 fprintf (stderr
, "<nil>\n");
241 /* Dump vinsn VI to stderr. */
243 debug_vinsn (vinsn_t vi
)
245 switch_dump (stderr
);
246 dump_vinsn_1 (vi
, debug_vinsn_flags
);
251 /* Dump EXPR honoring flags. */
253 dump_expr_1 (expr_t expr
, int flags
)
257 /* flags == -1 also means dumping all. */
260 flags
|= DUMP_EXPR_ALL
;
264 if (flags
& DUMP_EXPR_VINSN
)
265 dump_vinsn_1 (EXPR_VINSN (expr
), dump_vinsn_flags
| all
);
267 if (flags
& DUMP_EXPR_SPEC
)
269 int spec
= EXPR_SPEC (expr
);
272 sel_print ("spec:%d;", spec
);
275 if (flags
& DUMP_EXPR_USEFULNESS
)
277 int use
= EXPR_USEFULNESS (expr
);
279 if (use
!= REG_BR_PROB_BASE
)
280 sel_print ("use:%d;", use
);
283 if (flags
& DUMP_EXPR_PRIORITY
)
284 sel_print ("prio:%d;", EXPR_PRIORITY (expr
));
286 if (flags
& DUMP_EXPR_SCHED_TIMES
)
288 int times
= EXPR_SCHED_TIMES (expr
);
291 sel_print ("times:%d;", times
);
294 if (flags
& DUMP_EXPR_SPEC_DONE_DS
)
296 ds_t spec_done_ds
= EXPR_SPEC_DONE_DS (expr
);
298 if (spec_done_ds
!= 0)
299 sel_print ("ds:%d;", spec_done_ds
);
302 if (flags
& DUMP_EXPR_ORIG_BB
)
304 int orig_bb
= EXPR_ORIG_BB_INDEX (expr
);
307 sel_print ("orig_bb:%d;", orig_bb
);
310 if (EXPR_TARGET_AVAILABLE (expr
) < 1)
311 sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr
));
315 /* Dump expression EXPR with default flags. */
317 dump_expr (expr_t expr
)
319 dump_expr_1 (expr
, dump_expr_flags
);
322 /* Dump expression EXPR to stderr. */
324 debug_expr (expr_t expr
)
326 switch_dump (stderr
);
327 dump_expr_1 (expr
, debug_expr_flags
);
332 /* Dump expression REF. */
335 debug (expr_def
&ref
)
337 switch_dump (stderr
);
338 dump_expr_1 (&ref
, 0);
344 debug (expr_def
*ptr
)
349 fprintf (stderr
, "<nil>\n");
352 /* Dump expression REF verbosely. */
355 debug_verbose (expr_def
&ref
)
357 switch_dump (stderr
);
358 dump_expr_1 (&ref
, DUMP_EXPR_ALL
);
364 debug_verbose (expr_def
*ptr
)
367 debug_verbose (*ptr
);
369 fprintf (stderr
, "<nil>\n");
372 /* Dump insn I honoring FLAGS. */
374 dump_insn_1 (insn_t i
, int flags
)
380 flags
|= DUMP_INSN_ALL
;
382 if (!sched_dump_to_dot_p
)
385 if (flags
& DUMP_INSN_EXPR
)
387 dump_expr_1 (INSN_EXPR (i
), dump_expr_flags
| all
);
390 else if (flags
& DUMP_INSN_PATTERN
)
392 dump_insn_rtx_1 (i
, DUMP_INSN_RTX_PATTERN
| all
);
395 else if (flags
& DUMP_INSN_UID
)
396 sel_print ("uid:%d;", INSN_UID (i
));
398 if (flags
& DUMP_INSN_SEQNO
)
399 sel_print ("seqno:%d;", INSN_SEQNO (i
));
401 if (flags
& DUMP_INSN_SCHED_CYCLE
)
403 int cycle
= INSN_SCHED_CYCLE (i
);
406 sel_print ("cycle:%d;", cycle
);
409 if (!sched_dump_to_dot_p
)
413 /* Dump insn I with default flags. */
417 dump_insn_1 (i
, DUMP_INSN_EXPR
| DUMP_INSN_SCHED_CYCLE
);
420 /* Dump INSN to stderr. */
422 debug_insn (insn_t insn
)
424 switch_dump (stderr
);
425 dump_insn_1 (insn
, debug_insn_flags
);
430 /* Dumps av_set AV. */
432 dump_av_set (av_set_t av
)
437 if (!sched_dump_to_dot_p
)
440 FOR_EACH_EXPR (expr
, i
, av
)
443 if (!sched_dump_to_dot_p
)
449 if (!sched_dump_to_dot_p
)
453 /* Dumps lvset LV. */
455 dump_lv_set (regset lv
)
459 /* This code was adapted from cfg.c: dump_regset (). */
465 reg_set_iterator rsi
;
468 EXECUTE_IF_SET_IN_REG_SET (lv
, 0, i
, rsi
)
470 sel_print (" %d", i
);
471 if (i
< FIRST_PSEUDO_REGISTER
)
473 sel_print (" [%s]", reg_names
[i
]);
479 if (sched_dump_to_dot_p
&& count
== 12)
490 /* Dumps a list of instructions pointed to by P. */
492 dump_ilist (ilist_t p
)
496 dump_insn (ILIST_INSN (p
));
501 /* Dumps a list of boundaries pointed to by BNDS. */
503 dump_blist (blist_t bnds
)
505 for (; bnds
; bnds
= BLIST_NEXT (bnds
))
507 bnd_t bnd
= BLIST_BND (bnds
);
509 sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd
)));
510 dump_ilist (BND_PTR (bnd
));
515 /* Dumps a list of fences pointed to by L. */
517 dump_flist (flist_t l
)
521 dump_insn_1 (FENCE_INSN (FLIST_FENCE (l
)), dump_flist_insn_flags
);
527 /* Dumps an insn vector SUCCS. */
529 dump_insn_vector (rtx_vec_t succs
)
534 FOR_EACH_VEC_ELT (succs
, i
, succ
)
541 /* Dumps a hard reg set SET to FILE using PREFIX. */
543 print_hard_reg_set (FILE *file
, const char *prefix
, HARD_REG_SET set
)
547 fprintf (file
, "%s{ ", prefix
);
548 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
550 if (TEST_HARD_REG_BIT (set
, i
))
551 fprintf (file
, "%d ", i
);
553 fprintf (file
, "}\n");
556 /* Dumps a hard reg set SET using PREFIX. */
558 dump_hard_reg_set (const char *prefix
, HARD_REG_SET set
)
560 print_hard_reg_set (sched_dump
, prefix
, set
);
563 /* Pretty print INSN. This is used as a hook. */
565 sel_print_insn (const rtx_insn
*insn
, int aligned ATTRIBUTE_UNUSED
)
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 ? "> " : "< ",
577 sprintf (buf
, "%s %4d",
578 INSN_SCHED_TIMES (insn
) > 0 ? "! " : " ",
581 if (GET_MODE (insn
) == TImode
)
582 sprintf (buf
, "+ %4d", INSN_UID (insn
));
584 sprintf (buf
, " %4d", INSN_UID (insn
));
590 /* Functions for pretty printing of CFG. */
591 /* FIXME: Using pretty-print here could simplify this stuff. */
593 /* Replace all occurencies of STR1 to STR2 in BUF.
594 The BUF must be large enough to hold the result. */
596 replace_str_in_buf (char *buf
, const char *str1
, const char *str2
)
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
;
606 p
= strstr (p
, str1
);
609 char *p1
= p
+ str1_len
;
610 /* Copy the rest of buf and '\0'. */
611 int n
= buf
+ buf_len
- p1
;
614 /* Shift str by DIFF chars. */
616 for (i
= n
; i
>= 0; i
--)
617 p1
[i
+ diff
] = p1
[i
];
619 for (i
= 0; i
<= n
; i
++)
620 p1
[i
+ diff
] = p1
[i
];
623 for (i
= 0; i
< str2_len
; i
++)
634 /* Replace characters in BUF that have special meaning in .dot file.
635 Similar to pp_write_text_as_dot_label_to_stream. */
637 sel_prepare_string_for_dot_label (char *buf
)
639 static char specials_from
[7][2] = { "<", ">", "{", "|", "}", "\"",
641 static char specials_to
[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}",
645 for (i
= 0; i
< 7; i
++)
646 replace_str_in_buf (buf
, specials_from
[i
], specials_to
[i
]);
649 /* This function acts like printf but dumps to the sched_dump file. */
651 sel_print (const char *fmt
, ...)
655 if (sched_dump_to_dot_p
)
658 if (vasprintf (&message
, fmt
, ap
) >= 0 && message
!= NULL
)
660 message
= (char *) xrealloc (message
, 2 * strlen (message
) + 1);
661 sel_prepare_string_for_dot_label (message
);
662 fprintf (sched_dump
, "%s", message
);
667 vfprintf (sched_dump
, fmt
, ap
);
671 /* Dump INSN with FLAGS. */
673 sel_dump_cfg_insn (insn_t insn
, int flags
)
675 int insn_flags
= DUMP_INSN_UID
| DUMP_INSN_PATTERN
;
677 if (sched_luids
.exists () && INSN_LUID (insn
) > 0)
679 if (flags
& SEL_DUMP_CFG_INSN_SEQNO
)
680 insn_flags
|= DUMP_INSN_SEQNO
| DUMP_INSN_SCHED_CYCLE
| DUMP_INSN_EXPR
;
683 dump_insn_1 (insn
, insn_flags
);
686 /* Dump E to the dot file F. */
688 sel_dump_cfg_edge (FILE *f
, edge e
)
693 if (e
->flags
& EDGE_FALLTHRU
)
696 color
= ", color = red";
698 else if (e
->src
->next_bb
== e
->dest
)
701 color
= ", color = blue";
709 fprintf (f
, "\tbb%d -> bb%d [weight = %d%s];\n",
710 e
->src
->index
, e
->dest
->index
, w
, color
);
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. */
718 has_preds_in_current_region_p (basic_block bb
)
723 gcc_assert (!in_current_region_p (bb
));
725 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
726 if (in_current_region_p (e
->src
))
732 /* Dump a cfg region to the dot file F honoring FLAGS. */
734 sel_dump_cfg_2 (FILE *f
, int flags
)
738 sched_dump_to_dot_p
= true;
741 fprintf (f
, "digraph G {\n"
743 "\tnode [shape = record, fontsize = 9];\n");
745 if (flags
& SEL_DUMP_CFG_FUNCTION_NAME
)
746 fprintf (f
, "function [label = \"%s\"];\n", current_function_name ());
748 FOR_EACH_BB_FN (bb
, cfun
)
750 insn_t insn
= BB_HEAD (bb
);
751 insn_t next_tail
= NEXT_INSN (BB_END (bb
));
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
)
758 bool some_p
= full_p
|| has_preds_in_current_region_p (bb
);
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, ";
772 if ((flags
& SEL_DUMP_CFG_FENCES
)
777 if (!sel_bb_empty_p (bb
))
780 insn_t tail
= BB_END (bb
);
783 cur_insn
= bb_note (bb
);
789 cur_insn
= NEXT_INSN (cur_insn
);
790 fence
= flist_lookup (fences
, cur_insn
);
794 if (!FENCE_SCHEDULED_P (fence
))
797 color
= "color = red, ";
799 color
= "color = yellow, ";
802 color
= "color = blue, ";
807 while (cur_insn
!= tail
);
811 style
= "style = dashed, ";
815 fprintf (f
, "\tbb%d [%s%slabel = \"{Basic block %d", bb
->index
,
816 style
, color
, bb
->index
);
818 if ((flags
& SEL_DUMP_CFG_BB_LOOP
)
819 && bb
->loop_father
!= NULL
)
820 fprintf (f
, ", loop %d", bb
->loop_father
->num
);
823 && (flags
& SEL_DUMP_CFG_BB_NOTES_LIST
))
825 insn_t notes
= BB_NOTE_LIST (bb
);
827 if (notes
!= NULL_RTX
)
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
)
835 sel_dump_cfg_insn (notes
, flags
);
838 notes
= PREV_INSN (notes
);
844 && (flags
& SEL_DUMP_CFG_AV_SET
)
845 && in_current_region_p (bb
)
846 && !sel_bb_empty_p (bb
))
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");
856 if ((flags
& SEL_DUMP_CFG_LV_SET
)
857 && !sel_bb_empty_p (bb
))
861 if (BB_LV_SET_VALID_P (bb
))
862 dump_lv_set (BB_LV_SET (bb
));
864 fprintf (f
, "LV_SET needs update");
868 && (flags
& SEL_DUMP_CFG_BB_INSNS
))
871 while (insn
!= next_tail
)
873 sel_dump_cfg_insn (insn
, flags
);
876 insn
= NEXT_INSN (insn
);
880 fprintf (f
, "}\"];\n");
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
);
890 sched_dump_to_dot_p
= false;
893 /* Dump a cfg region to the file specified by TAG honoring flags.
894 The file is created by the function. */
896 sel_dump_cfg_1 (const char *tag
, int flags
)
902 ++sel_dump_cfg_fileno
;
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
);
913 f
= fopen (buf
, "w");
916 fprintf (stderr
, "Can't create file: %s.\n", buf
);
919 sel_dump_cfg_2 (f
, flags
);
927 /* Setup cfg dumping flags. Used for debugging. */
929 setup_dump_cfg_params (void)
931 sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
933 sel_debug_cfg_root_postfix
= sel_debug_cfg_root_postfix_default
;
936 /* Debug a cfg region with FLAGS. */
938 sel_debug_cfg_1 (int flags
)
940 bool t1
= sel_dump_cfg_p
;
941 int t2
= sel_dump_cfg_fileno
;
943 sel_dump_cfg_p
= true;
944 sel_dump_cfg_fileno
= ++sel_debug_cfg_fileno
;
946 sel_dump_cfg_1 ("sel-debug-cfg", flags
);
948 sel_dump_cfg_fileno
= t2
;
952 /* Dumps av_set AV to stderr. */
954 debug_av_set (av_set_t av
)
956 switch_dump (stderr
);
962 /* Dump LV to stderr. */
964 debug_lv_set (regset lv
)
966 switch_dump (stderr
);
972 /* Dump an instruction list P to stderr. */
974 debug_ilist (ilist_t p
)
976 switch_dump (stderr
);
982 /* Dump a boundary list BNDS to stderr. */
984 debug_blist (blist_t bnds
)
986 switch_dump (stderr
);
992 /* Dump a hard reg set SET to stderr. */
994 debug_hard_reg_set (HARD_REG_SET set
)
996 switch_dump (stderr
);
997 dump_hard_reg_set ("", set
);
1002 /* Debug a cfg region with default flags. */
1004 sel_debug_cfg (void)
1006 sel_debug_cfg_1 (sel_debug_cfg_flags
);
1009 /* Print a current cselib value for X's address to stderr. */
1011 debug_mem_addr_value (rtx x
)
1014 machine_mode address_mode
;
1016 gcc_assert (MEM_P (x
));
1017 address_mode
= get_address_mode (x
);
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
));
1024 addr
= get_addr (XEXP (t
, 0));