From ccb05ef2c3b9ffca62b80bf8ecd9207e41249b64 Mon Sep 17 00:00:00 2001 From: Jan Hubicka Date: Tue, 15 Apr 2014 23:01:04 +0200 Subject: [PATCH] ipa-devirt.c (referenced_from_vtable_p): New predicate. * ipa-devirt.c (referenced_from_vtable_p): New predicate. (maybe_record_node, likely_target_p): Use it. From-SVN: r209435 --- gcc/ChangeLog | 5 ++++ gcc/ipa-devirt.c | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 76 insertions(+), 5 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 4479bdc..1b81ddc 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,8 @@ +2014-04-15 Jan Hubicka + + * ipa-devirt.c (referenced_from_vtable_p): New predicate. + (maybe_record_node, likely_target_p): Use it. + 2014-04-15 Bill Schmidt PR target/60839 diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index 3a5432e..ce724a5 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -598,6 +598,48 @@ build_type_inheritance_graph (void) timevar_pop (TV_IPA_INHERITANCE); } +/* Return true if N has reference from live virtual table + (and thus can be a destination of polymorphic call). + Be conservatively correct when callgraph is not built or + if the method may be referred externally. */ + +static bool +referenced_from_vtable_p (struct cgraph_node *node) +{ + int i; + struct ipa_ref *ref; + bool found = false; + + if (node->externally_visible + || node->used_from_other_partition) + return true; + + /* Keep this test constant time. + It is unlikely this can happen except for the case where speculative + devirtualization introduced many speculative edges to this node. + In this case the target is very likely alive anyway. */ + if (node->ref_list.referring.length () > 100) + return true; + + /* We need references built. */ + if (cgraph_state <= CGRAPH_STATE_CONSTRUCTION) + return true; + + for (i = 0; ipa_ref_list_referring_iterate (&node->ref_list, + i, ref); i++) + + if ((ref->use == IPA_REF_ALIAS + && referenced_from_vtable_p (cgraph (ref->referring))) + || (ref->use == IPA_REF_ADDR + && TREE_CODE (ref->referring->decl) == VAR_DECL + && DECL_VIRTUAL_P (ref->referring->decl))) + { + found = true; + break; + } + return found; +} + /* If TARGET has associated node, record it in the NODES array. CAN_REFER specify if program can refer to the target directly. if TARGET is unknown (NULL) or it can not be inserted (for example because @@ -634,11 +676,29 @@ maybe_record_node (vec &nodes, target_node = cgraph_get_node (target); - if (target_node != NULL - && ((TREE_PUBLIC (target) - || DECL_EXTERNAL (target)) - || target_node->definition) - && symtab_real_symbol_p (target_node)) + /* Method can only be called by polymorphic call if any + of vtables refering to it are alive. + + While this holds for non-anonymous functions, too, there are + cases where we want to keep them in the list; for example + inline functions with -fno-weak are static, but we still + may devirtualize them when instance comes from other unit. + The same holds for LTO. + + Currently we ignore these functions in speculative devirtualization. + ??? Maybe it would make sense to be more aggressive for LTO even + eslewhere. */ + if (!flag_ltrans + && type_in_anonymous_namespace_p (DECL_CONTEXT (target)) + && (!target_node + || !referenced_from_vtable_p (target_node))) + ; + /* See if TARGET is useful function we can deal with. */ + else if (target_node != NULL + && (TREE_PUBLIC (target) + || DECL_EXTERNAL (target) + || target_node->definition) + && symtab_real_symbol_p (target_node)) { gcc_assert (!target_node->global.inlined_to); gcc_assert (symtab_real_symbol_p (target_node)); @@ -1725,6 +1785,12 @@ likely_target_p (struct cgraph_node *n) return false; if (n->frequency < NODE_FREQUENCY_NORMAL) return false; + /* If there are no virtual tables refering the target alive, + the only way the target can be called is an instance comming from other + compilation unit; speculative devirtualization is build around an + assumption that won't happen. */ + if (!referenced_from_vtable_p (n)) + return false; return true; } -- 2.7.4