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 */
35 static FILE *alt_dump_file = NULL;
37 static void dump_loc (int, FILE *, source_location);
38 static int dump_enabled_p (int);
39 static FILE *dump_open_alternate_stream (struct dump_file_info *);
41 /* Table of tree dump switches. This must be consistent with the
42 TREE_DUMP_INDEX enumeration in dumpfile.h. */
43 static struct dump_file_info dump_files[TDI_end] =
45 {NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, 0},
46 {".cgraph", "ipa-cgraph", NULL, NULL, NULL, NULL, NULL, TDF_IPA,
48 {".tu", "translation-unit", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
50 {".class", "class-hierarchy", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
52 {".original", "tree-original", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
54 {".gimple", "tree-gimple", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
56 {".nested", "tree-nested", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
58 {".vcg", "tree-vcg", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
60 #define FIRST_AUTO_NUMBERED_DUMP 7
62 {NULL, "tree-all", NULL, NULL, NULL, NULL, NULL, TDF_TREE,
64 {NULL, "rtl-all", NULL, NULL, NULL, NULL, NULL, TDF_RTL,
66 {NULL, "ipa-all", NULL, NULL, NULL, NULL, NULL, TDF_IPA,
70 /* Dynamically registered tree dump files and switches. */
71 static struct dump_file_info *extra_dump_files;
72 static size_t extra_dump_files_in_use;
73 static size_t extra_dump_files_alloced;
75 /* Define a name->number mapping for a dump flag value. */
76 struct dump_option_value_info
78 const char *const name; /* the name of the value */
79 const int value; /* the value of the name */
82 /* Table of dump options. This must be consistent with the TDF_* flags
83 in dumpfile.h and opt_info_options below. */
84 static const struct dump_option_value_info dump_options[] =
86 {"address", TDF_ADDRESS},
87 {"asmname", TDF_ASMNAME},
91 {"details", (TDF_DETAILS | MSG_OPTIMIZED_LOCATIONS
92 | MSG_MISSED_OPTIMIZATION
94 {"cselib", TDF_CSELIB},
96 {"blocks", TDF_BLOCKS},
98 {"lineno", TDF_LINENO},
100 {"stmtaddr", TDF_STMTADDR},
101 {"memsyms", TDF_MEMSYMS},
102 {"verbose", TDF_VERBOSE},
104 {"alias", TDF_ALIAS},
105 {"nouid", TDF_NOUID},
106 {"enumerate_locals", TDF_ENUMERATE_LOCALS},
108 {"all", ~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_TREE | TDF_RTL | TDF_IPA
109 | TDF_STMTADDR | TDF_GRAPH | TDF_DIAGNOSTIC | TDF_VERBOSE
110 | TDF_RHS_ONLY | TDF_NOUID | TDF_ENUMERATE_LOCALS | TDF_SCEV)},
114 /* A subset of the dump_options table which is used for opt-info
115 options. This must be consistent with the MSG_* flags in
118 static const struct dump_option_value_info opt_info_options[] =
120 {"optimized", MSG_OPTIMIZED_LOCATIONS},
121 {"missed", MSG_MISSED_OPTIMIZATION},
123 {"optall", (MSG_OPTIMIZED_LOCATIONS
124 | MSG_MISSED_OPTIMIZATION
130 dump_register (const char *suffix, const char *swtch, const char *glob,
133 static int next_dump = FIRST_AUTO_NUMBERED_DUMP;
134 int num = next_dump++;
136 size_t count = extra_dump_files_in_use++;
138 if (count >= extra_dump_files_alloced)
140 if (extra_dump_files_alloced == 0)
141 extra_dump_files_alloced = 32;
143 extra_dump_files_alloced *= 2;
144 extra_dump_files = XRESIZEVEC (struct dump_file_info,
146 extra_dump_files_alloced);
149 memset (&extra_dump_files[count], 0, sizeof (struct dump_file_info));
150 extra_dump_files[count].suffix = suffix;
151 extra_dump_files[count].swtch = swtch;
152 extra_dump_files[count].glob = glob;
153 extra_dump_files[count].pflags = flags;
154 extra_dump_files[count].num = num;
156 return count + TDI_end;
160 /* Return the dump_file_info for the given phase. */
162 struct dump_file_info *
163 get_dump_file_info (int phase)
166 return &dump_files[phase];
167 else if ((size_t) (phase - TDI_end) >= extra_dump_files_in_use)
170 return extra_dump_files + (phase - TDI_end);
174 /* Return the name of the dump file for the given phase.
175 If the dump is not enabled, returns NULL. */
178 get_dump_file_name (int phase)
181 struct dump_file_info *dfi;
183 if (phase == TDI_none)
186 dfi = get_dump_file_info (phase);
187 if (dfi->pstate == 0)
190 /* If available, use the command line dump filename. */
192 return xstrdup (dfi->pfilename);
199 if (dfi->pflags & TDF_TREE)
201 else if (dfi->pflags & TDF_IPA)
206 if (snprintf (dump_id, sizeof (dump_id), ".%03d%c", dfi->num, suffix) < 0)
210 return concat (dump_base_name, dump_id, dfi->suffix, NULL);
213 /* For a given DFI, open an alternate dump filename (which could also
214 be a standard stream such as stdout/stderr). If the alternate dump
215 file cannot be opened, return NULL. */
218 dump_open_alternate_stream (struct dump_file_info *dfi)
221 if (!dfi->alt_filename)
225 return dfi->alt_stream;
227 stream = strcmp("stderr", dfi->alt_filename) == 0
229 : strcmp("stdout", dfi->alt_filename) == 0
231 : fopen (dfi->alt_filename, dfi->alt_state < 0 ? "w" : "a");
234 error ("could not open dump file %qs: %m", dfi->alt_filename);
241 /* Print source location on DFILE if enabled. */
244 dump_loc (int dump_kind, FILE *dfile, source_location loc)
246 /* Currently vectorization passes print location information. */
249 if (loc == UNKNOWN_LOCATION)
250 fprintf (dfile, "\n%s:%d: note: ",
251 DECL_SOURCE_FILE (current_function_decl),
252 DECL_SOURCE_LINE (current_function_decl));
254 fprintf (dfile, "\n%d: ", LOCATION_LINE (loc));
258 /* Dump gimple statement GS with SPC indentation spaces and
259 EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled. */
262 dump_gimple_stmt (int dump_kind, int extra_dump_flags, gimple gs, int spc)
264 if (dump_file && (dump_kind & pflags))
265 print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
267 if (alt_dump_file && (dump_kind & alt_flags))
268 print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
271 /* Similar to dump_gimple_stmt, except additionally print source location. */
274 dump_gimple_stmt_loc (int dump_kind, source_location loc, int extra_dump_flags,
277 if (dump_file && (dump_kind & pflags))
279 dump_loc (dump_kind, dump_file, loc);
280 print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
283 if (alt_dump_file && (dump_kind & alt_flags))
285 dump_loc (dump_kind, alt_dump_file, loc);
286 print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
290 /* Dump expression tree T using EXTRA_DUMP_FLAGS on dump streams if
291 DUMP_KIND is enabled. */
294 dump_generic_expr (int dump_kind, int extra_dump_flags, tree t)
296 if (dump_file && (dump_kind & pflags))
297 print_generic_expr (dump_file, t, dump_flags | extra_dump_flags);
299 if (alt_dump_file && (dump_kind & alt_flags))
300 print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags);
304 /* Similar to dump_generic_expr, except additionally print the source
308 dump_generic_expr_loc (int dump_kind, source_location loc,
309 int extra_dump_flags, tree t)
311 if (dump_file && (dump_kind & pflags))
313 dump_loc (dump_kind, dump_file, loc);
314 print_generic_expr (dump_file, t, dump_flags | extra_dump_flags);
317 if (alt_dump_file && (dump_kind & alt_flags))
319 dump_loc (dump_kind, alt_dump_file, loc);
320 print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags);
324 /* Output a formatted message using FORMAT on appropriate dump streams. */
327 dump_printf (int dump_kind, const char *format, ...)
329 if (dump_file && (dump_kind & pflags))
332 va_start (ap, format);
333 vfprintf (dump_file, format, ap);
337 if (alt_dump_file && (dump_kind & alt_flags))
340 va_start (ap, format);
341 vfprintf (alt_dump_file, format, ap);
346 /* Similar to dump_printf, except source location is also printed. */
349 dump_printf_loc (int dump_kind, source_location loc, const char *format, ...)
351 if (dump_file && (dump_kind & pflags))
354 dump_loc (dump_kind, dump_file, loc);
355 va_start (ap, format);
356 vfprintf (dump_file, format, ap);
360 if (alt_dump_file && (dump_kind & alt_flags))
363 dump_loc (dump_kind, alt_dump_file, loc);
364 va_start (ap, format);
365 vfprintf (alt_dump_file, format, ap);
370 /* Start a dump for PHASE. Store user-supplied dump flags in
371 *FLAG_PTR. Return the number of streams opened. Set globals
372 DUMP_FILE, and ALT_DUMP_FILE to point to the opened streams, and
373 set dump_flags appropriately for both pass dump stream and opt-info
377 dump_start (int phase, int *flag_ptr)
381 struct dump_file_info *dfi;
383 if (phase == TDI_none || !dump_enabled_p (phase))
386 dfi = get_dump_file_info (phase);
387 name = get_dump_file_name (phase);
390 stream = strcmp("stderr", name) == 0
392 : strcmp("stdout", name) == 0
394 : fopen (name, dfi->pstate < 0 ? "w" : "a");
396 error ("could not open dump file %qs: %m", name);
403 dfi->pstream = stream;
404 dump_file = dfi->pstream;
405 /* Initialize current dump flags. */
406 pflags = dfi->pflags;
409 stream = dump_open_alternate_stream (dfi);
412 dfi->alt_stream = stream;
414 alt_dump_file = dfi->alt_stream;
415 /* Initialize current opt-info flags. */
416 alt_flags = dfi->alt_flags;
420 *flag_ptr = dfi->pflags;
425 /* Finish a tree dump for PHASE and close associated dump streams. Also
426 reset the globals DUMP_FILE, ALT_DUMP_FILE, and DUMP_FLAGS. */
429 dump_finish (int phase)
431 struct dump_file_info *dfi;
435 dfi = get_dump_file_info (phase);
437 fclose (dfi->pstream);
439 if (dfi->alt_stream && strcmp("stderr", dfi->alt_filename) != 0
440 && strcmp("stdout", dfi->alt_filename) != 0)
441 fclose (dfi->alt_stream);
443 dfi->alt_stream = NULL;
446 alt_dump_file = NULL;
447 dump_flags = TDI_none;
452 /* Begin a tree dump for PHASE. Stores any user supplied flag in
453 *FLAG_PTR and returns a stream to write to. If the dump is not
454 enabled, returns NULL.
455 Multiple calls will reopen and append to the dump file. */
458 dump_begin (int phase, int *flag_ptr)
461 struct dump_file_info *dfi;
464 if (phase == TDI_none || !dump_enabled_p (phase))
467 name = get_dump_file_name (phase);
470 dfi = get_dump_file_info (phase);
472 stream = strcmp("stderr", name) == 0
474 : strcmp("stdout", name) == 0
476 : fopen (name, dfi->pstate < 0 ? "w" : "a");
479 error ("could not open dump file %qs: %m", name);
485 *flag_ptr = dfi->pflags;
487 /* Initialize current flags */
488 pflags = dfi->pflags;
492 /* Returns nonzero if dump PHASE is enabled for at least one stream.
493 If PHASE is TDI_tree_all, return nonzero if any dump is enabled for
497 dump_enabled_p (int phase)
499 if (phase == TDI_tree_all)
502 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
503 if (dump_files[i].pstate || dump_files[i].alt_state)
505 for (i = 0; i < extra_dump_files_in_use; i++)
506 if (extra_dump_files[i].pstate || extra_dump_files[i].alt_state)
512 struct dump_file_info *dfi = get_dump_file_info (phase);
513 return dfi->pstate || dfi->alt_state;
517 /* Returns nonzero if tree dump PHASE has been initialized. */
520 dump_initialized_p (int phase)
522 struct dump_file_info *dfi = get_dump_file_info (phase);
523 return dfi->pstate > 0 || dfi->alt_state > 0;
526 /* Returns the switch name of PHASE. */
529 dump_flag_name (int phase)
531 struct dump_file_info *dfi = get_dump_file_info (phase);
535 /* Finish a tree dump for PHASE. STREAM is the stream created by
539 dump_end (int phase ATTRIBUTE_UNUSED, FILE *stream)
541 if (stream != stderr && stream != stdout)
545 /* Enable all tree dumps with FLAGS on FILENAME. Return number of
546 enabled tree dumps. */
549 dump_enable_all (int flags, const char *filename)
551 int ir_dump_type = (flags & (TDF_TREE | TDF_RTL | TDF_IPA));
555 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
557 if ((dump_files[i].pflags & ir_dump_type))
559 const char *old_filename = dump_files[i].pfilename;
560 dump_files[i].pstate = -1;
561 dump_files[i].pflags |= flags;
563 /* Override the existing filename. */
566 dump_files[i].pfilename = xstrdup (filename);
567 /* Since it is a command-line provided file, which is
568 common to all the phases, use it in append mode. */
569 dump_files[i].pstate = 1;
571 if (old_filename && filename != old_filename)
572 free (CONST_CAST (char *, old_filename));
576 for (i = 0; i < extra_dump_files_in_use; i++)
578 if ((extra_dump_files[i].pflags & ir_dump_type))
580 const char *old_filename = extra_dump_files[i].pfilename;
581 extra_dump_files[i].pstate = -1;
582 extra_dump_files[i].pflags |= flags;
584 /* Override the existing filename. */
587 extra_dump_files[i].pfilename = xstrdup (filename);
588 /* Since it is a command-line provided file, which is
589 common to all the phases, use it in append mode. */
590 extra_dump_files[i].pstate = 1;
592 if (old_filename && filename != old_filename)
593 free (CONST_CAST (char *, old_filename));
600 /* Enable opt-info dumps on all IR_DUMP_TYPE passes with FLAGS on
601 FILENAME. Return the number of enabled dumps. */
604 opt_info_enable_all (int ir_dump_type, int flags, const char *filename)
609 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
611 if ((dump_files[i].pflags & ir_dump_type))
613 const char *old_filename = dump_files[i].alt_filename;
614 /* Since this file is shared among different passes, it
615 should be opened in append mode. */
616 dump_files[i].alt_state = 1;
617 dump_files[i].alt_flags |= flags;
619 /* Override the existing filename. */
621 dump_files[i].alt_filename = xstrdup (filename);
622 if (old_filename && filename != old_filename)
623 free (CONST_CAST (char *, old_filename));
627 for (i = 0; i < extra_dump_files_in_use; i++)
629 if ((extra_dump_files[i].pflags & ir_dump_type))
631 const char *old_filename = extra_dump_files[i].alt_filename;
632 /* Since this file is shared among different passes, it
633 should be opened in append mode. */
634 extra_dump_files[i].alt_state = 1;
635 extra_dump_files[i].alt_flags |= flags;
637 /* Override the existing filename. */
639 extra_dump_files[i].alt_filename = xstrdup (filename);
640 if (old_filename && filename != old_filename)
641 free (CONST_CAST (char *, old_filename));
648 /* Parse ARG as a dump switch. Return nonzero if it is, and store the
649 relevant details in the dump_files array. */
652 dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
654 const char *option_value;
658 if (doglob && !dfi->glob)
661 option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
665 if (*option_value && *option_value != '-' && *option_value != '=')
673 const struct dump_option_value_info *option_ptr;
680 end_ptr = strchr (ptr, '-');
681 eq_ptr = strchr (ptr, '=');
683 if (eq_ptr && !end_ptr)
687 end_ptr = ptr + strlen (ptr);
688 length = end_ptr - ptr;
690 for (option_ptr = dump_options; option_ptr->name; option_ptr++)
691 if (strlen (option_ptr->name) == length
692 && !memcmp (option_ptr->name, ptr, length))
694 flags |= option_ptr->value;
700 /* Interpret rest of the argument as a dump filename. This
701 filename overrides other command line filenames. */
703 free (CONST_CAST (char *, dfi->pfilename));
704 dfi->pfilename = xstrdup (ptr + 1);
708 warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
709 length, ptr, dfi->swtch);
715 dfi->pflags |= flags;
717 /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
719 if (dfi->suffix == NULL)
720 dump_enable_all (dfi->pflags, dfi->pfilename);
726 dump_switch_p (const char *arg)
731 for (i = TDI_none + 1; i != TDI_end; i++)
732 any |= dump_switch_p_1 (arg, &dump_files[i], false);
734 /* Don't glob if we got a hit already */
736 for (i = TDI_none + 1; i != TDI_end; i++)
737 any |= dump_switch_p_1 (arg, &dump_files[i], true);
739 for (i = 0; i < extra_dump_files_in_use; i++)
740 any |= dump_switch_p_1 (arg, &extra_dump_files[i], false);
743 for (i = 0; i < extra_dump_files_in_use; i++)
744 any |= dump_switch_p_1 (arg, &extra_dump_files[i], true);
750 /* Parse ARG as a -fopt-info switch and store flags and filename.
751 Return non-zero if it is a recognized switch. */
754 opt_info_switch_p_1 (const char *arg, int *flags, char **filename)
756 const char *option_value;
770 const struct dump_option_value_info *option_ptr;
777 end_ptr = strchr (ptr, '-');
778 eq_ptr = strchr (ptr, '=');
780 if (eq_ptr && !end_ptr)
784 end_ptr = ptr + strlen (ptr);
785 length = end_ptr - ptr;
787 for (option_ptr = opt_info_options; option_ptr->name; option_ptr++)
788 if (strlen (option_ptr->name) == length
789 && !memcmp (option_ptr->name, ptr, length))
791 *flags |= option_ptr->value;
797 /* Interpret rest of the argument as a dump filename. This
798 filename overrides other command line filenames. */
799 *filename = xstrdup (ptr + 1);
803 warning (0, "ignoring unknown option %q.*s in %<-fopt-info=%s%>",
812 /* Return non-zero if ARG is a recognized switch for
813 -fopt-info. Return zero otherwise. */
816 opt_info_switch_p (const char *arg)
821 opt_info_switch_p_1 (arg, &flags, &filename);
824 filename = xstrdup ("stderr");
828 return opt_info_enable_all ((TDF_TREE | TDF_RTL | TDF_IPA), flags, filename);
831 /* Return true if any dumps are enabled for the given MSG_TYPE, false
835 dump_kind_p (int msg_type)
837 if (!current_function_decl)
839 return ((msg_type & pflags) || (msg_type & alt_flags));
842 /* Print basic block on the dump streams. */
845 dump_basic_block (int dump_kind, basic_block bb, int indent)
847 if (dump_file && (dump_kind & pflags))
848 dump_bb (dump_file, bb, indent, TDF_DETAILS);
849 if (alt_dump_file && (dump_kind & alt_flags))
850 dump_bb (alt_dump_file, bb, indent, TDF_DETAILS);
853 /* Print information from the combine pass on dump_file. */
856 print_combine_total_stats (void)
859 dump_combine_total_stats (dump_file);
862 /* Enable RTL dump for all the RTL passes. */
865 enable_rtl_dump_file (void)
867 return dump_enable_all (TDF_RTL | TDF_DETAILS | TDF_BLOCKS, NULL) > 0;