]> git.ipfire.org Git - thirdparty/gcc.git/blame - gcc/dumpfile.c
Avoid matching the same pattern statement twice
[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"
4f5b9c80
DM
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"
b5f47924
SS
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
1a817418 42static dump_flags_t pflags; /* current dump_flags */
b5f47924 43
1a817418 44static void dump_loc (dump_flags_t, FILE *, source_location);
29b54a9d
DM
45
46/* Current -fopt-info output stream, if any, and flags. */
47static FILE *alt_dump_file = NULL;
48static dump_flags_t alt_flags;
49
b5f47924
SS
50static FILE *dump_open_alternate_stream (struct dump_file_info *);
51
73fbfcad
SS
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. */
55FILE *dump_file = NULL;
73fbfcad 56const char *dump_file_name;
1a817418 57dump_flags_t dump_flags;
29b54a9d
DM
58bool 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
64static void
65refresh_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
73void
74set_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
83static void
84set_alt_dump_file (FILE *new_alt_dump_file)
85{
86 alt_dump_file = new_alt_dump_file;
87 refresh_dumps_are_enabled ();
88}
73fbfcad 89
63523736 90#define DUMP_FILE_INFO(suffix, swtch, dkind, num) \
4af78ef8
DM
91 {suffix, swtch, NULL, NULL, NULL, NULL, NULL, dkind, TDF_NONE, TDF_NONE, \
92 OPTGROUP_NONE, 0, 0, num, false, false}
8264c84d 93
b5f47924
SS
94/* Table of tree dump switches. This must be consistent with the
95 TREE_DUMP_INDEX enumeration in dumpfile.h. */
96static struct dump_file_info dump_files[TDI_end] =
97{
63523736
ML
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),
363dc72c
JJ
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),
b4da704c 105 DUMP_FILE_INFO (".lto-stream-out", "ipa-lto-stream-out", DK_ipa, 0),
363dc72c 106#define FIRST_AUTO_NUMBERED_DUMP 1
29a50dfb 107#define FIRST_ME_AUTO_NUMBERED_DUMP 4
b5f47924 108
63523736
ML
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),
b5f47924
SS
113};
114
b5f47924 115/* Define a name->number mapping for a dump flag value. */
4af78ef8
DM
116template <typename ValueType>
117struct kv_pair
b5f47924
SS
118{
119 const char *const name; /* the name of the value */
4af78ef8 120 const ValueType value; /* the value of the name */
b5f47924
SS
121};
122
123/* Table of dump options. This must be consistent with the TDF_* flags
124 in dumpfile.h and opt_info_options below. */
4af78ef8 125static const kv_pair<dump_flags_t> dump_options[] =
b5f47924
SS
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},
b5f47924
SS
143 {"eh", TDF_EH},
144 {"alias", TDF_ALIAS},
145 {"nouid", TDF_NOUID},
146 {"enumerate_locals", TDF_ENUMERATE_LOCALS},
147 {"scev", TDF_SCEV},
1ee62b92 148 {"gimple", TDF_GIMPLE},
56af751e 149 {"folding", TDF_FOLDING},
f14726bd
TJ
150 {"optimized", MSG_OPTIMIZED_LOCATIONS},
151 {"missed", MSG_MISSED_OPTIMIZATION},
152 {"note", MSG_NOTE},
153 {"optall", MSG_ALL},
f6b3ca5a
JJ
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))},
4af78ef8 157 {NULL, TDF_NONE}
b5f47924
SS
158};
159
2b4e6bf1
SS
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.
b5f47924 162 */
4af78ef8 163static const kv_pair<dump_flags_t> optinfo_verbosity_options[] =
b5f47924
SS
164{
165 {"optimized", MSG_OPTIMIZED_LOCATIONS},
166 {"missed", MSG_MISSED_OPTIMIZATION},
167 {"note", MSG_NOTE},
2b4e6bf1 168 {"all", MSG_ALL},
4af78ef8 169 {NULL, TDF_NONE}
2b4e6bf1
SS
170};
171
172/* Flags used for -fopt-info groups. */
4af78ef8 173static const kv_pair<optgroup_flags_t> optgroup_options[] =
2b4e6bf1
SS
174{
175 {"ipa", OPTGROUP_IPA},
176 {"loop", OPTGROUP_LOOP},
177 {"inline", OPTGROUP_INLINE},
fd2b8c8b 178 {"omp", OPTGROUP_OMP},
2b4e6bf1
SS
179 {"vec", OPTGROUP_VEC},
180 {"optall", OPTGROUP_ALL},
4af78ef8 181 {NULL, OPTGROUP_NONE}
b5f47924
SS
182};
183
47e0da37
DM
184gcc::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
10fdd6e9
DM
192gcc::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
b5f47924 213unsigned int
47e0da37 214gcc::dump_manager::
b5f47924 215dump_register (const char *suffix, const char *swtch, const char *glob,
4af78ef8
DM
216 dump_kind dkind, optgroup_flags_t optgroup_flags,
217 bool take_ownership)
b5f47924 218{
47e0da37 219 int num = m_next_dump++;
b5f47924 220
47e0da37 221 size_t count = m_extra_dump_files_in_use++;
b5f47924 222
47e0da37 223 if (count >= m_extra_dump_files_alloced)
b5f47924 224 {
47e0da37 225 if (m_extra_dump_files_alloced == 0)
363dc72c 226 m_extra_dump_files_alloced = 512;
b5f47924 227 else
47e0da37
DM
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);
c3684b7b
MS
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 ();
b5f47924
SS
240 }
241
47e0da37
DM
242 m_extra_dump_files[count].suffix = suffix;
243 m_extra_dump_files[count].swtch = swtch;
244 m_extra_dump_files[count].glob = glob;
8264c84d 245 m_extra_dump_files[count].dkind = dkind;
47e0da37
DM
246 m_extra_dump_files[count].optgroup_flags = optgroup_flags;
247 m_extra_dump_files[count].num = num;
10fdd6e9 248 m_extra_dump_files[count].owns_strings = take_ownership;
b5f47924
SS
249
250 return count + TDI_end;
251}
252
253
363dc72c
JJ
254/* Allow languages and middle-end to register their dumps before the
255 optimization passes. */
256
257void
258gcc::dump_manager::
259register_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
b5f47924
SS
273/* Return the dump_file_info for the given phase. */
274
275struct dump_file_info *
47e0da37
DM
276gcc::dump_manager::
277get_dump_file_info (int phase) const
b5f47924
SS
278{
279 if (phase < TDI_end)
280 return &dump_files[phase];
47e0da37 281 else if ((size_t) (phase - TDI_end) >= m_extra_dump_files_in_use)
b5f47924
SS
282 return NULL;
283 else
47e0da37 284 return m_extra_dump_files + (phase - TDI_end);
b5f47924
SS
285}
286
799505ae
DM
287/* Locate the dump_file_info with swtch equal to SWTCH,
288 or return NULL if no such dump_file_info exists. */
289
290struct dump_file_info *
291gcc::dump_manager::
292get_dump_file_info_by_switch (const char *swtch) const
293{
294 for (unsigned i = 0; i < m_extra_dump_files_in_use; i++)
01512446 295 if (strcmp (m_extra_dump_files[i].swtch, swtch) == 0)
799505ae
DM
296 return &m_extra_dump_files[i];
297
298 /* Not found. */
299 return NULL;
300}
301
b5f47924
SS
302
303/* Return the name of the dump file for the given phase.
799505ae
DM
304 The caller is responsible for calling free on the returned
305 buffer.
b5f47924
SS
306 If the dump is not enabled, returns NULL. */
307
308char *
47e0da37
DM
309gcc::dump_manager::
310get_dump_file_name (int phase) const
b5f47924 311{
b5f47924
SS
312 struct dump_file_info *dfi;
313
314 if (phase == TDI_none)
315 return NULL;
316
317 dfi = get_dump_file_info (phase);
799505ae
DM
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
327char *
328gcc::dump_manager::
329get_dump_file_name (struct dump_file_info *dfi) const
330{
331 char dump_id[10];
332
333 gcc_assert (dfi);
334
b5f47924
SS
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 {
8264c84d
ML
346 /* (null), LANG, TREE, RTL, IPA. */
347 char suffix = " ltri"[dfi->dkind];
a529e0a6 348
8264c84d 349 if (snprintf (dump_id, sizeof (dump_id), ".%03d%c", dfi->num, suffix) < 0)
b5f47924
SS
350 dump_id[0] = '\0';
351 }
352
353 return concat (dump_base_name, dump_id, dfi->suffix, NULL);
354}
355
5d8b352a
NS
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
361static FILE *
362dump_open (const char *filename, bool trunc)
363{
364 if (strcmp ("stderr", filename) == 0)
365 return stderr;
366
bd9918c4
NS
367 if (strcmp ("stdout", filename) == 0
368 || strcmp ("-", filename) == 0)
5d8b352a
NS
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
b5f47924
SS
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
382static FILE *
383dump_open_alternate_stream (struct dump_file_info *dfi)
384{
b5f47924
SS
385 if (!dfi->alt_filename)
386 return NULL;
387
388 if (dfi->alt_stream)
389 return dfi->alt_stream;
390
5d8b352a 391 FILE *stream = dump_open (dfi->alt_filename, dfi->alt_state < 0);
b5f47924 392
5d8b352a 393 if (stream)
b5f47924
SS
394 dfi->alt_state = 1;
395
396 return stream;
397}
398
4f5b9c80
DM
399/* Construct a dump_user_location_t from STMT (using its location and
400 hotness). */
401
402dump_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
416dump_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
431dump_user_location_t
432dump_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
b5f47924
SS
441/* Print source location on DFILE if enabled. */
442
4f5b9c80 443static void
1a817418 444dump_loc (dump_flags_t dump_kind, FILE *dfile, source_location loc)
b5f47924 445{
b5f47924
SS
446 if (dump_kind)
447 {
502498d5 448 if (LOCATION_LOCUS (loc) > BUILTINS_LOCATION)
e645e942 449 fprintf (dfile, "%s:%d:%d: note: ", LOCATION_FILE (loc),
103ff0d6 450 LOCATION_LINE (loc), LOCATION_COLUMN (loc));
a3d7af04 451 else if (current_function_decl)
e645e942 452 fprintf (dfile, "%s:%d:%d: note: ",
b5f47924 453 DECL_SOURCE_FILE (current_function_decl),
103ff0d6
TJ
454 DECL_SOURCE_LINE (current_function_decl),
455 DECL_SOURCE_COLUMN (current_function_decl));
6475e077
DM
456 /* Indentation based on scope depth. */
457 fprintf (dfile, "%*s", get_dump_scope_depth (), "");
b5f47924
SS
458 }
459}
460
461/* Dump gimple statement GS with SPC indentation spaces and
462 EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled. */
463
464void
1a817418
ML
465dump_gimple_stmt (dump_flags_t dump_kind, dump_flags_t extra_dump_flags,
466 gimple *gs, int spc)
b5f47924
SS
467{
468 if (dump_file && (dump_kind & pflags))
469 print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
470
471 if (alt_dump_file && (dump_kind & alt_flags))
472 print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
473}
474
475/* Similar to dump_gimple_stmt, except additionally print source location. */
476
477void
4f5b9c80 478dump_gimple_stmt_loc (dump_flags_t dump_kind, const dump_location_t &loc,
1a817418 479 dump_flags_t extra_dump_flags, gimple *gs, int spc)
b5f47924 480{
4f5b9c80 481 location_t srcloc = loc.get_location_t ();
b5f47924
SS
482 if (dump_file && (dump_kind & pflags))
483 {
4f5b9c80 484 dump_loc (dump_kind, dump_file, srcloc);
b5f47924
SS
485 print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
486 }
487
488 if (alt_dump_file && (dump_kind & alt_flags))
489 {
4f5b9c80 490 dump_loc (dump_kind, alt_dump_file, srcloc);
b5f47924
SS
491 print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
492 }
493}
494
30f502ed
RB
495/* Dump gimple statement GS with SPC indentation spaces and
496 EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled.
497 Do not terminate with a newline or semicolon. */
498
499void
500dump_gimple_expr (dump_flags_t dump_kind, dump_flags_t extra_dump_flags,
501 gimple *gs, int spc)
502{
503 if (dump_file && (dump_kind & pflags))
504 print_gimple_expr (dump_file, gs, spc, dump_flags | extra_dump_flags);
505
506 if (alt_dump_file && (dump_kind & alt_flags))
507 print_gimple_expr (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
508}
509
510/* Similar to dump_gimple_expr, except additionally print source location. */
511
512void
513dump_gimple_expr_loc (dump_flags_t dump_kind, const dump_location_t &loc,
514 dump_flags_t extra_dump_flags, gimple *gs, int spc)
515{
516 location_t srcloc = loc.get_location_t ();
517 if (dump_file && (dump_kind & pflags))
518 {
519 dump_loc (dump_kind, dump_file, srcloc);
520 print_gimple_expr (dump_file, gs, spc, dump_flags | extra_dump_flags);
521 }
522
523 if (alt_dump_file && (dump_kind & alt_flags))
524 {
525 dump_loc (dump_kind, alt_dump_file, srcloc);
526 print_gimple_expr (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
527 }
528}
529
530
b5f47924
SS
531/* Dump expression tree T using EXTRA_DUMP_FLAGS on dump streams if
532 DUMP_KIND is enabled. */
533
534void
1a817418
ML
535dump_generic_expr (dump_flags_t dump_kind, dump_flags_t extra_dump_flags,
536 tree t)
b5f47924
SS
537{
538 if (dump_file && (dump_kind & pflags))
539 print_generic_expr (dump_file, t, dump_flags | extra_dump_flags);
540
541 if (alt_dump_file && (dump_kind & alt_flags))
542 print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags);
543}
544
d7259673
DM
545
546/* Similar to dump_generic_expr, except additionally print the source
547 location. */
548
549void
550dump_generic_expr_loc (dump_flags_t dump_kind, const dump_location_t &loc,
551 dump_flags_t extra_dump_flags, tree t)
552{
553 location_t srcloc = loc.get_location_t ();
554 if (dump_file && (dump_kind & pflags))
555 {
556 dump_loc (dump_kind, dump_file, srcloc);
557 print_generic_expr (dump_file, t, dump_flags | extra_dump_flags);
558 }
559
560 if (alt_dump_file && (dump_kind & alt_flags))
561 {
562 dump_loc (dump_kind, alt_dump_file, srcloc);
563 print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags);
564 }
565}
566
b5f47924
SS
567/* Output a formatted message using FORMAT on appropriate dump streams. */
568
569void
1a817418 570dump_printf (dump_flags_t dump_kind, const char *format, ...)
b5f47924
SS
571{
572 if (dump_file && (dump_kind & pflags))
573 {
574 va_list ap;
575 va_start (ap, format);
576 vfprintf (dump_file, format, ap);
577 va_end (ap);
578 }
579
580 if (alt_dump_file && (dump_kind & alt_flags))
581 {
582 va_list ap;
583 va_start (ap, format);
584 vfprintf (alt_dump_file, format, ap);
585 va_end (ap);
586 }
587}
588
589/* Similar to dump_printf, except source location is also printed. */
590
591void
4f5b9c80 592dump_printf_loc (dump_flags_t dump_kind, const dump_location_t &loc,
1a817418 593 const char *format, ...)
b5f47924 594{
4f5b9c80 595 location_t srcloc = loc.get_location_t ();
b5f47924
SS
596 if (dump_file && (dump_kind & pflags))
597 {
598 va_list ap;
4f5b9c80 599 dump_loc (dump_kind, dump_file, srcloc);
b5f47924
SS
600 va_start (ap, format);
601 vfprintf (dump_file, format, ap);
602 va_end (ap);
603 }
604
605 if (alt_dump_file && (dump_kind & alt_flags))
606 {
607 va_list ap;
4f5b9c80 608 dump_loc (dump_kind, alt_dump_file, srcloc);
b5f47924
SS
609 va_start (ap, format);
610 vfprintf (alt_dump_file, format, ap);
611 va_end (ap);
612 }
613}
614
dc3f3805
RS
615/* Output VALUE in decimal to appropriate dump streams. */
616
617template<unsigned int N, typename C>
618void
4af78ef8 619dump_dec (dump_flags_t dump_kind, const poly_int<N, C> &value)
dc3f3805
RS
620{
621 STATIC_ASSERT (poly_coeff_traits<C>::signedness >= 0);
622 signop sgn = poly_coeff_traits<C>::signedness ? SIGNED : UNSIGNED;
623 if (dump_file && (dump_kind & pflags))
624 print_dec (value, dump_file, sgn);
625
626 if (alt_dump_file && (dump_kind & alt_flags))
627 print_dec (value, alt_dump_file, sgn);
628}
629
4af78ef8
DM
630template void dump_dec (dump_flags_t, const poly_uint16 &);
631template void dump_dec (dump_flags_t, const poly_int64 &);
632template void dump_dec (dump_flags_t, const poly_uint64 &);
633template void dump_dec (dump_flags_t, const poly_offset_int &);
634template void dump_dec (dump_flags_t, const poly_widest_int &);
dc3f3805 635
6475e077
DM
636/* The current dump scope-nesting depth. */
637
638static int dump_scope_depth;
639
640/* Get the current dump scope-nesting depth.
641 For use by dump_*_loc (for showing nesting via indentation). */
642
643unsigned int
644get_dump_scope_depth ()
645{
646 return dump_scope_depth;
647}
648
649/* Push a nested dump scope.
650 Print "=== NAME ===\n" to the dumpfile, if any, and to the -fopt-info
651 destination, if any.
652 Increment the scope depth. */
653
654void
655dump_begin_scope (const char *name, const dump_location_t &loc)
656{
657 dump_printf_loc (MSG_NOTE, loc, "=== %s ===\n", name);
658 dump_scope_depth++;
659}
660
661/* Pop a nested dump scope. */
662
663void
664dump_end_scope ()
665{
666 dump_scope_depth--;
667}
668
b5f47924
SS
669/* Start a dump for PHASE. Store user-supplied dump flags in
670 *FLAG_PTR. Return the number of streams opened. Set globals
671 DUMP_FILE, and ALT_DUMP_FILE to point to the opened streams, and
2b4e6bf1
SS
672 set dump_flags appropriately for both pass dump stream and
673 -fopt-info stream. */
b5f47924
SS
674
675int
47e0da37 676gcc::dump_manager::
1a817418 677dump_start (int phase, dump_flags_t *flag_ptr)
b5f47924
SS
678{
679 int count = 0;
680 char *name;
681 struct dump_file_info *dfi;
682 FILE *stream;
74911c3c 683 if (phase == TDI_none || !dump_phase_enabled_p (phase))
b5f47924
SS
684 return 0;
685
686 dfi = get_dump_file_info (phase);
687 name = get_dump_file_name (phase);
688 if (name)
689 {
5d8b352a
NS
690 stream = dump_open (name, dfi->pstate < 0);
691 if (stream)
b5f47924
SS
692 {
693 dfi->pstate = 1;
694 count++;
695 }
696 free (name);
697 dfi->pstream = stream;
29b54a9d 698 set_dump_file (dfi->pstream);
b5f47924 699 /* Initialize current dump flags. */
8264c84d 700 pflags = dfi->pflags;
b5f47924
SS
701 }
702
703 stream = dump_open_alternate_stream (dfi);
704 if (stream)
705 {
706 dfi->alt_stream = stream;
707 count++;
29b54a9d 708 set_alt_dump_file (dfi->alt_stream);
2b4e6bf1 709 /* Initialize current -fopt-info flags. */
8264c84d 710 alt_flags = dfi->alt_flags;
b5f47924
SS
711 }
712
713 if (flag_ptr)
714 *flag_ptr = dfi->pflags;
715
716 return count;
717}
718
719/* Finish a tree dump for PHASE and close associated dump streams. Also
720 reset the globals DUMP_FILE, ALT_DUMP_FILE, and DUMP_FLAGS. */
721
722void
47e0da37 723gcc::dump_manager::
b5f47924
SS
724dump_finish (int phase)
725{
726 struct dump_file_info *dfi;
727
728 if (phase < 0)
729 return;
730 dfi = get_dump_file_info (phase);
5d8b352a 731 if (dfi->pstream && dfi->pstream != stdout && dfi->pstream != stderr)
b5f47924
SS
732 fclose (dfi->pstream);
733
5d8b352a 734 if (dfi->alt_stream && dfi->alt_stream != stdout && dfi->alt_stream != stderr)
b5f47924
SS
735 fclose (dfi->alt_stream);
736
737 dfi->alt_stream = NULL;
738 dfi->pstream = NULL;
29b54a9d
DM
739 set_dump_file (NULL);
740 set_alt_dump_file (NULL);
4af78ef8
DM
741 dump_flags = TDF_NONE;
742 alt_flags = TDF_NONE;
743 pflags = TDF_NONE;
b5f47924
SS
744}
745
746/* Begin a tree dump for PHASE. Stores any user supplied flag in
747 *FLAG_PTR and returns a stream to write to. If the dump is not
748 enabled, returns NULL.
749 Multiple calls will reopen and append to the dump file. */
750
751FILE *
1a817418 752dump_begin (int phase, dump_flags_t *flag_ptr)
47e0da37
DM
753{
754 return g->get_dumps ()->dump_begin (phase, flag_ptr);
755}
756
757FILE *
758gcc::dump_manager::
1a817418 759dump_begin (int phase, dump_flags_t *flag_ptr)
b5f47924
SS
760{
761 char *name;
762 struct dump_file_info *dfi;
763 FILE *stream;
764
74911c3c 765 if (phase == TDI_none || !dump_phase_enabled_p (phase))
b5f47924
SS
766 return NULL;
767
768 name = get_dump_file_name (phase);
769 if (!name)
770 return NULL;
771 dfi = get_dump_file_info (phase);
772
5d8b352a
NS
773 stream = dump_open (name, dfi->pstate < 0);
774 if (stream)
b5f47924
SS
775 dfi->pstate = 1;
776 free (name);
777
778 if (flag_ptr)
779 *flag_ptr = dfi->pflags;
780
781 /* Initialize current flags */
782 pflags = dfi->pflags;
783 return stream;
784}
785
786/* Returns nonzero if dump PHASE is enabled for at least one stream.
787 If PHASE is TDI_tree_all, return nonzero if any dump is enabled for
788 any phase. */
789
47e0da37
DM
790int
791gcc::dump_manager::
792dump_phase_enabled_p (int phase) const
b5f47924
SS
793{
794 if (phase == TDI_tree_all)
795 {
796 size_t i;
797 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
798 if (dump_files[i].pstate || dump_files[i].alt_state)
799 return 1;
47e0da37
DM
800 for (i = 0; i < m_extra_dump_files_in_use; i++)
801 if (m_extra_dump_files[i].pstate || m_extra_dump_files[i].alt_state)
b5f47924
SS
802 return 1;
803 return 0;
804 }
805 else
806 {
807 struct dump_file_info *dfi = get_dump_file_info (phase);
808 return dfi->pstate || dfi->alt_state;
809 }
810}
811
812/* Returns nonzero if tree dump PHASE has been initialized. */
813
814int
47e0da37
DM
815gcc::dump_manager::
816dump_initialized_p (int phase) const
b5f47924
SS
817{
818 struct dump_file_info *dfi = get_dump_file_info (phase);
819 return dfi->pstate > 0 || dfi->alt_state > 0;
820}
821
822/* Returns the switch name of PHASE. */
823
824const char *
825dump_flag_name (int phase)
47e0da37
DM
826{
827 return g->get_dumps ()->dump_flag_name (phase);
828}
829
830const char *
831gcc::dump_manager::
832dump_flag_name (int phase) const
b5f47924
SS
833{
834 struct dump_file_info *dfi = get_dump_file_info (phase);
835 return dfi->swtch;
836}
837
838/* Finish a tree dump for PHASE. STREAM is the stream created by
839 dump_begin. */
840
841void
842dump_end (int phase ATTRIBUTE_UNUSED, FILE *stream)
843{
844 if (stream != stderr && stream != stdout)
845 fclose (stream);
846}
847
848/* Enable all tree dumps with FLAGS on FILENAME. Return number of
849 enabled tree dumps. */
850
47e0da37
DM
851int
852gcc::dump_manager::
8264c84d 853dump_enable_all (dump_kind dkind, dump_flags_t flags, const char *filename)
b5f47924 854{
b5f47924
SS
855 int n = 0;
856 size_t i;
857
858 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
859 {
8264c84d 860 if ((dump_files[i].dkind == dkind))
b5f47924
SS
861 {
862 const char *old_filename = dump_files[i].pfilename;
863 dump_files[i].pstate = -1;
864 dump_files[i].pflags |= flags;
865 n++;
866 /* Override the existing filename. */
867 if (filename)
868 {
869 dump_files[i].pfilename = xstrdup (filename);
870 /* Since it is a command-line provided file, which is
871 common to all the phases, use it in append mode. */
872 dump_files[i].pstate = 1;
873 }
874 if (old_filename && filename != old_filename)
875 free (CONST_CAST (char *, old_filename));
876 }
877 }
878
47e0da37 879 for (i = 0; i < m_extra_dump_files_in_use; i++)
b5f47924 880 {
8264c84d 881 if ((m_extra_dump_files[i].dkind == dkind))
b5f47924 882 {
47e0da37
DM
883 const char *old_filename = m_extra_dump_files[i].pfilename;
884 m_extra_dump_files[i].pstate = -1;
885 m_extra_dump_files[i].pflags |= flags;
b5f47924
SS
886 n++;
887 /* Override the existing filename. */
888 if (filename)
889 {
47e0da37 890 m_extra_dump_files[i].pfilename = xstrdup (filename);
b5f47924
SS
891 /* Since it is a command-line provided file, which is
892 common to all the phases, use it in append mode. */
47e0da37 893 m_extra_dump_files[i].pstate = 1;
b5f47924
SS
894 }
895 if (old_filename && filename != old_filename)
896 free (CONST_CAST (char *, old_filename));
897 }
898 }
899
900 return n;
901}
902
2b4e6bf1
SS
903/* Enable -fopt-info dumps on all dump files matching OPTGROUP_FLAGS.
904 Enable dumps with FLAGS on FILENAME. Return the number of enabled
905 dumps. */
b5f47924 906
47e0da37
DM
907int
908gcc::dump_manager::
4af78ef8 909opt_info_enable_passes (optgroup_flags_t optgroup_flags, dump_flags_t flags,
1a817418 910 const char *filename)
b5f47924
SS
911{
912 int n = 0;
913 size_t i;
914
915 for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
916 {
2b4e6bf1 917 if ((dump_files[i].optgroup_flags & optgroup_flags))
b5f47924
SS
918 {
919 const char *old_filename = dump_files[i].alt_filename;
920 /* Since this file is shared among different passes, it
921 should be opened in append mode. */
922 dump_files[i].alt_state = 1;
923 dump_files[i].alt_flags |= flags;
924 n++;
925 /* Override the existing filename. */
926 if (filename)
927 dump_files[i].alt_filename = xstrdup (filename);
928 if (old_filename && filename != old_filename)
929 free (CONST_CAST (char *, old_filename));
930 }
931 }
932
47e0da37 933 for (i = 0; i < m_extra_dump_files_in_use; i++)
b5f47924 934 {
47e0da37 935 if ((m_extra_dump_files[i].optgroup_flags & optgroup_flags))
b5f47924 936 {
47e0da37 937 const char *old_filename = m_extra_dump_files[i].alt_filename;
b5f47924
SS
938 /* Since this file is shared among different passes, it
939 should be opened in append mode. */
47e0da37
DM
940 m_extra_dump_files[i].alt_state = 1;
941 m_extra_dump_files[i].alt_flags |= flags;
b5f47924
SS
942 n++;
943 /* Override the existing filename. */
944 if (filename)
47e0da37 945 m_extra_dump_files[i].alt_filename = xstrdup (filename);
b5f47924
SS
946 if (old_filename && filename != old_filename)
947 free (CONST_CAST (char *, old_filename));
948 }
949 }
950
951 return n;
952}
953
954/* Parse ARG as a dump switch. Return nonzero if it is, and store the
955 relevant details in the dump_files array. */
956
47e0da37
DM
957int
958gcc::dump_manager::
b5f47924
SS
959dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
960{
961 const char *option_value;
962 const char *ptr;
1a817418 963 dump_flags_t flags;
b5f47924
SS
964
965 if (doglob && !dfi->glob)
966 return 0;
967
968 option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
969 if (!option_value)
970 return 0;
971
972 if (*option_value && *option_value != '-' && *option_value != '=')
973 return 0;
974
975 ptr = option_value;
4af78ef8 976 flags = TDF_NONE;
b5f47924
SS
977
978 while (*ptr)
979 {
4af78ef8 980 const struct kv_pair<dump_flags_t> *option_ptr;
b5f47924
SS
981 const char *end_ptr;
982 const char *eq_ptr;
983 unsigned length;
984
985 while (*ptr == '-')
986 ptr++;
987 end_ptr = strchr (ptr, '-');
988 eq_ptr = strchr (ptr, '=');
989
990 if (eq_ptr && !end_ptr)
991 end_ptr = eq_ptr;
992
993 if (!end_ptr)
994 end_ptr = ptr + strlen (ptr);
995 length = end_ptr - ptr;
996
997 for (option_ptr = dump_options; option_ptr->name; option_ptr++)
998 if (strlen (option_ptr->name) == length
999 && !memcmp (option_ptr->name, ptr, length))
1000 {
1001 flags |= option_ptr->value;
1002 goto found;
1003 }
1004
1005 if (*ptr == '=')
1006 {
1007 /* Interpret rest of the argument as a dump filename. This
1008 filename overrides other command line filenames. */
1009 if (dfi->pfilename)
1010 free (CONST_CAST (char *, dfi->pfilename));
1011 dfi->pfilename = xstrdup (ptr + 1);
1012 break;
1013 }
1014 else
1015 warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
1016 length, ptr, dfi->swtch);
1017 found:;
1018 ptr = end_ptr;
1019 }
1020
1021 dfi->pstate = -1;
1022 dfi->pflags |= flags;
1023
1024 /* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
1025 known dumps. */
1026 if (dfi->suffix == NULL)
8264c84d 1027 dump_enable_all (dfi->dkind, dfi->pflags, dfi->pfilename);
b5f47924
SS
1028
1029 return 1;
1030}
1031
1032int
47e0da37 1033gcc::dump_manager::
b5f47924
SS
1034dump_switch_p (const char *arg)
1035{
1036 size_t i;
1037 int any = 0;
1038
1039 for (i = TDI_none + 1; i != TDI_end; i++)
1040 any |= dump_switch_p_1 (arg, &dump_files[i], false);
1041
1042 /* Don't glob if we got a hit already */
1043 if (!any)
1044 for (i = TDI_none + 1; i != TDI_end; i++)
1045 any |= dump_switch_p_1 (arg, &dump_files[i], true);
1046
47e0da37
DM
1047 for (i = 0; i < m_extra_dump_files_in_use; i++)
1048 any |= dump_switch_p_1 (arg, &m_extra_dump_files[i], false);
b5f47924
SS
1049
1050 if (!any)
47e0da37
DM
1051 for (i = 0; i < m_extra_dump_files_in_use; i++)
1052 any |= dump_switch_p_1 (arg, &m_extra_dump_files[i], true);
b5f47924
SS
1053
1054
1055 return any;
1056}
1057
2b4e6bf1
SS
1058/* Parse ARG as a -fopt-info switch and store flags, optgroup_flags
1059 and filename. Return non-zero if it is a recognized switch. */
b5f47924
SS
1060
1061static int
4af78ef8
DM
1062opt_info_switch_p_1 (const char *arg, dump_flags_t *flags,
1063 optgroup_flags_t *optgroup_flags, char **filename)
b5f47924
SS
1064{
1065 const char *option_value;
1066 const char *ptr;
1067
1068 option_value = arg;
1069 ptr = option_value;
1070
1071 *filename = NULL;
4af78ef8
DM
1072 *flags = TDF_NONE;
1073 *optgroup_flags = OPTGROUP_NONE;
b5f47924
SS
1074
1075 if (!ptr)
2b4e6bf1 1076 return 1; /* Handle '-fopt-info' without any additional options. */
b5f47924
SS
1077
1078 while (*ptr)
1079 {
b5f47924
SS
1080 const char *end_ptr;
1081 const char *eq_ptr;
1082 unsigned length;
1083
1084 while (*ptr == '-')
1085 ptr++;
1086 end_ptr = strchr (ptr, '-');
1087 eq_ptr = strchr (ptr, '=');
1088
1089 if (eq_ptr && !end_ptr)
1090 end_ptr = eq_ptr;
1091
1092 if (!end_ptr)
1093 end_ptr = ptr + strlen (ptr);
1094 length = end_ptr - ptr;
1095
4af78ef8
DM
1096 for (const kv_pair<dump_flags_t> *option_ptr = optinfo_verbosity_options;
1097 option_ptr->name; option_ptr++)
b5f47924
SS
1098 if (strlen (option_ptr->name) == length
1099 && !memcmp (option_ptr->name, ptr, length))
1100 {
1101 *flags |= option_ptr->value;
1102 goto found;
1103 }
1104
4af78ef8
DM
1105 for (const kv_pair<optgroup_flags_t> *option_ptr = optgroup_options;
1106 option_ptr->name; option_ptr++)
2b4e6bf1
SS
1107 if (strlen (option_ptr->name) == length
1108 && !memcmp (option_ptr->name, ptr, length))
1109 {
1110 *optgroup_flags |= option_ptr->value;
1111 goto found;
1112 }
1113
b5f47924
SS
1114 if (*ptr == '=')
1115 {
1116 /* Interpret rest of the argument as a dump filename. This
1117 filename overrides other command line filenames. */
1118 *filename = xstrdup (ptr + 1);
1119 break;
1120 }
1121 else
2b4e6bf1
SS
1122 {
1123 warning (0, "unknown option %q.*s in %<-fopt-info-%s%>",
1124 length, ptr, arg);
1125 return 0;
1126 }
b5f47924
SS
1127 found:;
1128 ptr = end_ptr;
1129 }
1130
1131 return 1;
1132}
1133
1134/* Return non-zero if ARG is a recognized switch for
1135 -fopt-info. Return zero otherwise. */
1136
1137int
1138opt_info_switch_p (const char *arg)
1139{
1a817418 1140 dump_flags_t flags;
4af78ef8 1141 optgroup_flags_t optgroup_flags;
b5f47924 1142 char *filename;
2b4e6bf1 1143 static char *file_seen = NULL;
47e0da37 1144 gcc::dump_manager *dumps = g->get_dumps ();
b5f47924 1145
2b4e6bf1
SS
1146 if (!opt_info_switch_p_1 (arg, &flags, &optgroup_flags, &filename))
1147 return 0;
b5f47924
SS
1148
1149 if (!filename)
1150 filename = xstrdup ("stderr");
2b4e6bf1
SS
1151
1152 /* Bail out if a different filename has been specified. */
1153 if (file_seen && strcmp (file_seen, filename))
1154 {
1155 warning (0, "ignoring possibly conflicting option %<-fopt-info-%s%>",
1156 arg);
1157 return 1;
1158 }
1159
1160 file_seen = xstrdup (filename);
b5f47924 1161 if (!flags)
5d318fd4 1162 flags = MSG_OPTIMIZED_LOCATIONS;
2b4e6bf1
SS
1163 if (!optgroup_flags)
1164 optgroup_flags = OPTGROUP_ALL;
b5f47924 1165
47e0da37 1166 return dumps->opt_info_enable_passes (optgroup_flags, flags, filename);
b5f47924
SS
1167}
1168
b5f47924
SS
1169/* Print basic block on the dump streams. */
1170
1171void
4af78ef8 1172dump_basic_block (dump_flags_t dump_kind, basic_block bb, int indent)
b5f47924
SS
1173{
1174 if (dump_file && (dump_kind & pflags))
1175 dump_bb (dump_file, bb, indent, TDF_DETAILS);
1176 if (alt_dump_file && (dump_kind & alt_flags))
1177 dump_bb (alt_dump_file, bb, indent, TDF_DETAILS);
1178}
1179
c24e924f
NS
1180/* Dump FUNCTION_DECL FN as tree dump PHASE. */
1181
1182void
1183dump_function (int phase, tree fn)
1184{
1185 FILE *stream;
1a817418 1186 dump_flags_t flags;
c24e924f
NS
1187
1188 stream = dump_begin (phase, &flags);
1189 if (stream)
1190 {
1191 dump_function_to_file (fn, stream, flags);
1192 dump_end (phase, stream);
1193 }
1194}
1195
b5f47924
SS
1196/* Print information from the combine pass on dump_file. */
1197
1198void
1199print_combine_total_stats (void)
1200{
1201 if (dump_file)
1202 dump_combine_total_stats (dump_file);
1203}
1204
1205/* Enable RTL dump for all the RTL passes. */
1206
1207bool
1208enable_rtl_dump_file (void)
1209{
47e0da37
DM
1210 gcc::dump_manager *dumps = g->get_dumps ();
1211 int num_enabled =
8264c84d
ML
1212 dumps->dump_enable_all (DK_rtl, dump_flags_t (TDF_DETAILS) | TDF_BLOCKS,
1213 NULL);
47e0da37 1214 return num_enabled > 0;
b5f47924 1215}
4f5b9c80
DM
1216
1217#if CHECKING_P
1218
1219namespace selftest {
1220
1221/* Verify that the dump_location_t constructors capture the source location
1222 at which they were called (provided that the build compiler is sufficiently
1223 recent). */
1224
1225static void
1226test_impl_location ()
1227{
1228#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)
1229 /* Default ctor. */
1230 {
1231 dump_location_t loc;
1232 const int expected_line = __LINE__ - 1;
1233 ASSERT_STR_CONTAINS (loc.get_impl_location ().m_file, "dumpfile.c");
1234 ASSERT_EQ (loc.get_impl_location ().m_line, expected_line);
1235 }
1236
1237 /* Constructing from a gimple. */
1238 {
1239 dump_location_t loc ((gimple *)NULL);
1240 const int expected_line = __LINE__ - 1;
1241 ASSERT_STR_CONTAINS (loc.get_impl_location ().m_file, "dumpfile.c");
1242 ASSERT_EQ (loc.get_impl_location ().m_line, expected_line);
1243 }
1244
1245 /* Constructing from an rtx_insn. */
1246 {
1247 dump_location_t loc ((rtx_insn *)NULL);
1248 const int expected_line = __LINE__ - 1;
1249 ASSERT_STR_CONTAINS (loc.get_impl_location ().m_file, "dumpfile.c");
1250 ASSERT_EQ (loc.get_impl_location ().m_line, expected_line);
1251 }
1252#endif
1253}
1254
1255/* Run all of the selftests within this file. */
1256
1257void
1258dumpfile_c_tests ()
1259{
1260 test_impl_location ();
1261}
1262
1263} // namespace selftest
1264
1265#endif /* CHECKING_P */