LCOV - code coverage report
Current view: top level - gcc - ipa.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 82.2 % 697 573
Test Date: 2025-10-18 14:39:06 Functions: 83.3 % 36 30
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Basic IPA optimizations and utilities.
       2                 :             :    Copyright (C) 2003-2025 Free Software Foundation, Inc.
       3                 :             : 
       4                 :             : This file is part of GCC.
       5                 :             : 
       6                 :             : GCC is free software; you can redistribute it and/or modify it under
       7                 :             : the terms of the GNU General Public License as published by the Free
       8                 :             : Software Foundation; either version 3, or (at your option) any later
       9                 :             : version.
      10                 :             : 
      11                 :             : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      12                 :             : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13                 :             : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      14                 :             : for more details.
      15                 :             : 
      16                 :             : You should have received a copy of the GNU General Public License
      17                 :             : along with GCC; see the file COPYING3.  If not see
      18                 :             : <http://www.gnu.org/licenses/>.  */
      19                 :             : 
      20                 :             : #include "config.h"
      21                 :             : #include "system.h"
      22                 :             : #include "coretypes.h"
      23                 :             : #include "backend.h"
      24                 :             : #include "target.h"
      25                 :             : #include "tree.h"
      26                 :             : #include "gimple.h"
      27                 :             : #include "alloc-pool.h"
      28                 :             : #include "tree-pass.h"
      29                 :             : #include "stringpool.h"
      30                 :             : #include "cgraph.h"
      31                 :             : #include "gimplify.h"
      32                 :             : #include "tree-iterator.h"
      33                 :             : #include "ipa-utils.h"
      34                 :             : #include "symbol-summary.h"
      35                 :             : #include "tree-vrp.h"
      36                 :             : #include "sreal.h"
      37                 :             : #include "ipa-cp.h"
      38                 :             : #include "ipa-prop.h"
      39                 :             : #include "ipa-fnsummary.h"
      40                 :             : #include "dbgcnt.h"
      41                 :             : #include "debug.h"
      42                 :             : #include "stringpool.h"
      43                 :             : #include "attribs.h"
      44                 :             : 
      45                 :             : /* Return true when NODE has ADDR reference.  */
      46                 :             : 
      47                 :             : static bool
      48                 :     3329233 : has_addr_references_p (struct cgraph_node *node,
      49                 :             :                        void *)
      50                 :             : {
      51                 :     3329233 :   int i;
      52                 :     3329233 :   struct ipa_ref *ref = NULL;
      53                 :             : 
      54                 :     3429469 :   for (i = 0; node->iterate_referring (i, ref); i++)
      55                 :     3337636 :     if (ref->use == IPA_REF_ADDR)
      56                 :             :       return true;
      57                 :             :   return false;
      58                 :             : }
      59                 :             : 
      60                 :             : /* Return true when NODE can be target of an indirect call.  */
      61                 :             : 
      62                 :             : static bool
      63                 :         493 : is_indirect_call_target_p (struct cgraph_node *node, void *)
      64                 :             : {
      65                 :         493 :   return node->indirect_call_target;
      66                 :             : }
      67                 :             : 
      68                 :             : /* Look for all functions inlined to NODE and update their inlined_to pointers
      69                 :             :    to INLINED_TO.  */
      70                 :             : 
      71                 :             : static void
      72                 :           0 : update_inlined_to_pointer (struct cgraph_node *node, struct cgraph_node *inlined_to)
      73                 :             : {
      74                 :           0 :   struct cgraph_edge *e;
      75                 :           0 :   for (e = node->callees; e; e = e->next_callee)
      76                 :           0 :     if (e->callee->inlined_to)
      77                 :             :       {
      78                 :           0 :         e->callee->inlined_to = inlined_to;
      79                 :           0 :         update_inlined_to_pointer (e->callee, inlined_to);
      80                 :             :       }
      81                 :           0 : }
      82                 :             : 
      83                 :             : /* Add symtab NODE to queue starting at FIRST.
      84                 :             : 
      85                 :             :    The queue is linked via AUX pointers and terminated by pointer to 1.
      86                 :             :    We enqueue nodes at two occasions: when we find them reachable or when we find
      87                 :             :    their bodies needed for further clonning.  In the second case we mark them
      88                 :             :    by pointer to 2 after processing so they are re-queue when they become
      89                 :             :    reachable.  */
      90                 :             : 
      91                 :             : static void
      92                 :   143521433 : enqueue_node (symtab_node *node, symtab_node **first,
      93                 :             :               hash_set<symtab_node *> *reachable)
      94                 :             : {
      95                 :             :   /* Node is still in queue; do nothing.  */
      96                 :   143521433 :   if (node->aux && node->aux != (void *) 2)
      97                 :             :     return;
      98                 :             :   /* Node was already processed as unreachable, re-enqueue
      99                 :             :      only if it became reachable now.  */
     100                 :    79795563 :   if (node->aux == (void *)2 && !reachable->contains (node))
     101                 :             :     return;
     102                 :    50369630 :   node->aux = *first;
     103                 :    50369630 :   *first = node;
     104                 :             : }
     105                 :             : 
     106                 :             : /* Return true if NODE may get inlined later.
     107                 :             :    This is used to keep DECL_EXTERNAL function bodies around long enough
     108                 :             :    so inliner can proces them.  */
     109                 :             : 
     110                 :             : static bool
     111                 :     1376389 : possible_inline_candidate_p (symtab_node *node)
     112                 :             : {
     113                 :     1376389 :   if (symtab->state >= IPA_SSA_AFTER_INLINING)
     114                 :             :     return false;
     115                 :     1308823 :   cgraph_node *cnode = dyn_cast <cgraph_node *> (node);
     116                 :     1277848 :   if (!cnode)
     117                 :             :     return false;
     118                 :     1277848 :   if (DECL_UNINLINABLE (cnode->decl))
     119                 :             :     return false;
     120                 :     1275791 :   if (opt_for_fn (cnode->decl, optimize))
     121                 :             :     return true;
     122                 :        1530 :   if (symtab->state >= IPA_SSA)
     123                 :             :     return false;
     124                 :        1454 :   return lookup_attribute ("always_inline", DECL_ATTRIBUTES (node->decl));
     125                 :             : }
     126                 :             : 
     127                 :             : /* Process references.  */
     128                 :             : 
     129                 :             : static void
     130                 :    36758594 : process_references (symtab_node *snode,
     131                 :             :                     symtab_node **first,
     132                 :             :                     hash_set<symtab_node *> *reachable)
     133                 :             : {
     134                 :    36758594 :   int i;
     135                 :    36758594 :   struct ipa_ref *ref = NULL;
     136                 :   104569797 :   for (i = 0; snode->iterate_reference (i, ref); i++)
     137                 :             :     {
     138                 :    67811203 :       symtab_node *node = ref->referred;
     139                 :    67811203 :       symtab_node *body = node->ultimate_alias_target ();
     140                 :             : 
     141                 :    48909414 :       if (node->definition && !node->in_other_partition
     142                 :   116720520 :           && ((!DECL_EXTERNAL (node->decl) || node->alias)
     143                 :       89033 :               || (possible_inline_candidate_p (node)
     144                 :             :                   /* We use variable constructors during late compilation for
     145                 :             :                      constant folding.  Keep references alive so partitioning
     146                 :             :                      knows about potential references.  */
     147                 :       34557 :                   || (VAR_P (node->decl)
     148                 :       30975 :                       && (flag_wpa
     149                 :       30975 :                           || flag_incremental_link
     150                 :             :                                  == INCREMENTAL_LINK_LTO)
     151                 :           0 :                       && dyn_cast <varpool_node *> (node)
     152                 :           0 :                            ->ctor_useable_for_folding_p ()))))
     153                 :             :         {
     154                 :             :           /* Be sure that we will not optimize out alias target
     155                 :             :              body.  */
     156                 :    48874760 :           if (DECL_EXTERNAL (node->decl)
     157                 :       55351 :               && node->alias
     158                 :    48875635 :               && symtab->state < IPA_SSA_AFTER_INLINING)
     159                 :         725 :             reachable->add (body);
     160                 :    48874760 :           reachable->add (node);
     161                 :             :         }
     162                 :    67811203 :       enqueue_node (node, first, reachable);
     163                 :             :     }
     164                 :    36758594 : }
     165                 :             : 
     166                 :             : /* EDGE is an polymorphic call.  If BEFORE_INLINING_P is set, mark
     167                 :             :    all its potential targets as reachable to permit later inlining if
     168                 :             :    devirtualization happens.  After inlining still keep their declarations
     169                 :             :    around, so we can devirtualize to a direct call.
     170                 :             : 
     171                 :             :    Also try to make trivial devirutalization when no or only one target is
     172                 :             :    possible.  */
     173                 :             : 
     174                 :             : static void
     175                 :      199824 : walk_polymorphic_call_targets (hash_set<void *> *reachable_call_targets,
     176                 :             :                                struct cgraph_edge *edge,
     177                 :             :                                symtab_node **first,
     178                 :             :                                hash_set<symtab_node *> *reachable)
     179                 :             : {
     180                 :      199824 :   unsigned int i;
     181                 :      199824 :   void *cache_token;
     182                 :      199824 :   bool final;
     183                 :      199824 :   vec <cgraph_node *>targets
     184                 :             :     = possible_polymorphic_call_targets
     185                 :      199824 :         (edge, &final, &cache_token);
     186                 :             : 
     187                 :      199824 :   if (cache_token != NULL && !reachable_call_targets->add (cache_token))
     188                 :             :     {
     189                 :      245369 :       for (i = 0; i < targets.length (); i++)
     190                 :             :         {
     191                 :      150471 :           struct cgraph_node *n = targets[i];
     192                 :             : 
     193                 :             :           /* Do not bother to mark virtual methods in anonymous namespace;
     194                 :             :              either we will find use of virtual table defining it, or it is
     195                 :             :              unused.  */
     196                 :      150471 :           if (TREE_CODE (TREE_TYPE (n->decl)) == METHOD_TYPE
     197                 :      294544 :               && type_in_anonymous_namespace_p
     198                 :      144073 :                     (TYPE_METHOD_BASETYPE (TREE_TYPE (n->decl))))
     199                 :        5621 :             continue;
     200                 :             : 
     201                 :      144850 :           n->indirect_call_target = true;
     202                 :      144850 :           symtab_node *body = n->function_symbol ();
     203                 :             : 
     204                 :             :           /* Prior inlining, keep alive bodies of possible targets for
     205                 :             :              devirtualization.  */
     206                 :      144850 :           if (n->definition
     207                 :      144850 :               && (possible_inline_candidate_p (body)
     208                 :      111365 :                   && opt_for_fn (body->decl, flag_devirtualize)))
     209                 :             :              {
     210                 :             :                 /* Be sure that we will not optimize out alias target
     211                 :             :                    body.  */
     212                 :      111365 :                 if (DECL_EXTERNAL (n->decl)
     213                 :        2952 :                     && n->alias
     214                 :      111365 :                     && symtab->state < IPA_SSA_AFTER_INLINING)
     215                 :           0 :                   reachable->add (body);
     216                 :      111365 :                reachable->add (n);
     217                 :             :              }
     218                 :             :           /* Even after inlining we want to keep the possible targets in the
     219                 :             :              boundary, so late passes can still produce direct call even if
     220                 :             :              the chance for inlining is lost.  */
     221                 :      144850 :           enqueue_node (n, first, reachable);
     222                 :             :         }
     223                 :             :     }
     224                 :             : 
     225                 :             :   /* Very trivial devirtualization; when the type is
     226                 :             :      final or anonymous (so we know all its derivation)
     227                 :             :      and there is only one possible virtual call target,
     228                 :             :      make the edge direct.  */
     229                 :      199824 :   if (final)
     230                 :             :     {
     231                 :         242 :       if (targets.length () <= 1 && dbg_cnt (devirt))
     232                 :             :         {
     233                 :          14 :           cgraph_node *target, *node = edge->caller;
     234                 :          14 :           if (targets.length () == 1)
     235                 :           6 :             target = targets[0];
     236                 :             :           else
     237                 :           8 :             target = cgraph_node::get_create (builtin_decl_unreachable ());
     238                 :             : 
     239                 :          14 :           if (dump_enabled_p ())
     240                 :             :             {
     241                 :           0 :               dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, edge->call_stmt,
     242                 :             :                                "devirtualizing call in %s to %s\n",
     243                 :           0 :                                edge->caller->dump_name (),
     244                 :             :                                target->dump_name ());
     245                 :             :             }
     246                 :          14 :           edge = cgraph_edge::make_direct (edge, target);
     247                 :          14 :           if (ipa_fn_summaries)
     248                 :           2 :             ipa_update_overall_fn_summary (node->inlined_to
     249                 :             :                                            ? node->inlined_to : node);
     250                 :          12 :           else if (edge->call_stmt)
     251                 :          12 :             cgraph_edge::redirect_call_stmt_to_callee (edge);
     252                 :             :         }
     253                 :             :     }
     254                 :      199824 : }
     255                 :             : 
     256                 :             : /* Perform reachability analysis and reclaim all unreachable nodes.
     257                 :             : 
     258                 :             :    The algorithm is basically mark&sweep but with some extra refinements:
     259                 :             : 
     260                 :             :    - reachable extern inline functions needs special handling; the bodies needs
     261                 :             :      to stay in memory until inlining in hope that they will be inlined.
     262                 :             :      After inlining we release their bodies and turn them into unanalyzed
     263                 :             :      nodes even when they are reachable.
     264                 :             : 
     265                 :             :    - virtual functions are kept in callgraph even if they seem unreachable in
     266                 :             :      hope calls to them will be devirtualized.
     267                 :             : 
     268                 :             :      Again we remove them after inlining.  In late optimization some
     269                 :             :      devirtualization may happen, but it is not important since we won't inline
     270                 :             :      the call. In theory early opts and IPA should work out all important cases.
     271                 :             : 
     272                 :             :    - virtual clones needs bodies of their origins for later materialization;
     273                 :             :      this means that we want to keep the body even if the origin is unreachable
     274                 :             :      otherwise.  To avoid origin from sitting in the callgraph and being
     275                 :             :      walked by IPA passes, we turn them into unanalyzed nodes with body
     276                 :             :      defined.
     277                 :             : 
     278                 :             :      We maintain set of function declaration where body needs to stay in
     279                 :             :      body_needed_for_clonning
     280                 :             : 
     281                 :             :      Inline clones represent special case: their declaration match the
     282                 :             :      declaration of origin and cgraph_remove_node already knows how to
     283                 :             :      reshape callgraph and preserve body when offline copy of function or
     284                 :             :      inline clone is being removed.
     285                 :             : 
     286                 :             :    - C++ virtual tables keyed to other unit are represented as DECL_EXTERNAL
     287                 :             :      variables with DECL_INITIAL set.  We finalize these and keep reachable
     288                 :             :      ones around for constant folding purposes.  After inlining we however
     289                 :             :      stop walking their references to let everything static referenced by them
     290                 :             :      to be removed when it is otherwise unreachable.
     291                 :             : 
     292                 :             :    We maintain queue of both reachable symbols (i.e. defined symbols that needs
     293                 :             :    to stay) and symbols that are in boundary (i.e. external symbols referenced
     294                 :             :    by reachable symbols or origins of clones).  The queue is represented
     295                 :             :    as linked list by AUX pointer terminated by 1.
     296                 :             : 
     297                 :             :    At the end we keep all reachable symbols. For symbols in boundary we always
     298                 :             :    turn definition into a declaration, but we may keep function body around
     299                 :             :    based on body_needed_for_clonning
     300                 :             : 
     301                 :             :    All symbols that enter the queue have AUX pointer non-zero and are in the
     302                 :             :    boundary.  Pointer set REACHABLE is used to track reachable symbols.
     303                 :             : 
     304                 :             :    Every symbol can be visited twice - once as part of boundary and once
     305                 :             :    as real reachable symbol. enqueue_node needs to decide whether the
     306                 :             :    node needs to be re-queued for second processing.  For this purpose
     307                 :             :    we set AUX pointer of processed symbols in the boundary to constant 2.  */
     308                 :             : 
     309                 :             : bool
     310                 :     1465955 : symbol_table::remove_unreachable_nodes (FILE *file)
     311                 :             : {
     312                 :     1465955 :   symtab_node *first = (symtab_node *) (void *) 1;
     313                 :     1465955 :   struct cgraph_node *node, *next;
     314                 :     1465955 :   varpool_node *vnode, *vnext;
     315                 :     1465955 :   bool changed = false;
     316                 :     1465955 :   hash_set<symtab_node *> reachable;
     317                 :     1465955 :   hash_set<tree> body_needed_for_clonning;
     318                 :     1465955 :   hash_set<void *> reachable_call_targets;
     319                 :             : 
     320                 :     1465955 :   timevar_push (TV_IPA_UNREACHABLE);
     321                 :     1465955 :   build_type_inheritance_graph ();
     322                 :     1465955 :   if (file)
     323                 :         694 :     fprintf (file, "\nReclaiming functions:");
     324                 :     1465955 :   if (flag_checking)
     325                 :             :     {
     326                 :    59844656 :       FOR_EACH_FUNCTION (node)
     327                 :    28456474 :         gcc_assert (!node->aux);
     328                 :    45926826 :       FOR_EACH_VARIABLE (vnode)
     329                 :    22230486 :         gcc_assert (!vnode->aux);
     330                 :             :     }
     331                 :             :   /* Mark functions whose bodies are obviously needed.
     332                 :             :      This is mostly when they can be referenced externally.  Inline clones
     333                 :             :      are special since their declarations are shared with master clone and thus
     334                 :             :      cgraph_can_remove_if_no_direct_calls_and_refs_p should not be called on them.  */
     335                 :    59845504 :   FOR_EACH_FUNCTION (node)
     336                 :             :     {
     337                 :    28456797 :       node->used_as_abstract_origin = false;
     338                 :    28456797 :       node->indirect_call_target = false;
     339                 :    28456797 :       if (node->definition
     340                 :    16953766 :           && !node->inlined_to
     341                 :    14520553 :           && !node->in_other_partition
     342                 :    42977115 :           && !node->can_remove_if_no_direct_calls_and_refs_p ())
     343                 :             :         {
     344                 :     7676497 :           gcc_assert (!node->inlined_to);
     345                 :     7676497 :           reachable.add (node);
     346                 :     7676497 :           enqueue_node (node, &first, &reachable);
     347                 :             :         }
     348                 :             :       else
     349                 :    20780300 :         gcc_assert (!node->aux);
     350                 :             :      }
     351                 :             : 
     352                 :             :   /* Mark variables that are obviously needed.  */
     353                 :    21623353 :   FOR_EACH_DEFINED_VARIABLE (vnode)
     354                 :    20157398 :     if (!vnode->can_remove_if_no_refs_p()
     355                 :    20157398 :         && !vnode->in_other_partition)
     356                 :             :       {
     357                 :    10093247 :         reachable.add (vnode);
     358                 :    10093247 :         enqueue_node (vnode, &first, &reachable);
     359                 :             :       }
     360                 :             : 
     361                 :             :   /* Perform reachability analysis.  */
     362                 :    51835585 :   while (first != (symtab_node *) (void *) 1)
     363                 :             :     {
     364                 :    50369630 :       bool in_boundary_p = !reachable.contains (first);
     365                 :    50369630 :       symtab_node *node = first;
     366                 :             : 
     367                 :    50369630 :       first = (symtab_node *)first->aux;
     368                 :             : 
     369                 :             :       /* If we are processing symbol in boundary, mark its AUX pointer for
     370                 :             :          possible later re-processing in enqueue_node.  */
     371                 :    50369630 :       if (in_boundary_p)
     372                 :             :         {
     373                 :    13611036 :           node->aux = (void *)2;
     374                 :    13611036 :           if (node->alias && node->analyzed)
     375                 :        3688 :             enqueue_node (node->get_alias_target (), &first, &reachable);
     376                 :             :         }
     377                 :             :       else
     378                 :             :         {
     379                 :    36758594 :           if (TREE_CODE (node->decl) == FUNCTION_DECL
     380                 :    36758594 :               && DECL_ABSTRACT_ORIGIN (node->decl))
     381                 :             :             {
     382                 :     3402103 :               struct cgraph_node *origin_node
     383                 :     3402103 :               = cgraph_node::get (DECL_ABSTRACT_ORIGIN (node->decl));
     384                 :     3402103 :               if (origin_node && !origin_node->used_as_abstract_origin)
     385                 :             :                 {
     386                 :      399991 :                   origin_node->used_as_abstract_origin = true;
     387                 :      399991 :                   gcc_assert (!origin_node->prev_sibling_clone);
     388                 :      399991 :                   gcc_assert (!origin_node->next_sibling_clone);
     389                 :      670524 :                   for (cgraph_node *n = origin_node->clones; n;
     390                 :      270533 :                        n = n->next_sibling_clone)
     391                 :      270533 :                     if (n->decl == DECL_ABSTRACT_ORIGIN (node->decl))
     392                 :      240504 :                       n->used_as_abstract_origin = true;
     393                 :             :                 }
     394                 :             :             }
     395                 :             :           /* If any non-external and non-local symbol in a comdat group is
     396                 :             :              reachable, force all externally visible symbols in the same comdat
     397                 :             :              group to be reachable as well.  Comdat-local symbols
     398                 :             :              can be discarded if all uses were inlined.  */
     399                 :    36758594 :           if (node->same_comdat_group
     400                 :     1623511 :               && node->externally_visible
     401                 :    38355344 :               && !DECL_EXTERNAL (node->decl))
     402                 :             :             {
     403                 :     1596750 :               symtab_node *next;
     404                 :     1596750 :               for (next = node->same_comdat_group;
     405                 :     4837576 :                    next != node;
     406                 :     3240826 :                    next = next->same_comdat_group)
     407                 :     6481652 :                 if (!next->comdat_local_p ()
     408                 :     3171917 :                     && !DECL_EXTERNAL (next->decl)
     409                 :     3171914 :                     && !reachable.add (next))
     410                 :      759317 :                   enqueue_node (next, &first, &reachable);
     411                 :             :             }
     412                 :             :           /* Mark references as reachable.  */
     413                 :    36758594 :           process_references (node, &first, &reachable);
     414                 :             :         }
     415                 :             : 
     416                 :    50369630 :       if (cgraph_node *cnode = dyn_cast <cgraph_node *> (node))
     417                 :             :         {
     418                 :             :           /* Mark the callees reachable unless they are direct calls to extern
     419                 :             :              inline functions we decided to not inline.  */
     420                 :    28182333 :           if (!in_boundary_p)
     421                 :             :             {
     422                 :    16643728 :               struct cgraph_edge *e;
     423                 :             :               /* Keep alive possible targets for devirtualization.  */
     424                 :    16643728 :               if (opt_for_fn (cnode->decl, optimize)
     425                 :    16643728 :                   && opt_for_fn (cnode->decl, flag_devirtualize))
     426                 :             :                 {
     427                 :    13794267 :                   struct cgraph_edge *next;
     428                 :    14993938 :                   for (e = cnode->indirect_calls; e; e = next)
     429                 :             :                     {
     430                 :     1199671 :                       next = e->next_callee;
     431                 :     1199671 :                       if (e->indirect_info->polymorphic)
     432                 :      199824 :                         walk_polymorphic_call_targets (&reachable_call_targets,
     433                 :             :                                                        e, &first, &reachable);
     434                 :             :                     }
     435                 :             :                 }
     436                 :             : 
     437                 :             :               /* A reference to the default node implies use of all the other
     438                 :             :                  versions (they get used in the function resolver made later
     439                 :             :                  in multiple_target.cc)  */
     440                 :    16643728 :               cgraph_function_version_info *node_v = cnode->function_version ();
     441                 :    16643728 :               if (node_v && is_function_default_version (node->decl))
     442                 :         963 :                 for (cgraph_function_version_info *fvi = node_v->next;
     443                 :        4066 :                      fvi;
     444                 :        3103 :                      fvi = fvi->next)
     445                 :        3103 :                   enqueue_node (fvi->this_node, &first, &reachable);
     446                 :             : 
     447                 :    72766535 :               for (e = cnode->callees; e; e = e->next_callee)
     448                 :             :                 {
     449                 :    56122807 :                   symtab_node *body = e->callee->function_symbol ();
     450                 :    56122807 :                   if (e->callee->definition
     451                 :    22382058 :                       && !e->callee->in_other_partition
     452                 :    78504742 :                       && (!e->inline_failed
     453                 :    19970448 :                           || !DECL_EXTERNAL (e->callee->decl)
     454                 :     1331997 :                           || e->callee->alias
     455                 :     1162466 :                           || possible_inline_candidate_p (e->callee)))
     456                 :             :                     {
     457                 :             :                       /* Be sure that we will not optimize out alias target
     458                 :             :                          body.  */
     459                 :    22329309 :                       if (DECL_EXTERNAL (e->callee->decl)
     460                 :     1497529 :                           && e->callee->alias
     461                 :    22498840 :                           && symtab->state < IPA_SSA_AFTER_INLINING)
     462                 :      168370 :                         reachable.add (body);
     463                 :    22329309 :                       reachable.add (e->callee);
     464                 :             :                     }
     465                 :    56122807 :                   enqueue_node (e->callee, &first, &reachable);
     466                 :             :                 }
     467                 :             : 
     468                 :             :               /* When inline clone exists, mark body to be preserved so when removing
     469                 :             :                  offline copy of the function we don't kill it.  */
     470                 :    16643728 :               if (cnode->inlined_to)
     471                 :     2411487 :                 body_needed_for_clonning.add (cnode->decl);
     472                 :             : 
     473                 :             :               /* For non-inline clones, force their origins to the boundary and ensure
     474                 :             :                  that body is not removed.  */
     475                 :    19948627 :               while (cnode->clone_of)
     476                 :             :                 {
     477                 :     3304899 :                   bool noninline = cnode->clone_of->decl != cnode->decl;
     478                 :     3304899 :                   cnode = cnode->clone_of;
     479                 :     3304899 :                   if (noninline)
     480                 :             :                     {
     481                 :      809098 :                       body_needed_for_clonning.add (cnode->decl);
     482                 :      809098 :                       enqueue_node (cnode, &first, &reachable);
     483                 :             :                     }
     484                 :             :                 }
     485                 :             : 
     486                 :             :             }
     487                 :    11538605 :           else if (cnode->thunk)
     488                 :          42 :             enqueue_node (cnode->callees->callee, &first, &reachable);
     489                 :             : 
     490                 :             :           /* If any reachable function has simd clones, mark them as
     491                 :             :              reachable as well.  */
     492                 :    28182333 :           if (cnode->simd_clones)
     493                 :             :             {
     494                 :             :               cgraph_node *next;
     495                 :           0 :               for (next = cnode->simd_clones;
     496                 :           0 :                    next;
     497                 :           0 :                    next = next->simdclone->next_clone)
     498                 :           0 :                 if (in_boundary_p
     499                 :           0 :                     || !reachable.add (next))
     500                 :           0 :                   enqueue_node (next, &first, &reachable);
     501                 :             :             }
     502                 :             :         }
     503                 :             :       /* When we see constructor of external variable, keep referred nodes in the
     504                 :             :         boundary.  This will also hold initializers of the external vars NODE
     505                 :             :         refers to.  */
     506                 :    50369630 :       varpool_node *vnode = dyn_cast <varpool_node *> (node);
     507                 :    50369630 :       if (vnode
     508                 :    22187297 :           && DECL_EXTERNAL (node->decl)
     509                 :     2072180 :           && !vnode->alias
     510                 :             :           && in_boundary_p)
     511                 :             :         {
     512                 :     2169759 :           struct ipa_ref *ref = NULL;
     513                 :     5707892 :           for (int i = 0; node->iterate_reference (i, ref); i++)
     514                 :       97581 :             enqueue_node (ref->referred, &first, &reachable);
     515                 :             :         }
     516                 :             :     }
     517                 :             : 
     518                 :             :   /* Remove unreachable functions.   */
     519                 :    31394205 :   for (node = first_function (); node; node = next)
     520                 :             :     {
     521                 :    28462295 :       next = next_function (node);
     522                 :             : 
     523                 :             :       /* If node is not needed at all, remove it.  */
     524                 :    28462295 :       if (!node->aux)
     525                 :             :         {
     526                 :      286898 :           if (file)
     527                 :          89 :             fprintf (file, " %s", node->dump_name ());
     528                 :      286898 :           node->remove ();
     529                 :      286898 :           changed = true;
     530                 :             :         }
     531                 :             :       /* If node is unreachable, remove its body.  */
     532                 :    28175397 :       else if (!reachable.contains (node))
     533                 :             :         {
     534                 :             :           /* We keep definitions of thunks and aliases in the boundary so
     535                 :             :              we can walk to the ultimate alias targets and function symbols
     536                 :             :              reliably.  */
     537                 :    11531669 :           if (node->alias || node->thunk)
     538                 :             :             ;
     539                 :    11527425 :           else if (!body_needed_for_clonning.contains (node->decl))
     540                 :             :             {
     541                 :             :               /* Make the node a non-clone so that we do not attempt to
     542                 :             :                  materialize it later.  */
     543                 :    11167662 :               if (node->clone_of)
     544                 :           0 :                 node->remove_from_clone_tree ();
     545                 :    11167662 :               node->release_body ();
     546                 :             :             }
     547                 :      359763 :           else if (!node->clone_of)
     548                 :      348618 :             gcc_assert (in_lto_p || DECL_RESULT (node->decl));
     549                 :    11531669 :           if (node->definition && !node->alias && !node->thunk)
     550                 :             :             {
     551                 :      142579 :               if (file)
     552                 :         179 :                 fprintf (file, " %s", node->dump_name ());
     553                 :      142579 :               node->body_removed = true;
     554                 :      142579 :               node->analyzed = false;
     555                 :      142579 :               node->definition = false;
     556                 :      142579 :               node->cpp_implicit_alias = false;
     557                 :      142579 :               node->alias = false;
     558                 :      142579 :               node->transparent_alias = false;
     559                 :      142579 :               node->thunk = false;
     560                 :      142579 :               node->weakref = false;
     561                 :             :               /* After early inlining we drop always_inline attributes on
     562                 :             :                  bodies of functions that are still referenced (have their
     563                 :             :                  address taken).  */
     564                 :      142579 :               DECL_ATTRIBUTES (node->decl)
     565                 :      142579 :                 = remove_attribute ("always_inline",
     566                 :      142579 :                                     DECL_ATTRIBUTES (node->decl));
     567                 :      142579 :               if (!node->in_other_partition)
     568                 :      142406 :                 node->local = false;
     569                 :      142579 :               node->remove_callees ();
     570                 :      142579 :               node->remove_all_references ();
     571                 :      142579 :               changed = true;
     572                 :             :             }
     573                 :             :         }
     574                 :             :       else
     575                 :    16643728 :         gcc_assert (node->clone_of || !node->has_gimple_body_p ()
     576                 :             :                     || in_lto_p || DECL_RESULT (node->decl));
     577                 :             :     }
     578                 :             : 
     579                 :             :   /* Inline clones might be kept around so their materializing allows further
     580                 :             :      cloning.  If the function the clone is inlined into is removed, we need
     581                 :             :      to turn it into normal cone.  */
     582                 :    31107307 :   FOR_EACH_FUNCTION (node)
     583                 :             :     {
     584                 :    28175397 :       if (node->inlined_to
     585                 :     2411487 :           && !node->callers)
     586                 :             :         {
     587                 :           0 :           gcc_assert (node->clones);
     588                 :           0 :           node->inlined_to = NULL;
     589                 :           0 :           update_inlined_to_pointer (node, node);
     590                 :             :         }
     591                 :    28175397 :       node->aux = NULL;
     592                 :             :     }
     593                 :             : 
     594                 :             :   /* Remove unreachable variables.  */
     595                 :     1465955 :   if (file)
     596                 :         694 :     fprintf (file, "\nReclaiming variables:");
     597                 :    25162816 :   for (vnode = first_variable (); vnode; vnode = vnext)
     598                 :             :     {
     599                 :    22230906 :       vnext = next_variable (vnode);
     600                 :    22230906 :       if (!vnode->aux
     601                 :             :           /* For can_refer_decl_in_current_unit_p we want to track for
     602                 :             :              all external variables if they are defined in other partition
     603                 :             :              or not.  */
     604                 :    22230906 :           && (!flag_ltrans || !DECL_EXTERNAL (vnode->decl)))
     605                 :             :         {
     606                 :       43558 :           struct ipa_ref *ref = NULL;
     607                 :             : 
     608                 :             :           /* First remove the aliases, so varpool::remove can possibly lookup
     609                 :             :              the constructor and save it for future use.  */
     610                 :       43558 :           while (vnode->iterate_direct_aliases (0, ref))
     611                 :             :             {
     612                 :           0 :               if (file)
     613                 :           0 :                 fprintf (file, " %s", ref->referred->dump_name ());
     614                 :           0 :               ref->referring->remove ();
     615                 :             :             }
     616                 :       43558 :           if (file)
     617                 :           1 :             fprintf (file, " %s", vnode->dump_name ());
     618                 :       43558 :           vnext = next_variable (vnode);
     619                 :             :           /* Signal removal to the debug machinery.  */
     620                 :       43558 :           if (! flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
     621                 :             :             {
     622                 :       41220 :               vnode->definition = false;
     623                 :       41220 :               (*debug_hooks->late_global_decl) (vnode->decl);
     624                 :             :             }
     625                 :       43558 :           vnode->remove ();
     626                 :       43558 :           changed = true;
     627                 :             :         }
     628                 :    22187348 :       else if (!reachable.contains (vnode) && !vnode->alias)
     629                 :             :         {
     630                 :     2072270 :           tree init;
     631                 :     2072270 :           if (vnode->definition)
     632                 :             :             {
     633                 :       16069 :               if (file)
     634                 :           0 :                 fprintf (file, " %s", vnode->dump_name ());
     635                 :             :               changed = true;
     636                 :             :             }
     637                 :             :           /* Keep body if it may be useful for constant folding.  */
     638                 :     2067542 :           if ((flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
     639                 :     4139752 :               || ((init = ctor_for_folding (vnode->decl)) == error_mark_node))
     640                 :     1986047 :             vnode->remove_initializer ();
     641                 :             :           else
     642                 :       86223 :             DECL_INITIAL (vnode->decl) = init;
     643                 :     2072270 :           vnode->body_removed = true;
     644                 :     2072270 :           vnode->definition = false;
     645                 :     2072270 :           vnode->analyzed = false;
     646                 :     2072270 :           vnode->aux = NULL;
     647                 :             : 
     648                 :     2072270 :           vnode->remove_from_same_comdat_group ();
     649                 :             : 
     650                 :     2072270 :           vnode->remove_all_references ();
     651                 :             :         }
     652                 :             :       else
     653                 :    20115078 :         vnode->aux = NULL;
     654                 :             :     }
     655                 :             : 
     656                 :             :   /* Now update address_taken flags and try to promote functions to be local.  */
     657                 :     1465955 :   if (file)
     658                 :         694 :     fprintf (file, "\nClearing address taken flags:");
     659                 :    18113260 :   FOR_EACH_DEFINED_FUNCTION (node)
     660                 :    16647305 :     if (node->address_taken
     661                 :     3260306 :         && !node->used_from_other_partition)
     662                 :             :       {
     663                 :     3260152 :         if (!node->call_for_symbol_and_aliases
     664                 :     3260152 :             (has_addr_references_p, NULL, true))
     665                 :             :           {
     666                 :       22752 :             if (file)
     667                 :           0 :               fprintf (file, " %s", node->dump_name ());
     668                 :       22752 :             node->address_taken = false;
     669                 :       22752 :             changed = true;
     670                 :       22752 :             if (node->local_p ()
     671                 :             :                 /* Virtual functions may be kept in cgraph just because
     672                 :             :                    of possible later devirtualization.  Do not mark them as
     673                 :             :                    local too early so we won't optimize them out before
     674                 :             :                    we are done with polymorphic call analysis.  */
     675                 :       22752 :                 && (symtab->state >= IPA_SSA_AFTER_INLINING
     676                 :         493 :                     || !node->call_for_symbol_and_aliases
     677                 :         493 :                        (is_indirect_call_target_p, NULL, true)))
     678                 :             :               {
     679                 :         503 :                 node->local = true;
     680                 :         503 :                 if (file)
     681                 :           0 :                   fprintf (file, " (local)");
     682                 :             :               }
     683                 :             :           }
     684                 :             :       }
     685                 :     1465955 :   if (file)
     686                 :         694 :     fprintf (file, "\n");
     687                 :             : 
     688                 :     1465955 :   symtab_node::checking_verify_symtab_nodes ();
     689                 :             : 
     690                 :             :   /* If we removed something, perhaps profile could be improved.  */
     691                 :     1465955 :   if (changed && (optimize || in_lto_p) && ipa_call_summaries)
     692                 :     4306560 :     FOR_EACH_DEFINED_FUNCTION (node)
     693                 :     4237468 :       ipa_propagate_frequency (node);
     694                 :             : 
     695                 :     1465955 :   timevar_pop (TV_IPA_UNREACHABLE);
     696                 :     1465955 :   return changed;
     697                 :     1465955 : }
     698                 :             : 
     699                 :             : /* Process references to VNODE and set flags WRITTEN, ADDRESS_TAKEN, READ
     700                 :             :    as needed, also clear EXPLICIT_REFS if the references to given variable
     701                 :             :    do not need to be explicit.  */
     702                 :             : 
     703                 :             : void
     704                 :     5386575 : process_references (varpool_node *vnode,
     705                 :             :                     bool *written, bool *address_taken,
     706                 :             :                     bool *read, bool *explicit_refs)
     707                 :             : {
     708                 :     5386575 :   int i;
     709                 :     5386575 :   struct ipa_ref *ref;
     710                 :             : 
     711                 :     5386575 :   if (!vnode->all_refs_explicit_p ()
     712                 :     5386575 :       || TREE_THIS_VOLATILE (vnode->decl))
     713                 :     2933586 :     *explicit_refs = false;
     714                 :             : 
     715                 :     4017356 :   for (i = 0; vnode->iterate_referring (i, ref)
     716                 :     9403931 :               && *explicit_refs && (!*written || !*address_taken || !*read); i++)
     717                 :     4017356 :     switch (ref->use)
     718                 :             :       {
     719                 :     2743145 :       case IPA_REF_ADDR:
     720                 :     2743145 :         *address_taken = true;
     721                 :     2743145 :         break;
     722                 :      696126 :       case IPA_REF_LOAD:
     723                 :      696126 :         *read = true;
     724                 :      696126 :         break;
     725                 :      565900 :       case IPA_REF_STORE:
     726                 :      565900 :         *written = true;
     727                 :      565900 :         break;
     728                 :       12185 :       case IPA_REF_ALIAS:
     729                 :       12185 :         process_references (dyn_cast<varpool_node *> (ref->referring), written,
     730                 :             :                             address_taken, read, explicit_refs);
     731                 :       12185 :         break;
     732                 :             :       }
     733                 :     5386575 : }
     734                 :             : 
     735                 :             : /* Set TREE_READONLY bit.  */
     736                 :             : 
     737                 :             : bool
     738                 :       77835 : set_readonly_bit (varpool_node *vnode, void *data ATTRIBUTE_UNUSED)
     739                 :             : {
     740                 :       77835 :   TREE_READONLY (vnode->decl) = true;
     741                 :       77835 :   return false;
     742                 :             : }
     743                 :             : 
     744                 :             : /* Set writeonly bit and clear the initalizer, since it will not be needed.  */
     745                 :             : 
     746                 :             : bool
     747                 :       25944 : set_writeonly_bit (varpool_node *vnode, void *data)
     748                 :             : {
     749                 :       25944 :   vnode->writeonly = true;
     750                 :       25944 :   if (optimize || in_lto_p)
     751                 :             :     {
     752                 :       25944 :       DECL_INITIAL (vnode->decl) = NULL;
     753                 :       25944 :       if (!vnode->alias)
     754                 :             :         {
     755                 :       25944 :           if (vnode->num_references ())
     756                 :         210 :             *(bool *)data = true;
     757                 :       25944 :           vnode->remove_all_references ();
     758                 :             :         }
     759                 :             :     }
     760                 :       25944 :   return false;
     761                 :             : }
     762                 :             : 
     763                 :             : /* Clear addressale bit of VNODE.  */
     764                 :             : 
     765                 :             : bool
     766                 :      174714 : clear_addressable_bit (varpool_node *vnode, void *data ATTRIBUTE_UNUSED)
     767                 :             : {
     768                 :      174714 :   vnode->address_taken = false;
     769                 :      174714 :   TREE_ADDRESSABLE (vnode->decl) = 0;
     770                 :      174714 :   return false;
     771                 :             : }
     772                 :             : 
     773                 :             : /* Discover variables that have no longer address taken, are read-only or
     774                 :             :    write-only and update their flags.
     775                 :             : 
     776                 :             :    Return true when unreachable symbol removal should be done.
     777                 :             : 
     778                 :             :    FIXME: This cannot be done in between gimplify and omp_expand since
     779                 :             :    readonly flag plays role on what is shared and what is not.  Currently we do
     780                 :             :    this transformation as part of whole program visibility and re-do at
     781                 :             :    ipa-reference pass (to take into account clonning), but it would
     782                 :             :    make sense to do it before early optimizations.  */
     783                 :             : 
     784                 :             : bool
     785                 :      303396 : ipa_discover_variable_flags (void)
     786                 :             : {
     787                 :      303396 :   if (!flag_ipa_reference_addressable)
     788                 :             :     return false;
     789                 :             : 
     790                 :      296897 :   bool remove_p = false;
     791                 :      296897 :   varpool_node *vnode;
     792                 :      296897 :   if (dump_file)
     793                 :          73 :     fprintf (dump_file, "Clearing variable flags:");
     794                 :    11367394 :   FOR_EACH_VARIABLE (vnode)
     795                 :     5386800 :     if (!vnode->alias
     796                 :     5386800 :         && (TREE_ADDRESSABLE (vnode->decl)
     797                 :     2370920 :             || !vnode->writeonly
     798                 :       25870 :             || !TREE_READONLY (vnode->decl)))
     799                 :             :       {
     800                 :     5374390 :         bool written = false;
     801                 :     5374390 :         bool address_taken = false;
     802                 :     5374390 :         bool read = false;
     803                 :     5374390 :         bool explicit_refs = true;
     804                 :             : 
     805                 :     5374390 :         process_references (vnode, &written, &address_taken, &read,
     806                 :             :                             &explicit_refs);
     807                 :     5374390 :         if (!explicit_refs)
     808                 :     2933586 :           continue;
     809                 :     2440804 :         if (!address_taken)
     810                 :             :           {
     811                 :      163497 :             if (TREE_ADDRESSABLE (vnode->decl) && dump_file)
     812                 :           0 :               fprintf (dump_file, " %s (non-addressable)",
     813                 :             :                        vnode->dump_name ());
     814                 :      163497 :             vnode->call_for_symbol_and_aliases (clear_addressable_bit, NULL,
     815                 :             :                                                 true);
     816                 :             :           }
     817                 :      163497 :         if (!address_taken && !written
     818                 :             :             /* Making variable in explicit section readonly can cause section
     819                 :             :                type conflict.
     820                 :             :                See e.g. gcc.c-torture/compile/pr23237.c */
     821                 :     2507456 :             && vnode->get_section () == NULL)
     822                 :             :           {
     823                 :       66622 :             if (!TREE_READONLY (vnode->decl) && dump_file)
     824                 :           3 :               fprintf (dump_file, " %s (read-only)", vnode->dump_name ());
     825                 :       66622 :             vnode->call_for_symbol_and_aliases (set_readonly_bit, NULL, true);
     826                 :             :           }
     827                 :     2440804 :         if (!vnode->writeonly && !read && !address_taken && written)
     828                 :             :           {
     829                 :       25944 :             if (dump_file)
     830                 :           0 :               fprintf (dump_file, " %s (write-only)", vnode->dump_name ());
     831                 :       25944 :             vnode->call_for_symbol_and_aliases (set_writeonly_bit, &remove_p,
     832                 :             :                                                 true);
     833                 :             :           }
     834                 :             :       }
     835                 :      296897 :   if (dump_file)
     836                 :          73 :     fprintf (dump_file, "\n");
     837                 :      296897 :   return remove_p;
     838                 :             : }
     839                 :             : 
     840                 :             : /* Generate and emit a static constructor or destructor.  WHICH must
     841                 :             :    be one of 'I' (for a constructor), 'D' (for a destructor).
     842                 :             :    BODY is a STATEMENT_LIST containing GENERIC
     843                 :             :    statements.  PRIORITY is the initialization priority for this
     844                 :             :    constructor or destructor.
     845                 :             : 
     846                 :             :    FINAL specify whether the externally visible name for collect2 should
     847                 :             :    be produced. */
     848                 :             : 
     849                 :             : static tree
     850                 :        4946 : cgraph_build_static_cdtor_1 (char which, tree body, int priority, bool final,
     851                 :             :                              tree optimization,
     852                 :             :                              tree target)
     853                 :             : {
     854                 :        4946 :   static int counter = 0;
     855                 :        4946 :   char which_buf[16];
     856                 :        4946 :   tree decl, name, resdecl;
     857                 :             : 
     858                 :             :   /* The priority is encoded in the constructor or destructor name.
     859                 :             :      collect2 will sort the names and arrange that they are called at
     860                 :             :      program startup.  */
     861                 :        4946 :   if (!targetm.have_ctors_dtors && final)
     862                 :             :     {
     863                 :           0 :       sprintf (which_buf, "%c_%.5d_%d", which, priority, counter++);
     864                 :           0 :       name = get_file_function_name (which_buf);
     865                 :             :     }
     866                 :             :   else
     867                 :             :     {
     868                 :             :       /* Proudce sane name but one not recognizable by collect2, just for the
     869                 :             :          case we fail to inline the function.  */
     870                 :        4946 :       sprintf (which_buf, "_sub_%c_%.5d_%d", which, priority, counter++);
     871                 :        4946 :       name = get_identifier (which_buf);
     872                 :             :     }
     873                 :             : 
     874                 :        4946 :   decl = build_decl (input_location, FUNCTION_DECL, name,
     875                 :             :                      build_function_type_list (void_type_node, NULL_TREE));
     876                 :        4946 :   current_function_decl = decl;
     877                 :             : 
     878                 :        4946 :   resdecl = build_decl (input_location,
     879                 :             :                         RESULT_DECL, NULL_TREE, void_type_node);
     880                 :        4946 :   DECL_ARTIFICIAL (resdecl) = 1;
     881                 :        4946 :   DECL_RESULT (decl) = resdecl;
     882                 :        4946 :   DECL_CONTEXT (resdecl) = decl;
     883                 :             : 
     884                 :        4946 :   allocate_struct_function (decl, false);
     885                 :             : 
     886                 :        4946 :   TREE_STATIC (decl) = 1;
     887                 :        4946 :   TREE_USED (decl) = 1;
     888                 :        4946 :   DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl) = optimization;
     889                 :        4946 :   DECL_FUNCTION_SPECIFIC_TARGET (decl) = target;
     890                 :        4946 :   DECL_ARTIFICIAL (decl) = 1;
     891                 :        4946 :   DECL_IGNORED_P (decl) = 1;
     892                 :        4946 :   DECL_NO_INSTRUMENT_FUNCTION_ENTRY_EXIT (decl) = 1;
     893                 :        4946 :   DECL_SAVED_TREE (decl) = body;
     894                 :        4946 :   if (!targetm.have_ctors_dtors && final)
     895                 :             :     {
     896                 :           0 :       TREE_PUBLIC (decl) = 1;
     897                 :           0 :       DECL_PRESERVE_P (decl) = 1;
     898                 :             :     }
     899                 :        4946 :   DECL_UNINLINABLE (decl) = 1;
     900                 :             : 
     901                 :        4946 :   DECL_INITIAL (decl) = make_node (BLOCK);
     902                 :        4946 :   BLOCK_SUPERCONTEXT (DECL_INITIAL (decl)) = decl;
     903                 :        4946 :   TREE_USED (DECL_INITIAL (decl)) = 1;
     904                 :             : 
     905                 :        4946 :   DECL_SOURCE_LOCATION (decl) = input_location;
     906                 :        4946 :   cfun->function_end_locus = input_location;
     907                 :             : 
     908                 :        4946 :   switch (which)
     909                 :             :     {
     910                 :        3473 :     case 'I':
     911                 :        3473 :       DECL_STATIC_CONSTRUCTOR (decl) = 1;
     912                 :        3473 :       decl_init_priority_insert (decl, priority);
     913                 :        3473 :       break;
     914                 :        1473 :     case 'D':
     915                 :        1473 :       DECL_STATIC_DESTRUCTOR (decl) = 1;
     916                 :        1473 :       decl_fini_priority_insert (decl, priority);
     917                 :        1473 :       break;
     918                 :           0 :     default:
     919                 :           0 :       gcc_unreachable ();
     920                 :             :     }
     921                 :             : 
     922                 :        4946 :   gimplify_function_tree (decl);
     923                 :             : 
     924                 :        4946 :   cgraph_node::add_new_function (decl, false);
     925                 :             : 
     926                 :        4946 :   set_cfun (NULL);
     927                 :        4946 :   current_function_decl = NULL;
     928                 :        4946 :   return decl;
     929                 :             : }
     930                 :             : 
     931                 :             : /* Generate and emit a static constructor or destructor.  WHICH must
     932                 :             :    be one of 'I' (for a constructor) or 'D' (for a destructor).
     933                 :             :    BODY is a STATEMENT_LIST containing GENERIC
     934                 :             :    statements.  PRIORITY is the initialization priority for this
     935                 :             :    constructor or destructor.  */
     936                 :             : 
     937                 :             : void
     938                 :        4938 : cgraph_build_static_cdtor (char which, tree body, int priority)
     939                 :             : {
     940                 :             :   /* FIXME: We should be able to
     941                 :             :      gcc_assert (!in_lto_p);
     942                 :             :      because at LTO time the global options are not safe to use.
     943                 :             :      Unfortunately ASAN finish_file will produce constructors late and they
     944                 :             :      may lead to surprises.  */
     945                 :        4938 :   cgraph_build_static_cdtor_1 (which, body, priority, false,
     946                 :             :                                optimization_default_node,
     947                 :             :                                target_option_default_node);
     948                 :        4938 : }
     949                 :             : 
     950                 :             : /* When target does not have ctors and dtors, we call all constructor
     951                 :             :    and destructor by special initialization/destruction function
     952                 :             :    recognized by collect2.
     953                 :             : 
     954                 :             :    When we are going to build this function, collect all constructors and
     955                 :             :    destructors and turn them into normal functions.  */
     956                 :             : 
     957                 :             : static void
     958                 :         100 : record_cdtor_fn (struct cgraph_node *node, vec<tree> *ctors, vec<tree> *dtors)
     959                 :             : {
     960                 :         100 :   if (DECL_STATIC_CONSTRUCTOR (node->decl))
     961                 :          75 :     ctors->safe_push (node->decl);
     962                 :         100 :   if (DECL_STATIC_DESTRUCTOR (node->decl))
     963                 :          29 :     dtors->safe_push (node->decl);
     964                 :         100 :   node = cgraph_node::get (node->decl);
     965                 :         100 :   DECL_DISREGARD_INLINE_LIMITS (node->decl) = 1;
     966                 :         100 : }
     967                 :             : 
     968                 :             : /* Define global constructors/destructor functions for the CDTORS, of
     969                 :             :    which they are LEN.  The CDTORS are sorted by initialization
     970                 :             :    priority.  If CTOR_P is true, these are constructors; otherwise,
     971                 :             :    they are destructors.  */
     972                 :             : 
     973                 :             : static void
     974                 :          72 : build_cdtor (bool ctor_p, const vec<tree> &cdtors)
     975                 :             : {
     976                 :          72 :   size_t i,j;
     977                 :          72 :   size_t len = cdtors.length ();
     978                 :             : 
     979                 :          72 :   i = 0;
     980                 :         168 :   while (i < len)
     981                 :             :     {
     982                 :          96 :       tree body;
     983                 :          96 :       tree fn;
     984                 :          96 :       priority_type priority;
     985                 :             : 
     986                 :          96 :       priority = 0;
     987                 :          96 :       body = NULL_TREE;
     988                 :          96 :       j = i;
     989                 :         128 :       do
     990                 :             :         {
     991                 :         128 :           priority_type p;
     992                 :         128 :           fn = cdtors[j];
     993                 :         128 :           p = ctor_p ? DECL_INIT_PRIORITY (fn) : DECL_FINI_PRIORITY (fn);
     994                 :         128 :           if (j == i)
     995                 :             :             priority = p;
     996                 :          32 :           else if (p != priority)
     997                 :             :             break;
     998                 :         104 :           j++;
     999                 :             :         }
    1000                 :         104 :       while (j < len);
    1001                 :             : 
    1002                 :             :       /* When there is only one cdtor and target supports them, do nothing.  */
    1003                 :          96 :       if (j == i + 1
    1004                 :          88 :           && targetm.have_ctors_dtors)
    1005                 :             :         {
    1006                 :          88 :           i++;
    1007                 :          88 :           continue;
    1008                 :             :         }
    1009                 :             :       /* Find the next batch of constructors/destructors with the same
    1010                 :             :          initialization priority.  */
    1011                 :          24 :       for (;i < j; i++)
    1012                 :             :         {
    1013                 :          16 :           tree call;
    1014                 :          16 :           fn = cdtors[i];
    1015                 :          16 :           call = build_call_expr (fn, 0);
    1016                 :          16 :           if (ctor_p)
    1017                 :           8 :             DECL_STATIC_CONSTRUCTOR (fn) = 0;
    1018                 :             :           else
    1019                 :           8 :             DECL_STATIC_DESTRUCTOR (fn) = 0;
    1020                 :             :           /* We do not want to optimize away pure/const calls here.
    1021                 :             :              When optimizing, these should be already removed, when not
    1022                 :             :              optimizing, we want user to be able to breakpoint in them.  */
    1023                 :          16 :           TREE_SIDE_EFFECTS (call) = 1;
    1024                 :          16 :           append_to_statement_list (call, &body);
    1025                 :             :         }
    1026                 :           8 :       gcc_assert (body != NULL_TREE);
    1027                 :             :       /* Generate a function to call all the function of like
    1028                 :             :          priority.  */
    1029                 :          16 :       cgraph_build_static_cdtor_1 (ctor_p ? 'I' : 'D', body, priority, true,
    1030                 :           8 :                                    DECL_FUNCTION_SPECIFIC_OPTIMIZATION (cdtors[0]),
    1031                 :           8 :                                    DECL_FUNCTION_SPECIFIC_TARGET (cdtors[0]));
    1032                 :             :     }
    1033                 :          72 : }
    1034                 :             : 
    1035                 :             : /* Helper functions for build_cxa_dtor_registrations ().
    1036                 :             :    Build a decl for __cxa_atexit ().  */
    1037                 :             : 
    1038                 :             : static tree
    1039                 :           0 : build_cxa_atexit_decl ()
    1040                 :             : {
    1041                 :             :   /* The parameter to "__cxa_atexit" is "void (*)(void *)".  */
    1042                 :           0 :   tree fn_type = build_function_type_list (void_type_node,
    1043                 :             :                                            ptr_type_node, NULL_TREE);
    1044                 :           0 :   tree fn_ptr_type = build_pointer_type (fn_type);
    1045                 :             :   /* The declaration for `__cxa_atexit' is:
    1046                 :             :      int __cxa_atexit (void (*)(void *), void *, void *).  */
    1047                 :           0 :   const char *name = "__cxa_atexit";
    1048                 :           0 :   tree cxa_name = get_identifier (name);
    1049                 :           0 :   fn_type = build_function_type_list (integer_type_node, fn_ptr_type,
    1050                 :             :                                       ptr_type_node, ptr_type_node, NULL_TREE);
    1051                 :           0 :   tree atexit_fndecl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
    1052                 :             :                                    cxa_name, fn_type);
    1053                 :           0 :   SET_DECL_ASSEMBLER_NAME (atexit_fndecl, cxa_name);
    1054                 :           0 :   DECL_VISIBILITY (atexit_fndecl) = VISIBILITY_DEFAULT;
    1055                 :           0 :   DECL_VISIBILITY_SPECIFIED (atexit_fndecl) = true;
    1056                 :           0 :   set_call_expr_flags (atexit_fndecl, ECF_LEAF | ECF_NOTHROW);
    1057                 :           0 :   TREE_PUBLIC (atexit_fndecl) = true;
    1058                 :           0 :   DECL_EXTERNAL (atexit_fndecl) = true;
    1059                 :           0 :   DECL_ARTIFICIAL (atexit_fndecl) = true;
    1060                 :           0 :   return atexit_fndecl;
    1061                 :             : }
    1062                 :             : 
    1063                 :             : /* Build a decl for __dso_handle.  */
    1064                 :             : 
    1065                 :             : static tree
    1066                 :           0 : build_dso_handle_decl ()
    1067                 :             : {
    1068                 :             :   /* Declare the __dso_handle variable.  */
    1069                 :           0 :   tree dso_handle_decl = build_decl (UNKNOWN_LOCATION, VAR_DECL,
    1070                 :             :                                      get_identifier ("__dso_handle"),
    1071                 :             :                                      ptr_type_node);
    1072                 :           0 :   TREE_PUBLIC (dso_handle_decl) = true;
    1073                 :           0 :   DECL_EXTERNAL (dso_handle_decl) = true;
    1074                 :           0 :   DECL_ARTIFICIAL (dso_handle_decl) = true;
    1075                 :             : #ifdef HAVE_GAS_HIDDEN
    1076                 :           0 :   if (dso_handle_decl != error_mark_node)
    1077                 :             :     {
    1078                 :           0 :       DECL_VISIBILITY (dso_handle_decl) = VISIBILITY_HIDDEN;
    1079                 :           0 :       DECL_VISIBILITY_SPECIFIED (dso_handle_decl) = true;
    1080                 :             :     }
    1081                 :             : #endif
    1082                 :           0 :   return dso_handle_decl;
    1083                 :             : }
    1084                 :             : 
    1085                 :             : /*  This builds one or more constructor functions that register DTORs with
    1086                 :             :     __cxa_atexit ().  Within a priority level, DTORs are registered in TU
    1087                 :             :     order - which means that they will run in reverse TU order from cxa_atexit.
    1088                 :             :     This is the same behavior as using a .fini / .mod_term_funcs section.
    1089                 :             :     As the functions are built, they are appended to the CTORs vector.  */
    1090                 :             : 
    1091                 :             : static void
    1092                 :           0 : build_cxa_dtor_registrations (const vec<tree> &dtors, vec<tree> *ctors)
    1093                 :             : {
    1094                 :           0 :   size_t i,j;
    1095                 :           0 :   size_t len = dtors.length ();
    1096                 :             : 
    1097                 :           0 :   location_t sav_loc = input_location;
    1098                 :           0 :   input_location = UNKNOWN_LOCATION;
    1099                 :             : 
    1100                 :           0 :   tree atexit_fndecl = build_cxa_atexit_decl ();
    1101                 :           0 :   tree dso_handle_decl = build_dso_handle_decl ();
    1102                 :             : 
    1103                 :             :   /* We want &__dso_handle.  */
    1104                 :           0 :   tree dso_ptr = build1_loc (UNKNOWN_LOCATION, ADDR_EXPR,
    1105                 :             :                              ptr_type_node, dso_handle_decl);
    1106                 :             : 
    1107                 :           0 :   i = 0;
    1108                 :           0 :   while (i < len)
    1109                 :             :     {
    1110                 :           0 :       priority_type priority = 0;
    1111                 :           0 :       tree body = NULL_TREE;
    1112                 :           0 :       j = i;
    1113                 :           0 :       do
    1114                 :             :         {
    1115                 :           0 :           priority_type p;
    1116                 :           0 :           tree fn = dtors[j];
    1117                 :           0 :           p = DECL_FINI_PRIORITY (fn);
    1118                 :           0 :           if (j == i)
    1119                 :             :             priority = p;
    1120                 :           0 :           else if (p != priority)
    1121                 :             :             break;
    1122                 :           0 :           j++;
    1123                 :             :         }
    1124                 :           0 :       while (j < len);
    1125                 :             : 
    1126                 :             :       /* Find the next batch of destructors with the same initialization
    1127                 :             :          priority.  */
    1128                 :           0 :       for (;i < j; i++)
    1129                 :             :         {
    1130                 :           0 :           tree fn = dtors[i];
    1131                 :           0 :           DECL_STATIC_DESTRUCTOR (fn) = 0;
    1132                 :           0 :           tree dtor_ptr = build1_loc (UNKNOWN_LOCATION, ADDR_EXPR,
    1133                 :             :                                       ptr_type_node, fn);
    1134                 :           0 :           tree call_cxa_atexit
    1135                 :           0 :             = build_call_expr_loc (UNKNOWN_LOCATION, atexit_fndecl, 3,
    1136                 :             :                                    dtor_ptr, null_pointer_node, dso_ptr);
    1137                 :           0 :           TREE_SIDE_EFFECTS (call_cxa_atexit) = 1;
    1138                 :           0 :           append_to_statement_list (call_cxa_atexit, &body);
    1139                 :             :         }
    1140                 :             : 
    1141                 :           0 :       gcc_assert (body != NULL_TREE);
    1142                 :             :       /* Generate a function to register the DTORs at this priority.  */
    1143                 :           0 :       tree new_ctor
    1144                 :           0 :         = cgraph_build_static_cdtor_1 ('I', body, priority, true,
    1145                 :           0 :                                        DECL_FUNCTION_SPECIFIC_OPTIMIZATION (dtors[0]),
    1146                 :           0 :                                        DECL_FUNCTION_SPECIFIC_TARGET (dtors[0]));
    1147                 :             :       /* Add this to the list of ctors.  */
    1148                 :           0 :       ctors->safe_push (new_ctor);
    1149                 :             :     }
    1150                 :           0 :   input_location = sav_loc;
    1151                 :           0 : }
    1152                 :             : 
    1153                 :             : /* Comparison function for qsort.  P1 and P2 are actually of type
    1154                 :             :    "tree *" and point to static constructors.  DECL_INIT_PRIORITY is
    1155                 :             :    used to determine the sort order.  */
    1156                 :             : 
    1157                 :             : static int
    1158                 :          96 : compare_ctor (const void *p1, const void *p2)
    1159                 :             : {
    1160                 :          96 :   tree f1;
    1161                 :          96 :   tree f2;
    1162                 :          96 :   int priority1;
    1163                 :          96 :   int priority2;
    1164                 :             : 
    1165                 :          96 :   f1 = *(const tree *)p1;
    1166                 :          96 :   f2 = *(const tree *)p2;
    1167                 :          96 :   priority1 = DECL_INIT_PRIORITY (f1);
    1168                 :          96 :   priority2 = DECL_INIT_PRIORITY (f2);
    1169                 :             : 
    1170                 :          96 :   if (priority1 < priority2)
    1171                 :             :     return -1;
    1172                 :          40 :   else if (priority1 > priority2)
    1173                 :             :     return 1;
    1174                 :             :   else
    1175                 :             :     /* Ensure a stable sort.  Constructors are executed in backwarding
    1176                 :             :        order to make LTO initialize braries first.  */
    1177                 :          16 :     return DECL_UID (f2) - DECL_UID (f1);
    1178                 :             : }
    1179                 :             : 
    1180                 :             : /* Comparison function for qsort.  P1 and P2 are actually of type
    1181                 :             :    "tree *" and point to static destructors.  DECL_FINI_PRIORITY is
    1182                 :             :    used to determine the sort order.  */
    1183                 :             : 
    1184                 :             : static int
    1185                 :          96 : compare_dtor (const void *p1, const void *p2)
    1186                 :             : {
    1187                 :          96 :   tree f1;
    1188                 :          96 :   tree f2;
    1189                 :          96 :   int priority1;
    1190                 :          96 :   int priority2;
    1191                 :             : 
    1192                 :          96 :   f1 = *(const tree *)p1;
    1193                 :          96 :   f2 = *(const tree *)p2;
    1194                 :          96 :   priority1 = DECL_FINI_PRIORITY (f1);
    1195                 :          96 :   priority2 = DECL_FINI_PRIORITY (f2);
    1196                 :             : 
    1197                 :          96 :   if (priority1 < priority2)
    1198                 :             :     return -1;
    1199                 :          40 :   else if (priority1 > priority2)
    1200                 :             :     return 1;
    1201                 :             :   else
    1202                 :             :     /* Ensure a stable sort - into TU order.  */
    1203                 :          16 :     return DECL_UID (f1) - DECL_UID (f2);
    1204                 :             : }
    1205                 :             : 
    1206                 :             : /* Comparison function for qsort.  P1 and P2 are of type "tree *" and point to
    1207                 :             :    a pair of static constructors or destructors.  We first sort on the basis of
    1208                 :             :    priority and then into TU order (on the strict assumption that DECL_UIDs are
    1209                 :             :    ordered in the same way as the original functions).  ???: this seems quite
    1210                 :             :    fragile. */
    1211                 :             : 
    1212                 :             : static int
    1213                 :           0 : compare_cdtor_tu_order (const void *p1, const void *p2)
    1214                 :             : {
    1215                 :           0 :   tree f1;
    1216                 :           0 :   tree f2;
    1217                 :           0 :   int priority1;
    1218                 :           0 :   int priority2;
    1219                 :             : 
    1220                 :           0 :   f1 = *(const tree *)p1;
    1221                 :           0 :   f2 = *(const tree *)p2;
    1222                 :             :   /* We process the DTORs first, and then remove their flag, so this order
    1223                 :             :      allows for functions that are declared as both CTOR and DTOR.  */
    1224                 :           0 :   if (DECL_STATIC_DESTRUCTOR (f1))
    1225                 :             :     {
    1226                 :           0 :       gcc_checking_assert (DECL_STATIC_DESTRUCTOR (f2));
    1227                 :           0 :       priority1 = DECL_FINI_PRIORITY (f1);
    1228                 :           0 :       priority2 = DECL_FINI_PRIORITY (f2);
    1229                 :             :     }
    1230                 :             :   else
    1231                 :             :     {
    1232                 :           0 :       priority1 = DECL_INIT_PRIORITY (f1);
    1233                 :           0 :       priority2 = DECL_INIT_PRIORITY (f2);
    1234                 :             :     }
    1235                 :             : 
    1236                 :           0 :   if (priority1 < priority2)
    1237                 :             :     return -1;
    1238                 :           0 :   else if (priority1 > priority2)
    1239                 :             :     return 1;
    1240                 :             :   else
    1241                 :             :     /* For equal priority, sort into the order of definition in the TU.  */
    1242                 :           0 :     return DECL_UID (f1) - DECL_UID (f2);
    1243                 :             : }
    1244                 :             : 
    1245                 :             : /* Generate functions to call static constructors and destructors
    1246                 :             :    for targets that do not support .ctors/.dtors sections.  These
    1247                 :             :    functions have magic names which are detected by collect2.  */
    1248                 :             : 
    1249                 :             : static void
    1250                 :       13227 : build_cdtor_fns (vec<tree> *ctors, vec<tree> *dtors)
    1251                 :             : {
    1252                 :       13227 :   if (!ctors->is_empty ())
    1253                 :             :     {
    1254                 :          59 :       gcc_assert (!targetm.have_ctors_dtors || in_lto_p);
    1255                 :          59 :       ctors->qsort (compare_ctor);
    1256                 :          59 :       build_cdtor (/*ctor_p=*/true, *ctors);
    1257                 :             :     }
    1258                 :             : 
    1259                 :       13227 :   if (!dtors->is_empty ())
    1260                 :             :     {
    1261                 :          13 :       gcc_assert (!targetm.have_ctors_dtors || in_lto_p);
    1262                 :          13 :       dtors->qsort (compare_dtor);
    1263                 :          13 :       build_cdtor (/*ctor_p=*/false, *dtors);
    1264                 :             :     }
    1265                 :       13227 : }
    1266                 :             : 
    1267                 :             : /* Generate new CTORs to register static destructors with __cxa_atexit and add
    1268                 :             :    them to the existing list of CTORs; we then process the revised CTORs list.
    1269                 :             : 
    1270                 :             :    We sort the DTORs into priority and then TU order, this means that they are
    1271                 :             :    registered in that order with __cxa_atexit () and therefore will be run in
    1272                 :             :    the reverse order.
    1273                 :             : 
    1274                 :             :    Likewise, CTORs are sorted into priority and then TU order, which means that
    1275                 :             :    they will run in that order.
    1276                 :             : 
    1277                 :             :    This matches the behavior of using init/fini or mod_init_func/mod_term_func
    1278                 :             :    sections.  */
    1279                 :             : 
    1280                 :             : static void
    1281                 :           0 : build_cxa_atexit_fns (vec<tree> *ctors, vec<tree> *dtors)
    1282                 :             : {
    1283                 :           0 :   if (!dtors->is_empty ())
    1284                 :             :     {
    1285                 :           0 :       gcc_assert (targetm.dtors_from_cxa_atexit);
    1286                 :           0 :       dtors->qsort (compare_cdtor_tu_order);
    1287                 :           0 :       build_cxa_dtor_registrations (*dtors, ctors);
    1288                 :             :     }
    1289                 :             : 
    1290                 :           0 :   if (!ctors->is_empty ())
    1291                 :             :     {
    1292                 :           0 :       gcc_assert (targetm.dtors_from_cxa_atexit);
    1293                 :           0 :       ctors->qsort (compare_cdtor_tu_order);
    1294                 :           0 :       build_cdtor (/*ctor_p=*/true, *ctors);
    1295                 :             :     }
    1296                 :           0 : }
    1297                 :             : 
    1298                 :             : /* Look for constructors and destructors and produce function calling them.
    1299                 :             :    This is needed for targets not supporting ctors or dtors, but we perform the
    1300                 :             :    transformation also at linktime to merge possibly numerous
    1301                 :             :    constructors/destructors into single function to improve code locality and
    1302                 :             :    reduce size.  */
    1303                 :             : 
    1304                 :             : static unsigned int
    1305                 :       13227 : ipa_cdtor_merge (void)
    1306                 :             : {
    1307                 :             :   /* A vector of FUNCTION_DECLs declared as static constructors.  */
    1308                 :       13227 :   auto_vec<tree, 20> ctors;
    1309                 :             :   /* A vector of FUNCTION_DECLs declared as static destructors.  */
    1310                 :       13227 :   auto_vec<tree, 20> dtors;
    1311                 :       13227 :   struct cgraph_node *node;
    1312                 :       92277 :   FOR_EACH_DEFINED_FUNCTION (node)
    1313                 :       79050 :     if (DECL_STATIC_CONSTRUCTOR (node->decl)
    1314                 :       79050 :         || DECL_STATIC_DESTRUCTOR (node->decl))
    1315                 :         100 :        record_cdtor_fn (node, &ctors, &dtors);
    1316                 :       13227 :   if (targetm.dtors_from_cxa_atexit)
    1317                 :           0 :     build_cxa_atexit_fns (&ctors, &dtors);
    1318                 :             :   else
    1319                 :       13227 :     build_cdtor_fns (&ctors, &dtors);
    1320                 :       13227 :   return 0;
    1321                 :       13227 : }
    1322                 :             : 
    1323                 :             : namespace {
    1324                 :             : 
    1325                 :             : const pass_data pass_data_ipa_cdtor_merge =
    1326                 :             : {
    1327                 :             :   IPA_PASS, /* type */
    1328                 :             :   "cdtor", /* name */
    1329                 :             :   OPTGROUP_NONE, /* optinfo_flags */
    1330                 :             :   TV_CGRAPHOPT, /* tv_id */
    1331                 :             :   0, /* properties_required */
    1332                 :             :   0, /* properties_provided */
    1333                 :             :   0, /* properties_destroyed */
    1334                 :             :   0, /* todo_flags_start */
    1335                 :             :   0, /* todo_flags_finish */
    1336                 :             : };
    1337                 :             : 
    1338                 :             : class pass_ipa_cdtor_merge : public ipa_opt_pass_d
    1339                 :             : {
    1340                 :             : public:
    1341                 :      289080 :   pass_ipa_cdtor_merge (gcc::context *ctxt)
    1342                 :             :     : ipa_opt_pass_d (pass_data_ipa_cdtor_merge, ctxt,
    1343                 :             :                       NULL, /* generate_summary */
    1344                 :             :                       NULL, /* write_summary */
    1345                 :             :                       NULL, /* read_summary */
    1346                 :             :                       NULL, /* write_optimization_summary */
    1347                 :             :                       NULL, /* read_optimization_summary */
    1348                 :             :                       NULL, /* stmt_fixup */
    1349                 :             :                       0, /* function_transform_todo_flags_start */
    1350                 :             :                       NULL, /* function_transform */
    1351                 :      289080 :                       NULL) /* variable_transform */
    1352                 :      289080 :   {}
    1353                 :             : 
    1354                 :             :   /* opt_pass methods: */
    1355                 :             :   bool gate (function *) final override;
    1356                 :       13227 :   unsigned int execute (function *) final override
    1357                 :             :   {
    1358                 :       13227 :     return ipa_cdtor_merge ();
    1359                 :             :   }
    1360                 :             : 
    1361                 :             : }; // class pass_ipa_cdtor_merge
    1362                 :             : 
    1363                 :             : bool
    1364                 :      568632 : pass_ipa_cdtor_merge::gate (function *)
    1365                 :             : {
    1366                 :             :   /* Perform the pass when we have no ctors/dtors support
    1367                 :             :      or at LTO time to merge multiple constructors into single
    1368                 :             :      function.  */
    1369                 :      568632 :   return !targetm.have_ctors_dtors || in_lto_p || targetm.dtors_from_cxa_atexit;
    1370                 :             : }
    1371                 :             : 
    1372                 :             : } // anon namespace
    1373                 :             : 
    1374                 :             : ipa_opt_pass_d *
    1375                 :      289080 : make_pass_ipa_cdtor_merge (gcc::context *ctxt)
    1376                 :             : {
    1377                 :      289080 :   return new pass_ipa_cdtor_merge (ctxt);
    1378                 :             : }
    1379                 :             : 
    1380                 :             : /* Invalid pointer representing BOTTOM for single user dataflow.  */
    1381                 :             : #define BOTTOM ((cgraph_node *)(size_t) 2)
    1382                 :             : 
    1383                 :             : /* Meet operation for single user dataflow.
    1384                 :             :    Here we want to associate variables with sigle function that may access it.
    1385                 :             : 
    1386                 :             :    FUNCTION is current single user of a variable, VAR is variable that uses it.
    1387                 :             :    Latttice is stored in SINGLE_USER_MAP.
    1388                 :             : 
    1389                 :             :    We represent:
    1390                 :             :     - TOP by no entry in SIGNLE_USER_MAP
    1391                 :             :     - BOTTOM by BOTTOM in AUX pointer (to save lookups)
    1392                 :             :     - known single user by cgraph pointer in SINGLE_USER_MAP.  */
    1393                 :             : 
    1394                 :             : cgraph_node *
    1395                 :     3437268 : meet (cgraph_node *function, varpool_node *var,
    1396                 :             :        hash_map<varpool_node *, cgraph_node *> &single_user_map)
    1397                 :             : {
    1398                 :     3437268 :   struct cgraph_node *user, **f;
    1399                 :             : 
    1400                 :     3437268 :   if (var->aux == BOTTOM)
    1401                 :             :     return BOTTOM;
    1402                 :             : 
    1403                 :     2454775 :   f = single_user_map.get (var);
    1404                 :     2454775 :   if (!f)
    1405                 :             :     return function;
    1406                 :     1002824 :   user = *f;
    1407                 :     1002824 :   if (!function)
    1408                 :             :     return user;
    1409                 :      980984 :   else if (function != user)
    1410                 :             :     return BOTTOM;
    1411                 :             :   else
    1412                 :             :     return function;
    1413                 :             : }
    1414                 :             : 
    1415                 :             : /* Propagation step of single-use dataflow.
    1416                 :             : 
    1417                 :             :    Check all uses of VNODE and see if they are used by single function FUNCTION.
    1418                 :             :    SINGLE_USER_MAP represents the dataflow lattice.  */
    1419                 :             : 
    1420                 :             : cgraph_node *
    1421                 :     1783279 : propagate_single_user (varpool_node *vnode, cgraph_node *function,
    1422                 :             :                        hash_map<varpool_node *, cgraph_node *> &single_user_map)
    1423                 :             : {
    1424                 :     1783279 :   int i;
    1425                 :     1783279 :   struct ipa_ref *ref;
    1426                 :             : 
    1427                 :     1783279 :   gcc_assert (!vnode->externally_visible);
    1428                 :             : 
    1429                 :             :   /* If node is an alias, first meet with its target.  */
    1430                 :     1783279 :   if (vnode->alias)
    1431                 :       16240 :     function = meet (function, vnode->get_alias_target (), single_user_map);
    1432                 :             : 
    1433                 :             :   /* Check all users and see if they correspond to a single function.  */
    1434                 :     5813051 :   for (i = 0; vnode->iterate_referring (i, ref) && function != BOTTOM; i++)
    1435                 :             :     {
    1436                 :     8059544 :       struct cgraph_node *cnode = dyn_cast <cgraph_node *> (ref->referring);
    1437                 :     4029772 :       if (cnode)
    1438                 :             :         {
    1439                 :      608744 :           if (cnode->inlined_to)
    1440                 :       87154 :             cnode = cnode->inlined_to;
    1441                 :      608744 :           if (!function)
    1442                 :             :             function = cnode;
    1443                 :      308763 :           else if (function != cnode)
    1444                 :       24833 :             function = BOTTOM;
    1445                 :             :         }
    1446                 :             :       else
    1447                 :     6842056 :         function = meet (function, dyn_cast <varpool_node *> (ref->referring),
    1448                 :             :                          single_user_map);
    1449                 :             :     }
    1450                 :     1783279 :   return function;
    1451                 :             : }
    1452                 :             : 
    1453                 :             : /* Pass setting used_by_single_function flag.
    1454                 :             :    This flag is set on variable when there is only one function that may
    1455                 :             :    possibly referr to it.  */
    1456                 :             : 
    1457                 :             : static unsigned int
    1458                 :      230804 : ipa_single_use (void)
    1459                 :             : {
    1460                 :      230804 :   varpool_node *first = (varpool_node *) (void *) 1;
    1461                 :      230804 :   varpool_node *var;
    1462                 :      230804 :   hash_map<varpool_node *, cgraph_node *> single_user_map;
    1463                 :             : 
    1464                 :     3091345 :   FOR_EACH_DEFINED_VARIABLE (var)
    1465                 :     2860541 :     if (!var->all_refs_explicit_p ())
    1466                 :     1560512 :       var->aux = BOTTOM;
    1467                 :             :     else
    1468                 :             :       {
    1469                 :             :         /* Enqueue symbol for dataflow.  */
    1470                 :     1300029 :         var->aux = first;
    1471                 :     1300029 :         first = var;
    1472                 :             :       }
    1473                 :             : 
    1474                 :             :   /* The actual dataflow.  */
    1475                 :             : 
    1476                 :     2014083 :   while (first != (void *) 1)
    1477                 :             :     {
    1478                 :     1783279 :       cgraph_node *user, *orig_user, **f;
    1479                 :             : 
    1480                 :     1783279 :       var = first;
    1481                 :     1783279 :       first = (varpool_node *)first->aux;
    1482                 :             : 
    1483                 :     1783279 :       f = single_user_map.get (var);
    1484                 :     1783279 :       if (f)
    1485                 :       29107 :         orig_user = *f;
    1486                 :             :       else
    1487                 :             :         orig_user = NULL;
    1488                 :     1783279 :       user = propagate_single_user (var, orig_user, single_user_map);
    1489                 :             : 
    1490                 :     1783279 :       gcc_checking_assert (var->aux != BOTTOM);
    1491                 :             : 
    1492                 :             :       /* If user differs, enqueue all references.  */
    1493                 :     1783279 :       if (user != orig_user)
    1494                 :             :         {
    1495                 :     1306006 :           unsigned int i;
    1496                 :     1306006 :           ipa_ref *ref;
    1497                 :             : 
    1498                 :     1306006 :           single_user_map.put (var, user);
    1499                 :             : 
    1500                 :             :           /* Enqueue all aliases for re-processing.  */
    1501                 :     2626042 :           for (i = 0; var->iterate_direct_aliases (i, ref); i++)
    1502                 :       14030 :             if (!ref->referring->aux)
    1503                 :             :               {
    1504                 :        4050 :                 ref->referring->aux = first;
    1505                 :       14030 :                 first = dyn_cast <varpool_node *> (ref->referring);
    1506                 :             :               }
    1507                 :             :           /* Enqueue all users for re-processing.  */
    1508                 :     5214776 :           for (i = 0; var->iterate_reference (i, ref); i++)
    1509                 :     1301382 :             if (!ref->referred->aux
    1510                 :      732734 :                 && ref->referred->definition
    1511                 :     2513316 :                 && is_a <varpool_node *> (ref->referred))
    1512                 :             :               {
    1513                 :      479200 :                 ref->referred->aux = first;
    1514                 :      479200 :                 first = dyn_cast <varpool_node *> (ref->referred);
    1515                 :             :               }
    1516                 :             : 
    1517                 :             :           /* If user is BOTTOM, just punt on this var.  */
    1518                 :     1306006 :           if (user == BOTTOM)
    1519                 :     1011002 :             var->aux = BOTTOM;
    1520                 :             :           else
    1521                 :      295004 :             var->aux = NULL;
    1522                 :             :         }
    1523                 :             :       else
    1524                 :      477273 :         var->aux = NULL;
    1525                 :             :     }
    1526                 :             : 
    1527                 :     3091345 :   FOR_EACH_DEFINED_VARIABLE (var)
    1528                 :             :     {
    1529                 :     2860541 :       if (var->aux != BOTTOM)
    1530                 :             :         {
    1531                 :             :           /* Not having the single user known means that the VAR is
    1532                 :             :              unreachable.  Either someone forgot to remove unreachable
    1533                 :             :              variables or the reachability here is wrong.  */
    1534                 :             : 
    1535                 :      289027 :           gcc_checking_assert (single_user_map.get (var));
    1536                 :             : 
    1537                 :      289027 :           if (dump_file)
    1538                 :             :             {
    1539                 :          10 :               fprintf (dump_file, "Variable %s is used by single function\n",
    1540                 :             :                        var->dump_name ());
    1541                 :             :             }
    1542                 :      289027 :           var->used_by_single_function = true;
    1543                 :             :         }
    1544                 :     2860541 :       var->aux = NULL;
    1545                 :             :     }
    1546                 :      230804 :   return 0;
    1547                 :      230804 : }
    1548                 :             : 
    1549                 :             : namespace {
    1550                 :             : 
    1551                 :             : const pass_data pass_data_ipa_single_use =
    1552                 :             : {
    1553                 :             :   IPA_PASS, /* type */
    1554                 :             :   "single-use", /* name */
    1555                 :             :   OPTGROUP_NONE, /* optinfo_flags */
    1556                 :             :   TV_CGRAPHOPT, /* tv_id */
    1557                 :             :   0, /* properties_required */
    1558                 :             :   0, /* properties_provided */
    1559                 :             :   0, /* properties_destroyed */
    1560                 :             :   0, /* todo_flags_start */
    1561                 :             :   0, /* todo_flags_finish */
    1562                 :             : };
    1563                 :             : 
    1564                 :             : class pass_ipa_single_use : public ipa_opt_pass_d
    1565                 :             : {
    1566                 :             : public:
    1567                 :      289080 :   pass_ipa_single_use (gcc::context *ctxt)
    1568                 :             :     : ipa_opt_pass_d (pass_data_ipa_single_use, ctxt,
    1569                 :             :                       NULL, /* generate_summary */
    1570                 :             :                       NULL, /* write_summary */
    1571                 :             :                       NULL, /* read_summary */
    1572                 :             :                       NULL, /* write_optimization_summary */
    1573                 :             :                       NULL, /* read_optimization_summary */
    1574                 :             :                       NULL, /* stmt_fixup */
    1575                 :             :                       0, /* function_transform_todo_flags_start */
    1576                 :             :                       NULL, /* function_transform */
    1577                 :      289080 :                       NULL) /* variable_transform */
    1578                 :      289080 :   {}
    1579                 :             : 
    1580                 :             :   /* opt_pass methods: */
    1581                 :      230804 :   unsigned int execute (function *) final override { return ipa_single_use (); }
    1582                 :             : 
    1583                 :             : }; // class pass_ipa_single_use
    1584                 :             : 
    1585                 :             : } // anon namespace
    1586                 :             : 
    1587                 :             : ipa_opt_pass_d *
    1588                 :      289080 : make_pass_ipa_single_use (gcc::context *ctxt)
    1589                 :             : {
    1590                 :      289080 :   return new pass_ipa_single_use (ctxt);
    1591                 :             : }
    1592                 :             : 
        

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.