LCOV - code coverage report
Current view: top level - gcc - ipa-inline-analysis.c (source / functions) Hit Total Coverage
Test: gcc.info Lines: 233 256 91.0 %
Date: 2020-03-28 11:57:23 Functions: 14 15 93.3 %
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-2020 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 "ipa-prop.h"
      44                 :            : #include "ipa-fnsummary.h"
      45                 :            : #include "ipa-inline.h"
      46                 :            : #include "cfgloop.h"
      47                 :            : #include "tree-scalar-evolution.h"
      48                 :            : #include "ipa-utils.h"
      49                 :            : #include "cfgexpand.h"
      50                 :            : #include "gimplify.h"
      51                 :            : 
      52                 :            : /* Cached node/edge growths.  */
      53                 :            : fast_call_summary<edge_growth_cache_entry *, va_heap> *edge_growth_cache = NULL;
      54                 :            : 
      55                 :            : /* The context cache remembers estimated time/size and hints for given
      56                 :            :    ipa_call_context of a call.  */
      57                 :            : class node_context_cache_entry
      58                 :            : {
      59                 :            : public:
      60                 :            :   ipa_call_context ctx;
      61                 :            :   sreal time, nonspec_time;
      62                 :            :   int size;
      63                 :            :   ipa_hints hints;
      64                 :            : 
      65                 :     648521 :   node_context_cache_entry ()
      66                 :     648521 :   : ctx ()
      67                 :            :   {
      68                 :            :   }
      69                 :     648521 :   ~node_context_cache_entry ()
      70                 :            :   {
      71                 :     648521 :     ctx.release ();
      72                 :            :   }
      73                 :            : };
      74                 :            : 
      75                 :            : /* At the moment we implement primitive single entry LRU cache.  */
      76                 :            : class node_context_summary
      77                 :            : {
      78                 :            : public:
      79                 :            :   node_context_cache_entry entry;
      80                 :            : 
      81                 :     648521 :   node_context_summary ()
      82                 :     648521 :   : entry ()
      83                 :            :   {
      84                 :            :   }
      85                 :     648521 :   ~node_context_summary ()
      86                 :     648521 :   {
      87                 :            :   }
      88                 :            : };
      89                 :            : 
      90                 :            : /* Summary holding the context cache.  */
      91                 :            : static fast_function_summary <node_context_summary *, va_heap>
      92                 :            :         *node_context_cache = NULL;
      93                 :            : /* Statistics about the context cache effectivity.  */
      94                 :            : static long node_context_cache_hit, node_context_cache_miss,
      95                 :            :             node_context_cache_clear;
      96                 :            : 
      97                 :            : /* Give initial reasons why inlining would fail on EDGE.  This gets either
      98                 :            :    nullified or usually overwritten by more precise reasons later.  */
      99                 :            : 
     100                 :            : void
     101                 :   24217300 : initialize_inline_failed (struct cgraph_edge *e)
     102                 :            : {
     103                 :   24217300 :   struct cgraph_node *callee = e->callee;
     104                 :            : 
     105                 :   24217300 :   if (e->inline_failed && e->inline_failed != CIF_BODY_NOT_AVAILABLE
     106                 :   24217300 :       && cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR)
     107                 :            :     ;
     108                 :   24204600 :   else if (e->indirect_unknown_callee)
     109                 :     574980 :     e->inline_failed = CIF_INDIRECT_UNKNOWN_CALL;
     110                 :   23629600 :   else if (!callee->definition)
     111                 :   12979300 :     e->inline_failed = CIF_BODY_NOT_AVAILABLE;
     112                 :   10650300 :   else if (callee->redefined_extern_inline)
     113                 :        270 :     e->inline_failed = CIF_REDEFINED_EXTERN_INLINE;
     114                 :            :   else
     115                 :   10650000 :     e->inline_failed = CIF_FUNCTION_NOT_CONSIDERED;
     116                 :   24217300 :   gcc_checking_assert (!e->call_stmt_cannot_inline_p
     117                 :            :                        || cgraph_inline_failed_type (e->inline_failed)
     118                 :            :                             == CIF_FINAL_ERROR);
     119                 :   24217300 : }
     120                 :            : 
     121                 :            : /* Allocate edge growth caches.  */
     122                 :            : 
     123                 :            : void
     124                 :     163508 : initialize_growth_caches ()
     125                 :            : {
     126                 :     163508 :   edge_growth_cache
     127                 :     163508 :     = new fast_call_summary<edge_growth_cache_entry *, va_heap> (symtab);
     128                 :     163508 :   node_context_cache
     129                 :     163508 :     = new fast_function_summary<node_context_summary *, va_heap> (symtab);
     130                 :     163508 : }
     131                 :            : 
     132                 :            : /* Free growth caches.  */
     133                 :            : 
     134                 :            : void
     135                 :     163508 : free_growth_caches (void)
     136                 :            : {
     137                 :     163508 :   delete edge_growth_cache;
     138                 :     163508 :   delete node_context_cache;
     139                 :     163508 :   edge_growth_cache = NULL;
     140                 :     163508 :   node_context_cache = NULL;
     141                 :     163508 :   if (dump_file)
     142                 :        192 :     fprintf (dump_file, "node context cache: %li hits, %li misses,"
     143                 :            :                         " %li initializations\n",
     144                 :            :              node_context_cache_hit, node_context_cache_miss,
     145                 :            :              node_context_cache_clear);
     146                 :     163508 :   node_context_cache_hit = 0;
     147                 :     163508 :   node_context_cache_miss = 0;
     148                 :     163508 :   node_context_cache_clear = 0;
     149                 :     163508 : }
     150                 :            : 
     151                 :            : /* Return hints derived from EDGE.   */
     152                 :            : 
     153                 :            : int
     154                 :    2273340 : simple_edge_hints (struct cgraph_edge *edge)
     155                 :            : {
     156                 :    2273340 :   int hints = 0;
     157                 :    4546670 :   struct cgraph_node *to = (edge->caller->inlined_to
     158                 :    2273340 :                             ? edge->caller->inlined_to : edge->caller);
     159                 :    2273340 :   struct cgraph_node *callee = edge->callee->ultimate_alias_target ();
     160                 :    2273340 :   int to_scc_no = ipa_fn_summaries->get (to)->scc_no;
     161                 :    2273340 :   int callee_scc_no = ipa_fn_summaries->get (callee)->scc_no;
     162                 :            : 
     163                 :    2273340 :   if (to_scc_no && to_scc_no  == callee_scc_no && !edge->recursive_p ())
     164                 :            :     hints |= INLINE_HINT_same_scc;
     165                 :            : 
     166                 :    2273340 :   if (cross_module_call_p (edge))
     167                 :       3417 :     hints |= INLINE_HINT_cross_module;
     168                 :            : 
     169                 :    2273340 :   return hints;
     170                 :            : }
     171                 :            : 
     172                 :            : /* Estimate the time cost for the caller when inlining EDGE.
     173                 :            :    Only to be called via estimate_edge_time, that handles the
     174                 :            :    caching mechanism.
     175                 :            : 
     176                 :            :    When caching, also update the cache entry.  Compute both time and
     177                 :            :    size, since we always need both metrics eventually.  */
     178                 :            : 
     179                 :            : sreal
     180                 :    2276650 : do_estimate_edge_time (struct cgraph_edge *edge, sreal *ret_nonspec_time)
     181                 :            : {
     182                 :    2276650 :   sreal time, nonspec_time;
     183                 :    2276650 :   int size;
     184                 :    2276650 :   ipa_hints hints;
     185                 :    2276650 :   struct cgraph_node *callee;
     186                 :    2276650 :   clause_t clause, nonspec_clause;
     187                 :    2276650 :   auto_vec<tree, 32> known_vals;
     188                 :    4553290 :   auto_vec<ipa_polymorphic_call_context, 32> known_contexts;
     189                 :    4553290 :   auto_vec<ipa_agg_value_set, 32> known_aggs;
     190                 :    2276650 :   class ipa_call_summary *es = ipa_call_summaries->get (edge);
     191                 :    2276650 :   int min_size = -1;
     192                 :            : 
     193                 :    2276650 :   callee = edge->callee->ultimate_alias_target ();
     194                 :            : 
     195                 :    2276650 :   gcc_checking_assert (edge->inline_failed);
     196                 :    2276650 :   evaluate_properties_for_edge (edge, true,
     197                 :            :                                 &clause, &nonspec_clause, &known_vals,
     198                 :            :                                 &known_contexts, &known_aggs);
     199                 :    2276650 :   ipa_call_context ctx (callee, clause, nonspec_clause, known_vals,
     200                 :    2276650 :                         known_contexts, known_aggs, es->param);
     201                 :    2276650 :   if (node_context_cache != NULL)
     202                 :            :     {
     203                 :    2273340 :       node_context_summary *e = node_context_cache->get_create (callee);
     204                 :    2273340 :       if (e->entry.ctx.equal_to (ctx))
     205                 :            :         {
     206                 :    1746800 :           node_context_cache_hit++;
     207                 :    1746800 :           size = e->entry.size;
     208                 :    1746800 :           time = e->entry.time;
     209                 :    1746800 :           nonspec_time = e->entry.nonspec_time;
     210                 :    1746800 :           hints = e->entry.hints;
     211                 :    1746800 :           if (flag_checking
     212                 :    1746800 :               && !opt_for_fn (callee->decl, flag_profile_partial_training)
     213                 :    3493610 :               && !callee->count.ipa_p ())
     214                 :            :             {
     215                 :    1731240 :               sreal chk_time, chk_nonspec_time;
     216                 :    1731240 :               int chk_size, chk_min_size;
     217                 :            : 
     218                 :    1731240 :               ipa_hints chk_hints;
     219                 :    1731240 :               ctx.estimate_size_and_time (&chk_size, &chk_min_size,
     220                 :            :                                           &chk_time, &chk_nonspec_time,
     221                 :            :                                           &chk_hints);
     222                 :    5193700 :               gcc_assert (chk_size == size && chk_time == time
     223                 :            :                           && chk_nonspec_time == nonspec_time
     224                 :            :                           && chk_hints == hints);
     225                 :            :             }
     226                 :            :         }
     227                 :            :       else
     228                 :            :         {
     229                 :     526534 :           if (e->entry.ctx.exists_p ())
     230                 :     164769 :             node_context_cache_miss++;
     231                 :            :           else
     232                 :     361765 :             node_context_cache_clear++;
     233                 :     526534 :           e->entry.ctx.release (true);
     234                 :     526534 :           ctx.estimate_size_and_time (&size, &min_size,
     235                 :            :                                       &time, &nonspec_time, &hints);
     236                 :     526534 :           e->entry.size = size;
     237                 :     526534 :           e->entry.time = time;
     238                 :     526534 :           e->entry.nonspec_time = nonspec_time;
     239                 :     526534 :           e->entry.hints = hints;
     240                 :     526534 :           e->entry.ctx.duplicate_from (ctx);
     241                 :            :         }
     242                 :            :     }
     243                 :            :   else
     244                 :       3309 :     ctx.estimate_size_and_time (&size, &min_size,
     245                 :            :                                 &time, &nonspec_time, &hints);
     246                 :            : 
     247                 :            :   /* When we have profile feedback, we can quite safely identify hot
     248                 :            :      edges and for those we disable size limits.  Don't do that when
     249                 :            :      probability that caller will call the callee is low however, since it
     250                 :            :      may hurt optimization of the caller's hot path.  */
     251                 :    2276650 :   if (edge->count.ipa ().initialized_p () && edge->maybe_hot_p ()
     252                 :    2276890 :       && (edge->count.ipa ().apply_scale (2, 1)
     253                 :        124 :           > (edge->caller->inlined_to
     254                 :    2276650 :              ? edge->caller->inlined_to->count.ipa ()
     255                 :         72 :              : edge->caller->count.ipa ())))
     256                 :        124 :     hints |= INLINE_HINT_known_hot;
     257                 :            : 
     258                 :    2276650 :   ctx.release ();
     259                 :    2276650 :   gcc_checking_assert (size >= 0);
     260                 :    2276650 :   gcc_checking_assert (time >= 0);
     261                 :            : 
     262                 :            :   /* When caching, update the cache entry.  */
     263                 :    2276650 :   if (edge_growth_cache != NULL)
     264                 :            :     {
     265                 :    2273340 :       if (min_size >= 0)
     266                 :     526534 :         ipa_fn_summaries->get (edge->callee->function_symbol ())->min_size
     267                 :     526534 :            = min_size;
     268                 :    2273340 :       edge_growth_cache_entry *entry
     269                 :    2273340 :         = edge_growth_cache->get_create (edge);
     270                 :    2273340 :       entry->time = time;
     271                 :    2273340 :       entry->nonspec_time = nonspec_time;
     272                 :            : 
     273                 :    2273340 :       entry->size = size + (size >= 0);
     274                 :    2273340 :       hints |= simple_edge_hints (edge);
     275                 :    2273340 :       entry->hints = hints + 1;
     276                 :            :     }
     277                 :    2276650 :   if (ret_nonspec_time)
     278                 :      55082 :     *ret_nonspec_time = nonspec_time;
     279                 :    2276650 :   return time;
     280                 :            : }
     281                 :            : 
     282                 :            : /* Reset cache for NODE.
     283                 :            :    This must be done each time NODE body is modified.  */
     284                 :            : void
     285                 :    1410640 : reset_node_cache (struct cgraph_node *node)
     286                 :            : {
     287                 :    1410640 :   if (node_context_cache)
     288                 :    1410500 :     node_context_cache->remove (node);
     289                 :    1410640 : }
     290                 :            : 
     291                 :            : /* Remove EDGE from caches once it was inlined.  */
     292                 :            : void
     293                 :    2283700 : ipa_remove_from_growth_caches (struct cgraph_edge *edge)
     294                 :            : {
     295                 :    2283700 :   if (node_context_cache)
     296                 :     438738 :     node_context_cache->remove (edge->callee);
     297                 :    2283700 :   if (edge_growth_cache)
     298                 :     438738 :     edge_growth_cache->remove (edge);
     299                 :    2283700 : }
     300                 :            : 
     301                 :            : /* Return estimated callee growth after inlining EDGE.
     302                 :            :    Only to be called via estimate_edge_size.  */
     303                 :            : 
     304                 :            : int
     305                 :    9678500 : do_estimate_edge_size (struct cgraph_edge *edge)
     306                 :            : {
     307                 :    9678500 :   int size;
     308                 :    9678500 :   struct cgraph_node *callee;
     309                 :    9678500 :   clause_t clause, nonspec_clause;
     310                 :    9678500 :   auto_vec<tree, 32> known_vals;
     311                 :   19357000 :   auto_vec<ipa_polymorphic_call_context, 32> known_contexts;
     312                 :   19357000 :   auto_vec<ipa_agg_value_set, 32> known_aggs;
     313                 :            : 
     314                 :            :   /* When we do caching, use do_estimate_edge_time to populate the entry.  */
     315                 :            : 
     316                 :    9678500 :   if (edge_growth_cache != NULL)
     317                 :            :     {
     318                 :    2198330 :       do_estimate_edge_time (edge);
     319                 :    2198330 :       size = edge_growth_cache->get (edge)->size;
     320                 :    2198330 :       gcc_checking_assert (size);
     321                 :    2198330 :       return size - (size > 0);
     322                 :            :     }
     323                 :            : 
     324                 :    7480170 :   callee = edge->callee->ultimate_alias_target ();
     325                 :            : 
     326                 :            :   /* Early inliner runs without caching, go ahead and do the dirty work.  */
     327                 :    7480170 :   gcc_checking_assert (edge->inline_failed);
     328                 :    7480170 :   evaluate_properties_for_edge (edge, true,
     329                 :            :                                 &clause, &nonspec_clause,
     330                 :            :                                 &known_vals, &known_contexts,
     331                 :            :                                 &known_aggs);
     332                 :    7480170 :   ipa_call_context ctx (callee, clause, nonspec_clause, known_vals,
     333                 :    7480170 :                         known_contexts, known_aggs, vNULL);
     334                 :    7480170 :   ctx.estimate_size_and_time (&size, NULL, NULL, NULL, NULL);
     335                 :    7480170 :   ctx.release ();
     336                 :    7480170 :   return size;
     337                 :            : }
     338                 :            : 
     339                 :            : 
     340                 :            : /* Estimate the growth of the caller when inlining EDGE.
     341                 :            :    Only to be called via estimate_edge_size.  */
     342                 :            : 
     343                 :            : ipa_hints
     344                 :          0 : do_estimate_edge_hints (struct cgraph_edge *edge)
     345                 :            : {
     346                 :          0 :   ipa_hints hints;
     347                 :          0 :   struct cgraph_node *callee;
     348                 :          0 :   clause_t clause, nonspec_clause;
     349                 :          0 :   auto_vec<tree, 32> known_vals;
     350                 :          0 :   auto_vec<ipa_polymorphic_call_context, 32> known_contexts;
     351                 :          0 :   auto_vec<ipa_agg_value_set, 32> known_aggs;
     352                 :            : 
     353                 :            :   /* When we do caching, use do_estimate_edge_time to populate the entry.  */
     354                 :            : 
     355                 :          0 :   if (edge_growth_cache != NULL)
     356                 :            :     {
     357                 :          0 :       do_estimate_edge_time (edge);
     358                 :          0 :       hints = edge_growth_cache->get (edge)->hints;
     359                 :          0 :       gcc_checking_assert (hints);
     360                 :          0 :       return hints - 1;
     361                 :            :     }
     362                 :            : 
     363                 :          0 :   callee = edge->callee->ultimate_alias_target ();
     364                 :            : 
     365                 :            :   /* Early inliner runs without caching, go ahead and do the dirty work.  */
     366                 :          0 :   gcc_checking_assert (edge->inline_failed);
     367                 :          0 :   evaluate_properties_for_edge (edge, true,
     368                 :            :                                 &clause, &nonspec_clause,
     369                 :            :                                 &known_vals, &known_contexts,
     370                 :            :                                 &known_aggs);
     371                 :          0 :   ipa_call_context ctx (callee, clause, nonspec_clause, known_vals,
     372                 :          0 :                         known_contexts, known_aggs, vNULL);
     373                 :          0 :   ctx.estimate_size_and_time (NULL, NULL, NULL, NULL, &hints);
     374                 :          0 :   ctx.release ();
     375                 :          0 :   hints |= simple_edge_hints (edge);
     376                 :          0 :   return hints;
     377                 :            : }
     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                 :    3657550 : estimate_size_after_inlining (struct cgraph_node *node,
     384                 :            :                               struct cgraph_edge *edge)
     385                 :            : {
     386                 :    3657550 :   class ipa_call_summary *es = ipa_call_summaries->get (edge);
     387                 :    3657550 :   ipa_size_summary *s = ipa_size_summaries->get (node);
     388                 :    3657550 :   if (!es->predicate || *es->predicate != false)
     389                 :            :     {
     390                 :    3657550 :       int size = s->size + estimate_edge_growth (edge);
     391                 :    3657550 :       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                 :    1120840 : do_estimate_growth_1 (struct cgraph_node *node, void *data)
     412                 :            : {
     413                 :    1120840 :   struct cgraph_edge *e;
     414                 :    1120840 :   struct growth_data *d = (struct growth_data *) data;
     415                 :            : 
     416                 :    2406970 :   for (e = node->callers; e; e = e->next_caller)
     417                 :            :     {
     418                 :    1331340 :       gcc_checking_assert (e->inline_failed);
     419                 :            : 
     420                 :    1331340 :       if (cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR
     421                 :    1331340 :           || !opt_for_fn (e->caller->decl, optimize))
     422                 :            :         {
     423                 :        131 :           d->uninlinable = true;
     424                 :        131 :           if (d->cap < INT_MAX)
     425                 :            :             return true;
     426                 :        131 :           continue;
     427                 :            :         }
     428                 :            : 
     429                 :    1331210 :       if (e->recursive_p ())
     430                 :            :         {
     431                 :       7703 :           d->self_recursive = true;
     432                 :       7703 :           if (d->cap < INT_MAX)
     433                 :            :             return true;
     434                 :       6636 :           continue;
     435                 :            :         }
     436                 :    1323510 :       d->growth += estimate_edge_growth (e);
     437                 :    1323510 :       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                 :    1850990 : offline_size (struct cgraph_node *node, ipa_size_summary *info)
     448                 :            : {
     449                 :    1850990 :   if (!DECL_EXTERNAL (node->decl))
     450                 :            :     {
     451                 :    1773030 :       if (node->will_be_removed_from_program_if_no_direct_calls_p ())
     452                 :     451044 :         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                 :    1321980 :       else if (DECL_COMDAT (node->decl)
     457                 :    1321980 :                && node->can_remove_if_no_direct_calls_p ())
     458                 :            :         {
     459                 :     305015 :           int prob = opt_for_fn (node->decl, param_comdat_sharing_probability);
     460                 :     305015 :           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                 :     866657 : estimate_growth (struct cgraph_node *node)
     470                 :            : {
     471                 :     866657 :   struct growth_data d = { node, false, false, 0, INT_MAX };
     472                 :     866657 :   ipa_size_summary *info = ipa_size_summaries->get (node);
     473                 :            : 
     474                 :     866657 :   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                 :     866657 :   if (d.self_recursive)
     482                 :       3386 :     d.growth = d.growth < info->size ? info->size : d.growth;
     483                 :     863271 :   else if (!d.uninlinable)
     484                 :     863151 :     d.growth -= offline_size (node, info);
     485                 :            : 
     486                 :     866657 :   return d.growth;
     487                 :            : }
     488                 :            : 
     489                 :            : /* Verify if there are fewer than MAX_CALLERS.  */
     490                 :            : 
     491                 :            : static bool
     492                 :      70701 : check_callers (cgraph_node *node, int *growth, int *n, int offline,
     493                 :            :                int min_size, struct cgraph_edge *known_edge)
     494                 :            : {
     495                 :      70701 :   ipa_ref *ref;
     496                 :            : 
     497                 :      70701 :   if (!node->can_remove_if_no_direct_calls_and_refs_p ())
     498                 :            :     return true;
     499                 :            : 
     500                 :      95470 :   for (cgraph_edge *e = node->callers; e; e = e->next_caller)
     501                 :            :     {
     502                 :      82508 :       edge_growth_cache_entry *entry;
     503                 :            : 
     504                 :      82508 :       if (e == known_edge)
     505                 :      12317 :         continue;
     506                 :      70191 :       if (cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR)
     507                 :            :         return true;
     508                 :      67749 :       if (edge_growth_cache != NULL
     509                 :      50410 :           && (entry = edge_growth_cache->get (e)) != NULL
     510                 :     111268 :           && entry->size != 0)
     511                 :      43519 :         *growth += entry->size - (entry->size > 0);
     512                 :            :       else
     513                 :            :         {
     514                 :      24230 :           class ipa_call_summary *es = ipa_call_summaries->get (e);
     515                 :      24230 :           if (!es)
     516                 :            :             return true;
     517                 :      24224 :           *growth += min_size - es->call_stmt_size;
     518                 :      24224 :           if (--(*n) < 0)
     519                 :            :             return false;
     520                 :            :         }
     521                 :      67574 :       if (*growth > offline)
     522                 :            :         return true;
     523                 :            :     }
     524                 :            : 
     525                 :      12962 :   if (*n > 0)
     526                 :      14173 :     FOR_EACH_ALIAS (node, ref)
     527                 :          0 :       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                 :     987842 : growth_positive_p (struct cgraph_node *node,
     541                 :            :                    struct cgraph_edge * known_edge, int edge_growth)
     542                 :            : {
     543                 :     987842 :   struct cgraph_edge *e;
     544                 :            : 
     545                 :     987842 :   ipa_size_summary *s = ipa_size_summaries->get (node);
     546                 :            : 
     547                 :            :   /* First quickly check if NODE is removable at all.  */
     548                 :     987842 :   int offline = offline_size (node, s);
     549                 :     987842 :   if (offline <= 0 && known_edge && edge_growth > 0)
     550                 :            :     return true;
     551                 :            : 
     552                 :     833151 :   int min_size = ipa_fn_summaries->get (node)->min_size;
     553                 :     833151 :   int n = 10;
     554                 :            : 
     555                 :     833151 :   int min_growth = known_edge ? edge_growth : 0;
     556                 :    1233750 :   for (e = node->callers; e; e = e->next_caller)
     557                 :            :     {
     558                 :     985513 :       edge_growth_cache_entry *entry;
     559                 :            : 
     560                 :     985513 :       if (cgraph_inline_failed_type (e->inline_failed) == CIF_FINAL_ERROR)
     561                 :            :         return true;
     562                 :     723391 :       if (e == known_edge)
     563                 :     140601 :         continue;
     564                 :     582790 :       if (edge_growth_cache != NULL
     565                 :     221951 :           && (entry = edge_growth_cache->get (e)) != NULL
     566                 :     735915 :           && entry->size != 0)
     567                 :     153125 :         min_growth += entry->size - (entry->size > 0);
     568                 :            :       else
     569                 :            :         {
     570                 :     429665 :           class ipa_call_summary *es = ipa_call_summaries->get (e);
     571                 :     429665 :           if (!es)
     572                 :            :             return true;
     573                 :     429607 :           min_growth += min_size - es->call_stmt_size;
     574                 :     429607 :           if (--n <= 0)
     575                 :            :             break;
     576                 :            :         }
     577                 :     579425 :       if (min_growth > offline)
     578                 :            :         return true;
     579                 :            :     }
     580                 :            : 
     581                 :     251546 :   ipa_ref *ref;
     582                 :     251546 :   if (n > 0)
     583                 :     345402 :     FOR_EACH_ALIAS (node, ref)
     584                 :     141402 :       if (check_callers (dyn_cast <cgraph_node *> (ref->referring),
     585                 :            :                          &min_growth, &n, offline, min_size, known_edge))
     586                 :            :         return true;
     587                 :            : 
     588                 :     193976 :   struct growth_data d = { node, false, false, 0, offline };
     589                 :     193976 :   if (node->call_for_symbol_and_aliases (do_estimate_growth_1, &d, true))
     590                 :            :     return true;
     591                 :     148763 :   if (d.self_recursive || d.uninlinable)
     592                 :            :     return true;
     593                 :     148763 :   return (d.growth > offline);
     594                 :            : }

Generated by: LCOV version 1.0

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 --enable-host-shared. GCC test suite is run with the built compiler.