> Hi. > > In order to fix the warnings mentioned in the PR, we need > to run remove_unreachable_nodes after early tree passes. That's > however possible only within a IPA pass. Thus I'm calling that > before the profile PASS. > > Patch survives regression tests on ppc64le-linux-gnu and majority > of warnings are gone in profiledbootstrap. > > Ready for trunk? > Thanks, > Martin > > gcc/ChangeLog: > > 2018-11-08 Martin Liska <mli...@suse.cz> > > * tree-profile.c: Run TODO_remove_functions before "profile" > pass in order to remove dead functions that will trigger > -Wmissing-profile.
Hi, it turns out there are few bugs on the way. First ipa.c has incomplete tests on when it needs to keep the functions. Also the function remval is actually scheduled in fnsummary1 pass that just run bit late because post-profile function splitting needs it. This is variant I ended up testing. My original plan to do it at the end of the early passes ipa pass did not fly because TODOs are run before subpasses (as already commented in ipa-fnsummary.c. So I ended up splitting ipa_fnsummary into two mini-passes. Bootstrapped/regtested x86_64-linux, plan to commit it shortly. Honza * ipa-fnsummary.c (pass_ipa_fnsummary): Do not remove functions * ipa.c (possible_inline_candidate_p): Break out from .. (process_references): ... here ; drop before_inlining_p; cleanup handling of alises. (walk_polymorphic_call_targets): Likewise. (symbol_table::remove_unreachable_nodes): Likewise. * passes.c (pass_data_ipa_remove_symbols): New structure. (pass_ipa_remove_symbols): New pass. (make_pass_ipa_remove_symbols): New functoin. * passes.def (pass_ipa_remove_symbols): Schedule after early passes. Index: ipa-fnsummary.c =================================================================== --- ipa-fnsummary.c (revision 266288) +++ ipa-fnsummary.c (working copy) @@ -3563,10 +3563,7 @@ public: virtual unsigned int execute (function *) { ipa_free_fn_summary (); - /* Early optimizations may make function unreachable. We can not - remove unreachable functions as part of the early opts pass because - TODOs are run before subpasses. Do it here. */ - return small_p ? TODO_remove_functions | TODO_dump_symtab : 0; + return 0; } private: Index: ipa.c =================================================================== --- ipa.c (revision 266288) +++ ipa.c (working copy) @@ -101,12 +101,32 @@ enqueue_node (symtab_node *node, symtab_ *first = node; } +/* Return true if NODE may get inlined later. + This is used to keep DECL_EXTERNAL function bodies around long enough + so inliner can proces them. */ + +static bool +possible_inline_candidate_p (symtab_node *node) +{ + if (symtab->state >= IPA_SSA_AFTER_INLINING) + return false; + cgraph_node *cnode = dyn_cast <cgraph_node *> (node); + if (!cnode) + return false; + if (DECL_UNINLINABLE (cnode->decl)) + return false; + if (opt_for_fn (cnode->decl, optimize)) + return true; + if (symtab->state >= IPA_SSA) + return false; + return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl)); +} + /* Process references. */ static void process_references (symtab_node *snode, symtab_node **first, - bool before_inlining_p, hash_set<symtab_node *> *reachable) { int i; @@ -118,14 +138,7 @@ process_references (symtab_node *snode, if (node->definition && !node->in_other_partition && ((!DECL_EXTERNAL (node->decl) || node->alias) - || (((before_inlining_p - && (TREE_CODE (node->decl) != FUNCTION_DECL - || (TREE_CODE (node->decl) == FUNCTION_DECL - && opt_for_fn (body->decl, optimize)) - || (symtab->state < IPA_SSA - && lookup_attribute - ("always_inline", - DECL_ATTRIBUTES (body->decl)))))) + || (possible_inline_candidate_p (node) /* We use variable constructors during late compilation for constant folding. Keep references alive so partitioning knows about potential references. */ @@ -140,7 +153,7 @@ process_references (symtab_node *snode, body. */ if (DECL_EXTERNAL (node->decl) && node->alias - && before_inlining_p) + && symtab->state < IPA_SSA_AFTER_INLINING) reachable->add (body); reachable->add (node); } @@ -160,8 +173,7 @@ static void walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets, struct cgraph_edge *edge, symtab_node **first, - hash_set<symtab_node *> *reachable, - bool before_inlining_p) + hash_set<symtab_node *> *reachable) { unsigned int i; void *cache_token; @@ -190,15 +202,14 @@ walk_polymorphic_call_targets (hash_set< /* Prior inlining, keep alive bodies of possible targets for devirtualization. */ if (n->definition - && (before_inlining_p - && opt_for_fn (body->decl, optimize) + && (possible_inline_candidate_p (body) && opt_for_fn (body->decl, flag_devirtualize))) { /* Be sure that we will not optimize out alias target body. */ if (DECL_EXTERNAL (n->decl) && n->alias - && before_inlining_p) + && symtab->state < IPA_SSA_AFTER_INLINING) reachable->add (body); reachable->add (n); } @@ -303,8 +314,6 @@ symbol_table::remove_unreachable_nodes ( hash_set<symtab_node *> reachable; hash_set<tree> body_needed_for_clonning; hash_set<void *> reachable_call_targets; - bool before_inlining_p = symtab->state < (!optimize && !in_lto_p ? IPA_SSA - : IPA_SSA_AFTER_INLINING); timevar_push (TV_IPA_UNREACHABLE); build_type_inheritance_graph (); @@ -396,7 +405,7 @@ symbol_table::remove_unreachable_nodes ( enqueue_node (next, &first, &reachable); } /* Mark references as reachable. */ - process_references (node, &first, before_inlining_p, &reachable); + process_references (node, &first, &reachable); } if (cgraph_node *cnode = dyn_cast <cgraph_node *> (node)) @@ -416,8 +425,7 @@ symbol_table::remove_unreachable_nodes ( next = e->next_callee; if (e->indirect_info->polymorphic) walk_polymorphic_call_targets (&reachable_call_targets, - e, &first, &reachable, - before_inlining_p); + e, &first, &reachable); } } for (e = cnode->callees; e; e = e->next_callee) @@ -428,18 +436,13 @@ symbol_table::remove_unreachable_nodes ( && (!e->inline_failed || !DECL_EXTERNAL (e->callee->decl) || e->callee->alias - || (before_inlining_p - && (opt_for_fn (body->decl, optimize) - || (symtab->state < IPA_SSA - && lookup_attribute - ("always_inline", - DECL_ATTRIBUTES (body->decl))))))) + || possible_inline_candidate_p (e->callee))) { /* Be sure that we will not optimize out alias target body. */ if (DECL_EXTERNAL (e->callee->decl) && e->callee->alias - && before_inlining_p) + && symtab->state < IPA_SSA_AFTER_INLINING) reachable.add (body); reachable.add (e->callee); } @@ -654,7 +657,7 @@ symbol_table::remove_unreachable_nodes ( of possible later devirtualization. Do not mark them as local too early so we won't optimize them out before we are done with polymorphic call analysis. */ - && (!before_inlining_p + && (symtab->state >= IPA_SSA_AFTER_INLINING || !node->call_for_symbol_and_aliases (is_indirect_call_target_p, NULL, true))) { Index: passes.c =================================================================== --- passes.c (revision 266288) +++ passes.c (working copy) @@ -459,6 +459,35 @@ public: }; // class pass_local_optimization_passes +const pass_data pass_data_ipa_remove_symbols = +{ + SIMPLE_IPA_PASS, /* type */ + "remove_symbols", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ + TV_NONE, /* tv_id */ + 0, /* properties_required */ + 0, /* properties_provided */ + 0, /* properties_destroyed */ + 0, /* todo_flags_start */ + TODO_remove_functions | TODO_dump_symtab, /* todo_flags_finish */ +}; + +class pass_ipa_remove_symbols : public simple_ipa_opt_pass +{ +public: + pass_ipa_remove_symbols (gcc::context *ctxt) + : simple_ipa_opt_pass (pass_data_ipa_remove_symbols, ctxt) + {} + + /* opt_pass methods: */ + virtual bool gate (function *) + { + /* Don't bother doing anything if the program has errors. */ + return (!seen_error () && !in_lto_p); + } + +}; // class pass_local_optimization_passes + } // anon namespace simple_ipa_opt_pass * @@ -473,6 +502,12 @@ make_pass_local_optimization_passes (gcc return new pass_local_optimization_passes (ctxt); } +simple_ipa_opt_pass * +make_pass_ipa_remove_symbols (gcc::context *ctxt) +{ + return new pass_ipa_remove_symbols (ctxt); +} + namespace { const pass_data pass_data_all_early_optimizations = Index: passes.def =================================================================== --- passes.def (revision 266288) +++ passes.def (working copy) @@ -106,6 +106,7 @@ along with GCC; see the file COPYING3. NEXT_PASS (pass_local_fn_summary); POP_INSERT_PASSES () + NEXT_PASS (pass_ipa_remove_symbols); NEXT_PASS (pass_ipa_oacc); PUSH_INSERT_PASSES_WITHIN (pass_ipa_oacc) NEXT_PASS (pass_ipa_pta); Index: testsuite/gcc.dg/ipa/ctor-empty-1.c =================================================================== --- testsuite/gcc.dg/ipa/ctor-empty-1.c (revision 266288) +++ testsuite/gcc.dg/ipa/ctor-empty-1.c (working copy) @@ -1,7 +1,7 @@ /* { dg-do compile } */ -/* { dg-options "-O3 -c -fdump-ipa-free-fnsummary1" } */ +/* { dg-options "-O3 -c -fdump-ipa-remove_symbols" } */ static __attribute__((constructor)) void empty_constructor() { } -/* { dg-final { scan-ipa-dump "Reclaiming functions: empty_constructor" "free-fnsummary1" } } */ +/* { dg-final { scan-ipa-dump "Reclaiming functions: empty_constructor" "remove_symbols" } } */