Question about function body and function specialization

Erick Ochoa erick.ochoa@theobroma-systems.com
Thu Jul 16 10:46:51 GMT 2020



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
> 


More information about the Gcc mailing list