diff options
author | Jan Hubicka <jh@suse.cz> | 2013-09-08 18:42:21 +0200 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2013-09-08 16:42:21 +0000 |
commit | 3462aa02a699dc716bd366fee8fc1c85f7f94541 (patch) | |
tree | 6aaf6ed20bc90f69bf381f4674ecd79f8abee69c /gcc/ipa.c | |
parent | 26e5b0fd2818c746fcd016bd1b6fa434204a5d72 (diff) | |
download | gcc-3462aa02a699dc716bd366fee8fc1c85f7f94541.zip gcc-3462aa02a699dc716bd366fee8fc1c85f7f94541.tar.gz gcc-3462aa02a699dc716bd366fee8fc1c85f7f94541.tar.bz2 |
devirt-11.C: Update template.
* testsuite/g++.dg/ipa/devirt-11.C: Update template.
* testsuite/g++.dg/ipa/devirt-16.C: New testcase.
* testsuite/g++.dg/ipa/devirt-17.C: New testcase.
* testsuite/g++.dg/ipa/devirt-18.C: New testcase.
* cgraphunit.c (walk_polymorphic_call_targets): Permit 0 possible
targets and devirtualize to BUILT_IN_UNREACHABLE.
* timevar.def (TV_IPA_UNREACHABLE): New timevar.
* ipa.c (walk_polymorphic_call_targets): New function.
(symtab_remove_unreachable_nodes): Use it; do not keep all virtual
functions; use the new timevar.
* ipa-devirt.c (maybe_record_node): Do not insert static nodes that
was removed from the program.
(record_binfo): If BINFO corresponds to an anonymous namespace, we may
not consider it in the walk when its vtable is dead.
(possible_polymorphic_call_targets_1): Pass anonymous flag to
record_binfo.
(devirt_variable_node_removal_hook): New function.
(possible_polymorphic_call_targets): Also register
devirt_variable_node_removal_hook.
(ipa_devirt): Do not do non-speculative devirtualization.
(gate_ipa_devirt): One execute if devirtualizing speculatively.
From-SVN: r202368
Diffstat (limited to 'gcc/ipa.c')
-rw-r--r-- | gcc/ipa.c | 100 |
1 files changed, 96 insertions, 4 deletions
@@ -149,6 +149,84 @@ process_references (struct ipa_ref_list *list, } } +/* EDGE is an polymorphic call. If BEFORE_INLINING_P is set, mark + all its potential targets as reachable to permit later inlining if + devirtualization happens. After inlining still keep their declarations + around, so we can devirtualize to a direct call. + + Also try to make trivial devirutalization when no or only one target is + possible. */ + +static void +walk_polymorphic_call_targets (pointer_set_t *reachable_call_targets, + struct cgraph_edge *edge, + symtab_node *first, + pointer_set_t *reachable, bool before_inlining_p) +{ + unsigned int i; + void *cache_token; + bool final; + vec <cgraph_node *>targets + = possible_polymorphic_call_targets + (edge, &final, &cache_token); + + if (!pointer_set_insert (reachable_call_targets, + cache_token)) + { + for (i = 0; i < targets.length(); i++) + { + struct cgraph_node *n = targets[i]; + + /* Do not bother to mark virtual methods in anonymous namespace; + either we will find use of virtual table defining it, or it is + unused. */ + if (TREE_CODE (TREE_TYPE (n->symbol.decl)) == METHOD_TYPE + && type_in_anonymous_namespace_p + (method_class_type (TREE_TYPE (n->symbol.decl)))) + continue; + + /* Prior inlining, keep alive bodies of possible targets for + devirtualization. */ + if (n->symbol.definition + && before_inlining_p) + pointer_set_insert (reachable, n); + + /* Even after inlining we want to keep the possible targets in the + boundary, so late passes can still produce direct call even if + the chance for inlining is lost. */ + enqueue_node ((symtab_node) n, first, reachable); + } + } + + /* Very trivial devirtualization; when the type is + final or anonymous (so we know all its derivation) + and there is only one possible virtual call target, + make the edge direct. */ + if (final) + { + if (targets.length() <= 1) + { + cgraph_node *target; + if (targets.length () == 1) + target = targets[0]; + else + target = cgraph_get_create_node + (builtin_decl_implicit (BUILT_IN_UNREACHABLE)); + + if (dump_file) + fprintf (dump_file, + "Devirtualizing call in %s/%i to %s/%i\n", + cgraph_node_name (edge->caller), + edge->caller->symbol.order, + cgraph_node_name (target), target->symbol.order); + edge = cgraph_make_edge_direct (edge, target); + if (cgraph_state != CGRAPH_STATE_IPA_SSA) + cgraph_redirect_edge_call_stmt_to_callee (edge); + else + inline_update_overall_summary (edge->caller); + } + } +} /* Perform reachability analysis and reclaim all unreachable nodes. @@ -214,7 +292,9 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) bool changed = false; struct pointer_set_t *reachable = pointer_set_create (); struct pointer_set_t *body_needed_for_clonning = pointer_set_create (); + struct pointer_set_t *reachable_call_targets = pointer_set_create (); + timevar_push (TV_IPA_UNREACHABLE); #ifdef ENABLE_CHECKING verify_symtab (); #endif @@ -238,10 +318,7 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) if (node->symbol.definition && !node->global.inlined_to && !node->symbol.in_other_partition - && (!cgraph_can_remove_if_no_direct_calls_and_refs_p (node) - /* Keep around virtual functions for possible devirtualization. */ - || (before_inlining_p - && DECL_VIRTUAL_P (node->symbol.decl)))) + && !cgraph_can_remove_if_no_direct_calls_and_refs_p (node)) { gcc_assert (!node->global.inlined_to); pointer_set_insert (reachable, node); @@ -304,6 +381,19 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) if (!in_boundary_p) { struct cgraph_edge *e; + /* Keep alive possible targets for devirtualization. */ + if (optimize && flag_devirtualize) + { + struct cgraph_edge *next; + for (e = cnode->indirect_calls; e; e = next) + { + next = e->next_callee; + if (e->indirect_info->polymorphic) + walk_polymorphic_call_targets (reachable_call_targets, + e, &first, reachable, + before_inlining_p); + } + } for (e = cnode->callees; e; e = e->next_callee) { if (e->callee->symbol.definition @@ -449,6 +539,7 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) pointer_set_destroy (reachable); pointer_set_destroy (body_needed_for_clonning); + pointer_set_destroy (reachable_call_targets); /* Now update address_taken flags and try to promote functions to be local. */ if (file) @@ -483,6 +574,7 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file) FOR_EACH_DEFINED_FUNCTION (node) ipa_propagate_frequency (node); + timevar_pop (TV_IPA_UNREACHABLE); return changed; } |