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"
24 #include "diagnostic-core.h"
27 #include "hard-reg-set.h"
31 #include "dominance.h"
33 #include "basic-block.h"
35 #include "insn-config.h"
36 #include "insn-attr.h"
38 #include "alloc-pool.h"
42 #ifdef INSN_SCHEDULING
43 #include "sel-sched-ir.h"
44 #include "sel-sched-dump.h"
47 /* These variables control high-level pretty printing. */
48 static int sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
49 static int sel_debug_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
51 /* True when a cfg should be dumped. */
52 static bool sel_dump_cfg_p
;
54 /* Variables that are used to build the cfg dump file name. */
55 static const char * const sel_debug_cfg_root
= "./";
56 static const char * const sel_debug_cfg_root_postfix_default
= "";
57 static const char *sel_debug_cfg_root_postfix
= "";
58 static int sel_dump_cfg_fileno
= -1;
59 static int sel_debug_cfg_fileno
= -1;
61 /* When this flag is on, we are dumping to the .dot file.
62 When it is off, we are dumping to log.
63 This is useful to differentiate formatting between log and .dot
65 bool sched_dump_to_dot_p
= false;
67 /* Controls how insns from a fence list should be dumped. */
68 static int dump_flist_insn_flags
= (DUMP_INSN_UID
| DUMP_INSN_BBN
72 /* The variable used to hold the value of sched_dump when temporarily
73 switching dump output to the other source, e.g. the .dot file. */
74 static FILE *saved_sched_dump
= NULL
;
76 /* Switch sched_dump to TO. It must not be called twice. */
78 switch_dump (FILE *to
)
80 gcc_assert (saved_sched_dump
== NULL
);
82 saved_sched_dump
= sched_dump
;
86 /* Restore previously switched dump. */
90 sched_dump
= saved_sched_dump
;
91 saved_sched_dump
= NULL
;
95 /* Functions for dumping instructions, av sets, and exprs. */
97 /* Default flags for dumping insns. */
98 static int dump_insn_rtx_flags
= DUMP_INSN_RTX_UID
| DUMP_INSN_RTX_PATTERN
;
100 /* Default flags for dumping vinsns. */
101 static int dump_vinsn_flags
= (DUMP_VINSN_INSN_RTX
| DUMP_VINSN_TYPE
104 /* Default flags for dumping expressions. */
105 static int dump_expr_flags
= DUMP_EXPR_ALL
;
107 /* Default flags for dumping insns when debugging. */
108 static int debug_insn_rtx_flags
= DUMP_INSN_RTX_ALL
;
110 /* Default flags for dumping vinsns when debugging. */
111 static int debug_vinsn_flags
= DUMP_VINSN_ALL
;
113 /* Default flags for dumping expressions when debugging. */
114 static int debug_expr_flags
= DUMP_EXPR_ALL
;
116 /* Controls how an insn from stream should be dumped when debugging. */
117 static int debug_insn_flags
= DUMP_INSN_ALL
;
119 /* Print an rtx X. */
121 sel_print_rtl (rtx x
)
123 print_rtl_single (sched_dump
, x
);
126 /* Dump insn INSN honoring FLAGS. */
128 dump_insn_rtx_1 (rtx insn
, int flags
)
132 /* flags == -1 also means dumping all. */
135 flags
|= DUMP_INSN_RTX_ALL
;
139 if (flags
& DUMP_INSN_RTX_UID
)
140 sel_print ("%d;", INSN_UID (insn
));
142 if (flags
& DUMP_INSN_RTX_PATTERN
)
143 sel_print ("%s;", str_pattern_slim (PATTERN (insn
)));
145 if (flags
& DUMP_INSN_RTX_BBN
)
147 basic_block bb
= BLOCK_FOR_INSN (insn
);
149 sel_print ("bb:%d;", bb
!= NULL
? bb
->index
: -1);
156 /* Dump INSN with default flags. */
158 dump_insn_rtx (rtx insn
)
160 dump_insn_rtx_1 (insn
, dump_insn_rtx_flags
);
164 /* Dump INSN to stderr. */
166 debug_insn_rtx (rtx insn
)
168 switch_dump (stderr
);
169 dump_insn_rtx_1 (insn
, debug_insn_rtx_flags
);
174 /* Dump vinsn VI honoring flags. */
176 dump_vinsn_1 (vinsn_t vi
, int flags
)
180 /* flags == -1 also means dumping all. */
183 flags
|= DUMP_VINSN_ALL
;
187 if (flags
& DUMP_VINSN_INSN_RTX
)
188 dump_insn_rtx_1 (VINSN_INSN_RTX (vi
), dump_insn_rtx_flags
| all
);
190 if (flags
& DUMP_VINSN_TYPE
)
191 sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi
)));
193 if (flags
& DUMP_VINSN_COUNT
)
194 sel_print ("count:%d;", VINSN_COUNT (vi
));
196 if (flags
& DUMP_VINSN_COST
)
201 sel_print ("cost:%d;", cost
);
207 /* Dump vinsn VI with default flags. */
209 dump_vinsn (vinsn_t vi
)
211 dump_vinsn_1 (vi
, dump_vinsn_flags
);
215 debug (vinsn_def
&ref
)
217 switch_dump (stderr
);
218 dump_vinsn_1 (&ref
, dump_vinsn_flags
);
224 debug (vinsn_def
*ptr
)
229 fprintf (stderr
, "<nil>\n");
233 debug_verbose (vinsn_def
&ref
)
235 switch_dump (stderr
);
236 dump_vinsn_1 (&ref
, debug_vinsn_flags
);
242 debug_verbose (vinsn_def
*ptr
)
247 fprintf (stderr
, "<nil>\n");
250 /* Dump vinsn VI to stderr. */
252 debug_vinsn (vinsn_t vi
)
254 switch_dump (stderr
);
255 dump_vinsn_1 (vi
, debug_vinsn_flags
);
260 /* Dump EXPR honoring flags. */
262 dump_expr_1 (expr_t expr
, int flags
)
266 /* flags == -1 also means dumping all. */
269 flags
|= DUMP_EXPR_ALL
;
273 if (flags
& DUMP_EXPR_VINSN
)
274 dump_vinsn_1 (EXPR_VINSN (expr
), dump_vinsn_flags
| all
);
276 if (flags
& DUMP_EXPR_SPEC
)
278 int spec
= EXPR_SPEC (expr
);
281 sel_print ("spec:%d;", spec
);
284 if (flags
& DUMP_EXPR_USEFULNESS
)
286 int use
= EXPR_USEFULNESS (expr
);
288 if (use
!= REG_BR_PROB_BASE
)
289 sel_print ("use:%d;", use
);
292 if (flags
& DUMP_EXPR_PRIORITY
)
293 sel_print ("prio:%d;", EXPR_PRIORITY (expr
));
295 if (flags
& DUMP_EXPR_SCHED_TIMES
)
297 int times
= EXPR_SCHED_TIMES (expr
);
300 sel_print ("times:%d;", times
);
303 if (flags
& DUMP_EXPR_SPEC_DONE_DS
)
305 ds_t spec_done_ds
= EXPR_SPEC_DONE_DS (expr
);
307 if (spec_done_ds
!= 0)
308 sel_print ("ds:%d;", spec_done_ds
);
311 if (flags
& DUMP_EXPR_ORIG_BB
)
313 int orig_bb
= EXPR_ORIG_BB_INDEX (expr
);
316 sel_print ("orig_bb:%d;", orig_bb
);
319 if (EXPR_TARGET_AVAILABLE (expr
) < 1)
320 sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr
));
324 /* Dump expression EXPR with default flags. */
326 dump_expr (expr_t expr
)
328 dump_expr_1 (expr
, dump_expr_flags
);
331 /* Dump expression EXPR to stderr. */
333 debug_expr (expr_t expr
)
335 switch_dump (stderr
);
336 dump_expr_1 (expr
, debug_expr_flags
);
341 /* Dump expression REF. */
344 debug (expr_def
&ref
)
346 switch_dump (stderr
);
347 dump_expr_1 (&ref
, 0);
353 debug (expr_def
*ptr
)
358 fprintf (stderr
, "<nil>\n");
361 /* Dump expression REF verbosely. */
364 debug_verbose (expr_def
&ref
)
366 switch_dump (stderr
);
367 dump_expr_1 (&ref
, DUMP_EXPR_ALL
);
373 debug_verbose (expr_def
*ptr
)
376 debug_verbose (*ptr
);
378 fprintf (stderr
, "<nil>\n");
381 /* Dump insn I honoring FLAGS. */
383 dump_insn_1 (insn_t i
, int flags
)
389 flags
|= DUMP_INSN_ALL
;
391 if (!sched_dump_to_dot_p
)
394 if (flags
& DUMP_INSN_EXPR
)
396 dump_expr_1 (INSN_EXPR (i
), dump_expr_flags
| all
);
399 else if (flags
& DUMP_INSN_PATTERN
)
401 dump_insn_rtx_1 (i
, DUMP_INSN_RTX_PATTERN
| all
);
404 else if (flags
& DUMP_INSN_UID
)
405 sel_print ("uid:%d;", INSN_UID (i
));
407 if (flags
& DUMP_INSN_SEQNO
)
408 sel_print ("seqno:%d;", INSN_SEQNO (i
));
410 if (flags
& DUMP_INSN_SCHED_CYCLE
)
412 int cycle
= INSN_SCHED_CYCLE (i
);
415 sel_print ("cycle:%d;", cycle
);
418 if (!sched_dump_to_dot_p
)
422 /* Dump insn I with default flags. */
426 dump_insn_1 (i
, DUMP_INSN_EXPR
| DUMP_INSN_SCHED_CYCLE
);
429 /* Dump INSN to stderr. */
431 debug_insn (insn_t insn
)
433 switch_dump (stderr
);
434 dump_insn_1 (insn
, debug_insn_flags
);
439 /* Dumps av_set AV. */
441 dump_av_set (av_set_t av
)
446 if (!sched_dump_to_dot_p
)
449 FOR_EACH_EXPR (expr
, i
, av
)
452 if (!sched_dump_to_dot_p
)
458 if (!sched_dump_to_dot_p
)
462 /* Dumps lvset LV. */
464 dump_lv_set (regset lv
)
468 /* This code was adapted from cfg.c: dump_regset (). */
474 reg_set_iterator rsi
;
477 EXECUTE_IF_SET_IN_REG_SET (lv
, 0, i
, rsi
)
479 sel_print (" %d", i
);
480 if (i
< FIRST_PSEUDO_REGISTER
)
482 sel_print (" [%s]", reg_names
[i
]);
488 if (sched_dump_to_dot_p
&& count
== 12)
499 /* Dumps a list of instructions pointed to by P. */
501 dump_ilist (ilist_t p
)
505 dump_insn (ILIST_INSN (p
));
510 /* Dumps a list of boundaries pointed to by BNDS. */
512 dump_blist (blist_t bnds
)
514 for (; bnds
; bnds
= BLIST_NEXT (bnds
))
516 bnd_t bnd
= BLIST_BND (bnds
);
518 sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd
)));
519 dump_ilist (BND_PTR (bnd
));
524 /* Dumps a list of fences pointed to by L. */
526 dump_flist (flist_t l
)
530 dump_insn_1 (FENCE_INSN (FLIST_FENCE (l
)), dump_flist_insn_flags
);
536 /* Dumps an insn vector SUCCS. */
538 dump_insn_vector (rtx_vec_t succs
)
543 FOR_EACH_VEC_ELT (succs
, i
, succ
)
550 /* Dumps a hard reg set SET to FILE using PREFIX. */
552 print_hard_reg_set (FILE *file
, const char *prefix
, HARD_REG_SET set
)
556 fprintf (file
, "%s{ ", prefix
);
557 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
559 if (TEST_HARD_REG_BIT (set
, i
))
560 fprintf (file
, "%d ", i
);
562 fprintf (file
, "}\n");
565 /* Dumps a hard reg set SET using PREFIX. */
567 dump_hard_reg_set (const char *prefix
, HARD_REG_SET set
)
569 print_hard_reg_set (sched_dump
, prefix
, set
);
572 /* Pretty print INSN. This is used as a hook. */
574 sel_print_insn (const rtx_insn
*insn
, int aligned ATTRIBUTE_UNUSED
)
578 /* '+' before insn means it is a new cycle start and it's not been
579 scheduled yet. '>' - has been scheduled. */
580 if (s_i_d
.exists () && INSN_LUID (insn
) > 0)
581 if (GET_MODE (insn
) == TImode
)
582 sprintf (buf
, "%s %4d",
583 INSN_SCHED_TIMES (insn
) > 0 ? "> " : "< ",
586 sprintf (buf
, "%s %4d",
587 INSN_SCHED_TIMES (insn
) > 0 ? "! " : " ",
590 if (GET_MODE (insn
) == TImode
)
591 sprintf (buf
, "+ %4d", INSN_UID (insn
));
593 sprintf (buf
, " %4d", INSN_UID (insn
));
599 /* Functions for pretty printing of CFG. */
600 /* FIXME: Using pretty-print here could simplify this stuff. */
602 /* Replace all occurencies of STR1 to STR2 in BUF.
603 The BUF must be large enough to hold the result. */
605 replace_str_in_buf (char *buf
, const char *str1
, const char *str2
)
607 int buf_len
= strlen (buf
);
608 int str1_len
= strlen (str1
);
609 int str2_len
= strlen (str2
);
610 int diff
= str2_len
- str1_len
;
615 p
= strstr (p
, str1
);
618 char *p1
= p
+ str1_len
;
619 /* Copy the rest of buf and '\0'. */
620 int n
= buf
+ buf_len
- p1
;
623 /* Shift str by DIFF chars. */
625 for (i
= n
; i
>= 0; i
--)
626 p1
[i
+ diff
] = p1
[i
];
628 for (i
= 0; i
<= n
; i
++)
629 p1
[i
+ diff
] = p1
[i
];
632 for (i
= 0; i
< str2_len
; i
++)
643 /* Replace characters in BUF that have special meaning in .dot file.
644 Similar to pp_write_text_as_dot_label_to_stream. */
646 sel_prepare_string_for_dot_label (char *buf
)
648 static char specials_from
[7][2] = { "<", ">", "{", "|", "}", "\"",
650 static char specials_to
[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}",
654 for (i
= 0; i
< 7; i
++)
655 replace_str_in_buf (buf
, specials_from
[i
], specials_to
[i
]);
658 /* This function acts like printf but dumps to the sched_dump file. */
660 sel_print (const char *fmt
, ...)
664 if (sched_dump_to_dot_p
)
667 if (vasprintf (&message
, fmt
, ap
) >= 0 && message
!= NULL
)
669 message
= (char *) xrealloc (message
, 2 * strlen (message
) + 1);
670 sel_prepare_string_for_dot_label (message
);
671 fprintf (sched_dump
, "%s", message
);
676 vfprintf (sched_dump
, fmt
, ap
);
680 /* Dump INSN with FLAGS. */
682 sel_dump_cfg_insn (insn_t insn
, int flags
)
684 int insn_flags
= DUMP_INSN_UID
| DUMP_INSN_PATTERN
;
686 if (sched_luids
.exists () && INSN_LUID (insn
) > 0)
688 if (flags
& SEL_DUMP_CFG_INSN_SEQNO
)
689 insn_flags
|= DUMP_INSN_SEQNO
| DUMP_INSN_SCHED_CYCLE
| DUMP_INSN_EXPR
;
692 dump_insn_1 (insn
, insn_flags
);
695 /* Dump E to the dot file F. */
697 sel_dump_cfg_edge (FILE *f
, edge e
)
702 if (e
->flags
& EDGE_FALLTHRU
)
705 color
= ", color = red";
707 else if (e
->src
->next_bb
== e
->dest
)
710 color
= ", color = blue";
718 fprintf (f
, "\tbb%d -> bb%d [weight = %d%s];\n",
719 e
->src
->index
, e
->dest
->index
, w
, color
);
723 /* Return true if BB has a predesessor from current region.
724 TODO: Either make this function to trace back through empty block
725 or just remove those empty blocks. */
727 has_preds_in_current_region_p (basic_block bb
)
732 gcc_assert (!in_current_region_p (bb
));
734 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
735 if (in_current_region_p (e
->src
))
741 /* Dump a cfg region to the dot file F honoring FLAGS. */
743 sel_dump_cfg_2 (FILE *f
, int flags
)
747 sched_dump_to_dot_p
= true;
750 fprintf (f
, "digraph G {\n"
752 "\tnode [shape = record, fontsize = 9];\n");
754 if (flags
& SEL_DUMP_CFG_FUNCTION_NAME
)
755 fprintf (f
, "function [label = \"%s\"];\n", current_function_name ());
757 FOR_EACH_BB_FN (bb
, cfun
)
759 insn_t insn
= BB_HEAD (bb
);
760 insn_t next_tail
= NEXT_INSN (BB_END (bb
));
763 bool in_region_p
= ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
764 && in_current_region_p (bb
));
765 bool full_p
= (!(flags
& SEL_DUMP_CFG_CURRENT_REGION
)
767 bool some_p
= full_p
|| has_preds_in_current_region_p (bb
);
774 if ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
775 && in_current_region_p (bb
)
776 && BLOCK_TO_BB (bb
->index
) == 0)
777 color
= "color = green, ";
781 if ((flags
& SEL_DUMP_CFG_FENCES
)
786 if (!sel_bb_empty_p (bb
))
789 insn_t tail
= BB_END (bb
);
792 cur_insn
= bb_note (bb
);
798 cur_insn
= NEXT_INSN (cur_insn
);
799 fence
= flist_lookup (fences
, cur_insn
);
803 if (!FENCE_SCHEDULED_P (fence
))
806 color
= "color = red, ";
808 color
= "color = yellow, ";
811 color
= "color = blue, ";
816 while (cur_insn
!= tail
);
820 style
= "style = dashed, ";
824 fprintf (f
, "\tbb%d [%s%slabel = \"{Basic block %d", bb
->index
,
825 style
, color
, bb
->index
);
827 if ((flags
& SEL_DUMP_CFG_BB_LOOP
)
828 && bb
->loop_father
!= NULL
)
829 fprintf (f
, ", loop %d", bb
->loop_father
->num
);
832 && (flags
& SEL_DUMP_CFG_BB_NOTES_LIST
))
834 insn_t notes
= BB_NOTE_LIST (bb
);
836 if (notes
!= NULL_RTX
)
840 /* For simplicity, we dump notes from note_list in reversed order
841 to that what they will appear in the code. */
842 while (notes
!= NULL_RTX
)
844 sel_dump_cfg_insn (notes
, flags
);
847 notes
= PREV_INSN (notes
);
853 && (flags
& SEL_DUMP_CFG_AV_SET
)
854 && in_current_region_p (bb
)
855 && !sel_bb_empty_p (bb
))
859 if (BB_AV_SET_VALID_P (bb
))
860 dump_av_set (BB_AV_SET (bb
));
861 else if (BB_AV_LEVEL (bb
) == -1)
862 fprintf (f
, "AV_SET needs update");
865 if ((flags
& SEL_DUMP_CFG_LV_SET
)
866 && !sel_bb_empty_p (bb
))
870 if (BB_LV_SET_VALID_P (bb
))
871 dump_lv_set (BB_LV_SET (bb
));
873 fprintf (f
, "LV_SET needs update");
877 && (flags
& SEL_DUMP_CFG_BB_INSNS
))
880 while (insn
!= next_tail
)
882 sel_dump_cfg_insn (insn
, flags
);
885 insn
= NEXT_INSN (insn
);
889 fprintf (f
, "}\"];\n");
891 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
892 if (full_p
|| in_current_region_p (e
->dest
))
893 sel_dump_cfg_edge (f
, e
);
899 sched_dump_to_dot_p
= false;
902 /* Dump a cfg region to the file specified by TAG honoring flags.
903 The file is created by the function. */
905 sel_dump_cfg_1 (const char *tag
, int flags
)
911 ++sel_dump_cfg_fileno
;
916 i
= 1 + snprintf (NULL
, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
917 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
918 buf
= XNEWVEC (char, i
);
919 snprintf (buf
, i
, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
920 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
922 f
= fopen (buf
, "w");
925 fprintf (stderr
, "Can't create file: %s.\n", buf
);
928 sel_dump_cfg_2 (f
, flags
);
936 /* Setup cfg dumping flags. Used for debugging. */
938 setup_dump_cfg_params (void)
940 sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
942 sel_debug_cfg_root_postfix
= sel_debug_cfg_root_postfix_default
;
945 /* Debug a cfg region with FLAGS. */
947 sel_debug_cfg_1 (int flags
)
949 bool t1
= sel_dump_cfg_p
;
950 int t2
= sel_dump_cfg_fileno
;
952 sel_dump_cfg_p
= true;
953 sel_dump_cfg_fileno
= ++sel_debug_cfg_fileno
;
955 sel_dump_cfg_1 ("sel-debug-cfg", flags
);
957 sel_dump_cfg_fileno
= t2
;
961 /* Dumps av_set AV to stderr. */
963 debug_av_set (av_set_t av
)
965 switch_dump (stderr
);
971 /* Dump LV to stderr. */
973 debug_lv_set (regset lv
)
975 switch_dump (stderr
);
981 /* Dump an instruction list P to stderr. */
983 debug_ilist (ilist_t p
)
985 switch_dump (stderr
);
991 /* Dump a boundary list BNDS to stderr. */
993 debug_blist (blist_t bnds
)
995 switch_dump (stderr
);
1001 /* Dump a rtx vector REF. */
1003 debug (vec
<rtx_insn
*> &ref
)
1005 switch_dump (stderr
);
1006 dump_insn_vector (ref
);
1012 debug (vec
<rtx_insn
*> *ptr
)
1017 fprintf (stderr
, "<nil>\n");
1020 /* Dump an insn vector SUCCS. */
1022 debug_insn_vector (rtx_vec_t succs
)
1024 switch_dump (stderr
);
1025 dump_insn_vector (succs
);
1030 /* Dump a hard reg set SET to stderr. */
1032 debug_hard_reg_set (HARD_REG_SET set
)
1034 switch_dump (stderr
);
1035 dump_hard_reg_set ("", set
);
1040 /* Debug a cfg region with default flags. */
1042 sel_debug_cfg (void)
1044 sel_debug_cfg_1 (sel_debug_cfg_flags
);
1047 /* Print a current cselib value for X's address to stderr. */
1049 debug_mem_addr_value (rtx x
)
1052 machine_mode address_mode
;
1054 gcc_assert (MEM_P (x
));
1055 address_mode
= get_address_mode (x
);
1057 t
= shallow_copy_rtx (x
);
1058 if (cselib_lookup (XEXP (t
, 0), address_mode
, 0, GET_MODE (t
)))
1059 XEXP (t
, 0) = cselib_subst_to_values (XEXP (t
, 0), GET_MODE (t
));
1062 addr
= get_addr (XEXP (t
, 0));