LCOV - code coverage report
Current view: top level - gcc - ipa-comdats.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 100.0 % 151 151
Test Date: 2024-12-21 13:15:12 Functions: 100.0 % 9 9
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Localize comdats.
       2                 :             :    Copyright (C) 2014-2024 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 is very simple pass that looks for static symbols that are used
      21                 :             :    exclusively by symbol within one comdat group.  In this case it makes
      22                 :             :    sense to bring the symbol itself into the group to avoid dead code
      23                 :             :    that would arrise when the comdat group from current unit is replaced
      24                 :             :    by a different copy.  Consider for example:
      25                 :             : 
      26                 :             :     static int q(void)
      27                 :             :     {
      28                 :             :       ....
      29                 :             :     }
      30                 :             :     inline int t(void)
      31                 :             :     {
      32                 :             :       return q();
      33                 :             :     }
      34                 :             : 
      35                 :             :    if Q is used only by T, it makes sense to put Q into T's comdat group.
      36                 :             : 
      37                 :             :    The pass solve simple dataflow across the callgraph trying to prove what
      38                 :             :    symbols are used exclusively from a given comdat group.
      39                 :             : 
      40                 :             :    The implementation maintains a queue linked by AUX pointer terminated by
      41                 :             :    pointer value 1. Lattice values are NULL for TOP, actual comdat group, or
      42                 :             :    ERROR_MARK_NODE for bottom.
      43                 :             : 
      44                 :             :    TODO: When symbol is used only by comdat symbols, but from different groups,
      45                 :             :    it would make sense to produce a new comdat group for it with anonymous name.
      46                 :             : 
      47                 :             :    TODO2: We can't mix variables and functions within one group.  Currently
      48                 :             :    we just give up on references of symbols of different types.  We also should
      49                 :             :    handle this by anonymous comdat group section.  */
      50                 :             : 
      51                 :             : #include "config.h"
      52                 :             : #include "system.h"
      53                 :             : #include "coretypes.h"
      54                 :             : #include "tm.h"
      55                 :             : #include "tree.h"
      56                 :             : #include "tree-pass.h"
      57                 :             : #include "cgraph.h"
      58                 :             : 
      59                 :             : /* Main dataflow loop propagating comdat groups across
      60                 :             :    the symbol table.  All references to SYMBOL are examined
      61                 :             :    and NEWGROUP is updated accordingly. MAP holds current lattice
      62                 :             :    values for individual symbols.  */
      63                 :             : 
      64                 :             : tree
      65                 :       72246 : propagate_comdat_group (struct symtab_node *symbol,
      66                 :             :                         tree newgroup, hash_map<symtab_node *, tree> &map)
      67                 :             : {
      68                 :       72246 :   int i;
      69                 :       72246 :   struct ipa_ref *ref;
      70                 :             : 
      71                 :             :   /* Walk all references to SYMBOL, recursively dive into aliases.  */
      72                 :             : 
      73                 :       96321 :   for (i = 0;
      74                 :      192642 :        symbol->iterate_referring (i, ref)
      75                 :       96321 :        && newgroup != error_mark_node; i++)
      76                 :             :     {
      77                 :       45549 :       struct symtab_node *symbol2 = ref->referring;
      78                 :             : 
      79                 :       45549 :       if (ref->use == IPA_REF_ALIAS)
      80                 :             :         {
      81                 :        1302 :           newgroup = propagate_comdat_group (symbol2, newgroup, map);
      82                 :        1302 :           continue;
      83                 :             :         }
      84                 :             : 
      85                 :             :       /* One COMDAT group cannot hold both variables and functions at
      86                 :             :          a same time.  For now we just go to BOTTOM, in future we may
      87                 :             :          invent special comdat groups for this case.  */
      88                 :             : 
      89                 :       44247 :       if (symbol->type != symbol2->type)
      90                 :             :         {
      91                 :       21474 :           newgroup = error_mark_node;
      92                 :       21474 :           break;
      93                 :             :         }
      94                 :             : 
      95                 :             :       /* If we see inline clone, its comdat group actually
      96                 :             :          corresponds to the comdat group of the function it is inlined
      97                 :             :          to.  */
      98                 :             : 
      99                 :       22773 :       if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2))
     100                 :             :         {
     101                 :       13620 :           if (cn->inlined_to)
     102                 :        1859 :             symbol2 = cn->inlined_to;
     103                 :             :         }
     104                 :             : 
     105                 :             :       /* The actual merge operation.  */
     106                 :             : 
     107                 :       22773 :       tree *val2 = map.get (symbol2);
     108                 :             : 
     109                 :       22773 :       if (val2 && *val2 != newgroup)
     110                 :             :         {
     111                 :       21350 :           if (!newgroup)
     112                 :             :             newgroup = *val2;
     113                 :             :           else
     114                 :          14 :             newgroup = error_mark_node;
     115                 :             :         }
     116                 :             :     }
     117                 :             : 
     118                 :             :   /* If we analyze function, walk also callers.  */
     119                 :             : 
     120                 :       72246 :   cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol);
     121                 :             : 
     122                 :       50262 :   if (cnode)
     123                 :       50262 :     for (struct cgraph_edge * edge = cnode->callers;
     124                 :       96517 :          edge && newgroup != error_mark_node; edge = edge->next_caller)
     125                 :             :       {
     126                 :       46255 :         struct symtab_node *symbol2 = edge->caller;
     127                 :             : 
     128                 :       46255 :         if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2))
     129                 :             :           {
     130                 :             :             /* Thunks cannot call across section boundary.  */
     131                 :       46255 :             if (cn->thunk)
     132                 :         427 :               newgroup = propagate_comdat_group (symbol2, newgroup, map);
     133                 :             :             /* If we see inline clone, its comdat group actually
     134                 :             :                corresponds to the comdat group of the function it
     135                 :             :                is inlined to.  */
     136                 :       46255 :             if (cn->inlined_to)
     137                 :       16694 :               symbol2 = cn->inlined_to;
     138                 :             :           }
     139                 :             : 
     140                 :             :         /* The actual merge operation.  */
     141                 :             : 
     142                 :       46255 :         tree *val2 = map.get (symbol2);
     143                 :             : 
     144                 :       46255 :         if (val2 && *val2 != newgroup)
     145                 :             :           {
     146                 :       28491 :             if (!newgroup)
     147                 :             :               newgroup = *val2;
     148                 :             :             else
     149                 :        4664 :               newgroup = error_mark_node;
     150                 :             :           }
     151                 :             :       }
     152                 :       72246 :   return newgroup;
     153                 :             : }
     154                 :             : 
     155                 :             : 
     156                 :             : /* Add all references of SYMBOL that are defined into queue started by FIRST
     157                 :             :    and linked by AUX pointer (unless they are already enqueued).
     158                 :             :    Walk recursively inlined functions.  */
     159                 :             : 
     160                 :             : void
     161                 :      161005 : enqueue_references (symtab_node **first,
     162                 :             :                     symtab_node *symbol)
     163                 :             : {
     164                 :      161005 :   int i;
     165                 :      161005 :   struct ipa_ref *ref = NULL;
     166                 :             : 
     167                 :      366694 :   for (i = 0; symbol->iterate_reference (i, ref); i++)
     168                 :             :     {
     169                 :      205689 :       symtab_node *node = ref->referred->ultimate_alias_target ();
     170                 :             : 
     171                 :             :       /* Always keep thunks in same sections as target function.  */
     172                 :      205689 :       if (is_a <cgraph_node *>(node))
     173                 :       22676 :         node = dyn_cast <cgraph_node *> (node)->function_symbol ();
     174                 :      205689 :       if (!node->aux && node->definition)
     175                 :             :         {
     176                 :        1200 :            node->aux = *first;
     177                 :        1200 :            *first = node;
     178                 :             :         }
     179                 :             :     }
     180                 :             : 
     181                 :      161005 :   if (cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol))
     182                 :             :     {
     183                 :      139993 :       struct cgraph_edge *edge;
     184                 :             : 
     185                 :      565643 :       for (edge = cnode->callees; edge; edge = edge->next_callee)
     186                 :      425650 :         if (!edge->inline_failed)
     187                 :       94134 :           enqueue_references (first, edge->callee);
     188                 :             :         else
     189                 :             :           {
     190                 :      331516 :             symtab_node *node = edge->callee->ultimate_alias_target ();
     191                 :             : 
     192                 :             :             /* Always keep thunks in same sections as target function.  */
     193                 :      331516 :             if (is_a <cgraph_node *>(node))
     194                 :      331516 :               node = dyn_cast <cgraph_node *> (node)->function_symbol ();
     195                 :      331516 :             if (!node->aux && node->definition)
     196                 :             :               {
     197                 :        2530 :                  node->aux = *first;
     198                 :        2530 :                  *first = node;
     199                 :             :               }
     200                 :             :           }
     201                 :             :     }
     202                 :      161005 : }
     203                 :             : 
     204                 :             : /* Set comdat group of SYMBOL to GROUP.
     205                 :             :    Callback for for_node_and_aliases.  */
     206                 :             : 
     207                 :             : bool
     208                 :        4829 : set_comdat_group (symtab_node *symbol,
     209                 :             :                   void *head_p)
     210                 :             : {
     211                 :        4829 :   symtab_node *head = (symtab_node *)head_p;
     212                 :             : 
     213                 :        4829 :   gcc_assert (!symbol->get_comdat_group ());
     214                 :        4829 :   if (symbol->real_symbol_p ())
     215                 :             :     {
     216                 :        4829 :       symbol->set_comdat_group (head->get_comdat_group ());
     217                 :        4829 :       symbol->add_to_same_comdat_group (head);
     218                 :             :     }
     219                 :        4829 :   return false;
     220                 :             : }
     221                 :             : 
     222                 :             : /* Set comdat group of SYMBOL to GROUP.
     223                 :             :    Callback for for_node_thunks_and_aliases.  */
     224                 :             : 
     225                 :             : bool
     226                 :        4823 : set_comdat_group_1 (cgraph_node *symbol,
     227                 :             :                     void *head_p)
     228                 :             : {
     229                 :        4823 :   return set_comdat_group (symbol, head_p);
     230                 :             : }
     231                 :             : 
     232                 :             : /* The actual pass with the main dataflow loop.  */
     233                 :             : 
     234                 :             : static unsigned int
     235                 :      223972 : ipa_comdats (void)
     236                 :             : {
     237                 :      223972 :   hash_map<symtab_node *, tree> map (251);
     238                 :      223972 :   hash_map<tree, symtab_node *> comdat_head_map (251);
     239                 :      223972 :   symtab_node *symbol;
     240                 :      223972 :   bool comdat_group_seen = false;
     241                 :      223972 :   symtab_node *first = (symtab_node *) (void *) 1;
     242                 :      223972 :   tree group;
     243                 :             : 
     244                 :             :   /* Start the dataflow by assigning comdat group to symbols that are in comdat
     245                 :             :      groups already.  All other externally visible symbols must stay, we use
     246                 :             :      ERROR_MARK_NODE as bottom for the propagation.  */
     247                 :             : 
     248                 :    11309278 :   FOR_EACH_DEFINED_SYMBOL (symbol)
     249                 :     5430667 :     if (!symbol->real_symbol_p ())
     250                 :             :       ;
     251                 :     4302894 :     else if ((group = symbol->get_comdat_group ()) != NULL)
     252                 :             :       {
     253                 :      509976 :         map.put (symbol, group);
     254                 :      509976 :         comdat_head_map.put (group, symbol);
     255                 :      509976 :         comdat_group_seen = true;
     256                 :             : 
     257                 :             :         /* Mark the symbol so we won't waste time visiting it for dataflow.  */
     258                 :      509976 :         symbol->aux = (symtab_node *) (void *) 1;
     259                 :             :       }
     260                 :             :     /* See symbols that cannot be privatized to comdats; that is externally
     261                 :             :        visible symbols or otherwise used ones.  We also do not want to mangle
     262                 :             :        user section names.  */
     263                 :     3792918 :     else if (symbol->externally_visible
     264                 :             :              || symbol->force_output
     265                 :     3792918 :              || symbol->used_from_other_partition
     266                 :     1467203 :              || TREE_THIS_VOLATILE (symbol->decl)
     267                 :     1460972 :              || symbol->get_section ()
     268                 :     4218069 :              || (TREE_CODE (symbol->decl) == FUNCTION_DECL
     269                 :      172676 :                  && (DECL_STATIC_CONSTRUCTOR (symbol->decl)
     270                 :      171062 :                      || DECL_STATIC_DESTRUCTOR (symbol->decl))))
     271                 :             :       {
     272                 :     3369434 :         symtab_node *target = symbol->ultimate_alias_target ();
     273                 :             : 
     274                 :             :         /* Always keep thunks in same sections as target function.  */
     275                 :     3369434 :         if (is_a <cgraph_node *>(target))
     276                 :     1096070 :           target = dyn_cast <cgraph_node *> (target)->function_symbol ();
     277                 :     3369434 :         map.put (target, error_mark_node);
     278                 :             : 
     279                 :             :         /* Mark the symbol so we won't waste time visiting it for dataflow.  */
     280                 :     3369434 :         symbol->aux = (symtab_node *) (void *) 1;
     281                 :             :       }
     282                 :             :     else
     283                 :             :       {
     284                 :             :         /* Enqueue symbol for dataflow.  */
     285                 :      423484 :         symbol->aux = first;
     286                 :      423484 :         first = symbol;
     287                 :             :       }
     288                 :             : 
     289                 :      223972 :   if (!comdat_group_seen)
     290                 :             :     {
     291                 :     2814438 :       FOR_EACH_DEFINED_SYMBOL (symbol)
     292                 :     2415176 :         symbol->aux = NULL;
     293                 :             :       return 0;
     294                 :             :     }
     295                 :             : 
     296                 :             :   /* The actual dataflow.  */
     297                 :             : 
     298                 :       94865 :   while (first != (void *) 1)
     299                 :             :     {
     300                 :       70524 :       tree group = NULL;
     301                 :       70524 :       tree newgroup, *val;
     302                 :             : 
     303                 :       70524 :       symbol = first;
     304                 :       70524 :       first = (symtab_node *)first->aux;
     305                 :             : 
     306                 :             :       /* Get current lattice value of SYMBOL.  */
     307                 :       70524 :       val = map.get (symbol);
     308                 :       70524 :       if (val)
     309                 :         302 :         group = *val;
     310                 :             : 
     311                 :             :       /* If it is bottom, there is nothing to do; do not clear AUX
     312                 :             :          so we won't re-queue the symbol.  */
     313                 :       70524 :       if (group == error_mark_node)
     314                 :        3653 :         continue;
     315                 :             : 
     316                 :       70517 :       newgroup = propagate_comdat_group (symbol, group, map);
     317                 :             : 
     318                 :             :       /* If nothing changed, proceed to next symbol.  */
     319                 :       70517 :       if (newgroup == group)
     320                 :             :         {
     321                 :        3646 :           symbol->aux = NULL;
     322                 :        3646 :           continue;
     323                 :             :         }
     324                 :             : 
     325                 :             :       /* Update lattice value and enqueue all references for re-visiting.  */
     326                 :       66871 :       gcc_assert (newgroup);
     327                 :       66871 :       if (val)
     328                 :         234 :         *val = newgroup;
     329                 :             :       else
     330                 :       66637 :         map.put (symbol, newgroup);
     331                 :       66871 :       enqueue_references (&first, symbol);
     332                 :             : 
     333                 :             :       /* We may need to revisit the symbol unless it is BOTTOM.  */
     334                 :       66871 :       if (newgroup != error_mark_node)
     335                 :        5112 :         symbol->aux = NULL;
     336                 :             :     }
     337                 :             : 
     338                 :             :   /* Finally assign symbols to the sections.  */
     339                 :             : 
     340                 :     6079664 :   FOR_EACH_DEFINED_SYMBOL (symbol)
     341                 :             :     {
     342                 :     3015491 :       struct cgraph_node *fun;
     343                 :     3015491 :       symbol->aux = NULL;
     344                 :     3015491 :       if (!symbol->get_comdat_group ()
     345                 :     2425936 :           && !symbol->alias
     346                 :     2416555 :           && (!(fun = dyn_cast <cgraph_node *> (symbol))
     347                 :     1178507 :               || !fun->thunk)
     348                 :     5431368 :           && symbol->real_symbol_p ())
     349                 :             :         {
     350                 :     1573536 :           tree *val = map.get (symbol);
     351                 :             : 
     352                 :             :           /* A NULL here means that SYMBOL is unreachable in the definition
     353                 :             :              of ipa-comdats. Either ipa-comdats is wrong about this or someone
     354                 :             :              forgot to cleanup and remove unreachable functions earlier.  */
     355                 :     1573536 :           gcc_assert (val);
     356                 :             : 
     357                 :     1573536 :           tree group = *val;
     358                 :             : 
     359                 :     1573536 :           if (group == error_mark_node)
     360                 :     1568719 :             continue;
     361                 :        4817 :           if (dump_file)
     362                 :             :             {
     363                 :           3 :               fprintf (dump_file, "Localizing symbol\n");
     364                 :           3 :               symbol->dump (dump_file);
     365                 :           3 :               fprintf (dump_file, "To group: %s\n", IDENTIFIER_POINTER (group));
     366                 :             :             }
     367                 :        4817 :           if (is_a <cgraph_node *> (symbol))
     368                 :        4811 :            dyn_cast <cgraph_node *>(symbol)->call_for_symbol_thunks_and_aliases
     369                 :        4811 :                   (set_comdat_group_1,
     370                 :        4811 :                    *comdat_head_map.get (group),
     371                 :             :                    true);
     372                 :             :           else
     373                 :           6 :            symbol->call_for_symbol_and_aliases
     374                 :           6 :                   (set_comdat_group,
     375                 :           6 :                    *comdat_head_map.get (group),
     376                 :             :                    true);
     377                 :             :         }
     378                 :             :     }
     379                 :             : 
     380                 :             : #if 0
     381                 :             :   /* Recompute calls comdat local flag.  This need to be done after all changes
     382                 :             :      are made.  */
     383                 :             :   cgraph_node *function;
     384                 :             :   FOR_EACH_DEFINED_FUNCTION (function)
     385                 :             :     if (function->get_comdat_group ())
     386                 :             :       function->calls_comdat_local = function->check_calls_comdat_local_p ();
     387                 :             : #endif
     388                 :             :   return 0;
     389                 :      223972 : }
     390                 :             : 
     391                 :             : namespace {
     392                 :             : 
     393                 :             : const pass_data pass_data_ipa_comdats =
     394                 :             : {
     395                 :             :   IPA_PASS, /* type */
     396                 :             :   "comdats", /* name */
     397                 :             :   OPTGROUP_NONE, /* optinfo_flags */
     398                 :             :   TV_IPA_COMDATS, /* tv_id */
     399                 :             :   0, /* properties_required */
     400                 :             :   0, /* properties_provided */
     401                 :             :   0, /* properties_destroyed */
     402                 :             :   0, /* todo_flags_start */
     403                 :             :   0, /* todo_flags_finish */
     404                 :             : };
     405                 :             : 
     406                 :             : class pass_ipa_comdats : public ipa_opt_pass_d
     407                 :             : {
     408                 :             : public:
     409                 :      280114 :   pass_ipa_comdats (gcc::context *ctxt)
     410                 :             :     : ipa_opt_pass_d (pass_data_ipa_comdats, ctxt,
     411                 :             :                       NULL, /* generate_summary */
     412                 :             :                       NULL, /* write_summary */
     413                 :             :                       NULL, /* read_summary */
     414                 :             :                       NULL, /* write_optimization_summary */
     415                 :             :                       NULL, /* read_optimization_summary */
     416                 :             :                       NULL, /* stmt_fixup */
     417                 :             :                       0, /* function_transform_todo_flags_start */
     418                 :             :                       NULL, /* function_transform */
     419                 :      280114 :                       NULL) /* variable_transform */
     420                 :      280114 :   {}
     421                 :             : 
     422                 :             :   /* opt_pass methods: */
     423                 :             :   bool gate (function *) final override;
     424                 :      223972 :   unsigned int execute (function *) final override { return ipa_comdats (); }
     425                 :             : 
     426                 :             : }; // class pass_ipa_comdats
     427                 :             : 
     428                 :             : bool
     429                 :      553805 : pass_ipa_comdats::gate (function *)
     430                 :             : {
     431                 :      553805 :   return HAVE_COMDAT_GROUP;
     432                 :             : }
     433                 :             : 
     434                 :             : } // anon namespace
     435                 :             : 
     436                 :             : ipa_opt_pass_d *
     437                 :      280114 : make_pass_ipa_comdats (gcc::context *ctxt)
     438                 :             : {
     439                 :      280114 :   return new pass_ipa_comdats (ctxt);
     440                 :             : }
        

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.