he 10/09/2025 16:27, Wilco Dijkstra wrote:
> Hi Alfie,
Hi Wilco,

Thanks for the review!
(email slightly hacked apart for brevity)

> > diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> > index 3f341f33f0a..6cfd269c07b 100644
> > --- a/gcc/config/aarch64/aarch64.cc
> > +++ b/gcc/config/aarch64/aarch64.cc
> > @@ -20403,21 +20403,27 @@ static aarch64_fmv_feature_datum 
> > aarch64_fmv_feature_data[] = {
> >   static enum aarch_parse_opt_result
> >   aarch64_parse_fmv_features (string_slice str, aarch64_feature_flags 
> > *isa_flags,
> >                         aarch64_fmv_feature_mask *feature_mask,
> > +                       unsigned int *priority,
> >                         std::string *invalid_extension)
> >   {
> >     if (feature_mask)
> >       *feature_mask = 0ULL;
> > +  if (priority)
> > +    *priority = 0;
> > +
> > +  str = str.strip ();      if (str == "default")
> >       return AARCH_PARSE_OK;
> > -  gcc_assert (str.is_valid ());
> > -
> > -  while (str.is_valid ())
> > +  /* Parse the architecture part of the string.  */
> > +  string_slice arch_string = string_slice::tokenize (&str, ";");
> > +  gcc_assert (arch_string.is_valid ());
> 
> Redundant assert - it's always valid even if empty, and we're testing it
> immediately below...

Yup agreed.

> 
> > +  while (arch_string.is_valid ())
> >       {
> >         string_slice ext;
> > -      ext = string_slice::tokenize (&str, "+");
> > +      ext = string_slice::tokenize (&arch_string, "+");
> >         gcc_assert (ext.is_valid ());
> > @@ -20458,6 +20464,60 @@ aarch64_parse_fmv_features (string_slice str, 
> > aarch64_feature_flags *isa_flags,
> >     }
> >       }
> > +  /* Parse any extra arguments.  */
> > +  while (str.is_valid ())
> > +    {
> > +      string_slice argument = string_slice::tokenize (&str, ";");
> > +      string_slice arg = argument;
> > +      char n[4];
> > +      argument = argument.strip ();
> 
> Wouldn't it make sense to strip spaces before arg = argument?
Yup thanks, my bad.
> 
> > +      string_slice name = string_slice::tokenize (&argument, "=").strip ();
> > +      unsigned int priority_res = 0;
> > +
> > +      /* priority=N argument (only one is allowed).  */
> > +      if (name == "priority" && priority_res == 0)
> > +   {
> > +     if (!argument.is_valid ())
> > +       {
> > +         *invalid_extension = std::string (arg.begin (), arg.size ());
> > +         return AARCH_PARSE_INVALID_FEATURE;
> > +       }
> > +     argument = argument.strip ();
> > +     if (!argument.is_valid ())
> > +       {
> > +         *invalid_extension = std::string (arg.begin (), arg.size ());
> > +         return AARCH_PARSE_INVALID_FEATURE;
> > +       }
> 
> This is dead code, it if was valid, it remains valid after stripping spaces.

Ugh, yes this is supposed to be empty(), will fix.

> 
> > +     if (argument.size () > 3)
> 
> Since the slice can be empty, we should also check argument.size () > 0.
> 
> > +       {
> > +         *invalid_extension = std::string (arg.begin (), arg.size ());
> > +         return AARCH_PARSE_INVALID_FEATURE;
> > +       }
> > +     memcpy (n, argument.begin (),
> > +             std::min (argument.size (), (unsigned int) 3));
> 
> What's the idea behind the ::min? We already know size() <= 3...
> 
> > +
> > +     int res = sscanf (n, "%ud", &priority_res);
> 
> This will return random results and can even read beyond the size of the
> array. You need to terminate the string. Also "%ud" will math "+1" which you
> probably don't want to match.

Do you know what function I can be use instead just to parse an unsigned int?

> 
> > +     if (res != 1)
> > +       {
> > +         *invalid_extension = std::string (arg.begin (), arg.size ());
> > +         return AARCH_PARSE_INVALID_FEATURE;
> > +       }
> > +     if (priority_res < 1 || priority_res > 255)
> > +       {
> > +         *invalid_extension = std::string (arg.begin (), arg.size ());
> > +         return AARCH_PARSE_INVALID_FEATURE;
> > +       }
> 
> I'd merge this if into the previous if and check all 3 conditions in one go.

Will do, thanks!

> 
> > +     if (priority)
> > +       *priority = priority_res;
> > +   }
> > +      else
> > +   {
> > +     /* Unrecognised argument.  */
> > +     *invalid_extension = std::string (arg.begin (), arg.size ());
> > +     return AARCH_PARSE_INVALID_FEATURE;
> > +   }
> > +    }
> > +
> >     return AARCH_PARSE_OK;
> >   }

> > -aarch64_same_function_versions (string_slice str1, string_slice str2)
> > +aarch64_same_function_versions (string_slice old_str, string_slice new_str)
> >   {
> >     enum aarch_parse_opt_result parse_res;
> >     aarch64_fmv_feature_mask feature_mask1;
> >     aarch64_fmv_feature_mask feature_mask2;
> > -  parse_res = aarch64_parse_fmv_features (str1, NULL,
> > -                                     &feature_mask1, NULL);
> > +  unsigned int priority1;
> > +  unsigned int priority2;
> > +  parse_res = aarch64_parse_fmv_features (old_str, NULL,
> > +                                     &feature_mask1, &priority1, NULL);
> >     gcc_assert (parse_res == AARCH_PARSE_OK);
> > -  parse_res = aarch64_parse_fmv_features (str2, NULL,
> > -                                     &feature_mask2, NULL);
> > +  parse_res = aarch64_parse_fmv_features (new_str, NULL,
> > +                                     &feature_mask2, &priority2, NULL);
> >     gcc_assert (parse_res == AARCH_PARSE_OK);
> > -  return feature_mask1 == feature_mask2;
> > +  if (feature_mask1 != feature_mask2)
> > +    return false;
> > +
> > +  if (priority1 != priority2 && priority1 != 0)
> > +    error ("inconsistent priority values");
> 
> Is it correct that this is asymmetric like that?

Yup.

We allow

int bar [[gnu::target_version("dotprod;priority=2")]] (int);
int bar [[gnu::target_version("dotprod")]] (int) { return 1; }

But not

int bar [[gnu::target_version("dotprod")]] (int);
int bar [[gnu::target_version("dotprod;priority=2")]] (int) { return 1; }

As the first example can merge the priority downwards simply. But in the other 
case
working out the priority at different points is confusing and unsound.

> 
> > +
> > +  return true;
> >   }
> >   /* Implement TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P.  Use an opt-out
> > @@ -30276,6 +30348,20 @@ aarch64_merge_decl_attributes (tree olddecl, tree 
> > newdecl)
> >     aarch64_check_arm_new_against_type (TREE_VALUE (new_new), newdecl);
> >       }
> > +  /* For target_version and target_clones, make sure we take the old 
> > version
> > +     as priority syntax cannot be added addetively.  */
> > +  tree old_target_version = lookup_attribute ("target_version", old_attrs);
> > +  tree new_target_version = lookup_attribute ("target_version", new_attrs);
> > +
> > +  if (old_target_version && new_target_version)
> > +    TREE_VALUE (new_target_version) = TREE_VALUE (old_target_version);
> > +
> > +  tree old_target_clones = lookup_attribute ("target_clones", old_attrs);
> > +  tree new_target_clones = lookup_attribute ("target_clones", new_attrs);
> > +
> > +  if (old_target_clones && new_target_clones)
> > +    TREE_VALUE (new_target_clones) = TREE_VALUE (old_target_clones);
> > +
> 

-- 
Alfie Richards

Reply via email to