public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
From: Martin Jambor <mjambor@suse.cz>
To: "Arsen Arsenović" <arsen@aarsen.me>
Cc: GCC Mailing List <gcc@gcc.gnu.org>, Jan Hubicka <hubicka@ucw.cz>,
	Martin Liska <mliska@suse.cz>
Subject: Re: cgraph: does node->inlined_to imply node->clones is non-empty?
Date: Wed, 15 Mar 2023 18:12:27 +0100	[thread overview]
Message-ID: <ri6cz5a5478.fsf@suse.cz> (raw)
In-Reply-To: <86bkkwude3.fsf@aarsen.me>

Hello,

I had been aware of your message even before Martin Liška pointed to it,
but I could not answer the questions without looking into the problem
myself.

On Mon, Mar 13 2023, Arsen Arsenović via Gcc wrote:
> Hi,
>
> I was debugging PR96059 and ran into a question which does not seem
> obvious from the code.

Thanks for looking into old bugs, it really is appreciated!

> When the original inline
> happens, ipa-inline-transform.cc:clone_inlined_nodes decides not to make
> a clone, since the function being cloned is a master clone but with no
> non-inline clones.

The reason is rather that cloning can simply be avoided if you know that
you do not need an offline copy, for anything, be it other normal calls,
calls from outside of the compilation unit, indirect calls, virtual
calls, calls through aliases, thunks... that you do not need the intact
body of the function to create other inline copies, other specialized
clones... and maybe I forgot about something.  But this is an efficiency
thing.

>
> For the test case in the PR, in ipa.cc:remove_unreachable_nodes, GCC
> seems to try to remove an unreachable function that was already inlined
> into a different unreachable function.

No, it fails to remove it.  It is still there but should not have been,
that is the problem.

>
> This decision later trips up the gcc_assert in:
>
>   /* Inline clones might be kept around so their materializing allows further
>      cloning.  If the function the clone is inlined into is removed, we need
>      to turn it into normal cone.  */
>   FOR_EACH_FUNCTION (node)
>     {
>       if (node->inlined_to
> 	  && !node->callers)
> 	{
> 	  gcc_assert (node->clones);
> 	  node->inlined_to = NULL;
> 	  update_inlined_to_pointer (node, node);
> 	}
>       node->aux = NULL;
>     }
>
> .. because it is expecting that an inlined function without callers
> (which is necessarily true here as this function is unreachable and so
> was ->remove ()'d earlier) has clones.

The assert makes sure that if we encounter an inlined-to node without
any caller, that it merely holds as the holder of the function body for
its other specialized (think IPA-CP) or inline clones.  If node->clones
is false, there are no such clones and it was a bug to mark the node as
required during the removal of unreachable nodes.

>
> Either removing the assertion or making clone_inline_nodes clone when
> there are no existing clones 'fixes' (suppresses, but I haven't verified
> whether the results are correct) the problem.
>
> Is this gcc_assert correct in that an inlined function without callers
> necessarily must have clones?

It is correct.  An inlined function without a caller is even a logical
oxymoron and can only exist if it has the purpose described above (and
even then probably only in a fairly special circumstances).

>
> And as a side question, do all clone nodes have a ->clones pointing to
> the same list of all clones, or are they in a tree-ish arrangement,
> where clones of clones end up forming a tree, with the clone_of pointer
> being a pointer to the parent?

The latter, they form a tree.

> (in this instance, the node that trips
> the assert has a nullptr clone_of and clones value, which would AIUI
> imply that it is the original)

Yes.

> This train of thinking doesn't end up involving any devirtualization
> code, which the PR was originally reproduced with, but my current theory
> is that devirtualizing here just exposed an edge case that is decently
> well hidden, rather than it playing a crucial role.

The inlined function is - I believe erroneously - marked as reachable by
walk_polymorphic_call_targets() within the unreachable analysis - so
devirtualizing is somewhat crucial.

I believe the real question - to which I don't have an answer yet - is
why does possible_polymorphic_call_targets return a method that is not
virtual?

  (gdb) p n->decl->decl_common.virtual_flag
  $19 = 0

Or even

  (gdb) p referenced_from_vtable_p(n)
  $24 = false

Time to dig into ipa-devirt.cc, I guess....

Martin

  parent reply	other threads:[~2023-03-15 17:12 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-03-13 10:24 Arsen Arsenović
2023-03-14 12:42 ` Martin Liška
2023-03-15 17:12 ` Martin Jambor [this message]
2023-03-18 15:26   ` Arsen Arsenović
2023-03-24 12:40     ` Martin Jambor
2023-03-24 13:29       ` Jan Hubicka
2023-03-28  1:10       ` Arsen Arsenović

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ri6cz5a5478.fsf@suse.cz \
    --to=mjambor@suse.cz \
    --cc=arsen@aarsen.me \
    --cc=gcc@gcc.gnu.org \
    --cc=hubicka@ucw.cz \
    --cc=mliska@suse.cz \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).