LCOV - code coverage report
Current view: top level - gcc - multiple_target.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 95.5 % 246 235
Test Date: 2024-03-23 14:05:01 Functions: 100.0 % 13 13
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* Pass for parsing functions with multiple target attributes.
       2                 :             : 
       3                 :             :    Contributed by Evgeny Stupachenko <evstupac@gmail.com>
       4                 :             : 
       5                 :             :    Copyright (C) 2015-2024 Free Software Foundation, Inc.
       6                 :             : 
       7                 :             : This file is part of GCC.
       8                 :             : 
       9                 :             : GCC is free software; you can redistribute it and/or modify it under
      10                 :             : the terms of the GNU General Public License as published by the Free
      11                 :             : Software Foundation; either version 3, or (at your option) any later
      12                 :             : version.
      13                 :             : 
      14                 :             : GCC is distributed in the hope that it will be useful, but WITHOUT ANY
      15                 :             : WARRANTY; without even the implied warranty of MERCHANTABILITY or
      16                 :             : FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      17                 :             : for more details.
      18                 :             : 
      19                 :             : You should have received a copy of the GNU General Public License
      20                 :             : along with GCC; see the file COPYING3.  If not see
      21                 :             : <http://www.gnu.org/licenses/>.  */
      22                 :             : 
      23                 :             : #include "config.h"
      24                 :             : #include "system.h"
      25                 :             : #include "coretypes.h"
      26                 :             : #include "backend.h"
      27                 :             : #include "tree.h"
      28                 :             : #include "stringpool.h"
      29                 :             : #include "gimple.h"
      30                 :             : #include "diagnostic-core.h"
      31                 :             : #include "gimple-ssa.h"
      32                 :             : #include "cgraph.h"
      33                 :             : #include "tree-pass.h"
      34                 :             : #include "target.h"
      35                 :             : #include "attribs.h"
      36                 :             : #include "pretty-print.h"
      37                 :             : #include "gimple-iterator.h"
      38                 :             : #include "gimple-walk.h"
      39                 :             : #include "tree-inline.h"
      40                 :             : #include "intl.h"
      41                 :             : 
      42                 :             : /* Walker callback that replaces all FUNCTION_DECL of a function that's
      43                 :             :    going to be versioned.  */
      44                 :             : 
      45                 :             : static tree
      46                 :         127 : replace_function_decl (tree *op, int *walk_subtrees, void *data)
      47                 :             : {
      48                 :         127 :   struct walk_stmt_info *wi = (struct walk_stmt_info *) data;
      49                 :         127 :   cgraph_function_version_info *info = (cgraph_function_version_info *)wi->info;
      50                 :             : 
      51                 :         127 :   if (TREE_CODE (*op) == FUNCTION_DECL
      52                 :          50 :       && info->this_node->decl == *op)
      53                 :             :     {
      54                 :          26 :       *op = info->dispatcher_resolver;
      55                 :          26 :       *walk_subtrees = 0;
      56                 :             :     }
      57                 :             : 
      58                 :         127 :   return NULL;
      59                 :             : }
      60                 :             : 
      61                 :             : /* If the call in NODE has multiple target attribute with multiple fields,
      62                 :             :    replace it with dispatcher call and create dispatcher (once).  */
      63                 :             : 
      64                 :             : static void
      65                 :          66 : create_dispatcher_calls (struct cgraph_node *node)
      66                 :             : {
      67                 :          66 :   ipa_ref *ref;
      68                 :             : 
      69                 :          66 :   if (!targetm.has_ifunc_p ())
      70                 :             :     {
      71                 :           0 :       error_at (DECL_SOURCE_LOCATION (node->decl),
      72                 :             :                 "the call requires %<ifunc%>, which is not"
      73                 :             :                 " supported by this target");
      74                 :           0 :       return;
      75                 :             :     }
      76                 :          66 :   else if (!targetm.get_function_versions_dispatcher)
      77                 :             :     {
      78                 :           0 :       error_at (DECL_SOURCE_LOCATION (node->decl),
      79                 :             :                 "target does not support function version dispatcher");
      80                 :           0 :       return;
      81                 :             :     }
      82                 :             : 
      83                 :          66 :   tree idecl = targetm.get_function_versions_dispatcher (node->decl);
      84                 :          66 :   if (!idecl)
      85                 :             :     {
      86                 :           0 :       error_at (DECL_SOURCE_LOCATION (node->decl),
      87                 :             :                 "default %<target_clones%> attribute was not set");
      88                 :           0 :       return;
      89                 :             :     }
      90                 :             : 
      91                 :          66 :   cgraph_node *inode = cgraph_node::get (idecl);
      92                 :          66 :   gcc_assert (inode);
      93                 :          66 :   tree resolver_decl = targetm.generate_version_dispatcher_body (inode);
      94                 :             : 
      95                 :             :   /* Update aliases.  */
      96                 :          66 :   inode->alias = true;
      97                 :          66 :   inode->alias_target = resolver_decl;
      98                 :          66 :   if (!inode->analyzed)
      99                 :          50 :     inode->resolve_alias (cgraph_node::get (resolver_decl));
     100                 :             : 
     101                 :          66 :   auto_vec<cgraph_edge *> edges_to_redirect;
     102                 :             :   /* We need to capture the references by value rather than just pointers to them
     103                 :             :      and remove them right away, as removing them later would invalidate what
     104                 :             :      some other reference pointers point to.  */
     105                 :          66 :   auto_vec<ipa_ref> references_to_redirect;
     106                 :             : 
     107                 :         162 :   while (node->iterate_referring (0, ref))
     108                 :             :     {
     109                 :          96 :       references_to_redirect.safe_push (*ref);
     110                 :          96 :       ref->remove_reference ();
     111                 :             :     }
     112                 :             : 
     113                 :             :   /* We need to remember NEXT_CALLER as it could be modified in the loop.  */
     114                 :         117 :   for (cgraph_edge *e = node->callers; e ; e = e->next_caller)
     115                 :          51 :     edges_to_redirect.safe_push (e);
     116                 :             : 
     117                 :          66 :   if (!edges_to_redirect.is_empty () || !references_to_redirect.is_empty ())
     118                 :             :     {
     119                 :             :       /* Redirect edges.  */
     120                 :             :       unsigned i;
     121                 :             :       cgraph_edge *e;
     122                 :         117 :       FOR_EACH_VEC_ELT (edges_to_redirect, i, e)
     123                 :             :         {
     124                 :          51 :           e->redirect_callee (inode);
     125                 :          51 :           cgraph_edge::redirect_call_stmt_to_callee (e);
     126                 :             :         }
     127                 :             : 
     128                 :             :       /* Redirect references.  */
     129                 :         162 :       FOR_EACH_VEC_ELT (references_to_redirect, i, ref)
     130                 :             :         {
     131                 :          96 :           if (ref->use == IPA_REF_ADDR)
     132                 :             :             {
     133                 :          92 :               struct walk_stmt_info wi;
     134                 :          92 :               memset (&wi, 0, sizeof (wi));
     135                 :          92 :               wi.info = (void *)node->function_version ();
     136                 :             : 
     137                 :          92 :               if (dyn_cast<varpool_node *> (ref->referring))
     138                 :             :                 {
     139                 :           1 :                   hash_set<tree> visited_nodes;
     140                 :           1 :                   walk_tree (&DECL_INITIAL (ref->referring->decl),
     141                 :             :                              replace_function_decl, &wi, &visited_nodes);
     142                 :           1 :                 }
     143                 :             :               else
     144                 :             :                 {
     145                 :          91 :                   gimple_stmt_iterator it = gsi_for_stmt (ref->stmt);
     146                 :          91 :                   if (ref->referring->decl != resolver_decl)
     147                 :          25 :                     walk_gimple_stmt (&it, NULL, replace_function_decl, &wi);
     148                 :             :                 }
     149                 :             : 
     150                 :          92 :               symtab_node *source = ref->referring;
     151                 :          92 :               source->create_reference (inode, IPA_REF_ADDR);
     152                 :             :             }
     153                 :           4 :           else if (ref->use == IPA_REF_ALIAS)
     154                 :             :             {
     155                 :           4 :               symtab_node *source = ref->referring;
     156                 :           4 :               source->create_reference (inode, IPA_REF_ALIAS);
     157                 :           4 :               if (inode->get_comdat_group ())
     158                 :           3 :                 source->add_to_same_comdat_group (inode);
     159                 :             :             }
     160                 :             :           else
     161                 :           0 :             gcc_unreachable ();
     162                 :             :         }
     163                 :             :     }
     164                 :             : 
     165                 :          66 :   tree fname = clone_function_name (node->decl, "default");
     166                 :          66 :   symtab->change_decl_assembler_name (node->decl, fname);
     167                 :             : 
     168                 :          66 :   if (node->definition)
     169                 :             :     {
     170                 :             :       /* FIXME: copy of cgraph_node::make_local that should be cleaned up
     171                 :             :                 in next stage1.  */
     172                 :          64 :       node->make_decl_local ();
     173                 :          64 :       node->set_section (NULL);
     174                 :          64 :       node->set_comdat_group (NULL);
     175                 :          64 :       node->externally_visible = false;
     176                 :          64 :       node->forced_by_abi = false;
     177                 :             : 
     178                 :          64 :       DECL_ARTIFICIAL (node->decl) = 1;
     179                 :          64 :       node->force_output = true;
     180                 :             :     }
     181                 :          66 : }
     182                 :             : 
     183                 :             : /* Create string with attributes separated by comma.
     184                 :             :    Return number of attributes.  */
     185                 :             : 
     186                 :             : static int
     187                 :          70 : get_attr_str (tree arglist, char *attr_str)
     188                 :             : {
     189                 :          70 :   tree arg;
     190                 :          70 :   size_t str_len_sum = 0;
     191                 :          70 :   int argnum = 0;
     192                 :             : 
     193                 :         255 :   for (arg = arglist; arg; arg = TREE_CHAIN (arg))
     194                 :             :     {
     195                 :         185 :       const char *str = TREE_STRING_POINTER (TREE_VALUE (arg));
     196                 :         185 :       size_t len = strlen (str);
     197                 :         199 :       for (const char *p = strchr (str, ','); p; p = strchr (p + 1, ','))
     198                 :          14 :         argnum++;
     199                 :         185 :       memcpy (attr_str + str_len_sum, str, len);
     200                 :         185 :       attr_str[str_len_sum + len] = TREE_CHAIN (arg) ? ',' : '\0';
     201                 :         185 :       str_len_sum += len + 1;
     202                 :         185 :       argnum++;
     203                 :             :     }
     204                 :          70 :   return argnum;
     205                 :             : }
     206                 :             : 
     207                 :             : /* Return number of attributes separated by comma and put them into ARGS.
     208                 :             :    If there is no DEFAULT attribute return -1.
     209                 :             :    If there is an empty string in attribute return -2.
     210                 :             :    If there are multiple DEFAULT attributes return -3.
     211                 :             :    */
     212                 :             : 
     213                 :             : static int
     214                 :          70 : separate_attrs (char *attr_str, char **attrs, int attrnum)
     215                 :             : {
     216                 :          70 :   int i = 0;
     217                 :          70 :   int default_count = 0;
     218                 :             : 
     219                 :          70 :   for (char *attr = strtok (attr_str, ",");
     220                 :         268 :        attr != NULL; attr = strtok (NULL, ","))
     221                 :             :     {
     222                 :         198 :       if (strcmp (attr, "default") == 0)
     223                 :             :         {
     224                 :          70 :           default_count++;
     225                 :          70 :           continue;
     226                 :             :         }
     227                 :         128 :       attrs[i++] = attr;
     228                 :             :     }
     229                 :          70 :   if (default_count == 0)
     230                 :             :     return -1;
     231                 :          69 :   else if (default_count > 1)
     232                 :             :     return -3;
     233                 :          68 :   else if (i + default_count < attrnum)
     234                 :           1 :     return -2;
     235                 :             : 
     236                 :             :   return i;
     237                 :             : }
     238                 :             : 
     239                 :             : /*  Return true if symbol is valid in assembler name.  */
     240                 :             : 
     241                 :             : static bool
     242                 :         935 : is_valid_asm_symbol (char c)
     243                 :             : {
     244                 :         935 :   if ('a' <= c && c <= 'z')
     245                 :             :     return true;
     246                 :         208 :   if ('A' <= c && c <= 'Z')
     247                 :             :     return true;
     248                 :         208 :   if ('0' <= c && c <= '9')
     249                 :             :     return true;
     250                 :          70 :   if (c == '_')
     251                 :           0 :     return true;
     252                 :             :   return false;
     253                 :             : }
     254                 :             : 
     255                 :             : /*  Replace all not valid assembler symbols with '_'.  */
     256                 :             : 
     257                 :             : static void
     258                 :         121 : create_new_asm_name (char *old_asm_name, char *new_asm_name)
     259                 :             : {
     260                 :         121 :   int i;
     261                 :         121 :   int old_name_len = strlen (old_asm_name);
     262                 :             : 
     263                 :             :   /* Replace all not valid assembler symbols with '_'.  */
     264                 :        1056 :   for (i = 0; i < old_name_len; i++)
     265                 :         935 :     if (!is_valid_asm_symbol (old_asm_name[i]))
     266                 :          70 :       new_asm_name[i] = '_';
     267                 :             :     else
     268                 :         865 :       new_asm_name[i] = old_asm_name[i];
     269                 :         121 :   new_asm_name[old_name_len] = '\0';
     270                 :         121 : }
     271                 :             : 
     272                 :             : /*  Creates target clone of NODE.  */
     273                 :             : 
     274                 :             : static cgraph_node *
     275                 :         121 : create_target_clone (cgraph_node *node, bool definition, char *name,
     276                 :             :                      tree attributes)
     277                 :             : {
     278                 :         121 :   cgraph_node *new_node;
     279                 :             : 
     280                 :         121 :   if (definition)
     281                 :             :     {
     282                 :         102 :       new_node
     283                 :         102 :         = node->create_version_clone_with_body (vNULL, NULL, NULL, NULL, NULL,
     284                 :             :                                                 name, attributes, false);
     285                 :         102 :       if (new_node == NULL)
     286                 :             :         return NULL;
     287                 :         101 :       new_node->force_output = true;
     288                 :             :     }
     289                 :             :   else
     290                 :             :     {
     291                 :          19 :       tree new_decl = copy_node (node->decl);
     292                 :          19 :       new_node = cgraph_node::get_create (new_decl);
     293                 :          19 :       DECL_ATTRIBUTES (new_decl) = attributes;
     294                 :             :       /* Generate a new name for the new version.  */
     295                 :          19 :       tree fname = clone_function_name (node->decl, name);
     296                 :          19 :       symtab->change_decl_assembler_name (new_node->decl, fname);
     297                 :             :     }
     298                 :             :   return new_node;
     299                 :             : }
     300                 :             : 
     301                 :             : /* If the function in NODE has multiple target attributes
     302                 :             :    create the appropriate clone for each valid target attribute.  */
     303                 :             : 
     304                 :             : static bool
     305                 :     3456932 : expand_target_clones (struct cgraph_node *node, bool definition)
     306                 :             : {
     307                 :     3456932 :   int i;
     308                 :             :   /* Parsing target attributes separated by comma.  */
     309                 :     3456932 :   tree attr_target = lookup_attribute ("target_clones",
     310                 :     3456932 :                                        DECL_ATTRIBUTES (node->decl));
     311                 :             :   /* No targets specified.  */
     312                 :     3456932 :   if (!attr_target)
     313                 :             :     return false;
     314                 :             : 
     315                 :          76 :   tree arglist = TREE_VALUE (attr_target);
     316                 :          76 :   int attr_len = get_target_clone_attr_len (arglist);
     317                 :             : 
     318                 :             :   /* No need to clone for 1 target attribute.  */
     319                 :          76 :   if (attr_len == -1)
     320                 :             :     {
     321                 :           0 :       warning_at (DECL_SOURCE_LOCATION (node->decl),
     322                 :             :                   0, "single %<target_clones%> attribute is ignored");
     323                 :           0 :       return false;
     324                 :             :     }
     325                 :             : 
     326                 :          76 :   if (node->definition
     327                 :          76 :       && (node->alias || !tree_versionable_function_p (node->decl)))
     328                 :             :     {
     329                 :           6 :       auto_diagnostic_group d;
     330                 :           6 :       error_at (DECL_SOURCE_LOCATION (node->decl),
     331                 :             :                 "clones for %<target_clones%> attribute cannot be created");
     332                 :           6 :       const char *reason = NULL;
     333                 :           6 :       if (lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
     334                 :             :         reason = G_("function %q+F can never be copied "
     335                 :             :                     "because it has %<noclone%> attribute");
     336                 :           3 :       else if (node->alias)
     337                 :             :         reason
     338                 :             :           = "%<target_clones%> cannot be combined with %<alias%> attribute";
     339                 :             :       else
     340                 :           2 :         reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl));
     341                 :           2 :       if (reason)
     342                 :           6 :         inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
     343                 :           6 :       return false;
     344                 :           6 :     }
     345                 :             : 
     346                 :          70 :   char *attr_str = XNEWVEC (char, attr_len);
     347                 :          70 :   int attrnum = get_attr_str (arglist, attr_str);
     348                 :          70 :   char **attrs = XNEWVEC (char *, attrnum);
     349                 :             : 
     350                 :          70 :   attrnum = separate_attrs (attr_str, attrs, attrnum);
     351                 :          70 :   switch (attrnum)
     352                 :             :     {
     353                 :           1 :     case -1:
     354                 :           1 :       error_at (DECL_SOURCE_LOCATION (node->decl),
     355                 :             :                 "%<default%> target was not set");
     356                 :           1 :       break;
     357                 :           1 :     case -2:
     358                 :           1 :       error_at (DECL_SOURCE_LOCATION (node->decl),
     359                 :             :                 "an empty string cannot be in %<target_clones%> attribute");
     360                 :           1 :       break;
     361                 :           1 :     case -3:
     362                 :           1 :       error_at (DECL_SOURCE_LOCATION (node->decl),
     363                 :             :                 "multiple %<default%> targets were set");
     364                 :           1 :       break;
     365                 :             :     default:
     366                 :             :       break;
     367                 :             :     }
     368                 :             : 
     369                 :          70 :   if (attrnum < 0)
     370                 :             :     {
     371                 :           3 :       XDELETEVEC (attrs);
     372                 :           3 :       XDELETEVEC (attr_str);
     373                 :           3 :       return false;
     374                 :             :     }
     375                 :             : 
     376                 :          67 :   const char *new_attr_name = (TARGET_HAS_FMV_TARGET_ATTRIBUTE
     377                 :             :                                ? "target" : "target_version");
     378                 :          67 :   cgraph_function_version_info *decl1_v = NULL;
     379                 :          67 :   cgraph_function_version_info *decl2_v = NULL;
     380                 :          67 :   cgraph_function_version_info *before = NULL;
     381                 :          67 :   cgraph_function_version_info *after = NULL;
     382                 :          67 :   decl1_v = node->function_version ();
     383                 :          67 :   if (decl1_v == NULL)
     384                 :          67 :     decl1_v = node->insert_new_function_version ();
     385                 :          67 :   before = decl1_v;
     386                 :          67 :   DECL_FUNCTION_VERSIONED (node->decl) = 1;
     387                 :             : 
     388                 :         187 :   for (i = 0; i < attrnum; i++)
     389                 :             :     {
     390                 :         121 :       char *attr = attrs[i];
     391                 :             : 
     392                 :             :       /* Create new target clone.  */
     393                 :         121 :       tree attributes = make_attribute (new_attr_name, attr,
     394                 :         121 :                                         DECL_ATTRIBUTES (node->decl));
     395                 :             : 
     396                 :         121 :       char *suffix = XNEWVEC (char, strlen (attr) + 1);
     397                 :         121 :       create_new_asm_name (attr, suffix);
     398                 :         121 :       cgraph_node *new_node = create_target_clone (node, definition, suffix,
     399                 :             :                                                    attributes);
     400                 :         121 :       XDELETEVEC (suffix);
     401                 :         121 :       if (new_node == NULL)
     402                 :             :         {
     403                 :           1 :           XDELETEVEC (attrs);
     404                 :           1 :           XDELETEVEC (attr_str);
     405                 :           1 :           return false;
     406                 :             :         }
     407                 :         120 :       new_node->local = false;
     408                 :             : 
     409                 :         120 :       decl2_v = new_node->function_version ();
     410                 :         120 :       if (decl2_v != NULL)
     411                 :           0 :         continue;
     412                 :         120 :       decl2_v = new_node->insert_new_function_version ();
     413                 :             : 
     414                 :             :       /* Chain decl2_v and decl1_v.  All semantically identical versions
     415                 :             :          will be chained together.  */
     416                 :         120 :       after = decl2_v;
     417                 :         293 :       while (before->next != NULL)
     418                 :             :         before = before->next;
     419                 :         120 :       while (after->prev != NULL)
     420                 :             :         after = after->prev;
     421                 :             : 
     422                 :         120 :       before->next = after;
     423                 :         120 :       after->prev = before;
     424                 :         120 :       DECL_FUNCTION_VERSIONED (new_node->decl) = 1;
     425                 :             :     }
     426                 :             : 
     427                 :          66 :   XDELETEVEC (attrs);
     428                 :          66 :   XDELETEVEC (attr_str);
     429                 :             : 
     430                 :             :   /* Setting new attribute to initial function.  */
     431                 :          66 :   tree attributes = make_attribute (new_attr_name, "default",
     432                 :          66 :                                     DECL_ATTRIBUTES (node->decl));
     433                 :          66 :   DECL_ATTRIBUTES (node->decl) = attributes;
     434                 :          66 :   node->local = false;
     435                 :          66 :   return true;
     436                 :             : }
     437                 :             : 
     438                 :             : /* When NODE is a target clone, consider all callees and redirect
     439                 :             :    to a clone with equal target attributes.  That prevents multiple
     440                 :             :    multi-versioning dispatches and a call-chain can be optimized.  */
     441                 :             : 
     442                 :             : static void
     443                 :     3457301 : redirect_to_specific_clone (cgraph_node *node)
     444                 :             : {
     445                 :     3457301 :   cgraph_function_version_info *fv = node->function_version ();
     446                 :     3457301 :   if (fv == NULL)
     447                 :             :     return;
     448                 :             : 
     449                 :        1001 :   tree attr_target = lookup_attribute ("target", DECL_ATTRIBUTES (node->decl));
     450                 :        1001 :   if (attr_target == NULL_TREE)
     451                 :             :     return;
     452                 :             : 
     453                 :             :   /* We need to remember NEXT_CALLER as it could be modified in the loop.  */
     454                 :         893 :   for (cgraph_edge *e = node->callees; e ; e = e->next_callee)
     455                 :             :     {
     456                 :          67 :       cgraph_function_version_info *fv2 = e->callee->function_version ();
     457                 :          67 :       if (!fv2)
     458                 :          54 :         continue;
     459                 :             : 
     460                 :          13 :       tree attr_target2 = lookup_attribute ("target",
     461                 :          13 :                                             DECL_ATTRIBUTES (e->callee->decl));
     462                 :             : 
     463                 :             :       /* Function is not calling proper target clone.  */
     464                 :          13 :       if (attr_target2 == NULL_TREE
     465                 :          13 :           || !attribute_value_equal (attr_target, attr_target2))
     466                 :             :         {
     467                 :          13 :           while (fv2->prev != NULL)
     468                 :             :             fv2 = fv2->prev;
     469                 :             : 
     470                 :             :           /* Try to find a clone with equal target attribute.  */
     471                 :          32 :           for (; fv2 != NULL; fv2 = fv2->next)
     472                 :             :             {
     473                 :          32 :               cgraph_node *callee = fv2->this_node;
     474                 :          32 :               attr_target2 = lookup_attribute ("target",
     475                 :          32 :                                                DECL_ATTRIBUTES (callee->decl));
     476                 :          32 :               if (attr_target2 != NULL_TREE
     477                 :          32 :                   && attribute_value_equal (attr_target, attr_target2))
     478                 :             :                 {
     479                 :          13 :                   e->redirect_callee (callee);
     480                 :          13 :                   cgraph_edge::redirect_call_stmt_to_callee (e);
     481                 :          13 :                   break;
     482                 :             :                 }
     483                 :             :             }
     484                 :             :         }
     485                 :             :     }
     486                 :             : }
     487                 :             : 
     488                 :             : static unsigned int
     489                 :      229921 : ipa_target_clone (void)
     490                 :             : {
     491                 :      229921 :   struct cgraph_node *node;
     492                 :      229921 :   auto_vec<cgraph_node *> to_dispatch;
     493                 :             : 
     494                 :     7373706 :   FOR_EACH_FUNCTION (node)
     495                 :     3456932 :     if (expand_target_clones (node, node->definition))
     496                 :          66 :       to_dispatch.safe_push (node);
     497                 :             : 
     498                 :      230114 :   for (unsigned i = 0; i < to_dispatch.length (); i++)
     499                 :          66 :     create_dispatcher_calls (to_dispatch[i]);
     500                 :             : 
     501                 :     7374444 :   FOR_EACH_FUNCTION (node)
     502                 :     3457301 :     redirect_to_specific_clone (node);
     503                 :             : 
     504                 :      229921 :   return 0;
     505                 :      229921 : }
     506                 :             : 
     507                 :             : namespace {
     508                 :             : 
     509                 :             : const pass_data pass_data_target_clone =
     510                 :             : {
     511                 :             :   SIMPLE_IPA_PASS,              /* type */
     512                 :             :   "targetclone",              /* name */
     513                 :             :   OPTGROUP_NONE,                /* optinfo_flags */
     514                 :             :   TV_NONE,                      /* tv_id */
     515                 :             :   ( PROP_ssa | PROP_cfg ),      /* properties_required */
     516                 :             :   0,                            /* properties_provided */
     517                 :             :   0,                            /* properties_destroyed */
     518                 :             :   0,                            /* todo_flags_start */
     519                 :             :   TODO_update_ssa               /* todo_flags_finish */
     520                 :             : };
     521                 :             : 
     522                 :             : class pass_target_clone : public simple_ipa_opt_pass
     523                 :             : {
     524                 :             : public:
     525                 :      285617 :   pass_target_clone (gcc::context *ctxt)
     526                 :      571234 :     : simple_ipa_opt_pass (pass_data_target_clone, ctxt)
     527                 :             :   {}
     528                 :             : 
     529                 :             :   /* opt_pass methods: */
     530                 :             :   bool gate (function *) final override;
     531                 :      229921 :   unsigned int execute (function *) final override
     532                 :             :   {
     533                 :      229921 :     return ipa_target_clone ();
     534                 :             :   }
     535                 :             : };
     536                 :             : 
     537                 :             : bool
     538                 :      230030 : pass_target_clone::gate (function *)
     539                 :             : {
     540                 :             :   /* If there were any errors avoid pass property verification errors.  */
     541                 :      230030 :   return !seen_error ();
     542                 :             : }
     543                 :             : 
     544                 :             : } // anon namespace
     545                 :             : 
     546                 :             : simple_ipa_opt_pass *
     547                 :      285617 : make_pass_target_clone (gcc::context *ctxt)
     548                 :             : {
     549                 :      285617 :   return new pass_target_clone (ctxt);
     550                 :             : }
        

Generated by: LCOV version 2.0-1

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.