/* Top level of GCC compilers (cc1, cc1plus, etc.)
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
- 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+ 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
Free Software Foundation, Inc.
This file is part of GCC.
#include "tree-dump.h"
#include "df.h"
#include "predict.h"
+#include "lto-streamer.h"
+#include "plugin.h"
#if defined (DWARF2_UNWIND_INFO) || defined (DWARF2_DEBUGGING_INFO)
#include "dwarf2out.h"
#endif
/* This is used for debugging. It allows the current pass to printed
- from anywhere in compilation. */
+ from anywhere in compilation.
+ The variable current_pass is also used for statistics and plugins. */
struct opt_pass *current_pass;
/* Call from anywhere to find out what pass this is. Useful for
print_current_pass (FILE *file)
{
if (current_pass)
- fprintf (file, "current pass = %s (%d)\n",
+ fprintf (file, "current pass = %s (%d)\n",
current_pass->name, current_pass->static_pass_number);
else
fprintf (file, "no current pass.\n");
debug_pass (void)
{
print_current_pass (stderr);
-}
+}
|| DECL_INITIAL (decl))
&& !DECL_EXTERNAL (decl))
{
- if (TREE_CODE (decl) != FUNCTION_DECL)
+ /* When reading LTO unit, we also read varpool, so do not
+ rebuild it. */
+ if (in_lto_p && !at_end)
+ ;
+ else if (TREE_CODE (decl) != FUNCTION_DECL)
varpool_finalize_decl (decl);
else
assemble_variable (decl, top_level, at_end, 0);
}
/* Let cgraph know about the existence of variables. */
- if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
+ if (in_lto_p && !at_end)
+ ;
+ else if (TREE_CODE (decl) == VAR_DECL && !DECL_EXTERNAL (decl))
varpool_node (decl);
}
void
finish_optimization_passes (void)
{
- enum tree_dump_index i;
+ int i;
struct dump_file_info *dfi;
char *name;
{
{
GIMPLE_PASS,
- NULL, /* name */
+ "*rest_of_compilation", /* name */
gate_rest_of_compilation, /* gate */
NULL, /* execute */
NULL, /* sub */
{
{
RTL_PASS,
- NULL, /* name */
+ "*all-postreload", /* name */
gate_postreload, /* gate */
NULL, /* execute */
NULL, /* sub */
NULL, /* next */
0, /* static_pass_number */
- 0, /* tv_id */
+ TV_NONE, /* tv_id */
PROP_rtl, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
/* 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;
+
+/* This is used by plugins, and should also be used in register_pass. */
+#define DEF_PASS_LIST(LIST) &LIST,
+struct opt_pass **gcc_pass_lists[] = { GCC_PASS_LISTS NULL };
+#undef DEF_PASS_LIST
/* A map from static pass id to optimization pass. */
struct opt_pass **passes_by_id;
to do this depth first, and independent of whether the pass is
enabled or not. */
-static void
+void
register_one_dump_file (struct opt_pass *pass)
{
char *dot_name, *flag_name, *glob_name;
- const char *prefix;
+ const char *name, *prefix;
char num[10];
int flags, id;
sprintf (num, "%d", ((int) pass->static_pass_number < 0
? 1 : pass->static_pass_number));
- dot_name = concat (".", pass->name, num, NULL);
+ /* The name is both used to identify the pass for the purposes of plugins,
+ and to specify dump file name and option.
+ The latter two might want something short which is not quite unique; for
+ that reason, we may have a disambiguating prefix, followed by a space
+ to mark the start of the following dump file name / option string. */
+ name = strchr (pass->name, ' ');
+ name = name ? name + 1 : pass->name;
+ dot_name = concat (".", name, num, NULL);
if (pass->type == SIMPLE_IPA_PASS || pass->type == IPA_PASS)
prefix = "ipa-", flags = TDF_IPA;
else if (pass->type == GIMPLE_PASS)
else
prefix = "rtl-", flags = TDF_RTL;
- flag_name = concat (prefix, pass->name, num, NULL);
- glob_name = concat (prefix, pass->name, NULL);
+ flag_name = concat (prefix, name, num, NULL);
+ glob_name = concat (prefix, name, NULL);
id = dump_register (dot_name, flag_name, glob_name, flags);
set_pass_for_id (id, pass);
}
/* Recursive worker function for register_dump_files. */
-static int
+static int
register_dump_files_1 (struct opt_pass *pass, int properties)
{
do
return properties;
}
-/* Register the dump files for the pipeline starting at PASS.
+/* Register the dump files for the pipeline starting at PASS.
PROPERTIES reflects the properties that are guaranteed to be available at
the beginning of the pipeline. */
-static void
+static void
register_dump_files (struct opt_pass *pass,int properties)
{
pass->properties_required |= properties;
register_dump_files_1 (pass, properties);
}
-/* Add a pass to the pass list. Duplicate the pass if it's already
- in the list. */
+/* Look at the static_pass_number and duplicate the pass
+ if it is already added to a list. */
-static struct opt_pass **
-next_pass_1 (struct opt_pass **list, struct opt_pass *pass)
+static struct opt_pass *
+make_pass_instance (struct opt_pass *pass, bool track_duplicates)
{
/* A nonzero static_pass_number indicates that the
pass is already in the list. */
{
struct opt_pass *new_pass;
- new_pass = XNEW (struct opt_pass);
- memcpy (new_pass, pass, sizeof (*new_pass));
+ if (pass->type == GIMPLE_PASS
+ || pass->type == RTL_PASS
+ || pass->type == SIMPLE_IPA_PASS)
+ {
+ new_pass = XNEW (struct opt_pass);
+ memcpy (new_pass, pass, sizeof (struct opt_pass));
+ }
+ else if (pass->type == IPA_PASS)
+ {
+ new_pass = (struct opt_pass *)XNEW (struct ipa_opt_pass_d);
+ memcpy (new_pass, pass, sizeof (struct ipa_opt_pass_d));
+ }
+ else
+ gcc_unreachable ();
+
new_pass->next = NULL;
new_pass->todo_flags_start &= ~TODO_mark_first_instance;
and so it should rename the dump file. The first instance will
be -1, and be number of duplicates = -static_pass_number - 1.
Subsequent instances will be > 0 and just the duplicate number. */
- if (pass->name)
+ if ((pass->name && pass->name[0] != '*') || track_duplicates)
{
pass->static_pass_number -= 1;
new_pass->static_pass_number = -pass->static_pass_number;
}
-
- *list = new_pass;
+ return new_pass;
}
else
{
pass->todo_flags_start |= TODO_mark_first_instance;
pass->static_pass_number = -1;
- *list = pass;
- }
-
+
+ invoke_plugin_callbacks (PLUGIN_NEW_PASS, pass);
+ }
+ return pass;
+}
+
+/* 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)
+{
+ /* Every pass should have a name so that plugins can refer to them. */
+ gcc_assert (pass->name != NULL);
+
+ *list = make_pass_instance (pass, false);
+
return &(*list)->next;
-
}
+/* List node for an inserted pass instance. We need to keep track of all
+ the newly-added pass instances (with 'added_pass_nodes' defined below)
+ so that we can register their dump files after pass-positioning is finished.
+ Registering dumping files needs to be post-processed or the
+ static_pass_number of the opt_pass object would be modified and mess up
+ the dump file names of future pass instances to be added. */
+
+struct pass_list_node
+{
+ struct opt_pass *pass;
+ struct pass_list_node *next;
+};
+
+static struct pass_list_node *added_pass_nodes = NULL;
+static struct pass_list_node *prev_added_pass_node;
+
+/* Insert the pass at the proper position. Return true if the pass
+ is successfully added.
+
+ NEW_PASS_INFO - new pass to be inserted
+ 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)
+{
+ struct opt_pass *pass = *pass_list, *prev_pass = NULL;
+ bool success = false;
+
+ for ( ; pass; prev_pass = pass, pass = pass->next)
+ {
+ /* Check if the current pass is of the same type as the new pass and
+ matches the name and the instance number of the reference pass. */
+ if (pass->type == new_pass_info->pass->type
+ && pass->name
+ && !strcmp (pass->name, new_pass_info->reference_pass_name)
+ && ((new_pass_info->ref_pass_instance_number == 0)
+ || (new_pass_info->ref_pass_instance_number ==
+ pass->static_pass_number)
+ || (new_pass_info->ref_pass_instance_number == 1
+ && pass->todo_flags_start & TODO_mark_first_instance)))
+ {
+ struct opt_pass *new_pass;
+ struct pass_list_node *new_pass_node;
+
+ new_pass = make_pass_instance (new_pass_info->pass, true);
+
+ /* Insert the new pass instance based on the positioning op. */
+ switch (new_pass_info->pos_op)
+ {
+ case PASS_POS_INSERT_AFTER:
+ new_pass->next = pass->next;
+ pass->next = new_pass;
+
+ /* Skip newly inserted pass to avoid repeated
+ insertions in the case where the new pass and the
+ existing one have the same name. */
+ pass = new_pass;
+ break;
+ case PASS_POS_INSERT_BEFORE:
+ new_pass->next = pass;
+ if (prev_pass)
+ prev_pass->next = new_pass;
+ else
+ *pass_list = new_pass;
+ break;
+ case PASS_POS_REPLACE:
+ new_pass->next = pass->next;
+ if (prev_pass)
+ prev_pass->next = new_pass;
+ else
+ *pass_list = new_pass;
+ new_pass->sub = pass->sub;
+ new_pass->tv_id = pass->tv_id;
+ pass = new_pass;
+ break;
+ default:
+ error ("Invalid pass positioning operation");
+ return false;
+ }
+
+ /* Save the newly added pass (instance) in the added_pass_nodes
+ list so that we can register its dump file later. Note that
+ we cannot register the dump file now because doing so will modify
+ the static_pass_number of the opt_pass object and therefore
+ mess up the dump file name of future instances. */
+ new_pass_node = XCNEW (struct pass_list_node);
+ new_pass_node->pass = new_pass;
+ if (!added_pass_nodes)
+ added_pass_nodes = new_pass_node;
+ else
+ prev_added_pass_node->next = new_pass_node;
+ prev_added_pass_node = new_pass_node;
+
+ success = true;
+ }
+
+ if (pass->sub && position_pass (new_pass_info, &pass->sub))
+ success = true;
+ }
+
+ return success;
+}
+
+/* Hooks a new pass into the pass lists.
+
+ PASS_INFO - pass information that specifies the opt_pass object,
+ reference pass, instance number, and how to position
+ the pass */
+
+void
+register_pass (struct register_pass_info *pass_info)
+{
+ bool all_instances, success;
+
+ /* 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");
+
+ if (!pass_info->pass->name)
+ fatal_error ("plugin cannot register an unnamed pass");
+
+ if (!pass_info->reference_pass_name)
+ 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 five lists as the reference pass could be in one (or all) of
+ them. */
+ all_instances = pass_info->ref_pass_instance_number == 0;
+ success = position_pass (pass_info, &all_lowering_passes);
+ if (!success || all_instances)
+ 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_passes);
+ if (!success)
+ fatal_error
+ ("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
+ the dump files for the newly added pass and its duplicates (if any).
+ Because the registration of plugin/backend passes happens after the
+ command-line options are parsed, the options that specify single
+ pass dumping (e.g. -fdump-tree-PASSNAME) cannot be used for new
+ passes. Therefore we currently can only enable dumping of
+ new passes when the 'dump-all' flags (e.g. -fdump-tree-all)
+ are specified. While doing so, we also delete the pass_list_node
+ objects created during pass positioning. */
+ while (added_pass_nodes)
+ {
+ struct pass_list_node *next_node = added_pass_nodes->next;
+ enum tree_dump_index tdi;
+ register_one_dump_file (added_pass_nodes->pass);
+ if (added_pass_nodes->pass->type == SIMPLE_IPA_PASS
+ || added_pass_nodes->pass->type == IPA_PASS)
+ tdi = TDI_ipa_all;
+ else if (added_pass_nodes->pass->type == GIMPLE_PASS)
+ tdi = TDI_tree_all;
+ else
+ tdi = TDI_rtl_all;
+ /* Check if dump-all flag is specified. */
+ if (get_dump_file_info (tdi)->state)
+ get_dump_file_info (added_pass_nodes->pass->static_pass_number)
+ ->state = get_dump_file_info (tdi)->state;
+ XDELETE (added_pass_nodes);
+ added_pass_nodes = next_node;
+ }
+}
/* Construct the pass tree. The sequencing of passes is driven by
the cgraph routines:
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)
backend might produce already lowered functions that are not processed
by these passes. */
p = &all_lowering_passes;
- NEXT_PASS (pass_remove_useless_stmts);
+ NEXT_PASS (pass_warn_unused_result);
+ NEXT_PASS (pass_diagnose_omp_blocks);
NEXT_PASS (pass_mudflap_1);
NEXT_PASS (pass_lower_omp);
NEXT_PASS (pass_lower_cf);
NEXT_PASS (pass_refactor_eh);
NEXT_PASS (pass_lower_eh);
NEXT_PASS (pass_build_cfg);
- NEXT_PASS (pass_lower_complex_O0);
NEXT_PASS (pass_lower_vector);
NEXT_PASS (pass_warn_function_return);
NEXT_PASS (pass_build_cgraph_edges);
*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);
{
NEXT_PASS (pass_inline_parameters);
NEXT_PASS (pass_rebuild_cgraph_edges);
}
+ NEXT_PASS (pass_ipa_free_lang_data);
NEXT_PASS (pass_early_local_passes);
{
struct opt_pass **p = &pass_early_local_passes.pass.sub;
+ NEXT_PASS (pass_fixup_cfg);
NEXT_PASS (pass_tree_profile);
NEXT_PASS (pass_cleanup_cfg);
NEXT_PASS (pass_init_datastructures);
NEXT_PASS (pass_expand_omp);
NEXT_PASS (pass_referenced_vars);
- NEXT_PASS (pass_reset_cc_flags);
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);
NEXT_PASS (pass_forwprop);
- NEXT_PASS (pass_update_address_taken);
+ /* pass_build_ealias is a dummy pass that ensures that we
+ execute TODO_rebuild_alias at this point. Re-building
+ alias information also rewrites no longer addressed
+ locals into SSA form if possible. */
+ NEXT_PASS (pass_build_ealias);
NEXT_PASS (pass_sra_early);
NEXT_PASS (pass_copy_prop);
NEXT_PASS (pass_merge_phi);
NEXT_PASS (pass_cd_dce);
- NEXT_PASS (pass_simple_dse);
+ NEXT_PASS (pass_early_ipa_sra);
NEXT_PASS (pass_tail_recursion);
NEXT_PASS (pass_convert_switch);
+ NEXT_PASS (pass_cleanup_eh);
NEXT_PASS (pass_profile);
+ NEXT_PASS (pass_local_pure_const);
}
NEXT_PASS (pass_release_ssa_names);
NEXT_PASS (pass_rebuild_cgraph_edges);
+ NEXT_PASS (pass_inline_parameters);
}
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_profile);
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_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_finish_out); /* This must be the last LTO pass. */
*p = NULL;
/* These passes are run after IPA passes on every function that is being
output to the assembler file. */
p = &all_passes;
+ NEXT_PASS (pass_lower_eh_dispatch);
NEXT_PASS (pass_all_optimizations);
{
struct opt_pass **p = &pass_all_optimizations.pass.sub;
+ NEXT_PASS (pass_remove_cgraph_callee_edges);
/* Initial scalar cleanups before alias computation.
They ensure memory accesses are not indirect wherever possible. */
+ NEXT_PASS (pass_strip_predict_hints);
NEXT_PASS (pass_update_address_taken);
NEXT_PASS (pass_rename_ssa_copies);
NEXT_PASS (pass_complete_unrolli);
NEXT_PASS (pass_ccp);
- /* Ideally the function call conditional
- dead code elimination phase can be delayed
- till later where potentially more opportunities
- can be found. Due to lack of good ways to
- update VDEFs associated with the shrink-wrapped
- calls, it is better to do the transformation
- here where memory SSA is not built yet. */
+ NEXT_PASS (pass_forwprop);
NEXT_PASS (pass_call_cdce);
/* pass_build_alias is a dummy pass that ensures that we
execute TODO_rebuild_alias at this point. Re-building
NEXT_PASS (pass_return_slot);
NEXT_PASS (pass_phiprop);
NEXT_PASS (pass_fre);
- NEXT_PASS (pass_dce);
- NEXT_PASS (pass_forwprop);
NEXT_PASS (pass_copy_prop);
NEXT_PASS (pass_merge_phi);
NEXT_PASS (pass_vrp);
NEXT_PASS (pass_dce);
NEXT_PASS (pass_cselim);
- NEXT_PASS (pass_dominator);
- /* The only const/copy propagation opportunities left after
- DOM should be due to degenerate PHI nodes. So rather than
- run the full propagators, run a specialized pass which
- only examines PHIs to discover const/copy propagation
- opportunities. */
- NEXT_PASS (pass_phi_only_cprop);
NEXT_PASS (pass_tree_ifcombine);
NEXT_PASS (pass_phiopt);
NEXT_PASS (pass_tail_recursion);
NEXT_PASS (pass_lower_complex);
NEXT_PASS (pass_sra);
NEXT_PASS (pass_rename_ssa_copies);
+ /* The dom pass will also resolve all __builtin_constant_p calls
+ that are still there to 0. This has to be done after some
+ propagations have already run, but before some more dead code
+ is removed, and this place fits nicely. Remember this when
+ trying to move or duplicate pass_dominator somewhere earlier. */
NEXT_PASS (pass_dominator);
/* The only const/copy propagation opportunities left after
DOM should be due to degenerate PHI nodes. So rather than
NEXT_PASS (pass_object_sizes);
NEXT_PASS (pass_ccp);
NEXT_PASS (pass_copy_prop);
- NEXT_PASS (pass_fold_builtins);
NEXT_PASS (pass_cse_sincos);
+ NEXT_PASS (pass_optimize_bswap);
NEXT_PASS (pass_split_crit_edges);
NEXT_PASS (pass_pre);
NEXT_PASS (pass_sink_code);
{
struct opt_pass **p = &pass_tree_loop.pass.sub;
NEXT_PASS (pass_tree_loop_init);
+ NEXT_PASS (pass_lim);
NEXT_PASS (pass_copy_prop);
NEXT_PASS (pass_dce_loop);
- NEXT_PASS (pass_lim);
- NEXT_PASS (pass_predcom);
NEXT_PASS (pass_tree_unswitch);
NEXT_PASS (pass_scev_cprop);
- NEXT_PASS (pass_empty_loop);
NEXT_PASS (pass_record_bounds);
NEXT_PASS (pass_check_data_deps);
NEXT_PASS (pass_loop_distribution);
NEXT_PASS (pass_linear_transform);
+ NEXT_PASS (pass_graphite_transforms);
+ {
+ struct opt_pass **p = &pass_graphite_transforms.pass.sub;
+ NEXT_PASS (pass_copy_prop);
+ NEXT_PASS (pass_dce_loop);
+ NEXT_PASS (pass_lim);
+ }
NEXT_PASS (pass_iv_canon);
NEXT_PASS (pass_if_conversion);
NEXT_PASS (pass_vectorize);
NEXT_PASS (pass_lower_vector_ssa);
NEXT_PASS (pass_dce_loop);
}
+ NEXT_PASS (pass_predcom);
NEXT_PASS (pass_complete_unroll);
+ NEXT_PASS (pass_slp_vectorize);
NEXT_PASS (pass_parallelize_loops);
NEXT_PASS (pass_loop_prefetch);
NEXT_PASS (pass_iv_optimize);
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);
we may get false warnings (e.g., testsuite/gcc.dg/uninit-5.c).
However, this also causes us to misdiagnose cases that should be
real warnings (e.g., testsuite/gcc.dg/pr18501.c).
-
+
To fix the false positives in uninit-5.c, we would have to
account for the predicates protecting the set and the use of each
variable. Using a representation like Gated Single Assignment
NEXT_PASS (pass_dse);
NEXT_PASS (pass_forwprop);
NEXT_PASS (pass_phiopt);
+ NEXT_PASS (pass_fold_builtins);
+ NEXT_PASS (pass_optimize_widening_mul);
NEXT_PASS (pass_tail_calls);
NEXT_PASS (pass_rename_ssa_copies);
NEXT_PASS (pass_uncprop);
+ NEXT_PASS (pass_local_pure_const);
}
- NEXT_PASS (pass_del_ssa);
+ NEXT_PASS (pass_lower_complex_O0);
+ NEXT_PASS (pass_cleanup_eh);
+ NEXT_PASS (pass_lower_resx);
NEXT_PASS (pass_nrv);
- NEXT_PASS (pass_mark_used_blocks);
+ NEXT_PASS (pass_mudflap_2);
NEXT_PASS (pass_cleanup_cfg_post_optimizing);
-
NEXT_PASS (pass_warn_function_noreturn);
- NEXT_PASS (pass_free_datastructures);
- NEXT_PASS (pass_mudflap_2);
- NEXT_PASS (pass_free_cfg_annotations);
NEXT_PASS (pass_expand);
+
NEXT_PASS (pass_rest_of_compilation);
{
struct opt_pass **p = &pass_rest_of_compilation.pass.sub;
NEXT_PASS (pass_df_initialize_opt);
NEXT_PASS (pass_cse);
NEXT_PASS (pass_rtl_fwprop);
- NEXT_PASS (pass_gcse);
+ NEXT_PASS (pass_rtl_cprop);
+ NEXT_PASS (pass_rtl_pre);
+ NEXT_PASS (pass_rtl_hoist);
+ NEXT_PASS (pass_rtl_cprop);
+ 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. */
*p = NULL;
}
NEXT_PASS (pass_web);
- NEXT_PASS (pass_jump_bypass);
+ NEXT_PASS (pass_rtl_cprop);
NEXT_PASS (pass_cse2);
NEXT_PASS (pass_rtl_dse1);
NEXT_PASS (pass_rtl_fwprop_addr);
- NEXT_PASS (pass_regclass_init);
NEXT_PASS (pass_inc_dec);
NEXT_PASS (pass_initialize_regs);
- NEXT_PASS (pass_outof_cfg_layout_mode);
NEXT_PASS (pass_ud_rtl_dce);
NEXT_PASS (pass_combine);
NEXT_PASS (pass_if_after_combine);
NEXT_PASS (pass_partition_blocks);
NEXT_PASS (pass_regmove);
+ NEXT_PASS (pass_outof_cfg_layout_mode);
NEXT_PASS (pass_split_all_insns);
NEXT_PASS (pass_lower_subreg2);
NEXT_PASS (pass_df_initialize_no_opt);
NEXT_PASS (pass_stack_ptr_mod);
NEXT_PASS (pass_mode_switching);
- NEXT_PASS (pass_see);
NEXT_PASS (pass_match_asm_constraints);
NEXT_PASS (pass_sms);
NEXT_PASS (pass_sched);
- NEXT_PASS (pass_subregs_of_mode_init);
- NEXT_PASS (pass_local_alloc);
- NEXT_PASS (pass_global_alloc);
- NEXT_PASS (pass_subregs_of_mode_finish);
+ NEXT_PASS (pass_ira);
NEXT_PASS (pass_postreload);
{
struct opt_pass **p = &pass_postreload.pass.sub;
NEXT_PASS (pass_branch_target_load_optimize1);
NEXT_PASS (pass_thread_prologue_and_epilogue);
NEXT_PASS (pass_rtl_dse2);
- NEXT_PASS (pass_rtl_seqabstr);
NEXT_PASS (pass_stack_adjustments);
NEXT_PASS (pass_peephole2);
NEXT_PASS (pass_if_after_reload);
/* Register the passes with the tree dump code. */
register_dump_files (all_lowering_passes, PROP_gimple_any);
- all_lowering_passes->todo_flags_start |= TODO_set_props;
- 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,
+ register_dump_files (all_passes,
PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh
| PROP_cfg);
}
/* 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. */
+ call CALLBACK on the current function. */
static void
do_per_function (void (*callback) (void *data), void *data)
{
struct cgraph_node *node;
for (node = cgraph_nodes; node; node = node->next)
- if (node->analyzed)
+ if (node->analyzed && gimple_has_body_p (node->decl)
+ && (!node->clone_of || node->decl != node->clone_of->decl))
{
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 ();
/* 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 void
+ 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)
{
int i;
gcc_assert (!order);
order = GGC_NEWVEC (struct cgraph_node *, cgraph_n_nodes);
nnodes = cgraph_postorder (order);
+ for (i = nnodes - 1; i >= 0; i--)
+ order[i]->process = 1;
for (i = nnodes - 1; i >= 0; i--)
{
struct cgraph_node *node = order[i];
/* Allow possibly removed nodes to be garbage collected. */
order[i] = NULL;
- if (node->analyzed && (node->needed || node->reachable))
+ node->process = 0;
+ if (node->analyzed)
{
push_cfun (DECL_STRUCT_FUNCTION (node->decl));
current_function_decl = node->decl;
if (cleanup && (cfun->curr_properties & PROP_ssa))
flags |= TODO_remove_unused_locals;
-
+
/* When cleanup_tree_cfg merges consecutive blocks, it may
perform some simplistic propagation when removing single
valued PHI nodes. This propagation may, in turn, cause the
SSA form to become out-of-date (see PR 22037). So, even
if the parent pass had not scheduled an SSA update, we may
still need to do one. */
- if (!(flags & TODO_update_ssa_any) && need_ssa_update_p ())
+ if (!(flags & TODO_update_ssa_any) && need_ssa_update_p (cfun))
flags |= TODO_update_ssa;
}
update_ssa (update_flags);
cfun->last_verified &= ~TODO_verify_ssa;
}
-
+
+ if (flags & TODO_update_address_taken)
+ execute_update_addresses_taken (true);
+
if (flags & TODO_rebuild_alias)
{
+ if (!(flags & TODO_update_address_taken))
+ execute_update_addresses_taken (true);
compute_may_aliases ();
- cfun->curr_properties |= PROP_alias;
}
-
+
if (flags & TODO_remove_unused_locals)
remove_unused_locals ();
}
#if defined ENABLE_CHECKING
- if (flags & TODO_verify_ssa)
+ if (flags & TODO_verify_ssa
+ || (current_loops && loops_state_satisfies_p (LOOP_CLOSED_SSA)))
verify_ssa (true);
if (flags & TODO_verify_flow)
verify_flow_info ();
if (flags & TODO_verify_stmts)
verify_stmts ();
- if (flags & TODO_verify_loops)
- verify_loop_closed_ssa ();
+ if (current_loops && loops_state_satisfies_p (LOOP_CLOSED_SSA))
+ verify_loop_closed_ssa (false);
if (flags & TODO_verify_rtl_sharing)
verify_rtl_sharing ();
#endif
execute_todo (unsigned int flags)
{
#if defined ENABLE_CHECKING
- if (need_ssa_update_p ())
+ if (cfun
+ && need_ssa_update_p (cfun))
gcc_assert (flags & TODO_update_ssa_any);
#endif
if (flags & TODO_ggc_collect)
ggc_collect ();
- /* Now that the dumping has been done, we can get rid of the optional
+ /* Now that the dumping has been done, we can get rid of the optional
df problems. */
if (flags & TODO_df_finish)
df_finish_pass ((flags & TODO_df_verify) != 0);
#endif
/* Initialize pass dump file. */
+/* This is non-static so that the plugins can use it. */
-static bool
+bool
pass_init_dump_file (struct opt_pass *pass)
{
/* If a dump file name is present, open it if enabled. */
if (dump_file && current_function_decl)
{
const char *dname, *aname;
+ struct cgraph_node *node = cgraph_node (current_function_decl);
dname = lang_hooks.decl_printable_name (current_function_decl, 2);
aname = (IDENTIFIER_POINTER
(DECL_ASSEMBLER_NAME (current_function_decl)));
fprintf (dump_file, "\n;; Function %s (%s)%s\n\n", dname, aname,
- cfun->function_frequency == FUNCTION_FREQUENCY_HOT
+ node->frequency == NODE_FREQUENCY_HOT
? " (hot)"
- : cfun->function_frequency == FUNCTION_FREQUENCY_UNLIKELY_EXECUTED
+ : node->frequency == NODE_FREQUENCY_UNLIKELY_EXECUTED
? " (unlikely executed)"
+ : node->frequency == NODE_FREQUENCY_EXECUTED_ONCE
+ ? " (executed once)"
: "");
}
return initializing_dump;
}
/* Flush PASS dump file. */
+/* This is non-static so that plugins can use it. */
-static void
+void
pass_fini_dump_file (struct opt_pass *pass)
{
/* Flush and close dump file. */
& ~pass->properties_destroyed;
}
-/* Schedule IPA transform pass DATA for CFUN. */
-
-static void
-add_ipa_transform_pass (void *data)
-{
- struct ipa_opt_pass *ipa_pass = (struct ipa_opt_pass *) data;
- VEC_safe_push (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply, ipa_pass);
-}
-
/* Execute summary generation for all of the passes in IPA_PASS. */
-static void
-execute_ipa_summary_passes (struct ipa_opt_pass *ipa_pass)
+void
+execute_ipa_summary_passes (struct ipa_opt_pass_d *ipa_pass)
{
while (ipa_pass)
{
struct opt_pass *pass = &ipa_pass->pass;
/* Execute all of the IPA_PASSes in the list. */
- if (ipa_pass->pass.type == IPA_PASS
- && (!pass->gate || pass->gate ()))
+ if (ipa_pass->pass.type == IPA_PASS
+ && (!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 *)ipa_pass->pass.next;
+ ipa_pass = (struct ipa_opt_pass_d *)ipa_pass->pass.next;
}
}
static void
execute_one_ipa_transform_pass (struct cgraph_node *node,
- struct ipa_opt_pass *ipa_pass)
+ struct ipa_opt_pass_d *ipa_pass)
{
struct opt_pass *pass = &ipa_pass->pass;
unsigned int todo_after = 0;
execute_todo (ipa_pass->function_transform_todo_flags_start);
/* If a timevar is present, start it. */
- if (pass->tv_id)
+ if (pass->tv_id != TV_NONE)
timevar_push (pass->tv_id);
/* Do it! */
todo_after = ipa_pass->function_transform (node);
/* Stop timevar. */
- if (pass->tv_id)
+ if (pass->tv_id != TV_NONE)
timevar_pop (pass->tv_id);
/* Run post-pass cleanup and verification. */
current_pass = NULL;
}
-static bool
+/* For the current function, execute all ipa transforms. */
+
+void
+execute_all_ipa_transforms (void)
+{
+ enum cgraph_state old_state = cgraph_state;
+ struct cgraph_node *node;
+ if (!cfun)
+ return;
+ node = cgraph_node (current_function_decl);
+
+ /* Statement verification skip verification of nothorw when
+ state is IPA_SSA because we do not modify function bodies
+ after setting the flag on function. Instead we leave it
+ to fixup_cfg to do such a transformation. We need to temporarily
+ change the cgraph state so statement verifier before
+ transform do not fire. */
+ cgraph_state = CGRAPH_STATE_IPA_SSA;
+
+ if (node->ipa_transforms_to_apply)
+ {
+ unsigned int i;
+
+ for (i = 0; i < VEC_length (ipa_opt_pass, node->ipa_transforms_to_apply);
+ i++)
+ execute_one_ipa_transform_pass (node,
+ VEC_index (ipa_opt_pass,
+ node->ipa_transforms_to_apply,
+ i));
+ VEC_free (ipa_opt_pass, heap, node->ipa_transforms_to_apply);
+ node->ipa_transforms_to_apply = NULL;
+ }
+ cgraph_state = old_state;
+}
+
+/* Execute PASS. */
+
+bool
execute_one_pass (struct opt_pass *pass)
{
bool initializing_dump;
unsigned int todo_after = 0;
+ bool gate_status;
+
/* 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)
else
gcc_assert (cfun && current_function_decl);
- if (cfun && cfun->ipa_transforms_to_apply)
- {
- unsigned int i;
- struct cgraph_node *node = cgraph_node (current_function_decl);
+ current_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,
- cfun->ipa_transforms_to_apply,
- i));
- VEC_free (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply);
- cfun->ipa_transforms_to_apply = NULL;
- }
+ /* Check whether gate check should be avoided.
+ User controls the value of the gate through the parameter "gate_status". */
+ gate_status = (pass->gate == NULL) ? true : pass->gate();
- current_pass = pass;
+ /* Override gate with plugin. */
+ invoke_plugin_callbacks (PLUGIN_OVERRIDE_GATE, &gate_status);
- /* See if we're supposed to run this pass. */
- if (pass->gate && !pass->gate ())
- return false;
+ if (!gate_status)
+ {
+ current_pass = NULL;
+ return false;
+ }
+
+ /* Pass execution event trigger: useful to identify passes being
+ executed. */
+ invoke_plugin_callbacks (PLUGIN_PASS_EXECUTION, pass);
if (!quiet_flag && !cfun)
fprintf (stderr, " <%s>", pass->name ? pass->name : "");
- if (pass->todo_flags_start & TODO_set_props)
- cfun->curr_properties = pass->properties_required;
-
/* Note that the folders should only create gimple expressions.
This is a hack until the new folder is ready. */
in_gimple_form = (cfun && (cfun->curr_properties & PROP_trees)) != 0;
+ initializing_dump = pass_init_dump_file (pass);
+
/* Run pre-pass verification. */
execute_todo (pass->todo_flags_start);
(void *)(size_t)pass->properties_required);
#endif
- initializing_dump = pass_init_dump_file (pass);
-
/* If a timevar is present, start it. */
- if (pass->tv_id)
+ if (pass->tv_id != TV_NONE)
timevar_push (pass->tv_id);
/* Do it! */
}
/* Stop timevar. */
- if (pass->tv_id)
+ if (pass->tv_id != TV_NONE)
timevar_pop (pass->tv_id);
do_per_function (update_properties_after_pass, pass);
if (initializing_dump
&& dump_file
&& graph_dump_format != no_graph
+ && cfun
&& (cfun->curr_properties & (PROP_cfg | PROP_rtl))
== (PROP_cfg | PROP_rtl))
{
execute_todo (todo_after | pass->todo_flags_finish);
verify_interpass_invariants ();
if (pass->type == IPA_PASS)
- do_per_function (add_ipa_transform_pass, pass);
+ {
+ struct cgraph_node *node;
+ for (node = cgraph_nodes; node; node = node->next)
+ if (node->analyzed)
+ VEC_safe_push (ipa_opt_pass, heap, node->ipa_transforms_to_apply,
+ (struct ipa_opt_pass_d *)pass);
+ }
if (!current_function_decl)
cgraph_process_new_functions ();
while (pass);
}
+/* 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, cgraph_node_set set,
+ varpool_node_set vset,
+ 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,vset);
+
+ /* 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, vset, 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, varpool_node_set vset)
+{
+ struct lto_out_decl_state *state = lto_new_out_decl_state ();
+ lto_push_out_decl_state (state);
+
+ gcc_assert (!flag_wpa);
+ ipa_write_summaries_2 (all_regular_ipa_passes, set, vset, state);
+ ipa_write_summaries_2 (all_lto_gen_passes, set, vset, 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
+ipa_write_summaries (void)
+{
+ cgraph_node_set set;
+ varpool_node_set vset;
+ struct cgraph_node **order;
+ struct varpool_node *vnode;
+ int i, order_pos;
+
+ if (!flag_generate_lto || errorcount || sorrycount)
+ return;
+
+ 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--)
+ {
+ struct cgraph_node *node = order[i];
+
+ if (node->analyzed)
+ {
+ /* When streaming out references to statements as part of some IPA
+ pass summary, the statements need to have uids assigned and the
+ following does that for all the IPA passes here. Naturally, this
+ ordering then matches the one IPA-passes get in their stmt_fixup
+ hooks. */
+
+ push_cfun (DECL_STRUCT_FUNCTION (node->decl));
+ renumber_gimple_stmt_uids ();
+ pop_cfun ();
+ }
+ if (node->needed || node->reachable || node->address_taken)
+ cgraph_node_set_add (set, node);
+ }
+ vset = varpool_node_set_new ();
+
+ for (vnode = varpool_nodes; vnode; vnode = vnode->next)
+ if (vnode->needed && !vnode->alias)
+ varpool_node_set_add (vset, vnode);
+
+ ipa_write_summaries_1 (set, vset);
+
+ free (order);
+ ggc_free (set);
+ ggc_free (vset);
+}
+
+/* Same as execute_pass_list but assume that subpasses of IPA passes
+ are local passes. If SET is not NULL, write out optimization summaries of
+ only those node in SET. */
+
+static void
+ipa_write_optimization_summaries_1 (struct opt_pass *pass, cgraph_node_set set,
+ varpool_node_set vset,
+ 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_optimization_summary
+ && (!pass->gate || pass->gate ()))
+ {
+ /* If a timevar is present, start it. */
+ if (pass->tv_id)
+ timevar_push (pass->tv_id);
+
+ ipa_pass->write_optimization_summary (set, vset);
+
+ /* 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_optimization_summaries_1 (pass->sub, set, vset, state);
+
+ pass = pass->next;
+ }
+}
+
+/* Write all the optimization summaries for the cgraph nodes in SET. If SET is
+ NULL, write out all summaries of all nodes. */
+
+void
+ipa_write_optimization_summaries (cgraph_node_set set, varpool_node_set vset)
+{
+ struct lto_out_decl_state *state = lto_new_out_decl_state ();
+ lto_push_out_decl_state (state);
+
+ gcc_assert (flag_wpa);
+ ipa_write_optimization_summaries_1 (all_regular_ipa_passes, set, vset, state);
+ ipa_write_optimization_summaries_1 (all_lto_gen_passes, set, vset, state);
+
+ gcc_assert (lto_get_out_decl_state () == state);
+ lto_pop_out_decl_state ();
+ lto_delete_out_decl_state (state);
+}
+
/* 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->gate == NULL || pass->gate ())
+ {
+ if (pass->type == IPA_PASS && ipa_pass->read_summary)
+ {
+ /* 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);
+ }
+
+ 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
-execute_ipa_pass_list (struct opt_pass *pass)
+ipa_read_summaries (void)
{
- bool summaries_generated = false;
- do
+ 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. */
+
+static void
+ipa_read_optimization_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_optimization_summary)
{
- if (!quiet_flag && !cfun)
- fprintf (stderr, " <summary generate>");
- execute_ipa_summary_passes ((struct ipa_opt_pass *) pass);
+ /* If a timevar is present, start it. */
+ if (pass->tv_id)
+ timevar_push (pass->tv_id);
+
+ ipa_pass->read_optimization_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_optimization_summaries_1 (pass->sub);
}
+ pass = pass->next;
+ }
+}
+
+/* Read all the summaries for all_regular_ipa_passes and all_lto_gen_passes. */
+
+void
+ipa_read_optimization_summaries (void)
+{
+ ipa_read_optimization_summaries_1 (all_regular_ipa_passes);
+ ipa_read_optimization_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)
- do_per_function_toporder ((void (*)(void *))execute_pass_list,
- pass->sub);
+ {
+ invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_START, NULL);
+ do_per_function_toporder ((void (*)(void *))execute_pass_list,
+ pass->sub);
+ invoke_plugin_callbacks (PLUGIN_EARLY_GIMPLE_PASSES_END, NULL);
+ }
else if (pass->sub->type == SIMPLE_IPA_PASS
|| pass->sub->type == IPA_PASS)
execute_ipa_pass_list (pass->sub);
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);
}
+/* 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)
+{
+ while (pass)
+ {
+ /* Execute all of the IPA_PASSes in the list. */
+ if (pass->type == IPA_PASS
+ && (!pass->gate || pass->gate ()))
+ {
+ struct ipa_opt_pass_d *ipa_pass = (struct ipa_opt_pass_d *) pass;
+
+ if (ipa_pass->stmt_fixup)
+ {
+ pass_init_dump_file (pass);
+ /* If a timevar is present, start it. */
+ if (pass->tv_id)
+ timevar_push (pass->tv_id);
+
+ ipa_pass->stmt_fixup (node, stmts);
+
+ /* Stop timevar. */
+ if (pass->tv_id)
+ timevar_pop (pass->tv_id);
+ pass_fini_dump_file (pass);
+ }
+ if (pass->sub)
+ execute_ipa_stmt_fixups (pass->sub, node, stmts);
+ }
+ pass = pass->next;
+ }
+}
+
+/* Execute stmt fixup hooks of all IPA passes for NODE and STMTS. */
+
+void
+execute_all_ipa_stmt_fixups (struct cgraph_node *node, gimple *stmts)
+{
+ execute_ipa_stmt_fixups (all_regular_ipa_passes, node, stmts);
+}
+
+
+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");
+ if (props & PROP_gimple_lcx)
+ fprintf (dump, "PROP_gimple_lcx\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. */
+bool
+function_called_by_processed_nodes_p (void)
+{
+ struct cgraph_edge *e;
+ for (e = cgraph_node (current_function_decl)->callers; e; e = e->next_caller)
+ {
+ if (e->caller->decl == current_function_decl)
+ continue;
+ if (!e->caller->analyzed)
+ continue;
+ 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);
+ }
+ return e != NULL;
+}
+
#include "gt-passes.h"