LCOV - code coverage report
Current view: top level - gcc - ipa-inline-analysis.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 92.3 % 259 239
Test Date: 2024-11-30 13:30:02 Functions: 93.3 % 15 14
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Analysis used by inlining decision heuristics.
       2                 :             :    Copyright (C) 2003-2024 Free Software Foundation, Inc.
       3                 :             :    Contributed by Jan Hubicka
       4                 :             : 
       5                 :             : This file is part of GCC.
       6                 :             : 
       7                 :             : GCC is free software; you can redistribute it and/or modify it under
       8                 :             : the terms of the GNU General Public License as published by the Free
       9                 :             : Software Foundation; either version 3, or (at your option) any later
      10                 :             : version.
      11                 :             : 
      12                 :             : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      13                 :             : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      14                 :             : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      15                 :             : for more details.
      16                 :             : 
      17                 :             : You should have received a copy of the GNU General Public License
      18                 :             : along with GCC; see the file COPYING3.  If not see
      19                 :             : <http://www.gnu.org/licenses/>.  */
      20                 :             : 
      21                 :             : #include "config.h"
      22                 :             : #include "system.h"
      23                 :             : #include "coretypes.h"
      24                 :             : #include "backend.h"
      25                 :             : #include "tree.h"
      26                 :             : #include "gimple.h"
      27                 :             : #include "alloc-pool.h"
      28                 :             : #include "tree-pass.h"
      29                 :             : #include "ssa.h"
      30                 :             : #include "tree-streamer.h"
      31                 :             : #include "cgraph.h"
      32                 :             : #include "diagnostic.h"
      33                 :             : #include "fold-const.h"
      34                 :             : #include "print-tree.h"
      35                 :             : #include "tree-inline.h"
      36                 :             : #include "gimple-pretty-print.h"
      37                 :             : #include "cfganal.h"
      38                 :             : #include "gimple-iterator.h"
      39                 :             : #include "tree-cfg.h"
      40                 :             : #include "tree-ssa-loop-niter.h"
      41                 :             : #include "tree-ssa-loop.h"
      42                 :             : #include "symbol-summary.h"
      43                 :             : #include "sreal.h"
      44                 :             : #include "ipa-cp.h"
      45                 :             : #include "ipa-prop.h"
      46                 :             : #include "ipa-fnsummary.h"
      47                 :             : #include "ipa-inline.h"
      48                 :             : #include "cfgloop.h"
      49                 :             : #include "tree-scalar-evolution.h"
      50                 :             : #include "ipa-utils.h"
      51                 :             : #include "cfgexpand.h"
      52                 :             : #include "gimplify.h"
      53                 :             : #include "attribs.h"
      54                 :             : 
      55                 :             : /* Cached node/edge growths.  */
      56                 :             : fast_call_summary<edge_growth_cache_entry *, va_heap> *edge_growth_cache = NULL;
      57                 :             : 
      58                 :             : /* The context cache remembers estimated time/size and hints for given
      59                 :             :    ipa_call_context of a call.  */
      60                 :             : class node_context_cache_entry
      61                 :             : {
      62                 :             : public:
      63                 :             :   ipa_cached_call_context ctx;
      64                 :             :   sreal time, nonspec_time;
      65                 :             :   int size;
      66                 :             :   ipa_hints hints;
      67                 :             : 
      68                 :     1010853 :   node_context_cache_entry ()
      69                 :     1010853 :   : ctx ()
      70                 :             :   {
      71                 :             :   }
      72                 :     1010853 :   ~node_context_cache_entry ()
      73                 :             :   {
      74                 :     1010853 :     ctx.release ();
      75                 :             :   }
      76                 :             : };
      77                 :             : 
      78                 :             : /* At the moment we implement primitive single entry LRU cache.  */
      79                 :             : class node_context_summary
      80                 :             : {
      81                 :             : public:
      82                 :             :   node_context_cache_entry entry;
      83                 :             : 
      84                 :     1010853 :   node_context_summary ()
      85                 :           0 :   : entry ()
      86                 :             :   {
      87                 :             :   }
      88                 :     1010853 :   ~node_context_summary ()
      89                 :             :   {
      90                 :     1010853 :   }
      91                 :             : };
      92                 :             : 
      93                 :             : /* Summary holding the context cache.  */
      94                 :             : static fast_function_summary <node_context_summary *, va_heap>
      95                 :             :         *node_context_cache = NULL;
      96                 :             : /* Statistics about the context cache effectivity.  */
      97                 :             : static long node_context_cache_hit, node_context_cache_miss,
      98                 :             :             node_context_cache_clear;
      99                 :             : 
     100                 :             : /* Give initial reasons why inlining would fail on EDGE.  This gets either
     101                 :             :    nullified or usually overwritten by more precise reasons later.  */
     102                 :             : 
     103                 :             : void
     104                 :    36601032 : initialize_inline_failed (struct cgraph_edge *e)
     105                 :             : {
     106                 :    36601032 :   struct cgraph_node *callee = e->callee;
     107                 :             : 
     108                 :    36601032 :   if (e->inline_failed && e->inline_failed != CIF_BODY_NOT_AVAILABLE
     109                 :    72972222 :       && cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR)
     110                 :             :     ;
     111                 :    36587707 :   else if (e->indirect_unknown_callee)
     112                 :      655739 :     e->inline_failed = CIF_INDIRECT_UNKNOWN_CALL;
     113                 :    35931968 :   else if (!callee->definition)
     114                 :    19745574 :     e->inline_failed = CIF_BODY_NOT_AVAILABLE;
     115                 :    16186394 :   else if (callee->redefined_extern_inline)
     116                 :         178 :     e->inline_failed = CIF_REDEFINED_EXTERN_INLINE;
     117                 :             :   else
     118                 :    16186216 :     e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED;
     119                 :    36601032 :   gcc_checking_assert (!e->call_stmt_cannot_inline_p
     120                 :             :                        || cgraph_inline_failed_type (e->inline_failed)
     121                 :             :                             == CIF_FINAL_ERROR);
     122                 :    36601032 : }
     123                 :             : 
     124                 :             : /* Allocate edge growth caches.  */
     125                 :             : 
     126                 :             : void
     127                 :      225138 : initialize_growth_caches ()
     128                 :             : {
     129                 :      225138 :   edge_growth_cache
     130                 :      225138 :     = new fast_call_summary<edge_growth_cache_entry *, va_heap> (symtab);
     131                 :      225138 :   node_context_cache
     132                 :      225138 :     = new fast_function_summary<node_context_summary *, va_heap> (symtab);
     133                 :      225138 :   edge_growth_cache->disable_duplication_hook ();
     134                 :      225138 :   node_context_cache->disable_insertion_hook ();
     135                 :      225138 :   node_context_cache->disable_duplication_hook ();
     136                 :      225138 : }
     137                 :             : 
     138                 :             : /* Free growth caches.  */
     139                 :             : 
     140                 :             : void
     141                 :      225138 : free_growth_caches (void)
     142                 :             : {
     143                 :      225138 :   delete edge_growth_cache;
     144                 :      225138 :   delete node_context_cache;
     145                 :      225138 :   edge_growth_cache = NULL;
     146                 :      225138 :   node_context_cache = NULL;
     147                 :      225138 :   if (dump_file)
     148                 :         178 :     fprintf (dump_file, "node context cache: %li hits, %li misses,"
     149                 :             :                         " %li initializations\n",
     150                 :             :              node_context_cache_hit, node_context_cache_miss,
     151                 :             :              node_context_cache_clear);
     152                 :      225138 :   node_context_cache_hit = 0;
     153                 :      225138 :   node_context_cache_miss = 0;
     154                 :      225138 :   node_context_cache_clear = 0;
     155                 :      225138 : }
     156                 :             : 
     157                 :             : /* Return hints derived from EDGE.   */
     158                 :             : 
     159                 :             : int
     160                 :     5485124 : simple_edge_hints (struct cgraph_edge *edge)
     161                 :             : {
     162                 :     5485124 :   int hints = 0;
     163                 :    10970248 :   struct cgraph_node *to = (edge->caller->inlined_to
     164                 :     5485124 :                             ? edge->caller->inlined_to : edge->caller);
     165                 :     5485124 :   struct cgraph_node *callee = edge->callee->ultimate_alias_target ();
     166                 :     5485124 :   int to_scc_no = ipa_fn_summaries->get (to)->scc_no;
     167                 :     5485124 :   int callee_scc_no = ipa_fn_summaries->get (callee)->scc_no;
     168                 :             : 
     169                 :     5485124 :   if (to_scc_no && to_scc_no  == callee_scc_no && !edge->recursive_p ())
     170                 :             :     hints |= INLINE_HINT_same_scc;
     171                 :             : 
     172                 :     5485124 :   if (cross_module_call_p (edge))
     173                 :        4035 :     hints |= INLINE_HINT_cross_module;
     174                 :             : 
     175                 :     5485124 :   return hints;
     176                 :             : }
     177                 :             : 
     178                 :             : /* Estimate the time cost for the caller when inlining EDGE.
     179                 :             :    Only to be called via estimate_edge_time, that handles the
     180                 :             :    caching mechanism.
     181                 :             : 
     182                 :             :    When caching, also update the cache entry.  Compute both time and
     183                 :             :    size, since we always need both metrics eventually.  */
     184                 :             : 
     185                 :             : sreal
     186                 :     5488936 : do_estimate_edge_time (struct cgraph_edge *edge, sreal *ret_nonspec_time)
     187                 :             : {
     188                 :     5488936 :   sreal time, nonspec_time;
     189                 :     5488936 :   int size;
     190                 :     5488936 :   ipa_hints hints;
     191                 :     5488936 :   struct cgraph_node *callee;
     192                 :     5488936 :   clause_t clause, nonspec_clause;
     193                 :     5488936 :   ipa_auto_call_arg_values avals;
     194                 :     5488936 :   class ipa_call_summary *es = ipa_call_summaries->get (edge);
     195                 :     5488936 :   int min_size = -1;
     196                 :             : 
     197                 :     5488936 :   callee = edge->callee->ultimate_alias_target ();
     198                 :             : 
     199                 :     5488936 :   gcc_checking_assert (edge->inline_failed);
     200                 :     5488936 :   evaluate_properties_for_edge (edge, true, &clause, &nonspec_clause,
     201                 :             :                                 &avals, true);
     202                 :     5488936 :   ipa_call_context ctx (callee, clause, nonspec_clause, es->param, &avals);
     203                 :     5488936 :   if (node_context_cache != NULL)
     204                 :             :     {
     205                 :     5485124 :       node_context_summary *e = node_context_cache->get_create (callee);
     206                 :     5485124 :       if (e->entry.ctx.equal_to (ctx))
     207                 :             :         {
     208                 :     3861122 :           node_context_cache_hit++;
     209                 :     3861122 :           size = e->entry.size;
     210                 :     3861122 :           time = e->entry.time;
     211                 :     3861122 :           nonspec_time = e->entry.nonspec_time;
     212                 :     3861122 :           hints = e->entry.hints;
     213                 :     3861122 :           if (flag_checking
     214                 :     3861122 :               && !opt_for_fn (callee->decl, flag_profile_partial_training)
     215                 :     7722244 :               && !callee->count.ipa_p ())
     216                 :             :             {
     217                 :     3827223 :               ipa_call_estimates chk_estimates;
     218                 :     3827223 :               ctx.estimate_size_and_time (&chk_estimates);
     219                 :    11481669 :               gcc_assert (chk_estimates.size == size
     220                 :             :                           && chk_estimates.time == time
     221                 :             :                           && chk_estimates.nonspecialized_time == nonspec_time
     222                 :             :                           && chk_estimates.hints == hints);
     223                 :             :             }
     224                 :             :         }
     225                 :             :       else
     226                 :             :         {
     227                 :     1624002 :           if (e->entry.ctx.exists_p ())
     228                 :      613149 :             node_context_cache_miss++;
     229                 :             :           else
     230                 :     1010853 :             node_context_cache_clear++;
     231                 :     1624002 :           e->entry.ctx.release ();
     232                 :     1624002 :           ipa_call_estimates estimates;
     233                 :     1624002 :           ctx.estimate_size_and_time (&estimates);
     234                 :     1624002 :           size = estimates.size;
     235                 :     1624002 :           e->entry.size = size;
     236                 :     1624002 :           time = estimates.time;
     237                 :     1624002 :           e->entry.time = time;
     238                 :     1624002 :           nonspec_time = estimates.nonspecialized_time;
     239                 :     1624002 :           e->entry.nonspec_time = nonspec_time;
     240                 :     1624002 :           hints = estimates.hints;
     241                 :     1624002 :           e->entry.hints = hints;
     242                 :     1624002 :           e->entry.ctx.duplicate_from (ctx);
     243                 :             :         }
     244                 :             :     }
     245                 :             :   else
     246                 :             :     {
     247                 :        3812 :       ipa_call_estimates estimates;
     248                 :        3812 :       ctx.estimate_size_and_time (&estimates);
     249                 :        3812 :       size = estimates.size;
     250                 :        3812 :       time = estimates.time;
     251                 :        3812 :       nonspec_time = estimates.nonspecialized_time;
     252                 :        3812 :       hints = estimates.hints;
     253                 :             :     }
     254                 :             : 
     255                 :             :   /* When we have profile feedback or function attribute, we can quite safely
     256                 :             :      identify hot edges and for those we disable size limits.  Don't do that
     257                 :             :      when probability that caller will call the callee is low however, since it
     258                 :             :      may hurt optimization of the caller's hot path.  */
     259                 :     5488936 :   if ((edge->count.ipa ().initialized_p () && edge->maybe_hot_p ()
     260                 :         254 :       && (edge->count.ipa () * 2
     261                 :         127 :           > (edge->caller->inlined_to
     262                 :     5488949 :              ? edge->caller->inlined_to->count.ipa ()
     263                 :         100 :              : edge->caller->count.ipa ())))
     264                 :     5754790 :       || (lookup_attribute ("hot", DECL_ATTRIBUTES (edge->caller->decl))
     265                 :             :           != NULL
     266                 :           2 :          && lookup_attribute ("hot", DECL_ATTRIBUTES (edge->callee->decl))
     267                 :             :           != NULL))
     268                 :         114 :     hints |= INLINE_HINT_known_hot;
     269                 :             : 
     270                 :     5488936 :   gcc_checking_assert (size >= 0);
     271                 :     5488936 :   gcc_checking_assert (time >= 0);
     272                 :             : 
     273                 :             :   /* When caching, update the cache entry.  */
     274                 :     5488936 :   if (edge_growth_cache != NULL)
     275                 :             :     {
     276                 :     5485124 :       if (min_size >= 0)
     277                 :             :         ipa_fn_summaries->get (edge->callee->function_symbol ())->min_size
     278                 :             :            = min_size;
     279                 :     5485124 :       edge_growth_cache_entry *entry
     280                 :     5485124 :         = edge_growth_cache->get_create (edge);
     281                 :     5485124 :       entry->time = time;
     282                 :     5485124 :       entry->nonspec_time = nonspec_time;
     283                 :             : 
     284                 :     5485124 :       entry->size = size + (size >= 0);
     285                 :     5485124 :       hints |= simple_edge_hints (edge);
     286                 :     5485124 :       entry->hints = hints + 1;
     287                 :             :     }
     288                 :     5488936 :   if (ret_nonspec_time)
     289                 :       86467 :     *ret_nonspec_time = nonspec_time;
     290                 :    10977872 :   return time;
     291                 :     5488936 : }
     292                 :             : 
     293                 :             : /* Reset cache for NODE.
     294                 :             :    This must be done each time NODE body is modified.  */
     295                 :             : void
     296                 :     2707283 : reset_node_cache (struct cgraph_node *node)
     297                 :             : {
     298                 :     2707283 :   if (node_context_cache)
     299                 :     2707203 :     node_context_cache->remove (node);
     300                 :     2707283 : }
     301                 :             : 
     302                 :             : /* Remove EDGE from caches once it was inlined.  */
     303                 :             : void
     304                 :     3339302 : ipa_remove_from_growth_caches (struct cgraph_edge *edge)
     305                 :             : {
     306                 :     3339302 :   if (node_context_cache)
     307                 :      752287 :     node_context_cache->remove (edge->callee);
     308                 :     3339302 :   if (edge_growth_cache)
     309                 :      752287 :     edge_growth_cache->remove (edge);
     310                 :     3339302 : }
     311                 :             : 
     312                 :             : /* Return estimated callee growth after inlining EDGE.
     313                 :             :    Only to be called via estimate_edge_size.  */
     314                 :             : 
     315                 :             : int
     316                 :    15832326 : do_estimate_edge_size (struct cgraph_edge *edge)
     317                 :             : {
     318                 :    15832326 :   int size;
     319                 :    15832326 :   struct cgraph_node *callee;
     320                 :    15832326 :   clause_t clause, nonspec_clause;
     321                 :             : 
     322                 :             :   /* When we do caching, use do_estimate_edge_time to populate the entry.  */
     323                 :             : 
     324                 :    15832326 :   if (edge_growth_cache != NULL)
     325                 :             :     {
     326                 :     5361015 :       do_estimate_edge_time (edge);
     327                 :     5361015 :       size = edge_growth_cache->get (edge)->size;
     328                 :     5361015 :       gcc_checking_assert (size);
     329                 :     5361015 :       return size - (size > 0);
     330                 :             :     }
     331                 :             : 
     332                 :    10471311 :   callee = edge->callee->ultimate_alias_target ();
     333                 :             : 
     334                 :             :   /* Early inliner runs without caching, go ahead and do the dirty work.  */
     335                 :    10471311 :   gcc_checking_assert (edge->inline_failed);
     336                 :    10471311 :   ipa_auto_call_arg_values avals;
     337                 :    10471311 :   evaluate_properties_for_edge (edge, true, &clause, &nonspec_clause,
     338                 :             :                                 &avals, true);
     339                 :    10471311 :   ipa_call_context ctx (callee, clause, nonspec_clause, vNULL, &avals);
     340                 :    10471311 :   ipa_call_estimates estimates;
     341                 :    10471311 :   ctx.estimate_size_and_time (&estimates, false, false);
     342                 :    10471311 :   return estimates.size;
     343                 :    10471311 : }
     344                 :             : 
     345                 :             : 
     346                 :             : /* Estimate the growth of the caller when inlining EDGE.
     347                 :             :    Only to be called via estimate_edge_size.  */
     348                 :             : 
     349                 :             : ipa_hints
     350                 :           0 : do_estimate_edge_hints (struct cgraph_edge *edge)
     351                 :             : {
     352                 :           0 :   struct cgraph_node *callee;
     353                 :           0 :   clause_t clause, nonspec_clause;
     354                 :             : 
     355                 :             :   /* When we do caching, use do_estimate_edge_time to populate the entry.  */
     356                 :             : 
     357                 :           0 :   if (edge_growth_cache != NULL)
     358                 :             :     {
     359                 :           0 :       do_estimate_edge_time (edge);
     360                 :           0 :       ipa_hints hints = edge_growth_cache->get (edge)->hints;
     361                 :           0 :       gcc_checking_assert (hints);
     362                 :           0 :       return hints - 1;
     363                 :             :     }
     364                 :             : 
     365                 :           0 :   callee = edge->callee->ultimate_alias_target ();
     366                 :             : 
     367                 :             :   /* Early inliner runs without caching, go ahead and do the dirty work.  */
     368                 :           0 :   gcc_checking_assert (edge->inline_failed);
     369                 :           0 :   ipa_auto_call_arg_values avals;
     370                 :           0 :   evaluate_properties_for_edge (edge, true, &clause, &nonspec_clause,
     371                 :             :                                 &avals, true);
     372                 :           0 :   ipa_call_context ctx (callee, clause, nonspec_clause, vNULL, &avals);
     373                 :           0 :   ipa_call_estimates estimates;
     374                 :           0 :   ctx.estimate_size_and_time (&estimates, false, true);
     375                 :           0 :   ipa_hints hints = estimates.hints | simple_edge_hints (edge);
     376                 :           0 :   return hints;
     377                 :           0 : }
     378                 :             : 
     379                 :             : /* Estimate the size of NODE after inlining EDGE which should be an
     380                 :             :    edge to either NODE or a call inlined into NODE.  */
     381                 :             : 
     382                 :             : int
     383                 :     5504052 : estimate_size_after_inlining (struct cgraph_node *node,
     384                 :             :                               struct cgraph_edge *edge)
     385                 :             : {
     386                 :     5504052 :   class ipa_call_summary *es = ipa_call_summaries->get (edge);
     387                 :     5504052 :   ipa_size_summary *s = ipa_size_summaries->get (node);
     388                 :     5504052 :   if (!es->predicate || *es->predicate != false)
     389                 :             :     {
     390                 :     5504052 :       int size = s->size + estimate_edge_growth (edge);
     391                 :     5504052 :       gcc_assert (size >= 0);
     392                 :             :       return size;
     393                 :             :     }
     394                 :           0 :   return s->size;
     395                 :             : }
     396                 :             : 
     397                 :             : 
     398                 :             : struct growth_data
     399                 :             : {
     400                 :             :   struct cgraph_node *node;
     401                 :             :   bool self_recursive;
     402                 :             :   bool uninlinable;
     403                 :             :   int growth;
     404                 :             :   int cap;
     405                 :             : };
     406                 :             : 
     407                 :             : 
     408                 :             : /* Worker for do_estimate_growth.  Collect growth for all callers.  */
     409                 :             : 
     410                 :             : static bool
     411                 :     1723725 : do_estimate_growth_1 (struct cgraph_node *node, void *data)
     412                 :             : {
     413                 :     1723725 :   struct cgraph_edge *e;
     414                 :     1723725 :   struct growth_data *d = (struct growth_data *) data;
     415                 :             : 
     416                 :     3850233 :   for (e = node->callers; e; e = e->next_caller)
     417                 :             :     {
     418                 :     2213779 :       gcc_checking_assert (e->inline_failed);
     419                 :             : 
     420                 :     2213779 :       if (cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR
     421                 :     2213779 :           || !opt_for_fn (e->caller->decl, optimize))
     422                 :             :         {
     423                 :         288 :           d->uninlinable = true;
     424                 :         288 :           if (d->cap < INT_MAX)
     425                 :             :             return true;
     426                 :         288 :           continue;
     427                 :             :         }
     428                 :             : 
     429                 :     2213491 :       if (e->recursive_p ())
     430                 :             :         {
     431                 :        9664 :           d->self_recursive = true;
     432                 :        9664 :           if (d->cap < INT_MAX)
     433                 :             :             return true;
     434                 :        8336 :           continue;
     435                 :             :         }
     436                 :     2203827 :       d->growth += estimate_edge_growth (e);
     437                 :     2203827 :       if (d->growth > d->cap)
     438                 :             :         return true;
     439                 :             :     }
     440                 :             :   return false;
     441                 :             : }
     442                 :             : 
     443                 :             : /* Return estimated savings for eliminating offline copy of NODE by inlining
     444                 :             :    it everywhere.  */
     445                 :             : 
     446                 :             : static int
     447                 :     3275540 : offline_size (struct cgraph_node *node, ipa_size_summary *info)
     448                 :             : {
     449                 :     3275540 :   if (!DECL_EXTERNAL (node->decl))
     450                 :             :     {
     451                 :     3156011 :       if (node->will_be_removed_from_program_if_no_direct_calls_p ())
     452                 :      966320 :         return info->size;
     453                 :             :       /* COMDAT functions are very often not shared across multiple units
     454                 :             :          since they come from various template instantiations.
     455                 :             :          Take this into account.  */
     456                 :     2189691 :       else if (DECL_COMDAT (node->decl)
     457                 :     2189691 :                && node->can_remove_if_no_direct_calls_p ())
     458                 :             :         {
     459                 :      538001 :           int prob = opt_for_fn (node->decl, param_comdat_sharing_probability);
     460                 :      538001 :           return (info->size * (100 - prob) + 50) / 100;
     461                 :             :         }
     462                 :             :     }
     463                 :             :   return 0;
     464                 :             : }
     465                 :             : 
     466                 :             : /* Estimate the growth caused by inlining NODE into all callers.  */
     467                 :             : 
     468                 :             : int
     469                 :     1329566 : estimate_growth (struct cgraph_node *node)
     470                 :             : {
     471                 :     1329566 :   struct growth_data d = { node, false, false, 0, INT_MAX };
     472                 :     1329566 :   ipa_size_summary *info = ipa_size_summaries->get (node);
     473                 :             : 
     474                 :     1329566 :   if (node->call_for_symbol_and_aliases (do_estimate_growth_1, &d, true))
     475                 :             :     return 1;
     476                 :             : 
     477                 :             :   /* For self recursive functions the growth estimation really should be
     478                 :             :      infinity.  We don't want to return very large values because the growth
     479                 :             :      plays various roles in badness computation fractions.  Be sure to not
     480                 :             :      return zero or negative growths. */
     481                 :     1329566 :   if (d.self_recursive)
     482                 :        4144 :     d.growth = d.growth < info->size ? info->size : d.growth;
     483                 :     1325422 :   else if (!d.uninlinable)
     484                 :     1325231 :     d.growth -= offline_size (node, info);
     485                 :             : 
     486                 :     1329566 :   return d.growth;
     487                 :             : }
     488                 :             : 
     489                 :             : /* Verify if there are fewer than MAX_CALLERS.  */
     490                 :             : 
     491                 :             : static bool
     492                 :      103784 : check_callers (cgraph_node *node, int *growth, int *n, int offline,
     493                 :             :                int min_size, struct cgraph_edge *known_edge)
     494                 :             : {
     495                 :      103784 :   ipa_ref *ref;
     496                 :             : 
     497                 :      103784 :   if (!node->can_remove_if_no_direct_calls_and_refs_p ())
     498                 :             :     return true;
     499                 :             : 
     500                 :      160606 :   for (cgraph_edge *e = node->callers; e; e = e->next_caller)
     501                 :             :     {
     502                 :      132902 :       edge_growth_cache_entry *entry;
     503                 :             : 
     504                 :      132902 :       if (e == known_edge)
     505                 :       26593 :         continue;
     506                 :      106309 :       if (cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR)
     507                 :             :         return true;
     508                 :      103652 :       if (edge_growth_cache != NULL
     509                 :       77994 :           && (entry = edge_growth_cache->get (e)) != NULL
     510                 :      163075 :           && entry->size != 0)
     511                 :       59423 :         *growth += entry->size - (entry->size > 0);
     512                 :             :       else
     513                 :             :         {
     514                 :       44229 :           class ipa_call_summary *es = ipa_call_summaries->get (e);
     515                 :       44229 :           if (!es)
     516                 :             :             return true;
     517                 :       44225 :           *growth += min_size - es->call_stmt_size;
     518                 :       44225 :           if (--(*n) < 0)
     519                 :             :             return false;
     520                 :             :         }
     521                 :      103358 :       if (*growth > offline)
     522                 :             :         return true;
     523                 :             :     }
     524                 :             : 
     525                 :       27704 :   if (*n > 0)
     526                 :       27692 :     FOR_EACH_ALIAS (node, ref)
     527                 :          68 :       if (check_callers (dyn_cast <cgraph_node *> (ref->referring), growth, n,
     528                 :             :                          offline, min_size, known_edge))
     529                 :             :         return true;
     530                 :             : 
     531                 :             :   return false;
     532                 :             : }
     533                 :             : 
     534                 :             : 
     535                 :             : /* Decide if growth of NODE is positive.  This is cheaper than calculating
     536                 :             :    actual growth.  If edge growth of KNOWN_EDGE is known
     537                 :             :    it is passed by EDGE_GROWTH.  */
     538                 :             : 
     539                 :             : bool
     540                 :     1950309 : growth_positive_p (struct cgraph_node *node,
     541                 :             :                    struct cgraph_edge * known_edge, int edge_growth)
     542                 :             : {
     543                 :     1950309 :   struct cgraph_edge *e;
     544                 :             : 
     545                 :     1950309 :   ipa_size_summary *s = ipa_size_summaries->get (node);
     546                 :             : 
     547                 :             :   /* First quickly check if NODE is removable at all.  */
     548                 :     1950309 :   int offline = offline_size (node, s);
     549                 :     1950309 :   if (offline <= 0 && known_edge && edge_growth > 0)
     550                 :             :     return true;
     551                 :             : 
     552                 :     1464785 :   int min_size = ipa_fn_summaries->get (node)->min_size;
     553                 :     1464785 :   int n = 10;
     554                 :             : 
     555                 :     1464785 :   int min_growth = known_edge ? edge_growth : 0;
     556                 :     2390201 :   for (e = node->callers; e; e = e->next_caller)
     557                 :             :     {
     558                 :     2022937 :       edge_growth_cache_entry *entry;
     559                 :             : 
     560                 :     2022937 :       if (cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR)
     561                 :             :         return true;
     562                 :     1601971 :       if (e == known_edge)
     563                 :      258092 :         continue;
     564                 :     1343879 :       if (edge_growth_cache != NULL
     565                 :      807240 :           && (entry = edge_growth_cache->get (e)) != NULL
     566                 :     2041205 :           && entry->size != 0)
     567                 :      697326 :         min_growth += entry->size - (entry->size > 0);
     568                 :             :       else
     569                 :             :         {
     570                 :      646553 :           class ipa_call_summary *es = ipa_call_summaries->get (e);
     571                 :      646553 :           if (!es)
     572                 :             :             return true;
     573                 :      646420 :           min_growth += min_size - es->call_stmt_size;
     574                 :      646420 :           if (--n <= 0)
     575                 :             :             break;
     576                 :             :         }
     577                 :     1334080 :       if (min_growth > offline)
     578                 :             :         return true;
     579                 :             :     }
     580                 :             : 
     581                 :      376930 :   ipa_ref *ref;
     582                 :      376930 :   if (n > 0)
     583                 :      395224 :     FOR_EACH_ALIAS (node, ref)
     584                 :      207500 :       if (check_callers (dyn_cast <cgraph_node *> (ref->referring),
     585                 :             :                          &min_growth, &n, offline, min_size, known_edge))
     586                 :             :         return true;
     587                 :             : 
     588                 :      301140 :   struct growth_data d = { node, false, false, 0, offline };
     589                 :      301140 :   if (node->call_for_symbol_and_aliases (do_estimate_growth_1, &d, true))
     590                 :             :     return true;
     591                 :      213869 :   if (d.self_recursive || d.uninlinable)
     592                 :             :     return true;
     593                 :      213869 :   return (d.growth > offline);
     594                 :             : }
        

Generated by: LCOV version 2.1-beta

LCOV profile is generated on x86_64 machine using following configure options: configure --disable-bootstrap --enable-coverage=opt --enable-languages=c,c++,fortran,go,jit,lto,rust,m2 --enable-host-shared. GCC test suite is run with the built compiler.