]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/dumpfile.c
Update copyright years.
[thirdparty/gcc.git] / gcc / dumpfile.c
CommitLineData
b5f47924 1/* Dump infrastructure for optimizations and intermediate representation.
85ec4feb 2 Copyright (C) 2012-2018 Free Software Foundation, Inc.
b5f47924
SS
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"
957060b5
AM
23#include "options.h"
24#include "tree.h"
25#include "gimple-pretty-print.h"
b5f47924
SS
26#include "diagnostic-core.h"
27#include "dumpfile.h"
47e0da37 28#include "context.h"
0de11d4d 29#include "profile-count.h"
c24e924f 30#include "tree-cfg.h"
363dc72c 31#include "langhooks.h"
b5f47924
SS
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
1a817418
ML
38static dump_flags_t pflags; /* current dump_flags */
39static dump_flags_t alt_flags; /* current opt_info flags */
b5f47924 40
1a817418 41static void dump_loc (dump_flags_t, FILE *, source_location);
b5f47924
SS
42static FILE *dump_open_alternate_stream (struct dump_file_info *);
43
73fbfcad
SS
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;
1a817418 50dump_flags_t dump_flags;
73fbfcad 51
63523736
ML
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}
8264c84d 55
b5f47924
SS
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{
63523736
ML
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),
363dc72c
JJ
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
b5f47924 69
63523736
ML
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),
b5f47924
SS
74};
75
b5f47924
SS
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 */
1a817418 80 const dump_flags_t value; /* the value of the name */
b5f47924
SS
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},
b5f47924
SS
103 {"eh", TDF_EH},
104 {"alias", TDF_ALIAS},
105 {"nouid", TDF_NOUID},
106 {"enumerate_locals", TDF_ENUMERATE_LOCALS},
107 {"scev", TDF_SCEV},
1ee62b92 108 {"gimple", TDF_GIMPLE},
56af751e 109 {"folding", TDF_FOLDING},
f14726bd
TJ
110 {"optimized", MSG_OPTIMIZED_LOCATIONS},
111 {"missed", MSG_MISSED_OPTIMIZATION},
112 {"note", MSG_NOTE},
113 {"optall", MSG_ALL},
f6b3ca5a
JJ
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))},
b5f47924
SS
117 {NULL, 0}
118};
119
2b4e6bf1
SS
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.
b5f47924 122 */
2b4e6bf1 123static const struct dump_option_value_info optinfo_verbosity_options[] =
b5f47924
SS
124{
125 {"optimized", MSG_OPTIMIZED_LOCATIONS},
126 {"missed", MSG_MISSED_OPTIMIZATION},
127 {"note", MSG_NOTE},
2b4e6bf1
SS
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},
fd2b8c8b 138 {"omp", OPTGROUP_OMP},
2b4e6bf1
SS
139 {"vec", OPTGROUP_VEC},
140 {"optall", OPTGROUP_ALL},
b5f47924
SS
141 {NULL, 0}
142};
143
47e0da37
DM
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
10fdd6e9
DM
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
b5f47924 173unsigned int
47e0da37 174gcc::dump_manager::
b5f47924 175dump_register (const char *suffix, const char *swtch, const char *glob,
8264c84d 176 dump_kind dkind, int optgroup_flags, bool take_ownership)
b5f47924 177{
47e0da37 178 int num = m_next_dump++;
b5f47924 179
47e0da37 180 size_t count = m_extra_dump_files_in_use++;
b5f47924 181
47e0da37 182 if (count >= m_extra_dump_files_alloced)
b5f47924 183 {
47e0da37 184 if (m_extra_dump_files_alloced == 0)
363dc72c 185 m_extra_dump_files_alloced = 512;
b5f47924 186 else
47e0da37
DM
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);
c3684b7b
MS
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 ();
b5f47924
SS
199 }
200
47e0da37
DM
201 m_extra_dump_files[count].suffix = suffix;
202 m_extra_dump_files[count].swtch = swtch;
203 m_extra_dump_files[count].glob = glob;
8264c84d 204 m_extra_dump_files[count].dkind = dkind;
47e0da37
DM
205 m_extra_dump_files[count].optgroup_flags = optgroup_flags;
206 m_extra_dump_files[count].num = num;
10fdd6e9 207 m_extra_dump_files[count].owns_strings = take_ownership;
b5f47924
SS
208
209 return count + TDI_end;
210}
211
212
363dc72c
JJ
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
b5f47924
SS
232/* Return the dump_file_info for the given phase. */
233
234struct dump_file_info *
47e0da37
DM
235gcc::dump_manager::
236get_dump_file_info (int phase) const
b5f47924
SS
237{
238 if (phase < TDI_end)
239 return &dump_files[phase];
47e0da37 240 else if ((size_t) (phase - TDI_end) >= m_extra_dump_files_in_use)
b5f47924
SS
241 return NULL;
242 else
47e0da37 243 return m_extra_dump_files + (phase - TDI_end);
b5f47924
SS
244}
245
799505ae
DM
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++)
01512446 254 if (strcmp (m_extra_dump_files[i].swtch, swtch) == 0)
799505ae
DM
255 return &m_extra_dump_files[i];
256
257 /* Not found. */
258 return NULL;
259}
260
b5f47924
SS
261
262/* Return the name of the dump file for the given phase.
799505ae
DM
263 The caller is responsible for calling free on the returned
264 buffer.
b5f47924
SS
265 If the dump is not enabled, returns NULL. */
266
267char *
47e0da37
DM
268gcc::dump_manager::
269get_dump_file_name (int phase) const
b5f47924 270{
b5f47924
SS
271 struct dump_file_info *dfi;
272
273 if (phase == TDI_none)
274 return NULL;
275
276 dfi = get_dump_file_info (phase);
799505ae
DM
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
b5f47924
SS
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 {
8264c84d
ML
305 /* (null), LANG, TREE, RTL, IPA. */
306 char suffix = " ltri"[dfi->dkind];
a529e0a6 307
8264c84d 308 if (snprintf (dump_id, sizeof (dump_id), ".%03d%c", dfi->num, suffix) < 0)
b5f47924
SS
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
c3284718 329 stream = strcmp ("stderr", dfi->alt_filename) == 0
b5f47924 330 ? stderr
c3284718
RS
331 : strcmp ("stdout", dfi->alt_filename) == 0
332 ? stdout
b5f47924
SS
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
1a817418 346dump_loc (dump_flags_t dump_kind, FILE *dfile, source_location loc)
b5f47924 347{
b5f47924
SS
348 if (dump_kind)
349 {
502498d5 350 if (LOCATION_LOCUS (loc) > BUILTINS_LOCATION)
e645e942 351 fprintf (dfile, "%s:%d:%d: note: ", LOCATION_FILE (loc),
103ff0d6 352 LOCATION_LINE (loc), LOCATION_COLUMN (loc));
a3d7af04 353 else if (current_function_decl)
e645e942 354 fprintf (dfile, "%s:%d:%d: note: ",
b5f47924 355 DECL_SOURCE_FILE (current_function_decl),
103ff0d6
TJ
356 DECL_SOURCE_LINE (current_function_decl),
357 DECL_SOURCE_COLUMN (current_function_decl));
b5f47924
SS
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
1a817418
ML
365dump_gimple_stmt (dump_flags_t dump_kind, dump_flags_t extra_dump_flags,
366 gimple *gs, int spc)
b5f47924
SS
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
1a817418
ML
378dump_gimple_stmt_loc (dump_flags_t dump_kind, source_location loc,
379 dump_flags_t extra_dump_flags, gimple *gs, int spc)
b5f47924
SS
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
1a817418
ML
398dump_generic_expr (dump_flags_t dump_kind, dump_flags_t extra_dump_flags,
399 tree t)
b5f47924
SS
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,
1a817418 414 dump_flags_t extra_dump_flags, tree t)
b5f47924
SS
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
1a817418 432dump_printf (dump_flags_t dump_kind, const char *format, ...)
b5f47924
SS
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
1a817418
ML
454dump_printf_loc (dump_flags_t dump_kind, source_location loc,
455 const char *format, ...)
b5f47924
SS
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
dc3f3805
RS
476/* Output VALUE in decimal to appropriate dump streams. */
477
478template<unsigned int N, typename C>
479void
480dump_dec (int dump_kind, const poly_int<N, C> &value)
481{
482 STATIC_ASSERT (poly_coeff_traits<C>::signedness >= 0);
483 signop sgn = poly_coeff_traits<C>::signedness ? SIGNED : UNSIGNED;
484 if (dump_file && (dump_kind & pflags))
485 print_dec (value, dump_file, sgn);
486
487 if (alt_dump_file && (dump_kind & alt_flags))
488 print_dec (value, alt_dump_file, sgn);
489}
490
491template void dump_dec (int, const poly_uint16 &);
492template void dump_dec (int, const poly_int64 &);
493template void dump_dec (int, const poly_uint64 &);
494template void dump_dec (int, const poly_offset_int &);
495template void dump_dec (int, const poly_widest_int &);
496
b5f47924
SS
497/* Start a dump for PHASE. Store user-supplied dump flags in
498 *FLAG_PTR. Return the number of streams opened. Set globals
499 DUMP_FILE, and ALT_DUMP_FILE to point to the opened streams, and
2b4e6bf1
SS
500 set dump_flags appropriately for both pass dump stream and
501 -fopt-info stream. */
b5f47924
SS
502
503int
47e0da37 504gcc::dump_manager::
1a817418 505dump_start (int phase, dump_flags_t *flag_ptr)
b5f47924
SS
506{
507 int count = 0;
508 char *name;
509 struct dump_file_info *dfi;
510 FILE *stream;
74911c3c 511 if (phase == TDI_none || !dump_phase_enabled_p (phase))
b5f47924
SS
512 return 0;
513
514 dfi = get_dump_file_info (phase);
515 name = get_dump_file_name (phase);
516 if (name)
517 {
c3284718 518 stream = strcmp ("stderr", name) == 0
b5f47924 519 ? stderr
c3284718
RS
520 : strcmp ("stdout", name) == 0
521 ? stdout
b5f47924
SS
522 : fopen (name, dfi->pstate < 0 ? "w" : "a");
523 if (!stream)
524 error ("could not open dump file %qs: %m", name);
525 else
526 {
527 dfi->pstate = 1;
528 count++;
529 }
530 free (name);
531 dfi->pstream = stream;
532 dump_file = dfi->pstream;
533 /* Initialize current dump flags. */
8264c84d 534 pflags = dfi->pflags;
b5f47924
SS
535 }
536
537 stream = dump_open_alternate_stream (dfi);
538 if (stream)
539 {
540 dfi->alt_stream = stream;
541 count++;
542 alt_dump_file = dfi->alt_stream;
2b4e6bf1 543 /* Initialize current -fopt-info flags. */
8264c84d 544 alt_flags = dfi->alt_flags;
b5f47924
SS
545 }
546
547 if (flag_ptr)
548 *flag_ptr = dfi->pflags;
549
550 return count;
551}
552
553/* Finish a tree dump for PHASE and close associated dump streams. Also
554 reset the globals DUMP_FILE, ALT_DUMP_FILE, and DUMP_FLAGS. */
555
556void
47e0da37 557gcc::dump_manager::
b5f47924
SS
558dump_finish (int phase)
559{
560 struct dump_file_info *dfi;
561
562 if (phase < 0)
563 return;
564 dfi = get_dump_file_info (phase);
71191083 565 if (dfi->pstream && (!dfi->pfilename
c3284718
RS
566 || (strcmp ("stderr", dfi->pfilename) != 0
567 && strcmp ("stdout", dfi->pfilename) != 0)))
b5f47924
SS
568 fclose (dfi->pstream);
569
c3284718
RS
570 if (dfi->alt_stream && strcmp ("stderr", dfi->alt_filename) != 0
571 && strcmp ("stdout", dfi->alt_filename) != 0)
b5f47924
SS
572 fclose (dfi->alt_stream);
573
574 dfi->alt_stream = NULL;
575 dfi->pstream = NULL;
576 dump_file = NULL;
577 alt_dump_file = NULL;
578 dump_flags = TDI_none;
579 alt_flags = 0;
580 pflags = 0;
581}
582
583/* Begin a tree dump for PHASE. Stores any user supplied flag in
584 *FLAG_PTR and returns a stream to write to. If the dump is not
585 enabled, returns NULL.
586 Multiple calls will reopen and append to the dump file. */
587
588FILE *
1a817418 589dump_begin (int phase, dump_flags_t *flag_ptr)
47e0da37
DM
590{
591 return g->get_dumps ()->dump_begin (phase, flag_ptr);
592}
593
594FILE *
595gcc::dump_manager::
1a817418 596dump_begin (int phase, dump_flags_t *flag_ptr)
b5f47924
SS
597{
598 char *name;
599 struct dump_file_info *dfi;
600 FILE *stream;
601
74911c3c 602 if (phase == TDI_none || !dump_phase_enabled_p (phase))
b5f47924
SS
603 return NULL;
604
605 name = get_dump_file_name (phase);
606 if (!name)
607 return NULL;
608 dfi = get_dump_file_info (phase);
609
c3284718 610 stream = strcmp ("stderr", name) == 0
b5f47924 611 ? stderr
c3284718
RS
612 : strcmp ("stdout", name) == 0
613 ? stdout
b5f47924
SS
614 : fopen (name, dfi->pstate < 0 ? "w" : "a");
615
616 if (!stream)
617 error ("could not open dump file %qs: %m", name);
618 else
619 dfi->pstate = 1;
620 free (name);
621
622 if (flag_ptr)
623 *flag_ptr = dfi->pflags;
624
625 /* Initialize current flags */
626 pflags = dfi->pflags;
627 return stream;
628}
629
630/* Returns nonzero if dump PHASE is enabled for at least one stream.
631 If PHASE is TDI_tree_all, return nonzero if any dump is enabled for
632 any phase. */
633
47e0da37
DM
634int
635gcc::dump_manager::
636dump_phase_enabled_p (int phase) const
b5f47924
SS
637{
638 if (phase == TDI_tree_all)
639 {
640 size_t i;
641 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
642 if (dump_files[i].pstate || dump_files[i].alt_state)
643 return 1;
47e0da37
DM
644 for (i = 0; i < m_extra_dump_files_in_use; i++)
645 if (m_extra_dump_files[i].pstate || m_extra_dump_files[i].alt_state)
b5f47924
SS
646 return 1;
647 return 0;
648 }
649 else
650 {
651 struct dump_file_info *dfi = get_dump_file_info (phase);
652 return dfi->pstate || dfi->alt_state;
653 }
654}
655
656/* Returns nonzero if tree dump PHASE has been initialized. */
657
658int
47e0da37
DM
659gcc::dump_manager::
660dump_initialized_p (int phase) const
b5f47924
SS
661{
662 struct dump_file_info *dfi = get_dump_file_info (phase);
663 return dfi->pstate > 0 || dfi->alt_state > 0;
664}
665
666/* Returns the switch name of PHASE. */
667
668const char *
669dump_flag_name (int phase)
47e0da37
DM
670{
671 return g->get_dumps ()->dump_flag_name (phase);
672}
673
674const char *
675gcc::dump_manager::
676dump_flag_name (int phase) const
b5f47924
SS
677{
678 struct dump_file_info *dfi = get_dump_file_info (phase);
679 return dfi->swtch;
680}
681
682/* Finish a tree dump for PHASE. STREAM is the stream created by
683 dump_begin. */
684
685void
686dump_end (int phase ATTRIBUTE_UNUSED, FILE *stream)
687{
688 if (stream != stderr && stream != stdout)
689 fclose (stream);
690}
691
692/* Enable all tree dumps with FLAGS on FILENAME. Return number of
693 enabled tree dumps. */
694
47e0da37
DM
695int
696gcc::dump_manager::
8264c84d 697dump_enable_all (dump_kind dkind, dump_flags_t flags, const char *filename)
b5f47924 698{
b5f47924
SS
699 int n = 0;
700 size_t i;
701
702 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
703 {
8264c84d 704 if ((dump_files[i].dkind == dkind))
b5f47924
SS
705 {
706 const char *old_filename = dump_files[i].pfilename;
707 dump_files[i].pstate = -1;
708 dump_files[i].pflags |= flags;
709 n++;
710 /* Override the existing filename. */
711 if (filename)
712 {
713 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 dump_files[i].pstate = 1;
717 }
718 if (old_filename && filename != old_filename)
719 free (CONST_CAST (char *, old_filename));
720 }
721 }
722
47e0da37 723 for (i = 0; i < m_extra_dump_files_in_use; i++)
b5f47924 724 {
8264c84d 725 if ((m_extra_dump_files[i].dkind == dkind))
b5f47924 726 {
47e0da37
DM
727 const char *old_filename = m_extra_dump_files[i].pfilename;
728 m_extra_dump_files[i].pstate = -1;
729 m_extra_dump_files[i].pflags |= flags;
b5f47924
SS
730 n++;
731 /* Override the existing filename. */
732 if (filename)
733 {
47e0da37 734 m_extra_dump_files[i].pfilename = xstrdup (filename);
b5f47924
SS
735 /* Since it is a command-line provided file, which is
736 common to all the phases, use it in append mode. */
47e0da37 737 m_extra_dump_files[i].pstate = 1;
b5f47924
SS
738 }
739 if (old_filename && filename != old_filename)
740 free (CONST_CAST (char *, old_filename));
741 }
742 }
743
744 return n;
745}
746
2b4e6bf1
SS
747/* Enable -fopt-info dumps on all dump files matching OPTGROUP_FLAGS.
748 Enable dumps with FLAGS on FILENAME. Return the number of enabled
749 dumps. */
b5f47924 750
47e0da37
DM
751int
752gcc::dump_manager::
1a817418
ML
753opt_info_enable_passes (int optgroup_flags, dump_flags_t flags,
754 const char *filename)
b5f47924
SS
755{
756 int n = 0;
757 size_t i;
758
759 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
760 {
2b4e6bf1 761 if ((dump_files[i].optgroup_flags & optgroup_flags))
b5f47924
SS
762 {
763 const char *old_filename = dump_files[i].alt_filename;
764 /* Since this file is shared among different passes, it
765 should be opened in append mode. */
766 dump_files[i].alt_state = 1;
767 dump_files[i].alt_flags |= flags;
768 n++;
769 /* Override the existing filename. */
770 if (filename)
771 dump_files[i].alt_filename = xstrdup (filename);
772 if (old_filename && filename != old_filename)
773 free (CONST_CAST (char *, old_filename));
774 }
775 }
776
47e0da37 777 for (i = 0; i < m_extra_dump_files_in_use; i++)
b5f47924 778 {
47e0da37 779 if ((m_extra_dump_files[i].optgroup_flags & optgroup_flags))
b5f47924 780 {
47e0da37 781 const char *old_filename = m_extra_dump_files[i].alt_filename;
b5f47924
SS
782 /* Since this file is shared among different passes, it
783 should be opened in append mode. */
47e0da37
DM
784 m_extra_dump_files[i].alt_state = 1;
785 m_extra_dump_files[i].alt_flags |= flags;
b5f47924
SS
786 n++;
787 /* Override the existing filename. */
788 if (filename)
47e0da37 789 m_extra_dump_files[i].alt_filename = xstrdup (filename);
b5f47924
SS
790 if (old_filename && filename != old_filename)
791 free (CONST_CAST (char *, old_filename));
792 }
793 }
794
795 return n;
796}
797
798/* Parse ARG as a dump switch. Return nonzero if it is, and store the
799 relevant details in the dump_files array. */
800
47e0da37
DM
801int
802gcc::dump_manager::
b5f47924
SS
803dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
804{
805 const char *option_value;
806 const char *ptr;
1a817418 807 dump_flags_t flags;
b5f47924
SS
808
809 if (doglob && !dfi->glob)
810 return 0;
811
812 option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
813 if (!option_value)
814 return 0;
815
816 if (*option_value && *option_value != '-' && *option_value != '=')
817 return 0;
818
819 ptr = option_value;
820 flags = 0;
821
822 while (*ptr)
823 {
824 const struct dump_option_value_info *option_ptr;
825 const char *end_ptr;
826 const char *eq_ptr;
827 unsigned length;
828
829 while (*ptr == '-')
830 ptr++;
831 end_ptr = strchr (ptr, '-');
832 eq_ptr = strchr (ptr, '=');
833
834 if (eq_ptr && !end_ptr)
835 end_ptr = eq_ptr;
836
837 if (!end_ptr)
838 end_ptr = ptr + strlen (ptr);
839 length = end_ptr - ptr;
840
841 for (option_ptr = dump_options; option_ptr->name; option_ptr++)
842 if (strlen (option_ptr->name) == length
843 && !memcmp (option_ptr->name, ptr, length))
844 {
845 flags |= option_ptr->value;
846 goto found;
847 }
848
849 if (*ptr == '=')
850 {
851 /* Interpret rest of the argument as a dump filename. This
852 filename overrides other command line filenames. */
853 if (dfi->pfilename)
854 free (CONST_CAST (char *, dfi->pfilename));
855 dfi->pfilename = xstrdup (ptr + 1);
856 break;
857 }
858 else
859 warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
860 length, ptr, dfi->swtch);
861 found:;
862 ptr = end_ptr;
863 }
864
865 dfi->pstate = -1;
866 dfi->pflags |= flags;
867
868 /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
869 known dumps. */
870 if (dfi->suffix == NULL)
8264c84d 871 dump_enable_all (dfi->dkind, dfi->pflags, dfi->pfilename);
b5f47924
SS
872
873 return 1;
874}
875
876int
47e0da37 877gcc::dump_manager::
b5f47924
SS
878dump_switch_p (const char *arg)
879{
880 size_t i;
881 int any = 0;
882
883 for (i = TDI_none + 1; i != TDI_end; i++)
884 any |= dump_switch_p_1 (arg, &dump_files[i], false);
885
886 /* Don't glob if we got a hit already */
887 if (!any)
888 for (i = TDI_none + 1; i != TDI_end; i++)
889 any |= dump_switch_p_1 (arg, &dump_files[i], true);
890
47e0da37
DM
891 for (i = 0; i < m_extra_dump_files_in_use; i++)
892 any |= dump_switch_p_1 (arg, &m_extra_dump_files[i], false);
b5f47924
SS
893
894 if (!any)
47e0da37
DM
895 for (i = 0; i < m_extra_dump_files_in_use; i++)
896 any |= dump_switch_p_1 (arg, &m_extra_dump_files[i], true);
b5f47924
SS
897
898
899 return any;
900}
901
2b4e6bf1
SS
902/* Parse ARG as a -fopt-info switch and store flags, optgroup_flags
903 and filename. Return non-zero if it is a recognized switch. */
b5f47924
SS
904
905static int
1a817418 906opt_info_switch_p_1 (const char *arg, dump_flags_t *flags, int *optgroup_flags,
2b4e6bf1 907 char **filename)
b5f47924
SS
908{
909 const char *option_value;
910 const char *ptr;
911
912 option_value = arg;
913 ptr = option_value;
914
915 *filename = NULL;
916 *flags = 0;
2b4e6bf1 917 *optgroup_flags = 0;
b5f47924
SS
918
919 if (!ptr)
2b4e6bf1 920 return 1; /* Handle '-fopt-info' without any additional options. */
b5f47924
SS
921
922 while (*ptr)
923 {
924 const struct dump_option_value_info *option_ptr;
925 const char *end_ptr;
926 const char *eq_ptr;
927 unsigned length;
928
929 while (*ptr == '-')
930 ptr++;
931 end_ptr = strchr (ptr, '-');
932 eq_ptr = strchr (ptr, '=');
933
934 if (eq_ptr && !end_ptr)
935 end_ptr = eq_ptr;
936
937 if (!end_ptr)
938 end_ptr = ptr + strlen (ptr);
939 length = end_ptr - ptr;
940
2b4e6bf1
SS
941 for (option_ptr = optinfo_verbosity_options; option_ptr->name;
942 option_ptr++)
b5f47924
SS
943 if (strlen (option_ptr->name) == length
944 && !memcmp (option_ptr->name, ptr, length))
945 {
946 *flags |= option_ptr->value;
947 goto found;
948 }
949
2b4e6bf1
SS
950 for (option_ptr = optgroup_options; option_ptr->name; option_ptr++)
951 if (strlen (option_ptr->name) == length
952 && !memcmp (option_ptr->name, ptr, length))
953 {
954 *optgroup_flags |= option_ptr->value;
955 goto found;
956 }
957
b5f47924
SS
958 if (*ptr == '=')
959 {
960 /* Interpret rest of the argument as a dump filename. This
961 filename overrides other command line filenames. */
962 *filename = xstrdup (ptr + 1);
963 break;
964 }
965 else
2b4e6bf1
SS
966 {
967 warning (0, "unknown option %q.*s in %<-fopt-info-%s%>",
968 length, ptr, arg);
969 return 0;
970 }
b5f47924
SS
971 found:;
972 ptr = end_ptr;
973 }
974
975 return 1;
976}
977
978/* Return non-zero if ARG is a recognized switch for
979 -fopt-info. Return zero otherwise. */
980
981int
982opt_info_switch_p (const char *arg)
983{
1a817418 984 dump_flags_t flags;
2b4e6bf1 985 int optgroup_flags;
b5f47924 986 char *filename;
2b4e6bf1 987 static char *file_seen = NULL;
47e0da37 988 gcc::dump_manager *dumps = g->get_dumps ();
b5f47924 989
2b4e6bf1
SS
990 if (!opt_info_switch_p_1 (arg, &flags, &optgroup_flags, &filename))
991 return 0;
b5f47924
SS
992
993 if (!filename)
994 filename = xstrdup ("stderr");
2b4e6bf1
SS
995
996 /* Bail out if a different filename has been specified. */
997 if (file_seen && strcmp (file_seen, filename))
998 {
999 warning (0, "ignoring possibly conflicting option %<-fopt-info-%s%>",
1000 arg);
1001 return 1;
1002 }
1003
1004 file_seen = xstrdup (filename);
b5f47924 1005 if (!flags)
5d318fd4 1006 flags = MSG_OPTIMIZED_LOCATIONS;
2b4e6bf1
SS
1007 if (!optgroup_flags)
1008 optgroup_flags = OPTGROUP_ALL;
b5f47924 1009
47e0da37 1010 return dumps->opt_info_enable_passes (optgroup_flags, flags, filename);
b5f47924
SS
1011}
1012
b5f47924
SS
1013/* Print basic block on the dump streams. */
1014
1015void
1016dump_basic_block (int dump_kind, basic_block bb, int indent)
1017{
1018 if (dump_file && (dump_kind & pflags))
1019 dump_bb (dump_file, bb, indent, TDF_DETAILS);
1020 if (alt_dump_file && (dump_kind & alt_flags))
1021 dump_bb (alt_dump_file, bb, indent, TDF_DETAILS);
1022}
1023
c24e924f
NS
1024/* Dump FUNCTION_DECL FN as tree dump PHASE. */
1025
1026void
1027dump_function (int phase, tree fn)
1028{
1029 FILE *stream;
1a817418 1030 dump_flags_t flags;
c24e924f
NS
1031
1032 stream = dump_begin (phase, &flags);
1033 if (stream)
1034 {
1035 dump_function_to_file (fn, stream, flags);
1036 dump_end (phase, stream);
1037 }
1038}
1039
b5f47924
SS
1040/* Print information from the combine pass on dump_file. */
1041
1042void
1043print_combine_total_stats (void)
1044{
1045 if (dump_file)
1046 dump_combine_total_stats (dump_file);
1047}
1048
1049/* Enable RTL dump for all the RTL passes. */
1050
1051bool
1052enable_rtl_dump_file (void)
1053{
47e0da37
DM
1054 gcc::dump_manager *dumps = g->get_dumps ();
1055 int num_enabled =
8264c84d
ML
1056 dumps->dump_enable_all (DK_rtl, dump_flags_t (TDF_DETAILS) | TDF_BLOCKS,
1057 NULL);
47e0da37 1058 return num_enabled > 0;
b5f47924 1059}