Alfie Richards <alfie.richa...@arm.com> writes: > Add support for a FMV set defined by a combination of target_clones and > target_version definitions. > > Additionally, change is_function_default_version to consider a function > declaration annotated with target_clones containing default to be a > default version. > > Lastly, add support for the case that a target_clone has all versions filtered > out and therefore the declaration should be removed. This is relevant as now > the default could be defined in a target_version, so a target_clones no longer > necessarily contains the default. > > This takes advantage of refactoring done in previous patches changing how > target_clones are expanded and how conflicting decls are handled. > > gcc/ChangeLog: > > * attribs.cc (is_function_default_version): Update to handle > target_clones. > * cgraph.h (FOR_EACH_FUNCTION_REMOVABLE): New macro. > * multiple_target.cc (expand_target_clones): Update logic to delete > empty target_clones and modify diagnostic. > (ipa_target_clone): Update to use FOR_EACH_FUNCTION_REMOVABLE. > > gcc/c-family/ChangeLog: > > * c-attribs.cc: Add support for target_version and target_clone mixing. > > 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.
OK, thanks. Richard > --- > gcc/attribs.cc | 10 ++++- > gcc/c-family/c-attribs.cc | 9 +--- > gcc/cgraph.h | 7 ++++ > gcc/multiple_target.cc | 24 +++++++++-- > .../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 +++++++++++++++++ > 8 files changed, 183 insertions(+), 13 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 > > diff --git a/gcc/attribs.cc b/gcc/attribs.cc > index 06785eaa136..2ca82674f7c 100644 > --- a/gcc/attribs.cc > +++ b/gcc/attribs.cc > @@ -1242,7 +1242,8 @@ make_dispatcher_decl (const tree decl) > With the target attribute semantics, returns true if the function is > marked > as default with the target version. > With the target_version attribute semantics, returns true if the function > - is either not annotated, or annotated as default. */ > + is either not annotated, annotated as default, or is a target_clone > + containing the default declaration. */ > > bool > is_function_default_version (const tree decl) > @@ -1259,6 +1260,13 @@ is_function_default_version (const tree decl) > } > else > { > + if (lookup_attribute ("target_clones", DECL_ATTRIBUTES (decl))) > + { > + int num_defaults = 0; > + get_clone_versions (decl, &num_defaults); > + return num_defaults > 0; > + } > + > 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 92d046d92ce..b2875e76031 100644 > --- a/gcc/c-family/c-attribs.cc > +++ b/gcc/c-family/c-attribs.cc > @@ -249,13 +249,6 @@ 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), > }; > > @@ -543,7 +536,7 @@ const struct attribute_spec c_common_gnu_attributes[] = > attr_target_exclusions }, > { "target_version", 1, 1, true, false, false, false, > handle_target_version_attribute, > - attr_target_version_exclusions }, > + NULL }, > { "target_clones", 1, -1, true, false, false, false, > handle_target_clones_attribute, > attr_target_clones_exclusions }, > diff --git a/gcc/cgraph.h b/gcc/cgraph.h > index d686238368d..1c91a7ba7ca 100644 > --- a/gcc/cgraph.h > +++ b/gcc/cgraph.h > @@ -3119,6 +3119,13 @@ symbol_table::next_function_with_gimple_body > (cgraph_node *node) > for ((node) = symtab->first_function (); (node); \ > (node) = symtab->next_function ((node))) > > +/* Walk all functions but precompute so a node can be deleted if needed. */ > +#define FOR_EACH_FUNCTION_REMOVABLE(node) \ > + cgraph_node *next; \ > + for ((node) = symtab->first_function (), \ > + next = (node) ? symtab->next_function ((node)) : NULL; (node); \ > + (node) = next, next = (node) ? symtab->next_function ((node)) : NULL) > + > /* Return true when callgraph node is a function with Gimple body defined > in current unit. Functions can also be define externally or they > can be thunks with no Gimple representation. > diff --git a/gcc/multiple_target.cc b/gcc/multiple_target.cc > index bb430bc4fbf..7784478d8e2 100644 > --- a/gcc/multiple_target.cc > +++ b/gcc/multiple_target.cc > @@ -269,14 +269,28 @@ expand_target_clones (struct cgraph_node *node, bool > definition) > auto_vec<string_slice> attr_list = get_clone_versions (node->decl, > &num_defaults); > > + /* If the target clones list is empty after filtering, remove this node. > */ > + if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE && attr_list.is_empty ()) > + { > + node->remove (); > + return false; > + } > + > /* No need to clone for 1 target attribute. */ > - if (attr_list.length () == 1) > + if (attr_list.length () == 1 && TARGET_HAS_FMV_TARGET_ATTRIBUTE) > { > warning_at (DECL_SOURCE_LOCATION (node->decl), > 0, "single %<target_clones%> attribute is ignored"); > return false; > } > > + /* For target_version semantics, a target clone with just a default version > + is the same as an unannotated decl, so can ignore. */ > + if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE > + && attr_list.length () == 1 > + && num_defaults == 1) > + return false; > + > if (node->definition > && (node->alias || !tree_versionable_function_p (node->decl))) > { > @@ -304,8 +318,10 @@ expand_target_clones (struct cgraph_node *node, bool > definition) > "multiple %<default%> targets were set"); > return false; > } > - /* Disallow target clones with no defaults. */ > - if (num_defaults == 0) > + > + /* For target FMV semantics, where target and target_clone mixing > + is not supported, disallow target clones with no defaults. */ > + if (TARGET_HAS_FMV_TARGET_ATTRIBUTE && num_defaults == 0) > { > error_at (DECL_SOURCE_LOCATION (node->decl), > "%<default%> target was not set"); > @@ -516,7 +532,7 @@ ipa_target_clone (bool early) > The late stage is only used for the expansion and dispatching of the > simple > case where the FMV set is defined by a single target_clone attribute. > */ > > - FOR_EACH_FUNCTION (node) > + FOR_EACH_FUNCTION_REMOVABLE (node) > { > /* In the early stage, we need to expand any target clone that is not > the simple case. */ > diff --git a/gcc/testsuite/g++.target/aarch64/mv-and-mvc1.C > b/gcc/testsuite/g++.target/aarch64/mv-and-mvc1.C > new file mode 100644 > index 00000000000..24b81f5f5f3 > --- /dev/null > +++ b/gcc/testsuite/g++.target/aarch64/mv-and-mvc1.C > @@ -0,0 +1,38 @@ > +/* { dg-do compile } */ > +/* { dg-require-ifunc "" } */ > +/* { dg-options "-O0" } */ > +/* { dg-additional-options "-Wno-experimental-fmv-target" } */ > + > +__attribute__((target_version("default"))) > +int foo () > +{ > + return 0; > +} > + > +__attribute__((target_clones("dotprod", "sve+sve2"))) > +int foo () > +{ > + return 1; > +} > + > +__attribute__((target_clones("sve2+sme", "sve2+sme2"))) > +int foo () > +{ > + return 2; > +} > + > +int bar() > +{ > + return foo (); > +} > + > + > +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._Msve2Msme:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._Msve2Msme2:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, > %gnu_indirect_function\n" 1 } } */ > +/* { dg-final { scan-assembler-times > "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ > diff --git a/gcc/testsuite/g++.target/aarch64/mv-and-mvc2.C > b/gcc/testsuite/g++.target/aarch64/mv-and-mvc2.C > new file mode 100644 > index 00000000000..5939353d2d2 > --- /dev/null > +++ b/gcc/testsuite/g++.target/aarch64/mv-and-mvc2.C > @@ -0,0 +1,29 @@ > +/* { dg-do compile } */ > +/* { dg-require-ifunc "" } */ > +/* { dg-options "-O0" } */ > +/* { dg-additional-options "-Wno-experimental-fmv-target" } */ > + > +__attribute__((target_version("default"))) > +int foo (); > + > +__attribute__((target_clones("dotprod", "sve+sve2"))) > +int foo () > +{ > + return 1; > +} > + > +__attribute__((target_clones("sve2+sme", "sve2+sme2"))) > +int foo () > +{ > + return 2; > +} > + > +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov:\n" 0 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._Msve2Msme:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._Msve2Msme2:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 0 } } */ > +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, > %gnu_indirect_function\n" 0 } } */ > +/* { dg-final { scan-assembler-times > "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 0 } } */ > diff --git a/gcc/testsuite/g++.target/aarch64/mv-and-mvc3.C > b/gcc/testsuite/g++.target/aarch64/mv-and-mvc3.C > new file mode 100644 > index 00000000000..fb1c596e919 > --- /dev/null > +++ b/gcc/testsuite/g++.target/aarch64/mv-and-mvc3.C > @@ -0,0 +1,41 @@ > +/* { dg-do compile } */ > +/* { dg-require-ifunc "" } */ > +/* { dg-options "-O0" } */ > +/* { dg-additional-options "-Wno-experimental-fmv-target" } */ > + > +__attribute__((target_clones("dotprod", "sve+sve2"))) > +int foo (); > + > +__attribute__((target_version("default"))) > +int foo () > +{ > + return 0; > +} > + > +__attribute__((target_clones("sve2+sme", "sve2+sme2"))) > +int foo () > +{ > + return 2; > +} > + > +int bar() > +{ > + return foo (); > +} > + > + > +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 0 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 0 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._Msve2Msme:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._Msve2Msme2:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, > %gnu_indirect_function\n" 1 } } */ > +/* { dg-final { scan-assembler-times > "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */ > +// { dg-final { scan-assembler-times "\n\tadrp\tx\[0-9\]+, > _Z3foov\.default\n" 1 } } > +/* { dg-final { scan-assembler-times "\n\tadrp\tx\[0-9\]+, > _Z3foov\._Mdotprod\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n\tadrp\tx\[0-9\]+, > _Z3foov\._MsveMsve2\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n\tadrp\tx\[0-9\]+, > _Z3foov\._Msve2Msme\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n\tadrp\tx\[0-9\]+, > _Z3foov\._Msve2Msme2\n" 1 } } */ > + > diff --git a/gcc/testsuite/g++.target/aarch64/mv-and-mvc4.C > b/gcc/testsuite/g++.target/aarch64/mv-and-mvc4.C > new file mode 100644 > index 00000000000..e198fecc4cc > --- /dev/null > +++ b/gcc/testsuite/g++.target/aarch64/mv-and-mvc4.C > @@ -0,0 +1,38 @@ > +/* { dg-do compile } */ > +/* { dg-require-ifunc "" } */ > +/* { dg-options "-O0" } */ > +/* { dg-additional-options "-Wno-experimental-fmv-target" } */ > + > +__attribute__((target_version("dotprod"))) > +int foo () > +{ > + return 0; > +} > + > +__attribute__((target_clones("default", "sve+sve2"))) > +int foo () > +{ > + return 1; > +} > + > +__attribute__((target_clones("sve2+sme", "sve2+sme2"))) > +int foo () > +{ > + return 2; > +} > + > +int bar() > +{ > + return foo (); > +} > + > + > +/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._Mdotprod:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._MsveMsve2:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._Msve2Msme:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\._Msve2Msme2:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n\tbl\t_Z3foov\n" 1 } } */ > +/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3foov, > %gnu_indirect_function\n" 1 } } */ > +/* { dg-final { scan-assembler-times > "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 1 } } */