1 /* Instruction scheduling pass. Log dumping infrastructure.
2 Copyright (C) 2006, 2007, 2008 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"
27 #include "hard-reg-set.h"
31 #include "insn-config.h"
32 #include "insn-attr.h"
35 #include "basic-block.h"
37 #include "sel-sched-ir.h"
38 #include "sel-sched-dump.h"
41 /* These variables control high-level pretty printing. */
42 static int sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
43 static int sel_debug_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
45 /* True when a cfg should be dumped. */
46 static bool sel_dump_cfg_p
;
48 /* Variables that are used to build the cfg dump file name. */
49 static const char * const sel_debug_cfg_root
= "./";
50 static const char * const sel_debug_cfg_root_postfix_default
= "";
51 static const char *sel_debug_cfg_root_postfix
= "";
52 static int sel_dump_cfg_fileno
= -1;
53 static int sel_debug_cfg_fileno
= -1;
55 /* When this flag is on, we are dumping to the .dot file.
56 When it is off, we are dumping to log.
57 This is useful to differentiate formatting between log and .dot
59 bool sched_dump_to_dot_p
= false;
61 /* Controls how insns from a fence list should be dumped. */
62 static int dump_flist_insn_flags
= (DUMP_INSN_UID
| DUMP_INSN_BBN
66 /* The variable used to hold the value of sched_dump when temporarily
67 switching dump output to the other source, e.g. the .dot file. */
68 static FILE *saved_sched_dump
= NULL
;
70 /* Switch sched_dump to TO. It must not be called twice. */
72 switch_dump (FILE *to
)
74 gcc_assert (saved_sched_dump
== NULL
);
76 saved_sched_dump
= sched_dump
;
80 /* Restore previously switched dump. */
84 sched_dump
= saved_sched_dump
;
85 saved_sched_dump
= NULL
;
89 /* Functions for dumping instructions, av sets, and exprs. */
91 /* Default flags for dumping insns. */
92 static int dump_insn_rtx_flags
= DUMP_INSN_RTX_PATTERN
;
94 /* Default flags for dumping vinsns. */
95 static int dump_vinsn_flags
= (DUMP_VINSN_INSN_RTX
| DUMP_VINSN_TYPE
98 /* Default flags for dumping expressions. */
99 static int dump_expr_flags
= DUMP_EXPR_ALL
;
101 /* Default flags for dumping insns when debugging. */
102 static int debug_insn_rtx_flags
= DUMP_INSN_RTX_ALL
;
104 /* Default flags for dumping vinsns when debugging. */
105 static int debug_vinsn_flags
= DUMP_VINSN_ALL
;
107 /* Default flags for dumping expressions when debugging. */
108 static int debug_expr_flags
= DUMP_EXPR_ALL
;
110 /* Controls how an insn from stream should be dumped when debugging. */
111 static int debug_insn_flags
= DUMP_INSN_ALL
;
113 /* Print an rtx X. */
115 sel_print_rtl (rtx x
)
117 print_rtl_single (sched_dump
, x
);
120 /* Dump insn INSN honoring FLAGS. */
122 dump_insn_rtx_1 (rtx insn
, int flags
)
126 /* flags == -1 also means dumping all. */
129 flags
|= DUMP_INSN_RTX_ALL
;
133 if (flags
& DUMP_INSN_RTX_UID
)
134 sel_print ("%d;", INSN_UID (insn
));
136 if (flags
& DUMP_INSN_RTX_PATTERN
)
140 print_insn (buf
, insn
, 0);
141 sel_print ("%s;", buf
);
144 if (flags
& DUMP_INSN_RTX_BBN
)
146 basic_block bb
= BLOCK_FOR_INSN (insn
);
148 sel_print ("bb:%d;", bb
!= NULL
? bb
->index
: -1);
155 /* Dump INSN with default flags. */
157 dump_insn_rtx (rtx insn
)
159 dump_insn_rtx_1 (insn
, dump_insn_rtx_flags
);
163 /* Dump INSN to stderr. */
165 debug_insn_rtx (rtx insn
)
167 switch_dump (stderr
);
168 dump_insn_rtx_1 (insn
, debug_insn_rtx_flags
);
173 /* Dump vinsn VI honoring flags. */
175 dump_vinsn_1 (vinsn_t vi
, int flags
)
179 /* flags == -1 also means dumping all. */
182 flags
|= DUMP_VINSN_ALL
;
186 if (flags
& DUMP_VINSN_INSN_RTX
)
187 dump_insn_rtx_1 (VINSN_INSN_RTX (vi
), dump_insn_rtx_flags
| all
);
189 if (flags
& DUMP_VINSN_TYPE
)
190 sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi
)));
192 if (flags
& DUMP_VINSN_COUNT
)
193 sel_print ("count:%d;", VINSN_COUNT (vi
));
195 if (flags
& DUMP_VINSN_COST
)
200 sel_print ("cost:%d;", cost
);
206 /* Dump vinsn VI with default flags. */
208 dump_vinsn (vinsn_t vi
)
210 dump_vinsn_1 (vi
, dump_vinsn_flags
);
213 /* Dump vinsn VI to stderr. */
215 debug_vinsn (vinsn_t vi
)
217 switch_dump (stderr
);
218 dump_vinsn_1 (vi
, debug_vinsn_flags
);
223 /* Dump EXPR honoring flags. */
225 dump_expr_1 (expr_t expr
, int flags
)
229 /* flags == -1 also means dumping all. */
232 flags
|= DUMP_EXPR_ALL
;
236 if (flags
& DUMP_EXPR_VINSN
)
237 dump_vinsn_1 (EXPR_VINSN (expr
), dump_vinsn_flags
| all
);
239 if (flags
& DUMP_EXPR_SPEC
)
241 int spec
= EXPR_SPEC (expr
);
244 sel_print ("spec:%d;", spec
);
247 if (flags
& DUMP_EXPR_USEFULNESS
)
249 int use
= EXPR_USEFULNESS (expr
);
251 if (use
!= REG_BR_PROB_BASE
)
252 sel_print ("use:%d;", use
);
255 if (flags
& DUMP_EXPR_PRIORITY
)
256 sel_print ("prio:%d;", EXPR_PRIORITY (expr
));
258 if (flags
& DUMP_EXPR_SCHED_TIMES
)
260 int times
= EXPR_SCHED_TIMES (expr
);
263 sel_print ("times:%d;", times
);
266 if (flags
& DUMP_EXPR_SPEC_DONE_DS
)
268 ds_t spec_done_ds
= EXPR_SPEC_DONE_DS (expr
);
270 if (spec_done_ds
!= 0)
271 sel_print ("ds:%d;", spec_done_ds
);
274 if (flags
& DUMP_EXPR_ORIG_BB
)
276 int orig_bb
= EXPR_ORIG_BB_INDEX (expr
);
279 sel_print ("orig_bb:%d;", orig_bb
);
282 if (EXPR_TARGET_AVAILABLE (expr
) < 1)
283 sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr
));
287 /* Dump expression EXPR with default flags. */
289 dump_expr (expr_t expr
)
291 dump_expr_1 (expr
, dump_expr_flags
);
294 /* Dump expression EXPR to stderr. */
296 debug_expr (expr_t expr
)
298 switch_dump (stderr
);
299 dump_expr_1 (expr
, debug_expr_flags
);
304 /* Dump insn I honoring FLAGS. */
306 dump_insn_1 (insn_t i
, int flags
)
312 flags
|= DUMP_INSN_ALL
;
314 if (!sched_dump_to_dot_p
)
317 if (flags
& DUMP_INSN_EXPR
)
319 dump_expr_1 (INSN_EXPR (i
), dump_expr_flags
| all
);
322 else if (flags
& DUMP_INSN_PATTERN
)
324 dump_insn_rtx_1 (i
, DUMP_INSN_RTX_PATTERN
| all
);
327 else if (flags
& DUMP_INSN_UID
)
328 sel_print ("uid:%d;", INSN_UID (i
));
330 if (flags
& DUMP_INSN_SEQNO
)
331 sel_print ("seqno:%d;", INSN_SEQNO (i
));
333 if (flags
& DUMP_INSN_SCHED_CYCLE
)
335 int cycle
= INSN_SCHED_CYCLE (i
);
338 sel_print ("cycle:%d;", cycle
);
341 if (!sched_dump_to_dot_p
)
345 /* Dump insn I with default flags. */
349 dump_insn_1 (i
, DUMP_INSN_EXPR
| DUMP_INSN_SCHED_CYCLE
);
352 /* Dump INSN to stderr. */
354 debug_insn (insn_t insn
)
356 switch_dump (stderr
);
357 dump_insn_1 (insn
, debug_insn_flags
);
362 /* Dumps av_set AV. */
364 dump_av_set (av_set_t av
)
369 if (!sched_dump_to_dot_p
)
372 FOR_EACH_EXPR (expr
, i
, av
)
375 if (!sched_dump_to_dot_p
)
381 if (!sched_dump_to_dot_p
)
385 /* Dumps lvset LV. */
387 dump_lv_set (regset lv
)
391 /* This code was adapted from flow.c: dump_regset (). */
397 reg_set_iterator rsi
;
400 EXECUTE_IF_SET_IN_REG_SET (lv
, 0, i
, rsi
)
402 sel_print (" %d", i
);
403 if (i
< FIRST_PSEUDO_REGISTER
)
405 sel_print (" [%s]", reg_names
[i
]);
411 if (sched_dump_to_dot_p
&& count
== 12)
422 /* Dumps a list of instructions pointed to by P. */
424 dump_ilist (ilist_t p
)
428 dump_insn (ILIST_INSN (p
));
433 /* Dumps a list of boundaries pointed to by BNDS. */
435 dump_blist (blist_t bnds
)
437 for (; bnds
; bnds
= BLIST_NEXT (bnds
))
439 bnd_t bnd
= BLIST_BND (bnds
);
441 sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd
)));
442 dump_ilist (BND_PTR (bnd
));
447 /* Dumps a list of fences pointed to by L. */
449 dump_flist (flist_t l
)
453 dump_insn_1 (FENCE_INSN (FLIST_FENCE (l
)), dump_flist_insn_flags
);
459 /* Dumps an insn vector SUCCS. */
461 dump_insn_vector (rtx_vec_t succs
)
466 for (i
= 0; VEC_iterate (rtx
, succs
, i
, succ
); i
++)
473 /* Dumps a hard reg set SET to FILE using PREFIX. */
475 print_hard_reg_set (FILE *file
, const char *prefix
, HARD_REG_SET set
)
479 fprintf (file
, "%s{ ", prefix
);
480 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
482 if (TEST_HARD_REG_BIT (set
, i
))
483 fprintf (file
, "%d ", i
);
485 fprintf (file
, "}\n");
488 /* Dumps a hard reg set SET using PREFIX. */
490 dump_hard_reg_set (const char *prefix
, HARD_REG_SET set
)
492 print_hard_reg_set (sched_dump
, prefix
, set
);
495 /* Pretty print INSN. This is used as a hook. */
497 sel_print_insn (const_rtx insn
, int aligned ATTRIBUTE_UNUSED
)
501 /* '+' before insn means it is a new cycle start and it's not been
502 scheduled yet. '>' - has been scheduled. */
503 if (s_i_d
&& INSN_LUID (insn
) > 0)
504 if (GET_MODE (insn
) == TImode
)
505 sprintf (buf
, "%s %4d",
506 INSN_SCHED_TIMES (insn
) > 0 ? "> " : "< ",
509 sprintf (buf
, "%s %4d",
510 INSN_SCHED_TIMES (insn
) > 0 ? "! " : " ",
513 if (GET_MODE (insn
) == TImode
)
514 sprintf (buf
, "+ %4d", INSN_UID (insn
));
516 sprintf (buf
, " %4d", INSN_UID (insn
));
522 /* Functions for pretty printing of CFG. */
524 /* Replace all occurencies of STR1 to STR2 in BUF.
525 The BUF must be large enough to hold the result. */
527 replace_str_in_buf (char *buf
, const char *str1
, const char *str2
)
529 int buf_len
= strlen (buf
);
530 int str1_len
= strlen (str1
);
531 int str2_len
= strlen (str2
);
532 int diff
= str2_len
- str1_len
;
537 p
= strstr (p
, str1
);
540 char *p1
= p
+ str1_len
;
541 /* Copy the rest of buf and '\0'. */
542 int n
= buf
+ buf_len
- p1
;
545 /* Shift str by DIFF chars. */
547 for (i
= n
; i
>= 0; i
--)
548 p1
[i
+ diff
] = p1
[i
];
550 for (i
= 0; i
<= n
; i
++)
551 p1
[i
+ diff
] = p1
[i
];
554 for (i
= 0; i
< str2_len
; i
++)
565 /* Replace characters in BUF that have special meaning in .dot file. */
567 sel_prepare_string_for_dot_label (char *buf
)
569 static char specials_from
[7][2] = { "<", ">", "{", "|", "}", "\"",
571 static char specials_to
[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}",
575 for (i
= 0; i
< 7; i
++)
576 replace_str_in_buf (buf
, specials_from
[i
], specials_to
[i
]);
579 /* Dump INSN with FLAGS. */
581 sel_dump_cfg_insn (insn_t insn
, int flags
)
583 int insn_flags
= DUMP_INSN_UID
| DUMP_INSN_PATTERN
;
585 if (sched_luids
!= NULL
&& INSN_LUID (insn
) > 0)
587 if (flags
& SEL_DUMP_CFG_INSN_SEQNO
)
588 insn_flags
|= DUMP_INSN_SEQNO
| DUMP_INSN_SCHED_CYCLE
| DUMP_INSN_EXPR
;
591 dump_insn_1 (insn
, insn_flags
);
594 /* Dump E to the dot file F. */
596 sel_dump_cfg_edge (FILE *f
, edge e
)
601 if (e
->flags
& EDGE_FALLTHRU
)
604 color
= ", color = red";
606 else if (e
->src
->next_bb
== e
->dest
)
609 color
= ", color = blue";
617 fprintf (f
, "\tbb%d -> bb%d [weight = %d%s];\n",
618 e
->src
->index
, e
->dest
->index
, w
, color
);
622 /* Return true if BB has a predesessor from current region.
623 TODO: Either make this function to trace back through empty block
624 or just remove those empty blocks. */
626 has_preds_in_current_region_p (basic_block bb
)
631 gcc_assert (!in_current_region_p (bb
));
633 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
634 if (in_current_region_p (e
->src
))
640 /* Dump a cfg region to the dot file F honoring FLAGS. */
642 sel_dump_cfg_2 (FILE *f
, int flags
)
646 sched_dump_to_dot_p
= true;
649 fprintf (f
, "digraph G {\n"
651 "\tnode [shape = record, fontsize = 9];\n");
653 if (flags
& SEL_DUMP_CFG_FUNCTION_NAME
)
654 fprintf (f
, "function [label = \"%s\"];\n", current_function_name ());
658 insn_t insn
= BB_HEAD (bb
);
659 insn_t next_tail
= NEXT_INSN (BB_END (bb
));
662 bool in_region_p
= ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
663 && in_current_region_p (bb
));
664 bool full_p
= (!(flags
& SEL_DUMP_CFG_CURRENT_REGION
)
666 bool some_p
= full_p
|| has_preds_in_current_region_p (bb
);
673 if ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
674 && in_current_region_p (bb
)
675 && BLOCK_TO_BB (bb
->index
) == 0)
676 color
= "color = green, ";
680 if ((flags
& SEL_DUMP_CFG_FENCES
)
685 if (!sel_bb_empty_p (bb
))
688 insn_t tail
= BB_END (bb
);
691 cur_insn
= bb_note (bb
);
697 cur_insn
= NEXT_INSN (cur_insn
);
698 fence
= flist_lookup (fences
, cur_insn
);
702 if (!FENCE_SCHEDULED_P (fence
))
705 color
= "color = red, ";
707 color
= "color = yellow, ";
710 color
= "color = blue, ";
715 while (cur_insn
!= tail
);
719 style
= "style = dashed, ";
723 fprintf (f
, "\tbb%d [%s%slabel = \"{Basic block %d", bb
->index
,
724 style
, color
, bb
->index
);
726 if ((flags
& SEL_DUMP_CFG_BB_LOOP
)
727 && bb
->loop_father
!= NULL
)
728 fprintf (f
, ", loop %d", bb
->loop_father
->num
);
731 && (flags
& SEL_DUMP_CFG_BB_NOTES_LIST
))
733 insn_t notes
= BB_NOTE_LIST (bb
);
735 if (notes
!= NULL_RTX
)
739 /* For simplicity, we dump notes from note_list in reversed order
740 to that what they will appear in the code. */
741 while (notes
!= NULL_RTX
)
743 sel_dump_cfg_insn (notes
, flags
);
746 notes
= PREV_INSN (notes
);
752 && (flags
& SEL_DUMP_CFG_AV_SET
)
753 && in_current_region_p (bb
)
754 && !sel_bb_empty_p (bb
))
758 if (BB_AV_SET_VALID_P (bb
))
759 dump_av_set (BB_AV_SET (bb
));
760 else if (BB_AV_LEVEL (bb
) == -1)
761 fprintf (f
, "AV_SET needs update");
764 if ((flags
& SEL_DUMP_CFG_LV_SET
)
765 && !sel_bb_empty_p (bb
))
769 if (BB_LV_SET_VALID_P (bb
))
770 dump_lv_set (BB_LV_SET (bb
));
772 fprintf (f
, "LV_SET needs update");
776 && (flags
& SEL_DUMP_CFG_BB_INSNS
))
779 while (insn
!= next_tail
)
781 sel_dump_cfg_insn (insn
, flags
);
784 insn
= NEXT_INSN (insn
);
788 fprintf (f
, "}\"];\n");
790 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
791 if (full_p
|| in_current_region_p (e
->dest
))
792 sel_dump_cfg_edge (f
, e
);
798 sched_dump_to_dot_p
= false;
801 /* Dump a cfg region to the file specified by TAG honoring flags.
802 The file is created by the function. */
804 sel_dump_cfg_1 (const char *tag
, int flags
)
810 ++sel_dump_cfg_fileno
;
815 i
= 1 + snprintf (NULL
, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
816 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
817 buf
= XNEWVEC (char, i
);
818 snprintf (buf
, i
, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
819 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
821 f
= fopen (buf
, "w");
824 fprintf (stderr
, "Can't create file: %s.\n", buf
);
827 sel_dump_cfg_2 (f
, flags
);
835 /* Setup cfg dumping flags. Used for debugging. */
837 setup_dump_cfg_params (void)
839 sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
841 sel_debug_cfg_root_postfix
= sel_debug_cfg_root_postfix_default
;
844 /* Debug a cfg region with FLAGS. */
846 sel_debug_cfg_1 (int flags
)
848 bool t1
= sel_dump_cfg_p
;
849 int t2
= sel_dump_cfg_fileno
;
851 sel_dump_cfg_p
= true;
852 sel_dump_cfg_fileno
= ++sel_debug_cfg_fileno
;
854 sel_dump_cfg_1 ("sel-debug-cfg", flags
);
856 sel_dump_cfg_fileno
= t2
;
860 /* Dumps av_set AV to stderr. */
862 debug_av_set (av_set_t av
)
864 switch_dump (stderr
);
870 /* Dump LV to stderr. */
872 debug_lv_set (regset lv
)
874 switch_dump (stderr
);
880 /* Dump an instruction list P to stderr. */
882 debug_ilist (ilist_t p
)
884 switch_dump (stderr
);
890 /* Dump a boundary list BNDS to stderr. */
892 debug_blist (blist_t bnds
)
894 switch_dump (stderr
);
900 /* Dump an insn vector SUCCS. */
902 debug_insn_vector (rtx_vec_t succs
)
904 switch_dump (stderr
);
905 dump_insn_vector (succs
);
910 /* Dump a hard reg set SET to stderr. */
912 debug_hard_reg_set (HARD_REG_SET set
)
914 switch_dump (stderr
);
915 dump_hard_reg_set ("", set
);
920 /* Debug a cfg region with default flags. */
924 sel_debug_cfg_1 (sel_debug_cfg_flags
);
927 /* Print a current cselib value for X's address to stderr. */
929 debug_mem_addr_value (rtx x
)
933 gcc_assert (MEM_P (x
));
934 t
= shallow_copy_rtx (x
);
935 if (cselib_lookup (XEXP (t
, 0), Pmode
, 0))
936 XEXP (t
, 0) = cselib_subst_to_values (XEXP (t
, 0));
939 addr
= get_addr (XEXP (t
, 0));