This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH, PR 59176] Mark "zombie" call graph nodes to remove verifier false positive
- From: Richard Biener <rguenther at suse dot de>
- To: Martin Jambor <mjambor at suse dot cz>
- Cc: Jakub Jelinek <jakub at redhat dot com>, GCC Patches <gcc-patches at gcc dot gnu dot org>, Jan Hubicka <hubicka at ucw dot cz>
- Date: Fri, 21 Mar 2014 09:47:45 +0100 (CET)
- Subject: Re: [PATCH, PR 59176] Mark "zombie" call graph nodes to remove verifier false positive
- Authentication-results: sourceware.org; auth=none
- References: <20140320160732 dot GK19304 at virgil dot suse> <20140320184056 dot GM1817 at tucnak dot redhat dot com> <20140320193053 dot GP19304 at virgil dot suse>
On Thu, 20 Mar 2014, Martin Jambor wrote:
> Hi,
>
> On Thu, Mar 20, 2014 at 07:40:56PM +0100, Jakub Jelinek wrote:
> > On Thu, Mar 20, 2014 at 05:07:32PM +0100, Martin Jambor wrote:
> > > in the PR, verifier claims an edge is pointing to a wrong declaration
> > > even though it has successfully verified the edge multiple times
> > > before. The reason is that symtab_remove_unreachable_nodes decides to
> > > "remove the body" of a node and also clear any information that it is
> > > an alias of another in the process (more detailed analysis in comment
> > > #9 of the bug).
> > >
> > > In bugzilla Honza wrote that "silencing the verifier" is the way to
> > > go. Either we can dedicate a new flag in each cgraph_node or
> > > symtab_node just for the purpose of verification or do something more
> > > hackish like the patch below which re-uses the former_clone_of field
> > > for this purpose. Since clones are always private nodes, they should
> > > always either survive removal of unreachable nodes or be completely
> > > killed by it and should never enter the in_border zombie state.
> > > Therefore their former_clone_of must always be NULL. So I added a new
> > > special value, error_mark_node, to mark this zombie state and taught
> > > the verifier to be happy with such nodes.
> > >
> > > Bootstrapped and tested on x86_64-linux. What do you think?
> >
> > Don't we have like 22 spare bits in cgraph_node and 20 spare bits in
> > symtab_node? I'd find it clearer if you just used a new flag to mark the
> > zombie nodes. Though, I'll let Richard or Honza to decide, don't feel
> > strongly about it.
> >
>
> I guess you are right, here is the proper version which is currently
> undergoing bootstrap and testing.
I agree with Jakub, the following variant is ok.
Thanks,
Richard.
> Thanks,
>
> Martin
>
> 2014-03-20 Martin Jambor <mjambor@suse.cz>
>
> PR ipa/59176
> * cgraph.h (symtab_node): New flag body_removed.
> * ipa.c (symtab_remove_unreachable_nodes): Set body_removed flag
> when removing bodies.
> * symtab.c (dump_symtab_base): Dump body_removed flag.
> * cgraph.c (verify_edge_corresponds_to_fndecl): Skip nodes which
> had their bodies removed.
>
> testsuite/
> * g++.dg/torture/pr59176.C: New test.
>
> diff --git a/gcc/cgraph.c b/gcc/cgraph.c
> index a15b6bc..fb6880c 100644
> --- a/gcc/cgraph.c
> +++ b/gcc/cgraph.c
> @@ -2601,8 +2601,13 @@ verify_edge_corresponds_to_fndecl (struct cgraph_edge *e, tree decl)
> node = cgraph_get_node (decl);
>
> /* We do not know if a node from a different partition is an alias or what it
> - aliases and therefore cannot do the former_clone_of check reliably. */
> - if (!node || node->in_other_partition || e->callee->in_other_partition)
> + aliases and therefore cannot do the former_clone_of check reliably. When
> + body_removed is set, we have lost all information about what was alias or
> + thunk of and also cannot proceed. */
> + if (!node
> + || node->body_removed
> + || node->in_other_partition
> + || e->callee->in_other_partition)
> return false;
> node = cgraph_function_or_thunk_node (node, NULL);
>
> diff --git a/gcc/cgraph.h b/gcc/cgraph.h
> index 32b1ee1..59d9ce6 100644
> --- a/gcc/cgraph.h
> +++ b/gcc/cgraph.h
> @@ -91,7 +91,9 @@ public:
> unsigned forced_by_abi : 1;
> /* True when the name is known to be unique and thus it does not need mangling. */
> unsigned unique_name : 1;
> -
> + /* True when body and other characteristics have been removed by
> + symtab_remove_unreachable_nodes. */
> + unsigned body_removed : 1;
>
> /*** WHOPR Partitioning flags.
> These flags are used at ltrans stage when only part of the callgraph is
> diff --git a/gcc/ipa.c b/gcc/ipa.c
> index 572dba1..4a8c6b7 100644
> --- a/gcc/ipa.c
> +++ b/gcc/ipa.c
> @@ -484,6 +484,7 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
> {
> if (file)
> fprintf (file, " %s", node->name ());
> + node->body_removed = true;
> node->analyzed = false;
> node->definition = false;
> node->cpp_implicit_alias = false;
> @@ -542,6 +543,7 @@ symtab_remove_unreachable_nodes (bool before_inlining_p, FILE *file)
> fprintf (file, " %s", vnode->name ());
> changed = true;
> }
> + vnode->body_removed = true;
> vnode->definition = false;
> vnode->analyzed = false;
> vnode->aux = NULL;
> diff --git a/gcc/symtab.c b/gcc/symtab.c
> index 5d69803..0ce8e8e 100644
> --- a/gcc/symtab.c
> +++ b/gcc/symtab.c
> @@ -601,6 +601,8 @@ dump_symtab_base (FILE *f, symtab_node *node)
> ? IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME
> (node->alias_target))
> : IDENTIFIER_POINTER (node->alias_target));
> + if (node->body_removed)
> + fprintf (f, "\n Body removed by symtab_remove_unreachable_nodes");
> fprintf (f, "\n Visibility:");
> if (node->in_other_partition)
> fprintf (f, " in_other_partition");
> diff --git a/gcc/testsuite/g++.dg/ipa/pr59176.C b/gcc/testsuite/g++.dg/ipa/pr59176.C
> new file mode 100644
> index 0000000..d576bc3
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/ipa/pr59176.C
> @@ -0,0 +1,41 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O3" } */
> +
> +template <class> class A {
> +protected:
> + void m_fn2();
> + ~A() { m_fn2(); }
> + virtual void m_fn1();
> +};
> +
> +class D : A<int> {};
> +template <class Key> void A<Key>::m_fn2() {
> + m_fn1();
> + m_fn1();
> + m_fn1();
> +}
> +
> +#pragma interface
> +class B {
> + D m_cellsAlreadyProcessed;
> + D m_cellsNotToProcess;
> +
> +public:
> + virtual ~B() {}
> + void m_fn1();
> +};
> +
> +class C {
> + unsigned long m_fn1();
> + B m_fn2();
> + unsigned long m_fn3();
> +};
> +unsigned long C::m_fn1() {
> +CellHierarchy:
> + m_fn2().m_fn1();
> +}
> +
> +unsigned long C::m_fn3() {
> +CellHierarchy:
> + m_fn2().m_fn1();
> +}
>
>
--
Richard Biener <rguenther@suse.de>
SUSE / SUSE Labs
SUSE LINUX Products GmbH - Nuernberg - AG Nuernberg - HRB 16746
GF: Jeff Hawn, Jennifer Guild, Felix Imend"orffer