1 /* Instruction scheduling pass. Log dumping infrastructure.
2 Copyright (C) 2006, 2007, 2008, 2010 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"
35 #include "basic-block.h"
39 #ifdef INSN_SCHEDULING
40 #include "sel-sched-ir.h"
41 #include "sel-sched-dump.h"
44 /* These variables control high-level pretty printing. */
45 static int sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
46 static int sel_debug_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
48 /* True when a cfg should be dumped. */
49 static bool sel_dump_cfg_p
;
51 /* Variables that are used to build the cfg dump file name. */
52 static const char * const sel_debug_cfg_root
= "./";
53 static const char * const sel_debug_cfg_root_postfix_default
= "";
54 static const char *sel_debug_cfg_root_postfix
= "";
55 static int sel_dump_cfg_fileno
= -1;
56 static int sel_debug_cfg_fileno
= -1;
58 /* When this flag is on, we are dumping to the .dot file.
59 When it is off, we are dumping to log.
60 This is useful to differentiate formatting between log and .dot
62 bool sched_dump_to_dot_p
= false;
64 /* Controls how insns from a fence list should be dumped. */
65 static int dump_flist_insn_flags
= (DUMP_INSN_UID
| DUMP_INSN_BBN
69 /* The variable used to hold the value of sched_dump when temporarily
70 switching dump output to the other source, e.g. the .dot file. */
71 static FILE *saved_sched_dump
= NULL
;
73 /* Switch sched_dump to TO. It must not be called twice. */
75 switch_dump (FILE *to
)
77 gcc_assert (saved_sched_dump
== NULL
);
79 saved_sched_dump
= sched_dump
;
83 /* Restore previously switched dump. */
87 sched_dump
= saved_sched_dump
;
88 saved_sched_dump
= NULL
;
92 /* Functions for dumping instructions, av sets, and exprs. */
94 /* Default flags for dumping insns. */
95 static int dump_insn_rtx_flags
= DUMP_INSN_RTX_PATTERN
;
97 /* Default flags for dumping vinsns. */
98 static int dump_vinsn_flags
= (DUMP_VINSN_INSN_RTX
| DUMP_VINSN_TYPE
101 /* Default flags for dumping expressions. */
102 static int dump_expr_flags
= DUMP_EXPR_ALL
;
104 /* Default flags for dumping insns when debugging. */
105 static int debug_insn_rtx_flags
= DUMP_INSN_RTX_ALL
;
107 /* Default flags for dumping vinsns when debugging. */
108 static int debug_vinsn_flags
= DUMP_VINSN_ALL
;
110 /* Default flags for dumping expressions when debugging. */
111 static int debug_expr_flags
= DUMP_EXPR_ALL
;
113 /* Controls how an insn from stream should be dumped when debugging. */
114 static int debug_insn_flags
= DUMP_INSN_ALL
;
116 /* Print an rtx X. */
118 sel_print_rtl (rtx x
)
120 print_rtl_single (sched_dump
, x
);
123 /* Dump insn INSN honoring FLAGS. */
125 dump_insn_rtx_1 (rtx insn
, int flags
)
129 /* flags == -1 also means dumping all. */
132 flags
|= DUMP_INSN_RTX_ALL
;
136 if (flags
& DUMP_INSN_RTX_UID
)
137 sel_print ("%d;", INSN_UID (insn
));
139 if (flags
& DUMP_INSN_RTX_PATTERN
)
143 print_insn (buf
, insn
, 0);
144 sel_print ("%s;", buf
);
147 if (flags
& DUMP_INSN_RTX_BBN
)
149 basic_block bb
= BLOCK_FOR_INSN (insn
);
151 sel_print ("bb:%d;", bb
!= NULL
? bb
->index
: -1);
158 /* Dump INSN with default flags. */
160 dump_insn_rtx (rtx insn
)
162 dump_insn_rtx_1 (insn
, dump_insn_rtx_flags
);
166 /* Dump INSN to stderr. */
168 debug_insn_rtx (rtx insn
)
170 switch_dump (stderr
);
171 dump_insn_rtx_1 (insn
, debug_insn_rtx_flags
);
176 /* Dump vinsn VI honoring flags. */
178 dump_vinsn_1 (vinsn_t vi
, int flags
)
182 /* flags == -1 also means dumping all. */
185 flags
|= DUMP_VINSN_ALL
;
189 if (flags
& DUMP_VINSN_INSN_RTX
)
190 dump_insn_rtx_1 (VINSN_INSN_RTX (vi
), dump_insn_rtx_flags
| all
);
192 if (flags
& DUMP_VINSN_TYPE
)
193 sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi
)));
195 if (flags
& DUMP_VINSN_COUNT
)
196 sel_print ("count:%d;", VINSN_COUNT (vi
));
198 if (flags
& DUMP_VINSN_COST
)
203 sel_print ("cost:%d;", cost
);
209 /* Dump vinsn VI with default flags. */
211 dump_vinsn (vinsn_t vi
)
213 dump_vinsn_1 (vi
, dump_vinsn_flags
);
216 /* Dump vinsn VI to stderr. */
218 debug_vinsn (vinsn_t vi
)
220 switch_dump (stderr
);
221 dump_vinsn_1 (vi
, debug_vinsn_flags
);
226 /* Dump EXPR honoring flags. */
228 dump_expr_1 (expr_t expr
, int flags
)
232 /* flags == -1 also means dumping all. */
235 flags
|= DUMP_EXPR_ALL
;
239 if (flags
& DUMP_EXPR_VINSN
)
240 dump_vinsn_1 (EXPR_VINSN (expr
), dump_vinsn_flags
| all
);
242 if (flags
& DUMP_EXPR_SPEC
)
244 int spec
= EXPR_SPEC (expr
);
247 sel_print ("spec:%d;", spec
);
250 if (flags
& DUMP_EXPR_USEFULNESS
)
252 int use
= EXPR_USEFULNESS (expr
);
254 if (use
!= REG_BR_PROB_BASE
)
255 sel_print ("use:%d;", use
);
258 if (flags
& DUMP_EXPR_PRIORITY
)
259 sel_print ("prio:%d;", EXPR_PRIORITY (expr
));
261 if (flags
& DUMP_EXPR_SCHED_TIMES
)
263 int times
= EXPR_SCHED_TIMES (expr
);
266 sel_print ("times:%d;", times
);
269 if (flags
& DUMP_EXPR_SPEC_DONE_DS
)
271 ds_t spec_done_ds
= EXPR_SPEC_DONE_DS (expr
);
273 if (spec_done_ds
!= 0)
274 sel_print ("ds:%d;", spec_done_ds
);
277 if (flags
& DUMP_EXPR_ORIG_BB
)
279 int orig_bb
= EXPR_ORIG_BB_INDEX (expr
);
282 sel_print ("orig_bb:%d;", orig_bb
);
285 if (EXPR_TARGET_AVAILABLE (expr
) < 1)
286 sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr
));
290 /* Dump expression EXPR with default flags. */
292 dump_expr (expr_t expr
)
294 dump_expr_1 (expr
, dump_expr_flags
);
297 /* Dump expression EXPR to stderr. */
299 debug_expr (expr_t expr
)
301 switch_dump (stderr
);
302 dump_expr_1 (expr
, debug_expr_flags
);
307 /* Dump insn I honoring FLAGS. */
309 dump_insn_1 (insn_t i
, int flags
)
315 flags
|= DUMP_INSN_ALL
;
317 if (!sched_dump_to_dot_p
)
320 if (flags
& DUMP_INSN_EXPR
)
322 dump_expr_1 (INSN_EXPR (i
), dump_expr_flags
| all
);
325 else if (flags
& DUMP_INSN_PATTERN
)
327 dump_insn_rtx_1 (i
, DUMP_INSN_RTX_PATTERN
| all
);
330 else if (flags
& DUMP_INSN_UID
)
331 sel_print ("uid:%d;", INSN_UID (i
));
333 if (flags
& DUMP_INSN_SEQNO
)
334 sel_print ("seqno:%d;", INSN_SEQNO (i
));
336 if (flags
& DUMP_INSN_SCHED_CYCLE
)
338 int cycle
= INSN_SCHED_CYCLE (i
);
341 sel_print ("cycle:%d;", cycle
);
344 if (!sched_dump_to_dot_p
)
348 /* Dump insn I with default flags. */
352 dump_insn_1 (i
, DUMP_INSN_EXPR
| DUMP_INSN_SCHED_CYCLE
);
355 /* Dump INSN to stderr. */
357 debug_insn (insn_t insn
)
359 switch_dump (stderr
);
360 dump_insn_1 (insn
, debug_insn_flags
);
365 /* Dumps av_set AV. */
367 dump_av_set (av_set_t av
)
372 if (!sched_dump_to_dot_p
)
375 FOR_EACH_EXPR (expr
, i
, av
)
378 if (!sched_dump_to_dot_p
)
384 if (!sched_dump_to_dot_p
)
388 /* Dumps lvset LV. */
390 dump_lv_set (regset lv
)
394 /* This code was adapted from cfg.c: dump_regset (). */
400 reg_set_iterator rsi
;
403 EXECUTE_IF_SET_IN_REG_SET (lv
, 0, i
, rsi
)
405 sel_print (" %d", i
);
406 if (i
< FIRST_PSEUDO_REGISTER
)
408 sel_print (" [%s]", reg_names
[i
]);
414 if (sched_dump_to_dot_p
&& count
== 12)
425 /* Dumps a list of instructions pointed to by P. */
427 dump_ilist (ilist_t p
)
431 dump_insn (ILIST_INSN (p
));
436 /* Dumps a list of boundaries pointed to by BNDS. */
438 dump_blist (blist_t bnds
)
440 for (; bnds
; bnds
= BLIST_NEXT (bnds
))
442 bnd_t bnd
= BLIST_BND (bnds
);
444 sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd
)));
445 dump_ilist (BND_PTR (bnd
));
450 /* Dumps a list of fences pointed to by L. */
452 dump_flist (flist_t l
)
456 dump_insn_1 (FENCE_INSN (FLIST_FENCE (l
)), dump_flist_insn_flags
);
462 /* Dumps an insn vector SUCCS. */
464 dump_insn_vector (rtx_vec_t succs
)
469 FOR_EACH_VEC_ELT (rtx
, succs
, i
, succ
)
476 /* Dumps a hard reg set SET to FILE using PREFIX. */
478 print_hard_reg_set (FILE *file
, const char *prefix
, HARD_REG_SET set
)
482 fprintf (file
, "%s{ ", prefix
);
483 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
485 if (TEST_HARD_REG_BIT (set
, i
))
486 fprintf (file
, "%d ", i
);
488 fprintf (file
, "}\n");
491 /* Dumps a hard reg set SET using PREFIX. */
493 dump_hard_reg_set (const char *prefix
, HARD_REG_SET set
)
495 print_hard_reg_set (sched_dump
, prefix
, set
);
498 /* Pretty print INSN. This is used as a hook. */
500 sel_print_insn (const_rtx insn
, int aligned ATTRIBUTE_UNUSED
)
504 /* '+' before insn means it is a new cycle start and it's not been
505 scheduled yet. '>' - has been scheduled. */
506 if (s_i_d
&& INSN_LUID (insn
) > 0)
507 if (GET_MODE (insn
) == TImode
)
508 sprintf (buf
, "%s %4d",
509 INSN_SCHED_TIMES (insn
) > 0 ? "> " : "< ",
512 sprintf (buf
, "%s %4d",
513 INSN_SCHED_TIMES (insn
) > 0 ? "! " : " ",
516 if (GET_MODE (insn
) == TImode
)
517 sprintf (buf
, "+ %4d", INSN_UID (insn
));
519 sprintf (buf
, " %4d", INSN_UID (insn
));
525 /* Functions for pretty printing of CFG. */
527 /* Replace all occurencies of STR1 to STR2 in BUF.
528 The BUF must be large enough to hold the result. */
530 replace_str_in_buf (char *buf
, const char *str1
, const char *str2
)
532 int buf_len
= strlen (buf
);
533 int str1_len
= strlen (str1
);
534 int str2_len
= strlen (str2
);
535 int diff
= str2_len
- str1_len
;
540 p
= strstr (p
, str1
);
543 char *p1
= p
+ str1_len
;
544 /* Copy the rest of buf and '\0'. */
545 int n
= buf
+ buf_len
- p1
;
548 /* Shift str by DIFF chars. */
550 for (i
= n
; i
>= 0; i
--)
551 p1
[i
+ diff
] = p1
[i
];
553 for (i
= 0; i
<= n
; i
++)
554 p1
[i
+ diff
] = p1
[i
];
557 for (i
= 0; i
< str2_len
; i
++)
568 /* Replace characters in BUF that have special meaning in .dot file. */
570 sel_prepare_string_for_dot_label (char *buf
)
572 static char specials_from
[7][2] = { "<", ">", "{", "|", "}", "\"",
574 static char specials_to
[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}",
578 for (i
= 0; i
< 7; i
++)
579 replace_str_in_buf (buf
, specials_from
[i
], specials_to
[i
]);
582 /* This function acts like printf but dumps to the sched_dump file. */
584 sel_print (const char *fmt
, ...)
588 if (sched_dump_to_dot_p
)
591 if (vasprintf (&message
, fmt
, ap
) >= 0 && message
!= NULL
)
593 message
= (char *) xrealloc (message
, 2 * strlen (message
) + 1);
594 sel_prepare_string_for_dot_label (message
);
595 fprintf (sched_dump
, "%s", message
);
600 vfprintf (sched_dump
, fmt
, ap
);
604 /* Dump INSN with FLAGS. */
606 sel_dump_cfg_insn (insn_t insn
, int flags
)
608 int insn_flags
= DUMP_INSN_UID
| DUMP_INSN_PATTERN
;
610 if (sched_luids
!= NULL
&& INSN_LUID (insn
) > 0)
612 if (flags
& SEL_DUMP_CFG_INSN_SEQNO
)
613 insn_flags
|= DUMP_INSN_SEQNO
| DUMP_INSN_SCHED_CYCLE
| DUMP_INSN_EXPR
;
616 dump_insn_1 (insn
, insn_flags
);
619 /* Dump E to the dot file F. */
621 sel_dump_cfg_edge (FILE *f
, edge e
)
626 if (e
->flags
& EDGE_FALLTHRU
)
629 color
= ", color = red";
631 else if (e
->src
->next_bb
== e
->dest
)
634 color
= ", color = blue";
642 fprintf (f
, "\tbb%d -> bb%d [weight = %d%s];\n",
643 e
->src
->index
, e
->dest
->index
, w
, color
);
647 /* Return true if BB has a predesessor from current region.
648 TODO: Either make this function to trace back through empty block
649 or just remove those empty blocks. */
651 has_preds_in_current_region_p (basic_block bb
)
656 gcc_assert (!in_current_region_p (bb
));
658 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
659 if (in_current_region_p (e
->src
))
665 /* Dump a cfg region to the dot file F honoring FLAGS. */
667 sel_dump_cfg_2 (FILE *f
, int flags
)
671 sched_dump_to_dot_p
= true;
674 fprintf (f
, "digraph G {\n"
676 "\tnode [shape = record, fontsize = 9];\n");
678 if (flags
& SEL_DUMP_CFG_FUNCTION_NAME
)
679 fprintf (f
, "function [label = \"%s\"];\n", current_function_name ());
683 insn_t insn
= BB_HEAD (bb
);
684 insn_t next_tail
= NEXT_INSN (BB_END (bb
));
687 bool in_region_p
= ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
688 && in_current_region_p (bb
));
689 bool full_p
= (!(flags
& SEL_DUMP_CFG_CURRENT_REGION
)
691 bool some_p
= full_p
|| has_preds_in_current_region_p (bb
);
698 if ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
699 && in_current_region_p (bb
)
700 && BLOCK_TO_BB (bb
->index
) == 0)
701 color
= "color = green, ";
705 if ((flags
& SEL_DUMP_CFG_FENCES
)
710 if (!sel_bb_empty_p (bb
))
713 insn_t tail
= BB_END (bb
);
716 cur_insn
= bb_note (bb
);
722 cur_insn
= NEXT_INSN (cur_insn
);
723 fence
= flist_lookup (fences
, cur_insn
);
727 if (!FENCE_SCHEDULED_P (fence
))
730 color
= "color = red, ";
732 color
= "color = yellow, ";
735 color
= "color = blue, ";
740 while (cur_insn
!= tail
);
744 style
= "style = dashed, ";
748 fprintf (f
, "\tbb%d [%s%slabel = \"{Basic block %d", bb
->index
,
749 style
, color
, bb
->index
);
751 if ((flags
& SEL_DUMP_CFG_BB_LOOP
)
752 && bb
->loop_father
!= NULL
)
753 fprintf (f
, ", loop %d", bb
->loop_father
->num
);
756 && (flags
& SEL_DUMP_CFG_BB_NOTES_LIST
))
758 insn_t notes
= BB_NOTE_LIST (bb
);
760 if (notes
!= NULL_RTX
)
764 /* For simplicity, we dump notes from note_list in reversed order
765 to that what they will appear in the code. */
766 while (notes
!= NULL_RTX
)
768 sel_dump_cfg_insn (notes
, flags
);
771 notes
= PREV_INSN (notes
);
777 && (flags
& SEL_DUMP_CFG_AV_SET
)
778 && in_current_region_p (bb
)
779 && !sel_bb_empty_p (bb
))
783 if (BB_AV_SET_VALID_P (bb
))
784 dump_av_set (BB_AV_SET (bb
));
785 else if (BB_AV_LEVEL (bb
) == -1)
786 fprintf (f
, "AV_SET needs update");
789 if ((flags
& SEL_DUMP_CFG_LV_SET
)
790 && !sel_bb_empty_p (bb
))
794 if (BB_LV_SET_VALID_P (bb
))
795 dump_lv_set (BB_LV_SET (bb
));
797 fprintf (f
, "LV_SET needs update");
801 && (flags
& SEL_DUMP_CFG_BB_INSNS
))
804 while (insn
!= next_tail
)
806 sel_dump_cfg_insn (insn
, flags
);
809 insn
= NEXT_INSN (insn
);
813 fprintf (f
, "}\"];\n");
815 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
816 if (full_p
|| in_current_region_p (e
->dest
))
817 sel_dump_cfg_edge (f
, e
);
823 sched_dump_to_dot_p
= false;
826 /* Dump a cfg region to the file specified by TAG honoring flags.
827 The file is created by the function. */
829 sel_dump_cfg_1 (const char *tag
, int flags
)
835 ++sel_dump_cfg_fileno
;
840 i
= 1 + snprintf (NULL
, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
841 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
842 buf
= XNEWVEC (char, i
);
843 snprintf (buf
, i
, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
844 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
846 f
= fopen (buf
, "w");
849 fprintf (stderr
, "Can't create file: %s.\n", buf
);
852 sel_dump_cfg_2 (f
, flags
);
860 /* Setup cfg dumping flags. Used for debugging. */
862 setup_dump_cfg_params (void)
864 sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
866 sel_debug_cfg_root_postfix
= sel_debug_cfg_root_postfix_default
;
869 /* Debug a cfg region with FLAGS. */
871 sel_debug_cfg_1 (int flags
)
873 bool t1
= sel_dump_cfg_p
;
874 int t2
= sel_dump_cfg_fileno
;
876 sel_dump_cfg_p
= true;
877 sel_dump_cfg_fileno
= ++sel_debug_cfg_fileno
;
879 sel_dump_cfg_1 ("sel-debug-cfg", flags
);
881 sel_dump_cfg_fileno
= t2
;
885 /* Dumps av_set AV to stderr. */
887 debug_av_set (av_set_t av
)
889 switch_dump (stderr
);
895 /* Dump LV to stderr. */
897 debug_lv_set (regset lv
)
899 switch_dump (stderr
);
905 /* Dump an instruction list P to stderr. */
907 debug_ilist (ilist_t p
)
909 switch_dump (stderr
);
915 /* Dump a boundary list BNDS to stderr. */
917 debug_blist (blist_t bnds
)
919 switch_dump (stderr
);
925 /* Dump an insn vector SUCCS. */
927 debug_insn_vector (rtx_vec_t succs
)
929 switch_dump (stderr
);
930 dump_insn_vector (succs
);
935 /* Dump a hard reg set SET to stderr. */
937 debug_hard_reg_set (HARD_REG_SET set
)
939 switch_dump (stderr
);
940 dump_hard_reg_set ("", set
);
945 /* Debug a cfg region with default flags. */
949 sel_debug_cfg_1 (sel_debug_cfg_flags
);
952 /* Print a current cselib value for X's address to stderr. */
954 debug_mem_addr_value (rtx x
)
957 enum machine_mode address_mode
;
959 gcc_assert (MEM_P (x
));
960 address_mode
= targetm
.addr_space
.address_mode (MEM_ADDR_SPACE (x
));
962 t
= shallow_copy_rtx (x
);
963 if (cselib_lookup (XEXP (t
, 0), address_mode
, 0, GET_MODE (t
)))
964 XEXP (t
, 0) = cselib_subst_to_values (XEXP (t
, 0), GET_MODE (t
));
967 addr
= get_addr (XEXP (t
, 0));