public inbox for gcc@gcc.gnu.org
 help / color / mirror / Atom feed
* Question about function body and function specialization
@ 2020-07-14 10:37 Erick Ochoa
  2020-07-14 11:19 ` Erick Ochoa
  0 siblings, 1 reply; 8+ messages in thread
From: Erick Ochoa @ 2020-07-14 10:37 UTC (permalink / raw)
  To: GCC Development; +Cc: Christoph Müllner, Philipp Tomsich

Hello,

I have a function foo defined on a source file. Sometimes, a function 
pointer pointing to foo is passed as a parameter to other functions 
where foo is called indirectly. This indirect call is specialized during 
link time. Still at link time, I analyze the function call the following 
way:

   // s is the gimple statement which corresponds to the indirect call
   tree fn = gimple_call_fndecl(s);
   // for this particular call the assertions are true
   gcc_assert(fn)
   cgraph_node *node = cgraph_node::get(fn)
   gcc_assert(node)

I have analyzed the body of this function previously by using the 
FOR_EACH_FUNCTION_WITH_GIMPLE_BODY macro. However, I do not know if 
there's a way to link the cnode_graph (or function decl) analyzed in the 
macro with the one obtained at the call site. What would be the best way 
to say something like:

   tree fn = gimple_call_fndecl(s);
   // for this particular call the assertions are true
   gcc_assert(fn)
   cgraph_node *node = cgraph_node::get(fn)
   gcc_assert(node)
   bool i_want_this_to_be_true = saw_fn_in_loop_before(node, fn);

I don't think that using storing the for loop and checking in 
saw_fn_in_loop_before is the way to go because I believe cnode->decl 
pointers can be different. Is this correct? In other words


FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(cnode)
{
   a_std_set.insert(cnode->decl)
}

// later

bool
saw_fn_in_loop_before(cnode_graph *cn, tree fn)
{
   return a_std_set.find(fn) != a_std_set.end();
}

Should not work. Something I found interesting is that for the fndecl 
obtained through the callsite gimple_has_body_p returns false. Even 
though I saw a fndecl which corresponds to the same function in the 
FOR_EACH_FUNCTION_WITH_GIMPLE_BODY.

Thanks! Any hints are appreciated!

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Question about function body and function specialization
  2020-07-14 10:37 Question about function body and function specialization Erick Ochoa
@ 2020-07-14 11:19 ` Erick Ochoa
  2020-07-15 12:03   ` Martin Jambor
  2020-07-15 14:31   ` Erick Ochoa
  0 siblings, 2 replies; 8+ messages in thread
From: Erick Ochoa @ 2020-07-14 11:19 UTC (permalink / raw)
  To: GCC Development; +Cc: Christoph Müllner, Philipp Tomsich

Actually, another interesting hint is that the original foo function 
takes two parameters. The function I am seeing inside the 
FOR_EACH_FUNCTION_WITH_GIMPLE_BODY is a specialized function of foo with 
only 1 parameter. However, the indirect function call is a version of 
foo which has not been specialized (i.e. it takes the original two 
parameters).

I guess my questions would be:

* Does FOR_EACH_FUNCTION_WITH_GIMPLE_BODY only iterates across functions 
which are reachable for main across the call graph?
* Is the the underlying mechanism for FOR_EACH_FUNCTION_WITH_GIMPLE_BODY 
not updated after ipa-prop discovers targets of indirect functions?
* Or is it just that the new callsite does not have a gimple body for 
its function? (This seems implausible since the new direct callsite 
should refer to the original function implementation.) How can I access 
this function's body?

Thanks.


On 14/07/2020 12:37, Erick Ochoa wrote:
> Hello,
> 
> I have a function foo defined on a source file. Sometimes, a function 
> pointer pointing to foo is passed as a parameter to other functions 
> where foo is called indirectly. This indirect call is specialized during 
> link time. Still at link time, I analyze the function call the following 
> way:
> 
>    // s is the gimple statement which corresponds to the indirect call
>    tree fn = gimple_call_fndecl(s);
>    // for this particular call the assertions are true
>    gcc_assert(fn)
>    cgraph_node *node = cgraph_node::get(fn)
>    gcc_assert(node)
> 
> I have analyzed the body of this function previously by using the 
> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY macro. However, I do not know if 
> there's a way to link the cnode_graph (or function decl) analyzed in the 
> macro with the one obtained at the call site. What would be the best way 
> to say something like:
> 
>    tree fn = gimple_call_fndecl(s);
>    // for this particular call the assertions are true
>    gcc_assert(fn)
>    cgraph_node *node = cgraph_node::get(fn)
>    gcc_assert(node)
>    bool i_want_this_to_be_true = saw_fn_in_loop_before(node, fn);
> 
> I don't think that using storing the for loop and checking in 
> saw_fn_in_loop_before is the way to go because I believe cnode->decl 
> pointers can be different. Is this correct? In other words
> 
> 
> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(cnode)
> {
>    a_std_set.insert(cnode->decl)
> }
> 
> // later
> 
> bool
> saw_fn_in_loop_before(cnode_graph *cn, tree fn)
> {
>    return a_std_set.find(fn) != a_std_set.end();
> }
> 
> Should not work. Something I found interesting is that for the fndecl 
> obtained through the callsite gimple_has_body_p returns false. Even 
> though I saw a fndecl which corresponds to the same function in the 
> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY.
> 
> Thanks! Any hints are appreciated!

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Question about function body and function specialization
  2020-07-14 11:19 ` Erick Ochoa
@ 2020-07-15 12:03   ` Martin Jambor
  2020-07-15 15:30     ` Erick Ochoa
  2020-07-15 14:31   ` Erick Ochoa
  1 sibling, 1 reply; 8+ messages in thread
From: Martin Jambor @ 2020-07-15 12:03 UTC (permalink / raw)
  To: Erick Ochoa, GCC Development; +Cc: Philipp Tomsich, Christoph Müllner

Hi,

On Tue, Jul 14 2020, Erick Ochoa wrote:
> On 14/07/2020 12:37, Erick Ochoa wrote:
>> Hello,
>> 
>> I have a function foo defined on a source file. Sometimes, a function 
>> pointer pointing to foo is passed as a parameter to other functions 
>> where foo is called indirectly. This indirect call is specialized during 
>> link time. Still at link time, I analyze the function call the following 

Does "at link time" mean that all of the below happens as part of the
execute method of an IPA pass?  Statements and call graph do diverge for
a while at that stage (perhaps watching
https://youtu.be/LBn-0jYKLb8?t=2604 from time 26:04 until about 50:20
might help a little).

>> way:
>> 
>>    // s is the gimple statement which corresponds to the indirect call
>>    tree fn = gimple_call_fndecl(s);
>>    // for this particular call the assertions are true
>>    gcc_assert(fn)

That can't be.  If s was an indirect call, gimple_call_fndecl(s) would
return NULL (because gimple_call_fn(gs) would be an SSA_NAME).  Perhaps
early inlining already converted it to a direct one?

>>    cgraph_node *node = cgraph_node::get(fn)
>>    gcc_assert(node)
>> 
>> I have analyzed the body of this function previously by using the 
>> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY macro. However, I do not know if 
>> there's a way to link the cnode_graph (or function decl) analyzed in the 
>> macro with the one obtained at the call site. What would be the best way 
>> to say something like:
>> 
>>    tree fn = gimple_call_fndecl(s);
>>    // for this particular call the assertions are true
>>    gcc_assert(fn)
>>    cgraph_node *node = cgraph_node::get(fn)
>>    gcc_assert(node)
>>    bool i_want_this_to_be_true = saw_fn_in_loop_before(node, fn);

At IPA time, the best way is always to look at the call graph edges,
something like:

   cgraph_edge *cs = caller_cgraph_node->get_edge (s);
   examine (e->callee);

Note that if the call is truly an indirect one cs->callee will be NULL
(and cs->indirect_unknown_callee will be set).  Things can also get
quite a bit more complicated if cs->speculative is set, then there is
both an indirect and guessed direct edge for a single call.

>> 
>> I don't think that using storing the for loop and checking in 
>> saw_fn_in_loop_before is the way to go because I believe cnode->decl 
>> pointers can be different. Is this correct? In other words
>> 
>> 
>> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(cnode)
>> {
>>    a_std_set.insert(cnode->decl)
>> }
>> 
>> // later
>> 
>> bool
>> saw_fn_in_loop_before(cnode_graph *cn, tree fn)
>> {
>>    return a_std_set.find(fn) != a_std_set.end();
>> }
>> 
>> Should not work. Something I found interesting is that for the fndecl 
>> obtained through the callsite gimple_has_body_p returns false. Even 
>> though I saw a fndecl which corresponds to the same function in the 
>> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY.

I can only guess but it seems that something has created specialized
clone for all contexts and you happen to be looking at the gimple bodies
after clone materialization but before edge redirection... but I am only
guessing.

>
> Actually, another interesting hint is that the original foo function 
> takes two parameters. The function I am seeing inside the 
> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY is a specialized function of foo with 
> only 1 parameter. However, the indirect function call is a version of 
> foo which has not been specialized (i.e. it takes the original two 
> parameters).
>
> I guess my questions would be:
>
> * Does FOR_EACH_FUNCTION_WITH_GIMPLE_BODY only iterates across functions 
> which are reachable for main across the call graph?

No.  But functions which are known not to be reachable are of course
removed from the call graph and from the entire compilation too.

> * Is the the underlying mechanism for FOR_EACH_FUNCTION_WITH_GIMPLE_BODY 
> not updated after ipa-prop discovers targets of indirect functions?

I am not sure I understand the question but I guess that no.  The
mechanism is simple, just look it up.

> * Or is it just that the new callsite does not have a gimple body for 
> its function? (This seems implausible since the new direct callsite 
> should refer to the original function implementation.) How can I access 
> this function's body?
>

In the IPA scheme of things, call-sites are updated last, even when the
function where they are keeps its body from the start until the end.  It
seems to me that you really want to be looking at the call graph edges
instead.

Generally speaking, at IPA time you want to work only with the call
graph and the data you collected in summary building stage and look at
actual function bodies only as the last resort.

Martin

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Question about function body and function specialization
  2020-07-14 11:19 ` Erick Ochoa
  2020-07-15 12:03   ` Martin Jambor
@ 2020-07-15 14:31   ` Erick Ochoa
  2020-07-15 14:46     ` Martin Jambor
  1 sibling, 1 reply; 8+ messages in thread
From: Erick Ochoa @ 2020-07-15 14:31 UTC (permalink / raw)
  To: GCC Development; +Cc: Christoph Müllner, Philipp Tomsich

Hi,

I narrowed down that ipa-inline is marking these indirect functions as 
unreachable (these functions have been specialized and therefore should 
now be direct functions). Therefore, symtab_remove_unreachable_nodes is 
called on them. Running the following (immediately after materialization):

tree fndecl = gimple_call_fndecl(s)
cgraph_node *from_fndecl = cgraph_node::get(fndecl);
cgraph_node *from_symtable = NULL;
bool found = false;
FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(from_symtable)
{
   found |= from_fndecl == from_symtable;
}

will result in found always being false.

Is it the desired behaviour that functions which addresses are taken to 
be marked as unreachable (and therefore being unregistered from the 
symbol table)?

If needed I can reduce the problem, but I don't want to do it if this is 
the intended behaviour.

Thanks!


On 14.07.20 04:19, Erick Ochoa wrote:
> Actually, another interesting hint is that the original foo function 
> takes two parameters. The function I am seeing inside the 
> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY is a specialized function of foo with 
> only 1 parameter. However, the indirect function call is a version of 
> foo which has not been specialized (i.e. it takes the original two 
> parameters).
> 
> I guess my questions would be:
> 
> * Does FOR_EACH_FUNCTION_WITH_GIMPLE_BODY only iterates across functions 
> which are reachable for main across the call graph?
> * Is the the underlying mechanism for FOR_EACH_FUNCTION_WITH_GIMPLE_BODY 
> not updated after ipa-prop discovers targets of indirect functions?
> * Or is it just that the new callsite does not have a gimple body for 
> its function? (This seems implausible since the new direct callsite 
> should refer to the original function implementation.) How can I access 
> this function's body?
> 
> Thanks.
> 
> 
> On 14/07/2020 12:37, Erick Ochoa wrote:
>> Hello,
>>
>> I have a function foo defined on a source file. Sometimes, a function 
>> pointer pointing to foo is passed as a parameter to other functions 
>> where foo is called indirectly. This indirect call is specialized 
>> during link time. Still at link time, I analyze the function call the 
>> following way:
>>
>>    // s is the gimple statement which corresponds to the indirect call
>>    tree fn = gimple_call_fndecl(s);
>>    // for this particular call the assertions are true
>>    gcc_assert(fn)
>>    cgraph_node *node = cgraph_node::get(fn)
>>    gcc_assert(node)
>>
>> I have analyzed the body of this function previously by using the 
>> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY macro. However, I do not know if 
>> there's a way to link the cnode_graph (or function decl) analyzed in 
>> the macro with the one obtained at the call site. What would be the 
>> best way to say something like:
>>
>>    tree fn = gimple_call_fndecl(s);
>>    // for this particular call the assertions are true
>>    gcc_assert(fn)
>>    cgraph_node *node = cgraph_node::get(fn)
>>    gcc_assert(node)
>>    bool i_want_this_to_be_true = saw_fn_in_loop_before(node, fn);
>>
>> I don't think that using storing the for loop and checking in 
>> saw_fn_in_loop_before is the way to go because I believe cnode->decl 
>> pointers can be different. Is this correct? In other words
>>
>>
>> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(cnode)
>> {
>>    a_std_set.insert(cnode->decl)
>> }
>>
>> // later
>>
>> bool
>> saw_fn_in_loop_before(cnode_graph *cn, tree fn)
>> {
>>    return a_std_set.find(fn) != a_std_set.end();
>> }
>>
>> Should not work. Something I found interesting is that for the fndecl 
>> obtained through the callsite gimple_has_body_p returns false. Even 
>> though I saw a fndecl which corresponds to the same function in the 
>> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY.
>>
>> Thanks! Any hints are appreciated!

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Question about function body and function specialization
  2020-07-15 14:31   ` Erick Ochoa
@ 2020-07-15 14:46     ` Martin Jambor
  0 siblings, 0 replies; 8+ messages in thread
From: Martin Jambor @ 2020-07-15 14:46 UTC (permalink / raw)
  To: Erick Ochoa, GCC Development; +Cc: Philipp Tomsich, Christoph Müllner

Hi,

On Wed, Jul 15 2020, Erick Ochoa wrote:
> Hi,
>
> I narrowed down that ipa-inline is marking these indirect functions as 
> unreachable (these functions have been specialized and therefore should 
> now be direct functions). Therefore, symtab_remove_unreachable_nodes is 
> called on them. Running the following (immediately after materialization):
>
> tree fndecl = gimple_call_fndecl(s)
> cgraph_node *from_fndecl = cgraph_node::get(fndecl);
> cgraph_node *from_symtable = NULL;
> bool found = false;
> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(from_symtable)
> {
>    found |= from_fndecl == from_symtable;
> }
>
> will result in found always being false.
>
> Is it the desired behaviour that functions which addresses are taken to 
> be marked as unreachable (and therefore being unregistered from the 
> symbol table)?

The individual references are tracked in the symbol table.  When we know
that we converted a former reference into a direct use, the associated
reference is removed.  When the last one is removed, the function is no
longer considered as address taken and is indeed a candidate for
removal.

Martin

>
>
> On 14.07.20 04:19, Erick Ochoa wrote:
>> Actually, another interesting hint is that the original foo function 
>> takes two parameters. The function I am seeing inside the 
>> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY is a specialized function of foo with 
>> only 1 parameter. However, the indirect function call is a version of 
>> foo which has not been specialized (i.e. it takes the original two 
>> parameters).
>> 
>> I guess my questions would be:
>> 
>> * Does FOR_EACH_FUNCTION_WITH_GIMPLE_BODY only iterates across functions 
>> which are reachable for main across the call graph?
>> * Is the the underlying mechanism for FOR_EACH_FUNCTION_WITH_GIMPLE_BODY 
>> not updated after ipa-prop discovers targets of indirect functions?
>> * Or is it just that the new callsite does not have a gimple body for 
>> its function? (This seems implausible since the new direct callsite 
>> should refer to the original function implementation.) How can I access 
>> this function's body?
>> 
>> Thanks.
>> 
>> 
>> On 14/07/2020 12:37, Erick Ochoa wrote:
>>> Hello,
>>>
>>> I have a function foo defined on a source file. Sometimes, a function 
>>> pointer pointing to foo is passed as a parameter to other functions 
>>> where foo is called indirectly. This indirect call is specialized 
>>> during link time. Still at link time, I analyze the function call the 
>>> following way:
>>>
>>>    // s is the gimple statement which corresponds to the indirect call
>>>    tree fn = gimple_call_fndecl(s);
>>>    // for this particular call the assertions are true
>>>    gcc_assert(fn)
>>>    cgraph_node *node = cgraph_node::get(fn)
>>>    gcc_assert(node)
>>>
>>> I have analyzed the body of this function previously by using the 
>>> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY macro. However, I do not know if 
>>> there's a way to link the cnode_graph (or function decl) analyzed in 
>>> the macro with the one obtained at the call site. What would be the 
>>> best way to say something like:
>>>
>>>    tree fn = gimple_call_fndecl(s);
>>>    // for this particular call the assertions are true
>>>    gcc_assert(fn)
>>>    cgraph_node *node = cgraph_node::get(fn)
>>>    gcc_assert(node)
>>>    bool i_want_this_to_be_true = saw_fn_in_loop_before(node, fn);
>>>
>>> I don't think that using storing the for loop and checking in 
>>> saw_fn_in_loop_before is the way to go because I believe cnode->decl 
>>> pointers can be different. Is this correct? In other words
>>>
>>>
>>> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(cnode)
>>> {
>>>    a_std_set.insert(cnode->decl)
>>> }
>>>
>>> // later
>>>
>>> bool
>>> saw_fn_in_loop_before(cnode_graph *cn, tree fn)
>>> {
>>>    return a_std_set.find(fn) != a_std_set.end();
>>> }
>>>
>>> Should not work. Something I found interesting is that for the fndecl 
>>> obtained through the callsite gimple_has_body_p returns false. Even 
>>> though I saw a fndecl which corresponds to the same function in the 
>>> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY.
>>>
>>> Thanks! Any hints are appreciated!

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Re: Question about function body and function specialization
  2020-07-15 12:03   ` Martin Jambor
@ 2020-07-15 15:30     ` Erick Ochoa
  2020-07-16 10:11       ` Martin Jambor
  0 siblings, 1 reply; 8+ messages in thread
From: Erick Ochoa @ 2020-07-15 15:30 UTC (permalink / raw)
  To: Martin Jambor, GCC Development; +Cc: Christoph Müllner, Philipp Tomsich



On 15.07.20 05:03, Martin Jambor wrote:
> Hi,
> 
> On Tue, Jul 14 2020, Erick Ochoa wrote:
>> On 14/07/2020 12:37, Erick Ochoa wrote:
>>> Hello,
>>>
>>> I have a function foo defined on a source file. Sometimes, a function
>>> pointer pointing to foo is passed as a parameter to other functions
>>> where foo is called indirectly. This indirect call is specialized during
>>> link time. Still at link time, I analyze the function call the following
> 
> Does "at link time" mean that all of the below happens as part of the
> execute method of an IPA pass?  Statements and call graph do diverge for
> a while at that stage (perhaps watching
> https://youtu.be/LBn-0jYKLb8?t=2604 from time 26:04 until about 50:20
> might help a little).

Thanks, I'll give this a watch.
What I meant is that the indirect call is specialized during ipa-cp.

> 
>>> way:
>>>
>>>     // s is the gimple statement which corresponds to the indirect call
>>>     tree fn = gimple_call_fndecl(s);
>>>     // for this particular call the assertions are true
>>>     gcc_assert(fn)
> 
> That can't be.  If s was an indirect call, gimple_call_fndecl(s) would
> return NULL (because gimple_call_fn(gs) would be an SSA_NAME).  Perhaps
> early inlining already converted it to a direct one?

It is not early inlining which converted this indirect function call to 
a direct call. It happens during ipa-cp.

In another pass (scheduled just after materialization) is when I inspect 
gimple instructions of the caller to this indirect function which has 
been specialized.

> 
>>>     cgraph_node *node = cgraph_node::get(fn)
>>>     gcc_assert(node)
>>>
>>> I have analyzed the body of this function previously by using the
>>> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY macro. However, I do not know if
>>> there's a way to link the cnode_graph (or function decl) analyzed in the
>>> macro with the one obtained at the call site. What would be the best way
>>> to say something like:
>>>
>>>     tree fn = gimple_call_fndecl(s);
>>>     // for this particular call the assertions are true
>>>     gcc_assert(fn)
>>>     cgraph_node *node = cgraph_node::get(fn)
>>>     gcc_assert(node)
>>>     bool i_want_this_to_be_true = saw_fn_in_loop_before(node, fn);
> 
> At IPA time, the best way is always to look at the call graph edges,
> something like:
> 
>     cgraph_edge *cs = caller_cgraph_node->get_edge (s);
>     examine (e->callee);
> 
> Note that if the call is truly an indirect one cs->callee will be NULL
> (and cs->indirect_unknown_callee will be set).  Things can also get
> quite a bit more complicated if cs->speculative is set, then there is
> both an indirect and guessed direct edge for a single call.

Thanks! I did read a bunch of source code and I was wondering why all 
the constant propagation and specialization happens by navigating the 
call graph edges and not the gimple code. I initially thought that 
gimple_call_set_fndecl was not called because I couldn't find anything 
except call graph edges. However, this was not the case.

Also, by the time I am inspecting the indirect edge, it has already been 
specialized and it is not speculative. So, it has been changed to a 
direct function.

> 
>>>
>>> I don't think that using storing the for loop and checking in
>>> saw_fn_in_loop_before is the way to go because I believe cnode->decl
>>> pointers can be different. Is this correct? In other words
>>>
>>>
>>> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY(cnode)
>>> {
>>>     a_std_set.insert(cnode->decl)
>>> }
>>>
>>> // later
>>>
>>> bool
>>> saw_fn_in_loop_before(cnode_graph *cn, tree fn)
>>> {
>>>     return a_std_set.find(fn) != a_std_set.end();
>>> }
>>>
>>> Should not work. Something I found interesting is that for the fndecl
>>> obtained through the callsite gimple_has_body_p returns false. Even
>>> though I saw a fndecl which corresponds to the same function in the
>>> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY.
> 
> I can only guess but it seems that something has created specialized
> clone for all contexts and you happen to be looking at the gimple bodies
> after clone materialization but before edge redirection... but I am only
> guessing.

I think this is close to the truth. So... the function I am interested 
in finding has indeed been specialized for "all contexts", but I think 
this "all contexts" did not take into account the function pointers.

During ipa-cp I looked at the code where the function call has been 
changed from an indirect call to a direct call and I was able to find 
that callee->has_gimple_body_p() returns true and that it was also found 
in FOR_EACH_FUNCTION_WITH_GIMPLE_BODY loop.

I also did this during ipa-sra and the same was true.

But for the pass just after materialization it was false.

As mentioned in a sibling post, I found out that during the inlining 
phase, the function is "reclaimed". I'm not 100% sure yet, but I think 
the indirect functions are not inlined. I used -fdump-ipa-inline and in 
my pass (after materialization) I used cnode->dump_name() to find its 
dump name... I then looked for its dump_name and only found the following:

IPA function summary for $dump_name inlinable

$dump_name ($name) @0x40002a1936d8
   Type: function
   Body removed by symtab_remove_unreachable_nodes
   Visibility: prevailing_def_ironly
   Address is taken.
   References:
   Referring:
   Read from file: $file
   Availability: not_available
   Profile id: 1677473182
   Unit id: 2
   Function flags: count:17343 (adjusted) first_run:3 hot
   Called by:
   Calls:

These are the only two mentions of the function by its dump_name

> 
>>
>> Actually, another interesting hint is that the original foo function
>> takes two parameters. The function I am seeing inside the
>> FOR_EACH_FUNCTION_WITH_GIMPLE_BODY is a specialized function of foo with
>> only 1 parameter. However, the indirect function call is a version of
>> foo which has not been specialized (i.e. it takes the original two
>> parameters).
>>
>> I guess my questions would be:
>>
>> * Does FOR_EACH_FUNCTION_WITH_GIMPLE_BODY only iterates across functions
>> which are reachable for main across the call graph?
> 
> No.  But functions which are known not to be reachable are of course
> removed from the call graph and from the entire compilation too.
> 
>> * Is the the underlying mechanism for FOR_EACH_FUNCTION_WITH_GIMPLE_BODY
>> not updated after ipa-prop discovers targets of indirect functions?
> 
> I am not sure I understand the question but I guess that no.  The
> mechanism is simple, just look it up.
> 
>> * Or is it just that the new callsite does not have a gimple body for
>> its function? (This seems implausible since the new direct callsite
>> should refer to the original function implementation.) How can I access
>> this function's body?
>>
> 
> In the IPA scheme of things, call-sites are updated last, even when the
> function where they are keeps its body from the start until the end.  It
> seems to me that you really want to be looking at the call graph edges
> instead.
> 
> Generally speaking, at IPA time you want to work only with the call
> graph and the data you collected in summary building stage and look at
> actual function bodies only as the last resort.

Thanks Martin, this is all very useful information. I'll see if I can 
refactor my code to use the call graph and not the gimple code. However, 
I still think that there might be an interesting behaviour on reclaiming 
a cgraph_node that is reachable through function pointers...

> 
> Martin
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Re: Question about function body and function specialization
  2020-07-15 15:30     ` Erick Ochoa
@ 2020-07-16 10:11       ` Martin Jambor
  2020-07-16 10:46         ` Erick Ochoa
  0 siblings, 1 reply; 8+ messages in thread
From: Martin Jambor @ 2020-07-16 10:11 UTC (permalink / raw)
  To: Erick Ochoa, GCC Development; +Cc: Christoph Müllner, Philipp Tomsich

Hi,

On Wed, Jul 15 2020, Erick Ochoa wrote:
> On 15.07.20 05:03, Martin Jambor wrote:

[...]

>> At IPA time, the best way is always to look at the call graph edges,
>> something like:
>> 
>>     cgraph_edge *cs = caller_cgraph_node->get_edge (s);
>>     examine (e->callee);
>> 
>> Note that if the call is truly an indirect one cs->callee will be NULL
>> (and cs->indirect_unknown_callee will be set).  Things can also get
>> quite a bit more complicated if cs->speculative is set, then there is
>> both an indirect and guessed direct edge for a single call.
>
> Thanks! I did read a bunch of source code and I was wondering why all 
> the constant propagation and specialization happens by navigating the 
> call graph edges and not the gimple code.

It is designed that way in order to save memory.  When LTOing huge
applications, you do not want to load bodies of all functions into
memory at once, that way you might not be able to build Firefox,
Chromium and others even with very many gigabytes of RAM.

> I initially thought that 
> gimple_call_set_fndecl was not called because I couldn't find anything 
> except call graph edges. However, this was not the case.

The redirection is bound to eventually happen in
cgraph_edge::redirect_call_stmt_to_callee - but as you can see, it may be
a complicated process and may need to rebuild the call statement instead
of just setting the fndecl.

[...]

>> 
>> I can only guess but it seems that something has created specialized
>> clone for all contexts and you happen to be looking at the gimple bodies
>> after clone materialization but before edge redirection... but I am only
>> guessing.
>
> I think this is close to the truth. So... the function I am interested 
> in finding has indeed been specialized for "all contexts", but I think 
> this "all contexts" did not take into account the function pointers.

IPA-CP can specialize for "all known contexts" too, leaving the original
function behind for indirect calls and calls from outside of the current
compilation unit (or dll), in that case it does include code duplication
in its cost estimate.

>
> During ipa-cp I looked at the code where the function call has been 
> changed from an indirect call to a direct call and I was able to find 
> that callee->has_gimple_body_p() returns true and that it was also found 
> in FOR_EACH_FUNCTION_WITH_GIMPLE_BODY loop.
>
> I also did this during ipa-sra and the same was true.
>
> But for the pass just after materialization it was false.
>
> As mentioned in a sibling post, I found out that during the inlining 
> phase, the function is "reclaimed". I'm not 100% sure yet, but I think 
> the indirect functions are not inlined. I used -fdump-ipa-inline and in 
> my pass (after materialization) I used cnode->dump_name() to find its 
> dump name... I then looked for its dump_name and only found the following:
>
> IPA function summary for $dump_name inlinable
>
> $dump_name ($name) @0x40002a1936d8
>    Type: function
>    Body removed by symtab_remove_unreachable_nodes
>    Visibility: prevailing_def_ironly
>    Address is taken.
>    References:
>    Referring:
>    Read from file: $file
>    Availability: not_available
>    Profile id: 1677473182
>    Unit id: 2
>    Function flags: count:17343 (adjusted) first_run:3 hot
>    Called by:
>    Calls:

It looks quite unreachable, no Callers, no Referring nodes - that's
where the address references which I wrote in another email are stored
in the symbol table.

Martin

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: Question about function body and function specialization
  2020-07-16 10:11       ` Martin Jambor
@ 2020-07-16 10:46         ` Erick Ochoa
  0 siblings, 0 replies; 8+ messages in thread
From: Erick Ochoa @ 2020-07-16 10:46 UTC (permalink / raw)
  To: Martin Jambor, GCC Development; +Cc: Christoph Müllner, Philipp Tomsich



On 16/07/2020 12:11, Martin Jambor wrote:
> Hi,
> 
> On Wed, Jul 15 2020, Erick Ochoa wrote:
>> On 15.07.20 05:03, Martin Jambor wrote:
> 
> [...]
> 
>>> At IPA time, the best way is always to look at the call graph edges,
>>> something like:
>>>
>>>      cgraph_edge *cs = caller_cgraph_node->get_edge (s);
>>>      examine (e->callee);
>>>
>>> Note that if the call is truly an indirect one cs->callee will be NULL
>>> (and cs->indirect_unknown_callee will be set).  Things can also get
>>> quite a bit more complicated if cs->speculative is set, then there is
>>> both an indirect and guessed direct edge for a single call.
>>
>> Thanks! I did read a bunch of source code and I was wondering why all
>> the constant propagation and specialization happens by navigating the
>> call graph edges and not the gimple code.
> 
> It is designed that way in order to save memory.  When LTOing huge
> applications, you do not want to load bodies of all functions into
> memory at once, that way you might not be able to build Firefox,
> Chromium and others even with very many gigabytes of RAM.
> 
>> I initially thought that
>> gimple_call_set_fndecl was not called because I couldn't find anything
>> except call graph edges. However, this was not the case.
> 
> The redirection is bound to eventually happen in
> cgraph_edge::redirect_call_stmt_to_callee - but as you can see, it may be
> a complicated process and may need to rebuild the call statement instead
> of just setting the fndecl.
> 
> [...]
> 
>>>
>>> I can only guess but it seems that something has created specialized
>>> clone for all contexts and you happen to be looking at the gimple bodies
>>> after clone materialization but before edge redirection... but I am only
>>> guessing.
>>
>> I think this is close to the truth. So... the function I am interested
>> in finding has indeed been specialized for "all contexts", but I think
>> this "all contexts" did not take into account the function pointers.
> 
> IPA-CP can specialize for "all known contexts" too, leaving the original
> function behind for indirect calls and calls from outside of the current
> compilation unit (or dll), in that case it does include code duplication
> in its cost estimate.
> 
>>
>> During ipa-cp I looked at the code where the function call has been
>> changed from an indirect call to a direct call and I was able to find
>> that callee->has_gimple_body_p() returns true and that it was also found
>> in FOR_EACH_FUNCTION_WITH_GIMPLE_BODY loop.
>>
>> I also did this during ipa-sra and the same was true.
>>
>> But for the pass just after materialization it was false.
>>
>> As mentioned in a sibling post, I found out that during the inlining
>> phase, the function is "reclaimed". I'm not 100% sure yet, but I think
>> the indirect functions are not inlined. I used -fdump-ipa-inline and in
>> my pass (after materialization) I used cnode->dump_name() to find its
>> dump name... I then looked for its dump_name and only found the following:
>>
>> IPA function summary for $dump_name inlinable
>>
>> $dump_name ($name) @0x40002a1936d8
>>     Type: function
>>     Body removed by symtab_remove_unreachable_nodes
>>     Visibility: prevailing_def_ironly
>>     Address is taken.
>>     References:
>>     Referring:
>>     Read from file: $file
>>     Availability: not_available
>>     Profile id: 1677473182
>>     Unit id: 2
>>     Function flags: count:17343 (adjusted) first_run:3 hot
>>     Called by:
>>     Calls:
> 
> It looks quite unreachable, no Callers, no Referring nodes - that's
> where the address references which I wrote in another email are stored
> in the symbol table.

Hi Martin, yesterday you told me to look at the callgraph. I had a 
chance to do so today. You were right that the fndecl from the gimple IL 
has not been modified to point to the correct callee's fndecl.

Looping through all callees I found that even though gimple IL says that 
the fndecl is the unmodified version of the function foo (for example), 
the call graph says that the callee's fndecl should be another 
specialized version of foo. The original foo is unreachable (the above 
dump is correct). And the node is removed.

The only reason why I believed this was a bug or an edge case, was 
because other callsites (which go through the same process as this one) 
were pointing to a fndecl (let's call this one bar) which was not 
removed. However, it just so happened that the original version of bar 
has other callers and therefore it was not removed from the nodes. So... 
technically even though the gimple IL refers to an unmodified version of 
bar (which has other callers), the call graph points to a specialized 
version of bar. This difference was the one that made me suspicious.

Thanks for all of this.

> 
> Martin
> 

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2020-07-16 10:46 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-07-14 10:37 Question about function body and function specialization Erick Ochoa
2020-07-14 11:19 ` Erick Ochoa
2020-07-15 12:03   ` Martin Jambor
2020-07-15 15:30     ` Erick Ochoa
2020-07-16 10:11       ` Martin Jambor
2020-07-16 10:46         ` Erick Ochoa
2020-07-15 14:31   ` Erick Ochoa
2020-07-15 14:46     ` Martin Jambor

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).