Commit 568cda29 by Martin Jambor Committed by Martin Jambor

ipa-prop.c (remove_described_reference): Accept missing references, return false…

ipa-prop.c (remove_described_reference): Accept missing references, return false if that hppens, otherwise return true.

2013-09-05  Martin Jambor  <mjambor@suse.cz>

	* ipa-prop.c (remove_described_reference): Accept missing references,
	return false if that hppens, otherwise return true.
	(cgraph_node_for_jfunc): New function.
	(try_decrement_rdesc_refcount): Likewise.
	(try_make_edge_direct_simple_call): Use them.
	(ipa_edge_removal_hook): Remove references from rdescs.
	(ipa_edge_duplication_hook): Clone rdescs and their references
	when the new edge has the same caller as the old one.
	* cgraph.c (cgraph_resolve_speculation): Remove speculative
	reference before removing any edges.

testsuite/
	* g++.dg/ipa/remref-1.C: New test.
	* g++.dg/ipa/remref-2.C: Likewise.

From-SVN: r202281
parent 5a200acb
2013-09-05 Martin Jambor <mjambor@suse.cz>
* ipa-prop.c (remove_described_reference): Accept missing references,
return false if that hppens, otherwise return true.
(cgraph_node_for_jfunc): New function.
(try_decrement_rdesc_refcount): Likewise.
(try_make_edge_direct_simple_call): Use them.
(ipa_edge_removal_hook): Remove references from rdescs.
(ipa_edge_duplication_hook): Clone rdescs and their references
when the new edge has the same caller as the old one.
* cgraph.c (cgraph_resolve_speculation): Remove speculative
reference before removing any edges.
2013-09-05 Richard Earnshaw <rearnsha@arm.com> 2013-09-05 Richard Earnshaw <rearnsha@arm.com>
* arm.c (thumb2_emit_strd_push): Rewrite to use pre-decrement on * arm.c (thumb2_emit_strd_push): Rewrite to use pre-decrement on
......
...@@ -1225,13 +1225,13 @@ cgraph_resolve_speculation (struct cgraph_edge *edge, tree callee_decl) ...@@ -1225,13 +1225,13 @@ cgraph_resolve_speculation (struct cgraph_edge *edge, tree callee_decl)
edge->frequency = CGRAPH_FREQ_MAX; edge->frequency = CGRAPH_FREQ_MAX;
edge->speculative = false; edge->speculative = false;
e2->speculative = false; e2->speculative = false;
ipa_remove_reference (ref);
if (e2->indirect_unknown_callee || e2->inline_failed) if (e2->indirect_unknown_callee || e2->inline_failed)
cgraph_remove_edge (e2); cgraph_remove_edge (e2);
else else
cgraph_remove_node_and_inline_clones (e2->callee, NULL); cgraph_remove_node_and_inline_clones (e2->callee, NULL);
if (edge->caller->call_site_hash) if (edge->caller->call_site_hash)
cgraph_update_edge_in_call_site_hash (edge); cgraph_update_edge_in_call_site_hash (edge);
ipa_remove_reference (ref);
return edge; return edge;
} }
......
...@@ -2496,9 +2496,10 @@ ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *agg, ...@@ -2496,9 +2496,10 @@ ipa_find_agg_cst_for_param (struct ipa_agg_jump_function *agg,
} }
/* Remove a reference to SYMBOL from the list of references of a node given by /* Remove a reference to SYMBOL from the list of references of a node given by
reference description RDESC. */ reference description RDESC. Return true if the reference has been
successfully found and removed. */
static void static bool
remove_described_reference (symtab_node symbol, struct ipa_cst_ref_desc *rdesc) remove_described_reference (symtab_node symbol, struct ipa_cst_ref_desc *rdesc)
{ {
struct ipa_ref *to_del; struct ipa_ref *to_del;
...@@ -2507,12 +2508,15 @@ remove_described_reference (symtab_node symbol, struct ipa_cst_ref_desc *rdesc) ...@@ -2507,12 +2508,15 @@ remove_described_reference (symtab_node symbol, struct ipa_cst_ref_desc *rdesc)
origin = rdesc->cs; origin = rdesc->cs;
to_del = ipa_find_reference ((symtab_node) origin->caller, symbol, to_del = ipa_find_reference ((symtab_node) origin->caller, symbol,
origin->call_stmt, origin->lto_stmt_uid); origin->call_stmt, origin->lto_stmt_uid);
gcc_assert (to_del); if (!to_del)
return false;
ipa_remove_reference (to_del); ipa_remove_reference (to_del);
if (dump_file) if (dump_file)
fprintf (dump_file, "ipa-prop: Removed a reference from %s/%i to %s.\n", fprintf (dump_file, "ipa-prop: Removed a reference from %s/%i to %s.\n",
xstrdup (cgraph_node_name (origin->caller)), xstrdup (cgraph_node_name (origin->caller)),
origin->caller->symbol.order, xstrdup (symtab_node_name (symbol))); origin->caller->symbol.order, xstrdup (symtab_node_name (symbol)));
return true;
} }
/* If JFUNC has a reference description with refcount different from /* If JFUNC has a reference description with refcount different from
...@@ -2529,6 +2533,45 @@ jfunc_rdesc_usable (struct ipa_jump_func *jfunc) ...@@ -2529,6 +2533,45 @@ jfunc_rdesc_usable (struct ipa_jump_func *jfunc)
return NULL; return NULL;
} }
/* If the value of constant jump function JFUNC is an address of a function
declaration, return the associated call graph node. Otherwise return
NULL. */
static cgraph_node *
cgraph_node_for_jfunc (struct ipa_jump_func *jfunc)
{
gcc_checking_assert (jfunc->type == IPA_JF_CONST);
tree cst = ipa_get_jf_constant (jfunc);
if (TREE_CODE (cst) != ADDR_EXPR
|| TREE_CODE (TREE_OPERAND (cst, 0)) != FUNCTION_DECL)
return NULL;
return cgraph_get_node (TREE_OPERAND (cst, 0));
}
/* If JFUNC is a constant jump function with a usable rdesc, decrement its
refcount and if it hits zero, remove reference to SYMBOL from the caller of
the edge specified in the rdesc. Return false if either the symbol or the
reference could not be found, otherwise return true. */
static bool
try_decrement_rdesc_refcount (struct ipa_jump_func *jfunc)
{
struct ipa_cst_ref_desc *rdesc;
if (jfunc->type == IPA_JF_CONST
&& (rdesc = jfunc_rdesc_usable (jfunc))
&& --rdesc->refcount == 0)
{
symtab_node symbol = (symtab_node) cgraph_node_for_jfunc (jfunc);
if (!symbol)
return false;
return remove_described_reference (symbol, rdesc);
}
return true;
}
/* Try to find a destination for indirect edge IE that corresponds to a simple /* Try to find a destination for indirect edge IE that corresponds to a simple
call or a call of a member function pointer and where the destination is a call or a call of a member function pointer and where the destination is a
pointer formal parameter described by jump function JFUNC. If it can be pointer formal parameter described by jump function JFUNC. If it can be
...@@ -2544,7 +2587,6 @@ try_make_edge_direct_simple_call (struct cgraph_edge *ie, ...@@ -2544,7 +2587,6 @@ try_make_edge_direct_simple_call (struct cgraph_edge *ie,
tree target; tree target;
bool agg_contents = ie->indirect_info->agg_contents; bool agg_contents = ie->indirect_info->agg_contents;
bool speculative = ie->speculative; bool speculative = ie->speculative;
struct ipa_cst_ref_desc *rdesc;
if (ie->indirect_info->agg_contents) if (ie->indirect_info->agg_contents)
target = ipa_find_agg_cst_for_param (&jfunc->agg, target = ipa_find_agg_cst_for_param (&jfunc->agg,
...@@ -2557,11 +2599,16 @@ try_make_edge_direct_simple_call (struct cgraph_edge *ie, ...@@ -2557,11 +2599,16 @@ try_make_edge_direct_simple_call (struct cgraph_edge *ie,
cs = ipa_make_edge_direct_to_target (ie, target); cs = ipa_make_edge_direct_to_target (ie, target);
/* FIXME: speculative edges can be handled. */ /* FIXME: speculative edges can be handled. */
if (cs && !agg_contents && !speculative if (cs && !agg_contents && !speculative)
&& jfunc->type == IPA_JF_CONST {
&& (rdesc = jfunc_rdesc_usable (jfunc)) bool ok;
&& --rdesc->refcount == 0) gcc_checking_assert (cs->callee
remove_described_reference ((symtab_node) cs->callee, rdesc); && (jfunc->type != IPA_JF_CONST
|| !cgraph_node_for_jfunc (jfunc)
|| cs->callee == cgraph_node_for_jfunc (jfunc)));
ok = try_decrement_rdesc_refcount (jfunc);
gcc_checking_assert (ok);
}
return cs; return cs;
} }
...@@ -2817,7 +2864,9 @@ propagate_controlled_uses (struct cgraph_edge *cs) ...@@ -2817,7 +2864,9 @@ propagate_controlled_uses (struct cgraph_edge *cs)
if (n) if (n)
{ {
struct cgraph_node *clone; struct cgraph_node *clone;
remove_described_reference ((symtab_node) n, rdesc); bool ok;
ok = remove_described_reference ((symtab_node) n, rdesc);
gcc_checking_assert (ok);
clone = cs->caller; clone = cs->caller;
while (clone->global.inlined_to while (clone->global.inlined_to
...@@ -2960,9 +3009,21 @@ ipa_set_node_agg_value_chain (struct cgraph_node *node, ...@@ -2960,9 +3009,21 @@ ipa_set_node_agg_value_chain (struct cgraph_node *node,
static void static void
ipa_edge_removal_hook (struct cgraph_edge *cs, void *data ATTRIBUTE_UNUSED) ipa_edge_removal_hook (struct cgraph_edge *cs, void *data ATTRIBUTE_UNUSED)
{ {
/* During IPA-CP updating we can be called on not-yet analyze clones. */ struct ipa_edge_args *args;
/* During IPA-CP updating we can be called on not-yet analyzed clones. */
if (vec_safe_length (ipa_edge_args_vector) <= (unsigned)cs->uid) if (vec_safe_length (ipa_edge_args_vector) <= (unsigned)cs->uid)
return; return;
args = IPA_EDGE_REF (cs);
if (args->jump_functions)
{
struct ipa_jump_func *jf;
int i;
FOR_EACH_VEC_ELT (*args->jump_functions, i, jf)
try_decrement_rdesc_refcount (jf);
}
ipa_free_edge_args_substructures (IPA_EDGE_REF (cs)); ipa_free_edge_args_substructures (IPA_EDGE_REF (cs));
} }
...@@ -3007,6 +3068,24 @@ ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst, ...@@ -3007,6 +3068,24 @@ ipa_edge_duplication_hook (struct cgraph_edge *src, struct cgraph_edge *dst,
if (!src_rdesc) if (!src_rdesc)
dst_jf->value.constant.rdesc = NULL; dst_jf->value.constant.rdesc = NULL;
else if (src->caller == dst->caller)
{
struct ipa_ref *ref;
symtab_node n = (symtab_node) cgraph_node_for_jfunc (src_jf);
gcc_checking_assert (n);
ref = ipa_find_reference ((symtab_node) src->caller, n,
src->call_stmt, src->lto_stmt_uid);
gcc_checking_assert (ref);
ipa_clone_ref (ref, (symtab_node) dst->caller, ref->stmt);
gcc_checking_assert (ipa_refdesc_pool);
struct ipa_cst_ref_desc *dst_rdesc
= (struct ipa_cst_ref_desc *) pool_alloc (ipa_refdesc_pool);
dst_rdesc->cs = dst;
dst_rdesc->refcount = src_rdesc->refcount;
dst_rdesc->next_duplicate = NULL;
dst_jf->value.constant.rdesc = dst_rdesc;
}
else if (src_rdesc->cs == src) else if (src_rdesc->cs == src)
{ {
struct ipa_cst_ref_desc *dst_rdesc; struct ipa_cst_ref_desc *dst_rdesc;
......
2013-09-05 Martin Jambor <mjambor@suse.cz>
* g++.dg/ipa/remref-1.C: New test.
* g++.dg/ipa/remref-2.C: Likewise.
2013-09-04 Paolo Carlini <paolo.carlini@oracle.com> 2013-09-04 Paolo Carlini <paolo.carlini@oracle.com>
PR c++/24926 PR c++/24926
......
/* Verify that indirect-inlining induced removal of referenes will not remove
too many references in presence of speculative devirtualization. */
/* { dg-do link } */
/* { dg-options "-O3 -fno-early-inlining" } */
class A
{
public:
virtual void foo(void (*)(void));
};
static
void b(void)
{
}
void
A::foo(void (*back)(void))
{
back();
}
class A *a;
void __attribute__ ((noinline, noclone))
allocate_a ()
{
a = new A();
}
main()
{
allocate_a();
for (int i=0; i<10000;i++)
a->foo(b);
}
/* Verify that we survive creation and deletion of references to facilitate
reference removal while also doing (unsuccessful) speculative
devirtualization. */
/* { dg-do link } */
/* { dg-options "-O3 -fno-early-inlining" } */
class A
{
public:
virtual void __attribute__ ((noinline)) foo(void (*)(void));
};
static
void b(void)
{
}
void __attribute__ ((noinline))
A::foo(void (*back)(void))
{
back();
}
class A *a;
void __attribute__ ((noinline, noclone))
allocate_a ()
{
a = new A();
}
main()
{
allocate_a();
for (int i=0; i<10000;i++)
a->foo(b);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment