1 /* Dump infrastructure for optimizations and intermediate representation.
2 Copyright (C) 2012-2013 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;
48 /* Table of tree dump switches. This must be consistent with the
49 TREE_DUMP_INDEX enumeration in dumpfile.h. */
50 static struct dump_file_info dump_files[TDI_end] =
52 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0, 0},
53 {".cgraph", "ipa-cgraph", NULL, NULL, NULL, NULL, NULL, TDF_IPA,
55 {".tu", "translation-unit", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
57 {".class", "class-hierarchy", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
59 {".original", "tree-original", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
61 {".gimple", "tree-gimple", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
63 {".nested", "tree-nested", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
65 #define FIRST_AUTO_NUMBERED_DUMP 6
67 {NULL, "tree-all", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
69 {NULL, "rtl-all", NULL, NULL, NULL, NULL, NULL, TDF_RTL,
71 {NULL, "ipa-all", NULL, NULL, NULL, NULL, NULL, TDF_IPA,
75 /* Dynamically registered tree dump files and switches. */
76 static struct dump_file_info *extra_dump_files;
77 static size_t extra_dump_files_in_use;
78 static size_t extra_dump_files_alloced;
80 /* Define a name->number mapping for a dump flag value. */
81 struct dump_option_value_info
83 const char *const name; /* the name of the value */
84 const int value; /* the value of the name */
87 /* Table of dump options. This must be consistent with the TDF_* flags
88 in dumpfile.h and opt_info_options below. */
89 static const struct dump_option_value_info dump_options[] =
91 {"address", TDF_ADDRESS},
92 {"asmname", TDF_ASMNAME},
96 {"details", (TDF_DETAILS | MSG_OPTIMIZED_LOCATIONS
97 | MSG_MISSED_OPTIMIZATION
99 {"cselib", TDF_CSELIB},
100 {"stats", TDF_STATS},
101 {"blocks", TDF_BLOCKS},
103 {"lineno", TDF_LINENO},
105 {"stmtaddr", TDF_STMTADDR},
106 {"memsyms", TDF_MEMSYMS},
107 {"verbose", TDF_VERBOSE},
109 {"alias", TDF_ALIAS},
110 {"nouid", TDF_NOUID},
111 {"enumerate_locals", TDF_ENUMERATE_LOCALS},
113 {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA
114 | TDF_STMTADDR | TDF_GRAPH | TDF_DIAGNOSTIC | TDF_VERBOSE
115 | TDF_RHS_ONLY | TDF_NOUID | TDF_ENUMERATE_LOCALS | TDF_SCEV)},
119 /* A subset of the dump_options table which is used for -fopt-info
120 types. This must be consistent with the MSG_* flags in dumpfile.h.
122 static const struct dump_option_value_info optinfo_verbosity_options[] =
124 {"optimized", MSG_OPTIMIZED_LOCATIONS},
125 {"missed", MSG_MISSED_OPTIMIZATION},
131 /* Flags used for -fopt-info groups. */
132 static const struct dump_option_value_info optgroup_options[] =
134 {"ipa", OPTGROUP_IPA},
135 {"loop", OPTGROUP_LOOP},
136 {"inline", OPTGROUP_INLINE},
137 {"vec", OPTGROUP_VEC},
138 {"optall", OPTGROUP_ALL},
143 dump_register (const char *suffix, const char *swtch, const char *glob,
144 int flags, int optgroup_flags)
146 static int next_dump = FIRST_AUTO_NUMBERED_DUMP;
147 int num = next_dump++;
149 size_t count = extra_dump_files_in_use++;
151 if (count >= extra_dump_files_alloced)
153 if (extra_dump_files_alloced == 0)
154 extra_dump_files_alloced = 32;
156 extra_dump_files_alloced *= 2;
157 extra_dump_files = XRESIZEVEC (struct dump_file_info,
159 extra_dump_files_alloced);
162 memset (&extra_dump_files[count], 0, sizeof (struct dump_file_info));
163 extra_dump_files[count].suffix = suffix;
164 extra_dump_files[count].swtch = swtch;
165 extra_dump_files[count].glob = glob;
166 extra_dump_files[count].pflags = flags;
167 extra_dump_files[count].optgroup_flags = optgroup_flags;
168 extra_dump_files[count].num = num;
170 return count + TDI_end;
174 /* Return the dump_file_info for the given phase. */
176 struct dump_file_info *
177 get_dump_file_info (int phase)
180 return &dump_files[phase];
181 else if ((size_t) (phase - TDI_end) >= extra_dump_files_in_use)
184 return extra_dump_files + (phase - TDI_end);
188 /* Return the name of the dump file for the given phase.
189 If the dump is not enabled, returns NULL. */
192 get_dump_file_name (int phase)
195 struct dump_file_info *dfi;
197 if (phase == TDI_none)
200 dfi = get_dump_file_info (phase);
201 if (dfi->pstate == 0)
204 /* If available, use the command line dump filename. */
206 return xstrdup (dfi->pfilename);
213 if (dfi->pflags & TDF_TREE)
215 else if (dfi->pflags & TDF_IPA)
220 if (snprintf (dump_id, sizeof (dump_id), ".%03d%c", dfi->num, suffix) < 0)
224 return concat (dump_base_name, dump_id, dfi->suffix, NULL);
227 /* For a given DFI, open an alternate dump filename (which could also
228 be a standard stream such as stdout/stderr). If the alternate dump
229 file cannot be opened, return NULL. */
232 dump_open_alternate_stream (struct dump_file_info *dfi)
235 if (!dfi->alt_filename)
239 return dfi->alt_stream;
241 stream = strcmp("stderr", dfi->alt_filename) == 0
243 : strcmp("stdout", dfi->alt_filename) == 0
245 : fopen (dfi->alt_filename, dfi->alt_state < 0 ? "w" : "a");
248 error ("could not open dump file %qs: %m", dfi->alt_filename);
255 /* Print source location on DFILE if enabled. */
258 dump_loc (int dump_kind, FILE *dfile, source_location loc)
260 /* Currently vectorization passes print location information. */
263 if (LOCATION_LOCUS (loc) > BUILTINS_LOCATION)
264 fprintf (dfile, "\n%s:%d: note: ", LOCATION_FILE (loc),
265 LOCATION_LINE (loc));
266 else if (current_function_decl)
267 fprintf (dfile, "\n%s:%d: note: ",
268 DECL_SOURCE_FILE (current_function_decl),
269 DECL_SOURCE_LINE (current_function_decl));
273 /* Dump gimple statement GS with SPC indentation spaces and
274 EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled. */
277 dump_gimple_stmt (int dump_kind, int extra_dump_flags, gimple gs, int spc)
279 if (dump_file && (dump_kind & pflags))
280 print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
282 if (alt_dump_file && (dump_kind & alt_flags))
283 print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
286 /* Similar to dump_gimple_stmt, except additionally print source location. */
289 dump_gimple_stmt_loc (int dump_kind, source_location loc, int extra_dump_flags,
292 if (dump_file && (dump_kind & pflags))
294 dump_loc (dump_kind, dump_file, loc);
295 print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
298 if (alt_dump_file && (dump_kind & alt_flags))
300 dump_loc (dump_kind, alt_dump_file, loc);
301 print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
305 /* Dump expression tree T using EXTRA_DUMP_FLAGS on dump streams if
306 DUMP_KIND is enabled. */
309 dump_generic_expr (int dump_kind, int extra_dump_flags, tree t)
311 if (dump_file && (dump_kind & pflags))
312 print_generic_expr (dump_file, t, dump_flags | extra_dump_flags);
314 if (alt_dump_file && (dump_kind & alt_flags))
315 print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags);
319 /* Similar to dump_generic_expr, except additionally print the source
323 dump_generic_expr_loc (int dump_kind, source_location loc,
324 int extra_dump_flags, tree t)
326 if (dump_file && (dump_kind & pflags))
328 dump_loc (dump_kind, dump_file, loc);
329 print_generic_expr (dump_file, t, dump_flags | extra_dump_flags);
332 if (alt_dump_file && (dump_kind & alt_flags))
334 dump_loc (dump_kind, alt_dump_file, loc);
335 print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags);
339 /* Output a formatted message using FORMAT on appropriate dump streams. */
342 dump_printf (int dump_kind, const char *format, ...)
344 if (dump_file && (dump_kind & pflags))
347 va_start (ap, format);
348 vfprintf (dump_file, format, ap);
352 if (alt_dump_file && (dump_kind & alt_flags))
355 va_start (ap, format);
356 vfprintf (alt_dump_file, format, ap);
361 /* Similar to dump_printf, except source location is also printed. */
364 dump_printf_loc (int dump_kind, source_location loc, const char *format, ...)
366 if (dump_file && (dump_kind & pflags))
369 dump_loc (dump_kind, dump_file, loc);
370 va_start (ap, format);
371 vfprintf (dump_file, format, ap);
375 if (alt_dump_file && (dump_kind & alt_flags))
378 dump_loc (dump_kind, alt_dump_file, loc);
379 va_start (ap, format);
380 vfprintf (alt_dump_file, format, ap);
385 /* Start a dump for PHASE. Store user-supplied dump flags in
386 *FLAG_PTR. Return the number of streams opened. Set globals
387 DUMP_FILE, and ALT_DUMP_FILE to point to the opened streams, and
388 set dump_flags appropriately for both pass dump stream and
389 -fopt-info stream. */
392 dump_start (int phase, int *flag_ptr)
396 struct dump_file_info *dfi;
398 if (phase == TDI_none || !dump_phase_enabled_p (phase))
401 dfi = get_dump_file_info (phase);
402 name = get_dump_file_name (phase);
405 stream = strcmp("stderr", name) == 0
407 : strcmp("stdout", name) == 0
409 : fopen (name, dfi->pstate < 0 ? "w" : "a");
411 error ("could not open dump file %qs: %m", name);
418 dfi->pstream = stream;
419 dump_file = dfi->pstream;
420 /* Initialize current dump flags. */
421 pflags = dfi->pflags;
424 stream = dump_open_alternate_stream (dfi);
427 dfi->alt_stream = stream;
429 alt_dump_file = dfi->alt_stream;
430 /* Initialize current -fopt-info flags. */
431 alt_flags = dfi->alt_flags;
435 *flag_ptr = dfi->pflags;
440 /* Finish a tree dump for PHASE and close associated dump streams. Also
441 reset the globals DUMP_FILE, ALT_DUMP_FILE, and DUMP_FLAGS. */
444 dump_finish (int phase)
446 struct dump_file_info *dfi;
450 dfi = get_dump_file_info (phase);
452 fclose (dfi->pstream);
454 if (dfi->alt_stream && strcmp("stderr", dfi->alt_filename) != 0
455 && strcmp("stdout", dfi->alt_filename) != 0)
456 fclose (dfi->alt_stream);
458 dfi->alt_stream = NULL;
461 alt_dump_file = NULL;
462 dump_flags = TDI_none;
467 /* Begin a tree dump for PHASE. Stores any user supplied flag in
468 *FLAG_PTR and returns a stream to write to. If the dump is not
469 enabled, returns NULL.
470 Multiple calls will reopen and append to the dump file. */
473 dump_begin (int phase, int *flag_ptr)
476 struct dump_file_info *dfi;
479 if (phase == TDI_none || !dump_phase_enabled_p (phase))
482 name = get_dump_file_name (phase);
485 dfi = get_dump_file_info (phase);
487 stream = strcmp("stderr", name) == 0
489 : strcmp("stdout", name) == 0
491 : fopen (name, dfi->pstate < 0 ? "w" : "a");
494 error ("could not open dump file %qs: %m", name);
500 *flag_ptr = dfi->pflags;
502 /* Initialize current flags */
503 pflags = dfi->pflags;
507 /* Returns nonzero if dump PHASE is enabled for at least one stream.
508 If PHASE is TDI_tree_all, return nonzero if any dump is enabled for
512 dump_phase_enabled_p (int phase)
514 if (phase == TDI_tree_all)
517 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
518 if (dump_files[i].pstate || dump_files[i].alt_state)
520 for (i = 0; i < extra_dump_files_in_use; i++)
521 if (extra_dump_files[i].pstate || extra_dump_files[i].alt_state)
527 struct dump_file_info *dfi = get_dump_file_info (phase);
528 return dfi->pstate || dfi->alt_state;
532 /* Returns nonzero if tree dump PHASE has been initialized. */
535 dump_initialized_p (int phase)
537 struct dump_file_info *dfi = get_dump_file_info (phase);
538 return dfi->pstate > 0 || dfi->alt_state > 0;
541 /* Returns the switch name of PHASE. */
544 dump_flag_name (int phase)
546 struct dump_file_info *dfi = get_dump_file_info (phase);
550 /* Finish a tree dump for PHASE. STREAM is the stream created by
554 dump_end (int phase ATTRIBUTE_UNUSED, FILE *stream)
556 if (stream != stderr && stream != stdout)
560 /* Enable all tree dumps with FLAGS on FILENAME. Return number of
561 enabled tree dumps. */
564 dump_enable_all (int flags, const char *filename)
566 int ir_dump_type = (flags & (TDF_TREE | TDF_RTL | TDF_IPA));
570 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
572 if ((dump_files[i].pflags & ir_dump_type))
574 const char *old_filename = dump_files[i].pfilename;
575 dump_files[i].pstate = -1;
576 dump_files[i].pflags |= flags;
578 /* Override the existing filename. */
581 dump_files[i].pfilename = xstrdup (filename);
582 /* Since it is a command-line provided file, which is
583 common to all the phases, use it in append mode. */
584 dump_files[i].pstate = 1;
586 if (old_filename && filename != old_filename)
587 free (CONST_CAST (char *, old_filename));
591 for (i = 0; i < extra_dump_files_in_use; i++)
593 if ((extra_dump_files[i].pflags & ir_dump_type))
595 const char *old_filename = extra_dump_files[i].pfilename;
596 extra_dump_files[i].pstate = -1;
597 extra_dump_files[i].pflags |= flags;
599 /* Override the existing filename. */
602 extra_dump_files[i].pfilename = xstrdup (filename);
603 /* Since it is a command-line provided file, which is
604 common to all the phases, use it in append mode. */
605 extra_dump_files[i].pstate = 1;
607 if (old_filename && filename != old_filename)
608 free (CONST_CAST (char *, old_filename));
615 /* Enable -fopt-info dumps on all dump files matching OPTGROUP_FLAGS.
616 Enable dumps with FLAGS on FILENAME. Return the number of enabled
620 opt_info_enable_passes (int optgroup_flags, int flags, const char *filename)
625 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
627 if ((dump_files[i].optgroup_flags & optgroup_flags))
629 const char *old_filename = dump_files[i].alt_filename;
630 /* Since this file is shared among different passes, it
631 should be opened in append mode. */
632 dump_files[i].alt_state = 1;
633 dump_files[i].alt_flags |= flags;
635 /* Override the existing filename. */
637 dump_files[i].alt_filename = xstrdup (filename);
638 if (old_filename && filename != old_filename)
639 free (CONST_CAST (char *, old_filename));
643 for (i = 0; i < extra_dump_files_in_use; i++)
645 if ((extra_dump_files[i].optgroup_flags & optgroup_flags))
647 const char *old_filename = extra_dump_files[i].alt_filename;
648 /* Since this file is shared among different passes, it
649 should be opened in append mode. */
650 extra_dump_files[i].alt_state = 1;
651 extra_dump_files[i].alt_flags |= flags;
653 /* Override the existing filename. */
655 extra_dump_files[i].alt_filename = xstrdup (filename);
656 if (old_filename && filename != old_filename)
657 free (CONST_CAST (char *, old_filename));
664 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
665 relevant details in the dump_files array. */
668 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
670 const char *option_value;
674 if (doglob && !dfi->glob)
677 option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
681 if (*option_value && *option_value != '-' && *option_value != '=')
689 const struct dump_option_value_info *option_ptr;
696 end_ptr = strchr (ptr, '-');
697 eq_ptr = strchr (ptr, '=');
699 if (eq_ptr && !end_ptr)
703 end_ptr = ptr + strlen (ptr);
704 length = end_ptr - ptr;
706 for (option_ptr = dump_options; option_ptr->name; option_ptr++)
707 if (strlen (option_ptr->name) == length
708 && !memcmp (option_ptr->name, ptr, length))
710 flags |= option_ptr->value;
716 /* Interpret rest of the argument as a dump filename. This
717 filename overrides other command line filenames. */
719 free (CONST_CAST (char *, dfi->pfilename));
720 dfi->pfilename = xstrdup (ptr + 1);
724 warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
725 length, ptr, dfi->swtch);
731 dfi->pflags |= flags;
733 /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
735 if (dfi->suffix == NULL)
736 dump_enable_all (dfi->pflags, dfi->pfilename);
742 dump_switch_p (const char *arg)
747 for (i = TDI_none + 1; i != TDI_end; i++)
748 any |= dump_switch_p_1 (arg, &dump_files[i], false);
750 /* Don't glob if we got a hit already */
752 for (i = TDI_none + 1; i != TDI_end; i++)
753 any |= dump_switch_p_1 (arg, &dump_files[i], true);
755 for (i = 0; i < extra_dump_files_in_use; i++)
756 any |= dump_switch_p_1 (arg, &extra_dump_files[i], false);
759 for (i = 0; i < extra_dump_files_in_use; i++)
760 any |= dump_switch_p_1 (arg, &extra_dump_files[i], true);
766 /* Parse ARG as a -fopt-info switch and store flags, optgroup_flags
767 and filename. Return non-zero if it is a recognized switch. */
770 opt_info_switch_p_1 (const char *arg, int *flags, int *optgroup_flags,
773 const char *option_value;
784 return 1; /* Handle '-fopt-info' without any additional options. */
788 const struct dump_option_value_info *option_ptr;
795 end_ptr = strchr (ptr, '-');
796 eq_ptr = strchr (ptr, '=');
798 if (eq_ptr && !end_ptr)
802 end_ptr = ptr + strlen (ptr);
803 length = end_ptr - ptr;
805 for (option_ptr = optinfo_verbosity_options; option_ptr->name;
807 if (strlen (option_ptr->name) == length
808 && !memcmp (option_ptr->name, ptr, length))
810 *flags |= option_ptr->value;
814 for (option_ptr = optgroup_options; option_ptr->name; option_ptr++)
815 if (strlen (option_ptr->name) == length
816 && !memcmp (option_ptr->name, ptr, length))
818 *optgroup_flags |= option_ptr->value;
824 /* Interpret rest of the argument as a dump filename. This
825 filename overrides other command line filenames. */
826 *filename = xstrdup (ptr + 1);
831 warning (0, "unknown option %q.*s in %<-fopt-info-%s%>",
842 /* Return non-zero if ARG is a recognized switch for
843 -fopt-info. Return zero otherwise. */
846 opt_info_switch_p (const char *arg)
851 static char *file_seen = NULL;
853 if (!opt_info_switch_p_1 (arg, &flags, &optgroup_flags, &filename))
857 filename = xstrdup ("stderr");
859 /* Bail out if a different filename has been specified. */
860 if (file_seen && strcmp (file_seen, filename))
862 warning (0, "ignoring possibly conflicting option %<-fopt-info-%s%>",
867 file_seen = xstrdup (filename);
871 optgroup_flags = OPTGROUP_ALL;
873 return opt_info_enable_passes (optgroup_flags, flags, filename);
876 /* Print basic block on the dump streams. */
879 dump_basic_block (int dump_kind, basic_block bb, int indent)
881 if (dump_file && (dump_kind & pflags))
882 dump_bb (dump_file, bb, indent, TDF_DETAILS);
883 if (alt_dump_file && (dump_kind & alt_flags))
884 dump_bb (alt_dump_file, bb, indent, TDF_DETAILS);
887 /* Print information from the combine pass on dump_file. */
890 print_combine_total_stats (void)
893 dump_combine_total_stats (dump_file);
896 /* Enable RTL dump for all the RTL passes. */
899 enable_rtl_dump_file (void)
901 return dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS, NULL) > 0;