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"
36 #include "dominance.h"
38 #include "basic-block.h"
40 #include "insn-config.h"
41 #include "insn-attr.h"
46 #ifdef INSN_SCHEDULING
47 #include "sel-sched-ir.h"
48 #include "sel-sched-dump.h"
51 /* These variables control high-level pretty printing. */
52 static int sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
53 static int sel_debug_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
55 /* True when a cfg should be dumped. */
56 static bool sel_dump_cfg_p
;
58 /* Variables that are used to build the cfg dump file name. */
59 static const char * const sel_debug_cfg_root
= "./";
60 static const char * const sel_debug_cfg_root_postfix_default
= "";
61 static const char *sel_debug_cfg_root_postfix
= "";
62 static int sel_dump_cfg_fileno
= -1;
63 static int sel_debug_cfg_fileno
= -1;
65 /* When this flag is on, we are dumping to the .dot file.
66 When it is off, we are dumping to log.
67 This is useful to differentiate formatting between log and .dot
69 bool sched_dump_to_dot_p
= false;
71 /* Controls how insns from a fence list should be dumped. */
72 static int dump_flist_insn_flags
= (DUMP_INSN_UID
| DUMP_INSN_BBN
76 /* The variable used to hold the value of sched_dump when temporarily
77 switching dump output to the other source, e.g. the .dot file. */
78 static FILE *saved_sched_dump
= NULL
;
80 /* Switch sched_dump to TO. It must not be called twice. */
82 switch_dump (FILE *to
)
84 gcc_assert (saved_sched_dump
== NULL
);
86 saved_sched_dump
= sched_dump
;
90 /* Restore previously switched dump. */
94 sched_dump
= saved_sched_dump
;
95 saved_sched_dump
= NULL
;
99 /* Functions for dumping instructions, av sets, and exprs. */
101 /* Default flags for dumping insns. */
102 static int dump_insn_rtx_flags
= DUMP_INSN_RTX_UID
| DUMP_INSN_RTX_PATTERN
;
104 /* Default flags for dumping vinsns. */
105 static int dump_vinsn_flags
= (DUMP_VINSN_INSN_RTX
| DUMP_VINSN_TYPE
108 /* Default flags for dumping expressions. */
109 static int dump_expr_flags
= DUMP_EXPR_ALL
;
111 /* Default flags for dumping insns when debugging. */
112 static int debug_insn_rtx_flags
= DUMP_INSN_RTX_ALL
;
114 /* Default flags for dumping vinsns when debugging. */
115 static int debug_vinsn_flags
= DUMP_VINSN_ALL
;
117 /* Default flags for dumping expressions when debugging. */
118 static int debug_expr_flags
= DUMP_EXPR_ALL
;
120 /* Controls how an insn from stream should be dumped when debugging. */
121 static int debug_insn_flags
= DUMP_INSN_ALL
;
123 /* Print an rtx X. */
125 sel_print_rtl (rtx x
)
127 print_rtl_single (sched_dump
, x
);
130 /* Dump insn INSN honoring FLAGS. */
132 dump_insn_rtx_1 (rtx insn
, int flags
)
136 /* flags == -1 also means dumping all. */
139 flags
|= DUMP_INSN_RTX_ALL
;
143 if (flags
& DUMP_INSN_RTX_UID
)
144 sel_print ("%d;", INSN_UID (insn
));
146 if (flags
& DUMP_INSN_RTX_PATTERN
)
147 sel_print ("%s;", str_pattern_slim (PATTERN (insn
)));
149 if (flags
& DUMP_INSN_RTX_BBN
)
151 basic_block bb
= BLOCK_FOR_INSN (insn
);
153 sel_print ("bb:%d;", bb
!= NULL
? bb
->index
: -1);
160 /* Dump INSN with default flags. */
162 dump_insn_rtx (rtx insn
)
164 dump_insn_rtx_1 (insn
, dump_insn_rtx_flags
);
168 /* Dump INSN to stderr. */
170 debug_insn_rtx (rtx insn
)
172 switch_dump (stderr
);
173 dump_insn_rtx_1 (insn
, debug_insn_rtx_flags
);
178 /* Dump vinsn VI honoring flags. */
180 dump_vinsn_1 (vinsn_t vi
, int flags
)
184 /* flags == -1 also means dumping all. */
187 flags
|= DUMP_VINSN_ALL
;
191 if (flags
& DUMP_VINSN_INSN_RTX
)
192 dump_insn_rtx_1 (VINSN_INSN_RTX (vi
), dump_insn_rtx_flags
| all
);
194 if (flags
& DUMP_VINSN_TYPE
)
195 sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi
)));
197 if (flags
& DUMP_VINSN_COUNT
)
198 sel_print ("count:%d;", VINSN_COUNT (vi
));
200 if (flags
& DUMP_VINSN_COST
)
205 sel_print ("cost:%d;", cost
);
211 /* Dump vinsn VI with default flags. */
213 dump_vinsn (vinsn_t vi
)
215 dump_vinsn_1 (vi
, dump_vinsn_flags
);
219 debug (vinsn_def
&ref
)
221 switch_dump (stderr
);
222 dump_vinsn_1 (&ref
, dump_vinsn_flags
);
228 debug (vinsn_def
*ptr
)
233 fprintf (stderr
, "<nil>\n");
237 debug_verbose (vinsn_def
&ref
)
239 switch_dump (stderr
);
240 dump_vinsn_1 (&ref
, debug_vinsn_flags
);
246 debug_verbose (vinsn_def
*ptr
)
251 fprintf (stderr
, "<nil>\n");
254 /* Dump vinsn VI to stderr. */
256 debug_vinsn (vinsn_t vi
)
258 switch_dump (stderr
);
259 dump_vinsn_1 (vi
, debug_vinsn_flags
);
264 /* Dump EXPR honoring flags. */
266 dump_expr_1 (expr_t expr
, int flags
)
270 /* flags == -1 also means dumping all. */
273 flags
|= DUMP_EXPR_ALL
;
277 if (flags
& DUMP_EXPR_VINSN
)
278 dump_vinsn_1 (EXPR_VINSN (expr
), dump_vinsn_flags
| all
);
280 if (flags
& DUMP_EXPR_SPEC
)
282 int spec
= EXPR_SPEC (expr
);
285 sel_print ("spec:%d;", spec
);
288 if (flags
& DUMP_EXPR_USEFULNESS
)
290 int use
= EXPR_USEFULNESS (expr
);
292 if (use
!= REG_BR_PROB_BASE
)
293 sel_print ("use:%d;", use
);
296 if (flags
& DUMP_EXPR_PRIORITY
)
297 sel_print ("prio:%d;", EXPR_PRIORITY (expr
));
299 if (flags
& DUMP_EXPR_SCHED_TIMES
)
301 int times
= EXPR_SCHED_TIMES (expr
);
304 sel_print ("times:%d;", times
);
307 if (flags
& DUMP_EXPR_SPEC_DONE_DS
)
309 ds_t spec_done_ds
= EXPR_SPEC_DONE_DS (expr
);
311 if (spec_done_ds
!= 0)
312 sel_print ("ds:%d;", spec_done_ds
);
315 if (flags
& DUMP_EXPR_ORIG_BB
)
317 int orig_bb
= EXPR_ORIG_BB_INDEX (expr
);
320 sel_print ("orig_bb:%d;", orig_bb
);
323 if (EXPR_TARGET_AVAILABLE (expr
) < 1)
324 sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr
));
328 /* Dump expression EXPR with default flags. */
330 dump_expr (expr_t expr
)
332 dump_expr_1 (expr
, dump_expr_flags
);
335 /* Dump expression EXPR to stderr. */
337 debug_expr (expr_t expr
)
339 switch_dump (stderr
);
340 dump_expr_1 (expr
, debug_expr_flags
);
345 /* Dump expression REF. */
348 debug (expr_def
&ref
)
350 switch_dump (stderr
);
351 dump_expr_1 (&ref
, 0);
357 debug (expr_def
*ptr
)
362 fprintf (stderr
, "<nil>\n");
365 /* Dump expression REF verbosely. */
368 debug_verbose (expr_def
&ref
)
370 switch_dump (stderr
);
371 dump_expr_1 (&ref
, DUMP_EXPR_ALL
);
377 debug_verbose (expr_def
*ptr
)
380 debug_verbose (*ptr
);
382 fprintf (stderr
, "<nil>\n");
385 /* Dump insn I honoring FLAGS. */
387 dump_insn_1 (insn_t i
, int flags
)
393 flags
|= DUMP_INSN_ALL
;
395 if (!sched_dump_to_dot_p
)
398 if (flags
& DUMP_INSN_EXPR
)
400 dump_expr_1 (INSN_EXPR (i
), dump_expr_flags
| all
);
403 else if (flags
& DUMP_INSN_PATTERN
)
405 dump_insn_rtx_1 (i
, DUMP_INSN_RTX_PATTERN
| all
);
408 else if (flags
& DUMP_INSN_UID
)
409 sel_print ("uid:%d;", INSN_UID (i
));
411 if (flags
& DUMP_INSN_SEQNO
)
412 sel_print ("seqno:%d;", INSN_SEQNO (i
));
414 if (flags
& DUMP_INSN_SCHED_CYCLE
)
416 int cycle
= INSN_SCHED_CYCLE (i
);
419 sel_print ("cycle:%d;", cycle
);
422 if (!sched_dump_to_dot_p
)
426 /* Dump insn I with default flags. */
430 dump_insn_1 (i
, DUMP_INSN_EXPR
| DUMP_INSN_SCHED_CYCLE
);
433 /* Dump INSN to stderr. */
435 debug_insn (insn_t insn
)
437 switch_dump (stderr
);
438 dump_insn_1 (insn
, debug_insn_flags
);
443 /* Dumps av_set AV. */
445 dump_av_set (av_set_t av
)
450 if (!sched_dump_to_dot_p
)
453 FOR_EACH_EXPR (expr
, i
, av
)
456 if (!sched_dump_to_dot_p
)
462 if (!sched_dump_to_dot_p
)
466 /* Dumps lvset LV. */
468 dump_lv_set (regset lv
)
472 /* This code was adapted from cfg.c: dump_regset (). */
478 reg_set_iterator rsi
;
481 EXECUTE_IF_SET_IN_REG_SET (lv
, 0, i
, rsi
)
483 sel_print (" %d", i
);
484 if (i
< FIRST_PSEUDO_REGISTER
)
486 sel_print (" [%s]", reg_names
[i
]);
492 if (sched_dump_to_dot_p
&& count
== 12)
503 /* Dumps a list of instructions pointed to by P. */
505 dump_ilist (ilist_t p
)
509 dump_insn (ILIST_INSN (p
));
514 /* Dumps a list of boundaries pointed to by BNDS. */
516 dump_blist (blist_t bnds
)
518 for (; bnds
; bnds
= BLIST_NEXT (bnds
))
520 bnd_t bnd
= BLIST_BND (bnds
);
522 sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd
)));
523 dump_ilist (BND_PTR (bnd
));
528 /* Dumps a list of fences pointed to by L. */
530 dump_flist (flist_t l
)
534 dump_insn_1 (FENCE_INSN (FLIST_FENCE (l
)), dump_flist_insn_flags
);
540 /* Dumps an insn vector SUCCS. */
542 dump_insn_vector (rtx_vec_t succs
)
547 FOR_EACH_VEC_ELT (succs
, i
, succ
)
554 /* Dumps a hard reg set SET to FILE using PREFIX. */
556 print_hard_reg_set (FILE *file
, const char *prefix
, HARD_REG_SET set
)
560 fprintf (file
, "%s{ ", prefix
);
561 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
563 if (TEST_HARD_REG_BIT (set
, i
))
564 fprintf (file
, "%d ", i
);
566 fprintf (file
, "}\n");
569 /* Dumps a hard reg set SET using PREFIX. */
571 dump_hard_reg_set (const char *prefix
, HARD_REG_SET set
)
573 print_hard_reg_set (sched_dump
, prefix
, set
);
576 /* Pretty print INSN. This is used as a hook. */
578 sel_print_insn (const rtx_insn
*insn
, int aligned ATTRIBUTE_UNUSED
)
582 /* '+' before insn means it is a new cycle start and it's not been
583 scheduled yet. '>' - has been scheduled. */
584 if (s_i_d
.exists () && INSN_LUID (insn
) > 0)
585 if (GET_MODE (insn
) == TImode
)
586 sprintf (buf
, "%s %4d",
587 INSN_SCHED_TIMES (insn
) > 0 ? "> " : "< ",
590 sprintf (buf
, "%s %4d",
591 INSN_SCHED_TIMES (insn
) > 0 ? "! " : " ",
594 if (GET_MODE (insn
) == TImode
)
595 sprintf (buf
, "+ %4d", INSN_UID (insn
));
597 sprintf (buf
, " %4d", INSN_UID (insn
));
603 /* Functions for pretty printing of CFG. */
604 /* FIXME: Using pretty-print here could simplify this stuff. */
606 /* Replace all occurencies of STR1 to STR2 in BUF.
607 The BUF must be large enough to hold the result. */
609 replace_str_in_buf (char *buf
, const char *str1
, const char *str2
)
611 int buf_len
= strlen (buf
);
612 int str1_len
= strlen (str1
);
613 int str2_len
= strlen (str2
);
614 int diff
= str2_len
- str1_len
;
619 p
= strstr (p
, str1
);
622 char *p1
= p
+ str1_len
;
623 /* Copy the rest of buf and '\0'. */
624 int n
= buf
+ buf_len
- p1
;
627 /* Shift str by DIFF chars. */
629 for (i
= n
; i
>= 0; i
--)
630 p1
[i
+ diff
] = p1
[i
];
632 for (i
= 0; i
<= n
; i
++)
633 p1
[i
+ diff
] = p1
[i
];
636 for (i
= 0; i
< str2_len
; i
++)
647 /* Replace characters in BUF that have special meaning in .dot file.
648 Similar to pp_write_text_as_dot_label_to_stream. */
650 sel_prepare_string_for_dot_label (char *buf
)
652 static char specials_from
[7][2] = { "<", ">", "{", "|", "}", "\"",
654 static char specials_to
[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}",
658 for (i
= 0; i
< 7; i
++)
659 replace_str_in_buf (buf
, specials_from
[i
], specials_to
[i
]);
662 /* This function acts like printf but dumps to the sched_dump file. */
664 sel_print (const char *fmt
, ...)
668 if (sched_dump_to_dot_p
)
671 if (vasprintf (&message
, fmt
, ap
) >= 0 && message
!= NULL
)
673 message
= (char *) xrealloc (message
, 2 * strlen (message
) + 1);
674 sel_prepare_string_for_dot_label (message
);
675 fprintf (sched_dump
, "%s", message
);
680 vfprintf (sched_dump
, fmt
, ap
);
684 /* Dump INSN with FLAGS. */
686 sel_dump_cfg_insn (insn_t insn
, int flags
)
688 int insn_flags
= DUMP_INSN_UID
| DUMP_INSN_PATTERN
;
690 if (sched_luids
.exists () && INSN_LUID (insn
) > 0)
692 if (flags
& SEL_DUMP_CFG_INSN_SEQNO
)
693 insn_flags
|= DUMP_INSN_SEQNO
| DUMP_INSN_SCHED_CYCLE
| DUMP_INSN_EXPR
;
696 dump_insn_1 (insn
, insn_flags
);
699 /* Dump E to the dot file F. */
701 sel_dump_cfg_edge (FILE *f
, edge e
)
706 if (e
->flags
& EDGE_FALLTHRU
)
709 color
= ", color = red";
711 else if (e
->src
->next_bb
== e
->dest
)
714 color
= ", color = blue";
722 fprintf (f
, "\tbb%d -> bb%d [weight = %d%s];\n",
723 e
->src
->index
, e
->dest
->index
, w
, color
);
727 /* Return true if BB has a predesessor from current region.
728 TODO: Either make this function to trace back through empty block
729 or just remove those empty blocks. */
731 has_preds_in_current_region_p (basic_block bb
)
736 gcc_assert (!in_current_region_p (bb
));
738 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
739 if (in_current_region_p (e
->src
))
745 /* Dump a cfg region to the dot file F honoring FLAGS. */
747 sel_dump_cfg_2 (FILE *f
, int flags
)
751 sched_dump_to_dot_p
= true;
754 fprintf (f
, "digraph G {\n"
756 "\tnode [shape = record, fontsize = 9];\n");
758 if (flags
& SEL_DUMP_CFG_FUNCTION_NAME
)
759 fprintf (f
, "function [label = \"%s\"];\n", current_function_name ());
761 FOR_EACH_BB_FN (bb
, cfun
)
763 insn_t insn
= BB_HEAD (bb
);
764 insn_t next_tail
= NEXT_INSN (BB_END (bb
));
767 bool in_region_p
= ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
768 && in_current_region_p (bb
));
769 bool full_p
= (!(flags
& SEL_DUMP_CFG_CURRENT_REGION
)
771 bool some_p
= full_p
|| has_preds_in_current_region_p (bb
);
778 if ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
779 && in_current_region_p (bb
)
780 && BLOCK_TO_BB (bb
->index
) == 0)
781 color
= "color = green, ";
785 if ((flags
& SEL_DUMP_CFG_FENCES
)
790 if (!sel_bb_empty_p (bb
))
793 insn_t tail
= BB_END (bb
);
796 cur_insn
= bb_note (bb
);
802 cur_insn
= NEXT_INSN (cur_insn
);
803 fence
= flist_lookup (fences
, cur_insn
);
807 if (!FENCE_SCHEDULED_P (fence
))
810 color
= "color = red, ";
812 color
= "color = yellow, ";
815 color
= "color = blue, ";
820 while (cur_insn
!= tail
);
824 style
= "style = dashed, ";
828 fprintf (f
, "\tbb%d [%s%slabel = \"{Basic block %d", bb
->index
,
829 style
, color
, bb
->index
);
831 if ((flags
& SEL_DUMP_CFG_BB_LOOP
)
832 && bb
->loop_father
!= NULL
)
833 fprintf (f
, ", loop %d", bb
->loop_father
->num
);
836 && (flags
& SEL_DUMP_CFG_BB_NOTES_LIST
))
838 insn_t notes
= BB_NOTE_LIST (bb
);
840 if (notes
!= NULL_RTX
)
844 /* For simplicity, we dump notes from note_list in reversed order
845 to that what they will appear in the code. */
846 while (notes
!= NULL_RTX
)
848 sel_dump_cfg_insn (notes
, flags
);
851 notes
= PREV_INSN (notes
);
857 && (flags
& SEL_DUMP_CFG_AV_SET
)
858 && in_current_region_p (bb
)
859 && !sel_bb_empty_p (bb
))
863 if (BB_AV_SET_VALID_P (bb
))
864 dump_av_set (BB_AV_SET (bb
));
865 else if (BB_AV_LEVEL (bb
) == -1)
866 fprintf (f
, "AV_SET needs update");
869 if ((flags
& SEL_DUMP_CFG_LV_SET
)
870 && !sel_bb_empty_p (bb
))
874 if (BB_LV_SET_VALID_P (bb
))
875 dump_lv_set (BB_LV_SET (bb
));
877 fprintf (f
, "LV_SET needs update");
881 && (flags
& SEL_DUMP_CFG_BB_INSNS
))
884 while (insn
!= next_tail
)
886 sel_dump_cfg_insn (insn
, flags
);
889 insn
= NEXT_INSN (insn
);
893 fprintf (f
, "}\"];\n");
895 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
896 if (full_p
|| in_current_region_p (e
->dest
))
897 sel_dump_cfg_edge (f
, e
);
903 sched_dump_to_dot_p
= false;
906 /* Dump a cfg region to the file specified by TAG honoring flags.
907 The file is created by the function. */
909 sel_dump_cfg_1 (const char *tag
, int flags
)
915 ++sel_dump_cfg_fileno
;
920 i
= 1 + snprintf (NULL
, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
921 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
922 buf
= XNEWVEC (char, i
);
923 snprintf (buf
, i
, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
924 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
926 f
= fopen (buf
, "w");
929 fprintf (stderr
, "Can't create file: %s.\n", buf
);
932 sel_dump_cfg_2 (f
, flags
);
940 /* Setup cfg dumping flags. Used for debugging. */
942 setup_dump_cfg_params (void)
944 sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
946 sel_debug_cfg_root_postfix
= sel_debug_cfg_root_postfix_default
;
949 /* Debug a cfg region with FLAGS. */
951 sel_debug_cfg_1 (int flags
)
953 bool t1
= sel_dump_cfg_p
;
954 int t2
= sel_dump_cfg_fileno
;
956 sel_dump_cfg_p
= true;
957 sel_dump_cfg_fileno
= ++sel_debug_cfg_fileno
;
959 sel_dump_cfg_1 ("sel-debug-cfg", flags
);
961 sel_dump_cfg_fileno
= t2
;
965 /* Dumps av_set AV to stderr. */
967 debug_av_set (av_set_t av
)
969 switch_dump (stderr
);
975 /* Dump LV to stderr. */
977 debug_lv_set (regset lv
)
979 switch_dump (stderr
);
985 /* Dump an instruction list P to stderr. */
987 debug_ilist (ilist_t p
)
989 switch_dump (stderr
);
995 /* Dump a boundary list BNDS to stderr. */
997 debug_blist (blist_t bnds
)
999 switch_dump (stderr
);
1005 /* Dump a rtx vector REF. */
1007 debug (vec
<rtx_insn
*> &ref
)
1009 switch_dump (stderr
);
1010 dump_insn_vector (ref
);
1016 debug (vec
<rtx_insn
*> *ptr
)
1021 fprintf (stderr
, "<nil>\n");
1024 /* Dump an insn vector SUCCS. */
1026 debug_insn_vector (rtx_vec_t succs
)
1028 switch_dump (stderr
);
1029 dump_insn_vector (succs
);
1034 /* Dump a hard reg set SET to stderr. */
1036 debug_hard_reg_set (HARD_REG_SET set
)
1038 switch_dump (stderr
);
1039 dump_hard_reg_set ("", set
);
1044 /* Debug a cfg region with default flags. */
1046 sel_debug_cfg (void)
1048 sel_debug_cfg_1 (sel_debug_cfg_flags
);
1051 /* Print a current cselib value for X's address to stderr. */
1053 debug_mem_addr_value (rtx x
)
1056 machine_mode address_mode
;
1058 gcc_assert (MEM_P (x
));
1059 address_mode
= get_address_mode (x
);
1061 t
= shallow_copy_rtx (x
);
1062 if (cselib_lookup (XEXP (t
, 0), address_mode
, 0, GET_MODE (t
)))
1063 XEXP (t
, 0) = cselib_subst_to_values (XEXP (t
, 0), GET_MODE (t
));
1066 addr
= get_addr (XEXP (t
, 0));