/* Top level of GCC compilers (cc1, cc1plus, etc.)
- Copyright (C) 1987-2014 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 "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 "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 "graph.h"
#include "tree-ssa-alias.h"
#include "internal-fn.h"
#include "gimple-expr.h"
-#include "is-a.h"
#include "gimple.h"
#include "gimple-ssa.h"
#include "tree-cfg.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"
-#include "hash-map.h"
using namespace gcc;
void
pass_manager::execute_early_local_passes ()
{
- execute_pass_list (cfun, 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
else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl)
&& TREE_STATIC (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. */
}
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;
}
namespace {
-const pass_data pass_data_early_local_passes =
+const pass_data pass_data_build_ssa_passes =
{
SIMPLE_IPA_PASS, /* type */
- "early_local_cleanups", /* name */
+ "build_ssa_passes", /* name */
OPTGROUP_NONE, /* optinfo_flags */
TV_EARLY_LOCAL, /* tv_id */
0, /* properties_required */
0, /* todo_flags_finish */
};
-class pass_early_local_passes : public simple_ipa_opt_pass
+class pass_build_ssa_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_build_ssa_passes (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_build_ssa_passes, ctxt)
{}
/* opt_pass methods: */
virtual unsigned int execute (function *)
{
- return execute_all_early_local_passes ();
+ return execute_build_ssa_passes ();
+ }
+
+}; // class pass_build_ssa_passes
+
+const pass_data pass_data_chkp_instrumentation_passes =
+{
+ SIMPLE_IPA_PASS, /* type */
+ "chkp_passes", /* name */
+ OPTGROUP_NONE, /* optinfo_flags */
+ 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 */
+ 0, /* todo_flags_finish */
+};
+
+class pass_local_optimization_passes : public simple_ipa_opt_pass
+{
+public:
+ pass_local_optimization_passes (gcc::context *ctxt)
+ : simple_ipa_opt_pass (pass_data_local_optimization_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);
}
-}; // 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_build_ssa_passes (ctxt);
+}
+
+simple_ipa_opt_pass *
+make_pass_chkp_instrumentation_passes (gcc::context *ctxt)
+{
+ return new pass_chkp_instrumentation_passes (ctxt);
+}
+
+simple_ipa_opt_pass *
+make_pass_local_optimization_passes (gcc::context *ctxt)
{
- return new pass_early_local_passes (ctxt);
+ return new pass_local_optimization_passes (ctxt);
}
namespace {
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
if (optgroup_flags == OPTGROUP_NONE)
optgroup_flags = OPTGROUP_OTHER;
id = dumps->dump_register (dot_name, flag_name, glob_name, flags,
- optgroup_flags);
+ optgroup_flags,
+ true);
set_pass_for_id (id, pass);
full_name = concat (prefix, pass->name, num, NULL);
register_pass_name (pass, full_name);
while (pass);
}
-/* Helper for pass_registry hash table. */
-
-struct pass_registry_hasher : default_hashmap_traits
-{
- static inline hashval_t hash (const char *);
- static inline bool equal_keys (const char *, const char *);
-};
-
-/* Pass registry hash function. */
-
-inline hashval_t
-pass_registry_hasher::hash (const char *name)
-{
- return htab_hash_string (name);
-}
-
-/* Hash equal function */
-
-inline bool
-pass_registry_hasher::equal_keys (const char *s1, const char *s2)
-{
- return !strcmp (s1, s2);
-}
-
-static hash_map<const char *, opt_pass *, pass_registry_hasher>
- *name_to_pass_map;
+static hash_map<nofree_string_hash, opt_pass *> *name_to_pass_map;
/* Register PASS with NAME. */
register_pass_name (opt_pass *pass, const char *name)
{
if (!name_to_pass_map)
- name_to_pass_map
- = new hash_map<const char *, opt_pass *, pass_registry_hasher> (256);
+ name_to_pass_map = new hash_map<nofree_string_hash, opt_pass *> (256);
if (name_to_pass_map->get (name))
return; /* Ignore plugin passes. */
void
pass_manager::dump_passes () const
{
- struct cgraph_node *n, *node = NULL;
+ push_dummy_function (true);
create_pass_tab ();
- FOR_EACH_FUNCTION (n)
- if (DECL_STRUCT_FUNCTION (n->decl))
- {
- node = n;
- break;
- }
-
- if (!node)
- return;
-
- push_cfun (DECL_STRUCT_FUNCTION (node->decl));
-
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_late_ipa_passes, 1);
dump_pass_list (all_passes, 1);
- pop_cfun ();
+ pop_dummy_function ();
}
-
/* Returns the pass with NAME. */
static opt_pass *
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_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
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),
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
function CALLBACK for every function in the call graph. Otherwise,
call CALLBACK on the current function. */
static int nnodes;
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.
callback (cfun, data);
else
{
+ cgraph_node_hook_list *hook;
+ int *order_idx;
gcc_assert (!order);
- order = ggc_vec_alloc<cgraph_node *> (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. */
if (node->has_gimple_body_p ())
callback (DECL_STRUCT_FUNCTION (node->decl), data);
}
+ symtab->remove_cgraph_removal_hook (hook);
}
ggc_free (order);
order = NULL;
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 ())
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)
if (pass->tv_id)
timevar_push (pass->tv_id);
+ current_pass = pass;
ipa_pass->generate_summary ();
/* Stop timevar. */
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)
- {
- struct cgraph_node *node;
- bool applied = false;
- FOR_EACH_DEFINED_FUNCTION (node)
- if (node->analyzed
- && node->has_gimple_body_p ()
- && (!node->clone_of || node->decl != node->clone_of->decl))
- {
- if (!node->global.inlined_to
- && node->ipa_transforms_to_apply.exists ())
- {
- node->get_body ();
- push_cfun (DECL_STRUCT_FUNCTION (node->decl));
- execute_all_ipa_transforms ();
- rebuild_cgraph_edges ();
- free_dominance_info (CDI_DOMINATORS);
- free_dominance_info (CDI_POST_DOMINATORS);
- pop_cfun ();
- applied = true;
- }
- }
- if (applied)
- symtab_remove_unreachable_nodes (false, dump_file);
- /* Restore current_pass. */
- current_pass = pass;
- }
-
if (!quiet_flag && !cfun)
fprintf (stderr, " <%s>", pass->name ? pass->name : "");
if (pass->type == IPA_PASS)
{
struct cgraph_node *node;
- FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
- node->ipa_transforms_to_apply.safe_push ((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);
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);
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--)
{
renumber_gimple_stmt_uids ();
pop_cfun ();
}
- if (node->definition)
+ if (node->definition && node->need_lto_streaming)
lto_set_symtab_encoder_in_partition (encoder, node);
}
FOR_EACH_DEFINED_FUNCTION (node)
- if (node->alias)
+ 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, vnode);
+ if (vnode->need_lto_streaming)
+ lto_set_symtab_encoder_in_partition (encoder, vnode);
ipa_write_summaries_1 (compute_ltrans_boundary (encoder));
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))
pass_init_dump_file (pass);
+ current_pass = pass;
ipa_pass->read_summary ();
pass_fini_dump_file (pass);
pass_init_dump_file (pass);
+ current_pass = pass;
ipa_pass->read_optimization_summary ();
pass_fini_dump_file (pass);
gcc_unreachable ();
}
gcc_assert (!current_function_decl);
- cgraph_process_new_functions ();
+ symtab->process_new_functions ();
pass = pass->next;
}
while (pass);
if (pass->tv_id)
timevar_push (pass->tv_id);
+ current_pass = pass;
ipa_pass->stmt_fixup (node, stmts);
/* Stop timevar. */