/* Top level of GCC compilers (cc1, cc1plus, etc.)
- Copyright (C) 1987-2013 Free Software Foundation, Inc.
+ Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GCC.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-#include "line-map.h"
-#include "hash-table.h"
-#include "input.h"
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
+#include "varasm.h"
#include "rtl.h"
#include "tm_p.h"
#include "flags.h"
#include "except.h"
#include "function.h"
#include "toplev.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "calls.h"
+#include "emit-rtl.h"
+#include "stmt.h"
#include "expr.h"
+#include "predict.h"
#include "basic-block.h"
#include "intl.h"
-#include "ggc.h"
#include "graph.h"
#include "regs.h"
#include "diagnostic-core.h"
#include "langhooks.h"
#include "cfgloop.h"
#include "hosthooks.h"
-#include "cgraph.h"
#include "opts.h"
#include "coverage.h"
#include "value-prof.h"
#include "tree-inline.h"
-#include "tree-flow.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "gimple-expr.h"
+#include "gimple.h"
+#include "gimple-ssa.h"
+#include "tree-cfg.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
+#include "tree-ssa-loop-manip.h"
+#include "tree-into-ssa.h"
+#include "tree-dfa.h"
+#include "tree-ssa.h"
#include "tree-pass.h"
#include "tree-dump.h"
#include "df.h"
-#include "predict.h"
+#include "cgraph.h"
#include "lto-streamer.h"
#include "plugin.h"
#include "ipa-utils.h"
#include "tree-pretty-print.h" /* for dump_function_header */
#include "context.h"
#include "pass_manager.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfgrtl.h"
+#include "tree-ssa-live.h" /* For remove_unused_locals. */
+#include "tree-cfgcleanup.h"
using namespace gcc;
/* This is used for debugging. It allows the current pass to printed
from anywhere in compilation.
The variable current_pass is also used for statistics and plugins. */
-struct opt_pass *current_pass;
+opt_pass *current_pass;
-static void register_pass_name (struct opt_pass *, const char *);
+static void register_pass_name (opt_pass *, const char *);
/* Most passes are single-instance (within their context) and thus don't
need to implement cloning, but passes that support multiple instances
}
bool
-opt_pass::gate ()
+opt_pass::gate (function *)
{
return true;
}
unsigned int
-opt_pass::execute ()
+opt_pass::execute (function *)
{
return 0;
}
-opt_pass::opt_pass(const pass_data &data, context *ctxt)
- : pass_data(data),
- sub(NULL),
- next(NULL),
- static_pass_number(0),
- ctxt_(ctxt)
+opt_pass::opt_pass (const pass_data &data, context *ctxt)
+ : pass_data (data),
+ sub (NULL),
+ next (NULL),
+ static_pass_number (0),
+ m_ctxt (ctxt)
{
}
void
pass_manager::execute_early_local_passes ()
{
- execute_pass_list (pass_early_local_passes_1->sub);
+ execute_pass_list (cfun, pass_build_ssa_passes_1->sub);
+ if (flag_check_pointer_bounds)
+ execute_pass_list (cfun, pass_chkp_instrumentation_passes_1->sub);
+ execute_pass_list (cfun, pass_local_optimization_passes_1->sub);
}
unsigned int
pass_manager::execute_pass_mode_switching ()
{
- return pass_mode_switching_1->execute ();
+ return pass_mode_switching_1->execute (cfun);
}
int top_level,
int at_end)
{
+ bool finalize = true;
+
/* We deferred calling assemble_alias so that we could collect
other attributes such as visibility. Emit the alias now. */
if (!in_lto_p)
DECL_EXTERNAL (decl) = 0;
TREE_STATIC (decl) = 1;
assemble_alias (decl, alias);
+ finalize = false;
}
}
rebuild it. */
if (in_lto_p && !at_end)
;
- else if (TREE_CODE (decl) != FUNCTION_DECL)
- varpool_finalize_decl (decl);
+ else if (finalize && TREE_CODE (decl) != FUNCTION_DECL)
+ varpool_node::finalize_decl (decl);
}
#ifdef ASM_FINISH_DECLARE_OBJECT
;
else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)
&& TREE_STATIC (decl))
- varpool_node_for_decl (decl);
+ varpool_node::get_create (decl);
+
+ /* Generate early debug for global variables. Any local variables will
+ be handled by either handling reachable functions from
+ finalize_compilation_unit (and by consequence, locally scoped
+ symbols), or by rest_of_type_compilation below.
+
+ Also, pick up function prototypes, which will be mostly ignored
+ by the different early_global_decl() hooks, but will at least be
+ used by Go's hijack of the debug_hooks to implement
+ -fdump-go-spec. */
+ if (!in_lto_p
+ && (TREE_CODE (decl) != FUNCTION_DECL
+ /* This will pick up function prototypes with no bodies,
+ which are not visible in finalize_compilation_unit()
+ while iterating with FOR_EACH_*_FUNCTION through the
+ symbol table. */
+ || !DECL_SAVED_TREE (decl))
+
+ /* We need to check both decl_function_context and
+ current_function_decl here to make sure local extern
+ declarations end up with the correct context.
+
+ For local extern declarations, decl_function_context is
+ empty, but current_function_decl is set to the function where
+ the extern was declared . Without the check for
+ !current_function_decl below, the local extern ends up
+ incorrectly with a top-level context.
+
+ For example:
+
+ namespace S
+ {
+ int
+ f()
+ {
+ {
+ int i = 42;
+ {
+ extern int i; // Local extern declaration.
+ return i;
+ }
+ }
+ }
+ }
+ */
+ && !decl_function_context (decl)
+ && !current_function_decl
+ && DECL_SOURCE_LOCATION (decl) != BUILTINS_LOCATION
+ && !decl_type_context (decl))
+ (*debug_hooks->early_global_decl) (decl);
}
/* Called after finishing a record, union or enumeral type. */
int i;
struct dump_file_info *dfi;
char *name;
+ gcc::dump_manager *dumps = m_ctxt->get_dumps ();
timevar_push (TV_DUMP);
if (profile_arc_flag || flag_test_coverage || flag_branch_probabilities)
{
- dump_start (pass_profile_1->static_pass_number, NULL);
+ dumps->dump_start (pass_profile_1->static_pass_number, NULL);
end_branch_prob ();
- dump_finish (pass_profile_1->static_pass_number);
+ dumps->dump_finish (pass_profile_1->static_pass_number);
}
if (optimize > 0)
{
- dump_start (pass_profile_1->static_pass_number, NULL);
+ dumps->dump_start (pass_profile_1->static_pass_number, NULL);
print_combine_total_stats ();
- dump_finish (pass_profile_1->static_pass_number);
+ dumps->dump_finish (pass_profile_1->static_pass_number);
}
/* Do whatever is necessary to finish printing the graphs. */
- for (i = TDI_end; (dfi = get_dump_file_info (i)) != NULL; ++i)
- if (dump_initialized_p (i)
+ for (i = TDI_end; (dfi = dumps->get_dump_file_info (i)) != NULL; ++i)
+ if (dumps->dump_initialized_p (i)
&& (dfi->pflags & TDF_GRAPH) != 0
- && (name = get_dump_file_name (i)) != NULL)
+ && (name = dumps->get_dump_file_name (i)) != NULL)
{
finish_graph_dump_file (name);
free (name);
}
static unsigned int
-execute_all_early_local_passes (void)
+execute_build_ssa_passes (void)
{
/* Once this pass (and its sub-passes) are complete, all functions
will be in SSA form. Technically this state change is happening
none of the sub-passes are IPA passes and do not create new
functions, this is ok. We're setting this value for the benefit
of IPA passes that follow. */
- if (cgraph_state < CGRAPH_STATE_IPA_SSA)
- cgraph_state = CGRAPH_STATE_IPA_SSA;
+ if (symtab->state < IPA_SSA)
+ symtab->state = IPA_SSA;
return 0;
}
-/* Gate: execute, or not, all of the non-trivial optimizations. */
+namespace {
-static bool
-gate_all_early_local_passes (void)
+const pass_data pass_data_build_ssa_passes =
{
- /* Don't bother doing anything if the program has errors. */
- return (!seen_error () && !in_lto_p);
-}
+ SIMPLE_IPA_PASS, /* type */
+ "build_ssa_passes", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_EARLY_LOCAL, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ /* todo_flags_finish is executed before subpases. For this reason
+ it makes no sense to remove unreachable functions here. */
+ 0, /* todo_flags_finish */
+};
-namespace {
+class pass_build_ssa_passes : public simple_ipa_opt_pass
+{
+public:
+ pass_build_ssa_passes (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_build_ssa_passes, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *)
+ {
+ /* Don't bother doing anything if the program has errors. */
+ return (!seen_error () && !in_lto_p);
+ }
+
+ virtual unsigned int execute (function *)
+ {
+ return execute_build_ssa_passes ();
+ }
-const pass_data pass_data_early_local_passes =
+}; // class pass_build_ssa_passes
+
+const pass_data pass_data_chkp_instrumentation_passes =
{
SIMPLE_IPA_PASS, /* type */
- "early_local_cleanups", /* name */
+ "chkp_passes", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- TV_EARLY_LOCAL, /* tv_id */
+ TV_NONE, /* tv_id */
+ 0, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
+
+class pass_chkp_instrumentation_passes : public simple_ipa_opt_pass
+{
+public:
+ pass_chkp_instrumentation_passes (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_chkp_instrumentation_passes, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *)
+ {
+ /* Don't bother doing anything if the program has errors. */
+ return (flag_check_pointer_bounds
+ && !seen_error () && !in_lto_p);
+ }
+
+}; // class pass_chkp_instrumentation_passes
+
+const pass_data pass_data_local_optimization_passes =
+{
+ SIMPLE_IPA_PASS, /* type */
+ "opt_local_passes", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_remove_functions, /* todo_flags_finish */
+ 0, /* todo_flags_finish */
};
-class pass_early_local_passes : public simple_ipa_opt_pass
+class pass_local_optimization_passes : public simple_ipa_opt_pass
{
public:
- pass_early_local_passes(gcc::context *ctxt)
- : simple_ipa_opt_pass(pass_data_early_local_passes, ctxt)
+ pass_local_optimization_passes (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_local_optimization_passes, ctxt)
{}
/* opt_pass methods: */
- bool gate () { return gate_all_early_local_passes (); }
- unsigned int execute () { return execute_all_early_local_passes (); }
+ virtual bool gate (function *)
+ {
+ /* Don't bother doing anything if the program has errors. */
+ return (!seen_error () && !in_lto_p);
+ }
-}; // class pass_early_local_passes
+}; // class pass_local_optimization_passes
} // anon namespace
simple_ipa_opt_pass *
-make_pass_early_local_passes (gcc::context *ctxt)
+make_pass_build_ssa_passes (gcc::context *ctxt)
{
- return new pass_early_local_passes (ctxt);
+ return new pass_build_ssa_passes (ctxt);
}
-/* Gate: execute, or not, all of the non-trivial optimizations. */
+simple_ipa_opt_pass *
+make_pass_chkp_instrumentation_passes (gcc::context *ctxt)
+{
+ return new pass_chkp_instrumentation_passes (ctxt);
+}
-static bool
-gate_all_early_optimizations (void)
+simple_ipa_opt_pass *
+make_pass_local_optimization_passes (gcc::context *ctxt)
{
- return (optimize >= 1
- /* Don't bother doing anything if the program has errors. */
- && !seen_error ());
+ return new pass_local_optimization_passes (ctxt);
}
namespace {
GIMPLE_PASS, /* type */
"early_optimizations", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
- false, /* has_execute */
TV_NONE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
class pass_all_early_optimizations : public gimple_opt_pass
{
public:
- pass_all_early_optimizations(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_all_early_optimizations, ctxt)
+ pass_all_early_optimizations (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_all_early_optimizations, ctxt)
{}
/* opt_pass methods: */
- bool gate () { return gate_all_early_optimizations (); }
+ virtual bool gate (function *)
+ {
+ return (optimize >= 1
+ /* Don't bother doing anything if the program has errors. */
+ && !seen_error ());
+ }
}; // class pass_all_early_optimizations
return new pass_all_early_optimizations (ctxt);
}
-/* Gate: execute, or not, all of the non-trivial optimizations. */
-
-static bool
-gate_all_optimizations (void)
-{
- return optimize >= 1 && !optimize_debug;
-}
-
namespace {
const pass_data pass_data_all_optimizations =
GIMPLE_PASS, /* type */
"*all_optimizations", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
- false, /* has_execute */
TV_OPTIMIZE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
class pass_all_optimizations : public gimple_opt_pass
{
public:
- pass_all_optimizations(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_all_optimizations, ctxt)
+ pass_all_optimizations (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_all_optimizations, ctxt)
{}
/* opt_pass methods: */
- bool gate () { return gate_all_optimizations (); }
+ virtual bool gate (function *) { return optimize >= 1 && !optimize_debug; }
}; // class pass_all_optimizations
return new pass_all_optimizations (ctxt);
}
-/* Gate: execute, or not, all of the non-trivial optimizations. */
-
-static bool
-gate_all_optimizations_g (void)
-{
- return optimize >= 1 && optimize_debug;
-}
-
namespace {
const pass_data pass_data_all_optimizations_g =
GIMPLE_PASS, /* type */
"*all_optimizations_g", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
- false, /* has_execute */
TV_OPTIMIZE, /* tv_id */
0, /* properties_required */
0, /* properties_provided */
class pass_all_optimizations_g : public gimple_opt_pass
{
public:
- pass_all_optimizations_g(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_all_optimizations_g, ctxt)
+ pass_all_optimizations_g (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_all_optimizations_g, ctxt)
{}
/* opt_pass methods: */
- bool gate () { return gate_all_optimizations_g (); }
+ virtual bool gate (function *) { return optimize >= 1 && optimize_debug; }
}; // class pass_all_optimizations_g
return new pass_all_optimizations_g (ctxt);
}
-static bool
-gate_rest_of_compilation (void)
-{
- /* Early return if there were errors. We can run afoul of our
- consistency checks, and there's not really much point in fixing them. */
- return !(rtl_dump_and_exit || flag_syntax_only || seen_error ());
-}
-
namespace {
const pass_data pass_data_rest_of_compilation =
RTL_PASS, /* type */
"*rest_of_compilation", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
- false, /* has_execute */
TV_REST_OF_COMPILATION, /* tv_id */
PROP_rtl, /* properties_required */
0, /* properties_provided */
class pass_rest_of_compilation : public rtl_opt_pass
{
public:
- pass_rest_of_compilation(gcc::context *ctxt)
- : rtl_opt_pass(pass_data_rest_of_compilation, ctxt)
+ pass_rest_of_compilation (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_rest_of_compilation, ctxt)
{}
/* opt_pass methods: */
- bool gate () { return gate_rest_of_compilation (); }
+ virtual bool gate (function *)
+ {
+ /* Early return if there were errors. We can run afoul of our
+ consistency checks, and there's not really much point in fixing them. */
+ return !(rtl_dump_and_exit || flag_syntax_only || seen_error ());
+ }
}; // class pass_rest_of_compilation
return new pass_rest_of_compilation (ctxt);
}
-static bool
-gate_postreload (void)
-{
- return reload_completed;
-}
-
namespace {
const pass_data pass_data_postreload =
RTL_PASS, /* type */
"*all-postreload", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
- false, /* has_execute */
TV_POSTRELOAD, /* tv_id */
PROP_rtl, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_verify_rtl_sharing, /* todo_flags_finish */
+ 0, /* todo_flags_finish */
};
class pass_postreload : public rtl_opt_pass
{
public:
- pass_postreload(gcc::context *ctxt)
- : rtl_opt_pass(pass_data_postreload, ctxt)
+ pass_postreload (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_postreload, ctxt)
{}
/* opt_pass methods: */
- bool gate () { return gate_postreload (); }
+ virtual bool gate (function *) { return reload_completed; }
}; // class pass_postreload
return new pass_postreload (ctxt);
}
+namespace {
+
+const pass_data pass_data_late_compilation =
+{
+ RTL_PASS, /* type */
+ "*all-late_compilation", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ TV_LATE_COMPILATION, /* tv_id */
+ PROP_rtl, /* properties_required */
+ 0, /* properties_provided */
+ 0, /* properties_destroyed */
+ 0, /* todo_flags_start */
+ 0, /* todo_flags_finish */
+};
+
+class pass_late_compilation : public rtl_opt_pass
+{
+public:
+ pass_late_compilation (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_late_compilation, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *)
+ {
+ return reload_completed || targetm.no_register_allocation;
+ }
+
+}; // class pass_late_compilation
+
+} // anon namespace
+
+static rtl_opt_pass *
+make_pass_late_compilation (gcc::context *ctxt)
+{
+ return new pass_late_compilation (ctxt);
+}
+
/* Set the static pass number of pass PASS to ID and record that
void
pass_manager::
-set_pass_for_id (int id, struct opt_pass *pass)
+set_pass_for_id (int id, opt_pass *pass)
{
pass->static_pass_number = id;
if (passes_by_id_size <= id)
{
- passes_by_id = XRESIZEVEC (struct opt_pass *, passes_by_id, id + 1);
+ passes_by_id = XRESIZEVEC (opt_pass *, passes_by_id, id + 1);
memset (passes_by_id + passes_by_id_size, 0,
(id + 1 - passes_by_id_size) * sizeof (void *));
passes_by_id_size = id + 1;
/* Return the pass with the static pass number ID. */
-struct opt_pass *
+opt_pass *
pass_manager::get_pass_for_id (int id) const
{
if (id >= passes_by_id_size)
enabled or not. */
void
-register_one_dump_file (struct opt_pass *pass)
+register_one_dump_file (opt_pass *pass)
{
g->get_passes ()->register_one_dump_file (pass);
}
void
-pass_manager::register_one_dump_file (struct opt_pass *pass)
+pass_manager::register_one_dump_file (opt_pass *pass)
{
char *dot_name, *flag_name, *glob_name;
const char *name, *full_name, *prefix;
char num[10];
int flags, id;
int optgroup_flags = OPTGROUP_NONE;
+ gcc::dump_manager *dumps = m_ctxt->get_dumps ();
/* See below in next_pass_1. */
num[0] = '\0';
flag_name = concat (prefix, name, num, NULL);
glob_name = concat (prefix, name, NULL);
optgroup_flags |= pass->optinfo_flags;
- id = dump_register (dot_name, flag_name, glob_name, flags, optgroup_flags);
+ /* For any passes that do not have an optgroup set, and which are not
+ IPA passes setup above, set the optgroup to OPTGROUP_OTHER so that
+ any dump messages are emitted properly under -fopt-info(-optall). */
+ if (optgroup_flags == OPTGROUP_NONE)
+ optgroup_flags = OPTGROUP_OTHER;
+ id = dumps->dump_register (dot_name, flag_name, glob_name, flags,
+ optgroup_flags,
+ true);
set_pass_for_id (id, pass);
full_name = concat (prefix, pass->name, num, NULL);
register_pass_name (pass, full_name);
free (CONST_CAST (char *, full_name));
}
-/* Recursive worker function for register_dump_files. */
+/* Register the dump files for the pass_manager starting at PASS. */
-int
-pass_manager::
-register_dump_files_1 (struct opt_pass *pass, int properties)
+void
+pass_manager::register_dump_files (opt_pass *pass)
{
do
{
- int new_properties = (properties | pass->properties_provided)
- & ~pass->properties_destroyed;
-
if (pass->name && pass->name[0] != '*')
register_one_dump_file (pass);
if (pass->sub)
- new_properties = register_dump_files_1 (pass->sub, new_properties);
-
- /* If we have a gate, combine the properties that we could have with
- and without the pass being examined. */
- if (pass->has_gate)
- properties &= new_properties;
- else
- properties = new_properties;
+ register_dump_files (pass->sub);
pass = pass->next;
}
while (pass);
-
- return properties;
}
-/* Register the dump files for the pass_manager starting at PASS.
- PROPERTIES reflects the properties that are guaranteed to be available at
- the beginning of the pipeline. */
-
-void
-pass_manager::
-register_dump_files (struct opt_pass *pass,int properties)
-{
- pass->properties_required |= properties;
- register_dump_files_1 (pass, properties);
-}
-
-struct pass_registry
-{
- const char* unique_name;
- struct opt_pass *pass;
-};
-
-/* Helper for pass_registry hash table. */
-
-struct pass_registry_hasher : typed_noop_remove <pass_registry>
-{
- typedef pass_registry value_type;
- typedef pass_registry compare_type;
- static inline hashval_t hash (const value_type *);
- static inline bool equal (const value_type *, const compare_type *);
-};
-
-/* Pass registry hash function. */
-
-inline hashval_t
-pass_registry_hasher::hash (const value_type *s)
-{
- return htab_hash_string (s->unique_name);
-}
-
-/* Hash equal function */
-
-inline bool
-pass_registry_hasher::equal (const value_type *s1, const compare_type *s2)
-{
- return !strcmp (s1->unique_name, s2->unique_name);
-}
-
-static hash_table <pass_registry_hasher> name_to_pass_map;
+static hash_map<nofree_string_hash, opt_pass *> *name_to_pass_map;
/* Register PASS with NAME. */
static void
-register_pass_name (struct opt_pass *pass, const char *name)
+register_pass_name (opt_pass *pass, const char *name)
{
- struct pass_registry **slot;
- struct pass_registry pr;
-
- if (!name_to_pass_map.is_created ())
- name_to_pass_map.create (256);
-
- pr.unique_name = name;
- slot = name_to_pass_map.find_slot (&pr, INSERT);
- if (!*slot)
- {
- struct pass_registry *new_pr;
+ if (!name_to_pass_map)
+ name_to_pass_map = new hash_map<nofree_string_hash, opt_pass *> (256);
- new_pr = XCNEW (struct pass_registry);
- new_pr->unique_name = xstrdup (name);
- new_pr->pass = pass;
- *slot = new_pr;
- }
- else
+ if (name_to_pass_map->get (name))
return; /* Ignore plugin passes. */
+
+ const char *unique_name = xstrdup (name);
+ name_to_pass_map->put (unique_name, pass);
}
/* Map from pass id to canonicalized pass name. */
/* Callback function for traversing NAME_TO_PASS_MAP. */
-int
-passes_pass_traverse (pass_registry **p, void *data ATTRIBUTE_UNUSED)
+bool
+passes_pass_traverse (const char *const &name, opt_pass *const &pass, void *)
{
- struct opt_pass *pass = (*p)->pass;
-
gcc_assert (pass->static_pass_number > 0);
gcc_assert (pass_tab.exists ());
- pass_tab[pass->static_pass_number] = (*p)->unique_name;
+ pass_tab[pass->static_pass_number] = name;
return 1;
}
return;
pass_tab.safe_grow_cleared (g->get_passes ()->passes_by_id_size + 1);
- name_to_pass_map.traverse <void *, passes_pass_traverse> (NULL);
+ name_to_pass_map->traverse <void *, passes_pass_traverse> (NULL);
}
-static bool override_gate_status (struct opt_pass *, tree, bool);
+static bool override_gate_status (opt_pass *, tree, bool);
/* Dump the instantiated name for PASS. IS_ON indicates if PASS
is turned on or not. */
static void
-dump_one_pass (struct opt_pass *pass, int pass_indent)
+dump_one_pass (opt_pass *pass, int pass_indent)
{
int indent = 3 * pass_indent;
const char *pn;
bool is_on, is_really_on;
- is_on = pass->has_gate ? pass->gate() : true;
+ is_on = pass->gate (cfun);
is_really_on = override_gate_status (pass, current_function_decl, is_on);
if (pass->static_pass_number <= 0)
/* Dump pass list PASS with indentation INDENT. */
static void
-dump_pass_list (struct opt_pass *pass, int indent)
+dump_pass_list (opt_pass *pass, int indent)
{
do
{
void
pass_manager::dump_passes () const
{
- struct cgraph_node *n, *node = NULL;
-
- create_pass_tab();
-
- FOR_EACH_FUNCTION (n)
- if (DECL_STRUCT_FUNCTION (n->symbol.decl))
- {
- node = n;
- break;
- }
-
- if (!node)
- return;
+ push_dummy_function (true);
- push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl));
+ create_pass_tab ();
dump_pass_list (all_lowering_passes, 1);
dump_pass_list (all_small_ipa_passes, 1);
dump_pass_list (all_regular_ipa_passes, 1);
- dump_pass_list (all_lto_gen_passes, 1);
dump_pass_list (all_late_ipa_passes, 1);
dump_pass_list (all_passes, 1);
- pop_cfun ();
+ pop_dummy_function ();
}
-
/* Returns the pass with NAME. */
-static struct opt_pass *
+static opt_pass *
get_pass_by_name (const char *name)
{
- struct pass_registry **slot, pr;
-
- pr.unique_name = name;
- slot = name_to_pass_map.find_slot (&pr, NO_INSERT);
-
- if (!slot || !*slot)
- return NULL;
+ opt_pass **p = name_to_pass_map->get (name);
+ if (p)
+ return *p;
- return (*slot)->pass;
+ return NULL;
}
static void
enable_disable_pass (const char *arg, bool is_enable)
{
- struct opt_pass *pass;
+ opt_pass *pass;
char *range_str, *phase_name;
char *argstr = xstrdup (arg);
vec<uid_range_p> *tab = 0;
/* Returns true if PASS is explicitly enabled/disabled for FUNC. */
static bool
-is_pass_explicitly_enabled_or_disabled (struct opt_pass *pass,
+is_pass_explicitly_enabled_or_disabled (opt_pass *pass,
tree func,
vec<uid_range_p> tab)
{
if (!slot)
return false;
- cgraph_uid = func ? cgraph_get_node (func)->uid : 0;
+ cgraph_uid = func ? cgraph_node::get (func)->uid : 0;
if (func && DECL_ASSEMBLER_NAME_SET_P (func))
aname = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (func));
(TDI_end + current value of extra_dump_files_in_use) ) */
static void
-add_pass_instance (struct opt_pass *new_pass, bool track_duplicates,
+add_pass_instance (opt_pass *new_pass, bool track_duplicates,
opt_pass *initial_pass)
{
/* Are we dealing with the first pass of its kind, or a clone? */
/* Add a pass to the pass list. Duplicate the pass if it's already
in the list. */
-static struct opt_pass **
-next_pass_1 (struct opt_pass **list, struct opt_pass *pass,
- struct opt_pass *initial_pass)
+static opt_pass **
+next_pass_1 (opt_pass **list, opt_pass *pass, opt_pass *initial_pass)
{
/* Every pass should have a name so that plugins can refer to them. */
gcc_assert (pass->name != NULL);
struct pass_list_node
{
- struct opt_pass *pass;
+ opt_pass *pass;
struct pass_list_node *next;
};
PASS_LIST - root of the pass list to insert the new pass to */
static bool
-position_pass (struct register_pass_info *new_pass_info,
- struct opt_pass **pass_list)
+position_pass (struct register_pass_info *new_pass_info, opt_pass **pass_list)
{
- struct opt_pass *pass = *pass_list, *prev_pass = NULL;
+ opt_pass *pass = *pass_list, *prev_pass = NULL;
bool success = false;
for ( ; pass; prev_pass = pass, pass = pass->next)
|| (new_pass_info->ref_pass_instance_number == 1
&& pass->todo_flags_start & TODO_mark_first_instance)))
{
- struct opt_pass *new_pass;
+ opt_pass *new_pass;
struct pass_list_node *new_pass_node;
if (new_pass_info->ref_pass_instance_number == 0)
register_pass (struct register_pass_info *pass_info)
{
g->get_passes ()->register_pass (pass_info);
+}
+void
+register_pass (opt_pass* pass, pass_positioning_ops pos,
+ const char* ref_pass_name, int ref_pass_inst_number)
+{
+ register_pass_info i;
+ i.pass = pass;
+ i.reference_pass_name = ref_pass_name;
+ i.ref_pass_instance_number = ref_pass_inst_number;
+ i.pos_op = pos;
+
+ g->get_passes ()->register_pass (&i);
}
void
pass_manager::register_pass (struct register_pass_info *pass_info)
{
bool all_instances, success;
+ gcc::dump_manager *dumps = m_ctxt->get_dumps ();
/* The checks below could fail in buggy plugins. Existing GCC
passes should never fail these checks, so we mention plugin in
the messages. */
if (!pass_info->pass)
- fatal_error ("plugin cannot register a missing pass");
+ fatal_error (input_location, "plugin cannot register a missing pass");
if (!pass_info->pass->name)
- fatal_error ("plugin cannot register an unnamed pass");
+ fatal_error (input_location, "plugin cannot register an unnamed pass");
if (!pass_info->reference_pass_name)
fatal_error
- ("plugin cannot register pass %qs without reference pass name",
+ (input_location,
+ "plugin cannot register pass %qs without reference pass name",
pass_info->pass->name);
/* Try to insert the new pass to the pass lists. We need to check
success |= position_pass (pass_info, &all_small_ipa_passes);
if (!success || all_instances)
success |= position_pass (pass_info, &all_regular_ipa_passes);
- if (!success || all_instances)
- success |= position_pass (pass_info, &all_lto_gen_passes);
if (!success || all_instances)
success |= position_pass (pass_info, &all_late_ipa_passes);
if (!success || all_instances)
success |= position_pass (pass_info, &all_passes);
if (!success)
fatal_error
- ("pass %qs not found but is referenced by new pass %qs",
+ (input_location,
+ "pass %qs not found but is referenced by new pass %qs",
pass_info->reference_pass_name, pass_info->pass->name);
/* OK, we have successfully inserted the new pass. We need to register
else
tdi = TDI_rtl_all;
/* Check if dump-all flag is specified. */
- if (get_dump_file_info (tdi)->pstate)
- get_dump_file_info (added_pass_nodes->pass->static_pass_number)
- ->pstate = get_dump_file_info (tdi)->pstate;
+ if (dumps->get_dump_file_info (tdi)->pstate)
+ dumps->get_dump_file_info (added_pass_nodes->pass->static_pass_number)
+ ->pstate = dumps->get_dump_file_info (tdi)->pstate;
XDELETE (added_pass_nodes);
added_pass_nodes = next_node;
}
return xcalloc (1, sz);
}
+void
+pass_manager::operator delete (void *ptr)
+{
+ free (ptr);
+}
+
pass_manager::pass_manager (context *ctxt)
-: all_passes(NULL), all_small_ipa_passes(NULL), all_lowering_passes(NULL),
- all_regular_ipa_passes(NULL), all_lto_gen_passes(NULL),
- all_late_ipa_passes(NULL), passes_by_id(NULL), passes_by_id_size(0),
- ctxt_(ctxt)
+: all_passes (NULL), all_small_ipa_passes (NULL), all_lowering_passes (NULL),
+ all_regular_ipa_passes (NULL),
+ all_late_ipa_passes (NULL), passes_by_id (NULL), passes_by_id_size (0),
+ m_ctxt (ctxt)
{
- struct opt_pass **p;
+ opt_pass **p;
/* Initialize the pass_lists array. */
#define DEF_PASS_LIST(LIST) pass_lists[PASS_LIST_NO_##LIST] = &LIST;
#define PUSH_INSERT_PASSES_WITHIN(PASS) \
{ \
- struct opt_pass **p = &(PASS ## _1)->sub;
+ opt_pass **p = &(PASS ## _1)->sub;
#define POP_INSERT_PASSES() \
}
do { \
gcc_assert (NULL == PASS ## _ ## NUM); \
if ((NUM) == 1) \
- PASS ## _1 = make_##PASS (ctxt_); \
+ PASS ## _1 = make_##PASS (m_ctxt); \
else \
{ \
gcc_assert (PASS ## _1); \
#undef TERMINATE_PASS_LIST
/* Register the passes with the tree dump code. */
- register_dump_files (all_lowering_passes, PROP_gimple_any);
- register_dump_files (all_small_ipa_passes,
- PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
- | PROP_cfg);
- register_dump_files (all_regular_ipa_passes,
- PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
- | PROP_cfg);
- register_dump_files (all_lto_gen_passes,
- PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
- | PROP_cfg);
- register_dump_files (all_late_ipa_passes,
- PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
- | PROP_cfg);
- register_dump_files (all_passes,
- PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
- | PROP_cfg);
+ register_dump_files (all_lowering_passes);
+ register_dump_files (all_small_ipa_passes);
+ register_dump_files (all_regular_ipa_passes);
+ register_dump_files (all_late_ipa_passes);
+ register_dump_files (all_passes);
+}
+
+static void
+delete_pass_tree (opt_pass *pass)
+{
+ while (pass)
+ {
+ /* Recurse into child passes. */
+ delete_pass_tree (pass->sub);
+
+ opt_pass *next = pass->next;
+
+ /* Delete this pass. */
+ delete pass;
+
+ /* Iterate onto sibling passes. */
+ pass = next;
+ }
+}
+
+pass_manager::~pass_manager ()
+{
+ XDELETEVEC (passes_by_id);
+
+ /* Call delete_pass_tree on each of the pass_lists. */
+#define DEF_PASS_LIST(LIST) \
+ delete_pass_tree (*pass_lists[PASS_LIST_NO_##LIST]);
+ GCC_PASS_LISTS
+#undef DEF_PASS_LIST
+
}
/* If we are in IPA mode (i.e., current_function_decl is NULL), call
call CALLBACK on the current function. */
static void
-do_per_function (void (*callback) (void *data), void *data)
+do_per_function (void (*callback) (function *, void *data), void *data)
{
if (current_function_decl)
- callback (data);
+ callback (cfun, data);
else
{
struct cgraph_node *node;
FOR_EACH_DEFINED_FUNCTION (node)
- if (node->symbol.analyzed && gimple_has_body_p (node->symbol.decl)
- && (!node->clone_of || node->symbol.decl != node->clone_of->symbol.decl))
- {
- push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl));
- callback (data);
- if (!flag_wpa)
- {
- free_dominance_info (CDI_DOMINATORS);
- free_dominance_info (CDI_POST_DOMINATORS);
- }
- pop_cfun ();
- ggc_collect ();
- }
+ if (node->analyzed && (gimple_has_body_p (node->decl) && !in_lto_p)
+ && (!node->clone_of || node->decl != node->clone_of->decl))
+ callback (DECL_STRUCT_FUNCTION (node->decl), data);
}
}
keep the array visible to garbage collector to avoid reading collected
out nodes. */
static int nnodes;
-static GTY ((length ("nnodes"))) cgraph_node_ptr *order;
+static GTY ((length ("nnodes"))) cgraph_node **order;
+
+/* Hook called when NODE is removed and therefore should be
+ excluded from order vector. DATA is an array of integers.
+ DATA[0] holds max index it may be accessed by. For cgraph
+ node DATA[node->uid + 1] holds index of this node in order
+ vector. */
+static void
+remove_cgraph_node_from_order (cgraph_node *node, void *data)
+{
+ int *order_idx = (int *)data;
+
+ if (node->uid >= order_idx[0])
+ return;
+
+ int idx = order_idx[node->uid + 1];
+ if (idx >= 0 && idx < nnodes && order[idx] == node)
+ order[idx] = NULL;
+}
/* If we are in IPA mode (i.e., current_function_decl is NULL), call
function CALLBACK for every function in the call graph. Otherwise,
call CALLBACK on the current function.
This function is global so that plugins can use it. */
void
-do_per_function_toporder (void (*callback) (void *data), void *data)
+do_per_function_toporder (void (*callback) (function *, void *data), void *data)
{
int i;
if (current_function_decl)
- callback (data);
+ callback (cfun, data);
else
{
+ cgraph_node_hook_list *hook;
+ int *order_idx;
gcc_assert (!order);
- order = ggc_alloc_vec_cgraph_node_ptr (cgraph_n_nodes);
+ order = ggc_vec_alloc<cgraph_node *> (symtab->cgraph_count);
+
+ order_idx = XALLOCAVEC (int, symtab->cgraph_max_uid + 1);
+ memset (order_idx + 1, -1, sizeof (int) * symtab->cgraph_max_uid);
+ order_idx[0] = symtab->cgraph_max_uid;
+
nnodes = ipa_reverse_postorder (order);
for (i = nnodes - 1; i >= 0; i--)
- order[i]->process = 1;
+ {
+ order[i]->process = 1;
+ order_idx[order[i]->uid + 1] = i;
+ }
+ hook = symtab->add_cgraph_removal_hook (remove_cgraph_node_from_order,
+ order_idx);
for (i = nnodes - 1; i >= 0; i--)
{
+ /* Function could be inlined and removed as unreachable. */
+ if (!order[i])
+ continue;
+
struct cgraph_node *node = order[i];
/* Allow possibly removed nodes to be garbage collected. */
order[i] = NULL;
node->process = 0;
- if (cgraph_function_with_gimple_body_p (node))
- {
- cgraph_get_body (node);
- push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl));
- callback (data);
- free_dominance_info (CDI_DOMINATORS);
- free_dominance_info (CDI_POST_DOMINATORS);
- pop_cfun ();
- ggc_collect ();
- }
+ if (node->has_gimple_body_p ())
+ callback (DECL_STRUCT_FUNCTION (node->decl), data);
}
+ symtab->remove_cgraph_removal_hook (hook);
}
ggc_free (order);
order = NULL;
/* Helper function to perform function body dump. */
static void
-execute_function_dump (void *data ATTRIBUTE_UNUSED)
+execute_function_dump (function *fn, void *data)
{
- if (dump_file && current_function_decl)
+ opt_pass *pass = (opt_pass *)data;
+
+ if (dump_file)
{
- if (cfun->curr_properties & PROP_trees)
- dump_function_to_file (current_function_decl, dump_file, dump_flags);
+ push_cfun (fn);
+
+ if (fn->curr_properties & PROP_trees)
+ dump_function_to_file (fn->decl, dump_file, dump_flags);
else
print_rtl_with_bb (dump_file, get_insns (), dump_flags);
close the file before aborting. */
fflush (dump_file);
- if ((cfun->curr_properties & PROP_cfg)
+ if ((fn->curr_properties & PROP_cfg)
&& (dump_flags & TDF_GRAPH))
- print_graph_cfg (dump_file_name, cfun);
+ {
+ if (!pass->graph_dump_initialized)
+ {
+ clean_graph_dump_file (dump_file_name);
+ pass->graph_dump_initialized = true;
+ }
+ print_graph_cfg (dump_file_name, fn);
+ }
+
+ pop_cfun ();
}
}
/* Perform all TODO actions that ought to be done on each function. */
static void
-execute_function_todo (void *data)
+execute_function_todo (function *fn, void *data)
{
+ bool from_ipa_pass = (cfun == NULL);
unsigned int flags = (size_t)data;
- flags &= ~cfun->last_verified;
+ flags &= ~fn->last_verified;
if (!flags)
return;
+ push_cfun (fn);
+
/* Always cleanup the CFG before trying to update SSA. */
if (flags & TODO_cleanup_cfg)
{
{
unsigned update_flags = flags & TODO_update_ssa_any;
update_ssa (update_flags);
- cfun->last_verified &= ~TODO_verify_ssa;
}
if (flag_tree_pta && (flags & TODO_rebuild_alias))
rebuild_frequencies ();
if (flags & TODO_rebuild_cgraph_edges)
- rebuild_cgraph_edges ();
+ cgraph_edge::rebuild_edges ();
/* If we've seen errors do not bother running any verifiers. */
- if (seen_error ())
- return;
-
-#if defined ENABLE_CHECKING
- if (flags & TODO_verify_ssa
- || (current_loops && loops_state_satisfies_p (LOOP_CLOSED_SSA)))
+ if (!seen_error ())
{
- verify_gimple_in_cfg (cfun);
- verify_ssa (true);
- }
- else if (flags & TODO_verify_stmts)
- verify_gimple_in_cfg (cfun);
- if (flags & TODO_verify_flow)
- verify_flow_info ();
- if (current_loops && loops_state_satisfies_p (LOOP_CLOSED_SSA))
- verify_loop_closed_ssa (false);
- if (flags & TODO_verify_rtl_sharing)
- verify_rtl_sharing ();
+#if defined ENABLE_CHECKING
+ dom_state pre_verify_state = dom_info_state (fn, CDI_DOMINATORS);
+ dom_state pre_verify_pstate = dom_info_state (fn, CDI_POST_DOMINATORS);
+
+ if (flags & TODO_verify_il)
+ {
+ if (cfun->curr_properties & PROP_trees)
+ {
+ if (cfun->curr_properties & PROP_cfg)
+ /* IPA passes leave stmts to be fixed up, so make sure to
+ not verify stmts really throw. */
+ verify_gimple_in_cfg (cfun, !from_ipa_pass);
+ else
+ verify_gimple_in_seq (gimple_body (cfun->decl));
+ }
+ if (cfun->curr_properties & PROP_ssa)
+ /* IPA passes leave stmts to be fixed up, so make sure to
+ not verify SSA operands whose verifier will choke on that. */
+ verify_ssa (true, !from_ipa_pass);
+ /* IPA passes leave basic-blocks unsplit, so make sure to
+ not trip on that. */
+ if ((cfun->curr_properties & PROP_cfg)
+ && !from_ipa_pass)
+ verify_flow_info ();
+ if (current_loops
+ && loops_state_satisfies_p (LOOP_CLOSED_SSA))
+ verify_loop_closed_ssa (false);
+ if (cfun->curr_properties & PROP_rtl)
+ verify_rtl_sharing ();
+ }
+
+ /* Make sure verifiers don't change dominator state. */
+ gcc_assert (dom_info_state (fn, CDI_DOMINATORS) == pre_verify_state);
+ gcc_assert (dom_info_state (fn, CDI_POST_DOMINATORS) == pre_verify_pstate);
#endif
+ }
- cfun->last_verified = flags & TODO_verify_all;
+ fn->last_verified = flags & TODO_verify_all;
+
+ pop_cfun ();
+
+ /* For IPA passes make sure to release dominator info, it can be
+ computed by non-verifying TODOs. */
+ if (from_ipa_pass)
+ {
+ free_dominance_info (fn, CDI_DOMINATORS);
+ free_dominance_info (fn, CDI_POST_DOMINATORS);
+ }
}
/* Perform all TODO actions. */
statistics_fini_pass ();
- do_per_function (execute_function_todo, (void *)(size_t) flags);
+ if (flags)
+ do_per_function (execute_function_todo, (void *)(size_t) flags);
/* Always remove functions just as before inlining: IPA passes might be
interested to see bodies of extern inline functions that are not inlined
if (flags & TODO_remove_functions)
{
gcc_assert (!cfun);
- symtab_remove_unreachable_nodes (true, dump_file);
+ symtab->remove_unreachable_nodes (dump_file);
}
if ((flags & TODO_dump_symtab) && dump_file && !current_function_decl)
{
gcc_assert (!cfun);
- dump_symtab (dump_file);
+ symtab_node::dump_table (dump_file);
/* Flush the file. If verification fails, we won't be able to
close the file before aborting. */
fflush (dump_file);
/* Clear the last verified flag. */
static void
-clear_last_verified (void *data ATTRIBUTE_UNUSED)
+clear_last_verified (function *fn, void *data ATTRIBUTE_UNUSED)
{
- cfun->last_verified = 0;
+ fn->last_verified = 0;
}
/* Helper function. Verify that the properties has been turn into the
#ifdef ENABLE_CHECKING
static void
-verify_curr_properties (void *data)
+verify_curr_properties (function *fn, void *data)
{
unsigned int props = (size_t)data;
- gcc_assert ((cfun->curr_properties & props) == props);
+ gcc_assert ((fn->curr_properties & props) == props);
}
#endif
/* This is non-static so that the plugins can use it. */
bool
-pass_init_dump_file (struct opt_pass *pass)
+pass_init_dump_file (opt_pass *pass)
{
/* If a dump file name is present, open it if enabled. */
if (pass->static_pass_number != -1)
{
timevar_push (TV_DUMP);
- bool initializing_dump = !dump_initialized_p (pass->static_pass_number);
- dump_file_name = get_dump_file_name (pass->static_pass_number);
- dump_start (pass->static_pass_number, &dump_flags);
+ gcc::dump_manager *dumps = g->get_dumps ();
+ bool initializing_dump =
+ !dumps->dump_initialized_p (pass->static_pass_number);
+ dump_file_name = dumps->get_dump_file_name (pass->static_pass_number);
+ dumps->dump_start (pass->static_pass_number, &dump_flags);
if (dump_file && current_function_decl)
dump_function_header (dump_file, current_function_decl, dump_flags);
if (initializing_dump
&& dump_file && (dump_flags & TDF_GRAPH)
&& cfun && (cfun->curr_properties & PROP_cfg))
- clean_graph_dump_file (dump_file_name);
+ {
+ clean_graph_dump_file (dump_file_name);
+ pass->graph_dump_initialized = true;
+ }
timevar_pop (TV_DUMP);
return initializing_dump;
}
/* This is non-static so that plugins can use it. */
void
-pass_fini_dump_file (struct opt_pass *pass)
+pass_fini_dump_file (opt_pass *pass)
{
timevar_push (TV_DUMP);
dump_file_name = NULL;
}
- dump_finish (pass->static_pass_number);
+ g->get_dumps ()->dump_finish (pass->static_pass_number);
timevar_pop (TV_DUMP);
}
properties. */
static void
-update_properties_after_pass (void *data)
+update_properties_after_pass (function *fn, void *data)
{
- struct opt_pass *pass = (struct opt_pass *) data;
- cfun->curr_properties = (cfun->curr_properties | pass->properties_provided)
- & ~pass->properties_destroyed;
+ opt_pass *pass = (opt_pass *) data;
+ fn->curr_properties = (fn->curr_properties | pass->properties_provided)
+ & ~pass->properties_destroyed;
}
/* Execute summary generation for all of the passes in IPA_PASS. */
void
-execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass)
+execute_ipa_summary_passes (ipa_opt_pass_d *ipa_pass)
{
while (ipa_pass)
{
- struct opt_pass *pass = ipa_pass;
+ opt_pass *pass = ipa_pass;
/* Execute all of the IPA_PASSes in the list. */
if (ipa_pass->type == IPA_PASS
- && ((!pass->has_gate) || pass->gate ())
+ && pass->gate (cfun)
&& ipa_pass->generate_summary)
{
pass_init_dump_file (pass);
if (pass->tv_id)
timevar_push (pass->tv_id);
+ current_pass = pass;
ipa_pass->generate_summary ();
/* Stop timevar. */
pass_fini_dump_file (pass);
}
- ipa_pass = (struct ipa_opt_pass_d *)ipa_pass->next;
+ ipa_pass = (ipa_opt_pass_d *)ipa_pass->next;
}
}
static void
execute_one_ipa_transform_pass (struct cgraph_node *node,
- struct ipa_opt_pass_d *ipa_pass)
+ ipa_opt_pass_d *ipa_pass)
{
- struct opt_pass *pass = ipa_pass;
+ opt_pass *pass = ipa_pass;
unsigned int todo_after = 0;
current_pass = pass;
if (profile_report && cfun && (cfun->curr_properties & PROP_cfg))
check_profile_consistency (pass->static_pass_number, 1, true);
- do_per_function (execute_function_dump, NULL);
+ if (dump_file)
+ do_per_function (execute_function_dump, NULL);
pass_fini_dump_file (pass);
current_pass = NULL;
struct cgraph_node *node;
if (!cfun)
return;
- node = cgraph_get_node (current_function_decl);
+ node = cgraph_node::get (current_function_decl);
if (node->ipa_transforms_to_apply.exists ())
{
}
}
-/* Callback for do_per_function to apply all IPA transforms. */
-
-static void
-apply_ipa_transforms (void *data)
-{
- struct cgraph_node *node = cgraph_get_node (current_function_decl);
- if (!node->global.inlined_to && node->ipa_transforms_to_apply.exists ())
- {
- *(bool *)data = true;
- execute_all_ipa_transforms();
- rebuild_cgraph_edges ();
- }
-}
-
/* Check if PASS is explicitly disabled or enabled and return
the gate status. FUNC is the function to be processed, and
GATE_STATUS is the gate status determined by pass manager by
default. */
static bool
-override_gate_status (struct opt_pass *pass, tree func, bool gate_status)
+override_gate_status (opt_pass *pass, tree func, bool gate_status)
{
bool explicitly_enabled = false;
bool explicitly_disabled = false;
/* Execute PASS. */
bool
-execute_one_pass (struct opt_pass *pass)
+execute_one_pass (opt_pass *pass)
{
unsigned int todo_after = 0;
/* Check whether gate check should be avoided.
User controls the value of the gate through the parameter "gate_status". */
- gate_status = pass->has_gate ? pass->gate() : true;
+ gate_status = pass->gate (cfun);
gate_status = override_gate_status (pass, current_function_decl, gate_status);
/* Override gate with plugin. */
executed. */
invoke_plugin_callbacks (PLUGIN_PASS_EXECUTION, pass);
- /* SIPLE IPA passes do not handle callgraphs with IPA transforms in it.
- Apply all trnasforms first. */
- if (pass->type == SIMPLE_IPA_PASS)
- {
- bool applied = false;
- do_per_function (apply_ipa_transforms, (void *)&applied);
- if (applied)
- symtab_remove_unreachable_nodes (true, dump_file);
- /* Restore current_pass. */
- current_pass = pass;
- }
-
if (!quiet_flag && !cfun)
fprintf (stderr, " <%s>", pass->name ? pass->name : "");
timevar_push (pass->tv_id);
/* Do it! */
- if (pass->has_execute)
- {
- todo_after = pass->execute ();
- do_per_function (clear_last_verified, NULL);
- }
+ todo_after = pass->execute (cfun);
+ do_per_function (clear_last_verified, NULL);
/* Stop timevar. */
if (pass->tv_id != TV_NONE)
check_profile_consistency (pass->static_pass_number, 0, true);
/* Run post-pass cleanup and verification. */
- execute_todo (todo_after | pass->todo_flags_finish);
+ execute_todo (todo_after | pass->todo_flags_finish | TODO_verify_il);
if (profile_report && cfun && (cfun->curr_properties & PROP_cfg))
check_profile_consistency (pass->static_pass_number, 1, true);
verify_interpass_invariants ();
- do_per_function (execute_function_dump, NULL);
+ if (dump_file)
+ do_per_function (execute_function_dump, pass);
if (pass->type == IPA_PASS)
{
struct cgraph_node *node;
- FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
- node->ipa_transforms_to_apply.safe_push ((struct ipa_opt_pass_d *)pass);
+ if (((ipa_opt_pass_d *)pass)->function_transform)
+ FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
+ node->ipa_transforms_to_apply.safe_push ((ipa_opt_pass_d *)pass);
}
if (!current_function_decl)
- cgraph_process_new_functions ();
+ symtab->process_new_functions ();
pass_fini_dump_file (pass);
return true;
}
-void
-execute_pass_list (struct opt_pass *pass)
+static void
+execute_pass_list_1 (opt_pass *pass)
{
do
{
gcc_assert (pass->type == GIMPLE_PASS
|| pass->type == RTL_PASS);
if (execute_one_pass (pass) && pass->sub)
- execute_pass_list (pass->sub);
+ execute_pass_list_1 (pass->sub);
pass = pass->next;
}
while (pass);
}
+void
+execute_pass_list (function *fn, opt_pass *pass)
+{
+ push_cfun (fn);
+ execute_pass_list_1 (pass);
+ if (fn->cfg)
+ {
+ free_dominance_info (CDI_DOMINATORS);
+ free_dominance_info (CDI_POST_DOMINATORS);
+ }
+ pop_cfun ();
+}
+
+/* Write out all LTO data. */
+static void
+write_lto (void)
+{
+ timevar_push (TV_IPA_LTO_GIMPLE_OUT);
+ lto_output ();
+ timevar_pop (TV_IPA_LTO_GIMPLE_OUT);
+ timevar_push (TV_IPA_LTO_DECL_OUT);
+ produce_asm_for_decls ();
+ timevar_pop (TV_IPA_LTO_DECL_OUT);
+}
+
/* Same as execute_pass_list but assume that subpasses of IPA passes
are local passes. If SET is not NULL, write out summaries of only
those node in SET. */
static void
-ipa_write_summaries_2 (struct opt_pass *pass, struct lto_out_decl_state *state)
+ipa_write_summaries_2 (opt_pass *pass, struct lto_out_decl_state *state)
{
while (pass)
{
- struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *)pass;
+ ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *)pass;
gcc_assert (!current_function_decl);
gcc_assert (!cfun);
gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
if (pass->type == IPA_PASS
&& ipa_pass->write_summary
- && ((!pass->has_gate) || pass->gate ()))
+ && pass->gate (cfun))
{
/* If a timevar is present, start it. */
if (pass->tv_id)
pass_init_dump_file (pass);
+ current_pass = pass;
ipa_pass->write_summary ();
pass_fini_dump_file (pass);
struct lto_out_decl_state *state = lto_new_out_decl_state ();
state->symtab_node_encoder = encoder;
+ lto_output_init_mode_table ();
lto_push_out_decl_state (state);
gcc_assert (!flag_wpa);
ipa_write_summaries_2 (passes->all_regular_ipa_passes, state);
- ipa_write_summaries_2 (passes->all_lto_gen_passes, state);
+
+ write_lto ();
gcc_assert (lto_get_out_decl_state () == state);
lto_pop_out_decl_state ();
{
lto_symtab_encoder_t encoder;
int i, order_pos;
- struct varpool_node *vnode;
+ varpool_node *vnode;
struct cgraph_node *node;
struct cgraph_node **order;
- if (!flag_generate_lto || seen_error ())
+ if ((!flag_generate_lto && !flag_generate_offload) || seen_error ())
return;
+ select_what_to_stream ();
+
encoder = lto_symtab_encoder_new (false);
/* Create the callgraph set in the same order used in
cgraph_expand_all_functions. This mostly facilitates debugging,
since it causes the gimple file to be processed in the same order
as the source code. */
- order = XCNEWVEC (struct cgraph_node *, cgraph_n_nodes);
+ order = XCNEWVEC (struct cgraph_node *, symtab->cgraph_count);
order_pos = ipa_reverse_postorder (order);
- gcc_assert (order_pos == cgraph_n_nodes);
+ gcc_assert (order_pos == symtab->cgraph_count);
for (i = order_pos - 1; i >= 0; i--)
{
struct cgraph_node *node = order[i];
- if (cgraph_function_with_gimple_body_p (node))
+ if (node->has_gimple_body_p ())
{
/* When streaming out references to statements as part of some IPA
pass summary, the statements need to have uids assigned and the
ordering then matches the one IPA-passes get in their stmt_fixup
hooks. */
- push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl));
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
renumber_gimple_stmt_uids ();
pop_cfun ();
}
- if (node->symbol.definition)
- lto_set_symtab_encoder_in_partition (encoder, (symtab_node)node);
+ if (node->definition && node->need_lto_streaming)
+ lto_set_symtab_encoder_in_partition (encoder, node);
}
FOR_EACH_DEFINED_FUNCTION (node)
- if (node->symbol.alias)
- lto_set_symtab_encoder_in_partition (encoder, (symtab_node)node);
+ if (node->alias && node->need_lto_streaming)
+ lto_set_symtab_encoder_in_partition (encoder, node);
FOR_EACH_DEFINED_VARIABLE (vnode)
- lto_set_symtab_encoder_in_partition (encoder, (symtab_node)vnode);
+ if (vnode->need_lto_streaming)
+ lto_set_symtab_encoder_in_partition (encoder, vnode);
ipa_write_summaries_1 (compute_ltrans_boundary (encoder));
only those node in SET. */
static void
-ipa_write_optimization_summaries_1 (struct opt_pass *pass, struct lto_out_decl_state *state)
+ipa_write_optimization_summaries_1 (opt_pass *pass,
+ struct lto_out_decl_state *state)
{
while (pass)
{
- struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *)pass;
+ ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *)pass;
gcc_assert (!current_function_decl);
gcc_assert (!cfun);
gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
if (pass->type == IPA_PASS
&& ipa_pass->write_optimization_summary
- && ((!pass->has_gate) || pass->gate ()))
+ && pass->gate (cfun))
{
/* If a timevar is present, start it. */
if (pass->tv_id)
pass_init_dump_file (pass);
+ current_pass = pass;
ipa_pass->write_optimization_summary ();
pass_fini_dump_file (pass);
lto_symtab_encoder_iterator lsei;
state->symtab_node_encoder = encoder;
+ lto_output_init_mode_table ();
lto_push_out_decl_state (state);
for (lsei = lsei_start_function_in_partition (encoder);
!lsei_end_p (lsei); lsei_next_function_in_partition (&lsei))
For functions newly born at WPA stage we need to initialize
the uids here. */
- if (node->symbol.definition
- && gimple_has_body_p (node->symbol.decl))
+ if (node->definition
+ && gimple_has_body_p (node->decl))
{
- push_cfun (DECL_STRUCT_FUNCTION (node->symbol.decl));
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
renumber_gimple_stmt_uids ();
pop_cfun ();
}
gcc_assert (flag_wpa);
pass_manager *passes = g->get_passes ();
ipa_write_optimization_summaries_1 (passes->all_regular_ipa_passes, state);
- ipa_write_optimization_summaries_1 (passes->all_lto_gen_passes, state);
+
+ write_lto ();
gcc_assert (lto_get_out_decl_state () == state);
lto_pop_out_decl_state ();
are local passes. */
static void
-ipa_read_summaries_1 (struct opt_pass *pass)
+ipa_read_summaries_1 (opt_pass *pass)
{
while (pass)
{
- struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *) pass;
+ ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *) pass;
gcc_assert (!current_function_decl);
gcc_assert (!cfun);
gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
- if ((!pass->has_gate) || pass->gate ())
+ if (pass->gate (cfun))
{
if (pass->type == IPA_PASS && ipa_pass->read_summary)
{
pass_init_dump_file (pass);
+ current_pass = pass;
ipa_pass->read_summary ();
pass_fini_dump_file (pass);
}
-/* Read all the summaries for all_regular_ipa_passes and all_lto_gen_passes. */
+/* Read all the summaries for all_regular_ipa_passes. */
void
ipa_read_summaries (void)
{
pass_manager *passes = g->get_passes ();
ipa_read_summaries_1 (passes->all_regular_ipa_passes);
- ipa_read_summaries_1 (passes->all_lto_gen_passes);
}
/* Same as execute_pass_list but assume that subpasses of IPA passes
are local passes. */
static void
-ipa_read_optimization_summaries_1 (struct opt_pass *pass)
+ipa_read_optimization_summaries_1 (opt_pass *pass)
{
while (pass)
{
- struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *) pass;
+ ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *) pass;
gcc_assert (!current_function_decl);
gcc_assert (!cfun);
gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
- if ((!pass->has_gate) || pass->gate ())
+ if (pass->gate (cfun))
{
if (pass->type == IPA_PASS && ipa_pass->read_optimization_summary)
{
pass_init_dump_file (pass);
+ current_pass = pass;
ipa_pass->read_optimization_summary ();
pass_fini_dump_file (pass);
}
}
-/* Read all the summaries for all_regular_ipa_passes and all_lto_gen_passes. */
+/* Read all the summaries for all_regular_ipa_passes. */
void
ipa_read_optimization_summaries (void)
{
pass_manager *passes = g->get_passes ();
ipa_read_optimization_summaries_1 (passes->all_regular_ipa_passes);
- ipa_read_optimization_summaries_1 (passes->all_lto_gen_passes);
}
/* Same as execute_pass_list but assume that subpasses of IPA passes
are local passes. */
void
-execute_ipa_pass_list (struct opt_pass *pass)
+execute_ipa_pass_list (opt_pass *pass)
{
do
{
if (pass->sub->type == GIMPLE_PASS)
{
invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_START, NULL);
- do_per_function_toporder ((void (*)(void *))execute_pass_list,
+ do_per_function_toporder ((void (*)(function *, void *))
+ execute_pass_list,
pass->sub);
invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_END, NULL);
}
gcc_unreachable ();
}
gcc_assert (!current_function_decl);
- cgraph_process_new_functions ();
+ symtab->process_new_functions ();
pass = pass->next;
}
while (pass);
/* Execute stmt fixup hooks of all passes in PASS for NODE and STMTS. */
static void
-execute_ipa_stmt_fixups (struct opt_pass *pass,
- struct cgraph_node *node, gimple *stmts)
+execute_ipa_stmt_fixups (opt_pass *pass,
+ struct cgraph_node *node, gimple *stmts)
{
while (pass)
{
/* Execute all of the IPA_PASSes in the list. */
if (pass->type == IPA_PASS
- && ((!pass->has_gate) || pass->gate ()))
+ && pass->gate (cfun))
{
- struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *) pass;
+ ipa_opt_pass_d *ipa_pass = (ipa_opt_pass_d *) pass;
if (ipa_pass->stmt_fixup)
{
if (pass->tv_id)
timevar_push (pass->tv_id);
+ current_pass = pass;
ipa_pass->stmt_fixup (node, stmts);
/* Stop timevar. */
function_called_by_processed_nodes_p (void)
{
struct cgraph_edge *e;
- for (e = cgraph_get_node (current_function_decl)->callers;
+ for (e = cgraph_node::get (current_function_decl)->callers;
e;
e = e->next_caller)
{
- if (e->caller->symbol.decl == current_function_decl)
+ if (e->caller->decl == current_function_decl)
continue;
- if (!cgraph_function_with_gimple_body_p (e->caller))
+ if (!e->caller->has_gimple_body_p ())
continue;
- if (TREE_ASM_WRITTEN (e->caller->symbol.decl))
+ if (TREE_ASM_WRITTEN (e->caller->decl))
continue;
if (!e->caller->process && !e->caller->global.inlined_to)
break;
if (dump_file && e)
{
fprintf (dump_file, "Already processed call to:\n");
- dump_cgraph_node (dump_file, e->caller);
+ e->caller->dump (dump_file);
}
return e != NULL;
}