X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fpasses.c;h=c087750cc19b5164c94c13f4ce912cd1ccbf32a6;hp=2d11c1f69878b56d2d0cdf69d655892b989ebe00;hb=a33890d064f843e2d810f02b80c0e049df944e51;hpb=e8eed2f8760fe42abb9f6228677dacd7a90271a8 diff --git a/gcc/passes.c b/gcc/passes.c index 2d11c1f6987..c087750cc19 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -1,6 +1,6 @@ /* 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. @@ -85,6 +85,7 @@ along with GCC; see the file COPYING3. If not see #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" @@ -104,7 +105,8 @@ along with GCC; see the file COPYING3. If not see #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 @@ -114,7 +116,7 @@ void 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"); @@ -126,7 +128,7 @@ void debug_pass (void) { print_current_pass (stderr); -} +} @@ -189,7 +191,11 @@ rest_of_decl_compilation (tree decl, || 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); @@ -216,7 +222,9 @@ rest_of_decl_compilation (tree decl, } /* 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); } @@ -314,7 +322,7 @@ struct rtl_opt_pass pass_postreload = { { RTL_PASS, - NULL, /* name */ + "*all-postreload", /* name */ gate_postreload, /* gate */ NULL, /* execute */ NULL, /* sub */ @@ -335,6 +343,11 @@ struct rtl_opt_pass pass_postreload = 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; int passes_by_id_size; @@ -374,7 +387,7 @@ 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; @@ -384,7 +397,14 @@ register_one_dump_file (struct opt_pass *pass) 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) @@ -392,15 +412,15 @@ register_one_dump_file (struct opt_pass *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 @@ -428,11 +448,11 @@ register_dump_files_1 (struct opt_pass *pass, int properties) 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; @@ -451,8 +471,21 @@ make_pass_instance (struct opt_pass *pass, bool track_duplicates) { 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; @@ -461,7 +494,7 @@ make_pass_instance (struct opt_pass *pass, bool track_duplicates) 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 || track_duplicates) + if ((pass->name && pass->name[0] != '*') || track_duplicates) { pass->static_pass_number -= 1; new_pass->static_pass_number = -pass->static_pass_number; @@ -472,8 +505,10 @@ make_pass_instance (struct opt_pass *pass, bool track_duplicates) { pass->todo_flags_start |= TODO_mark_first_instance; pass->static_pass_number = -1; - } - return pass; + + invoke_plugin_callbacks (PLUGIN_NEW_PASS, pass); + } + return pass; } /* Add a pass to the pass list. Duplicate the pass if it's already @@ -482,8 +517,11 @@ make_pass_instance (struct opt_pass *pass, bool track_duplicates) 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; } @@ -503,7 +541,7 @@ struct pass_list_node 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 +/* Insert the pass at the proper position. Return true if the pass is successfully added. NEW_PASS_INFO - new pass to be inserted @@ -533,7 +571,7 @@ position_pass (struct register_pass_info *new_pass_info, 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) { @@ -544,7 +582,7 @@ position_pass (struct register_pass_info *new_pass_info, /* 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; + pass = new_pass; break; case PASS_POS_INSERT_BEFORE: new_pass->next = pass; @@ -600,6 +638,8 @@ position_pass (struct register_pass_info *new_pass_info, 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. */ @@ -615,46 +655,50 @@ register_pass (struct register_pass_info *pass_info) 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 + all five 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_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)) + 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); - else + + /* 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) { - /* 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; - } + 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; } } @@ -696,7 +740,6 @@ init_optimization_passes (void) 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); @@ -705,6 +748,7 @@ init_optimization_passes (void) /* Interprocedural optimization passes. */ p = &all_small_ipa_passes; + NEXT_PASS (pass_ipa_free_lang_data); NEXT_PASS (pass_ipa_function_and_variable_visibility); NEXT_PASS (pass_ipa_early_inline); { @@ -713,7 +757,6 @@ init_optimization_passes (void) 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; @@ -766,10 +809,11 @@ init_optimization_passes (void) 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); @@ -777,7 +821,6 @@ init_optimization_passes (void) 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; @@ -848,9 +891,9 @@ init_optimization_passes (void) { 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_tree_unswitch); NEXT_PASS (pass_scev_cprop); NEXT_PASS (pass_record_bounds); @@ -860,6 +903,7 @@ init_optimization_passes (void) 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); } @@ -880,7 +924,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); @@ -897,7 +940,7 @@ init_optimization_passes (void) 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 @@ -907,11 +950,13 @@ init_optimization_passes (void) 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); @@ -1028,23 +1073,23 @@ 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_small_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, + 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, + 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) @@ -1081,9 +1126,9 @@ static GTY ((length ("nnodes"))) struct cgraph_node **order; /* 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; @@ -1143,7 +1188,7 @@ execute_function_todo (void *data) 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 @@ -1160,7 +1205,7 @@ execute_function_todo (void *data) update_ssa (update_flags); cfun->last_verified &= ~TODO_verify_ssa; } - + if (flags & TODO_update_address_taken) execute_update_addresses_taken (true); @@ -1170,7 +1215,7 @@ execute_function_todo (void *data) execute_update_addresses_taken (true); compute_may_aliases (); } - + if (flags & TODO_remove_unused_locals) remove_unused_locals (); @@ -1218,14 +1263,15 @@ execute_function_todo (void *data) } #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 @@ -1270,7 +1316,7 @@ execute_todo (unsigned int flags) 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); @@ -1308,8 +1354,9 @@ verify_curr_properties (void *data) #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. */ @@ -1321,14 +1368,17 @@ pass_init_dump_file (struct opt_pass *pass) 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; @@ -1338,8 +1388,9 @@ pass_init_dump_file (struct opt_pass *pass) } /* 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. */ @@ -1367,15 +1418,6 @@ update_properties_after_pass (void *data) & ~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. */ void @@ -1386,7 +1428,7 @@ execute_ipa_summary_passes (struct ipa_opt_pass_d *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 + if (ipa_pass->pass.type == IPA_PASS && (!pass->gate || pass->gate ()) && ipa_pass->generate_summary) { @@ -1455,30 +1497,46 @@ execute_one_ipa_transform_pass (struct cgraph_node *node, void execute_all_ipa_transforms (void) { - if (cfun && cfun->ipa_transforms_to_apply) + 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; - struct cgraph_node *node = cgraph_node (current_function_decl); - for (i = 0; i < VEC_length (ipa_opt_pass, cfun->ipa_transforms_to_apply); + 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, - cfun->ipa_transforms_to_apply, + node->ipa_transforms_to_apply, i)); - VEC_free (ipa_opt_pass, heap, cfun->ipa_transforms_to_apply); - cfun->ipa_transforms_to_apply = NULL; + VEC_free (ipa_opt_pass, heap, node->ipa_transforms_to_apply); + node->ipa_transforms_to_apply = NULL; } + cgraph_state = old_state; } /* Execute PASS. */ -static bool +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) @@ -1488,9 +1546,22 @@ execute_one_pass (struct opt_pass *pass) current_pass = pass; - /* See if we're supposed to run this pass. */ - if (pass->gate && !pass->gate ()) - return false; + /* 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(); + + /* Override gate with plugin. */ + invoke_plugin_callbacks (PLUGIN_OVERRIDE_GATE, &gate_status); + + 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 : ""); @@ -1542,7 +1613,13 @@ execute_one_pass (struct opt_pass *pass) 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 (); @@ -1578,6 +1655,7 @@ execute_pass_list (struct opt_pass *pass) 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) @@ -1594,7 +1672,7 @@ ipa_write_summaries_2 (struct opt_pass *pass, cgraph_node_set set, if (pass->tv_id) timevar_push (pass->tv_id); - ipa_pass->write_summary (set); + ipa_pass->write_summary (set,vset); /* If a timevar is present, start it. */ if (pass->tv_id) @@ -1602,7 +1680,7 @@ ipa_write_summaries_2 (struct opt_pass *pass, cgraph_node_set set, } if (pass->sub && pass->sub->type != GIMPLE_PASS) - ipa_write_summaries_2 (pass->sub, set, state); + ipa_write_summaries_2 (pass->sub, set, vset, state); pass = pass->next; } @@ -1613,13 +1691,17 @@ ipa_write_summaries_2 (struct opt_pass *pass, cgraph_node_set set, summaries. SET is the set of nodes to be written. */ static void -ipa_write_summaries_1 (cgraph_node_set set) +ipa_write_summaries_1 (cgraph_node_set set, varpool_node_set vset) { struct lto_out_decl_state *state = lto_new_out_decl_state (); + state->cgraph_node_encoder = lto_cgraph_encoder_new (); + state->varpool_node_encoder = lto_varpool_encoder_new (); + lto_push_out_decl_state (state); - ipa_write_summaries_2 (all_regular_ipa_passes, set, state); - ipa_write_summaries_2 (all_lto_gen_passes, set, 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 (); @@ -1632,13 +1714,14 @@ 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; - lto_new_extern_inline_states (); set = cgraph_node_set_new (); /* Create the callgraph set in the same order used in @@ -1650,24 +1733,92 @@ ipa_write_summaries (void) gcc_assert (order_pos == cgraph_n_nodes); for (i = order_pos - 1; i >= 0; i--) - cgraph_node_set_add (set, order[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); - lto_delete_extern_inline_states (); + 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); -/* Write all the summaries for the cgraph nodes in SET. If SET is + /* 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_summaries_of_cgraph_node_set (cgraph_node_set set) +ipa_write_optimization_summaries (cgraph_node_set set, varpool_node_set vset) { - if (flag_generate_lto && !(errorcount || sorrycount)) - ipa_write_summaries_1 (set); + struct lto_out_decl_state *state = lto_new_out_decl_state (); + state->cgraph_node_encoder = lto_cgraph_encoder_new (); + state->varpool_node_encoder = lto_varpool_encoder_new (); + 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 @@ -1718,6 +1869,51 @@ ipa_read_summaries (void) /* 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->gate == NULL || pass->gate ()) + { + if (pass->type == IPA_PASS && ipa_pass->read_optimization_summary) + { + /* 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); + } + + 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) { @@ -1729,8 +1925,12 @@ execute_ipa_pass_list (struct opt_pass *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); @@ -1744,6 +1944,50 @@ execute_ipa_pass_list (struct opt_pass *pass) 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); @@ -1769,6 +2013,8 @@ dump_properties (FILE *dump, unsigned int props) 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