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"
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
);
211 debug (vinsn_def
&ref
)
213 switch_dump (stderr
);
214 dump_vinsn_1 (&ref
, dump_vinsn_flags
);
220 debug (vinsn_def
*ptr
)
225 fprintf (stderr
, "<nil>\n");
229 debug_verbose (vinsn_def
&ref
)
231 switch_dump (stderr
);
232 dump_vinsn_1 (&ref
, debug_vinsn_flags
);
238 debug_verbose (vinsn_def
*ptr
)
243 fprintf (stderr
, "<nil>\n");
246 /* Dump vinsn VI to stderr. */
248 debug_vinsn (vinsn_t vi
)
250 switch_dump (stderr
);
251 dump_vinsn_1 (vi
, debug_vinsn_flags
);
256 /* Dump EXPR honoring flags. */
258 dump_expr_1 (expr_t expr
, int flags
)
262 /* flags == -1 also means dumping all. */
265 flags
|= DUMP_EXPR_ALL
;
269 if (flags
& DUMP_EXPR_VINSN
)
270 dump_vinsn_1 (EXPR_VINSN (expr
), dump_vinsn_flags
| all
);
272 if (flags
& DUMP_EXPR_SPEC
)
274 int spec
= EXPR_SPEC (expr
);
277 sel_print ("spec:%d;", spec
);
280 if (flags
& DUMP_EXPR_USEFULNESS
)
282 int use
= EXPR_USEFULNESS (expr
);
284 if (use
!= REG_BR_PROB_BASE
)
285 sel_print ("use:%d;", use
);
288 if (flags
& DUMP_EXPR_PRIORITY
)
289 sel_print ("prio:%d;", EXPR_PRIORITY (expr
));
291 if (flags
& DUMP_EXPR_SCHED_TIMES
)
293 int times
= EXPR_SCHED_TIMES (expr
);
296 sel_print ("times:%d;", times
);
299 if (flags
& DUMP_EXPR_SPEC_DONE_DS
)
301 ds_t spec_done_ds
= EXPR_SPEC_DONE_DS (expr
);
303 if (spec_done_ds
!= 0)
304 sel_print ("ds:%d;", spec_done_ds
);
307 if (flags
& DUMP_EXPR_ORIG_BB
)
309 int orig_bb
= EXPR_ORIG_BB_INDEX (expr
);
312 sel_print ("orig_bb:%d;", orig_bb
);
315 if (EXPR_TARGET_AVAILABLE (expr
) < 1)
316 sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr
));
320 /* Dump expression EXPR with default flags. */
322 dump_expr (expr_t expr
)
324 dump_expr_1 (expr
, dump_expr_flags
);
327 /* Dump expression EXPR to stderr. */
329 debug_expr (expr_t expr
)
331 switch_dump (stderr
);
332 dump_expr_1 (expr
, debug_expr_flags
);
337 /* Dump expression REF. */
340 debug (expr_def
&ref
)
342 switch_dump (stderr
);
343 dump_expr_1 (&ref
, 0);
349 debug (expr_def
*ptr
)
354 fprintf (stderr
, "<nil>\n");
357 /* Dump expression REF verbosely. */
360 debug_verbose (expr_def
&ref
)
362 switch_dump (stderr
);
363 dump_expr_1 (&ref
, DUMP_EXPR_ALL
);
369 debug_verbose (expr_def
*ptr
)
372 debug_verbose (*ptr
);
374 fprintf (stderr
, "<nil>\n");
377 /* Dump insn I honoring FLAGS. */
379 dump_insn_1 (insn_t i
, int flags
)
385 flags
|= DUMP_INSN_ALL
;
387 if (!sched_dump_to_dot_p
)
390 if (flags
& DUMP_INSN_EXPR
)
392 dump_expr_1 (INSN_EXPR (i
), dump_expr_flags
| all
);
395 else if (flags
& DUMP_INSN_PATTERN
)
397 dump_insn_rtx_1 (i
, DUMP_INSN_RTX_PATTERN
| all
);
400 else if (flags
& DUMP_INSN_UID
)
401 sel_print ("uid:%d;", INSN_UID (i
));
403 if (flags
& DUMP_INSN_SEQNO
)
404 sel_print ("seqno:%d;", INSN_SEQNO (i
));
406 if (flags
& DUMP_INSN_SCHED_CYCLE
)
408 int cycle
= INSN_SCHED_CYCLE (i
);
411 sel_print ("cycle:%d;", cycle
);
414 if (!sched_dump_to_dot_p
)
418 /* Dump insn I with default flags. */
422 dump_insn_1 (i
, DUMP_INSN_EXPR
| DUMP_INSN_SCHED_CYCLE
);
425 /* Dump INSN to stderr. */
427 debug_insn (insn_t insn
)
429 switch_dump (stderr
);
430 dump_insn_1 (insn
, debug_insn_flags
);
435 /* Dumps av_set AV. */
437 dump_av_set (av_set_t av
)
442 if (!sched_dump_to_dot_p
)
445 FOR_EACH_EXPR (expr
, i
, av
)
448 if (!sched_dump_to_dot_p
)
454 if (!sched_dump_to_dot_p
)
458 /* Dumps lvset LV. */
460 dump_lv_set (regset lv
)
464 /* This code was adapted from cfg.c: dump_regset (). */
470 reg_set_iterator rsi
;
473 EXECUTE_IF_SET_IN_REG_SET (lv
, 0, i
, rsi
)
475 sel_print (" %d", i
);
476 if (i
< FIRST_PSEUDO_REGISTER
)
478 sel_print (" [%s]", reg_names
[i
]);
484 if (sched_dump_to_dot_p
&& count
== 12)
495 /* Dumps a list of instructions pointed to by P. */
497 dump_ilist (ilist_t p
)
501 dump_insn (ILIST_INSN (p
));
506 /* Dumps a list of boundaries pointed to by BNDS. */
508 dump_blist (blist_t bnds
)
510 for (; bnds
; bnds
= BLIST_NEXT (bnds
))
512 bnd_t bnd
= BLIST_BND (bnds
);
514 sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd
)));
515 dump_ilist (BND_PTR (bnd
));
520 /* Dumps a list of fences pointed to by L. */
522 dump_flist (flist_t l
)
526 dump_insn_1 (FENCE_INSN (FLIST_FENCE (l
)), dump_flist_insn_flags
);
532 /* Dumps an insn vector SUCCS. */
534 dump_insn_vector (rtx_vec_t succs
)
539 FOR_EACH_VEC_ELT (succs
, i
, succ
)
546 /* Dumps a hard reg set SET to FILE using PREFIX. */
548 print_hard_reg_set (FILE *file
, const char *prefix
, HARD_REG_SET set
)
552 fprintf (file
, "%s{ ", prefix
);
553 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
555 if (TEST_HARD_REG_BIT (set
, i
))
556 fprintf (file
, "%d ", i
);
558 fprintf (file
, "}\n");
561 /* Dumps a hard reg set SET using PREFIX. */
563 dump_hard_reg_set (const char *prefix
, HARD_REG_SET set
)
565 print_hard_reg_set (sched_dump
, prefix
, set
);
568 /* Pretty print INSN. This is used as a hook. */
570 sel_print_insn (const_rtx insn
, int aligned ATTRIBUTE_UNUSED
)
574 /* '+' before insn means it is a new cycle start and it's not been
575 scheduled yet. '>' - has been scheduled. */
576 if (s_i_d
.exists () && INSN_LUID (insn
) > 0)
577 if (GET_MODE (insn
) == TImode
)
578 sprintf (buf
, "%s %4d",
579 INSN_SCHED_TIMES (insn
) > 0 ? "> " : "< ",
582 sprintf (buf
, "%s %4d",
583 INSN_SCHED_TIMES (insn
) > 0 ? "! " : " ",
586 if (GET_MODE (insn
) == TImode
)
587 sprintf (buf
, "+ %4d", INSN_UID (insn
));
589 sprintf (buf
, " %4d", INSN_UID (insn
));
595 /* Functions for pretty printing of CFG. */
596 /* FIXME: Using pretty-print here could simplify this stuff. */
598 /* Replace all occurencies of STR1 to STR2 in BUF.
599 The BUF must be large enough to hold the result. */
601 replace_str_in_buf (char *buf
, const char *str1
, const char *str2
)
603 int buf_len
= strlen (buf
);
604 int str1_len
= strlen (str1
);
605 int str2_len
= strlen (str2
);
606 int diff
= str2_len
- str1_len
;
611 p
= strstr (p
, str1
);
614 char *p1
= p
+ str1_len
;
615 /* Copy the rest of buf and '\0'. */
616 int n
= buf
+ buf_len
- p1
;
619 /* Shift str by DIFF chars. */
621 for (i
= n
; i
>= 0; i
--)
622 p1
[i
+ diff
] = p1
[i
];
624 for (i
= 0; i
<= n
; i
++)
625 p1
[i
+ diff
] = p1
[i
];
628 for (i
= 0; i
< str2_len
; i
++)
639 /* Replace characters in BUF that have special meaning in .dot file.
640 Similar to pp_write_text_as_dot_label_to_stream. */
642 sel_prepare_string_for_dot_label (char *buf
)
644 static char specials_from
[7][2] = { "<", ">", "{", "|", "}", "\"",
646 static char specials_to
[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}",
650 for (i
= 0; i
< 7; i
++)
651 replace_str_in_buf (buf
, specials_from
[i
], specials_to
[i
]);
654 /* This function acts like printf but dumps to the sched_dump file. */
656 sel_print (const char *fmt
, ...)
660 if (sched_dump_to_dot_p
)
663 if (vasprintf (&message
, fmt
, ap
) >= 0 && message
!= NULL
)
665 message
= (char *) xrealloc (message
, 2 * strlen (message
) + 1);
666 sel_prepare_string_for_dot_label (message
);
667 fprintf (sched_dump
, "%s", message
);
672 vfprintf (sched_dump
, fmt
, ap
);
676 /* Dump INSN with FLAGS. */
678 sel_dump_cfg_insn (insn_t insn
, int flags
)
680 int insn_flags
= DUMP_INSN_UID
| DUMP_INSN_PATTERN
;
682 if (sched_luids
.exists () && INSN_LUID (insn
) > 0)
684 if (flags
& SEL_DUMP_CFG_INSN_SEQNO
)
685 insn_flags
|= DUMP_INSN_SEQNO
| DUMP_INSN_SCHED_CYCLE
| DUMP_INSN_EXPR
;
688 dump_insn_1 (insn
, insn_flags
);
691 /* Dump E to the dot file F. */
693 sel_dump_cfg_edge (FILE *f
, edge e
)
698 if (e
->flags
& EDGE_FALLTHRU
)
701 color
= ", color = red";
703 else if (e
->src
->next_bb
== e
->dest
)
706 color
= ", color = blue";
714 fprintf (f
, "\tbb%d -> bb%d [weight = %d%s];\n",
715 e
->src
->index
, e
->dest
->index
, w
, color
);
719 /* Return true if BB has a predesessor from current region.
720 TODO: Either make this function to trace back through empty block
721 or just remove those empty blocks. */
723 has_preds_in_current_region_p (basic_block bb
)
728 gcc_assert (!in_current_region_p (bb
));
730 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
731 if (in_current_region_p (e
->src
))
737 /* Dump a cfg region to the dot file F honoring FLAGS. */
739 sel_dump_cfg_2 (FILE *f
, int flags
)
743 sched_dump_to_dot_p
= true;
746 fprintf (f
, "digraph G {\n"
748 "\tnode [shape = record, fontsize = 9];\n");
750 if (flags
& SEL_DUMP_CFG_FUNCTION_NAME
)
751 fprintf (f
, "function [label = \"%s\"];\n", current_function_name ());
753 FOR_EACH_BB_FN (bb
, cfun
)
755 insn_t insn
= BB_HEAD (bb
);
756 insn_t next_tail
= NEXT_INSN (BB_END (bb
));
759 bool in_region_p
= ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
760 && in_current_region_p (bb
));
761 bool full_p
= (!(flags
& SEL_DUMP_CFG_CURRENT_REGION
)
763 bool some_p
= full_p
|| has_preds_in_current_region_p (bb
);
770 if ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
771 && in_current_region_p (bb
)
772 && BLOCK_TO_BB (bb
->index
) == 0)
773 color
= "color = green, ";
777 if ((flags
& SEL_DUMP_CFG_FENCES
)
782 if (!sel_bb_empty_p (bb
))
785 insn_t tail
= BB_END (bb
);
788 cur_insn
= bb_note (bb
);
794 cur_insn
= NEXT_INSN (cur_insn
);
795 fence
= flist_lookup (fences
, cur_insn
);
799 if (!FENCE_SCHEDULED_P (fence
))
802 color
= "color = red, ";
804 color
= "color = yellow, ";
807 color
= "color = blue, ";
812 while (cur_insn
!= tail
);
816 style
= "style = dashed, ";
820 fprintf (f
, "\tbb%d [%s%slabel = \"{Basic block %d", bb
->index
,
821 style
, color
, bb
->index
);
823 if ((flags
& SEL_DUMP_CFG_BB_LOOP
)
824 && bb
->loop_father
!= NULL
)
825 fprintf (f
, ", loop %d", bb
->loop_father
->num
);
828 && (flags
& SEL_DUMP_CFG_BB_NOTES_LIST
))
830 insn_t notes
= BB_NOTE_LIST (bb
);
832 if (notes
!= NULL_RTX
)
836 /* For simplicity, we dump notes from note_list in reversed order
837 to that what they will appear in the code. */
838 while (notes
!= NULL_RTX
)
840 sel_dump_cfg_insn (notes
, flags
);
843 notes
= PREV_INSN (notes
);
849 && (flags
& SEL_DUMP_CFG_AV_SET
)
850 && in_current_region_p (bb
)
851 && !sel_bb_empty_p (bb
))
855 if (BB_AV_SET_VALID_P (bb
))
856 dump_av_set (BB_AV_SET (bb
));
857 else if (BB_AV_LEVEL (bb
) == -1)
858 fprintf (f
, "AV_SET needs update");
861 if ((flags
& SEL_DUMP_CFG_LV_SET
)
862 && !sel_bb_empty_p (bb
))
866 if (BB_LV_SET_VALID_P (bb
))
867 dump_lv_set (BB_LV_SET (bb
));
869 fprintf (f
, "LV_SET needs update");
873 && (flags
& SEL_DUMP_CFG_BB_INSNS
))
876 while (insn
!= next_tail
)
878 sel_dump_cfg_insn (insn
, flags
);
881 insn
= NEXT_INSN (insn
);
885 fprintf (f
, "}\"];\n");
887 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
888 if (full_p
|| in_current_region_p (e
->dest
))
889 sel_dump_cfg_edge (f
, e
);
895 sched_dump_to_dot_p
= false;
898 /* Dump a cfg region to the file specified by TAG honoring flags.
899 The file is created by the function. */
901 sel_dump_cfg_1 (const char *tag
, int flags
)
907 ++sel_dump_cfg_fileno
;
912 i
= 1 + snprintf (NULL
, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
913 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
914 buf
= XNEWVEC (char, i
);
915 snprintf (buf
, i
, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
916 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
918 f
= fopen (buf
, "w");
921 fprintf (stderr
, "Can't create file: %s.\n", buf
);
924 sel_dump_cfg_2 (f
, flags
);
932 /* Setup cfg dumping flags. Used for debugging. */
934 setup_dump_cfg_params (void)
936 sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
938 sel_debug_cfg_root_postfix
= sel_debug_cfg_root_postfix_default
;
941 /* Debug a cfg region with FLAGS. */
943 sel_debug_cfg_1 (int flags
)
945 bool t1
= sel_dump_cfg_p
;
946 int t2
= sel_dump_cfg_fileno
;
948 sel_dump_cfg_p
= true;
949 sel_dump_cfg_fileno
= ++sel_debug_cfg_fileno
;
951 sel_dump_cfg_1 ("sel-debug-cfg", flags
);
953 sel_dump_cfg_fileno
= t2
;
957 /* Dumps av_set AV to stderr. */
959 debug_av_set (av_set_t av
)
961 switch_dump (stderr
);
967 /* Dump LV to stderr. */
969 debug_lv_set (regset lv
)
971 switch_dump (stderr
);
977 /* Dump an instruction list P to stderr. */
979 debug_ilist (ilist_t p
)
981 switch_dump (stderr
);
987 /* Dump a boundary list BNDS to stderr. */
989 debug_blist (blist_t bnds
)
991 switch_dump (stderr
);
997 /* Dump a rtx vector REF. */
999 debug (vec
<rtx
> &ref
)
1001 switch_dump (stderr
);
1002 dump_insn_vector (ref
);
1008 debug (vec
<rtx
> *ptr
)
1013 fprintf (stderr
, "<nil>\n");
1016 /* Dump an insn vector SUCCS. */
1018 debug_insn_vector (rtx_vec_t succs
)
1020 switch_dump (stderr
);
1021 dump_insn_vector (succs
);
1026 /* Dump a hard reg set SET to stderr. */
1028 debug_hard_reg_set (HARD_REG_SET set
)
1030 switch_dump (stderr
);
1031 dump_hard_reg_set ("", set
);
1036 /* Debug a cfg region with default flags. */
1038 sel_debug_cfg (void)
1040 sel_debug_cfg_1 (sel_debug_cfg_flags
);
1043 /* Print a current cselib value for X's address to stderr. */
1045 debug_mem_addr_value (rtx x
)
1048 enum machine_mode address_mode
;
1050 gcc_assert (MEM_P (x
));
1051 address_mode
= get_address_mode (x
);
1053 t
= shallow_copy_rtx (x
);
1054 if (cselib_lookup (XEXP (t
, 0), address_mode
, 0, GET_MODE (t
)))
1055 XEXP (t
, 0) = cselib_subst_to_values (XEXP (t
, 0), GET_MODE (t
));
1058 addr
= get_addr (XEXP (t
, 0));