1 /* Instruction scheduling pass. Log dumping infrastructure.
2 Copyright (C) 2006-2015 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 "diagnostic-core.h"
30 #include "insn-config.h"
31 #include "insn-attr.h"
33 #include "alloc-pool.h"
37 #ifdef INSN_SCHEDULING
39 #include "sched-int.h"
41 #include "sel-sched-ir.h"
42 #include "sel-sched-dump.h"
43 #include "print-rtl.h"
46 /* These variables control high-level pretty printing. */
47 static int sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
48 static int sel_debug_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
50 /* True when a cfg should be dumped. */
51 static bool sel_dump_cfg_p
;
53 /* Variables that are used to build the cfg dump file name. */
54 static const char * const sel_debug_cfg_root
= "./";
55 static const char * const sel_debug_cfg_root_postfix_default
= "";
56 static const char *sel_debug_cfg_root_postfix
= "";
57 static int sel_dump_cfg_fileno
= -1;
58 static int sel_debug_cfg_fileno
= -1;
60 /* When this flag is on, we are dumping to the .dot file.
61 When it is off, we are dumping to log.
62 This is useful to differentiate formatting between log and .dot
64 bool sched_dump_to_dot_p
= false;
66 /* Controls how insns from a fence list should be dumped. */
67 static int dump_flist_insn_flags
= (DUMP_INSN_UID
| DUMP_INSN_BBN
71 /* The variable used to hold the value of sched_dump when temporarily
72 switching dump output to the other source, e.g. the .dot file. */
73 static FILE *saved_sched_dump
= NULL
;
75 /* Switch sched_dump to TO. It must not be called twice. */
77 switch_dump (FILE *to
)
79 gcc_assert (saved_sched_dump
== NULL
);
81 saved_sched_dump
= sched_dump
;
85 /* Restore previously switched dump. */
89 sched_dump
= saved_sched_dump
;
90 saved_sched_dump
= NULL
;
94 /* Functions for dumping instructions, av sets, and exprs. */
96 /* Default flags for dumping insns. */
97 static int dump_insn_rtx_flags
= DUMP_INSN_RTX_UID
| DUMP_INSN_RTX_PATTERN
;
99 /* Default flags for dumping vinsns. */
100 static int dump_vinsn_flags
= (DUMP_VINSN_INSN_RTX
| DUMP_VINSN_TYPE
103 /* Default flags for dumping expressions. */
104 static int dump_expr_flags
= DUMP_EXPR_ALL
;
106 /* Default flags for dumping insns when debugging. */
107 static int debug_insn_rtx_flags
= DUMP_INSN_RTX_ALL
;
109 /* Default flags for dumping vinsns when debugging. */
110 static int debug_vinsn_flags
= DUMP_VINSN_ALL
;
112 /* Default flags for dumping expressions when debugging. */
113 static int debug_expr_flags
= DUMP_EXPR_ALL
;
115 /* Controls how an insn from stream should be dumped when debugging. */
116 static int debug_insn_flags
= DUMP_INSN_ALL
;
118 /* Print an rtx X. */
120 sel_print_rtl (rtx x
)
122 print_rtl_single (sched_dump
, x
);
125 /* Dump insn INSN honoring FLAGS. */
127 dump_insn_rtx_1 (rtx insn
, int flags
)
131 /* flags == -1 also means dumping all. */
134 flags
|= DUMP_INSN_RTX_ALL
;
138 if (flags
& DUMP_INSN_RTX_UID
)
139 sel_print ("%d;", INSN_UID (insn
));
141 if (flags
& DUMP_INSN_RTX_PATTERN
)
142 sel_print ("%s;", str_pattern_slim (PATTERN (insn
)));
144 if (flags
& DUMP_INSN_RTX_BBN
)
146 basic_block bb
= BLOCK_FOR_INSN (insn
);
148 sel_print ("bb:%d;", bb
!= NULL
? bb
->index
: -1);
155 /* Dump INSN with default flags. */
157 dump_insn_rtx (rtx insn
)
159 dump_insn_rtx_1 (insn
, dump_insn_rtx_flags
);
163 /* Dump INSN to stderr. */
165 debug_insn_rtx (rtx insn
)
167 switch_dump (stderr
);
168 dump_insn_rtx_1 (insn
, debug_insn_rtx_flags
);
173 /* Dump vinsn VI honoring flags. */
175 dump_vinsn_1 (vinsn_t vi
, int flags
)
179 /* flags == -1 also means dumping all. */
182 flags
|= DUMP_VINSN_ALL
;
186 if (flags
& DUMP_VINSN_INSN_RTX
)
187 dump_insn_rtx_1 (VINSN_INSN_RTX (vi
), dump_insn_rtx_flags
| all
);
189 if (flags
& DUMP_VINSN_TYPE
)
190 sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi
)));
192 if (flags
& DUMP_VINSN_COUNT
)
193 sel_print ("count:%d;", VINSN_COUNT (vi
));
195 if (flags
& DUMP_VINSN_COST
)
200 sel_print ("cost:%d;", cost
);
206 /* Dump vinsn VI with default flags. */
208 dump_vinsn (vinsn_t vi
)
210 dump_vinsn_1 (vi
, dump_vinsn_flags
);
214 debug (vinsn_def
&ref
)
216 switch_dump (stderr
);
217 dump_vinsn_1 (&ref
, dump_vinsn_flags
);
223 debug (vinsn_def
*ptr
)
228 fprintf (stderr
, "<nil>\n");
232 debug_verbose (vinsn_def
&ref
)
234 switch_dump (stderr
);
235 dump_vinsn_1 (&ref
, debug_vinsn_flags
);
241 debug_verbose (vinsn_def
*ptr
)
246 fprintf (stderr
, "<nil>\n");
249 /* Dump vinsn VI to stderr. */
251 debug_vinsn (vinsn_t vi
)
253 switch_dump (stderr
);
254 dump_vinsn_1 (vi
, debug_vinsn_flags
);
259 /* Dump EXPR honoring flags. */
261 dump_expr_1 (expr_t expr
, int flags
)
265 /* flags == -1 also means dumping all. */
268 flags
|= DUMP_EXPR_ALL
;
272 if (flags
& DUMP_EXPR_VINSN
)
273 dump_vinsn_1 (EXPR_VINSN (expr
), dump_vinsn_flags
| all
);
275 if (flags
& DUMP_EXPR_SPEC
)
277 int spec
= EXPR_SPEC (expr
);
280 sel_print ("spec:%d;", spec
);
283 if (flags
& DUMP_EXPR_USEFULNESS
)
285 int use
= EXPR_USEFULNESS (expr
);
287 if (use
!= REG_BR_PROB_BASE
)
288 sel_print ("use:%d;", use
);
291 if (flags
& DUMP_EXPR_PRIORITY
)
292 sel_print ("prio:%d;", EXPR_PRIORITY (expr
));
294 if (flags
& DUMP_EXPR_SCHED_TIMES
)
296 int times
= EXPR_SCHED_TIMES (expr
);
299 sel_print ("times:%d;", times
);
302 if (flags
& DUMP_EXPR_SPEC_DONE_DS
)
304 ds_t spec_done_ds
= EXPR_SPEC_DONE_DS (expr
);
306 if (spec_done_ds
!= 0)
307 sel_print ("ds:%d;", spec_done_ds
);
310 if (flags
& DUMP_EXPR_ORIG_BB
)
312 int orig_bb
= EXPR_ORIG_BB_INDEX (expr
);
315 sel_print ("orig_bb:%d;", orig_bb
);
318 if (EXPR_TARGET_AVAILABLE (expr
) < 1)
319 sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr
));
323 /* Dump expression EXPR with default flags. */
325 dump_expr (expr_t expr
)
327 dump_expr_1 (expr
, dump_expr_flags
);
330 /* Dump expression EXPR to stderr. */
332 debug_expr (expr_t expr
)
334 switch_dump (stderr
);
335 dump_expr_1 (expr
, debug_expr_flags
);
340 /* Dump expression REF. */
343 debug (expr_def
&ref
)
345 switch_dump (stderr
);
346 dump_expr_1 (&ref
, 0);
352 debug (expr_def
*ptr
)
357 fprintf (stderr
, "<nil>\n");
360 /* Dump expression REF verbosely. */
363 debug_verbose (expr_def
&ref
)
365 switch_dump (stderr
);
366 dump_expr_1 (&ref
, DUMP_EXPR_ALL
);
372 debug_verbose (expr_def
*ptr
)
375 debug_verbose (*ptr
);
377 fprintf (stderr
, "<nil>\n");
380 /* Dump insn I honoring FLAGS. */
382 dump_insn_1 (insn_t i
, int flags
)
388 flags
|= DUMP_INSN_ALL
;
390 if (!sched_dump_to_dot_p
)
393 if (flags
& DUMP_INSN_EXPR
)
395 dump_expr_1 (INSN_EXPR (i
), dump_expr_flags
| all
);
398 else if (flags
& DUMP_INSN_PATTERN
)
400 dump_insn_rtx_1 (i
, DUMP_INSN_RTX_PATTERN
| all
);
403 else if (flags
& DUMP_INSN_UID
)
404 sel_print ("uid:%d;", INSN_UID (i
));
406 if (flags
& DUMP_INSN_SEQNO
)
407 sel_print ("seqno:%d;", INSN_SEQNO (i
));
409 if (flags
& DUMP_INSN_SCHED_CYCLE
)
411 int cycle
= INSN_SCHED_CYCLE (i
);
414 sel_print ("cycle:%d;", cycle
);
417 if (!sched_dump_to_dot_p
)
421 /* Dump insn I with default flags. */
425 dump_insn_1 (i
, DUMP_INSN_EXPR
| DUMP_INSN_SCHED_CYCLE
);
428 /* Dump INSN to stderr. */
430 debug_insn (insn_t insn
)
432 switch_dump (stderr
);
433 dump_insn_1 (insn
, debug_insn_flags
);
438 /* Dumps av_set AV. */
440 dump_av_set (av_set_t av
)
445 if (!sched_dump_to_dot_p
)
448 FOR_EACH_EXPR (expr
, i
, av
)
451 if (!sched_dump_to_dot_p
)
457 if (!sched_dump_to_dot_p
)
461 /* Dumps lvset LV. */
463 dump_lv_set (regset lv
)
467 /* This code was adapted from cfg.c: dump_regset (). */
473 reg_set_iterator rsi
;
476 EXECUTE_IF_SET_IN_REG_SET (lv
, 0, i
, rsi
)
478 sel_print (" %d", i
);
479 if (i
< FIRST_PSEUDO_REGISTER
)
481 sel_print (" [%s]", reg_names
[i
]);
487 if (sched_dump_to_dot_p
&& count
== 12)
498 /* Dumps a list of instructions pointed to by P. */
500 dump_ilist (ilist_t p
)
504 dump_insn (ILIST_INSN (p
));
509 /* Dumps a list of boundaries pointed to by BNDS. */
511 dump_blist (blist_t bnds
)
513 for (; bnds
; bnds
= BLIST_NEXT (bnds
))
515 bnd_t bnd
= BLIST_BND (bnds
);
517 sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd
)));
518 dump_ilist (BND_PTR (bnd
));
523 /* Dumps a list of fences pointed to by L. */
525 dump_flist (flist_t l
)
529 dump_insn_1 (FENCE_INSN (FLIST_FENCE (l
)), dump_flist_insn_flags
);
535 /* Dumps an insn vector SUCCS. */
537 dump_insn_vector (rtx_vec_t succs
)
542 FOR_EACH_VEC_ELT (succs
, i
, succ
)
549 /* Dumps a hard reg set SET to FILE using PREFIX. */
551 print_hard_reg_set (FILE *file
, const char *prefix
, HARD_REG_SET set
)
555 fprintf (file
, "%s{ ", prefix
);
556 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
558 if (TEST_HARD_REG_BIT (set
, i
))
559 fprintf (file
, "%d ", i
);
561 fprintf (file
, "}\n");
564 /* Dumps a hard reg set SET using PREFIX. */
566 dump_hard_reg_set (const char *prefix
, HARD_REG_SET set
)
568 print_hard_reg_set (sched_dump
, prefix
, set
);
571 /* Pretty print INSN. This is used as a hook. */
573 sel_print_insn (const rtx_insn
*insn
, int aligned ATTRIBUTE_UNUSED
)
577 /* '+' before insn means it is a new cycle start and it's not been
578 scheduled yet. '>' - has been scheduled. */
579 if (s_i_d
.exists () && INSN_LUID (insn
) > 0)
580 if (GET_MODE (insn
) == TImode
)
581 sprintf (buf
, "%s %4d",
582 INSN_SCHED_TIMES (insn
) > 0 ? "> " : "< ",
585 sprintf (buf
, "%s %4d",
586 INSN_SCHED_TIMES (insn
) > 0 ? "! " : " ",
589 if (GET_MODE (insn
) == TImode
)
590 sprintf (buf
, "+ %4d", INSN_UID (insn
));
592 sprintf (buf
, " %4d", INSN_UID (insn
));
598 /* Functions for pretty printing of CFG. */
599 /* FIXME: Using pretty-print here could simplify this stuff. */
601 /* Replace all occurencies of STR1 to STR2 in BUF.
602 The BUF must be large enough to hold the result. */
604 replace_str_in_buf (char *buf
, const char *str1
, const char *str2
)
606 int buf_len
= strlen (buf
);
607 int str1_len
= strlen (str1
);
608 int str2_len
= strlen (str2
);
609 int diff
= str2_len
- str1_len
;
614 p
= strstr (p
, str1
);
617 char *p1
= p
+ str1_len
;
618 /* Copy the rest of buf and '\0'. */
619 int n
= buf
+ buf_len
- p1
;
622 /* Shift str by DIFF chars. */
624 for (i
= n
; i
>= 0; i
--)
625 p1
[i
+ diff
] = p1
[i
];
627 for (i
= 0; i
<= n
; i
++)
628 p1
[i
+ diff
] = p1
[i
];
631 for (i
= 0; i
< str2_len
; i
++)
642 /* Replace characters in BUF that have special meaning in .dot file.
643 Similar to pp_write_text_as_dot_label_to_stream. */
645 sel_prepare_string_for_dot_label (char *buf
)
647 static char specials_from
[7][2] = { "<", ">", "{", "|", "}", "\"",
649 static char specials_to
[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}",
653 for (i
= 0; i
< 7; i
++)
654 replace_str_in_buf (buf
, specials_from
[i
], specials_to
[i
]);
657 /* This function acts like printf but dumps to the sched_dump file. */
659 sel_print (const char *fmt
, ...)
663 if (sched_dump_to_dot_p
)
666 if (vasprintf (&message
, fmt
, ap
) >= 0 && message
!= NULL
)
668 message
= (char *) xrealloc (message
, 2 * strlen (message
) + 1);
669 sel_prepare_string_for_dot_label (message
);
670 fprintf (sched_dump
, "%s", message
);
675 vfprintf (sched_dump
, fmt
, ap
);
679 /* Dump INSN with FLAGS. */
681 sel_dump_cfg_insn (insn_t insn
, int flags
)
683 int insn_flags
= DUMP_INSN_UID
| DUMP_INSN_PATTERN
;
685 if (sched_luids
.exists () && INSN_LUID (insn
) > 0)
687 if (flags
& SEL_DUMP_CFG_INSN_SEQNO
)
688 insn_flags
|= DUMP_INSN_SEQNO
| DUMP_INSN_SCHED_CYCLE
| DUMP_INSN_EXPR
;
691 dump_insn_1 (insn
, insn_flags
);
694 /* Dump E to the dot file F. */
696 sel_dump_cfg_edge (FILE *f
, edge e
)
701 if (e
->flags
& EDGE_FALLTHRU
)
704 color
= ", color = red";
706 else if (e
->src
->next_bb
== e
->dest
)
709 color
= ", color = blue";
717 fprintf (f
, "\tbb%d -> bb%d [weight = %d%s];\n",
718 e
->src
->index
, e
->dest
->index
, w
, color
);
722 /* Return true if BB has a predesessor from current region.
723 TODO: Either make this function to trace back through empty block
724 or just remove those empty blocks. */
726 has_preds_in_current_region_p (basic_block bb
)
731 gcc_assert (!in_current_region_p (bb
));
733 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
734 if (in_current_region_p (e
->src
))
740 /* Dump a cfg region to the dot file F honoring FLAGS. */
742 sel_dump_cfg_2 (FILE *f
, int flags
)
746 sched_dump_to_dot_p
= true;
749 fprintf (f
, "digraph G {\n"
751 "\tnode [shape = record, fontsize = 9];\n");
753 if (flags
& SEL_DUMP_CFG_FUNCTION_NAME
)
754 fprintf (f
, "function [label = \"%s\"];\n", current_function_name ());
756 FOR_EACH_BB_FN (bb
, cfun
)
758 insn_t insn
= BB_HEAD (bb
);
759 insn_t next_tail
= NEXT_INSN (BB_END (bb
));
762 bool in_region_p
= ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
763 && in_current_region_p (bb
));
764 bool full_p
= (!(flags
& SEL_DUMP_CFG_CURRENT_REGION
)
766 bool some_p
= full_p
|| has_preds_in_current_region_p (bb
);
773 if ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
774 && in_current_region_p (bb
)
775 && BLOCK_TO_BB (bb
->index
) == 0)
776 color
= "color = green, ";
780 if ((flags
& SEL_DUMP_CFG_FENCES
)
785 if (!sel_bb_empty_p (bb
))
788 insn_t tail
= BB_END (bb
);
791 cur_insn
= bb_note (bb
);
797 cur_insn
= NEXT_INSN (cur_insn
);
798 fence
= flist_lookup (fences
, cur_insn
);
802 if (!FENCE_SCHEDULED_P (fence
))
805 color
= "color = red, ";
807 color
= "color = yellow, ";
810 color
= "color = blue, ";
815 while (cur_insn
!= tail
);
819 style
= "style = dashed, ";
823 fprintf (f
, "\tbb%d [%s%slabel = \"{Basic block %d", bb
->index
,
824 style
, color
, bb
->index
);
826 if ((flags
& SEL_DUMP_CFG_BB_LOOP
)
827 && bb
->loop_father
!= NULL
)
828 fprintf (f
, ", loop %d", bb
->loop_father
->num
);
831 && (flags
& SEL_DUMP_CFG_BB_NOTES_LIST
))
833 insn_t notes
= BB_NOTE_LIST (bb
);
835 if (notes
!= NULL_RTX
)
839 /* For simplicity, we dump notes from note_list in reversed order
840 to that what they will appear in the code. */
841 while (notes
!= NULL_RTX
)
843 sel_dump_cfg_insn (notes
, flags
);
846 notes
= PREV_INSN (notes
);
852 && (flags
& SEL_DUMP_CFG_AV_SET
)
853 && in_current_region_p (bb
)
854 && !sel_bb_empty_p (bb
))
858 if (BB_AV_SET_VALID_P (bb
))
859 dump_av_set (BB_AV_SET (bb
));
860 else if (BB_AV_LEVEL (bb
) == -1)
861 fprintf (f
, "AV_SET needs update");
864 if ((flags
& SEL_DUMP_CFG_LV_SET
)
865 && !sel_bb_empty_p (bb
))
869 if (BB_LV_SET_VALID_P (bb
))
870 dump_lv_set (BB_LV_SET (bb
));
872 fprintf (f
, "LV_SET needs update");
876 && (flags
& SEL_DUMP_CFG_BB_INSNS
))
879 while (insn
!= next_tail
)
881 sel_dump_cfg_insn (insn
, flags
);
884 insn
= NEXT_INSN (insn
);
888 fprintf (f
, "}\"];\n");
890 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
891 if (full_p
|| in_current_region_p (e
->dest
))
892 sel_dump_cfg_edge (f
, e
);
898 sched_dump_to_dot_p
= false;
901 /* Dump a cfg region to the file specified by TAG honoring flags.
902 The file is created by the function. */
904 sel_dump_cfg_1 (const char *tag
, int flags
)
910 ++sel_dump_cfg_fileno
;
915 i
= 1 + snprintf (NULL
, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
916 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
917 buf
= XNEWVEC (char, i
);
918 snprintf (buf
, i
, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
919 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
921 f
= fopen (buf
, "w");
924 fprintf (stderr
, "Can't create file: %s.\n", buf
);
927 sel_dump_cfg_2 (f
, flags
);
935 /* Setup cfg dumping flags. Used for debugging. */
937 setup_dump_cfg_params (void)
939 sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
941 sel_debug_cfg_root_postfix
= sel_debug_cfg_root_postfix_default
;
944 /* Debug a cfg region with FLAGS. */
946 sel_debug_cfg_1 (int flags
)
948 bool t1
= sel_dump_cfg_p
;
949 int t2
= sel_dump_cfg_fileno
;
951 sel_dump_cfg_p
= true;
952 sel_dump_cfg_fileno
= ++sel_debug_cfg_fileno
;
954 sel_dump_cfg_1 ("sel-debug-cfg", flags
);
956 sel_dump_cfg_fileno
= t2
;
960 /* Dumps av_set AV to stderr. */
962 debug_av_set (av_set_t av
)
964 switch_dump (stderr
);
970 /* Dump LV to stderr. */
972 debug_lv_set (regset lv
)
974 switch_dump (stderr
);
980 /* Dump an instruction list P to stderr. */
982 debug_ilist (ilist_t p
)
984 switch_dump (stderr
);
990 /* Dump a boundary list BNDS to stderr. */
992 debug_blist (blist_t bnds
)
994 switch_dump (stderr
);
1000 /* Dump a rtx vector REF. */
1002 debug (vec
<rtx_insn
*> &ref
)
1004 switch_dump (stderr
);
1005 dump_insn_vector (ref
);
1011 debug (vec
<rtx_insn
*> *ptr
)
1016 fprintf (stderr
, "<nil>\n");
1019 /* Dump an insn vector SUCCS. */
1021 debug_insn_vector (rtx_vec_t succs
)
1023 switch_dump (stderr
);
1024 dump_insn_vector (succs
);
1029 /* Dump a hard reg set SET to stderr. */
1031 debug_hard_reg_set (HARD_REG_SET set
)
1033 switch_dump (stderr
);
1034 dump_hard_reg_set ("", set
);
1039 /* Debug a cfg region with default flags. */
1041 sel_debug_cfg (void)
1043 sel_debug_cfg_1 (sel_debug_cfg_flags
);
1046 /* Print a current cselib value for X's address to stderr. */
1048 debug_mem_addr_value (rtx x
)
1051 machine_mode address_mode
;
1053 gcc_assert (MEM_P (x
));
1054 address_mode
= get_address_mode (x
);
1056 t
= shallow_copy_rtx (x
);
1057 if (cselib_lookup (XEXP (t
, 0), address_mode
, 0, GET_MODE (t
)))
1058 XEXP (t
, 0) = cselib_subst_to_values (XEXP (t
, 0), GET_MODE (t
));
1061 addr
= get_addr (XEXP (t
, 0));