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

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.