summaryrefslogtreecommitdiff
path: root/gcc/passes.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/passes.c')
-rw-r--r--gcc/passes.c324
1 files changed, 271 insertions, 53 deletions
diff --git a/gcc/passes.c b/gcc/passes.c
index 5b91698e179..80225490cbd 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -84,6 +84,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-dump.h"
#include "df.h"
#include "predict.h"
+#include "lto-streamer.h"
#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
#include "dwarf2out.h"
@@ -331,7 +332,8 @@ struct rtl_opt_pass pass_postreload =
/* The root of the compilation pass tree, once constructed. */
-struct opt_pass *all_passes, *all_ipa_passes, *all_lowering_passes;
+struct opt_pass *all_passes, *all_small_ipa_passes, *all_lowering_passes,
+ *all_regular_ipa_passes, *all_lto_gen_passes;
/* A map from static pass id to optimization pass. */
struct opt_pass **passes_by_id;
@@ -598,22 +600,31 @@ position_pass (struct register_pass_info *new_pass_info,
void
register_pass (struct register_pass_info *pass_info)
{
+ /* 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)
- {
- gcc_unreachable ();
- }
+ fatal_error ("plugin cannot register a missing pass");
+
+ if (!pass_info->pass->name)
+ fatal_error ("plugin cannot register an unnamed pass");
if (!pass_info->reference_pass_name)
- {
- gcc_unreachable ();
- }
+ fatal_error
+ ("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 all
- three lists as the reference pass could be in one (or all) of them. */
+ /* Try to insert the new pass to the pass lists. We need to check
+ all three lists as the reference pass could be in one (or all) of
+ them. */
if (!position_pass (pass_info, &all_lowering_passes)
- && !position_pass (pass_info, &all_ipa_passes)
+ && !position_pass (pass_info, &all_small_ipa_passes)
+ && !position_pass (pass_info, &all_regular_ipa_passes)
+ && !position_pass (pass_info, &all_lto_gen_passes)
&& !position_pass (pass_info, &all_passes))
- gcc_unreachable ();
+ fatal_error
+ ("pass %qs not found but is referenced by new pass %qs",
+ pass_info->reference_pass_name, pass_info->pass->name);
else
{
/* OK, we have successfully inserted the new pass. We need to register
@@ -658,7 +669,7 @@ register_pass (struct register_pass_info *pass_info)
If we are optimizing, cgraph_optimize is then invoked:
cgraph_optimize ()
- ipa_passes () -> all_ipa_passes
+ ipa_passes () -> all_small_ipa_passes
cgraph_expand_all_functions ()
for each node N in the cgraph
cgraph_expand_function (N)
@@ -679,7 +690,6 @@ init_optimization_passes (void)
p = &all_lowering_passes;
NEXT_PASS (pass_warn_unused_result);
NEXT_PASS (pass_diagnose_omp_blocks);
- NEXT_PASS (pass_remove_useless_stmts);
NEXT_PASS (pass_mudflap_1);
NEXT_PASS (pass_lower_omp);
NEXT_PASS (pass_lower_cf);
@@ -694,7 +704,7 @@ init_optimization_passes (void)
*p = NULL;
/* Interprocedural optimization passes. */
- p = &all_ipa_passes;
+ p = &all_small_ipa_passes;
NEXT_PASS (pass_ipa_function_and_variable_visibility);
NEXT_PASS (pass_ipa_early_inline);
{
@@ -716,11 +726,16 @@ init_optimization_passes (void)
NEXT_PASS (pass_referenced_vars);
NEXT_PASS (pass_build_ssa);
NEXT_PASS (pass_early_warn_uninitialized);
+ /* Note that it is not strictly necessary to schedule an early
+ inline pass here. However, some test cases (e.g.,
+ g++.dg/other/p334435.C g++.dg/other/i386-1.C) expect extern
+ inline functions to be inlined even at -O0. This does not
+ happen during the first early inline pass. */
+ NEXT_PASS (pass_rebuild_cgraph_edges);
+ NEXT_PASS (pass_early_inline);
NEXT_PASS (pass_all_early_optimizations);
{
struct opt_pass **p = &pass_all_early_optimizations.pass.sub;
- NEXT_PASS (pass_rebuild_cgraph_edges);
- NEXT_PASS (pass_early_inline);
NEXT_PASS (pass_remove_cgraph_callee_edges);
NEXT_PASS (pass_rename_ssa_copies);
NEXT_PASS (pass_ccp);
@@ -747,13 +762,23 @@ init_optimization_passes (void)
}
NEXT_PASS (pass_ipa_increase_alignment);
NEXT_PASS (pass_ipa_matrix_reorg);
+ *p = NULL;
+
+ p = &all_regular_ipa_passes;
+ NEXT_PASS (pass_ipa_whole_program_visibility);
NEXT_PASS (pass_ipa_cp);
NEXT_PASS (pass_ipa_inline);
NEXT_PASS (pass_ipa_reference);
NEXT_PASS (pass_ipa_pure_const);
NEXT_PASS (pass_ipa_type_escape);
NEXT_PASS (pass_ipa_pta);
- NEXT_PASS (pass_ipa_struct_reorg);
+ NEXT_PASS (pass_ipa_struct_reorg);
+ *p = NULL;
+
+ p = &all_lto_gen_passes;
+ NEXT_PASS (pass_ipa_lto_gimple_out);
+ NEXT_PASS (pass_ipa_lto_wpa_fixup);
+ NEXT_PASS (pass_ipa_lto_finish_out); /* This must be the last LTO pass. */
*p = NULL;
/* These passes are run after IPA passes on every function that is being
@@ -855,7 +880,6 @@ init_optimization_passes (void)
NEXT_PASS (pass_tree_loop_done);
}
NEXT_PASS (pass_cse_reciprocals);
- NEXT_PASS (pass_convert_to_rsqrt);
NEXT_PASS (pass_reassoc);
NEXT_PASS (pass_vrp);
NEXT_PASS (pass_dominator);
@@ -918,6 +942,7 @@ init_optimization_passes (void)
NEXT_PASS (pass_rtl_store_motion);
NEXT_PASS (pass_cse_after_global_opts);
NEXT_PASS (pass_rtl_ifcvt);
+ NEXT_PASS (pass_reginfo_init);
/* Perform loop optimizations. It might be better to do them a bit
sooner, but we want the profile feedback to work more
efficiently. */
@@ -937,7 +962,6 @@ init_optimization_passes (void)
NEXT_PASS (pass_cse2);
NEXT_PASS (pass_rtl_dse1);
NEXT_PASS (pass_rtl_fwprop_addr);
- NEXT_PASS (pass_reginfo_init);
NEXT_PASS (pass_inc_dec);
NEXT_PASS (pass_initialize_regs);
NEXT_PASS (pass_ud_rtl_dce);
@@ -953,10 +977,8 @@ init_optimization_passes (void)
NEXT_PASS (pass_mode_switching);
NEXT_PASS (pass_match_asm_constraints);
NEXT_PASS (pass_sms);
- NEXT_PASS (pass_subregs_of_mode_init);
NEXT_PASS (pass_sched);
NEXT_PASS (pass_ira);
- NEXT_PASS (pass_subregs_of_mode_finish);
NEXT_PASS (pass_postreload);
{
struct opt_pass **p = &pass_postreload.pass.sub;
@@ -1005,7 +1027,13 @@ init_optimization_passes (void)
/* Register the passes with the tree dump code. */
register_dump_files (all_lowering_passes, PROP_gimple_any);
- register_dump_files (all_ipa_passes,
+ 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_passes,
@@ -1032,8 +1060,11 @@ do_per_function (void (*callback) (void *data), void *data)
push_cfun (DECL_STRUCT_FUNCTION (node->decl));
current_function_decl = node->decl;
callback (data);
- free_dominance_info (CDI_DOMINATORS);
- free_dominance_info (CDI_POST_DOMINATORS);
+ if (!flag_wpa)
+ {
+ free_dominance_info (CDI_DOMINATORS);
+ free_dominance_info (CDI_POST_DOMINATORS);
+ }
current_function_decl = NULL;
pop_cfun ();
ggc_collect ();
@@ -1072,7 +1103,7 @@ do_per_function_toporder (void (*callback) (void *data), void *data)
/* Allow possibly removed nodes to be garbage collected. */
order[i] = NULL;
node->process = 0;
- if (node->analyzed && (node->needed || node->reachable))
+ if (node->analyzed)
{
push_cfun (DECL_STRUCT_FUNCTION (node->decl));
current_function_decl = node->decl;
@@ -1346,7 +1377,7 @@ add_ipa_transform_pass (void *data)
/* Execute summary generation for all of the passes in IPA_PASS. */
-static void
+void
execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass)
{
while (ipa_pass)
@@ -1355,10 +1386,21 @@ execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass)
/* Execute all of the IPA_PASSes in the list. */
if (ipa_pass->pass.type == IPA_PASS
- && (!pass->gate || pass->gate ()))
+ && (!pass->gate || pass->gate ())
+ && ipa_pass->generate_summary)
{
pass_init_dump_file (pass);
+
+ /* If a timevar is present, start it. */
+ if (pass->tv_id)
+ timevar_push (pass->tv_id);
+
ipa_pass->generate_summary ();
+
+ /* Stop timevar. */
+ if (pass->tv_id)
+ timevar_pop (pass->tv_id);
+
pass_fini_dump_file (pass);
}
ipa_pass = (struct ipa_opt_pass_d *)ipa_pass->pass.next;
@@ -1407,19 +1449,11 @@ execute_one_ipa_transform_pass (struct cgraph_node *node,
current_pass = NULL;
}
-static bool
-execute_one_pass (struct opt_pass *pass)
-{
- bool initializing_dump;
- unsigned int todo_after = 0;
-
- /* IPA passes are executed on whole program, so cfun should be NULL.
- Other passes need function context set. */
- if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS)
- gcc_assert (!cfun && !current_function_decl);
- else
- gcc_assert (cfun && current_function_decl);
+/* For the current function, execute all ipa transforms. */
+void
+execute_all_ipa_transforms (void)
+{
if (cfun && cfun->ipa_transforms_to_apply)
{
unsigned int i;
@@ -1428,12 +1462,28 @@ execute_one_pass (struct opt_pass *pass)
for (i = 0; i < VEC_length (ipa_opt_pass, cfun->ipa_transforms_to_apply);
i++)
execute_one_ipa_transform_pass (node,
- VEC_index (ipa_opt_pass,
+ VEC_index (ipa_opt_pass,
cfun->ipa_transforms_to_apply,
i));
VEC_free (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply);
cfun->ipa_transforms_to_apply = NULL;
}
+}
+
+/* Execute PASS. */
+
+static bool
+execute_one_pass (struct opt_pass *pass)
+{
+ bool initializing_dump;
+ unsigned int todo_after = 0;
+
+ /* IPA passes are executed on whole program, so cfun should be NULL.
+ Other passes need function context set. */
+ if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS)
+ gcc_assert (!cfun && !current_function_decl);
+ else
+ gcc_assert (cfun && current_function_decl);
current_pass = pass;
@@ -1522,26 +1572,161 @@ execute_pass_list (struct opt_pass *pass)
}
/* Same as execute_pass_list but assume that subpasses of IPA passes
- are local 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, cgraph_node_set set,
+ struct lto_out_decl_state *state)
+{
+ while (pass)
+ {
+ struct ipa_opt_pass_d *ipa_pass = (struct 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->gate || pass->gate ()))
+ {
+ /* If a timevar is present, start it. */
+ if (pass->tv_id)
+ timevar_push (pass->tv_id);
+
+ ipa_pass->write_summary (set);
+
+ /* If a timevar is present, start it. */
+ if (pass->tv_id)
+ timevar_pop (pass->tv_id);
+ }
+
+ if (pass->sub && pass->sub->type != GIMPLE_PASS)
+ ipa_write_summaries_2 (pass->sub, set, state);
+
+ pass = pass->next;
+ }
+}
+
+/* Helper function of ipa_write_summaries. Creates and destroys the
+ decl state and calls ipa_write_summaries_2 for all passes that have
+ summaries. SET is the set of nodes to be written. */
+
+static void
+ipa_write_summaries_1 (cgraph_node_set set)
+{
+ struct lto_out_decl_state *state = lto_new_out_decl_state ();
+ lto_push_out_decl_state (state);
+
+ if (!flag_wpa)
+ ipa_write_summaries_2 (all_regular_ipa_passes, set, state);
+ ipa_write_summaries_2 (all_lto_gen_passes, set, state);
+
+ gcc_assert (lto_get_out_decl_state () == state);
+ lto_pop_out_decl_state ();
+ lto_delete_out_decl_state (state);
+}
+
+/* Write out summaries for all the nodes in the callgraph. */
+
void
-execute_ipa_pass_list (struct opt_pass *pass)
+ipa_write_summaries (void)
{
- bool summaries_generated = false;
- do
+ cgraph_node_set set;
+ struct cgraph_node **order;
+ int i, order_pos;
+
+ if (!flag_generate_lto || errorcount || sorrycount)
+ return;
+
+ lto_new_extern_inline_states ();
+ set = cgraph_node_set_new ();
+
+ /* 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_pos = cgraph_postorder (order);
+ gcc_assert (order_pos == cgraph_n_nodes);
+
+ for (i = order_pos - 1; i >= 0; i--)
+ cgraph_node_set_add (set, order[i]);
+
+ ipa_write_summaries_1 (set);
+ lto_delete_extern_inline_states ();
+
+ free (order);
+ ggc_free (set);
+}
+
+
+/* Write all the summaries for the cgraph nodes in SET. If SET is
+ NULL, write out all summaries of all nodes. */
+
+void
+ipa_write_summaries_of_cgraph_node_set (cgraph_node_set set)
+{
+ if (flag_generate_lto && !(errorcount || sorrycount))
+ ipa_write_summaries_1 (set);
+}
+
+/* Same as execute_pass_list but assume that subpasses of IPA passes
+ are local passes. */
+
+static void
+ipa_read_summaries_1 (struct opt_pass *pass)
+{
+ while (pass)
{
+ struct ipa_opt_pass_d *ipa_pass = (struct 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 && (!pass->gate || pass->gate ()))
+
+ if (pass->gate == NULL || pass->gate ())
{
- if (!summaries_generated)
+ if (pass->type == IPA_PASS && ipa_pass->read_summary)
{
- if (!quiet_flag && !cfun)
- fprintf (stderr, " <summary generate>");
- execute_ipa_summary_passes ((struct ipa_opt_pass_d *) pass);
+ /* If a timevar is present, start it. */
+ if (pass->tv_id)
+ timevar_push (pass->tv_id);
+
+ ipa_pass->read_summary ();
+
+ /* Stop timevar. */
+ if (pass->tv_id)
+ timevar_pop (pass->tv_id);
}
- summaries_generated = true;
+
+ if (pass->sub && pass->sub->type != GIMPLE_PASS)
+ ipa_read_summaries_1 (pass->sub);
}
+ pass = pass->next;
+ }
+}
+
+
+/* Read all the summaries for all_regular_ipa_passes and all_lto_gen_passes. */
+
+void
+ipa_read_summaries (void)
+{
+ if (!flag_ltrans)
+ ipa_read_summaries_1 (all_regular_ipa_passes);
+ ipa_read_summaries_1 (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)
+{
+ do
+ {
+ gcc_assert (!current_function_decl);
+ gcc_assert (!cfun);
+ gcc_assert (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS);
if (execute_one_pass (pass) && pass->sub)
{
if (pass->sub->type == GIMPLE_PASS)
@@ -1553,13 +1738,46 @@ execute_ipa_pass_list (struct opt_pass *pass)
else
gcc_unreachable ();
}
- if (!current_function_decl)
- cgraph_process_new_functions ();
+ gcc_assert (!current_function_decl);
+ cgraph_process_new_functions ();
pass = pass->next;
}
while (pass);
}
+extern void debug_properties (unsigned int);
+extern void dump_properties (FILE *, unsigned int);
+
+void
+dump_properties (FILE *dump, unsigned int props)
+{
+ fprintf (dump, "Properties:\n");
+ if (props & PROP_gimple_any)
+ fprintf (dump, "PROP_gimple_any\n");
+ if (props & PROP_gimple_lcf)
+ fprintf (dump, "PROP_gimple_lcf\n");
+ if (props & PROP_gimple_leh)
+ fprintf (dump, "PROP_gimple_leh\n");
+ if (props & PROP_cfg)
+ fprintf (dump, "PROP_cfg\n");
+ if (props & PROP_referenced_vars)
+ fprintf (dump, "PROP_referenced_vars\n");
+ if (props & PROP_ssa)
+ fprintf (dump, "PROP_ssa\n");
+ if (props & PROP_no_crit_edges)
+ fprintf (dump, "PROP_no_crit_edges\n");
+ if (props & PROP_rtl)
+ fprintf (dump, "PROP_rtl\n");
+ if (props & PROP_gimple_lomp)
+ fprintf (dump, "PROP_gimple_lomp\n");
+}
+
+void
+debug_properties (unsigned int props)
+{
+ dump_properties (stderr, props);
+}
+
/* Called by local passes to see if function is called by already processed nodes.
Because we process nodes in topological order, this means that function is
in recursive cycle or we introduced new direct calls. */
@@ -1571,7 +1789,7 @@ function_called_by_processed_nodes_p (void)
{
if (e->caller->decl == current_function_decl)
continue;
- if (!e->caller->analyzed || (!e->caller->needed && !e->caller->reachable))
+ if (!e->caller->analyzed)
continue;
if (TREE_ASM_WRITTEN (e->caller->decl))
continue;