LCOV - code coverage report
Current view: top level - gcc - multiple_target.cc (source / functions) Coverage Total Hit
Test: gcc.info Lines: 95.6 % 250 239
Test Date: 2024-12-21 13:15:12 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                 :          64 : create_dispatcher_calls (struct cgraph_node *node)
      66                 :             : {
      67                 :          64 :   ipa_ref *ref;
      68                 :             : 
      69                 :          64 :   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                 :          64 :   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                 :          64 :   tree idecl = targetm.get_function_versions_dispatcher (node->decl);
      84                 :          64 :   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                 :          64 :   cgraph_node *inode = cgraph_node::get (idecl);
      92                 :          64 :   gcc_assert (inode);
      93                 :          64 :   tree resolver_decl = targetm.generate_version_dispatcher_body (inode);
      94                 :             : 
      95                 :             :   /* Update aliases.  */
      96                 :          64 :   inode->alias = true;
      97                 :          64 :   inode->alias_target = resolver_decl;
      98                 :          64 :   if (!inode->analyzed)
      99                 :          52 :     inode->resolve_alias (cgraph_node::get (resolver_decl));
     100                 :             : 
     101                 :          64 :   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                 :          64 :   auto_vec<ipa_ref> references_to_redirect;
     106                 :             : 
     107                 :         158 :   while (node->iterate_referring (0, ref))
     108                 :             :     {
     109                 :          94 :       references_to_redirect.safe_push (*ref);
     110                 :          94 :       ref->remove_reference ();
     111                 :             :     }
     112                 :             : 
     113                 :             :   /* We need to remember NEXT_CALLER as it could be modified in the loop.  */
     114                 :         112 :   for (cgraph_edge *e = node->callers; e ; e = e->next_caller)
     115                 :          48 :     edges_to_redirect.safe_push (e);
     116                 :             : 
     117                 :          64 :   if (!edges_to_redirect.is_empty () || !references_to_redirect.is_empty ())
     118                 :             :     {
     119                 :             :       /* Redirect edges.  */
     120                 :             :       unsigned i;
     121                 :             :       cgraph_edge *e;
     122                 :         112 :       FOR_EACH_VEC_ELT (edges_to_redirect, i, e)
     123                 :             :         {
     124                 :          48 :           e->redirect_callee (inode);
     125                 :          48 :           cgraph_edge::redirect_call_stmt_to_callee (e);
     126                 :             :         }
     127                 :             : 
     128                 :             :       /* Redirect references.  */
     129                 :         158 :       FOR_EACH_VEC_ELT (references_to_redirect, i, ref)
     130                 :             :         {
     131                 :          94 :           if (ref->use == IPA_REF_ADDR)
     132                 :             :             {
     133                 :          90 :               struct walk_stmt_info wi;
     134                 :          90 :               memset (&wi, 0, sizeof (wi));
     135                 :          90 :               wi.info = (void *)node->function_version ();
     136                 :             : 
     137                 :          90 :               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                 :          89 :                   gimple_stmt_iterator it = gsi_for_stmt (ref->stmt);
     146                 :          89 :                   if (ref->referring->decl != resolver_decl)
     147                 :          25 :                     walk_gimple_stmt (&it, NULL, replace_function_decl, &wi);
     148                 :             :                 }
     149                 :             : 
     150                 :          90 :               symtab_node *source = ref->referring;
     151                 :          90 :               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                 :          64 :   tree fname = clone_function_name (node->decl, "default");
     166                 :          64 :   symtab->change_decl_assembler_name (node->decl, fname);
     167                 :             : 
     168                 :          64 :   if (node->definition)
     169                 :             :     {
     170                 :             :       /* FIXME: copy of cgraph_node::make_local that should be cleaned up
     171                 :             :                 in next stage1.  */
     172                 :          62 :       node->make_decl_local ();
     173                 :          62 :       node->set_section (NULL);
     174                 :          62 :       node->set_comdat_group (NULL);
     175                 :          62 :       node->externally_visible = false;
     176                 :          62 :       node->forced_by_abi = false;
     177                 :             : 
     178                 :          62 :       DECL_ARTIFICIAL (node->decl) = 1;
     179                 :          62 :       node->force_output = true;
     180                 :             :     }
     181                 :          64 : }
     182                 :             : 
     183                 :             : /* Create string with attributes separated by TARGET_CLONES_ATTR_SEPARATOR.
     184                 :             :    Return number of attributes.  */
     185                 :             : 
     186                 :             : static int
     187                 :          68 : get_attr_str (tree arglist, char *attr_str)
     188                 :             : {
     189                 :          68 :   tree arg;
     190                 :          68 :   size_t str_len_sum = 0;
     191                 :          68 :   int argnum = 0;
     192                 :             : 
     193                 :         247 :   for (arg = arglist; arg; arg = TREE_CHAIN (arg))
     194                 :             :     {
     195                 :         179 :       const char *str = TREE_STRING_POINTER (TREE_VALUE (arg));
     196                 :         179 :       size_t len = strlen (str);
     197                 :         179 :       for (const char *p = strchr (str, TARGET_CLONES_ATTR_SEPARATOR);
     198                 :         193 :            p;
     199                 :          14 :            p = strchr (p + 1, TARGET_CLONES_ATTR_SEPARATOR))
     200                 :          14 :         argnum++;
     201                 :         179 :       memcpy (attr_str + str_len_sum, str, len);
     202                 :         358 :       attr_str[str_len_sum + len]
     203                 :         179 :         = TREE_CHAIN (arg) ? TARGET_CLONES_ATTR_SEPARATOR : '\0';
     204                 :         179 :       str_len_sum += len + 1;
     205                 :         179 :       argnum++;
     206                 :             :     }
     207                 :          68 :   return argnum;
     208                 :             : }
     209                 :             : 
     210                 :             : /* Return number of attributes separated by TARGET_CLONES_ATTR_SEPARATOR
     211                 :             :    and put them into ARGS.
     212                 :             :    If there is no DEFAULT attribute return -1.
     213                 :             :    If there is an empty string in attribute return -2.
     214                 :             :    If there are multiple DEFAULT attributes return -3.
     215                 :             :    */
     216                 :             : 
     217                 :             : static int
     218                 :          68 : separate_attrs (char *attr_str, char **attrs, int attrnum)
     219                 :             : {
     220                 :          68 :   int i = 0;
     221                 :          68 :   int default_count = 0;
     222                 :          68 :   static const char separator_str[] = { TARGET_CLONES_ATTR_SEPARATOR, 0 };
     223                 :             : 
     224                 :          68 :   for (char *attr = strtok (attr_str, separator_str);
     225                 :         260 :        attr != NULL; attr = strtok (NULL, separator_str))
     226                 :             :     {
     227                 :         192 :       if (strcmp (attr, "default") == 0)
     228                 :             :         {
     229                 :          68 :           default_count++;
     230                 :          68 :           continue;
     231                 :             :         }
     232                 :         124 :       attrs[i++] = attr;
     233                 :             :     }
     234                 :          68 :   if (default_count == 0)
     235                 :             :     return -1;
     236                 :          67 :   else if (default_count > 1)
     237                 :             :     return -3;
     238                 :          66 :   else if (i + default_count < attrnum)
     239                 :           1 :     return -2;
     240                 :             : 
     241                 :             :   return i;
     242                 :             : }
     243                 :             : 
     244                 :             : /*  Return true if symbol is valid in assembler name.  */
     245                 :             : 
     246                 :             : static bool
     247                 :         922 : is_valid_asm_symbol (char c)
     248                 :             : {
     249                 :         922 :   if ('a' <= c && c <= 'z')
     250                 :             :     return true;
     251                 :         219 :   if ('A' <= c && c <= 'Z')
     252                 :             :     return true;
     253                 :         219 :   if ('0' <= c && c <= '9')
     254                 :             :     return true;
     255                 :          71 :   if (c == '_')
     256                 :           0 :     return true;
     257                 :             :   return false;
     258                 :             : }
     259                 :             : 
     260                 :             : /*  Replace all not valid assembler symbols with '_'.  */
     261                 :             : 
     262                 :             : static void
     263                 :         117 : create_new_asm_name (char *old_asm_name, char *new_asm_name)
     264                 :             : {
     265                 :         117 :   int i;
     266                 :         117 :   int old_name_len = strlen (old_asm_name);
     267                 :             : 
     268                 :             :   /* Replace all not valid assembler symbols with '_'.  */
     269                 :        1039 :   for (i = 0; i < old_name_len; i++)
     270                 :         922 :     if (!is_valid_asm_symbol (old_asm_name[i]))
     271                 :          71 :       new_asm_name[i] = '_';
     272                 :             :     else
     273                 :         851 :       new_asm_name[i] = old_asm_name[i];
     274                 :         117 :   new_asm_name[old_name_len] = '\0';
     275                 :         117 : }
     276                 :             : 
     277                 :             : /*  Creates target clone of NODE.  */
     278                 :             : 
     279                 :             : static cgraph_node *
     280                 :         117 : create_target_clone (cgraph_node *node, bool definition, char *name,
     281                 :             :                      tree attributes)
     282                 :             : {
     283                 :         117 :   cgraph_node *new_node;
     284                 :             : 
     285                 :         117 :   if (definition)
     286                 :             :     {
     287                 :          98 :       new_node
     288                 :          98 :         = node->create_version_clone_with_body (vNULL, NULL, NULL, NULL, NULL,
     289                 :             :                                                 name, attributes, false);
     290                 :          98 :       if (new_node == NULL)
     291                 :             :         return NULL;
     292                 :          97 :       new_node->force_output = true;
     293                 :             :     }
     294                 :             :   else
     295                 :             :     {
     296                 :          19 :       tree new_decl = copy_node (node->decl);
     297                 :          19 :       new_node = cgraph_node::get_create (new_decl);
     298                 :          19 :       DECL_ATTRIBUTES (new_decl) = attributes;
     299                 :             :       /* Generate a new name for the new version.  */
     300                 :          19 :       tree fname = clone_function_name (node->decl, name);
     301                 :          19 :       symtab->change_decl_assembler_name (new_node->decl, fname);
     302                 :             :     }
     303                 :             :   return new_node;
     304                 :             : }
     305                 :             : 
     306                 :             : /* If the function in NODE has multiple target attributes
     307                 :             :    create the appropriate clone for each valid target attribute.  */
     308                 :             : 
     309                 :             : static bool
     310                 :     3462880 : expand_target_clones (struct cgraph_node *node, bool definition)
     311                 :             : {
     312                 :     3462880 :   int i;
     313                 :             :   /* Parsing target attributes separated by TARGET_CLONES_ATTR_SEPARATOR.  */
     314                 :     3462880 :   tree attr_target = lookup_attribute ("target_clones",
     315                 :     3462880 :                                        DECL_ATTRIBUTES (node->decl));
     316                 :             :   /* No targets specified.  */
     317                 :     3462880 :   if (!attr_target)
     318                 :             :     return false;
     319                 :             : 
     320                 :          74 :   tree arglist = TREE_VALUE (attr_target);
     321                 :          74 :   int attr_len = get_target_clone_attr_len (arglist);
     322                 :             : 
     323                 :             :   /* No need to clone for 1 target attribute.  */
     324                 :          74 :   if (attr_len == -1)
     325                 :             :     {
     326                 :           0 :       warning_at (DECL_SOURCE_LOCATION (node->decl),
     327                 :             :                   0, "single %<target_clones%> attribute is ignored");
     328                 :           0 :       return false;
     329                 :             :     }
     330                 :             : 
     331                 :          74 :   if (node->definition
     332                 :          74 :       && (node->alias || !tree_versionable_function_p (node->decl)))
     333                 :             :     {
     334                 :           6 :       auto_diagnostic_group d;
     335                 :           6 :       error_at (DECL_SOURCE_LOCATION (node->decl),
     336                 :             :                 "clones for %<target_clones%> attribute cannot be created");
     337                 :           6 :       const char *reason = NULL;
     338                 :           6 :       if (lookup_attribute ("noclone", DECL_ATTRIBUTES (node->decl)))
     339                 :             :         reason = G_("function %q+F can never be copied "
     340                 :             :                     "because it has %<noclone%> attribute");
     341                 :           3 :       else if (node->alias)
     342                 :             :         reason
     343                 :             :           = "%<target_clones%> cannot be combined with %<alias%> attribute";
     344                 :             :       else
     345                 :           2 :         reason = copy_forbidden (DECL_STRUCT_FUNCTION (node->decl));
     346                 :           2 :       if (reason)
     347                 :           6 :         inform (DECL_SOURCE_LOCATION (node->decl), reason, node->decl);
     348                 :           6 :       return false;
     349                 :           6 :     }
     350                 :             : 
     351                 :          68 :   char *attr_str = XNEWVEC (char, attr_len);
     352                 :          68 :   int attrnum = get_attr_str (arglist, attr_str);
     353                 :          68 :   char **attrs = XNEWVEC (char *, attrnum);
     354                 :             : 
     355                 :          68 :   attrnum = separate_attrs (attr_str, attrs, attrnum);
     356                 :          68 :   switch (attrnum)
     357                 :             :     {
     358                 :           1 :     case -1:
     359                 :           1 :       error_at (DECL_SOURCE_LOCATION (node->decl),
     360                 :             :                 "%<default%> target was not set");
     361                 :           1 :       break;
     362                 :           1 :     case -2:
     363                 :           1 :       error_at (DECL_SOURCE_LOCATION (node->decl),
     364                 :             :                 "an empty string cannot be in %<target_clones%> attribute");
     365                 :           1 :       break;
     366                 :           1 :     case -3:
     367                 :           1 :       error_at (DECL_SOURCE_LOCATION (node->decl),
     368                 :             :                 "multiple %<default%> targets were set");
     369                 :           1 :       break;
     370                 :             :     default:
     371                 :             :       break;
     372                 :             :     }
     373                 :             : 
     374                 :          68 :   if (attrnum < 0)
     375                 :             :     {
     376                 :           3 :       XDELETEVEC (attrs);
     377                 :           3 :       XDELETEVEC (attr_str);
     378                 :           3 :       return false;
     379                 :             :     }
     380                 :             : 
     381                 :          65 :   const char *new_attr_name = (TARGET_HAS_FMV_TARGET_ATTRIBUTE
     382                 :             :                                ? "target" : "target_version");
     383                 :          65 :   cgraph_function_version_info *decl1_v = NULL;
     384                 :          65 :   cgraph_function_version_info *decl2_v = NULL;
     385                 :          65 :   cgraph_function_version_info *before = NULL;
     386                 :          65 :   cgraph_function_version_info *after = NULL;
     387                 :          65 :   decl1_v = node->function_version ();
     388                 :          65 :   if (decl1_v == NULL)
     389                 :          65 :     decl1_v = node->insert_new_function_version ();
     390                 :          65 :   before = decl1_v;
     391                 :          65 :   DECL_FUNCTION_VERSIONED (node->decl) = 1;
     392                 :             : 
     393                 :         181 :   for (i = 0; i < attrnum; i++)
     394                 :             :     {
     395                 :         117 :       char *attr = attrs[i];
     396                 :             : 
     397                 :             :       /* Create new target clone.  */
     398                 :         117 :       tree attributes = make_attribute (new_attr_name, attr,
     399                 :         117 :                                         DECL_ATTRIBUTES (node->decl));
     400                 :             : 
     401                 :         117 :       char *suffix = XNEWVEC (char, strlen (attr) + 1);
     402                 :         117 :       create_new_asm_name (attr, suffix);
     403                 :         117 :       cgraph_node *new_node = create_target_clone (node, definition, suffix,
     404                 :             :                                                    attributes);
     405                 :         117 :       XDELETEVEC (suffix);
     406                 :         117 :       if (new_node == NULL)
     407                 :             :         {
     408                 :           1 :           XDELETEVEC (attrs);
     409                 :           1 :           XDELETEVEC (attr_str);
     410                 :           1 :           return false;
     411                 :             :         }
     412                 :         116 :       new_node->local = false;
     413                 :             : 
     414                 :         116 :       decl2_v = new_node->function_version ();
     415                 :         116 :       if (decl2_v != NULL)
     416                 :           0 :         continue;
     417                 :         116 :       decl2_v = new_node->insert_new_function_version ();
     418                 :             : 
     419                 :             :       /* Chain decl2_v and decl1_v.  All semantically identical versions
     420                 :             :          will be chained together.  */
     421                 :         116 :       after = decl2_v;
     422                 :         283 :       while (before->next != NULL)
     423                 :             :         before = before->next;
     424                 :         116 :       while (after->prev != NULL)
     425                 :             :         after = after->prev;
     426                 :             : 
     427                 :         116 :       before->next = after;
     428                 :         116 :       after->prev = before;
     429                 :         116 :       DECL_FUNCTION_VERSIONED (new_node->decl) = 1;
     430                 :             :     }
     431                 :             : 
     432                 :          64 :   XDELETEVEC (attrs);
     433                 :          64 :   XDELETEVEC (attr_str);
     434                 :             : 
     435                 :             :   /* Setting new attribute to initial function.  */
     436                 :          64 :   tree attributes = make_attribute (new_attr_name, "default",
     437                 :          64 :                                     DECL_ATTRIBUTES (node->decl));
     438                 :          64 :   DECL_ATTRIBUTES (node->decl) = attributes;
     439                 :          64 :   node->local = false;
     440                 :          64 :   return true;
     441                 :             : }
     442                 :             : 
     443                 :             : /* When NODE is a target clone, consider all callees and redirect
     444                 :             :    to a clone with equal target attributes.  That prevents multiple
     445                 :             :    multi-versioning dispatches and a call-chain can be optimized.  */
     446                 :             : 
     447                 :             : static void
     448                 :     3463240 : redirect_to_specific_clone (cgraph_node *node)
     449                 :             : {
     450                 :     3463240 :   cgraph_function_version_info *fv = node->function_version ();
     451                 :     3463240 :   if (fv == NULL)
     452                 :             :     return;
     453                 :             : 
     454                 :         869 :   tree attr_target = lookup_attribute ("target", DECL_ATTRIBUTES (node->decl));
     455                 :         869 :   if (attr_target == NULL_TREE)
     456                 :             :     return;
     457                 :             : 
     458                 :             :   /* We need to remember NEXT_CALLER as it could be modified in the loop.  */
     459                 :         771 :   for (cgraph_edge *e = node->callees; e ; e = e->next_callee)
     460                 :             :     {
     461                 :          60 :       cgraph_function_version_info *fv2 = e->callee->function_version ();
     462                 :          60 :       if (!fv2)
     463                 :          48 :         continue;
     464                 :             : 
     465                 :          12 :       tree attr_target2 = lookup_attribute ("target",
     466                 :          12 :                                             DECL_ATTRIBUTES (e->callee->decl));
     467                 :             : 
     468                 :             :       /* Function is not calling proper target clone.  */
     469                 :          12 :       if (attr_target2 == NULL_TREE
     470                 :          12 :           || !attribute_value_equal (attr_target, attr_target2))
     471                 :             :         {
     472                 :          12 :           while (fv2->prev != NULL)
     473                 :             :             fv2 = fv2->prev;
     474                 :             : 
     475                 :             :           /* Try to find a clone with equal target attribute.  */
     476                 :          30 :           for (; fv2 != NULL; fv2 = fv2->next)
     477                 :             :             {
     478                 :          30 :               cgraph_node *callee = fv2->this_node;
     479                 :          30 :               attr_target2 = lookup_attribute ("target",
     480                 :          30 :                                                DECL_ATTRIBUTES (callee->decl));
     481                 :          30 :               if (attr_target2 != NULL_TREE
     482                 :          30 :                   && attribute_value_equal (attr_target, attr_target2))
     483                 :             :                 {
     484                 :          12 :                   e->redirect_callee (callee);
     485                 :          12 :                   cgraph_edge::redirect_call_stmt_to_callee (e);
     486                 :          12 :                   break;
     487                 :             :                 }
     488                 :             :             }
     489                 :             :         }
     490                 :             :     }
     491                 :             : }
     492                 :             : 
     493                 :             : static unsigned int
     494                 :      224501 : ipa_target_clone (void)
     495                 :             : {
     496                 :      224501 :   struct cgraph_node *node;
     497                 :      224501 :   auto_vec<cgraph_node *> to_dispatch;
     498                 :             : 
     499                 :     7374762 :   FOR_EACH_FUNCTION (node)
     500                 :     3462880 :     if (expand_target_clones (node, node->definition))
     501                 :          64 :       to_dispatch.safe_push (node);
     502                 :             : 
     503                 :      224565 :   for (unsigned i = 0; i < to_dispatch.length (); i++)
     504                 :          64 :     create_dispatcher_calls (to_dispatch[i]);
     505                 :             : 
     506                 :     7375482 :   FOR_EACH_FUNCTION (node)
     507                 :     3463240 :     redirect_to_specific_clone (node);
     508                 :             : 
     509                 :      224501 :   return 0;
     510                 :      224501 : }
     511                 :             : 
     512                 :             : namespace {
     513                 :             : 
     514                 :             : const pass_data pass_data_target_clone =
     515                 :             : {
     516                 :             :   SIMPLE_IPA_PASS,              /* type */
     517                 :             :   "targetclone",              /* name */
     518                 :             :   OPTGROUP_NONE,                /* optinfo_flags */
     519                 :             :   TV_NONE,                      /* tv_id */
     520                 :             :   ( PROP_ssa | PROP_cfg ),      /* properties_required */
     521                 :             :   0,                            /* properties_provided */
     522                 :             :   0,                            /* properties_destroyed */
     523                 :             :   0,                            /* todo_flags_start */
     524                 :             :   TODO_update_ssa               /* todo_flags_finish */
     525                 :             : };
     526                 :             : 
     527                 :             : class pass_target_clone : public simple_ipa_opt_pass
     528                 :             : {
     529                 :             : public:
     530                 :      280114 :   pass_target_clone (gcc::context *ctxt)
     531                 :      560228 :     : simple_ipa_opt_pass (pass_data_target_clone, ctxt)
     532                 :             :   {}
     533                 :             : 
     534                 :             :   /* opt_pass methods: */
     535                 :             :   bool gate (function *) final override;
     536                 :      224501 :   unsigned int execute (function *) final override
     537                 :             :   {
     538                 :      224501 :     return ipa_target_clone ();
     539                 :             :   }
     540                 :             : };
     541                 :             : 
     542                 :             : bool
     543                 :      224613 : pass_target_clone::gate (function *)
     544                 :             : {
     545                 :             :   /* If there were any errors avoid pass property verification errors.  */
     546                 :      224613 :   return !seen_error ();
     547                 :             : }
     548                 :             : 
     549                 :             : } // anon namespace
     550                 :             : 
     551                 :             : simple_ipa_opt_pass *
     552                 :      280114 : make_pass_target_clone (gcc::context *ctxt)
     553                 :             : {
     554                 :      280114 :   return new pass_target_clone (ctxt);
     555                 :             : }
        

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.