aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJan Hubicka <jh@suse.cz>2014-04-15 23:01:04 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2014-04-15 21:01:04 +0000
commitccb05ef2c3b9ffca62b80bf8ecd9207e41249b64 (patch)
tree09ccc9a11cb09ad632d2e6388de36605e026b7fd /gcc
parent33fbb3584a1c3836cf54d1346a76f7d6e7db5331 (diff)
downloadgcc-ccb05ef2c3b9ffca62b80bf8ecd9207e41249b64.zip
gcc-ccb05ef2c3b9ffca62b80bf8ecd9207e41249b64.tar.gz
gcc-ccb05ef2c3b9ffca62b80bf8ecd9207e41249b64.tar.bz2
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
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/ipa-devirt.c76
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 <jh@suse.cz>
+
+ * ipa-devirt.c (referenced_from_vtable_p): New predicate.
+ (maybe_record_node, likely_target_p): Use it.
+
2014-04-15 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
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 <cgraph_node *> &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;
}