/* 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, 2009
+ 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);
}
{
{
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 */
/* 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;
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_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);
NEXT_PASS (pass_copy_prop);
NEXT_PASS (pass_merge_phi);
NEXT_PASS (pass_cd_dce);
+ NEXT_PASS (pass_early_ipa_sra);
NEXT_PASS (pass_tail_recursion);
NEXT_PASS (pass_convert_switch);
NEXT_PASS (pass_cleanup_eh);
}
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_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_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_lower_complex_O0);
NEXT_PASS (pass_cleanup_eh);
+ NEXT_PASS (pass_lower_resx);
NEXT_PASS (pass_nrv);
NEXT_PASS (pass_mudflap_2);
NEXT_PASS (pass_cleanup_cfg_post_optimizing);
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. */
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);
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_ira);
- NEXT_PASS (pass_subregs_of_mode_finish);
NEXT_PASS (pass_postreload);
{
struct opt_pass **p = &pass_postreload.pass.sub;
/* 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_passes,
+ 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,
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)
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;
/* 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;
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
update_ssa (update_flags);
cfun->last_verified &= ~TODO_verify_ssa;
}
-
+
if (flags & TODO_update_address_taken)
execute_update_addresses_taken (true);
execute_update_addresses_taken (true);
compute_may_aliases ();
}
-
+
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
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_d *ipa_pass = (struct ipa_opt_pass_d *) 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
+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_d *)ipa_pass->pass.next;
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;
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_d *) 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. */
{
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;