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.
---
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 b5287f0da06..a4e657d9ffd 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 0eed6a9d46d..fb89a7b5919 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -3093,6 +3093,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 } } */
--
2.34.1