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"
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_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
)
142 print_insn (buf
, insn
, 0);
143 sel_print ("%s;", buf
);
146 if (flags
& DUMP_INSN_RTX_BBN
)
148 basic_block bb
= BLOCK_FOR_INSN (insn
);
150 sel_print ("bb:%d;", bb
!= NULL
? bb
->index
: -1);
157 /* Dump INSN with default flags. */
159 dump_insn_rtx (rtx insn
)
161 dump_insn_rtx_1 (insn
, dump_insn_rtx_flags
);
165 /* Dump INSN to stderr. */
167 debug_insn_rtx (rtx insn
)
169 switch_dump (stderr
);
170 dump_insn_rtx_1 (insn
, debug_insn_rtx_flags
);
175 /* Dump vinsn VI honoring flags. */
177 dump_vinsn_1 (vinsn_t vi
, int flags
)
181 /* flags == -1 also means dumping all. */
184 flags
|= DUMP_VINSN_ALL
;
188 if (flags
& DUMP_VINSN_INSN_RTX
)
189 dump_insn_rtx_1 (VINSN_INSN_RTX (vi
), dump_insn_rtx_flags
| all
);
191 if (flags
& DUMP_VINSN_TYPE
)
192 sel_print ("type:%s;", GET_RTX_NAME (VINSN_TYPE (vi
)));
194 if (flags
& DUMP_VINSN_COUNT
)
195 sel_print ("count:%d;", VINSN_COUNT (vi
));
197 if (flags
& DUMP_VINSN_COST
)
202 sel_print ("cost:%d;", cost
);
208 /* Dump vinsn VI with default flags. */
210 dump_vinsn (vinsn_t vi
)
212 dump_vinsn_1 (vi
, dump_vinsn_flags
);
215 /* Dump vinsn VI to stderr. */
217 debug_vinsn (vinsn_t vi
)
219 switch_dump (stderr
);
220 dump_vinsn_1 (vi
, debug_vinsn_flags
);
225 /* Dump EXPR honoring flags. */
227 dump_expr_1 (expr_t expr
, int flags
)
231 /* flags == -1 also means dumping all. */
234 flags
|= DUMP_EXPR_ALL
;
238 if (flags
& DUMP_EXPR_VINSN
)
239 dump_vinsn_1 (EXPR_VINSN (expr
), dump_vinsn_flags
| all
);
241 if (flags
& DUMP_EXPR_SPEC
)
243 int spec
= EXPR_SPEC (expr
);
246 sel_print ("spec:%d;", spec
);
249 if (flags
& DUMP_EXPR_USEFULNESS
)
251 int use
= EXPR_USEFULNESS (expr
);
253 if (use
!= REG_BR_PROB_BASE
)
254 sel_print ("use:%d;", use
);
257 if (flags
& DUMP_EXPR_PRIORITY
)
258 sel_print ("prio:%d;", EXPR_PRIORITY (expr
));
260 if (flags
& DUMP_EXPR_SCHED_TIMES
)
262 int times
= EXPR_SCHED_TIMES (expr
);
265 sel_print ("times:%d;", times
);
268 if (flags
& DUMP_EXPR_SPEC_DONE_DS
)
270 ds_t spec_done_ds
= EXPR_SPEC_DONE_DS (expr
);
272 if (spec_done_ds
!= 0)
273 sel_print ("ds:%d;", spec_done_ds
);
276 if (flags
& DUMP_EXPR_ORIG_BB
)
278 int orig_bb
= EXPR_ORIG_BB_INDEX (expr
);
281 sel_print ("orig_bb:%d;", orig_bb
);
284 if (EXPR_TARGET_AVAILABLE (expr
) < 1)
285 sel_print ("target:%d;", EXPR_TARGET_AVAILABLE (expr
));
289 /* Dump expression EXPR with default flags. */
291 dump_expr (expr_t expr
)
293 dump_expr_1 (expr
, dump_expr_flags
);
296 /* Dump expression EXPR to stderr. */
298 debug_expr (expr_t expr
)
300 switch_dump (stderr
);
301 dump_expr_1 (expr
, debug_expr_flags
);
306 /* Dump insn I honoring FLAGS. */
308 dump_insn_1 (insn_t i
, int flags
)
314 flags
|= DUMP_INSN_ALL
;
316 if (!sched_dump_to_dot_p
)
319 if (flags
& DUMP_INSN_EXPR
)
321 dump_expr_1 (INSN_EXPR (i
), dump_expr_flags
| all
);
324 else if (flags
& DUMP_INSN_PATTERN
)
326 dump_insn_rtx_1 (i
, DUMP_INSN_RTX_PATTERN
| all
);
329 else if (flags
& DUMP_INSN_UID
)
330 sel_print ("uid:%d;", INSN_UID (i
));
332 if (flags
& DUMP_INSN_SEQNO
)
333 sel_print ("seqno:%d;", INSN_SEQNO (i
));
335 if (flags
& DUMP_INSN_SCHED_CYCLE
)
337 int cycle
= INSN_SCHED_CYCLE (i
);
340 sel_print ("cycle:%d;", cycle
);
343 if (!sched_dump_to_dot_p
)
347 /* Dump insn I with default flags. */
351 dump_insn_1 (i
, DUMP_INSN_EXPR
| DUMP_INSN_SCHED_CYCLE
);
354 /* Dump INSN to stderr. */
356 debug_insn (insn_t insn
)
358 switch_dump (stderr
);
359 dump_insn_1 (insn
, debug_insn_flags
);
364 /* Dumps av_set AV. */
366 dump_av_set (av_set_t av
)
371 if (!sched_dump_to_dot_p
)
374 FOR_EACH_EXPR (expr
, i
, av
)
377 if (!sched_dump_to_dot_p
)
383 if (!sched_dump_to_dot_p
)
387 /* Dumps lvset LV. */
389 dump_lv_set (regset lv
)
393 /* This code was adapted from cfg.c: dump_regset (). */
399 reg_set_iterator rsi
;
402 EXECUTE_IF_SET_IN_REG_SET (lv
, 0, i
, rsi
)
404 sel_print (" %d", i
);
405 if (i
< FIRST_PSEUDO_REGISTER
)
407 sel_print (" [%s]", reg_names
[i
]);
413 if (sched_dump_to_dot_p
&& count
== 12)
424 /* Dumps a list of instructions pointed to by P. */
426 dump_ilist (ilist_t p
)
430 dump_insn (ILIST_INSN (p
));
435 /* Dumps a list of boundaries pointed to by BNDS. */
437 dump_blist (blist_t bnds
)
439 for (; bnds
; bnds
= BLIST_NEXT (bnds
))
441 bnd_t bnd
= BLIST_BND (bnds
);
443 sel_print ("[to: %d; ptr: ", INSN_UID (BND_TO (bnd
)));
444 dump_ilist (BND_PTR (bnd
));
449 /* Dumps a list of fences pointed to by L. */
451 dump_flist (flist_t l
)
455 dump_insn_1 (FENCE_INSN (FLIST_FENCE (l
)), dump_flist_insn_flags
);
461 /* Dumps an insn vector SUCCS. */
463 dump_insn_vector (rtx_vec_t succs
)
468 FOR_EACH_VEC_ELT (rtx
, succs
, i
, succ
)
475 /* Dumps a hard reg set SET to FILE using PREFIX. */
477 print_hard_reg_set (FILE *file
, const char *prefix
, HARD_REG_SET set
)
481 fprintf (file
, "%s{ ", prefix
);
482 for (i
= 0; i
< FIRST_PSEUDO_REGISTER
; i
++)
484 if (TEST_HARD_REG_BIT (set
, i
))
485 fprintf (file
, "%d ", i
);
487 fprintf (file
, "}\n");
490 /* Dumps a hard reg set SET using PREFIX. */
492 dump_hard_reg_set (const char *prefix
, HARD_REG_SET set
)
494 print_hard_reg_set (sched_dump
, prefix
, set
);
497 /* Pretty print INSN. This is used as a hook. */
499 sel_print_insn (const_rtx insn
, int aligned ATTRIBUTE_UNUSED
)
503 /* '+' before insn means it is a new cycle start and it's not been
504 scheduled yet. '>' - has been scheduled. */
505 if (s_i_d
&& INSN_LUID (insn
) > 0)
506 if (GET_MODE (insn
) == TImode
)
507 sprintf (buf
, "%s %4d",
508 INSN_SCHED_TIMES (insn
) > 0 ? "> " : "< ",
511 sprintf (buf
, "%s %4d",
512 INSN_SCHED_TIMES (insn
) > 0 ? "! " : " ",
515 if (GET_MODE (insn
) == TImode
)
516 sprintf (buf
, "+ %4d", INSN_UID (insn
));
518 sprintf (buf
, " %4d", INSN_UID (insn
));
524 /* Functions for pretty printing of CFG. */
526 /* Replace all occurencies of STR1 to STR2 in BUF.
527 The BUF must be large enough to hold the result. */
529 replace_str_in_buf (char *buf
, const char *str1
, const char *str2
)
531 int buf_len
= strlen (buf
);
532 int str1_len
= strlen (str1
);
533 int str2_len
= strlen (str2
);
534 int diff
= str2_len
- str1_len
;
539 p
= strstr (p
, str1
);
542 char *p1
= p
+ str1_len
;
543 /* Copy the rest of buf and '\0'. */
544 int n
= buf
+ buf_len
- p1
;
547 /* Shift str by DIFF chars. */
549 for (i
= n
; i
>= 0; i
--)
550 p1
[i
+ diff
] = p1
[i
];
552 for (i
= 0; i
<= n
; i
++)
553 p1
[i
+ diff
] = p1
[i
];
556 for (i
= 0; i
< str2_len
; i
++)
567 /* Replace characters in BUF that have special meaning in .dot file. */
569 sel_prepare_string_for_dot_label (char *buf
)
571 static char specials_from
[7][2] = { "<", ">", "{", "|", "}", "\"",
573 static char specials_to
[7][3] = { "\\<", "\\>", "\\{", "\\|", "\\}",
577 for (i
= 0; i
< 7; i
++)
578 replace_str_in_buf (buf
, specials_from
[i
], specials_to
[i
]);
581 /* This function acts like printf but dumps to the sched_dump file. */
583 sel_print (const char *fmt
, ...)
587 if (sched_dump_to_dot_p
)
590 if (vasprintf (&message
, fmt
, ap
) >= 0 && message
!= NULL
)
592 message
= (char *) xrealloc (message
, 2 * strlen (message
) + 1);
593 sel_prepare_string_for_dot_label (message
);
594 fprintf (sched_dump
, "%s", message
);
599 vfprintf (sched_dump
, fmt
, ap
);
603 /* Dump INSN with FLAGS. */
605 sel_dump_cfg_insn (insn_t insn
, int flags
)
607 int insn_flags
= DUMP_INSN_UID
| DUMP_INSN_PATTERN
;
609 if (sched_luids
!= NULL
&& INSN_LUID (insn
) > 0)
611 if (flags
& SEL_DUMP_CFG_INSN_SEQNO
)
612 insn_flags
|= DUMP_INSN_SEQNO
| DUMP_INSN_SCHED_CYCLE
| DUMP_INSN_EXPR
;
615 dump_insn_1 (insn
, insn_flags
);
618 /* Dump E to the dot file F. */
620 sel_dump_cfg_edge (FILE *f
, edge e
)
625 if (e
->flags
& EDGE_FALLTHRU
)
628 color
= ", color = red";
630 else if (e
->src
->next_bb
== e
->dest
)
633 color
= ", color = blue";
641 fprintf (f
, "\tbb%d -> bb%d [weight = %d%s];\n",
642 e
->src
->index
, e
->dest
->index
, w
, color
);
646 /* Return true if BB has a predesessor from current region.
647 TODO: Either make this function to trace back through empty block
648 or just remove those empty blocks. */
650 has_preds_in_current_region_p (basic_block bb
)
655 gcc_assert (!in_current_region_p (bb
));
657 FOR_EACH_EDGE (e
, ei
, bb
->preds
)
658 if (in_current_region_p (e
->src
))
664 /* Dump a cfg region to the dot file F honoring FLAGS. */
666 sel_dump_cfg_2 (FILE *f
, int flags
)
670 sched_dump_to_dot_p
= true;
673 fprintf (f
, "digraph G {\n"
675 "\tnode [shape = record, fontsize = 9];\n");
677 if (flags
& SEL_DUMP_CFG_FUNCTION_NAME
)
678 fprintf (f
, "function [label = \"%s\"];\n", current_function_name ());
682 insn_t insn
= BB_HEAD (bb
);
683 insn_t next_tail
= NEXT_INSN (BB_END (bb
));
686 bool in_region_p
= ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
687 && in_current_region_p (bb
));
688 bool full_p
= (!(flags
& SEL_DUMP_CFG_CURRENT_REGION
)
690 bool some_p
= full_p
|| has_preds_in_current_region_p (bb
);
697 if ((flags
& SEL_DUMP_CFG_CURRENT_REGION
)
698 && in_current_region_p (bb
)
699 && BLOCK_TO_BB (bb
->index
) == 0)
700 color
= "color = green, ";
704 if ((flags
& SEL_DUMP_CFG_FENCES
)
709 if (!sel_bb_empty_p (bb
))
712 insn_t tail
= BB_END (bb
);
715 cur_insn
= bb_note (bb
);
721 cur_insn
= NEXT_INSN (cur_insn
);
722 fence
= flist_lookup (fences
, cur_insn
);
726 if (!FENCE_SCHEDULED_P (fence
))
729 color
= "color = red, ";
731 color
= "color = yellow, ";
734 color
= "color = blue, ";
739 while (cur_insn
!= tail
);
743 style
= "style = dashed, ";
747 fprintf (f
, "\tbb%d [%s%slabel = \"{Basic block %d", bb
->index
,
748 style
, color
, bb
->index
);
750 if ((flags
& SEL_DUMP_CFG_BB_LOOP
)
751 && bb
->loop_father
!= NULL
)
752 fprintf (f
, ", loop %d", bb
->loop_father
->num
);
755 && (flags
& SEL_DUMP_CFG_BB_NOTES_LIST
))
757 insn_t notes
= BB_NOTE_LIST (bb
);
759 if (notes
!= NULL_RTX
)
763 /* For simplicity, we dump notes from note_list in reversed order
764 to that what they will appear in the code. */
765 while (notes
!= NULL_RTX
)
767 sel_dump_cfg_insn (notes
, flags
);
770 notes
= PREV_INSN (notes
);
776 && (flags
& SEL_DUMP_CFG_AV_SET
)
777 && in_current_region_p (bb
)
778 && !sel_bb_empty_p (bb
))
782 if (BB_AV_SET_VALID_P (bb
))
783 dump_av_set (BB_AV_SET (bb
));
784 else if (BB_AV_LEVEL (bb
) == -1)
785 fprintf (f
, "AV_SET needs update");
788 if ((flags
& SEL_DUMP_CFG_LV_SET
)
789 && !sel_bb_empty_p (bb
))
793 if (BB_LV_SET_VALID_P (bb
))
794 dump_lv_set (BB_LV_SET (bb
));
796 fprintf (f
, "LV_SET needs update");
800 && (flags
& SEL_DUMP_CFG_BB_INSNS
))
803 while (insn
!= next_tail
)
805 sel_dump_cfg_insn (insn
, flags
);
808 insn
= NEXT_INSN (insn
);
812 fprintf (f
, "}\"];\n");
814 FOR_EACH_EDGE (e
, ei
, bb
->succs
)
815 if (full_p
|| in_current_region_p (e
->dest
))
816 sel_dump_cfg_edge (f
, e
);
822 sched_dump_to_dot_p
= false;
825 /* Dump a cfg region to the file specified by TAG honoring flags.
826 The file is created by the function. */
828 sel_dump_cfg_1 (const char *tag
, int flags
)
834 ++sel_dump_cfg_fileno
;
839 i
= 1 + snprintf (NULL
, 0, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
840 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
841 buf
= XNEWVEC (char, i
);
842 snprintf (buf
, i
, "%s/%s%05d-%s.dot", sel_debug_cfg_root
,
843 sel_debug_cfg_root_postfix
, sel_dump_cfg_fileno
, tag
);
845 f
= fopen (buf
, "w");
848 fprintf (stderr
, "Can't create file: %s.\n", buf
);
851 sel_dump_cfg_2 (f
, flags
);
859 /* Setup cfg dumping flags. Used for debugging. */
861 setup_dump_cfg_params (void)
863 sel_dump_cfg_flags
= SEL_DUMP_CFG_FLAGS
;
865 sel_debug_cfg_root_postfix
= sel_debug_cfg_root_postfix_default
;
868 /* Debug a cfg region with FLAGS. */
870 sel_debug_cfg_1 (int flags
)
872 bool t1
= sel_dump_cfg_p
;
873 int t2
= sel_dump_cfg_fileno
;
875 sel_dump_cfg_p
= true;
876 sel_dump_cfg_fileno
= ++sel_debug_cfg_fileno
;
878 sel_dump_cfg_1 ("sel-debug-cfg", flags
);
880 sel_dump_cfg_fileno
= t2
;
884 /* Dumps av_set AV to stderr. */
886 debug_av_set (av_set_t av
)
888 switch_dump (stderr
);
894 /* Dump LV to stderr. */
896 debug_lv_set (regset lv
)
898 switch_dump (stderr
);
904 /* Dump an instruction list P to stderr. */
906 debug_ilist (ilist_t p
)
908 switch_dump (stderr
);
914 /* Dump a boundary list BNDS to stderr. */
916 debug_blist (blist_t bnds
)
918 switch_dump (stderr
);
924 /* Dump an insn vector SUCCS. */
926 debug_insn_vector (rtx_vec_t succs
)
928 switch_dump (stderr
);
929 dump_insn_vector (succs
);
934 /* Dump a hard reg set SET to stderr. */
936 debug_hard_reg_set (HARD_REG_SET set
)
938 switch_dump (stderr
);
939 dump_hard_reg_set ("", set
);
944 /* Debug a cfg region with default flags. */
948 sel_debug_cfg_1 (sel_debug_cfg_flags
);
951 /* Print a current cselib value for X's address to stderr. */
953 debug_mem_addr_value (rtx x
)
956 enum machine_mode address_mode
;
958 gcc_assert (MEM_P (x
));
959 address_mode
= get_address_mode (x
);
961 t
= shallow_copy_rtx (x
);
962 if (cselib_lookup (XEXP (t
, 0), address_mode
, 0, GET_MODE (t
)))
963 XEXP (t
, 0) = cselib_subst_to_values (XEXP (t
, 0), GET_MODE (t
));
966 addr
= get_addr (XEXP (t
, 0));