diff options
author | Jan Hubicka <hubicka@ucw.cz> | 2016-03-10 17:11:14 +0100 |
---|---|---|
committer | Jan Hubicka <hubicka@gcc.gnu.org> | 2016-03-10 16:11:14 +0000 |
commit | 4f4ada6afb970674c3f33d895ec793491a026c1c (patch) | |
tree | 75330395a11be8ce2a0a3af9dc620e72f851a88a /gcc | |
parent | 079cd8548b540ceda89887711f6f7fb3a8fa49ec (diff) | |
download | gcc-4f4ada6afb970674c3f33d895ec793491a026c1c.zip gcc-4f4ada6afb970674c3f33d895ec793491a026c1c.tar.gz gcc-4f4ada6afb970674c3f33d895ec793491a026c1c.tar.bz2 |
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
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 11 | ||||
-rw-r--r-- | gcc/cgraph.c | 4 | ||||
-rw-r--r-- | gcc/cgraph.h | 2 | ||||
-rw-r--r-- | gcc/ipa.c | 49 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lto/pr69589_0.C | 26 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/lto/pr69589_1.C | 61 |
7 files changed, 143 insertions, 16 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index f65902b..ba9f5b5 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,16 @@ 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 * ipa-devirt.c (possible_polymorphic_call_targets): Do not ICE on cxa_pure_virtual. diff --git a/gcc/cgraph.c b/gcc/cgraph.c index ee6a209..871ed62 100644 --- a/gcc/cgraph.c +++ b/gcc/cgraph.c @@ -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)) diff --git a/gcc/cgraph.h b/gcc/cgraph.h index fc7bb22..d0345c6 100644 --- a/gcc/cgraph.h +++ b/gcc/cgraph.h @@ -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. */ @@ -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) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 093ef57..c6ffcf3 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -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 diff --git a/gcc/testsuite/g++.dg/lto/pr69589_0.C b/gcc/testsuite/g++.dg/lto/pr69589_0.C new file mode 100644 index 0000000..bbdcb73 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr69589_0.C @@ -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 (); +} + diff --git a/gcc/testsuite/g++.dg/lto/pr69589_1.C b/gcc/testsuite/g++.dg/lto/pr69589_1.C new file mode 100644 index 0000000..01c1620 --- /dev/null +++ b/gcc/testsuite/g++.dg/lto/pr69589_1.C @@ -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 (); +} + |