1/* Dump infrastructure for optimizations and intermediate representation.
2 Copyright (C) 2012-2017 Free Software Foundation, Inc.
3
4This file is part of GCC.
5
6GCC is free software; you can redistribute it and/or modify it under
7the terms of the GNU General Public License as published by the Free
8Software Foundation; either version 3, or (at your option) any later
9version.
10
11GCC is distributed in the hope that it will be useful, but WITHOUT ANY
12WARRANTY; without even the implied warranty of MERCHANTABILITY or
13FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14for more details.
15
16You should have received a copy of the GNU General Public License
17along with GCC; see the file COPYING3. If not see
18<http://www.gnu.org/licenses/>. */
19
20#include "config.h"
21#include "system.h"
22#include "coretypes.h"
23#include "options.h"
24#include "tree.h"
25#include "gimple-pretty-print.h"
26#include "diagnostic-core.h"
27#include "dumpfile.h"
28#include "context.h"
29#include "profile-count.h"
30#include "tree-cfg.h"
31#include "langhooks.h"
32
33/* If non-NULL, return one past-the-end of the matching SUBPART of
34 the WHOLE string. */
35#define skip_leading_substring(whole, part) \
36 (strncmp (whole, part, strlen (part)) ? NULL : whole + strlen (part))
37
38static dump_flags_t pflags; /* current dump_flags */
39static dump_flags_t alt_flags; /* current opt_info flags */
40
41static void dump_loc (dump_flags_t, FILE *, source_location);
42static FILE *dump_open_alternate_stream (struct dump_file_info *);
43
44/* These are currently used for communicating between passes.
45 However, instead of accessing them directly, the passes can use
46 dump_printf () for dumps. */
47FILE *dump_file = NULL;
48FILE *alt_dump_file = NULL;
49const char *dump_file_name;
50dump_flags_t dump_flags;
51
52#define DUMP_FILE_INFO(suffix, swtch, dkind, num) \
53 {suffix, swtch, NULL, NULL, NULL, NULL, NULL, dkind, 0, 0, 0, 0, 0, num, \
54 false, false}
55
56/* Table of tree dump switches. This must be consistent with the
57 TREE_DUMP_INDEX enumeration in dumpfile.h. */
58static struct dump_file_info dump_files[TDI_end] =
59{
60 DUMP_FILE_INFO (NULL, NULL, DK_none, 0),
61 DUMP_FILE_INFO (".cgraph", "ipa-cgraph", DK_ipa, 0),
62 DUMP_FILE_INFO (".type-inheritance", "ipa-type-inheritance", DK_ipa, 0),
63 DUMP_FILE_INFO (".ipa-clones", "ipa-clones", DK_ipa, 0),
64 DUMP_FILE_INFO (".original", "tree-original", DK_tree, 0),
65 DUMP_FILE_INFO (".gimple", "tree-gimple", DK_tree, 0),
66 DUMP_FILE_INFO (".nested", "tree-nested", DK_tree, 0),
67#define FIRST_AUTO_NUMBERED_DUMP 1
68#define FIRST_ME_AUTO_NUMBERED_DUMP 3
69
70 DUMP_FILE_INFO (NULL, "lang-all", DK_lang, 0),
71 DUMP_FILE_INFO (NULL, "tree-all", DK_tree, 0),
72 DUMP_FILE_INFO (NULL, "rtl-all", DK_rtl, 0),
73 DUMP_FILE_INFO (NULL, "ipa-all", DK_ipa, 0),
74};
75
76/* Define a name->number mapping for a dump flag value. */
77struct dump_option_value_info
78{
79 const char *const name; /* the name of the value */
80 const dump_flags_t value; /* the value of the name */
81};
82
83/* Table of dump options. This must be consistent with the TDF_* flags
84 in dumpfile.h and opt_info_options below. */
85static const struct dump_option_value_info dump_options[] =
86{
87 {"address", TDF_ADDRESS},
88 {"asmname", TDF_ASMNAME},
89 {"slim", TDF_SLIM},
90 {"raw", TDF_RAW},
91 {"graph", TDF_GRAPH},
92 {"details", (TDF_DETAILS | MSG_OPTIMIZED_LOCATIONS
93 | MSG_MISSED_OPTIMIZATION
94 | MSG_NOTE)},
95 {"cselib", TDF_CSELIB},
96 {"stats", TDF_STATS},
97 {"blocks", TDF_BLOCKS},
98 {"vops", TDF_VOPS},
99 {"lineno", TDF_LINENO},
100 {"uid", TDF_UID},
101 {"stmtaddr", TDF_STMTADDR},
102 {"memsyms", TDF_MEMSYMS},
103 {"eh", TDF_EH},
104 {"alias", TDF_ALIAS},
105 {"nouid", TDF_NOUID},
106 {"enumerate_locals", TDF_ENUMERATE_LOCALS},
107 {"scev", TDF_SCEV},
108 {"gimple", TDF_GIMPLE},
109 {"folding", TDF_FOLDING},
110 {"optimized", MSG_OPTIMIZED_LOCATIONS},
111 {"missed", MSG_MISSED_OPTIMIZATION},
112 {"note", MSG_NOTE},
113 {"optall", MSG_ALL},
114 {"all", dump_flags_t (~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_GRAPH
115 | TDF_STMTADDR | TDF_RHS_ONLY | TDF_NOUID
116 | TDF_ENUMERATE_LOCALS | TDF_SCEV | TDF_GIMPLE))},
117 {NULL, 0}
118};
119
120/* A subset of the dump_options table which is used for -fopt-info
121 types. This must be consistent with the MSG_* flags in dumpfile.h.
122 */
123static const struct dump_option_value_info optinfo_verbosity_options[] =
124{
125 {"optimized", MSG_OPTIMIZED_LOCATIONS},
126 {"missed", MSG_MISSED_OPTIMIZATION},
127 {"note", MSG_NOTE},
128 {"all", MSG_ALL},
129 {NULL, 0}
130};
131
132/* Flags used for -fopt-info groups. */
133static const struct dump_option_value_info optgroup_options[] =
134{
135 {"ipa", OPTGROUP_IPA},
136 {"loop", OPTGROUP_LOOP},
137 {"inline", OPTGROUP_INLINE},
138 {"omp", OPTGROUP_OMP},
139 {"vec", OPTGROUP_VEC},
140 {"optall", OPTGROUP_ALL},
141 {NULL, 0}
142};
143
144gcc::dump_manager::dump_manager ():
145 m_next_dump (FIRST_AUTO_NUMBERED_DUMP),
146 m_extra_dump_files (NULL),
147 m_extra_dump_files_in_use (0),
148 m_extra_dump_files_alloced (0)
149{
150}
151
152gcc::dump_manager::~dump_manager ()
153{
154 for (size_t i = 0; i < m_extra_dump_files_in_use; i++)
155 {
156 dump_file_info *dfi = &m_extra_dump_files[i];
157 /* suffix, swtch, glob are statically allocated for the entries
158 in dump_files, and for statistics, but are dynamically allocated
159 for those for passes. */
160 if (dfi->owns_strings)
161 {
162 XDELETEVEC (const_cast <char *> (dfi->suffix));
163 XDELETEVEC (const_cast <char *> (dfi->swtch));
164 XDELETEVEC (const_cast <char *> (dfi->glob));
165 }
166 /* These, if non-NULL, are always dynamically allocated. */
167 XDELETEVEC (const_cast <char *> (dfi->pfilename));
168 XDELETEVEC (const_cast <char *> (dfi->alt_filename));
169 }
170 XDELETEVEC (m_extra_dump_files);
171}
172
173unsigned int
174gcc::dump_manager::
175dump_register (const char *suffix, const char *swtch, const char *glob,
176 dump_kind dkind, int optgroup_flags, bool take_ownership)
177{
178 int num = m_next_dump++;
179
180 size_t count = m_extra_dump_files_in_use++;
181
182 if (count >= m_extra_dump_files_alloced)
183 {
184 if (m_extra_dump_files_alloced == 0)
185 m_extra_dump_files_alloced = 512;
186 else
187 m_extra_dump_files_alloced *= 2;
188 m_extra_dump_files = XRESIZEVEC (struct dump_file_info,
189 m_extra_dump_files,
190 m_extra_dump_files_alloced);
191
192 /* Construct a new object in the space allocated above. */
193 new (m_extra_dump_files + count) dump_file_info ();
194 }
195 else
196 {
197 /* Zero out the already constructed object. */
198 m_extra_dump_files[count] = dump_file_info ();
199 }
200
201 m_extra_dump_files[count].suffix = suffix;
202 m_extra_dump_files[count].swtch = swtch;
203 m_extra_dump_files[count].glob = glob;
204 m_extra_dump_files[count].dkind = dkind;
205 m_extra_dump_files[count].optgroup_flags = optgroup_flags;
206 m_extra_dump_files[count].num = num;
207 m_extra_dump_files[count].owns_strings = take_ownership;
208
209 return count + TDI_end;
210}
211
212
213/* Allow languages and middle-end to register their dumps before the
214 optimization passes. */
215
216void
217gcc::dump_manager::
218register_dumps ()
219{
220 lang_hooks.register_dumps (this);
221 /* If this assert fails, some FE registered more than
222 FIRST_ME_AUTO_NUMBERED_DUMP - FIRST_AUTO_NUMBERED_DUMP
223 dump files. Bump FIRST_ME_AUTO_NUMBERED_DUMP accordingly. */
224 gcc_assert (m_next_dump <= FIRST_ME_AUTO_NUMBERED_DUMP);
225 m_next_dump = FIRST_ME_AUTO_NUMBERED_DUMP;
226 dump_files[TDI_original].num = m_next_dump++;
227 dump_files[TDI_gimple].num = m_next_dump++;
228 dump_files[TDI_nested].num = m_next_dump++;
229}
230
231
232/* Return the dump_file_info for the given phase. */
233
234struct dump_file_info *
235gcc::dump_manager::
236get_dump_file_info (int phase) const
237{
238 if (phase < TDI_end)
239 return &dump_files[phase];
240 else if ((size_t) (phase - TDI_end) >= m_extra_dump_files_in_use)
241 return NULL;
242 else
243 return m_extra_dump_files + (phase - TDI_end);
244}
245
246/* Locate the dump_file_info with swtch equal to SWTCH,
247 or return NULL if no such dump_file_info exists. */
248
249struct dump_file_info *
250gcc::dump_manager::
251get_dump_file_info_by_switch (const char *swtch) const
252{
253 for (unsigned i = 0; i < m_extra_dump_files_in_use; i++)
254 if (0 == strcmp (m_extra_dump_files[i].swtch, swtch))
255 return &m_extra_dump_files[i];
256
257 /* Not found. */
258 return NULL;
259}
260
261
262/* Return the name of the dump file for the given phase.
263 The caller is responsible for calling free on the returned
264 buffer.
265 If the dump is not enabled, returns NULL. */
266
267char *
268gcc::dump_manager::
269get_dump_file_name (int phase) const
270{
271 struct dump_file_info *dfi;
272
273 if (phase == TDI_none)
274 return NULL;
275
276 dfi = get_dump_file_info (phase);
277
278 return get_dump_file_name (dfi);
279}
280
281/* Return the name of the dump file for the given dump_file_info.
282 The caller is responsible for calling free on the returned
283 buffer.
284 If the dump is not enabled, returns NULL. */
285
286char *
287gcc::dump_manager::
288get_dump_file_name (struct dump_file_info *dfi) const
289{
290 char dump_id[10];
291
292 gcc_assert (dfi);
293
294 if (dfi->pstate == 0)
295 return NULL;
296
297 /* If available, use the command line dump filename. */
298 if (dfi->pfilename)
299 return xstrdup (dfi->pfilename);
300
301 if (dfi->num < 0)
302 dump_id[0] = '\0';
303 else
304 {
305 /* (null), LANG, TREE, RTL, IPA. */
306 char suffix = " ltri"[dfi->dkind];
307
308 if (snprintf (dump_id, sizeof (dump_id), ".%03d%c", dfi->num, suffix) < 0)
309 dump_id[0] = '\0';
310 }
311
312 return concat (dump_base_name, dump_id, dfi->suffix, NULL);
313}
314
315/* For a given DFI, open an alternate dump filename (which could also
316 be a standard stream such as stdout/stderr). If the alternate dump
317 file cannot be opened, return NULL. */
318
319static FILE *
320dump_open_alternate_stream (struct dump_file_info *dfi)
321{
322 FILE *stream ;
323 if (!dfi->alt_filename)
324 return NULL;
325
326 if (dfi->alt_stream)
327 return dfi->alt_stream;
328
329 stream = strcmp ("stderr", dfi->alt_filename) == 0
330 ? stderr
331 : strcmp ("stdout", dfi->alt_filename) == 0
332 ? stdout
333 : fopen (dfi->alt_filename, dfi->alt_state < 0 ? "w" : "a");
334
335 if (!stream)
336 error ("could not open dump file %qs: %m", dfi->alt_filename);
337 else
338 dfi->alt_state = 1;
339
340 return stream;
341}
342
343/* Print source location on DFILE if enabled. */
344
345void
346dump_loc (dump_flags_t dump_kind, FILE *dfile, source_location loc)
347{
348 if (dump_kind)
349 {
350 if (LOCATION_LOCUS (loc) > BUILTINS_LOCATION)
351 fprintf (dfile, "%s:%d:%d: note: ", LOCATION_FILE (loc),
352 LOCATION_LINE (loc), LOCATION_COLUMN (loc));
353 else if (current_function_decl)
354 fprintf (dfile, "%s:%d:%d: note: ",
355 DECL_SOURCE_FILE (current_function_decl),
356 DECL_SOURCE_LINE (current_function_decl),
357 DECL_SOURCE_COLUMN (current_function_decl));
358 }
359}
360
361/* Dump gimple statement GS with SPC indentation spaces and
362 EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled. */
363
364void
365dump_gimple_stmt (dump_flags_t dump_kind, dump_flags_t extra_dump_flags,
366 gimple *gs, int spc)
367{
368 if (dump_file && (dump_kind & pflags))
369 print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
370
371 if (alt_dump_file && (dump_kind & alt_flags))
372 print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
373}
374
375/* Similar to dump_gimple_stmt, except additionally print source location. */
376
377void
378dump_gimple_stmt_loc (dump_flags_t dump_kind, source_location loc,
379 dump_flags_t extra_dump_flags, gimple *gs, int spc)
380{
381 if (dump_file && (dump_kind & pflags))
382 {
383 dump_loc (dump_kind, dump_file, loc);
384 print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
385 }
386
387 if (alt_dump_file && (dump_kind & alt_flags))
388 {
389 dump_loc (dump_kind, alt_dump_file, loc);
390 print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
391 }
392}
393
394/* Dump expression tree T using EXTRA_DUMP_FLAGS on dump streams if
395 DUMP_KIND is enabled. */
396
397void
398dump_generic_expr (dump_flags_t dump_kind, dump_flags_t extra_dump_flags,
399 tree t)
400{
401 if (dump_file && (dump_kind & pflags))
402 print_generic_expr (dump_file, t, dump_flags | extra_dump_flags);
403
404 if (alt_dump_file && (dump_kind & alt_flags))
405 print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags);
406}
407
408
409/* Similar to dump_generic_expr, except additionally print the source
410 location. */
411
412void
413dump_generic_expr_loc (int dump_kind, source_location loc,
414 dump_flags_t extra_dump_flags, tree t)
415{
416 if (dump_file && (dump_kind & pflags))
417 {
418 dump_loc (dump_kind, dump_file, loc);
419 print_generic_expr (dump_file, t, dump_flags | extra_dump_flags);
420 }
421
422 if (alt_dump_file && (dump_kind & alt_flags))
423 {
424 dump_loc (dump_kind, alt_dump_file, loc);
425 print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags);
426 }
427}
428
429/* Output a formatted message using FORMAT on appropriate dump streams. */
430
431void
432dump_printf (dump_flags_t dump_kind, const char *format, ...)
433{
434 if (dump_file && (dump_kind & pflags))
435 {
436 va_list ap;
437 va_start (ap, format);
438 vfprintf (dump_file, format, ap);
439 va_end (ap);
440 }
441
442 if (alt_dump_file && (dump_kind & alt_flags))
443 {
444 va_list ap;
445 va_start (ap, format);
446 vfprintf (alt_dump_file, format, ap);
447 va_end (ap);
448 }
449}
450
451/* Similar to dump_printf, except source location is also printed. */
452
453void
454dump_printf_loc (dump_flags_t dump_kind, source_location loc,
455 const char *format, ...)
456{
457 if (dump_file && (dump_kind & pflags))
458 {
459 va_list ap;
460 dump_loc (dump_kind, dump_file, loc);
461 va_start (ap, format);
462 vfprintf (dump_file, format, ap);
463 va_end (ap);
464 }
465
466 if (alt_dump_file && (dump_kind & alt_flags))
467 {
468 va_list ap;
469 dump_loc (dump_kind, alt_dump_file, loc);
470 va_start (ap, format);
471 vfprintf (alt_dump_file, format, ap);
472 va_end (ap);
473 }
474}
475
476/* Start a dump for PHASE. Store user-supplied dump flags in
477 *FLAG_PTR. Return the number of streams opened. Set globals
478 DUMP_FILE, and ALT_DUMP_FILE to point to the opened streams, and
479 set dump_flags appropriately for both pass dump stream and
480 -fopt-info stream. */
481
482int
483gcc::dump_manager::
484dump_start (int phase, dump_flags_t *flag_ptr)
485{
486 int count = 0;
487 char *name;
488 struct dump_file_info *dfi;
489 FILE *stream;
490 if (phase == TDI_none || !dump_phase_enabled_p (phase))
491 return 0;
492
493 dfi = get_dump_file_info (phase);
494 name = get_dump_file_name (phase);
495 if (name)
496 {
497 stream = strcmp ("stderr", name) == 0
498 ? stderr
499 : strcmp ("stdout", name) == 0
500 ? stdout
501 : fopen (name, dfi->pstate < 0 ? "w" : "a");
502 if (!stream)
503 error ("could not open dump file %qs: %m", name);
504 else
505 {
506 dfi->pstate = 1;
507 count++;
508 }
509 free (name);
510 dfi->pstream = stream;
511 dump_file = dfi->pstream;
512 /* Initialize current dump flags. */
513 pflags = dfi->pflags;
514 }
515
516 stream = dump_open_alternate_stream (dfi);
517 if (stream)
518 {
519 dfi->alt_stream = stream;
520 count++;
521 alt_dump_file = dfi->alt_stream;
522 /* Initialize current -fopt-info flags. */
523 alt_flags = dfi->alt_flags;
524 }
525
526 if (flag_ptr)
527 *flag_ptr = dfi->pflags;
528
529 return count;
530}
531
532/* Finish a tree dump for PHASE and close associated dump streams. Also
533 reset the globals DUMP_FILE, ALT_DUMP_FILE, and DUMP_FLAGS. */
534
535void
536gcc::dump_manager::
537dump_finish (int phase)
538{
539 struct dump_file_info *dfi;
540
541 if (phase < 0)
542 return;
543 dfi = get_dump_file_info (phase);
544 if (dfi->pstream && (!dfi->pfilename
545 || (strcmp ("stderr", dfi->pfilename) != 0
546 && strcmp ("stdout", dfi->pfilename) != 0)))
547 fclose (dfi->pstream);
548
549 if (dfi->alt_stream && strcmp ("stderr", dfi->alt_filename) != 0
550 && strcmp ("stdout", dfi->alt_filename) != 0)
551 fclose (dfi->alt_stream);
552
553 dfi->alt_stream = NULL;
554 dfi->pstream = NULL;
555 dump_file = NULL;
556 alt_dump_file = NULL;
557 dump_flags = TDI_none;
558 alt_flags = 0;
559 pflags = 0;
560}
561
562/* Begin a tree dump for PHASE. Stores any user supplied flag in
563 *FLAG_PTR and returns a stream to write to. If the dump is not
564 enabled, returns NULL.
565 Multiple calls will reopen and append to the dump file. */
566
567FILE *
568dump_begin (int phase, dump_flags_t *flag_ptr)
569{
570 return g->get_dumps ()->dump_begin (phase, flag_ptr);
571}
572
573FILE *
574gcc::dump_manager::
575dump_begin (int phase, dump_flags_t *flag_ptr)
576{
577 char *name;
578 struct dump_file_info *dfi;
579 FILE *stream;
580
581 if (phase == TDI_none || !dump_phase_enabled_p (phase))
582 return NULL;
583
584 name = get_dump_file_name (phase);
585 if (!name)
586 return NULL;
587 dfi = get_dump_file_info (phase);
588
589 stream = strcmp ("stderr", name) == 0
590 ? stderr
591 : strcmp ("stdout", name) == 0
592 ? stdout
593 : fopen (name, dfi->pstate < 0 ? "w" : "a");
594
595 if (!stream)
596 error ("could not open dump file %qs: %m", name);
597 else
598 dfi->pstate = 1;
599 free (name);
600
601 if (flag_ptr)
602 *flag_ptr = dfi->pflags;
603
604 /* Initialize current flags */
605 pflags = dfi->pflags;
606 return stream;
607}
608
609/* Returns nonzero if dump PHASE is enabled for at least one stream.
610 If PHASE is TDI_tree_all, return nonzero if any dump is enabled for
611 any phase. */
612
613int
614gcc::dump_manager::
615dump_phase_enabled_p (int phase) const
616{
617 if (phase == TDI_tree_all)
618 {
619 size_t i;
620 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
621 if (dump_files[i].pstate || dump_files[i].alt_state)
622 return 1;
623 for (i = 0; i < m_extra_dump_files_in_use; i++)
624 if (m_extra_dump_files[i].pstate || m_extra_dump_files[i].alt_state)
625 return 1;
626 return 0;
627 }
628 else
629 {
630 struct dump_file_info *dfi = get_dump_file_info (phase);
631 return dfi->pstate || dfi->alt_state;
632 }
633}
634
635/* Returns nonzero if tree dump PHASE has been initialized. */
636
637int
638gcc::dump_manager::
639dump_initialized_p (int phase) const
640{
641 struct dump_file_info *dfi = get_dump_file_info (phase);
642 return dfi->pstate > 0 || dfi->alt_state > 0;
643}
644
645/* Returns the switch name of PHASE. */
646
647const char *
648dump_flag_name (int phase)
649{
650 return g->get_dumps ()->dump_flag_name (phase);
651}
652
653const char *
654gcc::dump_manager::
655dump_flag_name (int phase) const
656{
657 struct dump_file_info *dfi = get_dump_file_info (phase);
658 return dfi->swtch;
659}
660
661/* Finish a tree dump for PHASE. STREAM is the stream created by
662 dump_begin. */
663
664void
665dump_end (int phase ATTRIBUTE_UNUSED, FILE *stream)
666{
667 if (stream != stderr && stream != stdout)
668 fclose (stream);
669}
670
671/* Enable all tree dumps with FLAGS on FILENAME. Return number of
672 enabled tree dumps. */
673
674int
675gcc::dump_manager::
676dump_enable_all (dump_kind dkind, dump_flags_t flags, const char *filename)
677{
678 int n = 0;
679 size_t i;
680
681 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
682 {
683 if ((dump_files[i].dkind == dkind))
684 {
685 const char *old_filename = dump_files[i].pfilename;
686 dump_files[i].pstate = -1;
687 dump_files[i].pflags |= flags;
688 n++;
689 /* Override the existing filename. */
690 if (filename)
691 {
692 dump_files[i].pfilename = xstrdup (filename);
693 /* Since it is a command-line provided file, which is
694 common to all the phases, use it in append mode. */
695 dump_files[i].pstate = 1;
696 }
697 if (old_filename && filename != old_filename)
698 free (CONST_CAST (char *, old_filename));
699 }
700 }
701
702 for (i = 0; i < m_extra_dump_files_in_use; i++)
703 {
704 if ((m_extra_dump_files[i].dkind == dkind))
705 {
706 const char *old_filename = m_extra_dump_files[i].pfilename;
707 m_extra_dump_files[i].pstate = -1;
708 m_extra_dump_files[i].pflags |= flags;
709 n++;
710 /* Override the existing filename. */
711 if (filename)
712 {
713 m_extra_dump_files[i].pfilename = xstrdup (filename);
714 /* Since it is a command-line provided file, which is
715 common to all the phases, use it in append mode. */
716 m_extra_dump_files[i].pstate = 1;
717 }
718 if (old_filename && filename != old_filename)
719 free (CONST_CAST (char *, old_filename));
720 }
721 }
722
723 return n;
724}
725
726/* Enable -fopt-info dumps on all dump files matching OPTGROUP_FLAGS.
727 Enable dumps with FLAGS on FILENAME. Return the number of enabled
728 dumps. */
729
730int
731gcc::dump_manager::
732opt_info_enable_passes (int optgroup_flags, dump_flags_t flags,
733 const char *filename)
734{
735 int n = 0;
736 size_t i;
737
738 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
739 {
740 if ((dump_files[i].optgroup_flags & optgroup_flags))
741 {
742 const char *old_filename = dump_files[i].alt_filename;
743 /* Since this file is shared among different passes, it
744 should be opened in append mode. */
745 dump_files[i].alt_state = 1;
746 dump_files[i].alt_flags |= flags;
747 n++;
748 /* Override the existing filename. */
749 if (filename)
750 dump_files[i].alt_filename = xstrdup (filename);
751 if (old_filename && filename != old_filename)
752 free (CONST_CAST (char *, old_filename));
753 }
754 }
755
756 for (i = 0; i < m_extra_dump_files_in_use; i++)
757 {
758 if ((m_extra_dump_files[i].optgroup_flags & optgroup_flags))
759 {
760 const char *old_filename = m_extra_dump_files[i].alt_filename;
761 /* Since this file is shared among different passes, it
762 should be opened in append mode. */
763 m_extra_dump_files[i].alt_state = 1;
764 m_extra_dump_files[i].alt_flags |= flags;
765 n++;
766 /* Override the existing filename. */
767 if (filename)
768 m_extra_dump_files[i].alt_filename = xstrdup (filename);
769 if (old_filename && filename != old_filename)
770 free (CONST_CAST (char *, old_filename));
771 }
772 }
773
774 return n;
775}
776
777/* Parse ARG as a dump switch. Return nonzero if it is, and store the
778 relevant details in the dump_files array. */
779
780int
781gcc::dump_manager::
782dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
783{
784 const char *option_value;
785 const char *ptr;
786 dump_flags_t flags;
787
788 if (doglob && !dfi->glob)
789 return 0;
790
791 option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
792 if (!option_value)
793 return 0;
794
795 if (*option_value && *option_value != '-' && *option_value != '=')
796 return 0;
797
798 ptr = option_value;
799 flags = 0;
800
801 while (*ptr)
802 {
803 const struct dump_option_value_info *option_ptr;
804 const char *end_ptr;
805 const char *eq_ptr;
806 unsigned length;
807
808 while (*ptr == '-')
809 ptr++;
810 end_ptr = strchr (ptr, '-');
811 eq_ptr = strchr (ptr, '=');
812
813 if (eq_ptr && !end_ptr)
814 end_ptr = eq_ptr;
815
816 if (!end_ptr)
817 end_ptr = ptr + strlen (ptr);
818 length = end_ptr - ptr;
819
820 for (option_ptr = dump_options; option_ptr->name; option_ptr++)
821 if (strlen (option_ptr->name) == length
822 && !memcmp (option_ptr->name, ptr, length))
823 {
824 flags |= option_ptr->value;
825 goto found;
826 }
827
828 if (*ptr == '=')
829 {
830 /* Interpret rest of the argument as a dump filename. This
831 filename overrides other command line filenames. */
832 if (dfi->pfilename)
833 free (CONST_CAST (char *, dfi->pfilename));
834 dfi->pfilename = xstrdup (ptr + 1);
835 break;
836 }
837 else
838 warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
839 length, ptr, dfi->swtch);
840 found:;
841 ptr = end_ptr;
842 }
843
844 dfi->pstate = -1;
845 dfi->pflags |= flags;
846
847 /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
848 known dumps. */
849 if (dfi->suffix == NULL)
850 dump_enable_all (dfi->dkind, dfi->pflags, dfi->pfilename);
851
852 return 1;
853}
854
855int
856gcc::dump_manager::
857dump_switch_p (const char *arg)
858{
859 size_t i;
860 int any = 0;
861
862 for (i = TDI_none + 1; i != TDI_end; i++)
863 any |= dump_switch_p_1 (arg, &dump_files[i], false);
864
865 /* Don't glob if we got a hit already */
866 if (!any)
867 for (i = TDI_none + 1; i != TDI_end; i++)
868 any |= dump_switch_p_1 (arg, &dump_files[i], true);
869
870 for (i = 0; i < m_extra_dump_files_in_use; i++)
871 any |= dump_switch_p_1 (arg, &m_extra_dump_files[i], false);
872
873 if (!any)
874 for (i = 0; i < m_extra_dump_files_in_use; i++)
875 any |= dump_switch_p_1 (arg, &m_extra_dump_files[i], true);
876
877
878 return any;
879}
880
881/* Parse ARG as a -fopt-info switch and store flags, optgroup_flags
882 and filename. Return non-zero if it is a recognized switch. */
883
884static int
885opt_info_switch_p_1 (const char *arg, dump_flags_t *flags, int *optgroup_flags,
886 char **filename)
887{
888 const char *option_value;
889 const char *ptr;
890
891 option_value = arg;
892 ptr = option_value;
893
894 *filename = NULL;
895 *flags = 0;
896 *optgroup_flags = 0;
897
898 if (!ptr)
899 return 1; /* Handle '-fopt-info' without any additional options. */
900
901 while (*ptr)
902 {
903 const struct dump_option_value_info *option_ptr;
904 const char *end_ptr;
905 const char *eq_ptr;
906 unsigned length;
907
908 while (*ptr == '-')
909 ptr++;
910 end_ptr = strchr (ptr, '-');
911 eq_ptr = strchr (ptr, '=');
912
913 if (eq_ptr && !end_ptr)
914 end_ptr = eq_ptr;
915
916 if (!end_ptr)
917 end_ptr = ptr + strlen (ptr);
918 length = end_ptr - ptr;
919
920 for (option_ptr = optinfo_verbosity_options; option_ptr->name;
921 option_ptr++)
922 if (strlen (option_ptr->name) == length
923 && !memcmp (option_ptr->name, ptr, length))
924 {
925 *flags |= option_ptr->value;
926 goto found;
927 }
928
929 for (option_ptr = optgroup_options; option_ptr->name; option_ptr++)
930 if (strlen (option_ptr->name) == length
931 && !memcmp (option_ptr->name, ptr, length))
932 {
933 *optgroup_flags |= option_ptr->value;
934 goto found;
935 }
936
937 if (*ptr == '=')
938 {
939 /* Interpret rest of the argument as a dump filename. This
940 filename overrides other command line filenames. */
941 *filename = xstrdup (ptr + 1);
942 break;
943 }
944 else
945 {
946 warning (0, "unknown option %q.*s in %<-fopt-info-%s%>",
947 length, ptr, arg);
948 return 0;
949 }
950 found:;
951 ptr = end_ptr;
952 }
953
954 return 1;
955}
956
957/* Return non-zero if ARG is a recognized switch for
958 -fopt-info. Return zero otherwise. */
959
960int
961opt_info_switch_p (const char *arg)
962{
963 dump_flags_t flags;
964 int optgroup_flags;
965 char *filename;
966 static char *file_seen = NULL;
967 gcc::dump_manager *dumps = g->get_dumps ();
968
969 if (!opt_info_switch_p_1 (arg, &flags, &optgroup_flags, &filename))
970 return 0;
971
972 if (!filename)
973 filename = xstrdup ("stderr");
974
975 /* Bail out if a different filename has been specified. */
976 if (file_seen && strcmp (file_seen, filename))
977 {
978 warning (0, "ignoring possibly conflicting option %<-fopt-info-%s%>",
979 arg);
980 return 1;
981 }
982
983 file_seen = xstrdup (filename);
984 if (!flags)
985 flags = MSG_OPTIMIZED_LOCATIONS;
986 if (!optgroup_flags)
987 optgroup_flags = OPTGROUP_ALL;
988
989 return dumps->opt_info_enable_passes (optgroup_flags, flags, filename);
990}
991
992/* Print basic block on the dump streams. */
993
994void
995dump_basic_block (int dump_kind, basic_block bb, int indent)
996{
997 if (dump_file && (dump_kind & pflags))
998 dump_bb (dump_file, bb, indent, TDF_DETAILS);
999 if (alt_dump_file && (dump_kind & alt_flags))
1000 dump_bb (alt_dump_file, bb, indent, TDF_DETAILS);
1001}
1002
1003/* Dump FUNCTION_DECL FN as tree dump PHASE. */
1004
1005void
1006dump_function (int phase, tree fn)
1007{
1008 FILE *stream;
1009 dump_flags_t flags;
1010
1011 stream = dump_begin (phase, &flags);
1012 if (stream)
1013 {
1014 dump_function_to_file (fn, stream, flags);
1015 dump_end (phase, stream);
1016 }
1017}
1018
1019/* Print information from the combine pass on dump_file. */
1020
1021void
1022print_combine_total_stats (void)
1023{
1024 if (dump_file)
1025 dump_combine_total_stats (dump_file);
1026}
1027
1028/* Enable RTL dump for all the RTL passes. */
1029
1030bool
1031enable_rtl_dump_file (void)
1032{
1033 gcc::dump_manager *dumps = g->get_dumps ();
1034 int num_enabled =
1035 dumps->dump_enable_all (DK_rtl, dump_flags_t (TDF_DETAILS) | TDF_BLOCKS,
1036 NULL);
1037 return num_enabled > 0;
1038}
1039