LCOV - code coverage report
Current view: top level - gcc - ipa-comdats.c (source / functions) Hit Total Coverage
Test: gcc.info Lines: 148 149 99.3 %
Date: 2020-04-04 11:58:09 Functions: 8 8 100.0 %
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-2020 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                 :      57876 : propagate_comdat_group (struct symtab_node *symbol,
      66                 :            :                         tree newgroup, hash_map<symtab_node *, tree> &map)
      67                 :            : {
      68                 :      57876 :   int i;
      69                 :      57876 :   struct ipa_ref *ref;
      70                 :            : 
      71                 :            :   /* Walk all references to SYMBOL, recursively dive into aliases.  */
      72                 :            : 
      73                 :      76277 :   for (i = 0;
      74                 :     179683 :        symbol->iterate_referring (i, ref)
      75                 :     121807 :        && newgroup != error_mark_node; i++)
      76                 :            :     {
      77                 :      39299 :       struct symtab_node *symbol2 = ref->referring;
      78                 :            : 
      79                 :      39299 :       if (ref->use == IPA_REF_ALIAS)
      80                 :            :         {
      81                 :        609 :           newgroup = propagate_comdat_group (symbol2, newgroup, map);
      82                 :        609 :           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                 :      38690 :       if (symbol->type != symbol2->type)
      90                 :            :         {
      91                 :      20898 :           newgroup = error_mark_node;
      92                 :      20898 :           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                 :      17792 :       if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2))
     100                 :            :         {
     101                 :      10715 :           if (cn->inlined_to)
     102                 :       1508 :             symbol2 = cn->inlined_to;
     103                 :            :         }
     104                 :            : 
     105                 :            :       /* The actual merge operation.  */
     106                 :            : 
     107                 :      35584 :       tree *val2 = map.get (symbol2);
     108                 :            : 
     109                 :      16848 :       if (val2 && *val2 != newgroup)
     110                 :            :         {
     111                 :      16844 :           if (!newgroup)
     112                 :            :             newgroup = *val2;
     113                 :            :           else
     114                 :         12 :             newgroup = error_mark_node;
     115                 :            :         }
     116                 :            :     }
     117                 :            : 
     118                 :            :   /* If we analyze function, walk also callers.  */
     119                 :            : 
     120                 :      57876 :   cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol);
     121                 :            : 
     122                 :      38778 :   if (cnode)
     123                 :      38778 :     for (struct cgraph_edge * edge = cnode->callers;
     124                 :      67957 :          edge && newgroup != error_mark_node; edge = edge->next_caller)
     125                 :            :       {
     126                 :      29179 :         struct symtab_node *symbol2 = edge->caller;
     127                 :            : 
     128                 :      29179 :         if (cgraph_node * cn = dyn_cast <cgraph_node *> (symbol2))
     129                 :            :           {
     130                 :            :             /* Thunks cannot call across section boundary.  */
     131                 :      29179 :             if (cn->thunk.thunk_p)
     132                 :        517 :               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                 :      29179 :             if (cn->inlined_to)
     137                 :      11738 :               symbol2 = cn->inlined_to;
     138                 :            :           }
     139                 :            : 
     140                 :            :         /* The actual merge operation.  */
     141                 :            : 
     142                 :      58358 :         tree *val2 = map.get (symbol2);
     143                 :            : 
     144                 :      21220 :         if (val2 && *val2 != newgroup)
     145                 :            :           {
     146                 :      19109 :             if (!newgroup)
     147                 :            :               newgroup = *val2;
     148                 :            :             else
     149                 :       2638 :               newgroup = error_mark_node;
     150                 :            :           }
     151                 :            :       }
     152                 :      57876 :   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                 :     112258 : enqueue_references (symtab_node **first,
     162                 :            :                     symtab_node *symbol)
     163                 :            : {
     164                 :     112258 :   int i;
     165                 :     112258 :   struct ipa_ref *ref = NULL;
     166                 :            : 
     167                 :     258619 :   for (i = 0; symbol->iterate_reference (i, ref); i++)
     168                 :            :     {
     169                 :     146361 :       symtab_node *node = ref->referred->ultimate_alias_target ();
     170                 :            : 
     171                 :            :       /* Always keep thunks in same sections as target function.  */
     172                 :     146361 :       if (is_a <cgraph_node *>(node))
     173                 :      15318 :         node = dyn_cast <cgraph_node *> (node)->function_symbol ();
     174                 :     146361 :       if (!node->aux && node->definition)
     175                 :            :         {
     176                 :        734 :            node->aux = *first;
     177                 :        734 :            *first = node;
     178                 :            :         }
     179                 :            :     }
     180                 :            : 
     181                 :     112258 :   if (cgraph_node *cnode = dyn_cast <cgraph_node *> (symbol))
     182                 :            :     {
     183                 :      93628 :       struct cgraph_edge *edge;
     184                 :            : 
     185                 :     386153 :       for (edge = cnode->callees; edge; edge = edge->next_callee)
     186                 :     292525 :         if (!edge->inline_failed)
     187                 :      57885 :           enqueue_references (first, edge->callee);
     188                 :            :         else
     189                 :            :           {
     190                 :     234640 :             symtab_node *node = edge->callee->ultimate_alias_target ();
     191                 :            : 
     192                 :            :             /* Always keep thunks in same sections as target function.  */
     193                 :     234640 :             if (is_a <cgraph_node *>(node))
     194                 :     234640 :               node = dyn_cast <cgraph_node *> (node)->function_symbol ();
     195                 :     234640 :             if (!node->aux && node->definition)
     196                 :            :               {
     197                 :       1672 :                  node->aux = *first;
     198                 :       1672 :                  *first = node;
     199                 :            :               }
     200                 :            :           }
     201                 :            :     }
     202                 :     112258 : }
     203                 :            : 
     204                 :            : /* Set comdat group of SYMBOL to GROUP.
     205                 :            :    Callback for for_node_and_aliases.  */
     206                 :            : 
     207                 :            : bool
     208                 :       2306 : set_comdat_group (symtab_node *symbol,
     209                 :            :                   void *head_p)
     210                 :            : {
     211                 :       2306 :   symtab_node *head = (symtab_node *)head_p;
     212                 :            : 
     213                 :       2306 :   gcc_assert (!symbol->get_comdat_group ());
     214                 :       2306 :   if (symbol->real_symbol_p ())
     215                 :            :     {
     216                 :       2306 :       symbol->set_comdat_group (head->get_comdat_group ());
     217                 :       2306 :       symbol->add_to_same_comdat_group (head);
     218                 :            :     }
     219                 :       2306 :   return false;
     220                 :            : }
     221                 :            : 
     222                 :            : /* Set comdat group of SYMBOL to GROUP.
     223                 :            :    Callback for for_node_thunks_and_aliases.  */
     224                 :            : 
     225                 :            : bool
     226                 :       2300 : set_comdat_group_1 (cgraph_node *symbol,
     227                 :            :                     void *head_p)
     228                 :            : {
     229                 :       2300 :   return set_comdat_group (symbol, head_p);
     230                 :            : }
     231                 :            : 
     232                 :            : /* The actual pass with the main dataflow loop.  */
     233                 :            : 
     234                 :            : static unsigned int
     235                 :     163705 : ipa_comdats (void)
     236                 :            : {
     237                 :     163705 :   hash_map<symtab_node *, tree> map (251);
     238                 :     327410 :   hash_map<tree, symtab_node *> comdat_head_map (251);
     239                 :     163705 :   symtab_node *symbol;
     240                 :     163705 :   bool comdat_group_seen = false;
     241                 :     163705 :   symtab_node *first = (symtab_node *) (void *) 1;
     242                 :     163705 :   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                 :    8100170 :   FOR_EACH_DEFINED_SYMBOL (symbol)
     249                 :    3886380 :     if (!symbol->real_symbol_p ())
     250                 :            :       ;
     251                 :    3294790 :     else if ((group = symbol->get_comdat_group ()) != NULL)
     252                 :            :       {
     253                 :     453420 :         map.put (symbol, group);
     254                 :     453420 :         comdat_head_map.put (group, symbol);
     255                 :     453420 :         comdat_group_seen = true;
     256                 :            : 
     257                 :            :         /* Mark the symbol so we won't waste time visiting it for dataflow.  */
     258                 :     453420 :         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                 :    2841370 :     else if (symbol->externally_visible
     264                 :            :              || symbol->force_output
     265                 :    2841370 :              || symbol->used_from_other_partition
     266                 :    1176220 :              || TREE_THIS_VOLATILE (symbol->decl)
     267                 :    1171860 :              || symbol->get_section ()
     268                 :    3128690 :              || (TREE_CODE (symbol->decl) == FUNCTION_DECL
     269                 :     132724 :                  && (DECL_STATIC_CONSTRUCTOR (symbol->decl)
     270                 :     132724 :                      || DECL_STATIC_DESTRUCTOR (symbol->decl))))
     271                 :            :       {
     272                 :    2561320 :         symtab_node *target = symbol->ultimate_alias_target ();
     273                 :            : 
     274                 :            :         /* Always keep thunks in same sections as target function.  */
     275                 :    2561320 :         if (is_a <cgraph_node *>(target))
     276                 :     703839 :           target = dyn_cast <cgraph_node *> (target)->function_symbol ();
     277                 :    2561320 :         map.put (target, error_mark_node);
     278                 :            : 
     279                 :            :         /* Mark the symbol so we won't waste time visiting it for dataflow.  */
     280                 :    2561320 :         symbol->aux = (symtab_node *) (void *) 1;
     281                 :            :       }
     282                 :            :     else
     283                 :            :       {
     284                 :            :         /* Enqueue symbol for dataflow.  */
     285                 :     280053 :         symbol->aux = first;
     286                 :     280053 :         first = symbol;
     287                 :            :       }
     288                 :            : 
     289                 :     163705 :   if (!comdat_group_seen)
     290                 :            :     {
     291                 :    1956620 :       FOR_EACH_DEFINED_SYMBOL (symbol)
     292                 :    1673060 :         symbol->aux = NULL;
     293                 :            :       return 0;
     294                 :            :     }
     295                 :            : 
     296                 :            :   /* The actual dataflow.  */
     297                 :            : 
     298                 :      78684 :   while (first != (void *) 1)
     299                 :            :     {
     300                 :      56756 :       tree group = NULL;
     301                 :      56756 :       tree newgroup, *val;
     302                 :            : 
     303                 :      56756 :       symbol = first;
     304                 :      56756 :       first = (symtab_node *)first->aux;
     305                 :            : 
     306                 :            :       /* Get current lattice value of SYMBOL.  */
     307                 :      56756 :       val = map.get (symbol);
     308                 :        228 :       if (val)
     309                 :        228 :         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                 :      56756 :       if (group == error_mark_node)
     314                 :       2383 :         continue;
     315                 :            : 
     316                 :      56750 :       newgroup = propagate_comdat_group (symbol, group, map);
     317                 :            : 
     318                 :            :       /* If nothing changed, proceed to next symbol.  */
     319                 :      56750 :       if (newgroup == group)
     320                 :            :         {
     321                 :       2377 :           symbol->aux = NULL;
     322                 :       2377 :           continue;
     323                 :            :         }
     324                 :            : 
     325                 :            :       /* Update lattice value and enqueue all references for re-visiting.  */
     326                 :      54373 :       gcc_assert (newgroup);
     327                 :      54373 :       if (val)
     328                 :        172 :         *val = newgroup;
     329                 :            :       else
     330                 :      54201 :         map.put (symbol, newgroup);
     331                 :      54373 :       enqueue_references (&first, symbol);
     332                 :            : 
     333                 :            :       /* We may need to revisit the symbol unless it is BOTTOM.  */
     334                 :      54373 :       if (newgroup != error_mark_node)
     335                 :       2599 :         symbol->aux = NULL;
     336                 :            :     }
     337                 :            : 
     338                 :            :   /* Finally assign symbols to the sections.  */
     339                 :            : 
     340                 :    4470490 :   FOR_EACH_DEFINED_SYMBOL (symbol)
     341                 :            :     {
     342                 :    2213320 :       struct cgraph_node *fun;
     343                 :    2213320 :       symbol->aux = NULL; 
     344                 :    2213320 :       if (!symbol->get_comdat_group ()
     345                 :    1712230 :           && !symbol->alias
     346                 :    1704360 :           && (!(fun = dyn_cast <cgraph_node *> (symbol))
     347                 :     696100 :               || !fun->thunk.thunk_p)
     348                 :    3916830 :           && symbol->real_symbol_p ())
     349                 :            :         {
     350                 :    1255180 :           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                 :          0 :           gcc_assert (val);
     356                 :            : 
     357                 :    1255180 :           tree group = *val;
     358                 :            : 
     359                 :    1255180 :           if (group == error_mark_node)
     360                 :    1252880 :             continue;
     361                 :       2306 :           if (dump_file)
     362                 :            :             {
     363                 :          4 :               fprintf (dump_file, "Localizing symbol\n");
     364                 :          4 :               symbol->dump (dump_file);
     365                 :          4 :               fprintf (dump_file, "To group: %s\n", IDENTIFIER_POINTER (group));
     366                 :            :             }
     367                 :       2306 :           if (is_a <cgraph_node *> (symbol))
     368                 :       2300 :            dyn_cast <cgraph_node *>(symbol)->call_for_symbol_thunks_and_aliases
     369                 :       2300 :                   (set_comdat_group_1,
     370                 :       2300 :                    *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                 :            :   return 0;
     380                 :            : }
     381                 :            : 
     382                 :            : namespace {
     383                 :            : 
     384                 :            : const pass_data pass_data_ipa_comdats =
     385                 :            : {
     386                 :            :   IPA_PASS, /* type */
     387                 :            :   "comdats", /* name */
     388                 :            :   OPTGROUP_NONE, /* optinfo_flags */
     389                 :            :   TV_IPA_COMDATS, /* tv_id */
     390                 :            :   0, /* properties_required */
     391                 :            :   0, /* properties_provided */
     392                 :            :   0, /* properties_destroyed */
     393                 :            :   0, /* todo_flags_start */
     394                 :            :   0, /* todo_flags_finish */
     395                 :            : };
     396                 :            : 
     397                 :            : class pass_ipa_comdats : public ipa_opt_pass_d
     398                 :            : {
     399                 :            : public:
     400                 :     200773 :   pass_ipa_comdats (gcc::context *ctxt)
     401                 :            :     : ipa_opt_pass_d (pass_data_ipa_comdats, ctxt,
     402                 :            :                       NULL, /* generate_summary */
     403                 :            :                       NULL, /* write_summary */
     404                 :            :                       NULL, /* read_summary */
     405                 :            :                       NULL, /* write_optimization_summary */
     406                 :            :                       NULL, /* read_optimization_summary */
     407                 :            :                       NULL, /* stmt_fixup */
     408                 :            :                       0, /* function_transform_todo_flags_start */
     409                 :            :                       NULL, /* function_transform */
     410                 :     401546 :                       NULL) /* variable_transform */
     411                 :            :   {}
     412                 :            : 
     413                 :            :   /* opt_pass methods: */
     414                 :            :   virtual bool gate (function *);
     415                 :     163705 :   virtual unsigned int execute (function *) { return ipa_comdats (); }
     416                 :            : 
     417                 :            : }; // class pass_ipa_comdats
     418                 :            : 
     419                 :            : bool
     420                 :     415684 : pass_ipa_comdats::gate (function *)
     421                 :            : {
     422                 :     415684 :   return HAVE_COMDAT_GROUP;
     423                 :            : }
     424                 :            : 
     425                 :            : } // anon namespace
     426                 :            : 
     427                 :            : ipa_opt_pass_d *
     428                 :     200773 : make_pass_ipa_comdats (gcc::context *ctxt)
     429                 :            : {
     430                 :     200773 :   return new pass_ipa_comdats (ctxt);
     431                 :            : }

Generated by: LCOV version 1.0

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