Alfie Richards <alfie.richa...@arm.com> writes:
> This patch adds support for the combination of target_clones and
> target_version in the definition of a versioned function.
>
> This patch changes is_function_default_version to consider a function
> declaration annotated with target_clones containing default to be a
> default version. It also changes the common_function_version hook to
> consider two functions annotated with target_clones and/or
> target_versions to be common if their specified versions don't overlap.
>
> This takes advantage of refactoring done in previous patches changing
> how target_clones are expanded.
>
> gcc/ChangeLog:
>
>       * attribs.cc (is_function_default_version): Add logic for
>       target_clones defining the default version.
>       * config/aarch64/aarch64.cc (aarch64_common_function_versions): Add
>       logic for a target_clones and target_version, or two target_clones
>       coexisting in a version set.
>
> gcc/c-family/ChangeLog:
>
>       * c-attribs.cc: Add support for target_version and target_clones
>       coexisting.
>
> gcc/testsuite/ChangeLog:
>
>       * g++.target/aarch64/mv-and-mvc1.C: New test.
>       * g++.target/aarch64/mv-and-mvc2.C: New test.
>       * g++.target/aarch64/mv-and-mvc3.C: New test.
>       * g++.target/aarch64/mv-and-mvc4.C: New test.
> ---
>  gcc/attribs.cc                                |  7 +++
>  gcc/c-family/c-attribs.cc                     |  2 -
>  gcc/config/aarch64/aarch64.cc                 | 46 ++++++++++++++++++-
>  .../g++.target/aarch64/mv-and-mvc1.C          | 38 +++++++++++++++
>  .../g++.target/aarch64/mv-and-mvc2.C          | 29 ++++++++++++
>  .../g++.target/aarch64/mv-and-mvc3.C          | 41 +++++++++++++++++
>  .../g++.target/aarch64/mv-and-mvc4.C          | 38 +++++++++++++++
>  gcc/testsuite/g++.target/aarch64/mv-error1.C  | 13 ++++++
>  gcc/testsuite/g++.target/aarch64/mv-error13.C | 13 ++++++
>  gcc/testsuite/g++.target/aarch64/mv-error2.C  | 10 ++++
>  gcc/testsuite/g++.target/aarch64/mv-error3.C  | 13 ++++++
>  gcc/testsuite/g++.target/aarch64/mv-error7.C  |  9 ++++
>  gcc/testsuite/g++.target/aarch64/mv-error8.C  | 21 +++++++++
>  gcc/testsuite/g++.target/aarch64/mv-error9.C  | 12 +++++
>  14 files changed, 289 insertions(+), 3 deletions(-)
>  create mode 100644 gcc/testsuite/g++.target/aarch64/mv-and-mvc1.C
>  create mode 100644 gcc/testsuite/g++.target/aarch64/mv-and-mvc2.C
>  create mode 100644 gcc/testsuite/g++.target/aarch64/mv-and-mvc3.C
>  create mode 100644 gcc/testsuite/g++.target/aarch64/mv-and-mvc4.C
>  create mode 100644 gcc/testsuite/g++.target/aarch64/mv-error1.C
>  create mode 100644 gcc/testsuite/g++.target/aarch64/mv-error13.C
>  create mode 100644 gcc/testsuite/g++.target/aarch64/mv-error2.C
>  create mode 100644 gcc/testsuite/g++.target/aarch64/mv-error3.C
>  create mode 100644 gcc/testsuite/g++.target/aarch64/mv-error7.C
>  create mode 100644 gcc/testsuite/g++.target/aarch64/mv-error8.C
>  create mode 100644 gcc/testsuite/g++.target/aarch64/mv-error9.C
>
> diff --git a/gcc/attribs.cc b/gcc/attribs.cc
> index 687e6d4143a..f877dc4f6e3 100644
> --- a/gcc/attribs.cc
> +++ b/gcc/attribs.cc
> @@ -1327,6 +1327,13 @@ is_function_default_version (const tree decl)
>      }
>    else
>      {
> +      if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (decl)))
> +     {
> +       int num_def = 0;
> +       auto_vec<string_slice> versions = get_clone_versions (decl, &num_def);
> +       return num_def > 0;
> +     }
> +

Might be worth expanding the name to num_default.  At first I read it
as "number of definitions".  The "auto_vec<string_slice> versions = "
looks redundant.

>        attr = lookup_attribute ("target_version", DECL_ATTRIBUTES (decl));
>        if (!attr)
>       return true;
> diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
> index 642d724f6c6..f2cc43ad641 100644
> --- a/gcc/c-family/c-attribs.cc
> +++ b/gcc/c-family/c-attribs.cc
> @@ -249,13 +249,11 @@ static const struct attribute_spec::exclusions 
> attr_target_clones_exclusions[] =
>    ATTR_EXCL ("always_inline", true, true, true),
>    ATTR_EXCL ("target", TARGET_HAS_FMV_TARGET_ATTRIBUTE,
>            TARGET_HAS_FMV_TARGET_ATTRIBUTE, TARGET_HAS_FMV_TARGET_ATTRIBUTE),
> -  ATTR_EXCL ("target_version", true, true, true),
>    ATTR_EXCL (NULL, false, false, false),
>  };
>  
>  static const struct attribute_spec::exclusions 
> attr_target_version_exclusions[] =
>  {
> -  ATTR_EXCL ("target_clones", true, true, true),
>    ATTR_EXCL (NULL, false, false, false),
>  };

We can remove the exclusions altogether if the list is empty.

>  
> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 420bbba9be2..f6cb7903d88 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -20671,7 +20671,51 @@ aarch64_common_function_versions (tree fn1, tree fn2)
>        || TREE_CODE (fn2) != FUNCTION_DECL)
>      return false;
>  
> -  return (aarch64_compare_version_priority (fn1, fn2) != 0);
> +  if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (fn2)))
> +    {
> +      tree temp = fn1;
> +      fn1 = fn2;
> +      fn2 = temp;
> +    }

This can use std::swap.

> +
> +  if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (fn1)))
> +    {
> +      auto_vec<string_slice> fn1_versions = get_clone_versions (fn1);
> +      // fn1 is target_clone
> +      if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (fn2)))
> +     {
> +       auto_vec<string_slice> fn2_versions = get_clone_versions (fn2);
> +       for (string_slice v1 : fn1_versions)
> +         {
> +           aarch64_fmv_feature_mask v1_mask;
> +           aarch64_parse_fmv_features (v1, NULL, &v1_mask, NULL);
> +           for (string_slice v2 : fn2_versions)
> +             {
> +               aarch64_fmv_feature_mask v2_mask;
> +               aarch64_parse_fmv_features (v2, NULL, &v2_mask, NULL);
> +               if (v1_mask == v2_mask)
> +                 return false;
> +             }
> +         }
> +       return true;
> +     }
> +      else
> +     {
> +       aarch64_fmv_feature_mask v2_mask = get_feature_mask_for_version (fn2);
> +       for (string_slice v1 : fn1_versions)
> +         {
> +           aarch64_fmv_feature_mask v1_mask;
> +           aarch64_parse_fmv_features (v1, NULL, &v1_mask, NULL);
> +           if (v1_mask == v2_mask)
> +             return false;
> +         }
> +       return true;
> +     }
> +    }
> +  // Can assume both are target_version
> +  else
> +    // Both are target_version
> +    return (aarch64_compare_version_priority (fn1, fn2) != 0);

Formatting nit: redundant brackets around the expression.  For files that
already use /* ... */ comments, I think we should stick to those.

>  }
>  
>  /* Implement TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P.  Use an opt-out
> [...]

It looks like all of the error tests are for duplicate target_versions.
It would be good to also test duplicates in and between target_clones
(if we don't do that elsewhere), and duplicates between target_versions
and target_clones.

Thanks,
Richard

Reply via email to