> The code removing function bodies when the last call graph clone of a
> node is removed is too aggressive when there are nodes up the
> clone_of chain which still need them.  Fixed by expanding the check.
> 
> gcc/ChangeLog:
> 
> 2023-01-18  Martin Jambor  <mjam...@suse.cz>
> 
>       PR ipa/107944
>       * cgraph.cc (cgraph_node::remove): Check whether nodes up the
>       lcone_of chain also do not need the body.
> ---
>  gcc/cgraph.cc | 14 ++++++++++++--
>  1 file changed, 12 insertions(+), 2 deletions(-)
> 
> diff --git a/gcc/cgraph.cc b/gcc/cgraph.cc
> index 5e60c2b73db..5f72ace9b57 100644
> --- a/gcc/cgraph.cc
> +++ b/gcc/cgraph.cc
> @@ -1893,8 +1893,18 @@ cgraph_node::remove (void)
>    else if (clone_of)
>      {
>        clone_of->clones = next_sibling_clone;
> -      if (!clone_of->analyzed && !clone_of->clones && !clones)
> -     clone_of->release_body ();
> +      if (!clones)
> +     {
> +       bool need_body = false;
> +       for (cgraph_node *n = clone_of; n; n = n->clone_of)
> +         if (n->analyzed || n->clones)
> +           {
> +             need_body = true;
If you want to walk immediate clones and see if any of them is needed, I
wonder why you don't also walk recursively clones of clones?

Original idea was that the clones should be materialized and removed one
by one (or proved unreachable and just removed) and once we remove last
one, we should figure out that body is not needed. For that one does not
not need the walk at all.

How exactly we end up with clones that are not analyzed?

Honza
> +             break;
> +           }
> +       if (!need_body)
> +         clone_of->release_body ();
> +     }
>      }
>    if (next_sibling_clone)
>      next_sibling_clone->prev_sibling_clone = prev_sibling_clone;
> -- 
> 2.39.0
> 

Reply via email to