1 /* Dump infrastructure for optimizations and intermediate representation.
2 Copyright (C) 2012 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"
23 #include "diagnostic-core.h"
25 #include "gimple-pretty-print.h"
28 /* If non-NULL, return one past-the-end of the matching SUBPART of
30 #define skip_leading_substring(whole, part) \
31 (strncmp (whole, part, strlen (part)) ? NULL : whole + strlen (part))
33 static int pflags
; /* current dump_flags */
34 static int alt_flags
; /* current opt_info flags */
36 static void dump_loc (int, FILE *, source_location
);
37 static int dump_phase_enabled_p (int);
38 static FILE *dump_open_alternate_stream (struct dump_file_info
*);
40 /* These are currently used for communicating between passes.
41 However, instead of accessing them directly, the passes can use
42 dump_printf () for dumps. */
43 FILE *dump_file
= NULL
;
44 FILE *alt_dump_file
= NULL
;
45 const char *dump_file_name
;
47 /* Table of tree dump switches. This must be consistent with the
48 TREE_DUMP_INDEX enumeration in dumpfile.h. */
49 static struct dump_file_info dump_files
[TDI_end
] =
51 {NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
, 0, 0, 0, 0, 0},
52 {".cgraph", "ipa-cgraph", NULL
, NULL
, NULL
, NULL
, NULL
, TDF_IPA
,
54 {".tu", "translation-unit", NULL
, NULL
, NULL
, NULL
, NULL
, TDF_TREE
,
56 {".class", "class-hierarchy", NULL
, NULL
, NULL
, NULL
, NULL
, TDF_TREE
,
58 {".original", "tree-original", NULL
, NULL
, NULL
, NULL
, NULL
, TDF_TREE
,
60 {".gimple", "tree-gimple", NULL
, NULL
, NULL
, NULL
, NULL
, TDF_TREE
,
62 {".nested", "tree-nested", NULL
, NULL
, NULL
, NULL
, NULL
, TDF_TREE
,
64 {".vcg", "tree-vcg", NULL
, NULL
, NULL
, NULL
, NULL
, TDF_TREE
,
66 #define FIRST_AUTO_NUMBERED_DUMP 7
68 {NULL
, "tree-all", NULL
, NULL
, NULL
, NULL
, NULL
, TDF_TREE
,
70 {NULL
, "rtl-all", NULL
, NULL
, NULL
, NULL
, NULL
, TDF_RTL
,
72 {NULL
, "ipa-all", NULL
, NULL
, NULL
, NULL
, NULL
, TDF_IPA
,
76 /* Dynamically registered tree dump files and switches. */
77 static struct dump_file_info
*extra_dump_files
;
78 static size_t extra_dump_files_in_use
;
79 static size_t extra_dump_files_alloced
;
81 /* Define a name->number mapping for a dump flag value. */
82 struct dump_option_value_info
84 const char *const name
; /* the name of the value */
85 const int value
; /* the value of the name */
88 /* Table of dump options. This must be consistent with the TDF_* flags
89 in dumpfile.h and opt_info_options below. */
90 static const struct dump_option_value_info dump_options
[] =
92 {"address", TDF_ADDRESS
},
93 {"asmname", TDF_ASMNAME
},
97 {"details", (TDF_DETAILS
| MSG_OPTIMIZED_LOCATIONS
98 | MSG_MISSED_OPTIMIZATION
100 {"cselib", TDF_CSELIB
},
101 {"stats", TDF_STATS
},
102 {"blocks", TDF_BLOCKS
},
104 {"lineno", TDF_LINENO
},
106 {"stmtaddr", TDF_STMTADDR
},
107 {"memsyms", TDF_MEMSYMS
},
108 {"verbose", TDF_VERBOSE
},
110 {"alias", TDF_ALIAS
},
111 {"nouid", TDF_NOUID
},
112 {"enumerate_locals", TDF_ENUMERATE_LOCALS
},
114 {"all", ~(TDF_RAW
| TDF_SLIM
| TDF_LINENO
| TDF_TREE
| TDF_RTL
| TDF_IPA
115 | TDF_STMTADDR
| TDF_GRAPH
| TDF_DIAGNOSTIC
| TDF_VERBOSE
116 | TDF_RHS_ONLY
| TDF_NOUID
| TDF_ENUMERATE_LOCALS
| TDF_SCEV
)},
120 /* A subset of the dump_options table which is used for opt-info
121 options. This must be consistent with the MSG_* flags in
124 static const struct dump_option_value_info opt_info_options
[] =
126 {"optimized", MSG_OPTIMIZED_LOCATIONS
},
127 {"missed", MSG_MISSED_OPTIMIZATION
},
129 {"optall", (MSG_OPTIMIZED_LOCATIONS
130 | MSG_MISSED_OPTIMIZATION
136 dump_register (const char *suffix
, const char *swtch
, const char *glob
,
139 static int next_dump
= FIRST_AUTO_NUMBERED_DUMP
;
140 int num
= next_dump
++;
142 size_t count
= extra_dump_files_in_use
++;
144 if (count
>= extra_dump_files_alloced
)
146 if (extra_dump_files_alloced
== 0)
147 extra_dump_files_alloced
= 32;
149 extra_dump_files_alloced
*= 2;
150 extra_dump_files
= XRESIZEVEC (struct dump_file_info
,
152 extra_dump_files_alloced
);
155 memset (&extra_dump_files
[count
], 0, sizeof (struct dump_file_info
));
156 extra_dump_files
[count
].suffix
= suffix
;
157 extra_dump_files
[count
].swtch
= swtch
;
158 extra_dump_files
[count
].glob
= glob
;
159 extra_dump_files
[count
].pflags
= flags
;
160 extra_dump_files
[count
].num
= num
;
162 return count
+ TDI_end
;
166 /* Return the dump_file_info for the given phase. */
168 struct dump_file_info
*
169 get_dump_file_info (int phase
)
172 return &dump_files
[phase
];
173 else if ((size_t) (phase
- TDI_end
) >= extra_dump_files_in_use
)
176 return extra_dump_files
+ (phase
- TDI_end
);
180 /* Return the name of the dump file for the given phase.
181 If the dump is not enabled, returns NULL. */
184 get_dump_file_name (int phase
)
187 struct dump_file_info
*dfi
;
189 if (phase
== TDI_none
)
192 dfi
= get_dump_file_info (phase
);
193 if (dfi
->pstate
== 0)
196 /* If available, use the command line dump filename. */
198 return xstrdup (dfi
->pfilename
);
205 if (dfi
->pflags
& TDF_TREE
)
207 else if (dfi
->pflags
& TDF_IPA
)
212 if (snprintf (dump_id
, sizeof (dump_id
), ".%03d%c", dfi
->num
, suffix
) < 0)
216 return concat (dump_base_name
, dump_id
, dfi
->suffix
, NULL
);
219 /* For a given DFI, open an alternate dump filename (which could also
220 be a standard stream such as stdout/stderr). If the alternate dump
221 file cannot be opened, return NULL. */
224 dump_open_alternate_stream (struct dump_file_info
*dfi
)
227 if (!dfi
->alt_filename
)
231 return dfi
->alt_stream
;
233 stream
= strcmp("stderr", dfi
->alt_filename
) == 0
235 : strcmp("stdout", dfi
->alt_filename
) == 0
237 : fopen (dfi
->alt_filename
, dfi
->alt_state
< 0 ? "w" : "a");
240 error ("could not open dump file %qs: %m", dfi
->alt_filename
);
247 /* Print source location on DFILE if enabled. */
250 dump_loc (int dump_kind
, FILE *dfile
, source_location loc
)
252 /* Currently vectorization passes print location information. */
255 if (loc
== UNKNOWN_LOCATION
)
256 fprintf (dfile
, "\n%s:%d: note: ",
257 DECL_SOURCE_FILE (current_function_decl
),
258 DECL_SOURCE_LINE (current_function_decl
));
260 fprintf (dfile
, "\n%d: ", LOCATION_LINE (loc
));
264 /* Dump gimple statement GS with SPC indentation spaces and
265 EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled. */
268 dump_gimple_stmt (int dump_kind
, int extra_dump_flags
, gimple gs
, int spc
)
270 if (dump_file
&& (dump_kind
& pflags
))
271 print_gimple_stmt (dump_file
, gs
, spc
, dump_flags
| extra_dump_flags
);
273 if (alt_dump_file
&& (dump_kind
& alt_flags
))
274 print_gimple_stmt (alt_dump_file
, gs
, spc
, dump_flags
| extra_dump_flags
);
277 /* Similar to dump_gimple_stmt, except additionally print source location. */
280 dump_gimple_stmt_loc (int dump_kind
, source_location loc
, int extra_dump_flags
,
283 if (dump_file
&& (dump_kind
& pflags
))
285 dump_loc (dump_kind
, dump_file
, loc
);
286 print_gimple_stmt (dump_file
, gs
, spc
, dump_flags
| extra_dump_flags
);
289 if (alt_dump_file
&& (dump_kind
& alt_flags
))
291 dump_loc (dump_kind
, alt_dump_file
, loc
);
292 print_gimple_stmt (alt_dump_file
, gs
, spc
, dump_flags
| extra_dump_flags
);
296 /* Dump expression tree T using EXTRA_DUMP_FLAGS on dump streams if
297 DUMP_KIND is enabled. */
300 dump_generic_expr (int dump_kind
, int extra_dump_flags
, tree t
)
302 if (dump_file
&& (dump_kind
& pflags
))
303 print_generic_expr (dump_file
, t
, dump_flags
| extra_dump_flags
);
305 if (alt_dump_file
&& (dump_kind
& alt_flags
))
306 print_generic_expr (alt_dump_file
, t
, dump_flags
| extra_dump_flags
);
310 /* Similar to dump_generic_expr, except additionally print the source
314 dump_generic_expr_loc (int dump_kind
, source_location loc
,
315 int extra_dump_flags
, tree t
)
317 if (dump_file
&& (dump_kind
& pflags
))
319 dump_loc (dump_kind
, dump_file
, loc
);
320 print_generic_expr (dump_file
, t
, dump_flags
| extra_dump_flags
);
323 if (alt_dump_file
&& (dump_kind
& alt_flags
))
325 dump_loc (dump_kind
, alt_dump_file
, loc
);
326 print_generic_expr (alt_dump_file
, t
, dump_flags
| extra_dump_flags
);
330 /* Output a formatted message using FORMAT on appropriate dump streams. */
333 dump_printf (int dump_kind
, const char *format
, ...)
335 if (dump_file
&& (dump_kind
& pflags
))
338 va_start (ap
, format
);
339 vfprintf (dump_file
, format
, ap
);
343 if (alt_dump_file
&& (dump_kind
& alt_flags
))
346 va_start (ap
, format
);
347 vfprintf (alt_dump_file
, format
, ap
);
352 /* Similar to dump_printf, except source location is also printed. */
355 dump_printf_loc (int dump_kind
, source_location loc
, const char *format
, ...)
357 if (dump_file
&& (dump_kind
& pflags
))
360 dump_loc (dump_kind
, dump_file
, loc
);
361 va_start (ap
, format
);
362 vfprintf (dump_file
, format
, ap
);
366 if (alt_dump_file
&& (dump_kind
& alt_flags
))
369 dump_loc (dump_kind
, alt_dump_file
, loc
);
370 va_start (ap
, format
);
371 vfprintf (alt_dump_file
, format
, ap
);
376 /* Start a dump for PHASE. Store user-supplied dump flags in
377 *FLAG_PTR. Return the number of streams opened. Set globals
378 DUMP_FILE, and ALT_DUMP_FILE to point to the opened streams, and
379 set dump_flags appropriately for both pass dump stream and opt-info
383 dump_start (int phase
, int *flag_ptr
)
387 struct dump_file_info
*dfi
;
389 if (phase
== TDI_none
|| !dump_phase_enabled_p (phase
))
392 dfi
= get_dump_file_info (phase
);
393 name
= get_dump_file_name (phase
);
396 stream
= strcmp("stderr", name
) == 0
398 : strcmp("stdout", name
) == 0
400 : fopen (name
, dfi
->pstate
< 0 ? "w" : "a");
402 error ("could not open dump file %qs: %m", name
);
409 dfi
->pstream
= stream
;
410 dump_file
= dfi
->pstream
;
411 /* Initialize current dump flags. */
412 pflags
= dfi
->pflags
;
415 stream
= dump_open_alternate_stream (dfi
);
418 dfi
->alt_stream
= stream
;
420 alt_dump_file
= dfi
->alt_stream
;
421 /* Initialize current opt-info flags. */
422 alt_flags
= dfi
->alt_flags
;
426 *flag_ptr
= dfi
->pflags
;
431 /* Finish a tree dump for PHASE and close associated dump streams. Also
432 reset the globals DUMP_FILE, ALT_DUMP_FILE, and DUMP_FLAGS. */
435 dump_finish (int phase
)
437 struct dump_file_info
*dfi
;
441 dfi
= get_dump_file_info (phase
);
443 fclose (dfi
->pstream
);
445 if (dfi
->alt_stream
&& strcmp("stderr", dfi
->alt_filename
) != 0
446 && strcmp("stdout", dfi
->alt_filename
) != 0)
447 fclose (dfi
->alt_stream
);
449 dfi
->alt_stream
= NULL
;
452 alt_dump_file
= NULL
;
453 dump_flags
= TDI_none
;
458 /* Begin a tree dump for PHASE. Stores any user supplied flag in
459 *FLAG_PTR and returns a stream to write to. If the dump is not
460 enabled, returns NULL.
461 Multiple calls will reopen and append to the dump file. */
464 dump_begin (int phase
, int *flag_ptr
)
467 struct dump_file_info
*dfi
;
470 if (phase
== TDI_none
|| !dump_phase_enabled_p (phase
))
473 name
= get_dump_file_name (phase
);
476 dfi
= get_dump_file_info (phase
);
478 stream
= strcmp("stderr", name
) == 0
480 : strcmp("stdout", name
) == 0
482 : fopen (name
, dfi
->pstate
< 0 ? "w" : "a");
485 error ("could not open dump file %qs: %m", name
);
491 *flag_ptr
= dfi
->pflags
;
493 /* Initialize current flags */
494 pflags
= dfi
->pflags
;
498 /* Returns nonzero if dump PHASE is enabled for at least one stream.
499 If PHASE is TDI_tree_all, return nonzero if any dump is enabled for
503 dump_phase_enabled_p (int phase
)
505 if (phase
== TDI_tree_all
)
508 for (i
= TDI_none
+ 1; i
< (size_t) TDI_end
; i
++)
509 if (dump_files
[i
].pstate
|| dump_files
[i
].alt_state
)
511 for (i
= 0; i
< extra_dump_files_in_use
; i
++)
512 if (extra_dump_files
[i
].pstate
|| extra_dump_files
[i
].alt_state
)
518 struct dump_file_info
*dfi
= get_dump_file_info (phase
);
519 return dfi
->pstate
|| dfi
->alt_state
;
523 /* Returns nonzero if tree dump PHASE has been initialized. */
526 dump_initialized_p (int phase
)
528 struct dump_file_info
*dfi
= get_dump_file_info (phase
);
529 return dfi
->pstate
> 0 || dfi
->alt_state
> 0;
532 /* Returns the switch name of PHASE. */
535 dump_flag_name (int phase
)
537 struct dump_file_info
*dfi
= get_dump_file_info (phase
);
541 /* Finish a tree dump for PHASE. STREAM is the stream created by
545 dump_end (int phase ATTRIBUTE_UNUSED
, FILE *stream
)
547 if (stream
!= stderr
&& stream
!= stdout
)
551 /* Enable all tree dumps with FLAGS on FILENAME. Return number of
552 enabled tree dumps. */
555 dump_enable_all (int flags
, const char *filename
)
557 int ir_dump_type
= (flags
& (TDF_TREE
| TDF_RTL
| TDF_IPA
));
561 for (i
= TDI_none
+ 1; i
< (size_t) TDI_end
; i
++)
563 if ((dump_files
[i
].pflags
& ir_dump_type
))
565 const char *old_filename
= dump_files
[i
].pfilename
;
566 dump_files
[i
].pstate
= -1;
567 dump_files
[i
].pflags
|= flags
;
569 /* Override the existing filename. */
572 dump_files
[i
].pfilename
= xstrdup (filename
);
573 /* Since it is a command-line provided file, which is
574 common to all the phases, use it in append mode. */
575 dump_files
[i
].pstate
= 1;
577 if (old_filename
&& filename
!= old_filename
)
578 free (CONST_CAST (char *, old_filename
));
582 for (i
= 0; i
< extra_dump_files_in_use
; i
++)
584 if ((extra_dump_files
[i
].pflags
& ir_dump_type
))
586 const char *old_filename
= extra_dump_files
[i
].pfilename
;
587 extra_dump_files
[i
].pstate
= -1;
588 extra_dump_files
[i
].pflags
|= flags
;
590 /* Override the existing filename. */
593 extra_dump_files
[i
].pfilename
= xstrdup (filename
);
594 /* Since it is a command-line provided file, which is
595 common to all the phases, use it in append mode. */
596 extra_dump_files
[i
].pstate
= 1;
598 if (old_filename
&& filename
!= old_filename
)
599 free (CONST_CAST (char *, old_filename
));
606 /* Enable opt-info dumps on all IR_DUMP_TYPE passes with FLAGS on
607 FILENAME. Return the number of enabled dumps. */
610 opt_info_enable_all (int ir_dump_type
, int flags
, const char *filename
)
615 for (i
= TDI_none
+ 1; i
< (size_t) TDI_end
; i
++)
617 if ((dump_files
[i
].pflags
& ir_dump_type
))
619 const char *old_filename
= dump_files
[i
].alt_filename
;
620 /* Since this file is shared among different passes, it
621 should be opened in append mode. */
622 dump_files
[i
].alt_state
= 1;
623 dump_files
[i
].alt_flags
|= flags
;
625 /* Override the existing filename. */
627 dump_files
[i
].alt_filename
= xstrdup (filename
);
628 if (old_filename
&& filename
!= old_filename
)
629 free (CONST_CAST (char *, old_filename
));
633 for (i
= 0; i
< extra_dump_files_in_use
; i
++)
635 if ((extra_dump_files
[i
].pflags
& ir_dump_type
))
637 const char *old_filename
= extra_dump_files
[i
].alt_filename
;
638 /* Since this file is shared among different passes, it
639 should be opened in append mode. */
640 extra_dump_files
[i
].alt_state
= 1;
641 extra_dump_files
[i
].alt_flags
|= flags
;
643 /* Override the existing filename. */
645 extra_dump_files
[i
].alt_filename
= xstrdup (filename
);
646 if (old_filename
&& filename
!= old_filename
)
647 free (CONST_CAST (char *, old_filename
));
654 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
655 relevant details in the dump_files array. */
658 dump_switch_p_1 (const char *arg
, struct dump_file_info
*dfi
, bool doglob
)
660 const char *option_value
;
664 if (doglob
&& !dfi
->glob
)
667 option_value
= skip_leading_substring (arg
, doglob
? dfi
->glob
: dfi
->swtch
);
671 if (*option_value
&& *option_value
!= '-' && *option_value
!= '=')
679 const struct dump_option_value_info
*option_ptr
;
686 end_ptr
= strchr (ptr
, '-');
687 eq_ptr
= strchr (ptr
, '=');
689 if (eq_ptr
&& !end_ptr
)
693 end_ptr
= ptr
+ strlen (ptr
);
694 length
= end_ptr
- ptr
;
696 for (option_ptr
= dump_options
; option_ptr
->name
; option_ptr
++)
697 if (strlen (option_ptr
->name
) == length
698 && !memcmp (option_ptr
->name
, ptr
, length
))
700 flags
|= option_ptr
->value
;
706 /* Interpret rest of the argument as a dump filename. This
707 filename overrides other command line filenames. */
709 free (CONST_CAST (char *, dfi
->pfilename
));
710 dfi
->pfilename
= xstrdup (ptr
+ 1);
714 warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
715 length
, ptr
, dfi
->swtch
);
721 dfi
->pflags
|= flags
;
723 /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
725 if (dfi
->suffix
== NULL
)
726 dump_enable_all (dfi
->pflags
, dfi
->pfilename
);
732 dump_switch_p (const char *arg
)
737 for (i
= TDI_none
+ 1; i
!= TDI_end
; i
++)
738 any
|= dump_switch_p_1 (arg
, &dump_files
[i
], false);
740 /* Don't glob if we got a hit already */
742 for (i
= TDI_none
+ 1; i
!= TDI_end
; i
++)
743 any
|= dump_switch_p_1 (arg
, &dump_files
[i
], true);
745 for (i
= 0; i
< extra_dump_files_in_use
; i
++)
746 any
|= dump_switch_p_1 (arg
, &extra_dump_files
[i
], false);
749 for (i
= 0; i
< extra_dump_files_in_use
; i
++)
750 any
|= dump_switch_p_1 (arg
, &extra_dump_files
[i
], true);
756 /* Parse ARG as a -fopt-info switch and store flags and filename.
757 Return non-zero if it is a recognized switch. */
760 opt_info_switch_p_1 (const char *arg
, int *flags
, char **filename
)
762 const char *option_value
;
776 const struct dump_option_value_info
*option_ptr
;
783 end_ptr
= strchr (ptr
, '-');
784 eq_ptr
= strchr (ptr
, '=');
786 if (eq_ptr
&& !end_ptr
)
790 end_ptr
= ptr
+ strlen (ptr
);
791 length
= end_ptr
- ptr
;
793 for (option_ptr
= opt_info_options
; option_ptr
->name
; option_ptr
++)
794 if (strlen (option_ptr
->name
) == length
795 && !memcmp (option_ptr
->name
, ptr
, length
))
797 *flags
|= option_ptr
->value
;
803 /* Interpret rest of the argument as a dump filename. This
804 filename overrides other command line filenames. */
805 *filename
= xstrdup (ptr
+ 1);
809 warning (0, "ignoring unknown option %q.*s in %<-fopt-info=%s%>",
818 /* Return non-zero if ARG is a recognized switch for
819 -fopt-info. Return zero otherwise. */
822 opt_info_switch_p (const char *arg
)
827 opt_info_switch_p_1 (arg
, &flags
, &filename
);
830 filename
= xstrdup ("stderr");
834 return opt_info_enable_all ((TDF_TREE
| TDF_RTL
| TDF_IPA
), flags
, filename
);
837 /* Print basic block on the dump streams. */
840 dump_basic_block (int dump_kind
, basic_block bb
, int indent
)
842 if (dump_file
&& (dump_kind
& pflags
))
843 dump_bb (dump_file
, bb
, indent
, TDF_DETAILS
);
844 if (alt_dump_file
&& (dump_kind
& alt_flags
))
845 dump_bb (alt_dump_file
, bb
, indent
, TDF_DETAILS
);
848 /* Print information from the combine pass on dump_file. */
851 print_combine_total_stats (void)
854 dump_combine_total_stats (dump_file
);
857 /* Enable RTL dump for all the RTL passes. */
860 enable_rtl_dump_file (void)
862 return dump_enable_all (TDF_RTL
| TDF_DETAILS
| TDF_BLOCKS
, NULL
) > 0;