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"
28 #include "hard-reg-set.h"
32 #include "insn-config.h"
33 #include "insn-attr.h"
36 #include "basic-block.h"
40 #ifdef INSN_SCHEDULING
41 #include "sel-sched-ir.h"
42 #include "sel-sched-dump.h"
45 /* These variables control high-level pretty printing. */
46 static int sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
47 static int sel_debug_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
49 /* True when a cfg should be dumped. */
50 static bool sel_dump_cfg_p
;
52 /* Variables that are used to build the cfg dump file name. */
53 static const char * const sel_debug_cfg_root
= "./";
54 static const char * const sel_debug_cfg_root_postfix_default
= "";
55 static const char *sel_debug_cfg_root_postfix
= "";
56 static int sel_dump_cfg_fileno
= -1;
57 static int sel_debug_cfg_fileno
= -1;
59 /* When this flag is on, we are dumping to the .dot file.
60 When it is off, we are dumping to log.
61 This is useful to differentiate formatting between log and .dot
63 bool sched_dump_to_dot_p
= false;
65 /* Controls how insns from a fence list should be dumped. */
66 static int dump_flist_insn_flags
= (DUMP_INSN_UID
| DUMP_INSN_BBN
70 /* The variable used to hold the value of sched_dump when temporarily
71 switching dump output to the other source, e.g. the .dot file. */
72 static FILE *saved_sched_dump
= NULL
;
74 /* Switch sched_dump to TO. It must not be called twice. */
76 switch_dump (FILE *to
)
78 gcc_assert (saved_sched_dump
== NULL
);
80 saved_sched_dump
= sched_dump
;
84 /* Restore previously switched dump. */
88 sched_dump
= saved_sched_dump
;
89 saved_sched_dump
= NULL
;
93 /* Functions for dumping instructions, av sets, and exprs. */
95 /* Default flags for dumping insns. */
96 static int dump_insn_rtx_flags
= DUMP_INSN_RTX_PATTERN
;
98 /* Default flags for dumping vinsns. */
99 static int dump_vinsn_flags
= (DUMP_VINSN_INSN_RTX
| DUMP_VINSN_TYPE
102 /* Default flags for dumping expressions. */
103 static int dump_expr_flags
= DUMP_EXPR_ALL
;
105 /* Default flags for dumping insns when debugging. */
106 static int debug_insn_rtx_flags
= DUMP_INSN_RTX_ALL
;
108 /* Default flags for dumping vinsns when debugging. */
109 static int debug_vinsn_flags
= DUMP_VINSN_ALL
;
111 /* Default flags for dumping expressions when debugging. */
112 static int debug_expr_flags
= DUMP_EXPR_ALL
;
114 /* Controls how an insn from stream should be dumped when debugging. */
115 static int debug_insn_flags
= DUMP_INSN_ALL
;
117 /* Print an rtx X. */
119 sel_print_rtl (rtx x
)
121 print_rtl_single (sched_dump
, x
);
124 /* Dump insn INSN honoring FLAGS. */
126 dump_insn_rtx_1 (rtx insn
, int flags
)
130 /* flags == -1 also means dumping all. */
133 flags
|= DUMP_INSN_RTX_ALL
;
137 if (flags
& DUMP_INSN_RTX_UID
)
138 sel_print ("%d;", INSN_UID (insn
));
140 if (flags
& DUMP_INSN_RTX_PATTERN
)
144 print_insn (buf
, insn
, 0);
145 sel_print ("%s;", buf
);
148 if (flags
& DUMP_INSN_RTX_BBN
)
150 basic_block bb
= BLOCK_FOR_INSN (insn
);
152 sel_print ("bb:%d;", bb
!= NULL
? bb
->index
: -1);
159 /* Dump INSN with default flags. */
161 dump_insn_rtx (rtx insn
)
163 dump_insn_rtx_1 (insn
, dump_insn_rtx_flags
);
167 /* Dump INSN to stderr. */
169 debug_insn_rtx (rtx insn
)
171 switch_dump (stderr
);
172 dump_insn_rtx_1 (insn
, debug_insn_rtx_flags
);
177 /* Dump vinsn VI honoring flags. */
179 dump_vinsn_1 (vinsn_t vi
, int flags
)
183 /* flags == -1 also means dumping all. */
186 flags
|= DUMP_VINSN_ALL
;
190 if (flags
& DUMP_VINSN_INSN_RTX
)
191 dump_insn_rtx_1 (VINSN_INSN_RTX (vi
), dump_insn_rtx_flags
| all
);
193 if (flags
& DUMP_VINSN_TYPE
)
194 sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi
)));
196 if (flags
& DUMP_VINSN_COUNT
)
197 sel_print ("count:%d;", VINSN_COUNT (vi
));
199 if (flags
& DUMP_VINSN_COST
)
204 sel_print ("cost:%d;", cost
);
210 /* Dump vinsn VI with default flags. */
212 dump_vinsn (vinsn_t vi
)
214 dump_vinsn_1 (vi
, dump_vinsn_flags
);
217 /* Dump vinsn VI to stderr. */
219 debug_vinsn (vinsn_t vi
)
221 switch_dump (stderr
);
222 dump_vinsn_1 (vi
, debug_vinsn_flags
);
227 /* Dump EXPR honoring flags. */
229 dump_expr_1 (expr_t expr
, int flags
)
233 /* flags == -1 also means dumping all. */
236 flags
|= DUMP_EXPR_ALL
;
240 if (flags
& DUMP_EXPR_VINSN
)
241 dump_vinsn_1 (EXPR_VINSN (expr
), dump_vinsn_flags
| all
);
243 if (flags
& DUMP_EXPR_SPEC
)
245 int spec
= EXPR_SPEC (expr
);
248 sel_print ("spec:%d;", spec
);
251 if (flags
& DUMP_EXPR_USEFULNESS
)
253 int use
= EXPR_USEFULNESS (expr
);
255 if (use
!= REG_BR_PROB_BASE
)
256 sel_print ("use:%d;", use
);
259 if (flags
& DUMP_EXPR_PRIORITY
)
260 sel_print ("prio:%d;", EXPR_PRIORITY (expr
));
262 if (flags
& DUMP_EXPR_SCHED_TIMES
)
264 int times
= EXPR_SCHED_TIMES (expr
);
267 sel_print ("times:%d;", times
);
270 if (flags
& DUMP_EXPR_SPEC_DONE_DS
)
272 ds_t spec_done_ds
= EXPR_SPEC_DONE_DS (expr
);
274 if (spec_done_ds
!= 0)
275 sel_print ("ds:%d;", spec_done_ds
);
278 if (flags
& DUMP_EXPR_ORIG_BB
)
280 int orig_bb
= EXPR_ORIG_BB_INDEX (expr
);
283 sel_print ("orig_bb:%d;", orig_bb
);
286 if (EXPR_TARGET_AVAILABLE (expr
) < 1)
287 sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr
));
291 /* Dump expression EXPR with default flags. */
293 dump_expr (expr_t expr
)
295 dump_expr_1 (expr
, dump_expr_flags
);
298 /* Dump expression EXPR to stderr. */
300 debug_expr (expr_t expr
)
302 switch_dump (stderr
);
303 dump_expr_1 (expr
, debug_expr_flags
);
308 /* Dump insn I honoring FLAGS. */
310 dump_insn_1 (insn_t i
, int flags
)
316 flags
|= DUMP_INSN_ALL
;
318 if (!sched_dump_to_dot_p
)
321 if (flags
& DUMP_INSN_EXPR
)
323 dump_expr_1 (INSN_EXPR (i
), dump_expr_flags
| all
);
326 else if (flags
& DUMP_INSN_PATTERN
)
328 dump_insn_rtx_1 (i
, DUMP_INSN_RTX_PATTERN
| all
);
331 else if (flags
& DUMP_INSN_UID
)
332 sel_print ("uid:%d;", INSN_UID (i
));
334 if (flags
& DUMP_INSN_SEQNO
)
335 sel_print ("seqno:%d;", INSN_SEQNO (i
));
337 if (flags
& DUMP_INSN_SCHED_CYCLE
)
339 int cycle
= INSN_SCHED_CYCLE (i
);
342 sel_print ("cycle:%d;", cycle
);
345 if (!sched_dump_to_dot_p
)
349 /* Dump insn I with default flags. */
353 dump_insn_1 (i
, DUMP_INSN_EXPR
| DUMP_INSN_SCHED_CYCLE
);
356 /* Dump INSN to stderr. */
358 debug_insn (insn_t insn
)
360 switch_dump (stderr
);
361 dump_insn_1 (insn
, debug_insn_flags
);
366 /* Dumps av_set AV. */
368 dump_av_set (av_set_t av
)
373 if (!sched_dump_to_dot_p
)
376 FOR_EACH_EXPR (expr
, i
, av
)
379 if (!sched_dump_to_dot_p
)
385 if (!sched_dump_to_dot_p
)
389 /* Dumps lvset LV. */
391 dump_lv_set (regset lv
)
395 /* This code was adapted from cfg.c: dump_regset (). */
401 reg_set_iterator rsi
;
404 EXECUTE_IF_SET_IN_REG_SET (lv
, 0, i
, rsi
)
406 sel_print (" %d", i
);
407 if (i
< FIRST_PSEUDO_REGISTER
)
409 sel_print (" [%s]", reg_names
[i
]);
415 if (sched_dump_to_dot_p
&& count
== 12)
426 /* Dumps a list of instructions pointed to by P. */
428 dump_ilist (ilist_t p
)
432 dump_insn (ILIST_INSN (p
));
437 /* Dumps a list of boundaries pointed to by BNDS. */
439 dump_blist (blist_t bnds
)
441 for (; bnds
; bnds
= BLIST_NEXT (bnds
))
443 bnd_t bnd
= BLIST_BND (bnds
);
445 sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd
)));
446 dump_ilist (BND_PTR (bnd
));
451 /* Dumps a list of fences pointed to by L. */
453 dump_flist (flist_t l
)
457 dump_insn_1 (FENCE_INSN (FLIST_FENCE (l
)), dump_flist_insn_flags
);
463 /* Dumps an insn vector SUCCS. */
465 dump_insn_vector (rtx_vec_t succs
)
470 FOR_EACH_VEC_ELT (rtx
, succs
, i
, succ
)
477 /* Dumps a hard reg set SET to FILE using PREFIX. */
479 print_hard_reg_set (FILE *file
, const char *prefix
, HARD_REG_SET set
)
483 fprintf (file
, "%s{ ", prefix
);
484 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
486 if (TEST_HARD_REG_BIT (set
, i
))
487 fprintf (file
, "%d ", i
);
489 fprintf (file
, "}\n");
492 /* Dumps a hard reg set SET using PREFIX. */
494 dump_hard_reg_set (const char *prefix
, HARD_REG_SET set
)
496 print_hard_reg_set (sched_dump
, prefix
, set
);
499 /* Pretty print INSN. This is used as a hook. */
501 sel_print_insn (const_rtx insn
, int aligned ATTRIBUTE_UNUSED
)
505 /* '+' before insn means it is a new cycle start and it's not been
506 scheduled yet. '>' - has been scheduled. */
507 if (s_i_d
&& INSN_LUID (insn
) > 0)
508 if (GET_MODE (insn
) == TImode
)
509 sprintf (buf
, "%s %4d",
510 INSN_SCHED_TIMES (insn
) > 0 ? "> " : "< ",
513 sprintf (buf
, "%s %4d",
514 INSN_SCHED_TIMES (insn
) > 0 ? "! " : " ",
517 if (GET_MODE (insn
) == TImode
)
518 sprintf (buf
, "+ %4d", INSN_UID (insn
));
520 sprintf (buf
, " %4d", INSN_UID (insn
));
526 /* Functions for pretty printing of CFG. */
528 /* Replace all occurencies of STR1 to STR2 in BUF.
529 The BUF must be large enough to hold the result. */
531 replace_str_in_buf (char *buf
, const char *str1
, const char *str2
)
533 int buf_len
= strlen (buf
);
534 int str1_len
= strlen (str1
);
535 int str2_len
= strlen (str2
);
536 int diff
= str2_len
- str1_len
;
541 p
= strstr (p
, str1
);
544 char *p1
= p
+ str1_len
;
545 /* Copy the rest of buf and '\0'. */
546 int n
= buf
+ buf_len
- p1
;
549 /* Shift str by DIFF chars. */
551 for (i
= n
; i
>= 0; i
--)
552 p1
[i
+ diff
] = p1
[i
];
554 for (i
= 0; i
<= n
; i
++)
555 p1
[i
+ diff
] = p1
[i
];
558 for (i
= 0; i
< str2_len
; i
++)
569 /* Replace characters in BUF that have special meaning in .dot file. */
571 sel_prepare_string_for_dot_label (char *buf
)
573 static char specials_from
[7][2] = { "<", ">", "{", "|", "}", "\"",
575 static char specials_to
[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}",
579 for (i
= 0; i
< 7; i
++)
580 replace_str_in_buf (buf
, specials_from
[i
], specials_to
[i
]);
583 /* This function acts like printf but dumps to the sched_dump file. */
585 sel_print (const char *fmt
, ...)
589 if (sched_dump_to_dot_p
)
592 if (vasprintf (&message
, fmt
, ap
) >= 0 && message
!= NULL
)
594 message
= (char *) xrealloc (message
, 2 * strlen (message
) + 1);
595 sel_prepare_string_for_dot_label (message
);
596 fprintf (sched_dump
, "%s", message
);
601 vfprintf (sched_dump
, fmt
, ap
);
605 /* Dump INSN with FLAGS. */
607 sel_dump_cfg_insn (insn_t insn
, int flags
)
609 int insn_flags
= DUMP_INSN_UID
| DUMP_INSN_PATTERN
;
611 if (sched_luids
!= NULL
&& INSN_LUID (insn
) > 0)
613 if (flags
& SEL_DUMP_CFG_INSN_SEQNO
)
614 insn_flags
|= DUMP_INSN_SEQNO
| DUMP_INSN_SCHED_CYCLE
| DUMP_INSN_EXPR
;
617 dump_insn_1 (insn
, insn_flags
);
620 /* Dump E to the dot file F. */
622 sel_dump_cfg_edge (FILE *f
, edge e
)
627 if (e
->flags
& EDGE_FALLTHRU
)
630 color
= ", color = red";
632 else if (e
->src
->next_bb
== e
->dest
)
635 color
= ", color = blue";
643 fprintf (f
, "\tbb%d -> bb%d [weight = %d%s];\n",
644 e
->src
->index
, e
->dest
->index
, w
, color
);
648 /* Return true if BB has a predesessor from current region.
649 TODO: Either make this function to trace back through empty block
650 or just remove those empty blocks. */
652 has_preds_in_current_region_p (basic_block bb
)
657 gcc_assert (!in_current_region_p (bb
));
659 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
660 if (in_current_region_p (e
->src
))
666 /* Dump a cfg region to the dot file F honoring FLAGS. */
668 sel_dump_cfg_2 (FILE *f
, int flags
)
672 sched_dump_to_dot_p
= true;
675 fprintf (f
, "digraph G {\n"
677 "\tnode [shape = record, fontsize = 9];\n");
679 if (flags
& SEL_DUMP_CFG_FUNCTION_NAME
)
680 fprintf (f
, "function [label = \"%s\"];\n", current_function_name ());
684 insn_t insn
= BB_HEAD (bb
);
685 insn_t next_tail
= NEXT_INSN (BB_END (bb
));
688 bool in_region_p
= ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
689 && in_current_region_p (bb
));
690 bool full_p
= (!(flags
& SEL_DUMP_CFG_CURRENT_REGION
)
692 bool some_p
= full_p
|| has_preds_in_current_region_p (bb
);
699 if ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
700 && in_current_region_p (bb
)
701 && BLOCK_TO_BB (bb
->index
) == 0)
702 color
= "color = green, ";
706 if ((flags
& SEL_DUMP_CFG_FENCES
)
711 if (!sel_bb_empty_p (bb
))
714 insn_t tail
= BB_END (bb
);
717 cur_insn
= bb_note (bb
);
723 cur_insn
= NEXT_INSN (cur_insn
);
724 fence
= flist_lookup (fences
, cur_insn
);
728 if (!FENCE_SCHEDULED_P (fence
))
731 color
= "color = red, ";
733 color
= "color = yellow, ";
736 color
= "color = blue, ";
741 while (cur_insn
!= tail
);
745 style
= "style = dashed, ";
749 fprintf (f
, "\tbb%d [%s%slabel = \"{Basic block %d", bb
->index
,
750 style
, color
, bb
->index
);
752 if ((flags
& SEL_DUMP_CFG_BB_LOOP
)
753 && bb
->loop_father
!= NULL
)
754 fprintf (f
, ", loop %d", bb
->loop_father
->num
);
757 && (flags
& SEL_DUMP_CFG_BB_NOTES_LIST
))
759 insn_t notes
= BB_NOTE_LIST (bb
);
761 if (notes
!= NULL_RTX
)
765 /* For simplicity, we dump notes from note_list in reversed order
766 to that what they will appear in the code. */
767 while (notes
!= NULL_RTX
)
769 sel_dump_cfg_insn (notes
, flags
);
772 notes
= PREV_INSN (notes
);
778 && (flags
& SEL_DUMP_CFG_AV_SET
)
779 && in_current_region_p (bb
)
780 && !sel_bb_empty_p (bb
))
784 if (BB_AV_SET_VALID_P (bb
))
785 dump_av_set (BB_AV_SET (bb
));
786 else if (BB_AV_LEVEL (bb
) == -1)
787 fprintf (f
, "AV_SET needs update");
790 if ((flags
& SEL_DUMP_CFG_LV_SET
)
791 && !sel_bb_empty_p (bb
))
795 if (BB_LV_SET_VALID_P (bb
))
796 dump_lv_set (BB_LV_SET (bb
));
798 fprintf (f
, "LV_SET needs update");
802 && (flags
& SEL_DUMP_CFG_BB_INSNS
))
805 while (insn
!= next_tail
)
807 sel_dump_cfg_insn (insn
, flags
);
810 insn
= NEXT_INSN (insn
);
814 fprintf (f
, "}\"];\n");
816 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
817 if (full_p
|| in_current_region_p (e
->dest
))
818 sel_dump_cfg_edge (f
, e
);
824 sched_dump_to_dot_p
= false;
827 /* Dump a cfg region to the file specified by TAG honoring flags.
828 The file is created by the function. */
830 sel_dump_cfg_1 (const char *tag
, int flags
)
836 ++sel_dump_cfg_fileno
;
841 i
= 1 + snprintf (NULL
, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
842 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
843 buf
= XNEWVEC (char, i
);
844 snprintf (buf
, i
, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
845 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
847 f
= fopen (buf
, "w");
850 fprintf (stderr
, "Can't create file: %s.\n", buf
);
853 sel_dump_cfg_2 (f
, flags
);
861 /* Setup cfg dumping flags. Used for debugging. */
863 setup_dump_cfg_params (void)
865 sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
867 sel_debug_cfg_root_postfix
= sel_debug_cfg_root_postfix_default
;
870 /* Debug a cfg region with FLAGS. */
872 sel_debug_cfg_1 (int flags
)
874 bool t1
= sel_dump_cfg_p
;
875 int t2
= sel_dump_cfg_fileno
;
877 sel_dump_cfg_p
= true;
878 sel_dump_cfg_fileno
= ++sel_debug_cfg_fileno
;
880 sel_dump_cfg_1 ("sel-debug-cfg", flags
);
882 sel_dump_cfg_fileno
= t2
;
886 /* Dumps av_set AV to stderr. */
888 debug_av_set (av_set_t av
)
890 switch_dump (stderr
);
896 /* Dump LV to stderr. */
898 debug_lv_set (regset lv
)
900 switch_dump (stderr
);
906 /* Dump an instruction list P to stderr. */
908 debug_ilist (ilist_t p
)
910 switch_dump (stderr
);
916 /* Dump a boundary list BNDS to stderr. */
918 debug_blist (blist_t bnds
)
920 switch_dump (stderr
);
926 /* Dump an insn vector SUCCS. */
928 debug_insn_vector (rtx_vec_t succs
)
930 switch_dump (stderr
);
931 dump_insn_vector (succs
);
936 /* Dump a hard reg set SET to stderr. */
938 debug_hard_reg_set (HARD_REG_SET set
)
940 switch_dump (stderr
);
941 dump_hard_reg_set ("", set
);
946 /* Debug a cfg region with default flags. */
950 sel_debug_cfg_1 (sel_debug_cfg_flags
);
953 /* Print a current cselib value for X's address to stderr. */
955 debug_mem_addr_value (rtx x
)
958 enum machine_mode address_mode
;
960 gcc_assert (MEM_P (x
));
961 address_mode
= targetm
.addr_space
.address_mode (MEM_ADDR_SPACE (x
));
963 t
= shallow_copy_rtx (x
);
964 if (cselib_lookup (XEXP (t
, 0), address_mode
, 0))
965 XEXP (t
, 0) = cselib_subst_to_values (XEXP (t
, 0));
968 addr
= get_addr (XEXP (t
, 0));