1 /* Instruction scheduling pass. Log dumping infrastructure.
2 Copyright (C) 2006-2013 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 "insn-config.h"
32 #include "insn-attr.h"
34 #include "basic-block.h"
38 #ifdef INSN_SCHEDULING
39 #include "sel-sched-ir.h"
40 #include "sel-sched-dump.h"
43 /* These variables control high-level pretty printing. */
44 static int sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
45 static int sel_debug_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
47 /* True when a cfg should be dumped. */
48 static bool sel_dump_cfg_p
;
50 /* Variables that are used to build the cfg dump file name. */
51 static const char * const sel_debug_cfg_root
= "./";
52 static const char * const sel_debug_cfg_root_postfix_default
= "";
53 static const char *sel_debug_cfg_root_postfix
= "";
54 static int sel_dump_cfg_fileno
= -1;
55 static int sel_debug_cfg_fileno
= -1;
57 /* When this flag is on, we are dumping to the .dot file.
58 When it is off, we are dumping to log.
59 This is useful to differentiate formatting between log and .dot
61 bool sched_dump_to_dot_p
= false;
63 /* Controls how insns from a fence list should be dumped. */
64 static int dump_flist_insn_flags
= (DUMP_INSN_UID
| DUMP_INSN_BBN
68 /* The variable used to hold the value of sched_dump when temporarily
69 switching dump output to the other source, e.g. the .dot file. */
70 static FILE *saved_sched_dump
= NULL
;
72 /* Switch sched_dump to TO. It must not be called twice. */
74 switch_dump (FILE *to
)
76 gcc_assert (saved_sched_dump
== NULL
);
78 saved_sched_dump
= sched_dump
;
82 /* Restore previously switched dump. */
86 sched_dump
= saved_sched_dump
;
87 saved_sched_dump
= NULL
;
91 /* Functions for dumping instructions, av sets, and exprs. */
93 /* Default flags for dumping insns. */
94 static int dump_insn_rtx_flags
= DUMP_INSN_RTX_UID
| DUMP_INSN_RTX_PATTERN
;
96 /* Default flags for dumping vinsns. */
97 static int dump_vinsn_flags
= (DUMP_VINSN_INSN_RTX
| DUMP_VINSN_TYPE
100 /* Default flags for dumping expressions. */
101 static int dump_expr_flags
= DUMP_EXPR_ALL
;
103 /* Default flags for dumping insns when debugging. */
104 static int debug_insn_rtx_flags
= DUMP_INSN_RTX_ALL
;
106 /* Default flags for dumping vinsns when debugging. */
107 static int debug_vinsn_flags
= DUMP_VINSN_ALL
;
109 /* Default flags for dumping expressions when debugging. */
110 static int debug_expr_flags
= DUMP_EXPR_ALL
;
112 /* Controls how an insn from stream should be dumped when debugging. */
113 static int debug_insn_flags
= DUMP_INSN_ALL
;
115 /* Print an rtx X. */
117 sel_print_rtl (rtx x
)
119 print_rtl_single (sched_dump
, x
);
122 /* Dump insn INSN honoring FLAGS. */
124 dump_insn_rtx_1 (rtx insn
, int flags
)
128 /* flags == -1 also means dumping all. */
131 flags
|= DUMP_INSN_RTX_ALL
;
135 if (flags
& DUMP_INSN_RTX_UID
)
136 sel_print ("%d;", INSN_UID (insn
));
138 if (flags
& DUMP_INSN_RTX_PATTERN
)
139 sel_print ("%s;", str_pattern_slim (PATTERN (insn
)));
141 if (flags
& DUMP_INSN_RTX_BBN
)
143 basic_block bb
= BLOCK_FOR_INSN (insn
);
145 sel_print ("bb:%d;", bb
!= NULL
? bb
->index
: -1);
152 /* Dump INSN with default flags. */
154 dump_insn_rtx (rtx insn
)
156 dump_insn_rtx_1 (insn
, dump_insn_rtx_flags
);
160 /* Dump INSN to stderr. */
162 debug_insn_rtx (rtx insn
)
164 switch_dump (stderr
);
165 dump_insn_rtx_1 (insn
, debug_insn_rtx_flags
);
170 /* Dump vinsn VI honoring flags. */
172 dump_vinsn_1 (vinsn_t vi
, int flags
)
176 /* flags == -1 also means dumping all. */
179 flags
|= DUMP_VINSN_ALL
;
183 if (flags
& DUMP_VINSN_INSN_RTX
)
184 dump_insn_rtx_1 (VINSN_INSN_RTX (vi
), dump_insn_rtx_flags
| all
);
186 if (flags
& DUMP_VINSN_TYPE
)
187 sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi
)));
189 if (flags
& DUMP_VINSN_COUNT
)
190 sel_print ("count:%d;", VINSN_COUNT (vi
));
192 if (flags
& DUMP_VINSN_COST
)
197 sel_print ("cost:%d;", cost
);
203 /* Dump vinsn VI with default flags. */
205 dump_vinsn (vinsn_t vi
)
207 dump_vinsn_1 (vi
, dump_vinsn_flags
);
210 /* Dump vinsn VI to stderr. */
212 debug_vinsn (vinsn_t vi
)
214 switch_dump (stderr
);
215 dump_vinsn_1 (vi
, debug_vinsn_flags
);
220 /* Dump EXPR honoring flags. */
222 dump_expr_1 (expr_t expr
, int flags
)
226 /* flags == -1 also means dumping all. */
229 flags
|= DUMP_EXPR_ALL
;
233 if (flags
& DUMP_EXPR_VINSN
)
234 dump_vinsn_1 (EXPR_VINSN (expr
), dump_vinsn_flags
| all
);
236 if (flags
& DUMP_EXPR_SPEC
)
238 int spec
= EXPR_SPEC (expr
);
241 sel_print ("spec:%d;", spec
);
244 if (flags
& DUMP_EXPR_USEFULNESS
)
246 int use
= EXPR_USEFULNESS (expr
);
248 if (use
!= REG_BR_PROB_BASE
)
249 sel_print ("use:%d;", use
);
252 if (flags
& DUMP_EXPR_PRIORITY
)
253 sel_print ("prio:%d;", EXPR_PRIORITY (expr
));
255 if (flags
& DUMP_EXPR_SCHED_TIMES
)
257 int times
= EXPR_SCHED_TIMES (expr
);
260 sel_print ("times:%d;", times
);
263 if (flags
& DUMP_EXPR_SPEC_DONE_DS
)
265 ds_t spec_done_ds
= EXPR_SPEC_DONE_DS (expr
);
267 if (spec_done_ds
!= 0)
268 sel_print ("ds:%d;", spec_done_ds
);
271 if (flags
& DUMP_EXPR_ORIG_BB
)
273 int orig_bb
= EXPR_ORIG_BB_INDEX (expr
);
276 sel_print ("orig_bb:%d;", orig_bb
);
279 if (EXPR_TARGET_AVAILABLE (expr
) < 1)
280 sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr
));
284 /* Dump expression EXPR with default flags. */
286 dump_expr (expr_t expr
)
288 dump_expr_1 (expr
, dump_expr_flags
);
291 /* Dump expression EXPR to stderr. */
293 debug_expr (expr_t expr
)
295 switch_dump (stderr
);
296 dump_expr_1 (expr
, debug_expr_flags
);
301 /* Dump insn I honoring FLAGS. */
303 dump_insn_1 (insn_t i
, int flags
)
309 flags
|= DUMP_INSN_ALL
;
311 if (!sched_dump_to_dot_p
)
314 if (flags
& DUMP_INSN_EXPR
)
316 dump_expr_1 (INSN_EXPR (i
), dump_expr_flags
| all
);
319 else if (flags
& DUMP_INSN_PATTERN
)
321 dump_insn_rtx_1 (i
, DUMP_INSN_RTX_PATTERN
| all
);
324 else if (flags
& DUMP_INSN_UID
)
325 sel_print ("uid:%d;", INSN_UID (i
));
327 if (flags
& DUMP_INSN_SEQNO
)
328 sel_print ("seqno:%d;", INSN_SEQNO (i
));
330 if (flags
& DUMP_INSN_SCHED_CYCLE
)
332 int cycle
= INSN_SCHED_CYCLE (i
);
335 sel_print ("cycle:%d;", cycle
);
338 if (!sched_dump_to_dot_p
)
342 /* Dump insn I with default flags. */
346 dump_insn_1 (i
, DUMP_INSN_EXPR
| DUMP_INSN_SCHED_CYCLE
);
349 /* Dump INSN to stderr. */
351 debug_insn (insn_t insn
)
353 switch_dump (stderr
);
354 dump_insn_1 (insn
, debug_insn_flags
);
359 /* Dumps av_set AV. */
361 dump_av_set (av_set_t av
)
366 if (!sched_dump_to_dot_p
)
369 FOR_EACH_EXPR (expr
, i
, av
)
372 if (!sched_dump_to_dot_p
)
378 if (!sched_dump_to_dot_p
)
382 /* Dumps lvset LV. */
384 dump_lv_set (regset lv
)
388 /* This code was adapted from cfg.c: dump_regset (). */
394 reg_set_iterator rsi
;
397 EXECUTE_IF_SET_IN_REG_SET (lv
, 0, i
, rsi
)
399 sel_print (" %d", i
);
400 if (i
< FIRST_PSEUDO_REGISTER
)
402 sel_print (" [%s]", reg_names
[i
]);
408 if (sched_dump_to_dot_p
&& count
== 12)
419 /* Dumps a list of instructions pointed to by P. */
421 dump_ilist (ilist_t p
)
425 dump_insn (ILIST_INSN (p
));
430 /* Dumps a list of boundaries pointed to by BNDS. */
432 dump_blist (blist_t bnds
)
434 for (; bnds
; bnds
= BLIST_NEXT (bnds
))
436 bnd_t bnd
= BLIST_BND (bnds
);
438 sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd
)));
439 dump_ilist (BND_PTR (bnd
));
444 /* Dumps a list of fences pointed to by L. */
446 dump_flist (flist_t l
)
450 dump_insn_1 (FENCE_INSN (FLIST_FENCE (l
)), dump_flist_insn_flags
);
456 /* Dumps an insn vector SUCCS. */
458 dump_insn_vector (rtx_vec_t succs
)
463 FOR_EACH_VEC_ELT (succs
, i
, succ
)
470 /* Dumps a hard reg set SET to FILE using PREFIX. */
472 print_hard_reg_set (FILE *file
, const char *prefix
, HARD_REG_SET set
)
476 fprintf (file
, "%s{ ", prefix
);
477 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
479 if (TEST_HARD_REG_BIT (set
, i
))
480 fprintf (file
, "%d ", i
);
482 fprintf (file
, "}\n");
485 /* Dumps a hard reg set SET using PREFIX. */
487 dump_hard_reg_set (const char *prefix
, HARD_REG_SET set
)
489 print_hard_reg_set (sched_dump
, prefix
, set
);
492 /* Pretty print INSN. This is used as a hook. */
494 sel_print_insn (const_rtx insn
, int aligned ATTRIBUTE_UNUSED
)
498 /* '+' before insn means it is a new cycle start and it's not been
499 scheduled yet. '>' - has been scheduled. */
500 if (s_i_d
.exists () && INSN_LUID (insn
) > 0)
501 if (GET_MODE (insn
) == TImode
)
502 sprintf (buf
, "%s %4d",
503 INSN_SCHED_TIMES (insn
) > 0 ? "> " : "< ",
506 sprintf (buf
, "%s %4d",
507 INSN_SCHED_TIMES (insn
) > 0 ? "! " : " ",
510 if (GET_MODE (insn
) == TImode
)
511 sprintf (buf
, "+ %4d", INSN_UID (insn
));
513 sprintf (buf
, " %4d", INSN_UID (insn
));
519 /* Functions for pretty printing of CFG. */
520 /* FIXME: Using pretty-print here could simplify this stuff. */
522 /* Replace all occurencies of STR1 to STR2 in BUF.
523 The BUF must be large enough to hold the result. */
525 replace_str_in_buf (char *buf
, const char *str1
, const char *str2
)
527 int buf_len
= strlen (buf
);
528 int str1_len
= strlen (str1
);
529 int str2_len
= strlen (str2
);
530 int diff
= str2_len
- str1_len
;
535 p
= strstr (p
, str1
);
538 char *p1
= p
+ str1_len
;
539 /* Copy the rest of buf and '\0'. */
540 int n
= buf
+ buf_len
- p1
;
543 /* Shift str by DIFF chars. */
545 for (i
= n
; i
>= 0; i
--)
546 p1
[i
+ diff
] = p1
[i
];
548 for (i
= 0; i
<= n
; i
++)
549 p1
[i
+ diff
] = p1
[i
];
552 for (i
= 0; i
< str2_len
; i
++)
563 /* Replace characters in BUF that have special meaning in .dot file.
564 Similar to pp_write_text_as_dot_label_to_stream. */
566 sel_prepare_string_for_dot_label (char *buf
)
568 static char specials_from
[7][2] = { "<", ">", "{", "|", "}", "\"",
570 static char specials_to
[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}",
574 for (i
= 0; i
< 7; i
++)
575 replace_str_in_buf (buf
, specials_from
[i
], specials_to
[i
]);
578 /* This function acts like printf but dumps to the sched_dump file. */
580 sel_print (const char *fmt
, ...)
584 if (sched_dump_to_dot_p
)
587 if (vasprintf (&message
, fmt
, ap
) >= 0 && message
!= NULL
)
589 message
= (char *) xrealloc (message
, 2 * strlen (message
) + 1);
590 sel_prepare_string_for_dot_label (message
);
591 fprintf (sched_dump
, "%s", message
);
596 vfprintf (sched_dump
, fmt
, ap
);
600 /* Dump INSN with FLAGS. */
602 sel_dump_cfg_insn (insn_t insn
, int flags
)
604 int insn_flags
= DUMP_INSN_UID
| DUMP_INSN_PATTERN
;
606 if (sched_luids
.exists () && INSN_LUID (insn
) > 0)
608 if (flags
& SEL_DUMP_CFG_INSN_SEQNO
)
609 insn_flags
|= DUMP_INSN_SEQNO
| DUMP_INSN_SCHED_CYCLE
| DUMP_INSN_EXPR
;
612 dump_insn_1 (insn
, insn_flags
);
615 /* Dump E to the dot file F. */
617 sel_dump_cfg_edge (FILE *f
, edge e
)
622 if (e
->flags
& EDGE_FALLTHRU
)
625 color
= ", color = red";
627 else if (e
->src
->next_bb
== e
->dest
)
630 color
= ", color = blue";
638 fprintf (f
, "\tbb%d -> bb%d [weight = %d%s];\n",
639 e
->src
->index
, e
->dest
->index
, w
, color
);
643 /* Return true if BB has a predesessor from current region.
644 TODO: Either make this function to trace back through empty block
645 or just remove those empty blocks. */
647 has_preds_in_current_region_p (basic_block bb
)
652 gcc_assert (!in_current_region_p (bb
));
654 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
655 if (in_current_region_p (e
->src
))
661 /* Dump a cfg region to the dot file F honoring FLAGS. */
663 sel_dump_cfg_2 (FILE *f
, int flags
)
667 sched_dump_to_dot_p
= true;
670 fprintf (f
, "digraph G {\n"
672 "\tnode [shape = record, fontsize = 9];\n");
674 if (flags
& SEL_DUMP_CFG_FUNCTION_NAME
)
675 fprintf (f
, "function [label = \"%s\"];\n", current_function_name ());
679 insn_t insn
= BB_HEAD (bb
);
680 insn_t next_tail
= NEXT_INSN (BB_END (bb
));
683 bool in_region_p
= ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
684 && in_current_region_p (bb
));
685 bool full_p
= (!(flags
& SEL_DUMP_CFG_CURRENT_REGION
)
687 bool some_p
= full_p
|| has_preds_in_current_region_p (bb
);
694 if ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
695 && in_current_region_p (bb
)
696 && BLOCK_TO_BB (bb
->index
) == 0)
697 color
= "color = green, ";
701 if ((flags
& SEL_DUMP_CFG_FENCES
)
706 if (!sel_bb_empty_p (bb
))
709 insn_t tail
= BB_END (bb
);
712 cur_insn
= bb_note (bb
);
718 cur_insn
= NEXT_INSN (cur_insn
);
719 fence
= flist_lookup (fences
, cur_insn
);
723 if (!FENCE_SCHEDULED_P (fence
))
726 color
= "color = red, ";
728 color
= "color = yellow, ";
731 color
= "color = blue, ";
736 while (cur_insn
!= tail
);
740 style
= "style = dashed, ";
744 fprintf (f
, "\tbb%d [%s%slabel = \"{Basic block %d", bb
->index
,
745 style
, color
, bb
->index
);
747 if ((flags
& SEL_DUMP_CFG_BB_LOOP
)
748 && bb
->loop_father
!= NULL
)
749 fprintf (f
, ", loop %d", bb
->loop_father
->num
);
752 && (flags
& SEL_DUMP_CFG_BB_NOTES_LIST
))
754 insn_t notes
= BB_NOTE_LIST (bb
);
756 if (notes
!= NULL_RTX
)
760 /* For simplicity, we dump notes from note_list in reversed order
761 to that what they will appear in the code. */
762 while (notes
!= NULL_RTX
)
764 sel_dump_cfg_insn (notes
, flags
);
767 notes
= PREV_INSN (notes
);
773 && (flags
& SEL_DUMP_CFG_AV_SET
)
774 && in_current_region_p (bb
)
775 && !sel_bb_empty_p (bb
))
779 if (BB_AV_SET_VALID_P (bb
))
780 dump_av_set (BB_AV_SET (bb
));
781 else if (BB_AV_LEVEL (bb
) == -1)
782 fprintf (f
, "AV_SET needs update");
785 if ((flags
& SEL_DUMP_CFG_LV_SET
)
786 && !sel_bb_empty_p (bb
))
790 if (BB_LV_SET_VALID_P (bb
))
791 dump_lv_set (BB_LV_SET (bb
));
793 fprintf (f
, "LV_SET needs update");
797 && (flags
& SEL_DUMP_CFG_BB_INSNS
))
800 while (insn
!= next_tail
)
802 sel_dump_cfg_insn (insn
, flags
);
805 insn
= NEXT_INSN (insn
);
809 fprintf (f
, "}\"];\n");
811 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
812 if (full_p
|| in_current_region_p (e
->dest
))
813 sel_dump_cfg_edge (f
, e
);
819 sched_dump_to_dot_p
= false;
822 /* Dump a cfg region to the file specified by TAG honoring flags.
823 The file is created by the function. */
825 sel_dump_cfg_1 (const char *tag
, int flags
)
831 ++sel_dump_cfg_fileno
;
836 i
= 1 + snprintf (NULL
, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
837 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
838 buf
= XNEWVEC (char, i
);
839 snprintf (buf
, i
, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
840 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
842 f
= fopen (buf
, "w");
845 fprintf (stderr
, "Can't create file: %s.\n", buf
);
848 sel_dump_cfg_2 (f
, flags
);
856 /* Setup cfg dumping flags. Used for debugging. */
858 setup_dump_cfg_params (void)
860 sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
862 sel_debug_cfg_root_postfix
= sel_debug_cfg_root_postfix_default
;
865 /* Debug a cfg region with FLAGS. */
867 sel_debug_cfg_1 (int flags
)
869 bool t1
= sel_dump_cfg_p
;
870 int t2
= sel_dump_cfg_fileno
;
872 sel_dump_cfg_p
= true;
873 sel_dump_cfg_fileno
= ++sel_debug_cfg_fileno
;
875 sel_dump_cfg_1 ("sel-debug-cfg", flags
);
877 sel_dump_cfg_fileno
= t2
;
881 /* Dumps av_set AV to stderr. */
883 debug_av_set (av_set_t av
)
885 switch_dump (stderr
);
891 /* Dump LV to stderr. */
893 debug_lv_set (regset lv
)
895 switch_dump (stderr
);
901 /* Dump an instruction list P to stderr. */
903 debug_ilist (ilist_t p
)
905 switch_dump (stderr
);
911 /* Dump a boundary list BNDS to stderr. */
913 debug_blist (blist_t bnds
)
915 switch_dump (stderr
);
921 /* Dump an insn vector SUCCS. */
923 debug_insn_vector (rtx_vec_t succs
)
925 switch_dump (stderr
);
926 dump_insn_vector (succs
);
931 /* Dump a hard reg set SET to stderr. */
933 debug_hard_reg_set (HARD_REG_SET set
)
935 switch_dump (stderr
);
936 dump_hard_reg_set ("", set
);
941 /* Debug a cfg region with default flags. */
945 sel_debug_cfg_1 (sel_debug_cfg_flags
);
948 /* Print a current cselib value for X's address to stderr. */
950 debug_mem_addr_value (rtx x
)
953 enum machine_mode address_mode
;
955 gcc_assert (MEM_P (x
));
956 address_mode
= get_address_mode (x
);
958 t
= shallow_copy_rtx (x
);
959 if (cselib_lookup (XEXP (t
, 0), address_mode
, 0, GET_MODE (t
)))
960 XEXP (t
, 0) = cselib_subst_to_values (XEXP (t
, 0), GET_MODE (t
));
963 addr
= get_addr (XEXP (t
, 0));