This changes behavior of target_clones and target_version attributes
to be inline with what is specified in the Arm C Language Extension.

Notably this changes the scope and signature of multiversioned functions
to that of the default version, and changes the resolver to be
created at the implementation of the default version.

This is achieved by changing the C++ front end to no longer resolve any
non-default version decls in lookup, and by moving dipatching
for default_target sets to reuse the dispatching logic for target_clones
in multiple_target.cc.

This also fixes https://gcc.gnu.org/bugzilla/show_bug.cgi?id=118313
for aarch64 and riscv.

This changes the behavior of both the aarch64, and riscv targets.

gcc/ChangeLog:

        * cgraphunit.cc (analyze_functions): Add dependency from default node
        to non-default versions.
        * ipa.cc (symbol_table::remove_unreachable_nodes): Ditto.
        * multiple_target.cc (ipa_target_clone): Change logic to conditionally
        dispatch target_clones and to dispatch some target_version sets.

gcc/cp/ChangeLog:

        * call.cc (add_candidates): For target_version semantics don't resolve
        non-default versions.
        * class.cc (resolve_address_of_overloaded_function): Ditto.
        * cp-gimplify.cc (cp_genericize_r): For target_version semantics don't
        redirect calls to versioned functions (done later at
        multiple_target.cc.)
        * decl.cc (start_decl): Mangle and mark all non-default function
        decls.
        (start_preparsed_function): Ditto.
        * typeck.cc (cp_build_function_call_vec): Add error if target has no
        default implementation.

gcc/testsuite/ChangeLog:

        * g++.target/aarch64/mv-1.C: Change for new semantics.
        * g++.target/aarch64/mv-symbols2.C: Ditto.
        * g++.target/aarch64/mv-symbols3.C: Ditto.
        * g++.target/aarch64/mv-symbols4.C: Ditto.
        * g++.target/aarch64/mv-symbols5.C: Ditto.
        * g++.target/aarch64/mvc-symbols3.C: Ditto.
        * g++.target/riscv/mv-symbols2.C: Ditto.
        * g++.target/riscv/mv-symbols3.C: Ditto.
        * g++.target/riscv/mv-symbols4.C: Ditto.
        * g++.target/riscv/mv-symbols5.C: Ditto.
        * g++.target/riscv/mvc-symbols3.C: Ditto.
        * g++.target/aarch64/mv-symbols10.C: New test.
        * g++.target/aarch64/mv-symbols11.C: New test.
        * g++.target/aarch64/mv-symbols12.C: New test.
        * g++.target/aarch64/mv-symbols14.C: New test.
        * g++.target/aarch64/mv-symbols15.C: New test.
        * g++.target/aarch64/mv-symbols6.C: New test.
        * g++.target/aarch64/mv-symbols8.C: New test.
        * g++.target/aarch64/mv-symbols9.C: New test.
---
 gcc/cgraphunit.cc                             |  9 ++++
 gcc/cp/call.cc                                |  8 ++++
 gcc/cp/class.cc                               | 11 ++++-
 gcc/cp/cp-gimplify.cc                         |  6 ++-
 gcc/cp/decl.cc                                | 24 ++++++++++
 gcc/cp/typeck.cc                              |  8 ++++
 gcc/ipa.cc                                    | 11 +++++
 gcc/multiple_target.cc                        | 13 ++++-
 gcc/testsuite/g++.target/aarch64/mv-1.C       |  4 ++
 .../g++.target/aarch64/mv-symbols10.C         | 43 +++++++++++++++++
 .../g++.target/aarch64/mv-symbols11.C         | 27 +++++++++++
 .../g++.target/aarch64/mv-symbols12.C         | 18 +++++++
 .../g++.target/aarch64/mv-symbols14.C         | 16 +++++++
 .../g++.target/aarch64/mv-symbols15.C         | 16 +++++++
 .../g++.target/aarch64/mv-symbols2.C          | 12 ++---
 .../g++.target/aarch64/mv-symbols3.C          |  6 +--
 .../g++.target/aarch64/mv-symbols4.C          |  6 +--
 .../g++.target/aarch64/mv-symbols5.C          |  6 +--
 .../g++.target/aarch64/mv-symbols6.C          | 23 +++++++++
 .../g++.target/aarch64/mv-symbols8.C          | 48 +++++++++++++++++++
 .../g++.target/aarch64/mv-symbols9.C          | 46 ++++++++++++++++++
 .../g++.target/aarch64/mvc-symbols3.C         | 12 ++---
 gcc/testsuite/g++.target/riscv/mv-symbols2.C  | 12 ++---
 gcc/testsuite/g++.target/riscv/mv-symbols3.C  |  6 +--
 gcc/testsuite/g++.target/riscv/mv-symbols4.C  |  6 +--
 gcc/testsuite/g++.target/riscv/mv-symbols5.C  |  6 +--
 gcc/testsuite/g++.target/riscv/mvc-symbols3.C | 12 ++---
 27 files changed, 368 insertions(+), 47 deletions(-)
 create mode 100644 gcc/testsuite/g++.target/aarch64/mv-symbols10.C
 create mode 100644 gcc/testsuite/g++.target/aarch64/mv-symbols11.C
 create mode 100644 gcc/testsuite/g++.target/aarch64/mv-symbols12.C
 create mode 100644 gcc/testsuite/g++.target/aarch64/mv-symbols14.C
 create mode 100644 gcc/testsuite/g++.target/aarch64/mv-symbols15.C
 create mode 100644 gcc/testsuite/g++.target/aarch64/mv-symbols6.C
 create mode 100644 gcc/testsuite/g++.target/aarch64/mv-symbols8.C
 create mode 100644 gcc/testsuite/g++.target/aarch64/mv-symbols9.C

diff --git a/gcc/cgraphunit.cc b/gcc/cgraphunit.cc
index 82f205488e9..f7f8957e618 100644
--- a/gcc/cgraphunit.cc
+++ b/gcc/cgraphunit.cc
@@ -1264,6 +1264,15 @@ analyze_functions (bool first_time)
 	      if (!cnode->analyzed)
 		cnode->analyze ();
 
+	      /* A reference to a default node in a funciton set implies a
+		 refrence to all versions in the set.  */
+	      if (cnode->function_version ()
+		  && is_function_default_version (node->decl))
+		for (cgraph_function_version_info *fvi
+		     = cnode->function_version ()->next;
+		     fvi; fvi = fvi->next)
+		  enqueue_node (fvi->this_node);
+
 	      for (edge = cnode->callees; edge; edge = edge->next_callee)
 		if (edge->callee->definition
 		    && (!DECL_EXTERNAL (edge->callee->decl)
diff --git a/gcc/cp/call.cc b/gcc/cp/call.cc
index 3a56a82632d..ae39c9b09a4 100644
--- a/gcc/cp/call.cc
+++ b/gcc/cp/call.cc
@@ -6785,6 +6785,14 @@ add_candidates (tree fns, tree first_arg, const vec<tree, va_gc> *args,
 	    continue;
 	}
 
+      /* Do not resolve any non-default function.  Only the default version
+	 is resolvable (for the target_version attribute semantics.)  */
+      if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE && !is_function_default_version (fn))
+	{
+	  add_ignored_candidate (candidates, fn);
+	  continue;
+	}
+
       if (TREE_CODE (fn) == TEMPLATE_DECL)
 	add_template_candidate (candidates,
 				fn,
diff --git a/gcc/cp/class.cc b/gcc/cp/class.cc
index a9a80d1b4be..a926dc00945 100644
--- a/gcc/cp/class.cc
+++ b/gcc/cp/class.cc
@@ -8789,6 +8789,11 @@ resolve_address_of_overloaded_function (tree target_type,
 	if (!constraints_satisfied_p (fn))
 	  continue;
 
+	/* Never resolve a non-default version.  */
+	if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE
+	    && !is_function_default_version (fn))
+	  continue;
+
 	if (undeduced_auto_decl (fn))
 	  {
 	    /* Force instantiation to do return type deduction.  */
@@ -9014,8 +9019,10 @@ resolve_address_of_overloaded_function (tree target_type,
   /* If a pointer to a function that is multi-versioned is requested, the
      pointer to the dispatcher function is returned instead.  This works
      well because indirectly calling the function will dispatch the right
-     function version at run-time.  */
-  if (DECL_FUNCTION_VERSIONED (fn))
+     function version at run-time.
+     This is done at multiple_target.cc for target_version semantics.  */
+
+  if (DECL_FUNCTION_VERSIONED (fn) && TARGET_HAS_FMV_TARGET_ATTRIBUTE)
     {
       fn = get_function_version_dispatcher (fn);
       if (fn == NULL)
diff --git a/gcc/cp/cp-gimplify.cc b/gcc/cp/cp-gimplify.cc
index 4ec3de13008..3ef5bec5d54 100644
--- a/gcc/cp/cp-gimplify.cc
+++ b/gcc/cp/cp-gimplify.cc
@@ -2130,10 +2130,12 @@ cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data)
 	 returns the function with the highest target priority, that is,
 	 the version that will checked for dispatching first.  If this
 	 version is inlinable, a direct call to this version can be made
-	 otherwise the call should go through the dispatcher.  */
+	 otherwise the call should go through the dispatcher.
+	 This is done at multiple_target.cc for target_version semantics.  */
       {
 	tree fn = cp_get_callee_fndecl_nofold (stmt);
-	if (fn && DECL_FUNCTION_VERSIONED (fn)
+	if (fn && TARGET_HAS_FMV_TARGET_ATTRIBUTE
+	    && DECL_FUNCTION_VERSIONED (fn)
 	    && (current_function_decl == NULL
 		|| !targetm.target_option.can_inline_p (current_function_decl,
 							fn)))
diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index 9e1a2e0a9bd..552b1845352 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -6174,6 +6174,12 @@ start_decl (const cp_declarator *declarator,
 
   was_public = TREE_PUBLIC (decl);
 
+  /* Mark any non-default function as versioned as it needs to be mangled
+     even when on its own in a TU.  */
+  if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE && TREE_CODE (decl) == FUNCTION_DECL
+      && !is_function_default_version (decl))
+    maybe_mark_function_versioned (decl);
+
   /* Set the assembler string for any versioned function.  */
   if (TREE_CODE (decl) == FUNCTION_DECL
       && (lookup_attribute (TARGET_HAS_FMV_TARGET_ATTRIBUTE ? "target"
@@ -6186,6 +6192,12 @@ start_decl (const cp_declarator *declarator,
 	node->insert_new_function_version ();
       if (!node->function_version ()->assembler_name)
 	node->function_version ()->assembler_name = DECL_ASSEMBLER_NAME (decl);
+
+      /* In target_version semantics mangle non-default versions even if no
+	 other versions are present.  */
+      if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE
+	  && !is_function_default_version (decl))
+	maybe_mark_function_versioned (decl);
     }
 
   if ((DECL_EXTERNAL (decl) || TREE_CODE (decl) == FUNCTION_DECL)
@@ -18776,6 +18788,12 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
   if (!DECL_OMP_DECLARE_REDUCTION_P (decl1))
     start_lambda_scope (decl1);
 
+  /* Mark any non-default function as versioned as it needs to be mangled
+     even when on its own in a TU.  */
+  if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE && TREE_CODE (decl1) == FUNCTION_DECL
+      && !is_function_default_version (decl1))
+    maybe_mark_function_versioned (decl1);
+
   /* Set the assembler string for any versioned function.  */
   if (TREE_CODE (decl1) == FUNCTION_DECL
       && (lookup_attribute (TARGET_HAS_FMV_TARGET_ATTRIBUTE ? "target"
@@ -18788,6 +18806,12 @@ start_preparsed_function (tree decl1, tree attrs, int flags)
 	node->insert_new_function_version ();
       if (!node->function_version ()->assembler_name)
 	node->function_version ()->assembler_name = DECL_ASSEMBLER_NAME (decl1);
+
+      /* In target_version semantics mangle non-default versions even if no
+	 other versions are present.  */
+      if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE
+	  && !is_function_default_version (decl1))
+	maybe_mark_function_versioned (decl1);
     }
 
   return true;
diff --git a/gcc/cp/typeck.cc b/gcc/cp/typeck.cc
index a9c32ff930d..ccb17df1feb 100644
--- a/gcc/cp/typeck.cc
+++ b/gcc/cp/typeck.cc
@@ -4439,6 +4439,14 @@ cp_build_function_call_vec (tree function, vec<tree, va_gc> **params,
 	return error_mark_node;
       fndecl = function;
 
+      if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE
+	   && !is_function_default_version (fndecl))
+	 {
+	   if (complain & tf_error)
+	    error ("no default version in scope");
+	   return error_mark_node;
+	 }
+
       /* Convert anything with function type to a pointer-to-function.  */
       if (DECL_MAIN_P (function))
 	{
diff --git a/gcc/ipa.cc b/gcc/ipa.cc
index 8a7b067a526..39ab0cc3de5 100644
--- a/gcc/ipa.cc
+++ b/gcc/ipa.cc
@@ -433,6 +433,17 @@ symbol_table::remove_unreachable_nodes (FILE *file)
 						       e, &first, &reachable);
 		    }
 		}
+
+	      /* A refrence to the default node implies use of all the other
+		 versions (they get used in the function resolver made later
+		 in multiple_target.cc)  */
+	      if (cnode->function_version ()
+		  && is_function_default_version (node->decl))
+		for (cgraph_function_version_info *fvi
+		     = cnode->function_version ()->next;
+		     fvi; fvi = fvi->next)
+		  enqueue_node (fvi->this_node, &first, &reachable);
+
 	      for (e = cnode->callees; e; e = e->next_callee)
 		{
 	          symtab_node *body = e->callee->function_symbol ();
diff --git a/gcc/multiple_target.cc b/gcc/multiple_target.cc
index 4f748a81f9b..07a894087f8 100644
--- a/gcc/multiple_target.cc
+++ b/gcc/multiple_target.cc
@@ -424,9 +424,20 @@ ipa_target_clone (void)
   auto_vec<cgraph_node *> to_dispatch;
 
   FOR_EACH_FUNCTION (node)
-    if (expand_target_clones (node, node->definition))
+    /* Expand all target versions.  */
+    if (expand_target_clones (node, node->definition)
+	&& TARGET_HAS_FMV_TARGET_ATTRIBUTE)
+      /* In non target_version semantics, dispatch all target clone sets.  */
       to_dispatch.safe_push (node);
 
+  /* In target_version semantics dispatch all FMV function sets with a default
+     implementation.  */
+  if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE)
+    FOR_EACH_FUNCTION (node)
+      if (is_function_default_version (node->decl)
+	  && DECL_FUNCTION_VERSIONED (node->decl) && TREE_STATIC (node->decl))
+	to_dispatch.safe_push (node);
+
   for (unsigned i = 0; i < to_dispatch.length (); i++)
     create_dispatcher_calls (to_dispatch[i]);
 
diff --git a/gcc/testsuite/g++.target/aarch64/mv-1.C b/gcc/testsuite/g++.target/aarch64/mv-1.C
index b10037f1b9b..93b8a136587 100644
--- a/gcc/testsuite/g++.target/aarch64/mv-1.C
+++ b/gcc/testsuite/g++.target/aarch64/mv-1.C
@@ -37,3 +37,7 @@ int bar()
 /* { dg-final { scan-assembler-times "\n_Z3foov\._Mrng:\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n_Z3foov\._MrngMflagm:\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n_Z3foov\._Mflagm:\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-symbols10.C b/gcc/testsuite/g++.target/aarch64/mv-symbols10.C
new file mode 100644
index 00000000000..dc5a8ff6572
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols10.C
@@ -0,0 +1,43 @@
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+/* { dg-additional-options "-Wno-experimental-fmv-target" } */
+
+int
+foo ();
+
+int
+foo ()
+{
+  return 1;
+}
+
+__attribute__ ((target_version ("dotprod"))) int
+foo ()
+{
+  return 3;
+}
+__attribute__ ((target_version ("sve+sve2"))) int
+foo ()
+{
+  return 5;
+}
+
+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\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tadrp\tx., _Z3foov\._MsveMsve2\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tadrp\tx., _Z3foov\._Mdotprod\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tadrp\tx., _Z3foov\.default\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-symbols11.C b/gcc/testsuite/g++.target/aarch64/mv-symbols11.C
new file mode 100644
index 00000000000..92d4ab617d8
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols11.C
@@ -0,0 +1,27 @@
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+/* { dg-additional-options "-Wno-experimental-fmv-target" } */
+
+__attribute__ ((target_version ("default"))) void
+foo (int a = 3);
+
+__attribute__ ((target_version ("sve"))) void
+foo (int a = 4);
+
+void bar() {
+  foo();
+}
+
+__attribute__ ((target_version ("sve"))) void
+foo2 (int a = 6);
+
+__attribute__ ((target_version ("default"))) void
+foo2 (int a = 5);
+
+void bar2() {
+  foo2();
+}
+
+
+/* { dg-final { scan-assembler-times "\n\tmov\tw\[0-9\]\+, 3\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tmov\tw\[0-9\]\+, 5\n" 1 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols12.C b/gcc/testsuite/g++.target/aarch64/mv-symbols12.C
new file mode 100644
index 00000000000..05d915f19ab
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols12.C
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+/* { dg-additional-options "-Wno-experimental-fmv-target" } */
+
+__attribute__ ((target_version ("default"))) int
+foo () { return 1; }
+
+__attribute__ ((target_version ("dotprod"))) int
+foo () { return 3; }
+
+int (*test)();
+
+int bar ()
+{
+  test = foo;
+
+  return test();
+}
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols14.C b/gcc/testsuite/g++.target/aarch64/mv-symbols14.C
new file mode 100644
index 00000000000..fbee7800ba2
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols14.C
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+/* { dg-additional-options "-Wno-experimental-fmv-target" } */
+
+int foo () {
+  return 1;
+}
+
+void
+bar ()
+{
+  foo ();
+}
+
+__attribute__ ((target_version ("dotprod"))) int
+foo ();
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols15.C b/gcc/testsuite/g++.target/aarch64/mv-symbols15.C
new file mode 100644
index 00000000000..a10c0bfb990
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols15.C
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+/* { dg-additional-options "-Wno-experimental-fmv-target" } */
+
+int foo () {
+  return 1;
+}
+
+void bar ()
+{
+  int (*test)() = foo;
+
+  test();
+}
+
+__attribute__ ((target_version ("dotprod"))) int foo ();
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols2.C b/gcc/testsuite/g++.target/aarch64/mv-symbols2.C
index 6da88ddfb48..55f2d48f5e4 100644
--- a/gcc/testsuite/g++.target/aarch64/mv-symbols2.C
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols2.C
@@ -41,13 +41,13 @@ int foo (int)
 /* { 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\.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 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\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_Z3fooi\.default:\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 1 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols3.C b/gcc/testsuite/g++.target/aarch64/mv-symbols3.C
index 5dd7b49be2a..6ba02a2aae9 100644
--- a/gcc/testsuite/g++.target/aarch64/mv-symbols3.C
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols3.C
@@ -29,10 +29,10 @@ int bar()
 /* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */
 /* { 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\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 0 } } */
 /* { 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\t\.type\t_Z3foov, %gnu_indirect_function\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 0 } } */
 
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 0 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols4.C b/gcc/testsuite/g++.target/aarch64/mv-symbols4.C
index 4b25d17cc15..cc013c47848 100644
--- a/gcc/testsuite/g++.target/aarch64/mv-symbols4.C
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols4.C
@@ -44,6 +44,6 @@ int bar()
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 1 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols5.C b/gcc/testsuite/g++.target/aarch64/mv-symbols5.C
index fac00b20313..1396ca379e4 100644
--- a/gcc/testsuite/g++.target/aarch64/mv-symbols5.C
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols5.C
@@ -44,10 +44,10 @@ int bar()
 /* { dg-final { scan-assembler-times "\n_Z3foov\.default:\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\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 0 } } */
 /* { 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\t\.type\t_Z3foov, %gnu_indirect_function\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 0 } } */
 
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 1 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols6.C b/gcc/testsuite/g++.target/aarch64/mv-symbols6.C
new file mode 100644
index 00000000000..bdfdcdbdaed
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols6.C
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+/* { dg-additional-options "-Wno-experimental-fmv-target" } */
+
+__attribute__ ((target_version ("default"))) int
+foo ()
+{
+  return 1;
+}
+
+int bar()
+{
+  return foo();
+}
+
+/* It is not overly clear what the correct behaviour is in this case.
+   This test serves more as a test of consistency for this case rather
+   than a test of correctness.  */
+
+/* { dg-final { scan-assembler-times "\n_Z3foov:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 0 } } */
+/* { dg-final { scan-assembler-times "bl\t_Z3foov\n" 1 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols8.C b/gcc/testsuite/g++.target/aarch64/mv-symbols8.C
new file mode 100644
index 00000000000..6c526227b31
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols8.C
@@ -0,0 +1,48 @@
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+/* { dg-additional-options "-Wno-experimental-fmv-target" } */
+
+__attribute__ ((target_version ("dotprod"))) int
+foo ();
+
+__attribute__ ((target_version ("sve+sve2"))) int
+foo ();
+
+__attribute__ ((target_version ("default"))) int
+foo ();
+
+__attribute__ ((target_version ("sve+sve2"))) int
+foo ()
+{
+  return 5;
+}
+__attribute__ ((target_version ("dotprod"))) int
+foo ()
+{
+  return 3;
+}
+__attribute__ ((target_version ("default"))) int
+foo ()
+{
+  return 1;
+}
+
+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\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tadrp\tx., _Z3foov\._MsveMsve2\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tadrp\tx., _Z3foov\._Mdotprod\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tadrp\tx., _Z3foov\.default\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-symbols9.C b/gcc/testsuite/g++.target/aarch64/mv-symbols9.C
new file mode 100644
index 00000000000..937a223fcb2
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols9.C
@@ -0,0 +1,46 @@
+/* { 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
+foo ()
+{
+  return 1;
+}
+
+__attribute__ ((target_version ("dotprod"))) int
+foo ()
+{
+  return 3;
+}
+__attribute__ ((target_version ("sve+sve2"))) int
+foo ()
+{
+  return 5;
+}
+
+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\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tadrp\tx., _Z3foov\._MsveMsve2\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tadrp\tx., _Z3foov\._Mdotprod\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tadrp\tx., _Z3foov\.default\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/mvc-symbols3.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols3.C
index 350a5586643..2a315d2db5c 100644
--- a/gcc/testsuite/g++.target/aarch64/mvc-symbols3.C
+++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols3.C
@@ -22,15 +22,15 @@ int bar(int x)
 /* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */
 /* { 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\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 0 } } */
 /* { 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\t\.type\t_Z3foov, %gnu_indirect_function\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 0 } } */
 
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\._Mdotprod:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\._MsveMsve2:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n\tbl\t_Z3fooi\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */
diff --git a/gcc/testsuite/g++.target/riscv/mv-symbols2.C b/gcc/testsuite/g++.target/riscv/mv-symbols2.C
index 43fa1502b7d..8a5c5a0bc9f 100644
--- a/gcc/testsuite/g++.target/riscv/mv-symbols2.C
+++ b/gcc/testsuite/g++.target/riscv/mv-symbols2.C
@@ -47,15 +47,15 @@ int foo (int)
 /* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n_Z3foov\.arch__v:\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n_Z3foov\.arch__zba__zbb:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n\tcall\t_Z3foov\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 } } */
+/* { 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_Z3fooi\.default:\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.arch__v:\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.arch__zba__zbb:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n\tcall\t_Z3fooi\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, @gnu_indirect_function\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, @gnu_indirect_function\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 1 } } */
diff --git a/gcc/testsuite/g++.target/riscv/mv-symbols3.C b/gcc/testsuite/g++.target/riscv/mv-symbols3.C
index 4dc81cf7395..fa2d3371e87 100644
--- a/gcc/testsuite/g++.target/riscv/mv-symbols3.C
+++ b/gcc/testsuite/g++.target/riscv/mv-symbols3.C
@@ -36,10 +36,10 @@ int bar()
 /* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3foov\.arch__v:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3foov\.arch__zba__zbb:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n\tcall\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\t\.type\t_Z3foov, @gnu_indirect_function\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 0 } } */
 
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.arch__v:\n" 0 } } */
diff --git a/gcc/testsuite/g++.target/riscv/mv-symbols4.C b/gcc/testsuite/g++.target/riscv/mv-symbols4.C
index b0ed16a5eda..fa84e25900c 100644
--- a/gcc/testsuite/g++.target/riscv/mv-symbols4.C
+++ b/gcc/testsuite/g++.target/riscv/mv-symbols4.C
@@ -50,7 +50,7 @@ int bar()
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.arch__v:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.arch__zba__zbb:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n\tcall\t_Z3fooi\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, @gnu_indirect_function\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, @gnu_indirect_function\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 1 } } */
diff --git a/gcc/testsuite/g++.target/riscv/mv-symbols5.C b/gcc/testsuite/g++.target/riscv/mv-symbols5.C
index f4c6b294e0f..5551f5da554 100644
--- a/gcc/testsuite/g++.target/riscv/mv-symbols5.C
+++ b/gcc/testsuite/g++.target/riscv/mv-symbols5.C
@@ -48,10 +48,10 @@ int bar()
 /* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3foov\.arch__v:\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n_Z3foov\.arch__zba__zbb:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n\tcall\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\t\.type\t_Z3foov, @gnu_indirect_function\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 0 } } */
 
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.arch__v:\n" 1 } } */
diff --git a/gcc/testsuite/g++.target/riscv/mvc-symbols3.C b/gcc/testsuite/g++.target/riscv/mvc-symbols3.C
index b36c3fa7a95..256fec7d368 100644
--- a/gcc/testsuite/g++.target/riscv/mvc-symbols3.C
+++ b/gcc/testsuite/g++.target/riscv/mvc-symbols3.C
@@ -28,15 +28,15 @@ int bar(int x)
 /* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3foov\.arch__v:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3foov\.arch__zba__zbb:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n\tcall\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\t\.type\t_Z3foov, @gnu_indirect_function\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3foov,_Z3foov\.resolver\n" 0 } } */
 
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.arch__v:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n_Z3fooi\.arch__zba__zbb:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 0 } } */
 /* { dg-final { scan-assembler-times "\n\tcall\t_Z3fooi\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, @gnu_indirect_function\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, @gnu_indirect_function\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\t\.set\t_Z3fooi,_Z3fooi\.resolver\n" 0 } } */

Reply via email to