re PR ipa/69589 (ICE in initialize_node_lattices, at ipa-cp.c:971)

PR lto/69589
	* cgraph.c (cgraph_node::dump): Dump split_part and indirect_call_target.
	* cgraph.h (cgraph_node): Add indirect_call_target flag.
	* ipa.c (has_addr_references_p): Cleanup.
	(is_indirect_call_target_p): New.
	(walk_polymorphic_call_targets): Do not mark virtuals that may be
	called indirectly as local.
	(symbol_table::remove_unreachable_nodes): Compute indirect_call_target.

	* g++.dg/lto/pr69589_0.C: New testcase
	* g++.dg/lto/pr69589_1.C: New testcase

From-SVN: r234115
This commit is contained in:
Jan Hubicka 2016-03-10 17:11:14 +01:00 committed by Jan Hubicka
parent 079cd8548b
commit 4f4ada6afb
7 changed files with 143 additions and 16 deletions

View File

@ -1,3 +1,14 @@
2016-03-10 Jan Hubicka <hubicka@ucw.cz>
PR lto/69589
* cgraph.c (cgraph_node::dump): Dump split_part and indirect_call_target.
* cgraph.h (cgraph_node): Add indirect_call_target flag.
* ipa.c (has_addr_references_p): Cleanup.
(is_indirect_call_target_p): New.
(walk_polymorphic_call_targets): Do not mark virtuals that may be
called indirectly as local.
(symbol_table::remove_unreachable_nodes): Compute indirect_call_target.
2016-03-10 Jan Hubicka <hubicka@ucw.cz>
PR ipa/69630

View File

@ -2061,6 +2061,10 @@ cgraph_node::dump (FILE *f)
fprintf (f, " icf_merged");
if (merged_comdat)
fprintf (f, " merged_comdat");
if (split_part)
fprintf (f, " split_part");
if (indirect_call_target)
fprintf (f, " indirect_call_target");
if (nonfreeing_fn)
fprintf (f, " nonfreeing_fn");
if (DECL_STATIC_CONSTRUCTOR (decl))

View File

@ -1366,6 +1366,8 @@ public:
unsigned parallelized_function : 1;
/* True if function is part split out by ipa-split. */
unsigned split_part : 1;
/* True if the function appears as possible target of indirect call. */
unsigned indirect_call_target : 1;
private:
/* Worker for call_for_symbol_and_aliases. */

View File

@ -41,7 +41,7 @@ along with GCC; see the file COPYING3. If not see
static bool
has_addr_references_p (struct cgraph_node *node,
void *data ATTRIBUTE_UNUSED)
void *)
{
int i;
struct ipa_ref *ref = NULL;
@ -52,6 +52,14 @@ has_addr_references_p (struct cgraph_node *node,
return false;
}
/* Return true when NODE can be target of an indirect call. */
static bool
is_indirect_call_target_p (struct cgraph_node *node, void *)
{
return node->indirect_call_target;
}
/* Look for all functions inlined to NODE and update their inlined_to pointers
to INLINED_TO. */
@ -172,23 +180,24 @@ walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
(TYPE_METHOD_BASETYPE (TREE_TYPE (n->decl))))
continue;
symtab_node *body = n->function_symbol ();
n->indirect_call_target = true;
symtab_node *body = n->function_symbol ();
/* Prior inlining, keep alive bodies of possible targets for
devirtualization. */
if (n->definition
&& (before_inlining_p
&& opt_for_fn (body->decl, optimize)
&& opt_for_fn (body->decl, flag_devirtualize)))
{
/* Be sure that we will not optimize out alias target
body. */
if (DECL_EXTERNAL (n->decl)
&& n->alias
&& before_inlining_p)
reachable->add (body);
reachable->add (n);
}
if (n->definition
&& (before_inlining_p
&& opt_for_fn (body->decl, optimize)
&& opt_for_fn (body->decl, flag_devirtualize)))
{
/* Be sure that we will not optimize out alias target
body. */
if (DECL_EXTERNAL (n->decl)
&& n->alias
&& before_inlining_p)
reachable->add (body);
reachable->add (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. */
@ -323,6 +332,7 @@ symbol_table::remove_unreachable_nodes (FILE *file)
FOR_EACH_FUNCTION (node)
{
node->used_as_abstract_origin = false;
node->indirect_call_target = false;
if (node->definition
&& !node->global.inlined_to
&& !node->in_other_partition
@ -659,7 +669,14 @@ symbol_table::remove_unreachable_nodes (FILE *file)
fprintf (file, " %s", node->name ());
node->address_taken = false;
changed = true;
if (node->local_p ())
if (node->local_p ()
/* Virtual functions may be kept in cgraph just because
of possible later devirtualization. Do not mark them as
local too early so we won't optimize them out before
we are done with polymorphic call analysis. */
&& (!before_inlining_p
|| !node->call_for_symbol_and_aliases
(is_indirect_call_target_p, NULL, true)))
{
node->local.local = true;
if (file)

View File

@ -1,3 +1,9 @@
2016-03-10 Jan Hubicka <hubicka@ucw.cz>
PR lto/69589
* g++.dg/lto/pr69589_0.C: New testcase
* g++.dg/lto/pr69589_1.C: New testcase
2016-03-10 Marek Polacek <polacek@redhat.com>
PR c++/70153

View File

@ -0,0 +1,26 @@
// { dg-lto-do link }
// { dg-lto-options "-O2 -rdynamic" }
// { dg-extra-ld-options "-r -nostdlib" }
#pragma GCC visibility push(hidden)
struct A { int &operator[] (long); };
template <typename> struct B;
template <typename T, typename = B<T> >
using Z = int;
template <typename> struct C;
struct S {
int e;
virtual ~S () {}
};
struct D : S {
A a;
long i;
D() { { e ? &a[i] : nullptr; } }
};
template <>
struct C<int> { Z<S> m8 () const; };
Z<S>
C<int>::m8 () const
{
D ();
}

View File

@ -0,0 +1,61 @@
struct A;
template <class T>
struct Q { Q (T); };
template<typename T, class D>
struct U {
~U () { m1 (nullptr); }
D m2 ();
T *u;
void m1 (T *) { m2 () (u); }
};
struct F { F (int *); };
template <class, class T = F>
using W = Q<T>;
int a, b;
void fn1 (void *);
template <class T>
void
fn2 (T *x)
{
if (x)
x->~T();
fn1 (x);
}
template <typename T>
struct C {
void operator() (T *x) { fn2 (x); }
};
struct D;
template <typename T, typename D = C<T> >
using V = U<T, D>;
struct A {
A (int *);
};
struct S;
struct G {
V<S> m3 ();
};
struct S {
int e;
virtual ~S () {}
};
template<typename T>
struct H {
H (int, T x, int) : h(x) {}
G g;
void m4 () { g.m3 (); }
T h;
};
struct I {
I(A, W<D>);
};
void
test ()
{
A c (&b);
W<D> d (&b);
I e (c, d);
H<I> f (0, e, a);
f.m4 ();
}