aboutsummaryrefslogtreecommitdiff
path: root/gcc/ipa.c
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2013-09-08 18:42:21 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2013-09-08 16:42:21 +0000
commit3462aa02a699dc716bd366fee8fc1c85f7f94541 (patch)
tree6aaf6ed20bc90f69bf381f4674ecd79f8abee69c /gcc/ipa.c
parent26e5b0fd2818c746fcd016bd1b6fa434204a5d72 (diff)
downloadgcc-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.c100
1 files changed, 96 insertions, 4 deletions
diff --git a/gcc/ipa.c b/gcc/ipa.c
index 37b6629..4b82d1d 100644
--- a/gcc/ipa.c
+++ b/gcc/ipa.c
@@ -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;
}