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; + } + 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), }; 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; + } + + 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); } /* Implement TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P. Use an opt-out 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..0e2e746f20e --- /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("sme", "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\._Msme:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Msme2:\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..6929b153c47 --- /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("sme", "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\._Msme:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Msme2:\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..b25b6214f4c --- /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("sme", "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\._Msme:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Msme2:\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\._Msme\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n\tadrp\tx\[0-9\]+, _Z3foov\._Msme2\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..c122c9fe3ab --- /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("sme", "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\._Msme:\n" 1 } } */ +/* { dg-final { scan-assembler-times "\n_Z3foov\._Msme2:\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-error1.C b/gcc/testsuite/g++.target/aarch64/mv-error1.C new file mode 100644 index 00000000000..2a659c02dfc --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-error1.C @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ +/* { dg-additional-options "-Wno-experimental-fmv-target" } */ + +__attribute__ ((target_version ("default"))) int +foo (); + +__attribute__ ((target_version ("default"))) int +foo () { return 1; } /* { dg-message "old declaration" } */ + +__attribute__ ((target_version ("dotprod"))) float +foo () { return 3; } /* { dg-error "ambiguating new declaration of" } */ diff --git a/gcc/testsuite/g++.target/aarch64/mv-error13.C b/gcc/testsuite/g++.target/aarch64/mv-error13.C new file mode 100644 index 00000000000..0b6b38ce100 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-error13.C @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ +/* { dg-additional-options "-Wno-experimental-fmv-target" } */ + +__attribute__ ((target_version ("dotprod"))) int +foo (); + +int +bar () +{ + return foo (); /* { dg-error "no default version in scope" } */ +} diff --git a/gcc/testsuite/g++.target/aarch64/mv-error2.C b/gcc/testsuite/g++.target/aarch64/mv-error2.C new file mode 100644 index 00000000000..167af4ad380 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-error2.C @@ -0,0 +1,10 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ +/* { dg-additional-options "-Wno-experimental-fmv-target" } */ + +__attribute__ ((target_version ("dotprod"))) float +foo () { return 3; } /* { dg-message "previously defined here" } */ + +__attribute__ ((target_version ("dotprod"))) float +foo () { return 3; } /* { dg-error "redefinition of" } */ diff --git a/gcc/testsuite/g++.target/aarch64/mv-error3.C b/gcc/testsuite/g++.target/aarch64/mv-error3.C new file mode 100644 index 00000000000..cc641488263 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-error3.C @@ -0,0 +1,13 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ +/* { dg-additional-options "-Wno-experimental-fmv-target" } */ + +__attribute__ ((target_version ("dotprod"))) float +foo () { return 3; } + +__attribute__ ((target_version ("default"))) float +foo () { return 3; } /* { dg-message "previously defined here" } */ + +__attribute__ ((target_version ("default"))) float +foo () { return 3; } /* { dg-error "redefinition of" } */ diff --git a/gcc/testsuite/g++.target/aarch64/mv-error7.C b/gcc/testsuite/g++.target/aarch64/mv-error7.C new file mode 100644 index 00000000000..3d2c73446be --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-error7.C @@ -0,0 +1,9 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ +/* { dg-additional-options "-Wno-experimental-fmv-target" } */ + +__attribute__ ((target_version ("sve+sve2"))) int +foo(); + +int bar () { return foo (); } /* { dg-error "no default version in scope" } */ diff --git a/gcc/testsuite/g++.target/aarch64/mv-error8.C b/gcc/testsuite/g++.target/aarch64/mv-error8.C new file mode 100644 index 00000000000..8ea26750480 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-error8.C @@ -0,0 +1,21 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ +/* { dg-additional-options "-Wno-experimental-fmv-target" } */ + +__attribute__ ((target_version ("sve+sve2"))) int +foo () { + return 1; +} + +__attribute__ ((target_version ("sve"))) int +foo () { + return 1; +} + +int bar () { return foo (); } /* { dg-error "no matching function for call to" } */ + +__attribute__ ((target_version ("sve+sve2"))) int +foo2(); + +int bar2 () { return foo2 (); } /* { dg-error "no default version in scope" } */ diff --git a/gcc/testsuite/g++.target/aarch64/mv-error9.C b/gcc/testsuite/g++.target/aarch64/mv-error9.C new file mode 100644 index 00000000000..c1b58edca11 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/mv-error9.C @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-require-ifunc "" } */ +/* { dg-options "-O0" } */ +/* { dg-additional-options "-Wno-experimental-fmv-target" } */ + +__attribute__ ((target_version ("dotprod"))) int +foo (); + +__attribute__ ((target_version ("sve+sve2"))) int +foo (); + +int bar () { return foo (); } /* { dg-error "no matching function for call to" } */