Sorry, I think I missed the multiple_targets.cc changes in my
previous review.

Alfie Richards <alfie.richa...@arm.com> writes:
> diff --git a/gcc/multiple_target.cc b/gcc/multiple_target.cc
> index d25277c0a93..44340cbc6a4 100644
> --- a/gcc/multiple_target.cc
> +++ b/gcc/multiple_target.cc
> @@ -313,7 +216,6 @@ create_target_clone (cgraph_node *node, bool definition, 
> char *name,
>  static bool
>  expand_target_clones (struct cgraph_node *node, bool definition)
>  {
> -  int i;
>    /* Parsing target attributes separated by TARGET_CLONES_ATTR_SEPARATOR.  */
>    tree attr_target = lookup_attribute ("target_clones",
>                                      DECL_ATTRIBUTES (node->decl));
> @@ -321,11 +223,12 @@ expand_target_clones (struct cgraph_node *node, bool 
> definition)
>    if (!attr_target)
>      return false;
>  
> -  tree arglist = TREE_VALUE (attr_target);
> -  int attr_len = get_target_clone_attr_len (arglist);
> +  int num_defaults = 0;
> +  auto_vec<string_slice> attr_list = get_clone_versions (node->decl,
> +                                                      &num_defaults);
>  
>    /* No need to clone for 1 target attribute.  */
> -  if (attr_len == -1)
> +  if (attr_list.length () == 1)
>      {
>        warning_at (DECL_SOURCE_LOCATION (node->decl),
>                 0, "single %<target_clones%> attribute is ignored");
> @@ -352,95 +255,114 @@ expand_target_clones (struct cgraph_node *node, bool 
> definition)
>        return false;
>      }
>  
> -  char *attr_str = XNEWVEC (char, attr_len);
> -  int attrnum = get_attr_str (arglist, attr_str);
> -  char **attrs = XNEWVEC (char *, attrnum);
> -
> -  attrnum = separate_attrs (attr_str, attrs, attrnum);
> -  switch (attrnum)
> +  /* Disallow multiple defaults.  */
> +  if (num_defaults > 1)
>      {
> -    case -1:
> -      error_at (DECL_SOURCE_LOCATION (node->decl),
> -             "%<default%> target was not set");
> -      break;
> -    case -2:
> -      error_at (DECL_SOURCE_LOCATION (node->decl),
> -             "an empty string cannot be in %<target_clones%> attribute");
> -      break;
> -    case -3:
>        error_at (DECL_SOURCE_LOCATION (node->decl),
>               "multiple %<default%> targets were set");
> -      break;
> -    default:
> -      break;
> +      return false;
>      }
> -
> -  if (attrnum < 0)
> +  /* Disallow target clones with no defaults.  */
> +  if (num_defaults == 0)
>      {
> -      XDELETEVEC (attrs);
> -      XDELETEVEC (attr_str);
> +      error_at (DECL_SOURCE_LOCATION (node->decl),
> +             "%<default%> target was not set");
>        return false;
>      }
>  
> -  const char *new_attr_name = (TARGET_HAS_FMV_TARGET_ATTRIBUTE
> -                            ? "target" : "target_version");
> -  cgraph_function_version_info *decl1_v = NULL;
> -  cgraph_function_version_info *decl2_v = NULL;
> -  cgraph_function_version_info *before = NULL;
> -  cgraph_function_version_info *after = NULL;
> -  decl1_v = node->function_version ();
> -  if (decl1_v == NULL)
> -    decl1_v = node->insert_new_function_version ();
> -  before = decl1_v;
> -  DECL_FUNCTION_VERSIONED (node->decl) = 1;
> -
> -  for (i = 0; i < attrnum; i++)
> +  /* Disallow any empty values in the clone attr.  */
> +  for (string_slice attr : attr_list)
> +    if (attr.empty () || !attr.is_valid ())
> +      {
> +     error_at (DECL_SOURCE_LOCATION (node->decl),
> +               "an empty string cannot be in %<target_clones%> attribute");
> +     return false;
> +      }
> +
> +  string_slice new_attr_name = TARGET_HAS_FMV_TARGET_ATTRIBUTE
> +                            ? "target"
> +                            : "target_version";
> +
> +  cgraph_function_version_info *node_v = node->function_version ();
> +
> +  if (!node_v)
> +    node_v = node->insert_new_function_version ();
> +
> +  /* If this target_clones contains a default, then convert this node to the
> +     default.  If this node does not contain default (this is only possible
> +     in target_version semantics) then remove the node.  This is safe at the
> +     point as only target_clones declarations containing default version is

s/the point/this point/
s/default versions is/a default version are/

> +     resolvable so this decl will have no calls/refrences.  */

Typo: references

> +
> +  tree attrs =  remove_attribute ("target_clones",
> +                               DECL_ATTRIBUTES (node->decl));
> +  tree assembler_name = node_v->assembler_name;
> +
> +  /* Change the current node into the default node.  */
> +  if (num_defaults == 1)
>      {
> -      char *attr = attrs[i];
> +      /* Setting new attribute to initial function.  */
> +      tree attributes = make_attribute (new_attr_name, "default", attrs);
> +      DECL_ATTRIBUTES (node->decl) = attributes;
> +      DECL_FUNCTION_VERSIONED (node->decl) = true;
> +
> +      node->is_target_clone = true;
> +      node->local = false;
> +
> +      /* Remangle base node after new target version string set.  */
> +      tree id = targetm.mangle_decl_assembler_name (node->decl, 
> assembler_name);
> +      symtab->change_decl_assembler_name (node->decl, id);
> +    }
> +  else
> +    {
> +      /* Target clones without a default are only allowed for target_version
> +      semantics where we can have target_clones/target_version mixing.  */
> +      gcc_assert (!TARGET_HAS_FMV_TARGET_ATTRIBUTE);
> +
> +      /* If there isn't a default version, can safely remove this version.
> +      The node itself gets removed after the other versions are created.  */
> +      cgraph_function_version_info *temp = node_v;
> +      node_v = node_v->next ? node_v->next : node_v->prev;
> +      cgraph_node::delete_function_version (temp);
> +    }

In terms of staging, would it be worth putting the else block in patch 8
instead, along with the corresponding !node_v and num_defaults == 0
handling?  As it stands, this code can't be reached.

I don't mind keeping it as-is if you prefer though.  I just found it a
little hard to follow in this context.

> +
> +  for (string_slice attr : attr_list)
> +    {
> +      /* Skip default nodes.  */
> +      if (attr == "default")
> +     continue;
>  
>        /* Create new target clone.  */
>        tree attributes = make_attribute (new_attr_name, attr,
>                                       DECL_ATTRIBUTES (node->decl));
>  
> -      char *suffix = XNEWVEC (char, strlen (attr) + 1);
> -      create_new_asm_name (attr, suffix);
> -      cgraph_node *new_node = create_target_clone (node, definition, suffix,
> -                                                attributes);
> -      XDELETEVEC (suffix);
> +      cgraph_node *new_node
> +     = create_target_clone (node, definition, NULL, attributes);
>        if (new_node == NULL)
> -     {
> -       XDELETEVEC (attrs);
> -       XDELETEVEC (attr_str);
> -       return false;
> -     }
> +     return false;
>        new_node->local = false;
>  
> -      decl2_v = new_node->function_version ();
> -      if (decl2_v != NULL)
> -        continue;
> -      decl2_v = new_node->insert_new_function_version ();
> -
> -      /* Chain decl2_v and decl1_v.  All semantically identical versions
> -      will be chained together.  */
> -      after = decl2_v;
> -      while (before->next != NULL)
> -     before = before->next;
> -      while (after->prev != NULL)
> -     after = after->prev;
> -
> -      before->next = after;
> -      after->prev = before;
> -      DECL_FUNCTION_VERSIONED (new_node->decl) = 1;
> +      DECL_FUNCTION_VERSIONED (new_node->decl) = true;
> +      if (!node_v)
> +     node_v = new_node->insert_new_function_version ();
> +      else
> +     cgraph_node::add_function_version (node_v, new_node->decl);
> +
> +      /* Use the base nodes assembler name for all created nodes.  */

node's

Thanks,
Richard

> +      new_node->function_version ()->assembler_name = assembler_name;
> +      new_node->is_target_clone = true;
> +
> +      /* Mangle all new nodes.  */
> +      tree id = targetm.mangle_decl_assembler_name
> +     (new_node->decl, new_node->function_version ()->assembler_name);
> +      symtab->change_decl_assembler_name (new_node->decl, id);
>      }
>  
> -  XDELETEVEC (attrs);
> -  XDELETEVEC (attr_str);
> +  /* If there are no default versions in the target_clones, this node is not
> +     reused, so can delete this node.  */
> +  if (num_defaults == 0)
> +    node->remove ();
>  
> -  /* Setting new attribute to initial function.  */
> -  tree attributes = make_attribute (new_attr_name, "default",
> -                                 DECL_ATTRIBUTES (node->decl));
> -  DECL_ATTRIBUTES (node->decl) = attributes;
> -  node->local = false;
>    return true;
>  }

Reply via email to