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