blob: 0acc7a98db5596ee229b8a42eadb99817be42c14 [file] [log] [blame]
/* Dump infrastructure for optimizations and intermediate representation.
Copyright (C) 2012-2018 Free Software Foundation, Inc.
This file is part of GCC.
GCC is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free
Software Foundation; either version 3, or (at your option) any later
version.
GCC is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "options.h"
#include "tree.h"
#include "gimple-pretty-print.h"
#include "diagnostic-core.h"
#include "dumpfile.h"
#include "context.h"
#include "profile-count.h"
#include "tree-cfg.h"
#include "langhooks.h"
/* If non-NULL, return one past-the-end of the matching SUBPART of
the WHOLE string. */
#define skip_leading_substring(whole, part) \
(strncmp (whole, part, strlen (part)) ? NULL : whole + strlen (part))
static dump_flags_t pflags; /* current dump_flags */
static dump_flags_t alt_flags; /* current opt_info flags */
static void dump_loc (dump_flags_t, FILE *, source_location);
static FILE *dump_open_alternate_stream (struct dump_file_info *);
/* These are currently used for communicating between passes.
However, instead of accessing them directly, the passes can use
dump_printf () for dumps. */
FILE *dump_file = NULL;
FILE *alt_dump_file = NULL;
const char *dump_file_name;
dump_flags_t dump_flags;
#define DUMP_FILE_INFO(suffix, swtch, dkind, num) \
{suffix, swtch, NULL, NULL, NULL, NULL, NULL, dkind, 0, 0, 0, 0, 0, num, \
false, false}
/* Table of tree dump switches. This must be consistent with the
TREE_DUMP_INDEX enumeration in dumpfile.h. */
static struct dump_file_info dump_files[TDI_end] =
{
DUMP_FILE_INFO (NULL, NULL, DK_none, 0),
DUMP_FILE_INFO (".cgraph", "ipa-cgraph", DK_ipa, 0),
DUMP_FILE_INFO (".type-inheritance", "ipa-type-inheritance", DK_ipa, 0),
DUMP_FILE_INFO (".ipa-clones", "ipa-clones", DK_ipa, 0),
DUMP_FILE_INFO (".original", "tree-original", DK_tree, 0),
DUMP_FILE_INFO (".gimple", "tree-gimple", DK_tree, 0),
DUMP_FILE_INFO (".nested", "tree-nested", DK_tree, 0),
#define FIRST_AUTO_NUMBERED_DUMP 1
#define FIRST_ME_AUTO_NUMBERED_DUMP 3
DUMP_FILE_INFO (NULL, "lang-all", DK_lang, 0),
DUMP_FILE_INFO (NULL, "tree-all", DK_tree, 0),
DUMP_FILE_INFO (NULL, "rtl-all", DK_rtl, 0),
DUMP_FILE_INFO (NULL, "ipa-all", DK_ipa, 0),
};
/* Define a name->number mapping for a dump flag value. */
struct dump_option_value_info
{
const char *const name; /* the name of the value */
const dump_flags_t value; /* the value of the name */
};
/* Table of dump options. This must be consistent with the TDF_* flags
in dumpfile.h and opt_info_options below. */
static const struct dump_option_value_info dump_options[] =
{
{"address", TDF_ADDRESS},
{"asmname", TDF_ASMNAME},
{"slim", TDF_SLIM},
{"raw", TDF_RAW},
{"graph", TDF_GRAPH},
{"details", (TDF_DETAILS | MSG_OPTIMIZED_LOCATIONS
| MSG_MISSED_OPTIMIZATION
| MSG_NOTE)},
{"cselib", TDF_CSELIB},
{"stats", TDF_STATS},
{"blocks", TDF_BLOCKS},
{"vops", TDF_VOPS},
{"lineno", TDF_LINENO},
{"uid", TDF_UID},
{"stmtaddr", TDF_STMTADDR},
{"memsyms", TDF_MEMSYMS},
{"eh", TDF_EH},
{"alias", TDF_ALIAS},
{"nouid", TDF_NOUID},
{"enumerate_locals", TDF_ENUMERATE_LOCALS},
{"scev", TDF_SCEV},
{"gimple", TDF_GIMPLE},
{"folding", TDF_FOLDING},
{"optimized", MSG_OPTIMIZED_LOCATIONS},
{"missed", MSG_MISSED_OPTIMIZATION},
{"note", MSG_NOTE},
{"optall", MSG_ALL},
{"all", dump_flags_t (~(TDF_RAW | TDF_SLIM | TDF_LINENO | TDF_GRAPH
| TDF_STMTADDR | TDF_RHS_ONLY | TDF_NOUID
| TDF_ENUMERATE_LOCALS | TDF_SCEV | TDF_GIMPLE))},
{NULL, 0}
};
/* A subset of the dump_options table which is used for -fopt-info
types. This must be consistent with the MSG_* flags in dumpfile.h.
*/
static const struct dump_option_value_info optinfo_verbosity_options[] =
{
{"optimized", MSG_OPTIMIZED_LOCATIONS},
{"missed", MSG_MISSED_OPTIMIZATION},
{"note", MSG_NOTE},
{"all", MSG_ALL},
{NULL, 0}
};
/* Flags used for -fopt-info groups. */
static const struct dump_option_value_info optgroup_options[] =
{
{"ipa", OPTGROUP_IPA},
{"loop", OPTGROUP_LOOP},
{"inline", OPTGROUP_INLINE},
{"omp", OPTGROUP_OMP},
{"vec", OPTGROUP_VEC},
{"optall", OPTGROUP_ALL},
{NULL, 0}
};
gcc::dump_manager::dump_manager ():
m_next_dump (FIRST_AUTO_NUMBERED_DUMP),
m_extra_dump_files (NULL),
m_extra_dump_files_in_use (0),
m_extra_dump_files_alloced (0)
{
}
gcc::dump_manager::~dump_manager ()
{
for (size_t i = 0; i < m_extra_dump_files_in_use; i++)
{
dump_file_info *dfi = &m_extra_dump_files[i];
/* suffix, swtch, glob are statically allocated for the entries
in dump_files, and for statistics, but are dynamically allocated
for those for passes. */
if (dfi->owns_strings)
{
XDELETEVEC (const_cast <char *> (dfi->suffix));
XDELETEVEC (const_cast <char *> (dfi->swtch));
XDELETEVEC (const_cast <char *> (dfi->glob));
}
/* These, if non-NULL, are always dynamically allocated. */
XDELETEVEC (const_cast <char *> (dfi->pfilename));
XDELETEVEC (const_cast <char *> (dfi->alt_filename));
}
XDELETEVEC (m_extra_dump_files);
}
unsigned int
gcc::dump_manager::
dump_register (const char *suffix, const char *swtch, const char *glob,
dump_kind dkind, int optgroup_flags, bool take_ownership)
{
int num = m_next_dump++;
size_t count = m_extra_dump_files_in_use++;
if (count >= m_extra_dump_files_alloced)
{
if (m_extra_dump_files_alloced == 0)
m_extra_dump_files_alloced = 512;
else
m_extra_dump_files_alloced *= 2;
m_extra_dump_files = XRESIZEVEC (struct dump_file_info,
m_extra_dump_files,
m_extra_dump_files_alloced);
/* Construct a new object in the space allocated above. */
new (m_extra_dump_files + count) dump_file_info ();
}
else
{
/* Zero out the already constructed object. */
m_extra_dump_files[count] = dump_file_info ();
}
m_extra_dump_files[count].suffix = suffix;
m_extra_dump_files[count].swtch = swtch;
m_extra_dump_files[count].glob = glob;
m_extra_dump_files[count].dkind = dkind;
m_extra_dump_files[count].optgroup_flags = optgroup_flags;
m_extra_dump_files[count].num = num;
m_extra_dump_files[count].owns_strings = take_ownership;
return count + TDI_end;
}
/* Allow languages and middle-end to register their dumps before the
optimization passes. */
void
gcc::dump_manager::
register_dumps ()
{
lang_hooks.register_dumps (this);
/* If this assert fails, some FE registered more than
FIRST_ME_AUTO_NUMBERED_DUMP - FIRST_AUTO_NUMBERED_DUMP
dump files. Bump FIRST_ME_AUTO_NUMBERED_DUMP accordingly. */
gcc_assert (m_next_dump <= FIRST_ME_AUTO_NUMBERED_DUMP);
m_next_dump = FIRST_ME_AUTO_NUMBERED_DUMP;
dump_files[TDI_original].num = m_next_dump++;
dump_files[TDI_gimple].num = m_next_dump++;
dump_files[TDI_nested].num = m_next_dump++;
}
/* Return the dump_file_info for the given phase. */
struct dump_file_info *
gcc::dump_manager::
get_dump_file_info (int phase) const
{
if (phase < TDI_end)
return &dump_files[phase];
else if ((size_t) (phase - TDI_end) >= m_extra_dump_files_in_use)
return NULL;
else
return m_extra_dump_files + (phase - TDI_end);
}
/* Locate the dump_file_info with swtch equal to SWTCH,
or return NULL if no such dump_file_info exists. */
struct dump_file_info *
gcc::dump_manager::
get_dump_file_info_by_switch (const char *swtch) const
{
for (unsigned i = 0; i < m_extra_dump_files_in_use; i++)
if (strcmp (m_extra_dump_files[i].swtch, swtch) == 0)
return &m_extra_dump_files[i];
/* Not found. */
return NULL;
}
/* Return the name of the dump file for the given phase.
The caller is responsible for calling free on the returned
buffer.
If the dump is not enabled, returns NULL. */
char *
gcc::dump_manager::
get_dump_file_name (int phase) const
{
struct dump_file_info *dfi;
if (phase == TDI_none)
return NULL;
dfi = get_dump_file_info (phase);
return get_dump_file_name (dfi);
}
/* Return the name of the dump file for the given dump_file_info.
The caller is responsible for calling free on the returned
buffer.
If the dump is not enabled, returns NULL. */
char *
gcc::dump_manager::
get_dump_file_name (struct dump_file_info *dfi) const
{
char dump_id[10];
gcc_assert (dfi);
if (dfi->pstate == 0)
return NULL;
/* If available, use the command line dump filename. */
if (dfi->pfilename)
return xstrdup (dfi->pfilename);
if (dfi->num < 0)
dump_id[0] = '\0';
else
{
/* (null), LANG, TREE, RTL, IPA. */
char suffix = " ltri"[dfi->dkind];
if (snprintf (dump_id, sizeof (dump_id), ".%03d%c", dfi->num, suffix) < 0)
dump_id[0] = '\0';
}
return concat (dump_base_name, dump_id, dfi->suffix, NULL);
}
/* For a given DFI, open an alternate dump filename (which could also
be a standard stream such as stdout/stderr). If the alternate dump
file cannot be opened, return NULL. */
static FILE *
dump_open_alternate_stream (struct dump_file_info *dfi)
{
FILE *stream ;
if (!dfi->alt_filename)
return NULL;
if (dfi->alt_stream)
return dfi->alt_stream;
stream = strcmp ("stderr", dfi->alt_filename) == 0
? stderr
: strcmp ("stdout", dfi->alt_filename) == 0
? stdout
: fopen (dfi->alt_filename, dfi->alt_state < 0 ? "w" : "a");
if (!stream)
error ("could not open dump file %qs: %m", dfi->alt_filename);
else
dfi->alt_state = 1;
return stream;
}
/* Print source location on DFILE if enabled. */
void
dump_loc (dump_flags_t dump_kind, FILE *dfile, source_location loc)
{
if (dump_kind)
{
if (LOCATION_LOCUS (loc) > BUILTINS_LOCATION)
fprintf (dfile, "%s:%d:%d: note: ", LOCATION_FILE (loc),
LOCATION_LINE (loc), LOCATION_COLUMN (loc));
else if (current_function_decl)
fprintf (dfile, "%s:%d:%d: note: ",
DECL_SOURCE_FILE (current_function_decl),
DECL_SOURCE_LINE (current_function_decl),
DECL_SOURCE_COLUMN (current_function_decl));
}
}
/* Dump gimple statement GS with SPC indentation spaces and
EXTRA_DUMP_FLAGS on the dump streams if DUMP_KIND is enabled. */
void
dump_gimple_stmt (dump_flags_t dump_kind, dump_flags_t extra_dump_flags,
gimple *gs, int spc)
{
if (dump_file && (dump_kind & pflags))
print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
if (alt_dump_file && (dump_kind & alt_flags))
print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
}
/* Similar to dump_gimple_stmt, except additionally print source location. */
void
dump_gimple_stmt_loc (dump_flags_t dump_kind, source_location loc,
dump_flags_t extra_dump_flags, gimple *gs, int spc)
{
if (dump_file && (dump_kind & pflags))
{
dump_loc (dump_kind, dump_file, loc);
print_gimple_stmt (dump_file, gs, spc, dump_flags | extra_dump_flags);
}
if (alt_dump_file && (dump_kind & alt_flags))
{
dump_loc (dump_kind, alt_dump_file, loc);
print_gimple_stmt (alt_dump_file, gs, spc, dump_flags | extra_dump_flags);
}
}
/* Dump expression tree T using EXTRA_DUMP_FLAGS on dump streams if
DUMP_KIND is enabled. */
void
dump_generic_expr (dump_flags_t dump_kind, dump_flags_t extra_dump_flags,
tree t)
{
if (dump_file && (dump_kind & pflags))
print_generic_expr (dump_file, t, dump_flags | extra_dump_flags);
if (alt_dump_file && (dump_kind & alt_flags))
print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags);
}
/* Similar to dump_generic_expr, except additionally print the source
location. */
void
dump_generic_expr_loc (int dump_kind, source_location loc,
dump_flags_t extra_dump_flags, tree t)
{
if (dump_file && (dump_kind & pflags))
{
dump_loc (dump_kind, dump_file, loc);
print_generic_expr (dump_file, t, dump_flags | extra_dump_flags);
}
if (alt_dump_file && (dump_kind & alt_flags))
{
dump_loc (dump_kind, alt_dump_file, loc);
print_generic_expr (alt_dump_file, t, dump_flags | extra_dump_flags);
}
}
/* Output a formatted message using FORMAT on appropriate dump streams. */
void
dump_printf (dump_flags_t dump_kind, const char *format, ...)
{
if (dump_file && (dump_kind & pflags))
{
va_list ap;
va_start (ap, format);
vfprintf (dump_file, format, ap);
va_end (ap);
}
if (alt_dump_file && (dump_kind & alt_flags))
{
va_list ap;
va_start (ap, format);
vfprintf (alt_dump_file, format, ap);
va_end (ap);
}
}
/* Similar to dump_printf, except source location is also printed. */
void
dump_printf_loc (dump_flags_t dump_kind, source_location loc,
const char *format, ...)
{
if (dump_file && (dump_kind & pflags))
{
va_list ap;
dump_loc (dump_kind, dump_file, loc);
va_start (ap, format);
vfprintf (dump_file, format, ap);
va_end (ap);
}
if (alt_dump_file && (dump_kind & alt_flags))
{
va_list ap;
dump_loc (dump_kind, alt_dump_file, loc);
va_start (ap, format);
vfprintf (alt_dump_file, format, ap);
va_end (ap);
}
}
/* Output VALUE in decimal to appropriate dump streams. */
template<unsigned int N, typename C>
void
dump_dec (int dump_kind, const poly_int<N, C> &value)
{
STATIC_ASSERT (poly_coeff_traits<C>::signedness >= 0);
signop sgn = poly_coeff_traits<C>::signedness ? SIGNED : UNSIGNED;
if (dump_file && (dump_kind & pflags))
print_dec (value, dump_file, sgn);
if (alt_dump_file && (dump_kind & alt_flags))
print_dec (value, alt_dump_file, sgn);
}
template void dump_dec (int, const poly_uint16 &);
template void dump_dec (int, const poly_int64 &);
template void dump_dec (int, const poly_uint64 &);
template void dump_dec (int, const poly_offset_int &);
template void dump_dec (int, const poly_widest_int &);
/* Start a dump for PHASE. Store user-supplied dump flags in
*FLAG_PTR. Return the number of streams opened. Set globals
DUMP_FILE, and ALT_DUMP_FILE to point to the opened streams, and
set dump_flags appropriately for both pass dump stream and
-fopt-info stream. */
int
gcc::dump_manager::
dump_start (int phase, dump_flags_t *flag_ptr)
{
int count = 0;
char *name;
struct dump_file_info *dfi;
FILE *stream;
if (phase == TDI_none || !dump_phase_enabled_p (phase))
return 0;
dfi = get_dump_file_info (phase);
name = get_dump_file_name (phase);
if (name)
{
stream = strcmp ("stderr", name) == 0
? stderr
: strcmp ("stdout", name) == 0
? stdout
: fopen (name, dfi->pstate < 0 ? "w" : "a");
if (!stream)
error ("could not open dump file %qs: %m", name);
else
{
dfi->pstate = 1;
count++;
}
free (name);
dfi->pstream = stream;
dump_file = dfi->pstream;
/* Initialize current dump flags. */
pflags = dfi->pflags;
}
stream = dump_open_alternate_stream (dfi);
if (stream)
{
dfi->alt_stream = stream;
count++;
alt_dump_file = dfi->alt_stream;
/* Initialize current -fopt-info flags. */
alt_flags = dfi->alt_flags;
}
if (flag_ptr)
*flag_ptr = dfi->pflags;
return count;
}
/* Finish a tree dump for PHASE and close associated dump streams. Also
reset the globals DUMP_FILE, ALT_DUMP_FILE, and DUMP_FLAGS. */
void
gcc::dump_manager::
dump_finish (int phase)
{
struct dump_file_info *dfi;
if (phase < 0)
return;
dfi = get_dump_file_info (phase);
if (dfi->pstream && (!dfi->pfilename
|| (strcmp ("stderr", dfi->pfilename) != 0
&& strcmp ("stdout", dfi->pfilename) != 0)))
fclose (dfi->pstream);
if (dfi->alt_stream && strcmp ("stderr", dfi->alt_filename) != 0
&& strcmp ("stdout", dfi->alt_filename) != 0)
fclose (dfi->alt_stream);
dfi->alt_stream = NULL;
dfi->pstream = NULL;
dump_file = NULL;
alt_dump_file = NULL;
dump_flags = TDI_none;
alt_flags = 0;
pflags = 0;
}
/* Begin a tree dump for PHASE. Stores any user supplied flag in
*FLAG_PTR and returns a stream to write to. If the dump is not
enabled, returns NULL.
Multiple calls will reopen and append to the dump file. */
FILE *
dump_begin (int phase, dump_flags_t *flag_ptr)
{
return g->get_dumps ()->dump_begin (phase, flag_ptr);
}
FILE *
gcc::dump_manager::
dump_begin (int phase, dump_flags_t *flag_ptr)
{
char *name;
struct dump_file_info *dfi;
FILE *stream;
if (phase == TDI_none || !dump_phase_enabled_p (phase))
return NULL;
name = get_dump_file_name (phase);
if (!name)
return NULL;
dfi = get_dump_file_info (phase);
stream = strcmp ("stderr", name) == 0
? stderr
: strcmp ("stdout", name) == 0
? stdout
: fopen (name, dfi->pstate < 0 ? "w" : "a");
if (!stream)
error ("could not open dump file %qs: %m", name);
else
dfi->pstate = 1;
free (name);
if (flag_ptr)
*flag_ptr = dfi->pflags;
/* Initialize current flags */
pflags = dfi->pflags;
return stream;
}
/* Returns nonzero if dump PHASE is enabled for at least one stream.
If PHASE is TDI_tree_all, return nonzero if any dump is enabled for
any phase. */
int
gcc::dump_manager::
dump_phase_enabled_p (int phase) const
{
if (phase == TDI_tree_all)
{
size_t i;
for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
if (dump_files[i].pstate || dump_files[i].alt_state)
return 1;
for (i = 0; i < m_extra_dump_files_in_use; i++)
if (m_extra_dump_files[i].pstate || m_extra_dump_files[i].alt_state)
return 1;
return 0;
}
else
{
struct dump_file_info *dfi = get_dump_file_info (phase);
return dfi->pstate || dfi->alt_state;
}
}
/* Returns nonzero if tree dump PHASE has been initialized. */
int
gcc::dump_manager::
dump_initialized_p (int phase) const
{
struct dump_file_info *dfi = get_dump_file_info (phase);
return dfi->pstate > 0 || dfi->alt_state > 0;
}
/* Returns the switch name of PHASE. */
const char *
dump_flag_name (int phase)
{
return g->get_dumps ()->dump_flag_name (phase);
}
const char *
gcc::dump_manager::
dump_flag_name (int phase) const
{
struct dump_file_info *dfi = get_dump_file_info (phase);
return dfi->swtch;
}
/* Finish a tree dump for PHASE. STREAM is the stream created by
dump_begin. */
void
dump_end (int phase ATTRIBUTE_UNUSED, FILE *stream)
{
if (stream != stderr && stream != stdout)
fclose (stream);
}
/* Enable all tree dumps with FLAGS on FILENAME. Return number of
enabled tree dumps. */
int
gcc::dump_manager::
dump_enable_all (dump_kind dkind, dump_flags_t flags, const char *filename)
{
int n = 0;
size_t i;
for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
{
if ((dump_files[i].dkind == dkind))
{
const char *old_filename = dump_files[i].pfilename;
dump_files[i].pstate = -1;
dump_files[i].pflags |= flags;
n++;
/* Override the existing filename. */
if (filename)
{
dump_files[i].pfilename = xstrdup (filename);
/* Since it is a command-line provided file, which is
common to all the phases, use it in append mode. */
dump_files[i].pstate = 1;
}
if (old_filename && filename != old_filename)
free (CONST_CAST (char *, old_filename));
}
}
for (i = 0; i < m_extra_dump_files_in_use; i++)
{
if ((m_extra_dump_files[i].dkind == dkind))
{
const char *old_filename = m_extra_dump_files[i].pfilename;
m_extra_dump_files[i].pstate = -1;
m_extra_dump_files[i].pflags |= flags;
n++;
/* Override the existing filename. */
if (filename)
{
m_extra_dump_files[i].pfilename = xstrdup (filename);
/* Since it is a command-line provided file, which is
common to all the phases, use it in append mode. */
m_extra_dump_files[i].pstate = 1;
}
if (old_filename && filename != old_filename)
free (CONST_CAST (char *, old_filename));
}
}
return n;
}
/* Enable -fopt-info dumps on all dump files matching OPTGROUP_FLAGS.
Enable dumps with FLAGS on FILENAME. Return the number of enabled
dumps. */
int
gcc::dump_manager::
opt_info_enable_passes (int optgroup_flags, dump_flags_t flags,
const char *filename)
{
int n = 0;
size_t i;
for (i = TDI_none + 1; i < (size_t) TDI_end; i++)
{
if ((dump_files[i].optgroup_flags & optgroup_flags))
{
const char *old_filename = dump_files[i].alt_filename;
/* Since this file is shared among different passes, it
should be opened in append mode. */
dump_files[i].alt_state = 1;
dump_files[i].alt_flags |= flags;
n++;
/* Override the existing filename. */
if (filename)
dump_files[i].alt_filename = xstrdup (filename);
if (old_filename && filename != old_filename)
free (CONST_CAST (char *, old_filename));
}
}
for (i = 0; i < m_extra_dump_files_in_use; i++)
{
if ((m_extra_dump_files[i].optgroup_flags & optgroup_flags))
{
const char *old_filename = m_extra_dump_files[i].alt_filename;
/* Since this file is shared among different passes, it
should be opened in append mode. */
m_extra_dump_files[i].alt_state = 1;
m_extra_dump_files[i].alt_flags |= flags;
n++;
/* Override the existing filename. */
if (filename)
m_extra_dump_files[i].alt_filename = xstrdup (filename);
if (old_filename && filename != old_filename)
free (CONST_CAST (char *, old_filename));
}
}
return n;
}
/* Parse ARG as a dump switch. Return nonzero if it is, and store the
relevant details in the dump_files array. */
int
gcc::dump_manager::
dump_switch_p_1 (const char *arg, struct dump_file_info *dfi, bool doglob)
{
const char *option_value;
const char *ptr;
dump_flags_t flags;
if (doglob && !dfi->glob)
return 0;
option_value = skip_leading_substring (arg, doglob ? dfi->glob : dfi->swtch);
if (!option_value)
return 0;
if (*option_value && *option_value != '-' && *option_value != '=')
return 0;
ptr = option_value;
flags = 0;
while (*ptr)
{
const struct dump_option_value_info *option_ptr;
const char *end_ptr;
const char *eq_ptr;
unsigned length;
while (*ptr == '-')
ptr++;
end_ptr = strchr (ptr, '-');
eq_ptr = strchr (ptr, '=');
if (eq_ptr && !end_ptr)
end_ptr = eq_ptr;
if (!end_ptr)
end_ptr = ptr + strlen (ptr);
length = end_ptr - ptr;
for (option_ptr = dump_options; option_ptr->name; option_ptr++)
if (strlen (option_ptr->name) == length
&& !memcmp (option_ptr->name, ptr, length))
{
flags |= option_ptr->value;
goto found;
}
if (*ptr == '=')
{
/* Interpret rest of the argument as a dump filename. This
filename overrides other command line filenames. */
if (dfi->pfilename)
free (CONST_CAST (char *, dfi->pfilename));
dfi->pfilename = xstrdup (ptr + 1);
break;
}
else
warning (0, "ignoring unknown option %q.*s in %<-fdump-%s%>",
length, ptr, dfi->swtch);
found:;
ptr = end_ptr;
}
dfi->pstate = -1;
dfi->pflags |= flags;
/* Process -fdump-tree-all and -fdump-rtl-all, by enabling all the
known dumps. */
if (dfi->suffix == NULL)
dump_enable_all (dfi->dkind, dfi->pflags, dfi->pfilename);
return 1;
}
int
gcc::dump_manager::
dump_switch_p (const char *arg)
{
size_t i;
int any = 0;
for (i = TDI_none + 1; i != TDI_end; i++)
any |= dump_switch_p_1 (arg, &dump_files[i], false);
/* Don't glob if we got a hit already */
if (!any)
for (i = TDI_none + 1; i != TDI_end; i++)
any |= dump_switch_p_1 (arg, &dump_files[i], true);
for (i = 0; i < m_extra_dump_files_in_use; i++)
any |= dump_switch_p_1 (arg, &m_extra_dump_files[i], false);
if (!any)
for (i = 0; i < m_extra_dump_files_in_use; i++)
any |= dump_switch_p_1 (arg, &m_extra_dump_files[i], true);
return any;
}
/* Parse ARG as a -fopt-info switch and store flags, optgroup_flags
and filename. Return non-zero if it is a recognized switch. */
static int
opt_info_switch_p_1 (const char *arg, dump_flags_t *flags, int *optgroup_flags,
char **filename)
{
const char *option_value;
const char *ptr;
option_value = arg;
ptr = option_value;
*filename = NULL;
*flags = 0;
*optgroup_flags = 0;
if (!ptr)
return 1; /* Handle '-fopt-info' without any additional options. */
while (*ptr)
{
const struct dump_option_value_info *option_ptr;
const char *end_ptr;
const char *eq_ptr;
unsigned length;
while (*ptr == '-')
ptr++;
end_ptr = strchr (ptr, '-');
eq_ptr = strchr (ptr, '=');
if (eq_ptr && !end_ptr)
end_ptr = eq_ptr;
if (!end_ptr)
end_ptr = ptr + strlen (ptr);
length = end_ptr - ptr;
for (option_ptr = optinfo_verbosity_options; option_ptr->name;
option_ptr++)
if (strlen (option_ptr->name) == length
&& !memcmp (option_ptr->name, ptr, length))
{
*flags |= option_ptr->value;
goto found;
}
for (option_ptr = optgroup_options; option_ptr->name; option_ptr++)
if (strlen (option_ptr->name) == length
&& !memcmp (option_ptr->name, ptr, length))
{
*optgroup_flags |= option_ptr->value;
goto found;
}
if (*ptr == '=')
{
/* Interpret rest of the argument as a dump filename. This
filename overrides other command line filenames. */
*filename = xstrdup (ptr + 1);
break;
}
else
{
warning (0, "unknown option %q.*s in %<-fopt-info-%s%>",
length, ptr, arg);
return 0;
}
found:;
ptr = end_ptr;
}
return 1;
}
/* Return non-zero if ARG is a recognized switch for
-fopt-info. Return zero otherwise. */
int
opt_info_switch_p (const char *arg)
{
dump_flags_t flags;
int optgroup_flags;
char *filename;
static char *file_seen = NULL;
gcc::dump_manager *dumps = g->get_dumps ();
if (!opt_info_switch_p_1 (arg, &flags, &optgroup_flags, &filename))
return 0;
if (!filename)
filename = xstrdup ("stderr");
/* Bail out if a different filename has been specified. */
if (file_seen && strcmp (file_seen, filename))
{
warning (0, "ignoring possibly conflicting option %<-fopt-info-%s%>",
arg);
return 1;
}
file_seen = xstrdup (filename);
if (!flags)
flags = MSG_OPTIMIZED_LOCATIONS;
if (!optgroup_flags)
optgroup_flags = OPTGROUP_ALL;
return dumps->opt_info_enable_passes (optgroup_flags, flags, filename);
}
/* Print basic block on the dump streams. */
void
dump_basic_block (int dump_kind, basic_block bb, int indent)
{
if (dump_file && (dump_kind & pflags))
dump_bb (dump_file, bb, indent, TDF_DETAILS);
if (alt_dump_file && (dump_kind & alt_flags))
dump_bb (alt_dump_file, bb, indent, TDF_DETAILS);
}
/* Dump FUNCTION_DECL FN as tree dump PHASE. */
void
dump_function (int phase, tree fn)
{
FILE *stream;
dump_flags_t flags;
stream = dump_begin (phase, &flags);
if (stream)
{
dump_function_to_file (fn, stream, flags);
dump_end (phase, stream);
}
}
/* Print information from the combine pass on dump_file. */
void
print_combine_total_stats (void)
{
if (dump_file)
dump_combine_total_stats (dump_file);
}
/* Enable RTL dump for all the RTL passes. */
bool
enable_rtl_dump_file (void)
{
gcc::dump_manager *dumps = g->get_dumps ();
int num_enabled =
dumps->dump_enable_all (DK_rtl, dump_flags_t (TDF_DETAILS) | TDF_BLOCKS,
NULL);
return num_enabled > 0;
}