1 /* Instruction scheduling pass. Log dumping infrastructure.
2 Copyright (C) 2006-2014 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"
24 #include "diagnostic-core.h"
27 #include "hard-reg-set.h"
36 #include "insn-config.h"
37 #include "insn-attr.h"
39 #include "basic-block.h"
43 #ifdef INSN_SCHEDULING
44 #include "sel-sched-ir.h"
45 #include "sel-sched-dump.h"
48 /* These variables control high-level pretty printing. */
49 static int sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
50 static int sel_debug_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
52 /* True when a cfg should be dumped. */
53 static bool sel_dump_cfg_p
;
55 /* Variables that are used to build the cfg dump file name. */
56 static const char * const sel_debug_cfg_root
= "./";
57 static const char * const sel_debug_cfg_root_postfix_default
= "";
58 static const char *sel_debug_cfg_root_postfix
= "";
59 static int sel_dump_cfg_fileno
= -1;
60 static int sel_debug_cfg_fileno
= -1;
62 /* When this flag is on, we are dumping to the .dot file.
63 When it is off, we are dumping to log.
64 This is useful to differentiate formatting between log and .dot
66 bool sched_dump_to_dot_p
= false;
68 /* Controls how insns from a fence list should be dumped. */
69 static int dump_flist_insn_flags
= (DUMP_INSN_UID
| DUMP_INSN_BBN
73 /* The variable used to hold the value of sched_dump when temporarily
74 switching dump output to the other source, e.g. the .dot file. */
75 static FILE *saved_sched_dump
= NULL
;
77 /* Switch sched_dump to TO. It must not be called twice. */
79 switch_dump (FILE *to
)
81 gcc_assert (saved_sched_dump
== NULL
);
83 saved_sched_dump
= sched_dump
;
87 /* Restore previously switched dump. */
91 sched_dump
= saved_sched_dump
;
92 saved_sched_dump
= NULL
;
96 /* Functions for dumping instructions, av sets, and exprs. */
98 /* Default flags for dumping insns. */
99 static int dump_insn_rtx_flags
= DUMP_INSN_RTX_UID
| DUMP_INSN_RTX_PATTERN
;
101 /* Default flags for dumping vinsns. */
102 static int dump_vinsn_flags
= (DUMP_VINSN_INSN_RTX
| DUMP_VINSN_TYPE
105 /* Default flags for dumping expressions. */
106 static int dump_expr_flags
= DUMP_EXPR_ALL
;
108 /* Default flags for dumping insns when debugging. */
109 static int debug_insn_rtx_flags
= DUMP_INSN_RTX_ALL
;
111 /* Default flags for dumping vinsns when debugging. */
112 static int debug_vinsn_flags
= DUMP_VINSN_ALL
;
114 /* Default flags for dumping expressions when debugging. */
115 static int debug_expr_flags
= DUMP_EXPR_ALL
;
117 /* Controls how an insn from stream should be dumped when debugging. */
118 static int debug_insn_flags
= DUMP_INSN_ALL
;
120 /* Print an rtx X. */
122 sel_print_rtl (rtx x
)
124 print_rtl_single (sched_dump
, x
);
127 /* Dump insn INSN honoring FLAGS. */
129 dump_insn_rtx_1 (rtx insn
, int flags
)
133 /* flags == -1 also means dumping all. */
136 flags
|= DUMP_INSN_RTX_ALL
;
140 if (flags
& DUMP_INSN_RTX_UID
)
141 sel_print ("%d;", INSN_UID (insn
));
143 if (flags
& DUMP_INSN_RTX_PATTERN
)
144 sel_print ("%s;", str_pattern_slim (PATTERN (insn
)));
146 if (flags
& DUMP_INSN_RTX_BBN
)
148 basic_block bb
= BLOCK_FOR_INSN (insn
);
150 sel_print ("bb:%d;", bb
!= NULL
? bb
->index
: -1);
157 /* Dump INSN with default flags. */
159 dump_insn_rtx (rtx insn
)
161 dump_insn_rtx_1 (insn
, dump_insn_rtx_flags
);
165 /* Dump INSN to stderr. */
167 debug_insn_rtx (rtx insn
)
169 switch_dump (stderr
);
170 dump_insn_rtx_1 (insn
, debug_insn_rtx_flags
);
175 /* Dump vinsn VI honoring flags. */
177 dump_vinsn_1 (vinsn_t vi
, int flags
)
181 /* flags == -1 also means dumping all. */
184 flags
|= DUMP_VINSN_ALL
;
188 if (flags
& DUMP_VINSN_INSN_RTX
)
189 dump_insn_rtx_1 (VINSN_INSN_RTX (vi
), dump_insn_rtx_flags
| all
);
191 if (flags
& DUMP_VINSN_TYPE
)
192 sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi
)));
194 if (flags
& DUMP_VINSN_COUNT
)
195 sel_print ("count:%d;", VINSN_COUNT (vi
));
197 if (flags
& DUMP_VINSN_COST
)
202 sel_print ("cost:%d;", cost
);
208 /* Dump vinsn VI with default flags. */
210 dump_vinsn (vinsn_t vi
)
212 dump_vinsn_1 (vi
, dump_vinsn_flags
);
216 debug (vinsn_def
&ref
)
218 switch_dump (stderr
);
219 dump_vinsn_1 (&ref
, dump_vinsn_flags
);
225 debug (vinsn_def
*ptr
)
230 fprintf (stderr
, "<nil>\n");
234 debug_verbose (vinsn_def
&ref
)
236 switch_dump (stderr
);
237 dump_vinsn_1 (&ref
, debug_vinsn_flags
);
243 debug_verbose (vinsn_def
*ptr
)
248 fprintf (stderr
, "<nil>\n");
251 /* Dump vinsn VI to stderr. */
253 debug_vinsn (vinsn_t vi
)
255 switch_dump (stderr
);
256 dump_vinsn_1 (vi
, debug_vinsn_flags
);
261 /* Dump EXPR honoring flags. */
263 dump_expr_1 (expr_t expr
, int flags
)
267 /* flags == -1 also means dumping all. */
270 flags
|= DUMP_EXPR_ALL
;
274 if (flags
& DUMP_EXPR_VINSN
)
275 dump_vinsn_1 (EXPR_VINSN (expr
), dump_vinsn_flags
| all
);
277 if (flags
& DUMP_EXPR_SPEC
)
279 int spec
= EXPR_SPEC (expr
);
282 sel_print ("spec:%d;", spec
);
285 if (flags
& DUMP_EXPR_USEFULNESS
)
287 int use
= EXPR_USEFULNESS (expr
);
289 if (use
!= REG_BR_PROB_BASE
)
290 sel_print ("use:%d;", use
);
293 if (flags
& DUMP_EXPR_PRIORITY
)
294 sel_print ("prio:%d;", EXPR_PRIORITY (expr
));
296 if (flags
& DUMP_EXPR_SCHED_TIMES
)
298 int times
= EXPR_SCHED_TIMES (expr
);
301 sel_print ("times:%d;", times
);
304 if (flags
& DUMP_EXPR_SPEC_DONE_DS
)
306 ds_t spec_done_ds
= EXPR_SPEC_DONE_DS (expr
);
308 if (spec_done_ds
!= 0)
309 sel_print ("ds:%d;", spec_done_ds
);
312 if (flags
& DUMP_EXPR_ORIG_BB
)
314 int orig_bb
= EXPR_ORIG_BB_INDEX (expr
);
317 sel_print ("orig_bb:%d;", orig_bb
);
320 if (EXPR_TARGET_AVAILABLE (expr
) < 1)
321 sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr
));
325 /* Dump expression EXPR with default flags. */
327 dump_expr (expr_t expr
)
329 dump_expr_1 (expr
, dump_expr_flags
);
332 /* Dump expression EXPR to stderr. */
334 debug_expr (expr_t expr
)
336 switch_dump (stderr
);
337 dump_expr_1 (expr
, debug_expr_flags
);
342 /* Dump expression REF. */
345 debug (expr_def
&ref
)
347 switch_dump (stderr
);
348 dump_expr_1 (&ref
, 0);
354 debug (expr_def
*ptr
)
359 fprintf (stderr
, "<nil>\n");
362 /* Dump expression REF verbosely. */
365 debug_verbose (expr_def
&ref
)
367 switch_dump (stderr
);
368 dump_expr_1 (&ref
, DUMP_EXPR_ALL
);
374 debug_verbose (expr_def
*ptr
)
377 debug_verbose (*ptr
);
379 fprintf (stderr
, "<nil>\n");
382 /* Dump insn I honoring FLAGS. */
384 dump_insn_1 (insn_t i
, int flags
)
390 flags
|= DUMP_INSN_ALL
;
392 if (!sched_dump_to_dot_p
)
395 if (flags
& DUMP_INSN_EXPR
)
397 dump_expr_1 (INSN_EXPR (i
), dump_expr_flags
| all
);
400 else if (flags
& DUMP_INSN_PATTERN
)
402 dump_insn_rtx_1 (i
, DUMP_INSN_RTX_PATTERN
| all
);
405 else if (flags
& DUMP_INSN_UID
)
406 sel_print ("uid:%d;", INSN_UID (i
));
408 if (flags
& DUMP_INSN_SEQNO
)
409 sel_print ("seqno:%d;", INSN_SEQNO (i
));
411 if (flags
& DUMP_INSN_SCHED_CYCLE
)
413 int cycle
= INSN_SCHED_CYCLE (i
);
416 sel_print ("cycle:%d;", cycle
);
419 if (!sched_dump_to_dot_p
)
423 /* Dump insn I with default flags. */
427 dump_insn_1 (i
, DUMP_INSN_EXPR
| DUMP_INSN_SCHED_CYCLE
);
430 /* Dump INSN to stderr. */
432 debug_insn (insn_t insn
)
434 switch_dump (stderr
);
435 dump_insn_1 (insn
, debug_insn_flags
);
440 /* Dumps av_set AV. */
442 dump_av_set (av_set_t av
)
447 if (!sched_dump_to_dot_p
)
450 FOR_EACH_EXPR (expr
, i
, av
)
453 if (!sched_dump_to_dot_p
)
459 if (!sched_dump_to_dot_p
)
463 /* Dumps lvset LV. */
465 dump_lv_set (regset lv
)
469 /* This code was adapted from cfg.c: dump_regset (). */
475 reg_set_iterator rsi
;
478 EXECUTE_IF_SET_IN_REG_SET (lv
, 0, i
, rsi
)
480 sel_print (" %d", i
);
481 if (i
< FIRST_PSEUDO_REGISTER
)
483 sel_print (" [%s]", reg_names
[i
]);
489 if (sched_dump_to_dot_p
&& count
== 12)
500 /* Dumps a list of instructions pointed to by P. */
502 dump_ilist (ilist_t p
)
506 dump_insn (ILIST_INSN (p
));
511 /* Dumps a list of boundaries pointed to by BNDS. */
513 dump_blist (blist_t bnds
)
515 for (; bnds
; bnds
= BLIST_NEXT (bnds
))
517 bnd_t bnd
= BLIST_BND (bnds
);
519 sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd
)));
520 dump_ilist (BND_PTR (bnd
));
525 /* Dumps a list of fences pointed to by L. */
527 dump_flist (flist_t l
)
531 dump_insn_1 (FENCE_INSN (FLIST_FENCE (l
)), dump_flist_insn_flags
);
537 /* Dumps an insn vector SUCCS. */
539 dump_insn_vector (rtx_vec_t succs
)
544 FOR_EACH_VEC_ELT (succs
, i
, succ
)
551 /* Dumps a hard reg set SET to FILE using PREFIX. */
553 print_hard_reg_set (FILE *file
, const char *prefix
, HARD_REG_SET set
)
557 fprintf (file
, "%s{ ", prefix
);
558 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
560 if (TEST_HARD_REG_BIT (set
, i
))
561 fprintf (file
, "%d ", i
);
563 fprintf (file
, "}\n");
566 /* Dumps a hard reg set SET using PREFIX. */
568 dump_hard_reg_set (const char *prefix
, HARD_REG_SET set
)
570 print_hard_reg_set (sched_dump
, prefix
, set
);
573 /* Pretty print INSN. This is used as a hook. */
575 sel_print_insn (const rtx_insn
*insn
, int aligned ATTRIBUTE_UNUSED
)
579 /* '+' before insn means it is a new cycle start and it's not been
580 scheduled yet. '>' - has been scheduled. */
581 if (s_i_d
.exists () && INSN_LUID (insn
) > 0)
582 if (GET_MODE (insn
) == TImode
)
583 sprintf (buf
, "%s %4d",
584 INSN_SCHED_TIMES (insn
) > 0 ? "> " : "< ",
587 sprintf (buf
, "%s %4d",
588 INSN_SCHED_TIMES (insn
) > 0 ? "! " : " ",
591 if (GET_MODE (insn
) == TImode
)
592 sprintf (buf
, "+ %4d", INSN_UID (insn
));
594 sprintf (buf
, " %4d", INSN_UID (insn
));
600 /* Functions for pretty printing of CFG. */
601 /* FIXME: Using pretty-print here could simplify this stuff. */
603 /* Replace all occurencies of STR1 to STR2 in BUF.
604 The BUF must be large enough to hold the result. */
606 replace_str_in_buf (char *buf
, const char *str1
, const char *str2
)
608 int buf_len
= strlen (buf
);
609 int str1_len
= strlen (str1
);
610 int str2_len
= strlen (str2
);
611 int diff
= str2_len
- str1_len
;
616 p
= strstr (p
, str1
);
619 char *p1
= p
+ str1_len
;
620 /* Copy the rest of buf and '\0'. */
621 int n
= buf
+ buf_len
- p1
;
624 /* Shift str by DIFF chars. */
626 for (i
= n
; i
>= 0; i
--)
627 p1
[i
+ diff
] = p1
[i
];
629 for (i
= 0; i
<= n
; i
++)
630 p1
[i
+ diff
] = p1
[i
];
633 for (i
= 0; i
< str2_len
; i
++)
644 /* Replace characters in BUF that have special meaning in .dot file.
645 Similar to pp_write_text_as_dot_label_to_stream. */
647 sel_prepare_string_for_dot_label (char *buf
)
649 static char specials_from
[7][2] = { "<", ">", "{", "|", "}", "\"",
651 static char specials_to
[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}",
655 for (i
= 0; i
< 7; i
++)
656 replace_str_in_buf (buf
, specials_from
[i
], specials_to
[i
]);
659 /* This function acts like printf but dumps to the sched_dump file. */
661 sel_print (const char *fmt
, ...)
665 if (sched_dump_to_dot_p
)
668 if (vasprintf (&message
, fmt
, ap
) >= 0 && message
!= NULL
)
670 message
= (char *) xrealloc (message
, 2 * strlen (message
) + 1);
671 sel_prepare_string_for_dot_label (message
);
672 fprintf (sched_dump
, "%s", message
);
677 vfprintf (sched_dump
, fmt
, ap
);
681 /* Dump INSN with FLAGS. */
683 sel_dump_cfg_insn (insn_t insn
, int flags
)
685 int insn_flags
= DUMP_INSN_UID
| DUMP_INSN_PATTERN
;
687 if (sched_luids
.exists () && INSN_LUID (insn
) > 0)
689 if (flags
& SEL_DUMP_CFG_INSN_SEQNO
)
690 insn_flags
|= DUMP_INSN_SEQNO
| DUMP_INSN_SCHED_CYCLE
| DUMP_INSN_EXPR
;
693 dump_insn_1 (insn
, insn_flags
);
696 /* Dump E to the dot file F. */
698 sel_dump_cfg_edge (FILE *f
, edge e
)
703 if (e
->flags
& EDGE_FALLTHRU
)
706 color
= ", color = red";
708 else if (e
->src
->next_bb
== e
->dest
)
711 color
= ", color = blue";
719 fprintf (f
, "\tbb%d -> bb%d [weight = %d%s];\n",
720 e
->src
->index
, e
->dest
->index
, w
, color
);
724 /* Return true if BB has a predesessor from current region.
725 TODO: Either make this function to trace back through empty block
726 or just remove those empty blocks. */
728 has_preds_in_current_region_p (basic_block bb
)
733 gcc_assert (!in_current_region_p (bb
));
735 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
736 if (in_current_region_p (e
->src
))
742 /* Dump a cfg region to the dot file F honoring FLAGS. */
744 sel_dump_cfg_2 (FILE *f
, int flags
)
748 sched_dump_to_dot_p
= true;
751 fprintf (f
, "digraph G {\n"
753 "\tnode [shape = record, fontsize = 9];\n");
755 if (flags
& SEL_DUMP_CFG_FUNCTION_NAME
)
756 fprintf (f
, "function [label = \"%s\"];\n", current_function_name ());
758 FOR_EACH_BB_FN (bb
, cfun
)
760 insn_t insn
= BB_HEAD (bb
);
761 insn_t next_tail
= NEXT_INSN (BB_END (bb
));
764 bool in_region_p
= ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
765 && in_current_region_p (bb
));
766 bool full_p
= (!(flags
& SEL_DUMP_CFG_CURRENT_REGION
)
768 bool some_p
= full_p
|| has_preds_in_current_region_p (bb
);
775 if ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
776 && in_current_region_p (bb
)
777 && BLOCK_TO_BB (bb
->index
) == 0)
778 color
= "color = green, ";
782 if ((flags
& SEL_DUMP_CFG_FENCES
)
787 if (!sel_bb_empty_p (bb
))
790 insn_t tail
= BB_END (bb
);
793 cur_insn
= bb_note (bb
);
799 cur_insn
= NEXT_INSN (cur_insn
);
800 fence
= flist_lookup (fences
, cur_insn
);
804 if (!FENCE_SCHEDULED_P (fence
))
807 color
= "color = red, ";
809 color
= "color = yellow, ";
812 color
= "color = blue, ";
817 while (cur_insn
!= tail
);
821 style
= "style = dashed, ";
825 fprintf (f
, "\tbb%d [%s%slabel = \"{Basic block %d", bb
->index
,
826 style
, color
, bb
->index
);
828 if ((flags
& SEL_DUMP_CFG_BB_LOOP
)
829 && bb
->loop_father
!= NULL
)
830 fprintf (f
, ", loop %d", bb
->loop_father
->num
);
833 && (flags
& SEL_DUMP_CFG_BB_NOTES_LIST
))
835 insn_t notes
= BB_NOTE_LIST (bb
);
837 if (notes
!= NULL_RTX
)
841 /* For simplicity, we dump notes from note_list in reversed order
842 to that what they will appear in the code. */
843 while (notes
!= NULL_RTX
)
845 sel_dump_cfg_insn (notes
, flags
);
848 notes
= PREV_INSN (notes
);
854 && (flags
& SEL_DUMP_CFG_AV_SET
)
855 && in_current_region_p (bb
)
856 && !sel_bb_empty_p (bb
))
860 if (BB_AV_SET_VALID_P (bb
))
861 dump_av_set (BB_AV_SET (bb
));
862 else if (BB_AV_LEVEL (bb
) == -1)
863 fprintf (f
, "AV_SET needs update");
866 if ((flags
& SEL_DUMP_CFG_LV_SET
)
867 && !sel_bb_empty_p (bb
))
871 if (BB_LV_SET_VALID_P (bb
))
872 dump_lv_set (BB_LV_SET (bb
));
874 fprintf (f
, "LV_SET needs update");
878 && (flags
& SEL_DUMP_CFG_BB_INSNS
))
881 while (insn
!= next_tail
)
883 sel_dump_cfg_insn (insn
, flags
);
886 insn
= NEXT_INSN (insn
);
890 fprintf (f
, "}\"];\n");
892 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
893 if (full_p
|| in_current_region_p (e
->dest
))
894 sel_dump_cfg_edge (f
, e
);
900 sched_dump_to_dot_p
= false;
903 /* Dump a cfg region to the file specified by TAG honoring flags.
904 The file is created by the function. */
906 sel_dump_cfg_1 (const char *tag
, int flags
)
912 ++sel_dump_cfg_fileno
;
917 i
= 1 + snprintf (NULL
, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
918 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
919 buf
= XNEWVEC (char, i
);
920 snprintf (buf
, i
, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
921 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
923 f
= fopen (buf
, "w");
926 fprintf (stderr
, "Can't create file: %s.\n", buf
);
929 sel_dump_cfg_2 (f
, flags
);
937 /* Setup cfg dumping flags. Used for debugging. */
939 setup_dump_cfg_params (void)
941 sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
943 sel_debug_cfg_root_postfix
= sel_debug_cfg_root_postfix_default
;
946 /* Debug a cfg region with FLAGS. */
948 sel_debug_cfg_1 (int flags
)
950 bool t1
= sel_dump_cfg_p
;
951 int t2
= sel_dump_cfg_fileno
;
953 sel_dump_cfg_p
= true;
954 sel_dump_cfg_fileno
= ++sel_debug_cfg_fileno
;
956 sel_dump_cfg_1 ("sel-debug-cfg", flags
);
958 sel_dump_cfg_fileno
= t2
;
962 /* Dumps av_set AV to stderr. */
964 debug_av_set (av_set_t av
)
966 switch_dump (stderr
);
972 /* Dump LV to stderr. */
974 debug_lv_set (regset lv
)
976 switch_dump (stderr
);
982 /* Dump an instruction list P to stderr. */
984 debug_ilist (ilist_t p
)
986 switch_dump (stderr
);
992 /* Dump a boundary list BNDS to stderr. */
994 debug_blist (blist_t bnds
)
996 switch_dump (stderr
);
1002 /* Dump a rtx vector REF. */
1004 debug (vec
<rtx_insn
*> &ref
)
1006 switch_dump (stderr
);
1007 dump_insn_vector (ref
);
1013 debug (vec
<rtx_insn
*> *ptr
)
1018 fprintf (stderr
, "<nil>\n");
1021 /* Dump an insn vector SUCCS. */
1023 debug_insn_vector (rtx_vec_t succs
)
1025 switch_dump (stderr
);
1026 dump_insn_vector (succs
);
1031 /* Dump a hard reg set SET to stderr. */
1033 debug_hard_reg_set (HARD_REG_SET set
)
1035 switch_dump (stderr
);
1036 dump_hard_reg_set ("", set
);
1041 /* Debug a cfg region with default flags. */
1043 sel_debug_cfg (void)
1045 sel_debug_cfg_1 (sel_debug_cfg_flags
);
1048 /* Print a current cselib value for X's address to stderr. */
1050 debug_mem_addr_value (rtx x
)
1053 enum machine_mode address_mode
;
1055 gcc_assert (MEM_P (x
));
1056 address_mode
= get_address_mode (x
);
1058 t
= shallow_copy_rtx (x
);
1059 if (cselib_lookup (XEXP (t
, 0), address_mode
, 0, GET_MODE (t
)))
1060 XEXP (t
, 0) = cselib_subst_to_values (XEXP (t
, 0), GET_MODE (t
));
1063 addr
= get_addr (XEXP (t
, 0));