[PATCH, PR 59176] Mark "zombie" call graph nodes to remove verifier false positive
Martin Jambor
mjambor@suse.cz
Thu Mar 20 19:37:00 GMT 2014
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.
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();
+}
More information about the Gcc-patches
mailing list