[5/5] Add target hook for function version name mangling

Message ID 065b00ae-970d-4a97-5ec9-5c16f425f343@e124511.cambridge.arm.com
State New
Headers
Series Fix fmv mangling for AArch64 |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Testing passed

Commit Message

Andrew Carlotti Jan. 15, 2024, 11:28 a.m. UTC
  When using "target" or "target_version" attributes, some parts of the
code assume that the default version has no function-specific mangling
while generating names for the resolver and ifunc.  Since aarch64 now
breaks that assumption, we add an explicit workaround for this issue.

Ideally we'd also use a target hook to generate the ifunc name, but it
turns out to be rather tricky to reproduce the existing x86 double
mangling quirk.

There should be no functional change, except on aarch64 where the
mangling is changed to match the latest proposed spec.

gcc/ChangeLog:

	* cgraph.h (create_version_clone_with_body): Update comment.
	* cgraphclones.cc: Set assembler name after attaching new
	  attributes, and use new target hook.
	* config/aarch64/aarch64.cc
	(make_resolver_func): Change ifunc and resolver assembler names.
	(aarch64_mangle_decl_assembler_name): Rename to ...
	(aarch64_mangle_function_version_name): ... this, and adjust
	mangling for default version.
	(TARGET_MANGLE_DECL_ASSEMBLER_NAME): Don't use this hook.
	(TARGET_MANGLE_FUNCTION_VERSION_NAME): Use this hook instead.
	* config/i386/i386-features.cc
	(is_valid_asm_symbol): Copy from multiple_target.cc.
	(ix86_mangle_function_version_assembler_name): Rename to ...
	(ix86_mangle_function_version_name): ... this, and add different
	handling for target clones.
	(ix86_mangle_decl_assembler_name): Remove target version mangling.
	* config/i386/i386-features.h
	(ix86_mangle_function_version_name): New declaration.
	* config/i386/i386.cc
	(TARGET_MANGLE_FUNCTION_VERSION_NAME): Implement this hook.
	* config/rs6000/rs6000.cc
	(TARGET_MANGLE_FUNCTION_VERSION_NAME): Implement this hook.
	(is_valid_asm_symbol): Copy from multiple_target.cc.
	(rs6000_mangle_function_version_name): New hook implementation.
	* doc/tm.texi: Regenerate.
	* doc/tm.texi.in: Add TARGET_MANGLE_FUNCTION_VERSION_NAME hook.
	* multiple_target.cc
	(create_dispatcher_calls): Use new target hook for mangling.
	(is_valid_asm_symbol): Move helper function to targets.
	(create_new_asm_name): Move and inline into target hooks.
	(create_target_clone): Use new target hook for mangling, and
	pass "target_version" instead of 'name' parameter for dump info.
	(expand_target_clones): Use new target hook for name mangling.
	* target.def (name): Define mangle_function_version_name hook.

gcc/cp/ChangeLog:

	* mangle.cc (get_mangled_id): Call the separate target hook for
	  target version magnling.

gcc/testsuite/ChangeLog:

	* g++.target/aarch64/mv-symbols1.C: Update for mangling fixes.
	* 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-symbols1.C: Ditto.
	* g++.target/aarch64/mvc-symbols2.C: Ditto.
	* g++.target/aarch64/mvc-symbols3.C: Ditto.
	* g++.target/aarch64/mvc-symbols4.C: Ditto.
  

Patch

diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 16e2b2d045767206d5ccf12ee226f92ee10511d9..4150c5ea7fce01f49971134a6f8e47cf4e1533b0 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -1015,8 +1015,8 @@  struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
      that will promote value of the attribute DECL_FUNCTION_SPECIFIC_TARGET
      of the declaration.
 
-     If TARGET_VERSION is set true, use clone_function_name to set new names.
-     Otherwise, use clone_function_name_numbered.
+     If TARGET_VERSION is set true, use targetm.mangle_function_version_name
+     to set new names.  Otherwise, use clone_function_name_numbered.
 
      Return the new version's cgraph node.  */
   cgraph_node *create_version_clone_with_body
diff --git a/gcc/cgraphclones.cc b/gcc/cgraphclones.cc
index ab9a0fe7ccc5fcf9a0a03363c66016466d39427e..ab8818e7057da3c0bc59f086abcdb5c577d1d935 100644
--- a/gcc/cgraphclones.cc
+++ b/gcc/cgraphclones.cc
@@ -1033,11 +1033,6 @@  cgraph_node::create_version_clone_with_body
   else
     new_decl = copy_node (old_decl);
 
-  /* Generate a new name for the new version. */
-  tree fnname = (target_version ? clone_function_name (old_decl, suffix)
-		: clone_function_name_numbered (old_decl, suffix));
-  DECL_NAME (new_decl) = fnname;
-  SET_DECL_ASSEMBLER_NAME (new_decl, fnname);
   SET_DECL_RTL (new_decl, NULL);
 
   DECL_VIRTUAL_P (new_decl) = 0;
@@ -1065,6 +1060,18 @@  cgraph_node::create_version_clone_with_body
 	return NULL;
     }
 
+  /* Generate a new name for the new version.  */
+  tree fnname;
+  if (target_version)
+    {
+      fnname = DECL_ASSEMBLER_NAME (old_decl);
+      fnname = targetm.mangle_function_version_name (new_decl, fnname);
+    }
+  else
+    fnname = (clone_function_name_numbered (old_decl, suffix));
+  DECL_NAME (new_decl) = fnname;
+  SET_DECL_ASSEMBLER_NAME (new_decl, fnname);
+
   /* When the old decl was a con-/destructor make sure the clone isn't.  */
   DECL_STATIC_CONSTRUCTOR (new_decl) = 0;
   DECL_STATIC_DESTRUCTOR (new_decl) = 0;
diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 7d1f8c65ce41044d6850262300cf08a23d606617..c3abf13351adac06f6612162f404c5fa1b65a167 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -19845,8 +19845,24 @@  make_resolver_func (const tree default_decl,
 {
   tree decl, type, t;
 
-  /* Create resolver function name based on default_decl.  */
-  tree decl_name = clone_function_name (default_decl, "resolver");
+  /* Fix ifunc alias name, and create resolver function name, based on
+     default_decl.  */
+  std::string name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (default_decl));
+
+  if (DECL_FUNCTION_VERSIONED (default_decl) == FUNCTION_VERSION_TARGET_VERSION)
+    {
+      /* ".default" suffix was already added, so remove it.  */
+      gcc_assert (name.size () >= 8);
+      name.resize (name.size () - 8);
+    }
+
+  symtab->change_decl_assembler_name (ifunc_alias_decl,
+				      get_identifier (name.c_str()));
+
+  name += ".resolver";
+
+  tree decl_name = get_identifier (name.c_str());
+
   const char *resolver_name = IDENTIFIER_POINTER (decl_name);
 
   /* The resolver function should have signature
@@ -20305,40 +20321,40 @@  aarch64_common_function_versions (tree fn1, tree fn2)
   return (aarch64_compare_version_priority (fn1, fn2) != 0);
 }
 
-/* Implement TARGET_MANGLE_DECL_ASSEMBLER_NAME, to add function multiversioning
-   suffixes.  */
+/* Implement TARGET_MANGLE_FUNCTION_VERSION_NAME.  */
 
 tree
-aarch64_mangle_decl_assembler_name (tree decl, tree id)
+aarch64_mangle_function_version_name (tree decl, tree id)
 {
-  /* For function version, add the target suffix to the assembler name.  */
-  if (TREE_CODE (decl) == FUNCTION_DECL
-      && DECL_FUNCTION_VERSIONED (decl))
-    {
-      aarch64_fmv_feature_mask feature_mask = get_feature_mask_for_version (decl);
+  gcc_assert (TREE_CODE (decl) == FUNCTION_DECL
+	      && DECL_FUNCTION_VERSIONED (decl));
+
+  aarch64_fmv_feature_mask feature_mask = get_feature_mask_for_version (decl);
 
-      /* No suffix for the default version.  */
-      if (feature_mask == 0ULL)
-	return id;
+  std::string name = IDENTIFIER_POINTER (id);
 
-      std::string name = IDENTIFIER_POINTER (id);
-      name += "._";
+  /* Handle default version separately.  */
+  if (feature_mask == 0ULL)
+    {
+      name += ".default";
+      return get_identifier (name.c_str());
+    }
 
-      for (int i = 0; i < FEAT_MAX; i++)
+  name += "._";
+
+  for (int i = 0; i < FEAT_MAX; i++)
+    {
+      if (feature_mask & aarch64_fmv_feature_data[i].feature_mask)
 	{
-	  if (feature_mask & aarch64_fmv_feature_data[i].feature_mask)
-	    {
-	      name += "M";
-	      name += aarch64_fmv_feature_data[i].name;
-	    }
+	  name += "M";
+	  name += aarch64_fmv_feature_data[i].name;
 	}
+    }
 
-      if (DECL_ASSEMBLER_NAME_SET_P (decl))
-	SET_DECL_RTL (decl, NULL);
+  if (DECL_ASSEMBLER_NAME_SET_P (decl))
+    SET_DECL_RTL (decl, NULL);
 
-      id = get_identifier (name.c_str());
-    }
-  return id;
+  return get_identifier (name.c_str());
 }
 
 /* Implement TARGET_FUNCTION_ATTRIBUTE_INLINABLE_P.  Use an opt-out
@@ -30929,8 +30945,9 @@  aarch64_libgcc_floating_mode_supported_p
 #define TARGET_GET_FUNCTION_VERSIONS_DISPATCHER \
   aarch64_get_function_versions_dispatcher
 
-#undef TARGET_MANGLE_DECL_ASSEMBLER_NAME
-#define TARGET_MANGLE_DECL_ASSEMBLER_NAME aarch64_mangle_decl_assembler_name
+#undef TARGET_MANGLE_FUNCTION_VERSION_NAME
+#define TARGET_MANGLE_FUNCTION_VERSION_NAME \
+  aarch64_mangle_function_version_name
 
 struct gcc_target targetm = TARGET_INITIALIZER;
 
diff --git a/gcc/config/i386/i386-features.h b/gcc/config/i386/i386-features.h
index 8bab2d8666deb685d78b02e4e5610afbae33c3ab..094fd94df57a4a407d115c221ddc32ff9f19c9ea 100644
--- a/gcc/config/i386/i386-features.h
+++ b/gcc/config/i386/i386-features.h
@@ -211,6 +211,7 @@  bool ix86_save_reg (unsigned int regno, bool maybe_eh_return,
 int ix86_compare_version_priority (tree decl1, tree decl2);
 tree ix86_generate_version_dispatcher_body (void *node_p);
 tree ix86_get_function_versions_dispatcher (void *decl);
+tree ix86_mangle_function_version_name (tree decl, tree id);
 tree ix86_mangle_decl_assembler_name (tree decl, tree id);
 
 
diff --git a/gcc/config/i386/i386-features.cc b/gcc/config/i386/i386-features.cc
index 4020b271328af9cce477d861bc916bcae7476dc7..ddded1f3b72ed9094ecfdcef52e5e4020acb5ad5 100644
--- a/gcc/config/i386/i386-features.cc
+++ b/gcc/config/i386/i386-features.cc
@@ -3484,17 +3484,35 @@  dispatch_function_versions (tree dispatch_decl,
   return 0;
 }
 
+/*  Return true if symbol is valid in assembler name.  */
+
+static bool
+is_valid_asm_symbol (char c)
+{
+  if ('a' <= c && c <= 'z')
+    return true;
+  if ('A' <= c && c <= 'Z')
+    return true;
+  if ('0' <= c && c <= '9')
+    return true;
+  if (c == '_')
+    return true;
+  return false;
+}
+
 /* This function changes the assembler name for functions that are
    versions.  If DECL is a function version and has a "target"
    attribute, it appends the attribute string to its assembler name.  */
 
-static tree
-ix86_mangle_function_version_assembler_name (tree decl, tree id)
+tree
+ix86_mangle_function_version_name (tree decl, tree id)
 {
   tree version_attr;
   const char *orig_name, *version_string;
-  char *attr_str, *assembler_name;
 
+  /* TODO: The name mangling hook seems like an odd place to put these checks -
+     are they really needed here?  After refactoring, these checks are also
+     being run in the target_clones case.  */
   if (DECL_DECLARED_INLINE_P (decl)
       && lookup_attribute ("gnu_inline",
 			   DECL_ATTRIBUTES (decl)))
@@ -3515,31 +3533,48 @@  ix86_mangle_function_version_assembler_name (tree decl, tree id)
   version_string
     = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (version_attr)));
 
-  if (strcmp (version_string, "default") == 0)
-    return id;
+  char *suffix;
 
-  attr_str = sorted_attr_string (TREE_VALUE (version_attr));
-  assembler_name = XNEWVEC (char, strlen (orig_name) + strlen (attr_str) + 2);
+  if (DECL_FUNCTION_VERSIONED (decl) == FUNCTION_VERSION_TARGET)
+    {
+      if (strcmp (version_string, "default") == 0)
+	return id;
 
-  sprintf (assembler_name, "%s.%s", orig_name, attr_str);
+      suffix = sorted_attr_string (TREE_VALUE (version_attr));
+      /* Allow assembler name to be modified if already set.  */
+      if (DECL_ASSEMBLER_NAME_SET_P (decl))
+	SET_DECL_RTL (decl, NULL);
+
+    }
+  else if (DECL_FUNCTION_VERSIONED (decl) == FUNCTION_VERSION_TARGET_CLONES)
+    {
+      int version_len = strlen (version_string);
+      suffix = XNEWVEC (char, version_len + 1);
+
+      /* Replace all not valid assembler symbols with '_'.  */
+      for (int i = 0; i < version_len; i++)
+	if (!is_valid_asm_symbol (version_string[i]))
+	  suffix[i] = '_';
+	else
+	  suffix[i] = version_string[i];
+      suffix[version_len] = '\0';
+    }
+  else
+    gcc_unreachable();
 
-  /* Allow assembler name to be modified if already set.  */
-  if (DECL_ASSEMBLER_NAME_SET_P (decl))
-    SET_DECL_RTL (decl, NULL);
+  char *assembler_name = XNEWVEC (char,
+				  strlen (orig_name) + strlen (suffix) + 2);
+  sprintf (assembler_name, "%s.%s", orig_name, suffix);
 
   tree ret = get_identifier (assembler_name);
-  XDELETEVEC (attr_str);
+  XDELETEVEC (suffix);
   XDELETEVEC (assembler_name);
   return ret;
 }
 
 tree 
-ix86_mangle_decl_assembler_name (tree decl, tree id)
+ix86_mangle_decl_assembler_name (tree decl ATTRIBUTE_UNUSED, tree id)
 {
-  /* For function version, add the target suffix to the assembler name.  */
-  if (TREE_CODE (decl) == FUNCTION_DECL
-      && DECL_FUNCTION_VERSIONED (decl))
-    id = ix86_mangle_function_version_assembler_name (decl, id);
 #ifdef SUBTARGET_MANGLE_DECL_ASSEMBLER_NAME
   id = SUBTARGET_MANGLE_DECL_ASSEMBLER_NAME (decl, id);
 #endif
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index 80105322fa522e926385a64d53cc1eb7641baca2..515d740ef282d83e84a030c87183bb165854c9ac 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -26137,6 +26137,9 @@  static const scoped_attribute_specs *const ix86_attribute_table[] =
 #undef TARGET_MANGLE_DECL_ASSEMBLER_NAME
 #define TARGET_MANGLE_DECL_ASSEMBLER_NAME ix86_mangle_decl_assembler_name
 
+#undef TARGET_MANGLE_FUNCTION_VERSION_NAME
+#define TARGET_MANGLE_FUNCTION_VERSION_NAME ix86_mangle_function_version_name
+
 #undef TARGET_ASM_UNALIGNED_HI_OP
 #define TARGET_ASM_UNALIGNED_HI_OP TARGET_ASM_ALIGNED_HI_OP
 #undef TARGET_ASM_UNALIGNED_SI_OP
diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index 5d975dab9216b55ce5b6a2d6aff1ae3f2bf0a1e0..2e70e21fe7cb6b374b5a43c510548af4eb199c8b 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -1728,6 +1728,9 @@  static const scoped_attribute_specs *const rs6000_attribute_table[] =
 #undef TARGET_OPTION_FUNCTION_VERSIONS
 #define TARGET_OPTION_FUNCTION_VERSIONS common_function_versions
 
+#undef TARGET_MANGLE_FUNCTION_VERSION_NAME
+#define TARGET_MANGLE_FUNCTION_VERSION_NAME rs6000_mangle_function_version_name
+
 #undef TARGET_HARD_REGNO_NREGS
 #define TARGET_HARD_REGNO_NREGS rs6000_hard_regno_nregs_hook
 #undef TARGET_HARD_REGNO_MODE_OK
@@ -25695,6 +25698,68 @@  rs6000_generate_version_dispatcher_body (void *node_p)
   return resolver;
 }
 
+/*  Return true if symbol is valid in assembler name.  */
+
+static bool
+is_valid_asm_symbol (char c)
+{
+  if ('a' <= c && c <= 'z')
+    return true;
+  if ('A' <= c && c <= 'Z')
+    return true;
+  if ('0' <= c && c <= '9')
+    return true;
+  if (c == '_')
+    return true;
+  return false;
+}
+
+/* This function changes the assembler name for functions that are
+   versions.  If DECL is a function version and has a "target"
+   attribute, it appends the attribute string to its assembler name.  */
+
+static tree
+rs6000_mangle_function_version_name (tree decl, tree id)
+{
+  if (DECL_FUNCTION_VERSIONED (decl) == FUNCTION_VERSION_TARGET)
+    /* This won't work, but it matches the preexisting behaviour.  It can be
+       modified to return something different if/when support for function
+       multiversioning with target or target version attributes is enabled.  */
+    return id;
+
+  tree version_attr;
+  const char *orig_name, *version_string;
+
+  version_attr = lookup_attribute ("target", DECL_ATTRIBUTES (decl));
+
+  /* target attribute string cannot be NULL.  */
+  gcc_assert (version_attr != NULL_TREE);
+
+  orig_name = IDENTIFIER_POINTER (id);
+  version_string
+    = TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (version_attr)));
+
+  int version_len = strlen (version_string);
+  char *suffix = XNEWVEC (char, version_len + 1);
+
+  /* Replace all not valid assembler symbols with '_'.  */
+  for (int i = 0; i < version_len; i++)
+    if (!is_valid_asm_symbol (version_string[i]))
+      suffix[i] = '_';
+    else
+      suffix[i] = version_string[i];
+  suffix[version_len] = '\0';
+
+  char *assembler_name = XNEWVEC (char,
+				  strlen (orig_name) + strlen (suffix) + 2);
+  sprintf (assembler_name, "%s.%s", orig_name, suffix);
+
+  tree ret = get_identifier (assembler_name);
+  XDELETEVEC (suffix);
+  XDELETEVEC (assembler_name);
+  return ret;
+}
+
 /* Hook to decide if we need to scan function gimple statements to
    collect target specific information for inlining, and update the
    corresponding RS6000_FN_TARGET_INFO_* bit in INFO if we are able
diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index 9bd684608b9e3378292cdb042184ba603b3d69aa..213cb72caf583772b9706a755f0f170ccc352542 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -4439,7 +4439,10 @@  static tree
 get_mangled_id (tree decl)
 {
   tree id = mangle_decl_string (decl);
-  return targetm.mangle_decl_assembler_name (decl, id);
+  id = targetm.mangle_decl_assembler_name (decl, id);
+  if (TREE_CODE (decl) == FUNCTION_DECL && DECL_FUNCTION_VERSIONED (decl))
+      id = targetm.mangle_function_version_name (decl, id);
+  return id;
 }
 
 /* Create an identifier for the external mangled name of DECL.  */
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index 69ae63c77de6e67e197fb40d8d5ccb2dbd42c2d0..6d76753bf302f46619515811dfb703abaad2b9fa 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -8057,6 +8057,16 @@  your target system.  The default implementation of this hook just
 returns the @var{id} provided.
 @end deftypefn
 
+@deftypefn {Target Hook} tree TARGET_MANGLE_FUNCTION_VERSION_NAME (tree @var{decl}, tree @var{id})
+Define this hook to specify how to postprocess the assembler name
+generated by target-independent code, to differentiate different target
+function versions.  The @var{id} provided to this hook will be
+the computed name (e.g., the macro @code{DECL_NAME} of the @var{decl} in C,
+or the mangled name of the @var{decl} in C++).  The return value of the
+hook is an @code{IDENTIFIER_NODE} for the appropriate mangled name on
+your target system.
+@end deftypefn
+
 @deftypefn {Target Hook} void TARGET_ENCODE_SECTION_INFO (tree @var{decl}, rtx @var{rtl}, int @var{new_decl_p})
 Define this hook if references to a symbol or a constant must be
 treated differently depending on something about the variable or
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 21343d4d1bf2fcee804e1365e985b4fa4fa7f066..3ef6d84d1d0678ff16be2f90b5c952e84f71c633 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -5035,6 +5035,8 @@  it is unlikely to be called.
 
 @hook TARGET_MANGLE_DECL_ASSEMBLER_NAME
 
+@hook TARGET_MANGLE_FUNCTION_VERSION_NAME
+
 @hook TARGET_ENCODE_SECTION_INFO
 
 @hook TARGET_STRIP_NAME_ENCODING
diff --git a/gcc/multiple_target.cc b/gcc/multiple_target.cc
index 5fa13ee78035924e5dbd2aec1dd05192342c1a59..4c5cc1911adb7680b8857ab9ac71ae22862e64ef 100644
--- a/gcc/multiple_target.cc
+++ b/gcc/multiple_target.cc
@@ -162,7 +162,8 @@  create_dispatcher_calls (struct cgraph_node *node)
 	}
     }
 
-  tree fname = clone_function_name (node->decl, "default");
+  tree fname = DECL_ASSEMBLER_NAME (node->decl);
+  fname = targetm.mangle_function_version_name (node->decl, fname);
   symtab->change_decl_assembler_name (node->decl, fname);
 
   if (node->definition)
@@ -236,44 +237,10 @@  separate_attrs (char *attr_str, char **attrs, int attrnum)
   return i;
 }
 
-/*  Return true if symbol is valid in assembler name.  */
-
-static bool
-is_valid_asm_symbol (char c)
-{
-  if ('a' <= c && c <= 'z')
-    return true;
-  if ('A' <= c && c <= 'Z')
-    return true;
-  if ('0' <= c && c <= '9')
-    return true;
-  if (c == '_')
-    return true;
-  return false;
-}
-
-/*  Replace all not valid assembler symbols with '_'.  */
-
-static void
-create_new_asm_name (char *old_asm_name, char *new_asm_name)
-{
-  int i;
-  int old_name_len = strlen (old_asm_name);
-
-  /* Replace all not valid assembler symbols with '_'.  */
-  for (i = 0; i < old_name_len; i++)
-    if (!is_valid_asm_symbol (old_asm_name[i]))
-      new_asm_name[i] = '_';
-    else
-      new_asm_name[i] = old_asm_name[i];
-  new_asm_name[old_name_len] = '\0';
-}
-
 /*  Creates target clone of NODE.  */
 
 static cgraph_node *
-create_target_clone (cgraph_node *node, bool definition, char *name,
-		     tree attributes)
+create_target_clone (cgraph_node *node, bool definition, tree attributes)
 {
   cgraph_node *new_node;
 
@@ -281,7 +248,7 @@  create_target_clone (cgraph_node *node, bool definition, char *name,
     {
       new_node
 	= node->create_version_clone_with_body (vNULL, NULL, NULL, NULL, NULL,
-						name, attributes, true);
+						"target_version", attributes, true);
       if (new_node == NULL)
 	return NULL;
       new_node->force_output = true;
@@ -291,9 +258,12 @@  create_target_clone (cgraph_node *node, bool definition, char *name,
       tree new_decl = copy_node (node->decl);
       new_node = cgraph_node::get_create (new_decl);
       DECL_ATTRIBUTES (new_decl) = attributes;
+      DECL_FUNCTION_VERSIONED (new_decl)
+	= FUNCTION_VERSION_TARGET_CLONES;
       /* Generate a new name for the new version.  */
-      tree fname = clone_function_name (node->decl, name);
-      symtab->change_decl_assembler_name (new_node->decl, fname);
+      tree fname = DECL_ASSEMBLER_NAME (node->decl);
+      fname = targetm.mangle_function_version_name (new_decl, fname);
+      symtab->change_decl_assembler_name (new_decl, fname);
     }
   return new_node;
 }
@@ -393,11 +363,8 @@  expand_target_clones (struct cgraph_node *node, bool definition)
       tree attributes = make_attribute (new_attr_name, attr,
 					DECL_ATTRIBUTES (node->decl));
 
-      char *suffix = XNEWVEC (char, strlen (attr) + 1);
-      create_new_asm_name (attr, suffix);
-      cgraph_node *new_node = create_target_clone (node, definition, suffix,
+      cgraph_node *new_node = create_target_clone (node, definition,
 						   attributes);
-      XDELETEVEC (suffix);
       if (new_node == NULL)
 	{
 	  XDELETEVEC (attrs);
diff --git a/gcc/target.def b/gcc/target.def
index fdad7bbc93e2ad8aea30336d5cd4af67801e9c74..6bd3d2c6831eb32c6695e86de402be8aaf39fa04 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -3162,6 +3162,20 @@  returns the @var{id} provided.",
  tree, (tree decl, tree  id),
  default_mangle_decl_assembler_name)
 
+/* Modify and return the identifier of a DECL's external name,
+   originally identified by ID, to differentiate different target function
+   versions as required by the target.  */
+DEFHOOK
+(mangle_function_version_name,
+ "Define this hook to specify how to postprocess the assembler name\n\
+generated by target-independent code, to differentiate different target\n\
+function versions.  The @var{id} provided to this hook will be\n\
+the computed name (e.g., the macro @code{DECL_NAME} of the @var{decl} in C,\n\
+or the mangled name of the @var{decl} in C++).  The return value of the\n\
+hook is an @code{IDENTIFIER_NODE} for the appropriate mangled name on\n\
+your target system.",
+ tree, (tree decl, tree id), NULL)
+
 /* Do something target-specific to record properties of the DECL into
    the associated SYMBOL_REF.  */
 DEFHOOK
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols1.C b/gcc/testsuite/g++.target/aarch64/mv-symbols1.C
index afbd9cacfc72e89ff4a06e3baae7ccc63ed64fc0..53e0abcd9b4333590a4c1415ec56cf09fb1ce2bf 100644
--- a/gcc/testsuite/g++.target/aarch64/mv-symbols1.C
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols1.C
@@ -49,18 +49,18 @@  int bar(int x)
 /* When updating any of the symbol names in these tests, make sure to also
    update any tests for their absence in mv-symbolsN.C */
 
-/* { dg-final { scan-assembler-times "\n_Z3foov:\n" 1 } } */
+/* { 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\tbl\t_Z7_Z3foovv\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z7_Z3foovv, %gnu_indirect_function\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3foovv,_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_Z3fooi:\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" 1 } } */
-/* { dg-final { scan-assembler-times "\n\tbl\t_Z7_Z3fooii\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z7_Z3fooii, %gnu_indirect_function\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3fooii,_Z3fooi\.resolver\n" 1 } } */
+/* { 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 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols2.C b/gcc/testsuite/g++.target/aarch64/mv-symbols2.C
index 54d2396f40705b6a6f7839ded78dcfddd911f7dd..f0c7967a97abb31f3cf9430ae9e8bb807beb8485 100644
--- a/gcc/testsuite/g++.target/aarch64/mv-symbols2.C
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols2.C
@@ -37,16 +37,16 @@  int foo (int)
   return 2;
 }
 
-/* { dg-final { scan-assembler-times "\n_Z3foov:\n" 1 } } */
+/* { 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_Z7_Z3foovv, %gnu_indirect_function\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3foovv,_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_Z3fooi:\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_Z7_Z3fooii, %gnu_indirect_function\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3fooii,_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 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols3.C b/gcc/testsuite/g++.target/aarch64/mv-symbols3.C
index 30e78b329851069e061e7ae179bbf78e1a2b4b04..3d30e27deb8b54b838cd8f5f18d5b68e87f4515e 100644
--- a/gcc/testsuite/g++.target/aarch64/mv-symbols3.C
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols3.C
@@ -25,17 +25,17 @@  int bar()
   return foo ();
 }
 
-/* { dg-final { scan-assembler-times "\n_Z3foov:\n" 0 } } */
+/* { 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\tbl\t_Z7_Z3foovv\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z7_Z3foovv, %gnu_indirect_function\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3foovv,_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_Z3fooi:\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" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z7_Z3fooii, %gnu_indirect_function\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3fooii,_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 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols4.C b/gcc/testsuite/g++.target/aarch64/mv-symbols4.C
index 674f8f88dce6b6b374de1198ed16ebcae9f816ca..73e3279ec314a5e5be3c6f8f1d2b6a520e639d27 100644
--- a/gcc/testsuite/g++.target/aarch64/mv-symbols4.C
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols4.C
@@ -32,17 +32,17 @@  int bar()
   return foo ();
 }
 
-/* { dg-final { scan-assembler-times "\n_Z3foov:\n" 1 } } */
+/* { 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\.resolver:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\tbl\t_Z7_Z3foovv\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z7_Z3foovv, %gnu_indirect_function\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3foovv,_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_Z3fooi:\n" 1 } } */
+/* { 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_Z7_Z3fooii, %gnu_indirect_function\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3fooii,_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 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols5.C b/gcc/testsuite/g++.target/aarch64/mv-symbols5.C
index 38bc2bdfc21aa9846e574442e1f53dc31a7234aa..05d1379f53ec1b74c29d386c8bd43a81de7ed0e4 100644
--- a/gcc/testsuite/g++.target/aarch64/mv-symbols5.C
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols5.C
@@ -40,17 +40,17 @@  int bar()
 /* When updating any of the symbol names in these tests, make sure to also
    update any tests for their absence in mvc-symbolsN.C */
 
-/* { dg-final { scan-assembler-times "\n_Z3foov:\n" 0 } } */
+/* { 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\tbl\t_Z7_Z3foovv\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.type\t_Z7_Z3foovv, %gnu_indirect_function\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3foovv,_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_Z3fooi:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */
 /* { 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_Z7_Z3fooii, %gnu_indirect_function\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n\t\.set\t_Z7_Z3fooii,_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 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mvc-symbols1.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols1.C
index b32e9200e763e8e73316c0d56cf290dadb11b3c8..2dd7c79f16cf7b6ac715c2ad2b35fface2695bed 100644
--- a/gcc/testsuite/g++.target/aarch64/mvc-symbols1.C
+++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols1.C
@@ -28,16 +28,16 @@  int bar(int x)
    update any tests for their absence in mvc-symbolsN.C */
 
 /* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n_Z3foov\.dotprod:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n_Z3foov\.sve_sve2:\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\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_Z3fooi\.default:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n_Z3fooi\.dotprod:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n_Z3fooi\.sve_sve2:\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" 1 } } */
 /* { 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 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mvc-symbols2.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols2.C
index f57ae25549be709bbf00811f7b78725051a79b9f..75b9c126dd8c337ac983862e3ba736a2c2c9a5ac 100644
--- a/gcc/testsuite/g++.target/aarch64/mvc-symbols2.C
+++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols2.C
@@ -15,15 +15,15 @@  int foo (int)
 }
 
 /* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n_Z3foov\.dotprod:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n_Z3foov\.sve_sve2:\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\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\.dotprod:\n" 1 } } */
-/* { dg-final { scan-assembler-times "\n_Z3fooi\.sve_sve2:\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" 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/mvc-symbols3.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols3.C
index 86340d05b4ad8ab4c3a0c34aacf31e40f7099336..82e777c8fc6ef5fa45aed431641a928b1960303a 100644
--- a/gcc/testsuite/g++.target/aarch64/mvc-symbols3.C
+++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols3.C
@@ -19,16 +19,16 @@  int bar(int x)
 }
 
 /* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n_Z3foov\.dotprod:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n_Z3foov\.sve_sve2:\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\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_Z3fooi\.default:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n_Z3fooi\.dotprod:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n_Z3fooi\.sve_sve2:\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\tbl\t_Z3fooi\n" 1 } } */
 /* { dg-final { scan-assembler-times "\n\t\.type\t_Z3fooi, %gnu_indirect_function\n" 1 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mvc-symbols4.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols4.C
index 351545fd201ca80d3d0bb13afdca1d49f211519b..6c86ae61e5fa52d14ed28cebb41d5fd8a7e1552f 100644
--- a/gcc/testsuite/g++.target/aarch64/mvc-symbols4.C
+++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols4.C
@@ -9,15 +9,15 @@  __attribute__((target_clones("sve+sve2", "dotprod", "default")))
 int foo (int);
 
 /* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n_Z3foov\.dotprod:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n_Z3foov\.sve_sve2:\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" 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_Z3fooi\.default:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n_Z3fooi\.dotprod:\n" 0 } } */
-/* { dg-final { scan-assembler-times "\n_Z3fooi\.sve_sve2:\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" 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 } } */