re PR tree-optimization/56265 (ICE in ipa_make_edge_direct_to_target)

PR tree-optimization/56265
	* ipa-prop.c (ipa_make_edge_direct_to_target): Fixup callgraph when target is
	referenced for firs ttime.
	* testsuite/g++.dg/ipa/devirt-11.C: New testcase.

From-SVN: r196177
This commit is contained in:
Jan Hubicka 2013-02-20 16:47:21 +01:00 committed by Jan Hubicka
parent c0e50f7246
commit a0a7b6118a
4 changed files with 119 additions and 3 deletions

View file

@ -1,3 +1,9 @@
2013-02-20 Jan Hubicka <jh@suse.cz>
PR tree-optimization/56265
* ipa-prop.c (ipa_make_edge_direct_to_target): Fixup callgraph when target is
referenced for firs ttime.
2013-02-20 Richard Biener <rguenther@suse.de>
* tree-call-cdce.c (tree_call_cdce): Do not remove unused locals.

View file

@ -2100,10 +2100,65 @@ ipa_make_edge_direct_to_target (struct cgraph_edge *ie, tree target)
if (TREE_CODE (target) == ADDR_EXPR)
target = TREE_OPERAND (target, 0);
if (TREE_CODE (target) != FUNCTION_DECL)
return NULL;
{
target = canonicalize_constructor_val (target, NULL);
if (!target || TREE_CODE (target) != FUNCTION_DECL)
{
if (dump_file)
fprintf (dump_file, "ipa-prop: Discovered direct call to non-function"
" in (%s/%i).\n",
cgraph_node_name (ie->caller), ie->caller->uid);
return NULL;
}
}
callee = cgraph_get_node (target);
if (!callee)
return NULL;
/* Because may-edges are not explicitely represented and vtable may be external,
we may create the first reference to the object in the unit. */
if (!callee || callee->global.inlined_to)
{
struct cgraph_node *first_clone = callee;
/* We are better to ensure we can refer to it.
In the case of static functions we are out of luck, since we already
removed its body. In the case of public functions we may or may
not introduce the reference. */
if (!canonicalize_constructor_val (target, NULL)
|| !TREE_PUBLIC (target))
{
if (dump_file)
fprintf (dump_file, "ipa-prop: Discovered call to a known target "
"(%s/%i -> %s/%i) but can not refer to it. Giving up.\n",
xstrdup (cgraph_node_name (ie->caller)), ie->caller->uid,
xstrdup (cgraph_node_name (ie->callee)), ie->callee->uid);
return NULL;
}
/* Create symbol table node. Even if inline clone exists, we can not take
it as a target of non-inlined call. */
callee = cgraph_create_node (target);
/* OK, we previously inlined the function, then removed the offline copy and
now we want it back for external call. This can happen when devirtualizing
while inlining function called once that happens after extern inlined and
virtuals are already removed. In this case introduce the external node
and make it available for call. */
if (first_clone)
{
first_clone->clone_of = callee;
callee->clones = first_clone;
symtab_prevail_in_asm_name_hash ((symtab_node)callee);
symtab_insert_node_to_hashtable ((symtab_node)callee);
if (dump_file)
fprintf (dump_file, "ipa-prop: Introduced new external node "
"(%s/%i) and turned into root of the clone tree.\n",
xstrdup (cgraph_node_name (callee)), callee->uid);
}
else if (dump_file)
fprintf (dump_file, "ipa-prop: Introduced new external node "
"(%s/%i).\n",
xstrdup (cgraph_node_name (callee)), callee->uid);
}
ipa_check_create_node_params ();
/* We can not make edges to inline clones. It is bug that someone removed

View file

@ -1,3 +1,8 @@
2013-02-20 Jan Hubicka <jh@suse.cz>
PR tree-optimization/56265
* testsuite/g++.dg/ipa/devirt-11.C: New testcase.
2013-02-20 Richard Biener <rguenther@suse.de>
* gcc.dg/tree-ssa/forwprop-8.c: Adjust.

View file

@ -0,0 +1,50 @@
/* { dg-do compile } */
/* { dg-options "-O2 -fdump-ipa-inline" } */
int baz ();
struct A
{
virtual int fn2 () = 0;
virtual int *fn3 ();
double *fn4 ();
int fn5 (int);
template <class T>
void fn1 (A &, T) { fn3 (); fn4 (); fn2 (); }
};
struct B : A
{
int fn2 () { return 6; }
void fn3 (int, double);
B (bool = true);
B (int, int);
};
template <typename T>
void
foo (B &x, A &y, A &z)
{
y.fn2 ();
z.fn2 ();
int i = baz ();
int j = (y.fn3 ())[i];
x.fn3 (j, (y.fn4 ())[i] + (z.fn4 ())[z.fn5 (j)]);
}
inline B
operator+ (A &y, A &z)
{
B x;
foo<int> (x, y, z);
return x;
}
void
bar ()
{
B a, b, c (4, 0), d;
a.fn1 (b, .6);
baz ();
c + d;
}
/* While inlining function called once we should devirtualize a new call to fn2
and two to fn3. While doing so the new symbol for fn2 needs to be
introduced. */
/* { dg-final { scan-ipa-dump-times "Discovered a virtual call to a known target" 3 "inline" } } */
/* { dg-final { scan-ipa-dump-times "and turned into root of the clone tree" 1 "inline" } } */
/* { dg-final { cleanup-ipa-dump "inline" } } */