LCOV - code coverage report
Current view: top level - gcc - ipa-visibility.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 95.5 % 404 386
Test Date: 2026-02-28 14:20:25 Functions: 100.0 % 20 20
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /* IPA visibility pass
       2              :    Copyright (C) 2003-2026 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              : /* This file implements two related passes:
      21              : 
      22              :      - pass_data_ipa_function_and_variable_visibility run just after
      23              :        symbol table, references and callgraph are built
      24              : 
      25              :      - pass_data_ipa_function_and_variable_visibility run as first
      26              :        proper IPA pass (that is after early optimization, or, (with LTO)
      27              :        as a first pass done at link-time.
      28              : 
      29              :    Purpose of both passes is to set correctly visibility properties
      30              :    of all symbols.  This includes:
      31              : 
      32              :     - Symbol privatization:
      33              : 
      34              :       Some symbols that are declared public by frontend may be
      35              :       turned local (either by -fwhole-program flag, by linker plugin feedback
      36              :       or by other reasons)
      37              : 
      38              :     - Discovery of local functions:
      39              : 
      40              :       A local function is one whose calls can occur only in the current
      41              :       compilation unit and all its calls are explicit, so we can change
      42              :       its calling convention.  We simply mark all static functions whose
      43              :       address is not taken as local.
      44              : 
      45              :       externally_visible flag is set for symbols that cannot be privatized.
      46              :       For privatized symbols we clear TREE_PUBLIC flag and dismantle comdat
      47              :       group.
      48              : 
      49              :     - Dismantling of comdat groups:
      50              : 
      51              :       Comdat group represent a section that may be replaced by linker by
      52              :       a different copy of the same section from other unit.
      53              :       If we have resolution information (from linker plugin) and we know that
      54              :       a given comdat gorup is prevailing, we can dismantle it and turn symbols
      55              :       into normal symbols.  If the resolution information says that the
      56              :       section was previaled by copy from non-LTO code, we can also dismantle
      57              :       it and turn all symbols into external.
      58              : 
      59              :     - Local aliases:
      60              : 
      61              :       Some symbols can be interposed by dynamic linker. Refering to these
      62              :       symbols is expensive, since it needs to be overwritable by the dynamic
      63              :       linker.  In some cases we know that the interposition does not change
      64              :       semantic and we can always refer to a local copy (as in the case of
      65              :       inline function).  In this case we produce a local alias and redirect
      66              :       calls to it.
      67              : 
      68              :       TODO: This should be done for references, too.
      69              : 
      70              :     - Removal of static ocnstructors and destructors that have no side effects.
      71              : 
      72              :     - Regularization of several oddities introduced by frontends that may
      73              :       be impractical later in the optimization queue.  */
      74              : 
      75              : #include "config.h"
      76              : #include "system.h"
      77              : #include "coretypes.h"
      78              : #include "tm.h"
      79              : #include "function.h"
      80              : #include "tree.h"
      81              : #include "gimple-expr.h"
      82              : #include "tree-pass.h"
      83              : #include "cgraph.h"
      84              : #include "calls.h"
      85              : #include "varasm.h"
      86              : #include "ipa-utils.h"
      87              : #include "stringpool.h"
      88              : #include "attribs.h"
      89              : 
      90              : /* Return true when NODE cannot be local. Worker for cgraph_local_node_p.  */
      91              : 
      92              : static bool
      93      5022474 : non_local_p (struct cgraph_node *node, void *data ATTRIBUTE_UNUSED)
      94              : {
      95      5022474 :   return !(node->only_called_directly_or_aliased_p ()
      96              :            /* i386 would need update to output thunk with local calling
      97              :               conventions.  */
      98       386823 :            && !node->thunk
      99       386823 :            && node->definition
     100       386821 :            && !DECL_EXTERNAL (node->decl)
     101       257272 :            && !lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl))
     102       256221 :            && !node->externally_visible
     103       256221 :            && !node->used_from_other_partition
     104       256221 :            && !node->in_other_partition
     105       256221 :            && node->get_availability () >= AVAIL_AVAILABLE
     106       256221 :            && !DECL_STATIC_CONSTRUCTOR (node->decl)
     107       256221 :            && !DECL_STATIC_DESTRUCTOR (node->decl));
     108              : }
     109              : 
     110              : /* Return true when function can be marked local.  */
     111              : 
     112              : bool
     113      4975176 : cgraph_node::local_p (void)
     114              : {
     115      4981157 :    cgraph_node *n = ultimate_alias_target ();
     116              : 
     117      4981157 :    if (n->thunk)
     118         5981 :      return n->callees->callee->local_p ();
     119      4975176 :    return !n->call_for_symbol_thunks_and_aliases (non_local_p,
     120      4975176 :                                                   NULL, true);
     121              : }
     122              : 
     123              : /* A helper for comdat_can_be_unshared_p.  */
     124              : 
     125              : static bool
     126         2084 : comdat_can_be_unshared_p_1 (symtab_node *node)
     127              : {
     128         2084 :   if (!node->externally_visible)
     129              :     return true;
     130         1838 :   if (node->address_can_be_compared_p ())
     131              :     {
     132              :       struct ipa_ref *ref;
     133              : 
     134         1188 :       for (unsigned int i = 0; node->iterate_referring (i, ref); i++)
     135          620 :         if (ref->address_matters_p ())
     136          454 :           return false;
     137              :     }
     138              : 
     139              :   /* If the symbol is used in some weird way, better to not touch it.  */
     140         1384 :   if (node->force_output)
     141              :     return false;
     142              : 
     143              :   /* Explicit instantiations needs to be output when possibly
     144              :      used externally.  */
     145         1384 :   if (node->forced_by_abi
     146           58 :       && TREE_PUBLIC (node->decl)
     147           58 :       && (node->resolution != LDPR_PREVAILING_DEF_IRONLY
     148           58 :           && !flag_whole_program))
     149              :     return false;
     150              : 
     151              :   /* Non-readonly and volatile variables cannot be duplicated.  */
     152              :   if (is_a <varpool_node *> (node)
     153          198 :       && (!TREE_READONLY (node->decl)
     154          195 :           || TREE_THIS_VOLATILE (node->decl)))
     155              :     return false;
     156              :   return true;
     157              : }
     158              : 
     159              : /* COMDAT functions must be shared only if they have address taken,
     160              :    otherwise we can produce our own private implementation with
     161              :    -fwhole-program.
     162              :    Return true when turning COMDAT function static cannot lead to wrong
     163              :    code when the resulting object links with a library defining same COMDAT.
     164              : 
     165              :    Virtual functions do have their addresses taken from the vtables,
     166              :    but in C++ there is no way to compare their addresses for equality.  */
     167              : 
     168              : static bool
     169         1587 : comdat_can_be_unshared_p (symtab_node *node)
     170              : {
     171         1587 :   if (!comdat_can_be_unshared_p_1 (node))
     172              :     return false;
     173         1078 :   if (node->same_comdat_group)
     174              :     {
     175              :       symtab_node *next;
     176              : 
     177              :       /* If more than one function is in the same COMDAT group, it must
     178              :          be shared even if just one function in the comdat group has
     179              :          address taken.  */
     180          497 :       for (next = node->same_comdat_group;
     181          843 :            next != node; next = next->same_comdat_group)
     182          497 :         if (!comdat_can_be_unshared_p_1 (next))
     183              :           return false;
     184              :     }
     185              :   return true;
     186              : }
     187              : 
     188              : /* Return true when function NODE should be considered externally visible.  */
     189              : 
     190              : static bool
     191      8551532 : cgraph_externally_visible_p (struct cgraph_node *node,
     192              :                              bool whole_program)
     193              : {
     194      8551581 :   while (node->transparent_alias && node->definition)
     195           49 :     node = node->get_alias_target ();
     196      8551532 :   if (!node->definition)
     197              :     return false;
     198      5086319 :   if (!TREE_PUBLIC (node->decl)
     199      5086319 :       || DECL_EXTERNAL (node->decl))
     200              :     return false;
     201      4271087 :   if (node->ref_by_asm)
     202              :     return true;
     203              : 
     204              :   /* Do not try to localize built-in functions yet.  One of problems is that we
     205              :      end up mangling their asm for WHOPR that makes it impossible to call them
     206              :      using the implicit built-in declarations anymore.  Similarly this enables
     207              :      us to remove them as unreachable before actual calls may appear during
     208              :      expansion or folding.  */
     209      4271052 :   if (fndecl_built_in_p (node->decl))
     210              :     return true;
     211              : 
     212              :   /* If linker counts on us, we must preserve the function.  */
     213      4260537 :   if (node->used_from_object_file_p ())
     214              :     return true;
     215      4252892 :   if (DECL_PRESERVE_P (node->decl))
     216              :     return true;
     217      4245270 :   if (lookup_attribute ("externally_visible",
     218      4245270 :                         DECL_ATTRIBUTES (node->decl)))
     219              :     return true;
     220      4192683 :   if (lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     221              :     return true;
     222              :   if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
     223              :       && lookup_attribute ("dllexport",
     224              :                            DECL_ATTRIBUTES (node->decl)))
     225              :     return true;
     226              : 
     227              :   /* Limitation of gas requires us to output targets of symver aliases as
     228              :      global symbols.  This is binutils PR 25295.  */
     229              :   ipa_ref *ref;
     230      4555178 :   FOR_EACH_ALIAS (node, ref)
     231       400011 :     if (ref->referring->symver)
     232              :       return true;
     233              : 
     234      4155167 :   if (node->resolution == LDPR_PREVAILING_DEF_IRONLY)
     235              :     return false;
     236              :   /* When doing LTO or whole program, we can bring COMDAT functions static.
     237              :      This improves code quality and we know we will duplicate them at most twice
     238              :      (in the case that we are not using plugin and link with object file
     239              :       implementing same COMDAT)  */
     240      4118283 :   if (((in_lto_p || whole_program) && !flag_incremental_link)
     241        31468 :       && DECL_COMDAT (node->decl)
     242      4119274 :       && comdat_can_be_unshared_p (node))
     243              :     return false;
     244              : 
     245              :   /* When doing link time optimizations, hidden symbols become local.  */
     246        30477 :   if ((in_lto_p && !flag_incremental_link)
     247        30223 :       && (DECL_VISIBILITY (node->decl) == VISIBILITY_HIDDEN
     248        30221 :           || DECL_VISIBILITY (node->decl) == VISIBILITY_INTERNAL)
     249              :       /* Be sure that node is defined in IR file, not in other object
     250              :          file.  In that case we don't set used_from_other_object_file.  */
     251      4117306 :       && node->definition)
     252              :     ;
     253      4117302 :   else if (!whole_program)
     254              :     return true;
     255              : 
     256          290 :   if (MAIN_NAME_P (DECL_NAME (node->decl)))
     257              :     return true;
     258              : 
     259              :   return false;
     260              : }
     261              : 
     262              : /* Return true when variable should be considered externally visible.  */
     263              : 
     264              : bool
     265      5856042 : varpool_node::externally_visible_p (void)
     266              : {
     267      5856050 :   while (transparent_alias && definition)
     268            8 :     return get_alias_target ()->externally_visible_p ();
     269      5856042 :   if (DECL_EXTERNAL (decl))
     270              :     return true;
     271              : 
     272      5837373 :   if (!TREE_PUBLIC (decl))
     273              :     return false;
     274      2952829 :   if (ref_by_asm)
     275              :     return true;
     276              : 
     277              :   /* If linker counts on us, we must preserve the function.  */
     278      2952765 :   if (used_from_object_file_p ())
     279              :     return true;
     280              : 
     281              :   /* Bringing TLS variables local may cause dynamic linker failures
     282              :      on limits of static TLS vars.  */
     283      2952754 :   if (DECL_THREAD_LOCAL_P (decl)
     284      2958809 :       && (DECL_TLS_MODEL (decl) != TLS_MODEL_EMULATED
     285         6055 :           && DECL_TLS_MODEL (decl) != TLS_MODEL_INITIAL_EXEC))
     286              :     return true;
     287              : 
     288      2946833 :   if (DECL_HARD_REGISTER (decl))
     289              :     return true;
     290      2946660 :   if (DECL_PRESERVE_P (decl))
     291              :     return true;
     292      2945287 :   if (lookup_attribute ("externally_visible",
     293      2945287 :                         DECL_ATTRIBUTES (decl)))
     294              :     return true;
     295              :   if (TARGET_DLLIMPORT_DECL_ATTRIBUTES
     296              :       && lookup_attribute ("dllexport",
     297              :                            DECL_ATTRIBUTES (decl)))
     298              :     return true;
     299              : 
     300              :   /* Limitation of gas requires us to output targets of symver aliases as
     301              :      global symbols.  This is binutils PR 25295.  */
     302              :   ipa_ref *ref;
     303      2945420 :   FOR_EACH_ALIAS (this, ref)
     304          204 :     if (ref->referring->symver)
     305              :       return true;
     306              : 
     307      2945216 :   if (resolution == LDPR_PREVAILING_DEF_IRONLY)
     308              :     return false;
     309              : 
     310              :   /* As a special case, the COMDAT virtual tables can be unshared.
     311              :      In LTO mode turn vtables into static variables.  The variable is readonly,
     312              :      so this does not enable more optimization, but referring static var
     313              :      is faster for dynamic linking.  Also this match logic hidding vtables
     314              :      from LTO symbol tables.  */
     315      2933263 :   if (((in_lto_p || flag_whole_program) && !flag_incremental_link)
     316         6520 :       && DECL_COMDAT (decl)
     317      2933859 :       && comdat_can_be_unshared_p (this))
     318              :     return false;
     319              : 
     320              :   /* When doing link time optimizations, hidden symbols become local.  */
     321         6393 :   if (in_lto_p && !flag_incremental_link
     322         6214 :       && (DECL_VISIBILITY (decl) == VISIBILITY_HIDDEN
     323         6213 :           || DECL_VISIBILITY (decl) == VISIBILITY_INTERNAL)
     324              :       /* Be sure that node is defined in IR file, not in other object
     325              :          file.  In that case we don't set used_from_other_object_file.  */
     326      2933165 :       && definition)
     327              :     ;
     328      2933163 :   else if (!flag_whole_program)
     329              :     return true;
     330              : 
     331              :   /* Do not attempt to privatize COMDATS by default.
     332              :      This would break linking with C++ libraries sharing
     333              :      inline definitions.
     334              : 
     335              :      FIXME: We can do so for readonly vars with no address taken and
     336              :      possibly also for vtables since no direct pointer comparsion is done.
     337              :      It might be interesting to do so to reduce linking overhead.  */
     338          240 :   if (DECL_COMDAT (decl) || DECL_WEAK (decl))
     339              :     return true;
     340              :   return false;
     341              : }
     342              : 
     343              : /* Return true if reference to NODE can be replaced by a local alias.
     344              :    Local aliases save dynamic linking overhead and enable more optimizations.
     345              :  */
     346              : 
     347              : static bool
     348      2982297 : can_replace_by_local_alias (symtab_node *node)
     349              : {
     350              :   /* If aliases aren't supported, we can't do replacement.  */
     351      2982297 :   if (!TARGET_SUPPORTS_ALIASES)
     352              :     return false;
     353              : 
     354              :   /* Weakrefs have a reason to be non-local.  Be sure we do not replace
     355              :      them.  */
     356      2982309 :   while (node->transparent_alias && node->definition && !node->weakref)
     357           12 :     node = node->get_alias_target ();
     358      2982297 :   if (node->weakref)
     359              :     return false;
     360              : 
     361      2982295 :   return (node->get_availability () > AVAIL_INTERPOSABLE
     362      2906010 :           && !decl_binds_to_current_def_p (node->decl)
     363      4935189 :           && !node->can_be_discarded_p ());
     364              : }
     365              : 
     366              : /* Return true if we can replace reference to NODE by local alias
     367              :    within a virtual table.  Generally we can replace function pointers
     368              :    and virtual table pointers.  */
     369              : 
     370              : static bool
     371       258223 : can_replace_by_local_alias_in_vtable (symtab_node *node)
     372              : {
     373       258223 :   if (is_a <varpool_node *> (node)
     374       143982 :       && !DECL_VIRTUAL_P (node->decl))
     375              :     return false;
     376       173780 :   return can_replace_by_local_alias (node);
     377              : }
     378              : 
     379              : /* walk_tree callback that rewrites initializer references.   */
     380              : 
     381              : static tree
     382           25 : update_vtable_references (tree *tp, int *walk_subtrees,
     383              :                           void *data ATTRIBUTE_UNUSED)
     384              : {
     385           25 :   if (VAR_OR_FUNCTION_DECL_P (*tp))
     386              :     {
     387            5 :       if (can_replace_by_local_alias_in_vtable (symtab_node::get (*tp)))
     388            4 :         *tp = symtab_node::get (*tp)->noninterposable_alias ()->decl;
     389            5 :       *walk_subtrees = 0;
     390              :     }
     391           20 :   else if (IS_TYPE_OR_DECL_P (*tp))
     392            0 :     *walk_subtrees = 0;
     393           25 :   return NULL;
     394              : }
     395              : 
     396              : /* In LTO we can remove COMDAT groups and weak symbols.
     397              :    Either turn them into normal symbols or external symbol depending on
     398              :    resolution info.  */
     399              : 
     400              : static void
     401     14405203 : update_visibility_by_resolution_info (symtab_node * node)
     402              : {
     403     14405203 :   bool define;
     404              : 
     405     14405203 :   if (!node->externally_visible
     406      7189957 :       || (!DECL_WEAK (node->decl) && !DECL_ONE_ONLY (node->decl))
     407     17231817 :       || node->resolution == LDPR_UNKNOWN)
     408     14404833 :     return;
     409              : 
     410          740 :   define = (node->resolution == LDPR_PREVAILING_DEF_IRONLY
     411              :             || node->resolution == LDPR_PREVAILING_DEF
     412          370 :             || node->resolution == LDPR_UNDEF
     413          370 :             || node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP);
     414              : 
     415              :   /* The linker decisions ought to agree in the whole group.  */
     416          370 :   if (node->same_comdat_group)
     417          108 :     for (symtab_node *next = node->same_comdat_group;
     418          176 :          next != node; next = next->same_comdat_group)
     419              :       {
     420          108 :         if (!next->externally_visible || next->transparent_alias)
     421            4 :           continue;
     422              : 
     423          104 :         bool same_def
     424          104 :           = define == (next->resolution == LDPR_PREVAILING_DEF_IRONLY
     425              :                        || next->resolution == LDPR_PREVAILING_DEF
     426              :                        || next->resolution == LDPR_UNDEF
     427          104 :                        || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP);
     428          104 :         gcc_assert (in_lto_p || same_def);
     429          104 :         if (!same_def)
     430              :           return;
     431              :       }
     432              : 
     433          370 :   if (node->same_comdat_group)
     434          108 :     for (symtab_node *next = node->same_comdat_group;
     435          176 :          next != node; next = next->same_comdat_group)
     436              :       {
     437              :         /* During incremental linking we need to keep symbol weak for future
     438              :            linking.  We can still drop definition if we know non-LTO world
     439              :            prevails.  */
     440          108 :         if (!flag_incremental_link)
     441              :           {
     442            8 :             DECL_WEAK (next->decl) = false;
     443            8 :             next->set_comdat_group (NULL);
     444              :           }
     445          108 :         if (!define)
     446              :           {
     447            0 :             if (next->externally_visible)
     448            0 :               DECL_EXTERNAL (next->decl) = true;
     449            0 :             next->set_comdat_group (NULL);
     450              :           }
     451              :       }
     452              : 
     453              :   /* During incremental linking we need to keep symbol weak for future
     454              :      linking.  We can still drop definition if we know non-LTO world prevails.  */
     455          370 :   if (!flag_incremental_link)
     456              :     {
     457          217 :       DECL_WEAK (node->decl) = false;
     458          217 :       node->set_comdat_group (NULL);
     459          217 :       node->dissolve_same_comdat_group_list ();
     460              :     }
     461          370 :   if (!define)
     462              :     {
     463            0 :       DECL_EXTERNAL (node->decl) = true;
     464            0 :       node->set_comdat_group (NULL);
     465            0 :       node->dissolve_same_comdat_group_list ();
     466              :     }
     467              : }
     468              : 
     469              : /* Try to get rid of weakref.  */
     470              : 
     471              : static void
     472          320 : optimize_weakref (symtab_node *node)
     473              : {
     474          320 :   bool strip_weakref = false;
     475          320 :   bool static_alias = false;
     476              : 
     477          320 :   gcc_assert (node->weakref);
     478              : 
     479              :   /* Weakrefs with no target defined cannot be optimized.  */
     480          320 :   if (!node->analyzed)
     481              :     return;
     482           47 :   symtab_node *target = node->get_alias_target ();
     483              : 
     484              :   /* Weakrefs to weakrefs can be optimized only if target can be.  */
     485           47 :   if (target->weakref)
     486           16 :     optimize_weakref (target);
     487           47 :   if (target->weakref)
     488              :     return;
     489              : 
     490              :   /* If we have definition of weakref's target and we know it binds locally,
     491              :      we can turn weakref to static alias.  */
     492           31 :   if (TARGET_SUPPORTS_ALIASES
     493           31 :       && target->definition && decl_binds_to_current_def_p (target->decl))
     494              :     strip_weakref = static_alias = true;
     495              :   /* Otherwise we can turn weakref into transparent alias.  This transformation
     496              :      may break asm statements which directly refers to symbol name and expect
     497              :      GNU as to translate it via .weakref directive. So do not optimize when
     498              :      DECL_PRESERVED is set and .weakref is supported.  */
     499            2 :   else if ((!DECL_PRESERVE_P (target->decl)
     500            0 :             || IDENTIFIER_TRANSPARENT_ALIAS (DECL_ASSEMBLER_NAME (node->decl)))
     501            2 :            && !DECL_WEAK (target->decl)
     502            0 :            && !DECL_EXTERNAL (target->decl)
     503            2 :            && ((target->definition && !target->can_be_discarded_p ())
     504            0 :                || target->resolution != LDPR_UNDEF))
     505              :     strip_weakref = true;
     506            2 :   if (!strip_weakref)
     507            2 :     return;
     508           29 :   node->weakref = false;
     509           29 :   IDENTIFIER_TRANSPARENT_ALIAS (DECL_ASSEMBLER_NAME (node->decl)) = 0;
     510           29 :   TREE_CHAIN (DECL_ASSEMBLER_NAME (node->decl)) = NULL_TREE;
     511           29 :   DECL_ATTRIBUTES (node->decl) = remove_attribute ("weakref",
     512           29 :                                                    DECL_ATTRIBUTES
     513              :                                                          (node->decl));
     514              : 
     515           29 :   if (dump_file)
     516            0 :     fprintf (dump_file, "Optimizing weakref %s %s\n",
     517              :              node->dump_name (),
     518              :              static_alias ? "as static alias" : "as transparent alias");
     519              : 
     520           29 :   if (static_alias)
     521              :     {
     522              :       /* make_decl_local will shortcircuit if it doesn't see TREE_PUBLIC.
     523              :          be sure it really clears the WEAK flag.  */
     524           29 :       TREE_PUBLIC (node->decl) = true;
     525           29 :       node->make_decl_local ();
     526           29 :       node->forced_by_abi = false;
     527           29 :       node->resolution = LDPR_PREVAILING_DEF_IRONLY;
     528           29 :       node->externally_visible = false;
     529           29 :       gcc_assert (!DECL_WEAK (node->decl));
     530           29 :       node->transparent_alias = false;
     531              :     }
     532              :   else
     533              :     {
     534            0 :       symtab->change_decl_assembler_name
     535            0 :         (node->decl, DECL_ASSEMBLER_NAME (node->get_alias_target ()->decl));
     536            0 :       node->transparent_alias = true;
     537            0 :       node->copy_visibility_from (target);
     538              :     }
     539           29 :   gcc_assert (node->alias);
     540              : }
     541              : 
     542              : /* NODE is an externally visible definition, which we've discovered is
     543              :    not needed externally.  Make it local to this compilation.  */
     544              : 
     545              : static void
     546      3597618 : localize_node (bool whole_program, symtab_node *node)
     547              : {
     548      3597618 :   gcc_assert (whole_program || in_lto_p || !TREE_PUBLIC (node->decl));
     549              : 
     550              :   /* It is possible that one comdat group contains both hidden and non-hidden
     551              :      symbols.  In this case we can privatize all hidden symbol but we need
     552              :      to keep non-hidden exported.  */
     553      3597618 :   if (node->same_comdat_group
     554         8988 :       && (node->resolution == LDPR_PREVAILING_DEF_IRONLY
     555         7583 :           || node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP))
     556              :     {
     557              :       symtab_node *next;
     558         1705 :       for (next = node->same_comdat_group;
     559         3266 :            next != node; next = next->same_comdat_group)
     560         1783 :         if (next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP
     561         1705 :             || next->resolution == LDPR_PREVAILING_DEF)
     562              :           break;
     563         1561 :       if (node != next)
     564              :         {
     565           78 :           if (!node->transparent_alias)
     566              :             {
     567           78 :               node->resolution = LDPR_PREVAILING_DEF_IRONLY;
     568           78 :               node->make_decl_local ();
     569           78 :               if (!flag_incremental_link)
     570           78 :                 node->unique_name |= true;
     571           78 :               return;
     572              :             }
     573              :         }
     574              :     }
     575              :   /* For similar reason do not privatize whole comdat when seeing comdat
     576              :      local.  Wait for non-comdat symbol to be privatized first.  */
     577      3597540 :   if (node->comdat_local_p ())
     578              :     return;
     579              : 
     580      3590303 :   if (node->same_comdat_group && TREE_PUBLIC (node->decl))
     581              :     {
     582         2025 :       for (symtab_node *next = node->same_comdat_group;
     583         3698 :            next != node; next = next->same_comdat_group)
     584              :         {
     585         2025 :           next->set_comdat_group (NULL);
     586         2025 :           if (!next->alias)
     587         1813 :             next->set_section (NULL);
     588         2025 :           if (!next->transparent_alias)
     589         2025 :             next->make_decl_local ();
     590         2025 :           next->unique_name
     591         2025 :             |= ((next->resolution == LDPR_PREVAILING_DEF_IRONLY
     592          374 :                  || next->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
     593         1651 :                 && TREE_PUBLIC (next->decl)
     594         2025 :                 && !flag_incremental_link);
     595              :         }
     596              : 
     597              :       /* Now everything's localized, the grouping has no meaning, and
     598              :          will cause crashes if we keep it around.  */
     599         1673 :       node->dissolve_same_comdat_group_list ();
     600              :     }
     601              : 
     602      3590303 :   node->unique_name
     603      7180606 :     |= ((node->resolution == LDPR_PREVAILING_DEF_IRONLY
     604      1826824 :          || node->resolution == LDPR_PREVAILING_DEF_IRONLY_EXP)
     605      1763895 :         && TREE_PUBLIC (node->decl)
     606      3639543 :         && !flag_incremental_link);
     607              : 
     608      3590303 :   if (TREE_PUBLIC (node->decl))
     609        50179 :     node->set_comdat_group (NULL);
     610      3590303 :   if (DECL_COMDAT (node->decl) && !node->alias)
     611         5236 :     node->set_section (NULL);
     612      3590303 :   if (!node->transparent_alias)
     613              :     {
     614      3590303 :       node->resolution = LDPR_PREVAILING_DEF_IRONLY;
     615      3590303 :       node->make_decl_local ();
     616              :     }
     617              : }
     618              : 
     619              : /* Decide on visibility of all symbols.  */
     620              : 
     621              : static unsigned int
     622       460018 : function_and_variable_visibility (bool whole_program)
     623              : {
     624       460018 :   struct cgraph_node *node;
     625       460018 :   varpool_node *vnode;
     626              : 
     627              :   /* All aliases should be processed at this point.  */
     628       460018 :   gcc_checking_assert (!alias_pairs || !alias_pairs->length ());
     629              : 
     630       460018 :   if (TARGET_SUPPORTS_ALIASES)
     631              :     {
     632      5546084 :       FOR_EACH_DEFINED_FUNCTION (node)
     633              :         {
     634      5086066 :           if (node->get_availability () != AVAIL_INTERPOSABLE
     635       113905 :               || DECL_EXTERNAL (node->decl)
     636       113905 :               || node->has_aliases_p ()
     637      5195548 :               || lookup_attribute ("noipa", DECL_ATTRIBUTES (node->decl)))
     638      5016257 :             continue;
     639              : 
     640        69809 :           cgraph_node *alias = 0;
     641        69809 :           cgraph_edge *next_edge;
     642       317513 :           for (cgraph_edge *e = node->callees; e; e = next_edge)
     643              :             {
     644       247704 :               next_edge = e->next_callee;
     645              :               /* Recursive function calls usually can't be interposed.  */
     646              : 
     647       247704 :               if (!e->recursive_p ())
     648       246765 :                 continue;
     649              : 
     650          939 :               if (!alias)
     651              :                 {
     652          263 :                   alias
     653          263 :                     = dyn_cast<cgraph_node *> (node->noninterposable_alias ());
     654          263 :                   gcc_assert (alias && alias != node);
     655              :                 }
     656              : 
     657          939 :               e->redirect_callee (alias);
     658          939 :               if (gimple_has_body_p (e->caller->decl))
     659              :                 {
     660          939 :                   push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl));
     661          939 :                   cgraph_edge::redirect_call_stmt_to_callee (e);
     662          939 :                   pop_cfun ();
     663              :                 }
     664              :             }
     665              :         }
     666              :     }
     667              : 
     668      9011550 :   FOR_EACH_FUNCTION (node)
     669              :     {
     670      8551532 :       int flags = flags_from_decl_or_type (node->decl);
     671              : 
     672              :       /* Optimize away PURE and CONST constructors and destructors.  */
     673      8551532 :       if (node->analyzed
     674      5086329 :           && (DECL_STATIC_CONSTRUCTOR (node->decl)
     675      5048085 :               || DECL_STATIC_DESTRUCTOR (node->decl))
     676        38868 :           && (flags & (ECF_CONST | ECF_PURE))
     677           23 :           && !(flags & ECF_LOOPING_CONST_OR_PURE)
     678      8551532 :           && opt_for_fn (node->decl, optimize))
     679              :         {
     680            0 :           DECL_STATIC_CONSTRUCTOR (node->decl) = 0;
     681            0 :           DECL_STATIC_DESTRUCTOR (node->decl) = 0;
     682              :         }
     683              : 
     684              :       /* Frontends and alias code marks nodes as needed before parsing
     685              :          is finished.  We may end up marking as node external nodes
     686              :          where this flag is meaningless strip it.  */
     687      8551532 :       if (DECL_EXTERNAL (node->decl) || !node->definition)
     688              :         {
     689      3617608 :           node->force_output = 0;
     690      3617608 :           node->forced_by_abi = 0;
     691              :         }
     692              : 
     693              :       /* C++ FE on lack of COMDAT support create local COMDAT functions
     694              :          (that ought to be shared but cannot due to object format
     695              :          limitations).  It is necessary to keep the flag to make rest of C++ FE
     696              :          happy.  Clear the flag here to avoid confusion in middle-end.  */
     697      8551532 :       if (DECL_COMDAT (node->decl) && !TREE_PUBLIC (node->decl))
     698           29 :         DECL_COMDAT (node->decl) = 0;
     699              : 
     700              :       /* For external decls stop tracking same_comdat_group. It doesn't matter
     701              :          what comdat group they are in when they won't be emitted in this TU.
     702              : 
     703              :          An exception is LTO where we may end up with both external
     704              :          and non-external declarations in the same comdat group in
     705              :          the case declarations was not merged.  */
     706      8551532 :       if (node->same_comdat_group && DECL_EXTERNAL (node->decl) && !in_lto_p)
     707              :         {
     708           24 :           if (flag_checking)
     709              :             {
     710           30 :               for (symtab_node *n = node->same_comdat_group;
     711           54 :                    n != node;
     712           30 :                    n = n->same_comdat_group)
     713              :                 /* If at least one of same comdat group functions is external,
     714              :                    all of them have to be, otherwise it is a front-end bug.  */
     715           30 :                 gcc_assert (DECL_EXTERNAL (n->decl));
     716              :             }
     717           24 :           node->dissolve_same_comdat_group_list ();
     718              :         }
     719      8551532 :       gcc_assert ((!DECL_WEAK (node->decl)
     720              :                   && !DECL_COMDAT (node->decl))
     721              :                   || TREE_PUBLIC (node->decl)
     722              :                   || node->weakref
     723              :                   || DECL_EXTERNAL (node->decl));
     724      8551532 :       if (cgraph_externally_visible_p (node, whole_program))
     725              :         {
     726      4233106 :           gcc_assert (!node->inlined_to);
     727      4233106 :           node->externally_visible = true;
     728              :         }
     729              :       else
     730              :         {
     731      4318426 :           node->externally_visible = false;
     732      4318426 :           node->forced_by_abi = false;
     733              :         }
     734      8551532 :       if (!node->externally_visible
     735      4318426 :           && node->definition && !node->weakref
     736      9404738 :           && !DECL_EXTERNAL (node->decl))
     737       700806 :         localize_node (whole_program, node);
     738              : 
     739      8551532 :       if (node->thunk
     740         5942 :           && TREE_PUBLIC (node->decl))
     741              :         {
     742         5807 :           struct cgraph_node *decl_node = node;
     743              : 
     744         5807 :           decl_node = decl_node->callees->callee->function_symbol ();
     745              : 
     746              :           /* Thunks have the same visibility as function they are attached to.
     747              :              Make sure the C++ front end set this up properly.  */
     748         5807 :           if (DECL_ONE_ONLY (decl_node->decl))
     749              :             {
     750         4655 :               gcc_checking_assert (DECL_COMDAT (node->decl)
     751              :                                    == DECL_COMDAT (decl_node->decl));
     752         4655 :               gcc_checking_assert (node->in_same_comdat_group_p (decl_node));
     753         4655 :               gcc_checking_assert (node->same_comdat_group);
     754              :             }
     755         5807 :           node->forced_by_abi = decl_node->forced_by_abi;
     756         5807 :           if (DECL_EXTERNAL (decl_node->decl))
     757            2 :             DECL_EXTERNAL (node->decl) = 1;
     758              :         }
     759              : 
     760      8551532 :       update_visibility_by_resolution_info (node);
     761      8551532 :       if (node->weakref)
     762          230 :         optimize_weakref (node);
     763              :     }
     764      5546347 :   FOR_EACH_DEFINED_FUNCTION (node)
     765              :     {
     766      5086329 :       if (!node->local)
     767      4939396 :         node->local |= node->local_p ();
     768              : 
     769              :       /* If we know that function cannot be overwritten by a
     770              :          different semantics and moreover its section cannot be
     771              :          discarded, replace all direct calls by calls to an
     772              :          noninterposable alias.  This make dynamic linking cheaper and
     773              :          enable more optimization.
     774              : 
     775              :          TODO: We can also update virtual tables.  */
     776      5086329 :       if (node->callers
     777      5086329 :           && can_replace_by_local_alias (node))
     778              :         {
     779           98 :           cgraph_node *alias = dyn_cast<cgraph_node *>
     780           98 :             (node->noninterposable_alias ());
     781              : 
     782           98 :           if (alias && alias != node)
     783              :             {
     784          227 :               while (node->callers)
     785              :                 {
     786          130 :                   struct cgraph_edge *e = node->callers;
     787              : 
     788          130 :                   e->redirect_callee (alias);
     789          130 :                   if (gimple_has_body_p (e->caller->decl))
     790              :                     {
     791          127 :                       push_cfun (DECL_STRUCT_FUNCTION (e->caller->decl));
     792          127 :                       cgraph_edge::redirect_call_stmt_to_callee (e);
     793          127 :                       pop_cfun ();
     794              :                     }
     795              :                 }
     796              :             }
     797              :         }
     798              :     }
     799      6901470 :   FOR_EACH_VARIABLE (vnode)
     800              :     {
     801              :       /* weak flag makes no sense on local variables.  */
     802      6441452 :       gcc_assert (!DECL_WEAK (vnode->decl)
     803              :                   || vnode->weakref
     804              :                   || TREE_PUBLIC (vnode->decl)
     805              :                   || DECL_EXTERNAL (vnode->decl));
     806              :       /* In several cases declarations cannot be common:
     807              : 
     808              :          - when declaration has initializer
     809              :          - when it is in weak
     810              :          - when it has specific section
     811              :          - when it resides in non-generic address space.
     812              :          - if declaration is local, it will get into .local common section
     813              :            so common flag is not needed.  Frontends still produce these in
     814              :            certain cases, such as for:
     815              : 
     816              :              static int a __attribute__ ((common))
     817              : 
     818              :          Canonicalize things here and clear the redundant flag.  */
     819      6441452 :       if (DECL_COMMON (vnode->decl)
     820      6441452 :           && (!(TREE_PUBLIC (vnode->decl)
     821           47 :               || DECL_EXTERNAL (vnode->decl))
     822        26320 :               || (DECL_INITIAL (vnode->decl)
     823        23465 :                   && DECL_INITIAL (vnode->decl) != error_mark_node)
     824         2855 :               || DECL_WEAK (vnode->decl)
     825         2852 :               || DECL_SECTION_NAME (vnode->decl) != NULL
     826         2847 :               || ! (ADDR_SPACE_GENERIC_P
     827              :                     (TYPE_ADDR_SPACE (TREE_TYPE (vnode->decl))))))
     828        23520 :         DECL_COMMON (vnode->decl) = 0;
     829      6441452 :       if (vnode->weakref)
     830           74 :         optimize_weakref (vnode);
     831              :     }
     832      6313689 :   FOR_EACH_DEFINED_VARIABLE (vnode)
     833              :     {
     834      5853671 :       if (!vnode->definition)
     835            0 :         continue;
     836      5853671 :       if (vnode->externally_visible_p ())
     837      2956851 :         vnode->externally_visible = true;
     838              :       else
     839              :         {
     840      2896820 :           vnode->externally_visible = false;
     841      2896820 :           vnode->forced_by_abi = false;
     842              :         }
     843      5853671 :       if (lookup_attribute ("no_reorder",
     844      5853671 :                             DECL_ATTRIBUTES (vnode->decl)))
     845            4 :         vnode->no_reorder = 1;
     846              : 
     847      5853671 :       if (!vnode->externally_visible
     848      2896820 :           && !vnode->transparent_alias
     849      8750483 :           && !DECL_EXTERNAL (vnode->decl))
     850      2896812 :         localize_node (whole_program, vnode);
     851              : 
     852      5853671 :       update_visibility_by_resolution_info (vnode);
     853              : 
     854              :       /* Update virtual tables to point to local aliases where possible.  */
     855      5853671 :       if (DECL_VIRTUAL_P (vnode->decl)
     856      5853671 :           && !DECL_EXTERNAL (vnode->decl))
     857              :         {
     858              :           int i;
     859              :           struct ipa_ref *ref;
     860       302141 :           bool found = false;
     861              : 
     862              :           /* See if there is something to update.  */
     863       302141 :           for (i = 0; vnode->iterate_reference (i, ref); i++)
     864       258218 :             if (ref->use == IPA_REF_ADDR
     865       258218 :                 && can_replace_by_local_alias_in_vtable (ref->referred))
     866              :               {
     867              :                 found = true;
     868              :                 break;
     869              :               }
     870        43926 :           if (found)
     871              :             {
     872            3 :               hash_set<tree> visited_nodes;
     873              : 
     874            3 :               vnode->get_constructor ();
     875            3 :               walk_tree (&DECL_INITIAL (vnode->decl),
     876              :                          update_vtable_references, NULL, &visited_nodes);
     877            3 :               vnode->remove_all_references ();
     878            3 :               record_references_in_initializer (vnode->decl, false);
     879            3 :             }
     880              :         }
     881              :     }
     882              : 
     883       460018 :   if (symtab->state >= IPA_SSA)
     884              :     {
     885      3393492 :       FOR_EACH_VARIABLE (vnode)
     886              :         {
     887      3163429 :           tree decl = vnode->decl;
     888              : 
     889              :           /* Upgrade TLS access model based on optimized visibility status,
     890              :              unless it was specified explicitly or no references remain.  */
     891      3163429 :           if (DECL_THREAD_LOCAL_P (decl)
     892         4568 :               && !lookup_attribute ("tls_model", DECL_ATTRIBUTES (decl))
     893      6330919 :               && vnode->ref_list.referring.length ())
     894              :             {
     895         4061 :               enum tls_model new_model = decl_default_tls_model (decl);
     896         4061 :               STATIC_ASSERT (TLS_MODEL_GLOBAL_DYNAMIC < TLS_MODEL_LOCAL_DYNAMIC);
     897         4061 :               STATIC_ASSERT (TLS_MODEL_INITIAL_EXEC < TLS_MODEL_LOCAL_EXEC);
     898              :               /* We'd prefer to assert that recomputed model is not weaker than
     899              :                  what the front-end assigned, but cannot: see PR 107353.  */
     900         4061 :               if (new_model >= decl_tls_model (decl))
     901         4061 :                 set_decl_tls_model (decl, new_model);
     902              :             }
     903              :         }
     904              :     }
     905              : 
     906       460018 :   if (dump_file)
     907              :     {
     908          136 :       fprintf (dump_file, "\nMarking local functions:");
     909          319 :       FOR_EACH_DEFINED_FUNCTION (node)
     910          183 :         if (node->local)
     911            1 :           fprintf (dump_file, " %s", node->dump_name ());
     912          136 :       fprintf (dump_file, "\n\n");
     913          136 :       fprintf (dump_file, "\nMarking externally visible functions:");
     914          319 :       FOR_EACH_DEFINED_FUNCTION (node)
     915          183 :         if (node->externally_visible)
     916          176 :           fprintf (dump_file, " %s", node->dump_name ());
     917          136 :       fprintf (dump_file, "\n\n");
     918          136 :       fprintf (dump_file, "\nMarking externally visible variables:");
     919          228 :       FOR_EACH_DEFINED_VARIABLE (vnode)
     920           92 :         if (vnode->externally_visible)
     921           60 :           fprintf (dump_file, " %s", vnode->dump_name ());
     922          136 :       fprintf (dump_file, "\n\n");
     923              :     }
     924       460018 :   symtab->function_flags_ready = true;
     925       460018 :   return 0;
     926              : }
     927              : 
     928              : /* Local function pass handling visibilities.  This happens before LTO streaming
     929              :    so in particular -fwhole-program should be ignored at this level.  */
     930              : 
     931              : namespace {
     932              : 
     933              : const pass_data pass_data_ipa_function_and_variable_visibility =
     934              : {
     935              :   SIMPLE_IPA_PASS, /* type */
     936              :   "visibility", /* name */
     937              :   OPTGROUP_NONE, /* optinfo_flags */
     938              :   TV_CGRAPHOPT, /* tv_id */
     939              :   0, /* properties_required */
     940              :   0, /* properties_provided */
     941              :   0, /* properties_destroyed */
     942              :   0, /* todo_flags_start */
     943              :   ( TODO_remove_functions | TODO_dump_symtab ), /* todo_flags_finish */
     944              : };
     945              : 
     946              : /* Bring functions local at LTO time with -fwhole-program.  */
     947              : 
     948              : static unsigned int
     949       230063 : whole_program_function_and_variable_visibility (void)
     950              : {
     951       230063 :   function_and_variable_visibility (flag_whole_program);
     952       230063 :   if (optimize || in_lto_p)
     953       151656 :     ipa_discover_variable_flags ();
     954       230063 :   return 0;
     955              : }
     956              : 
     957              : } // anon namespace
     958              : 
     959              : namespace {
     960              : 
     961              : const pass_data pass_data_ipa_whole_program_visibility =
     962              : {
     963              :   IPA_PASS, /* type */
     964              :   "whole-program", /* name */
     965              :   OPTGROUP_NONE, /* optinfo_flags */
     966              :   TV_CGRAPHOPT, /* tv_id */
     967              :   0, /* properties_required */
     968              :   0, /* properties_provided */
     969              :   0, /* properties_destroyed */
     970              :   0, /* todo_flags_start */
     971              :   ( TODO_remove_functions | TODO_dump_symtab ), /* todo_flags_finish */
     972              : };
     973              : 
     974              : class pass_ipa_whole_program_visibility : public ipa_opt_pass_d
     975              : {
     976              : public:
     977       285722 :   pass_ipa_whole_program_visibility (gcc::context *ctxt)
     978              :     : ipa_opt_pass_d (pass_data_ipa_whole_program_visibility, ctxt,
     979              :                       NULL, /* generate_summary */
     980              :                       NULL, /* write_summary */
     981              :                       NULL, /* read_summary */
     982              :                       NULL, /* write_optimization_summary */
     983              :                       NULL, /* read_optimization_summary */
     984              :                       NULL, /* stmt_fixup */
     985              :                       0, /* function_transform_todo_flags_start */
     986              :                       NULL, /* function_transform */
     987       285722 :                       NULL) /* variable_transform */
     988       285722 :   {}
     989              : 
     990              :   /* opt_pass methods: */
     991              : 
     992       563719 :   bool gate (function *) final override
     993              :     {
     994              :       /* Do not re-run on ltrans stage.  */
     995       563719 :       return !flag_ltrans;
     996              :     }
     997       230063 :   unsigned int execute (function *) final override
     998              :     {
     999       230063 :       return whole_program_function_and_variable_visibility ();
    1000              :     }
    1001              : 
    1002              : }; // class pass_ipa_whole_program_visibility
    1003              : 
    1004              : } // anon namespace
    1005              : 
    1006              : ipa_opt_pass_d *
    1007       285722 : make_pass_ipa_whole_program_visibility (gcc::context *ctxt)
    1008              : {
    1009       285722 :   return new pass_ipa_whole_program_visibility (ctxt);
    1010              : }
    1011              : 
    1012              : class pass_ipa_function_and_variable_visibility : public simple_ipa_opt_pass
    1013              : {
    1014              : public:
    1015       285722 :   pass_ipa_function_and_variable_visibility (gcc::context *ctxt)
    1016              :     : simple_ipa_opt_pass (pass_data_ipa_function_and_variable_visibility,
    1017       571444 :                            ctxt)
    1018              :   {}
    1019              : 
    1020              :   /* opt_pass methods: */
    1021       229955 :   unsigned int execute (function *) final override
    1022              :     {
    1023       459813 :       return function_and_variable_visibility (flag_whole_program && !flag_lto);
    1024              :     }
    1025              : 
    1026              : }; // class pass_ipa_function_and_variable_visibility
    1027              : 
    1028              : simple_ipa_opt_pass *
    1029       285722 : make_pass_ipa_function_and_variable_visibility (gcc::context *ctxt)
    1030              : {
    1031       285722 :   return new pass_ipa_function_and_variable_visibility (ctxt);
    1032              : }
        

Generated by: LCOV version 2.4-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.