public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH 0/5] Fix fmv mangling for AArch64
@ 2024-01-15 11:26 Andrew Carlotti
  2024-01-15 11:26 ` [PATCH 1/5] testsuite: Add tests for fmv symbol presence and mangling Andrew Carlotti
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Andrew Carlotti @ 2024-01-15 11:26 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener

This patch series should have no functional change besides the mangling of some symbol names on AArch64.

Patch 1/5 adds lots of tests to verify that existing mangling behaviour on x86 and PowerPC is unchanged.

Patch 2/5 extends DECL_FUNCTION_VERSIONED to a 2-bit enum.

Patches 3/5 and 4/5 are trivial refactorings.

Patch 5/5 is the only patch with any functional change, and that should be
minimal.  I've bootstrapped and tested the entire series on both AArch64 and
x86.  I've also run the new x86 and PowerPC tests on a cross-compiler (with a
temporary hack to disable ifunc availability checks) to verify that function
multiversioning still works on those platforms, with the symbol mangling
unchanged.

I'm aware now that we just started of Stage 4, and this isn't actually a
regression, but is this still ok for master?



Some other things I previously tried that I couldn't make work:
- I had hoped to create an explicit target hook for the ifunc symbol name
mangling as well, but it turned out to be rather tricky to replicate the
existing double mangling weirdness for x86 (I didn't work out how to convince
the frontend to apply C++ mangling to the new symbol on-demand without breaking
other things).

- It's also awkward to try to access the base assembler name after applying
function version mangling - this is why I resorted to just reversing the
default version mangling in the AArch64 backend.  I tried delaying function
version mangling until after the resolver was generated, but that led to issues
with duplicate comdat group names from make_decl_one_only.

There may be less hacky solutions or workarounds for these issues, but they
would involve a more substantial refactoring and will have to wait until GCC 15
(or later).

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/5] testsuite: Add tests for fmv symbol presence and mangling
  2024-01-15 11:26 [PATCH 0/5] Fix fmv mangling for AArch64 Andrew Carlotti
@ 2024-01-15 11:26 ` Andrew Carlotti
  2024-01-15 11:27 ` [PATCH 2/5] tree: Extend DECL_FUNCTION_VERSIONED to an enum Andrew Carlotti
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Andrew Carlotti @ 2024-01-15 11:26 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener

These tests are not intended to designate "correct" behaviour, but are
instead intended to demonstrate current behaviour, and provide a warning
if subsequent patches might lead to compatibility issues for targets
with existing function multiversioning support.

gcc/testsuite/ChangeLog:

	* g++.target/aarch64/mv-symbols1.C: New test.
	* g++.target/aarch64/mv-symbols2.C: New test.
	* g++.target/aarch64/mv-symbols3.C: New test.
	* g++.target/aarch64/mv-symbols4.C: New test.
	* g++.target/aarch64/mv-symbols5.C: New test.
	* g++.target/aarch64/mvc-symbols1.C: New test.
	* g++.target/aarch64/mvc-symbols2.C: New test.
	* g++.target/aarch64/mvc-symbols3.C: New test.
	* g++.target/aarch64/mvc-symbols4.C: New test.
	* g++.target/i386/mv-symbols1.C: New test.
	* g++.target/i386/mv-symbols2.C: New test.
	* g++.target/i386/mv-symbols3.C: New test.
	* g++.target/i386/mv-symbols4.C: New test.
	* g++.target/i386/mv-symbols5.C: New test.
	* g++.target/i386/mvc-symbols1.C: New test.
	* g++.target/i386/mvc-symbols2.C: New test.
	* g++.target/i386/mvc-symbols3.C: New test.
	* g++.target/i386/mvc-symbols4.C: New test.
	* g++.target/powerpc/mvc-symbols1.C: New test.
	* g++.target/powerpc/mvc-symbols2.C: New test.
	* g++.target/powerpc/mvc-symbols3.C: New test.
	* g++.target/powerpc/mvc-symbols4.C: New test.


diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols1.C b/gcc/testsuite/g++.target/aarch64/mv-symbols1.C
new file mode 100644
index 0000000000000000000000000000000000000000..afbd9cacfc72e89ff4a06e3baae7ccc63ed64fc0
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols1.C
@@ -0,0 +1,66 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+int foo ()
+{
+  return 1;
+}
+
+__attribute__((target_version("dotprod")))
+int foo ()
+{
+  return 3;
+}
+__attribute__((target_version("sve+sve2")))
+int foo ()
+{
+  return 5;
+}
+
+__attribute__((target_version("sve+sve2")))
+int foo (int)
+{
+  return 6;
+}
+
+__attribute__((target_version("dotprod")))
+int foo (int)
+{
+  return 4;
+}
+
+int foo (int)
+{
+  return 2;
+}
+
+
+int bar()
+{
+  return foo ();
+}
+
+int bar(int x)
+{
+  return foo (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\._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_Z3fooi:\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 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols2.C b/gcc/testsuite/g++.target/aarch64/mv-symbols2.C
new file mode 100644
index 0000000000000000000000000000000000000000..54d2396f40705b6a6f7839ded78dcfddd911f7dd
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols2.C
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_version("default")))
+int foo ()
+{
+  return 1;
+}
+
+__attribute__((target_version("dotprod")))
+int foo ()
+{
+  return 3;
+}
+__attribute__((target_version("sve+sve2")))
+int foo ()
+{
+  return 5;
+}
+
+__attribute__((target_version("sve+sve2")))
+int foo (int)
+{
+  return 6;
+}
+
+__attribute__((target_version("dotprod")))
+int foo (int)
+{
+  return 4;
+}
+
+__attribute__((target_version("default")))
+int foo (int)
+{
+  return 2;
+}
+
+/* { dg-final { scan-assembler-times "\n_Z3foov:\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_Z3fooi:\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 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols3.C b/gcc/testsuite/g++.target/aarch64/mv-symbols3.C
new file mode 100644
index 0000000000000000000000000000000000000000..30e78b329851069e061e7ae179bbf78e1a2b4b04
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols3.C
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_version("default")))
+int foo ();
+
+__attribute__((target_version("dotprod")))
+int foo ();
+
+__attribute__((target_version("sve+sve2")))
+int foo ();
+
+__attribute__((target_version("default")))
+int foo (int);
+
+__attribute__((target_version("dotprod")))
+int foo (int);
+
+__attribute__((target_version("sve+sve2")))
+int foo (int);
+
+int bar()
+{
+  return foo ();
+}
+
+/* { dg-final { scan-assembler-times "\n_Z3foov:\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_Z3fooi:\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 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols4.C b/gcc/testsuite/g++.target/aarch64/mv-symbols4.C
new file mode 100644
index 0000000000000000000000000000000000000000..674f8f88dce6b6b374de1198ed16ebcae9f816ca
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols4.C
@@ -0,0 +1,48 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_version("default")))
+int foo ()
+{
+  return 1;
+}
+
+__attribute__((target_version("dotprod")))
+int foo ();
+
+__attribute__((target_version("sve+sve2")))
+int foo ();
+
+__attribute__((target_version("default")))
+int foo (int)
+{
+  return 2;
+}
+
+__attribute__((target_version("dotprod")))
+int foo (int);
+
+__attribute__((target_version("sve+sve2")))
+int foo (int);
+
+
+int bar()
+{
+  return foo ();
+}
+
+/* { dg-final { scan-assembler-times "\n_Z3foov:\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_Z3fooi:\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 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mv-symbols5.C b/gcc/testsuite/g++.target/aarch64/mv-symbols5.C
new file mode 100644
index 0000000000000000000000000000000000000000..38bc2bdfc21aa9846e574442e1f53dc31a7234aa
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mv-symbols5.C
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_version("default")))
+int foo ();
+
+__attribute__((target_version("dotprod")))
+int foo ()
+{
+  return 3;
+}
+__attribute__((target_version("sve+sve2")))
+int foo ()
+{
+  return 5;
+}
+
+__attribute__((target_version("default")))
+int foo (int);
+
+__attribute__((target_version("dotprod")))
+int foo (int)
+{
+  return 4;
+}
+
+__attribute__((target_version("sve+sve2")))
+int foo (int)
+{
+  return 6;
+}
+
+
+int bar()
+{
+  return foo ();
+}
+
+/* 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\._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_Z3fooi:\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 } } */
diff --git a/gcc/testsuite/g++.target/aarch64/mvc-symbols1.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols1.C
new file mode 100644
index 0000000000000000000000000000000000000000..b32e9200e763e8e73316c0d56cf290dadb11b3c8
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols1.C
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_clones("default", "dotprod", "sve+sve2")))
+int foo ()
+{
+  return 1;
+}
+
+__attribute__((target_clones("sve+sve2", "dotprod", "default")))
+int foo (int)
+{
+  return 2;
+}
+
+int bar()
+{
+  return foo ();
+}
+
+int bar(int x)
+{
+  return foo (x);
+}
+
+/* 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\.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\.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\.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/mvc-symbols2.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols2.C
new file mode 100644
index 0000000000000000000000000000000000000000..f57ae25549be709bbf00811f7b78725051a79b9f
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols2.C
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_clones("default", "dotprod", "sve+sve2")))
+int foo ()
+{
+  return 1;
+}
+
+__attribute__((target_clones("sve+sve2", "dotprod", "default")))
+int foo (int)
+{
+  return 2;
+}
+
+/* { 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\.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\.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
new file mode 100644
index 0000000000000000000000000000000000000000..86340d05b4ad8ab4c3a0c34aacf31e40f7099336
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols3.C
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_clones("default", "dotprod", "sve+sve2")))
+int foo ();
+
+__attribute__((target_clones("sve+sve2", "dotprod", "default")))
+int foo (int);
+
+int bar()
+{
+  return foo ();
+}
+
+int bar(int x)
+{
+  return foo (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\.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\.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/mvc-symbols4.C b/gcc/testsuite/g++.target/aarch64/mvc-symbols4.C
new file mode 100644
index 0000000000000000000000000000000000000000..351545fd201ca80d3d0bb13afdca1d49f211519b
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/mvc-symbols4.C
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_clones("default", "dotprod", "sve+sve2")))
+int foo ();
+
+__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\.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\.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/i386/mv-symbols1.C b/gcc/testsuite/g++.target/i386/mv-symbols1.C
new file mode 100644
index 0000000000000000000000000000000000000000..1290299aea5eff77de9951ee2fac5a626b7aa487
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/mv-symbols1.C
@@ -0,0 +1,68 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target("default")))
+int foo ()
+{
+  return 1;
+}
+
+__attribute__((target("arch=slm")))
+int foo ()
+{
+  return 3;
+}
+
+__attribute__((target("sse4.2")))
+int foo ()
+{
+  return 5;
+}
+
+__attribute__((target("sse4.2")))
+int foo (int)
+{
+  return 6;
+}
+
+__attribute__((target("arch=slm")))
+int foo (int)
+{
+  return 4;
+}
+
+__attribute__((target("default")))
+int foo (int)
+{
+  return 2;
+}
+
+int bar()
+{
+  return foo ();
+}
+
+int bar(int x)
+{
+  return foo (x);
+}
+
+/* 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" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.arch_slm:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.sse4.2:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tcall\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_Z3fooi:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.arch_slm:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.sse4.2:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tcall\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 } } */
diff --git a/gcc/testsuite/g++.target/i386/mv-symbols2.C b/gcc/testsuite/g++.target/i386/mv-symbols2.C
new file mode 100644
index 0000000000000000000000000000000000000000..8b75565d78d03abda18a3a99d6fa7010ee6c8515
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/mv-symbols2.C
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target("default")))
+int foo ()
+{
+  return 1;
+}
+
+__attribute__((target("arch=slm")))
+int foo ()
+{
+  return 3;
+}
+
+__attribute__((target("sse4.2")))
+int foo ()
+{
+  return 5;
+}
+
+__attribute__((target("sse4.2")))
+int foo (int)
+{
+  return 6;
+}
+
+__attribute__((target("arch=slm")))
+int foo (int)
+{
+  return 4;
+}
+
+__attribute__((target("default")))
+int foo (int)
+{
+  return 2;
+}
+
+/* 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" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.arch_slm:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.sse4.2:\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_Z3fooi:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.arch_slm:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.sse4.2:\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 } } */
diff --git a/gcc/testsuite/g++.target/i386/mv-symbols3.C b/gcc/testsuite/g++.target/i386/mv-symbols3.C
new file mode 100644
index 0000000000000000000000000000000000000000..a5cf3445a4314d57ad7ff7296e88797b138f2a21
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/mv-symbols3.C
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target("default")))
+int foo ();
+
+__attribute__((target("arch=slm")))
+int foo ();
+
+__attribute__((target("sse4.2")))
+int foo ();
+
+__attribute__((target("sse4.2")))
+int foo (int);
+
+__attribute__((target("arch=slm")))
+int foo (int);
+
+__attribute__((target("default")))
+int foo (int);
+
+int bar()
+{
+  return foo ();
+}
+
+/* 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\.arch_slm:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.sse4.2:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tcall\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_Z3fooi:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.arch_slm:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.sse4.2:\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 } } */
diff --git a/gcc/testsuite/g++.target/i386/mv-symbols4.C b/gcc/testsuite/g++.target/i386/mv-symbols4.C
new file mode 100644
index 0000000000000000000000000000000000000000..bb10f126f673fc08010ce97333102b9ae4952d6d
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/mv-symbols4.C
@@ -0,0 +1,50 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target("default")))
+int foo ()
+{
+  return 1;
+}
+
+__attribute__((target("arch=slm")))
+int foo ();
+
+__attribute__((target("sse4.2")))
+int foo ();
+
+__attribute__((target("sse4.2")))
+int foo (int);
+
+__attribute__((target("arch=slm")))
+int foo (int);
+
+__attribute__((target("default")))
+int foo (int)
+{
+  return 2;
+}
+
+int bar()
+{
+  return foo ();
+}
+
+/* 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" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.arch_slm:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.sse4.2:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tcall\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_Z3fooi:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.arch_slm:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.sse4.2:\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 } } */
diff --git a/gcc/testsuite/g++.target/i386/mv-symbols5.C b/gcc/testsuite/g++.target/i386/mv-symbols5.C
new file mode 100644
index 0000000000000000000000000000000000000000..d36e4c304c2d1a62257ea0e1bc54d35d66358cce
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/mv-symbols5.C
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target("default")))
+int foo ();
+
+__attribute__((target("arch=slm")))
+int foo ()
+{
+  return 3;
+}
+
+__attribute__((target("sse4.2")))
+int foo ()
+{
+  return 5;
+}
+
+__attribute__((target("sse4.2")))
+int foo (int)
+{
+  return 6;
+}
+
+__attribute__((target("arch=slm")))
+int foo (int)
+{
+  return 4;
+}
+
+__attribute__((target("default")))
+int foo (int);
+
+int bar()
+{
+  return foo ();
+}
+
+/* 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\.arch_slm:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.sse4.2:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tcall\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_Z3fooi:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.arch_slm:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.sse4.2:\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 } } */
diff --git a/gcc/testsuite/g++.target/i386/mvc-symbols1.C b/gcc/testsuite/g++.target/i386/mvc-symbols1.C
new file mode 100644
index 0000000000000000000000000000000000000000..ea8c434c353e8eacea73a2285438d02011ba21a0
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/mvc-symbols1.C
@@ -0,0 +1,44 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_clones("default", "arch=slm", "sse4.2")))
+int foo ()
+{
+  return 1;
+}
+
+__attribute__((target_clones("sse4.2", "arch=slm", "default")))
+int foo (int)
+{
+  return 2;
+}
+
+int bar()
+{
+  return foo ();
+}
+
+int bar(int x)
+{
+  return foo (x);
+}
+
+/* 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\.default:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.arch_slm:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.sse4_2:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
+/* { 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_Z3fooi.default:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.arch_slm:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.sse4_2:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */
+/* { 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 } } */
diff --git a/gcc/testsuite/g++.target/i386/mvc-symbols2.C b/gcc/testsuite/g++.target/i386/mvc-symbols2.C
new file mode 100644
index 0000000000000000000000000000000000000000..84b54a980b33df95dcc238cd3be4b4fdd041fe62
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/mvc-symbols2.C
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_clones("default", "arch=slm", "sse4.2")))
+int foo ()
+{
+  return 1;
+}
+
+__attribute__((target_clones("sse4.2", "arch=slm", "default")))
+int foo (int)
+{
+  return 2;
+}
+
+/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.arch_slm:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.sse4_2:\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\.arch_slm:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.sse4_2:\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/i386/mvc-symbols3.C b/gcc/testsuite/g++.target/i386/mvc-symbols3.C
new file mode 100644
index 0000000000000000000000000000000000000000..33927071028d7508d46e779eb9a85a40e0cbd37e
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/mvc-symbols3.C
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_clones("default", "arch=slm", "sse4.2")))
+int foo ();
+
+__attribute__((target_clones("sse4.2", "arch=slm", "default")))
+int foo (int);
+
+int bar()
+{
+  return foo ();
+}
+
+int bar(int x)
+{
+  return foo (x);
+}
+
+/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.arch_slm:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.sse4_2:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
+/* { 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_Z3fooi.default:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.arch_slm:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.sse4_2:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */
+/* { 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 } } */
diff --git a/gcc/testsuite/g++.target/i386/mvc-symbols4.C b/gcc/testsuite/g++.target/i386/mvc-symbols4.C
new file mode 100644
index 0000000000000000000000000000000000000000..ed9bc8f3e16f9a43412d089ff607887a48ccf2cc
--- /dev/null
+++ b/gcc/testsuite/g++.target/i386/mvc-symbols4.C
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_clones("default", "arch=slm", "sse4.2")))
+int foo ();
+
+__attribute__((target_clones("sse4.2", "arch=slm", "default")))
+int foo (int);
+
+/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.arch_slm:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.sse4_2:\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\.arch_slm:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.sse4_2:\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 } } */
diff --git a/gcc/testsuite/g++.target/powerpc/mvc-symbols1.C b/gcc/testsuite/g++.target/powerpc/mvc-symbols1.C
new file mode 100644
index 0000000000000000000000000000000000000000..8b331ed3a048d3e3422d716ef399011675af9955
--- /dev/null
+++ b/gcc/testsuite/g++.target/powerpc/mvc-symbols1.C
@@ -0,0 +1,47 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_clones("default", "cpu=power6", "cpu=power6x")))
+int foo ()
+{
+  return 1;
+}
+
+__attribute__((target_clones("cpu=power6x", "cpu=power6", "default")))
+int foo (int)
+{
+  return 2;
+}
+
+int bar()
+{
+  return foo ();
+}
+
+int bar(int x)
+{
+  return foo (x);
+}
+
+/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.cpu_power6:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.cpu_power6x:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tbl _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\tlis \[\\d\]+,_Z3foov\.default@ha\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3foov\.cpu_power6@ha\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3foov\.cpu_power6x@ha\n" 0 } } */
+
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.cpu_power6:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.cpu_power6x:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tbl _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\tlis \[\\d\]+,_Z3fooi\.default@ha\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3fooi\.cpu_power6@ha\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3fooi\.cpu_power6x@ha\n" 1 } } */
diff --git a/gcc/testsuite/g++.target/powerpc/mvc-symbols2.C b/gcc/testsuite/g++.target/powerpc/mvc-symbols2.C
new file mode 100644
index 0000000000000000000000000000000000000000..f62427faf037e32015276d0960495d1fe39b790d
--- /dev/null
+++ b/gcc/testsuite/g++.target/powerpc/mvc-symbols2.C
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_clones("default", "cpu=power6", "cpu=power6x")))
+int foo ()
+{
+  return 1;
+}
+
+__attribute__((target_clones("cpu=power6x", "cpu=power6", "default")))
+int foo (int)
+{
+  return 2;
+}
+
+/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.cpu_power6:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.cpu_power6x:\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\tlis \[\\d\]+,_Z3foov\.default@ha\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3foov\.cpu_power6@ha\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3foov\.cpu_power6x@ha\n" 0 } } */
+
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.cpu_power6:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.cpu_power6x:\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 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3fooi\.default@ha\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3fooi\.cpu_power6@ha\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3fooi\.cpu_power6x@ha\n" 1 } } */
diff --git a/gcc/testsuite/g++.target/powerpc/mvc-symbols3.C b/gcc/testsuite/g++.target/powerpc/mvc-symbols3.C
new file mode 100644
index 0000000000000000000000000000000000000000..d5813922961a17a0788bd6a53255743f750783d6
--- /dev/null
+++ b/gcc/testsuite/g++.target/powerpc/mvc-symbols3.C
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_clones("default", "cpu=power6", "cpu=power6x")))
+int foo ();
+
+__attribute__((target_clones("cpu=power6x", "cpu=power6", "default")))
+int foo (int);
+
+int bar()
+{
+  return foo ();
+}
+
+int bar(int x)
+{
+  return foo (x);
+}
+
+/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.cpu_power6:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.cpu_power6x:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tbl _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\tlis \[\\d\]+,_Z3foov\.default@ha\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3foov\.cpu_power6@ha\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3foov\.cpu_power6x@ha\n" 0 } } */
+
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.cpu_power6:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.cpu_power6x:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.resolver:\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tbl _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\tlis \[\\d\]+,_Z3fooi\.default@ha\n" 1 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3fooi\.cpu_power6@ha\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3fooi\.cpu_power6x@ha\n" 0 } } */
diff --git a/gcc/testsuite/g++.target/powerpc/mvc-symbols4.C b/gcc/testsuite/g++.target/powerpc/mvc-symbols4.C
new file mode 100644
index 0000000000000000000000000000000000000000..ec111f53d935641aeda579e928822e71797e8301
--- /dev/null
+++ b/gcc/testsuite/g++.target/powerpc/mvc-symbols4.C
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-require-ifunc "" } */
+/* { dg-options "-O0" } */
+
+__attribute__((target_clones("default", "cpu=power6", "cpu=power6x")))
+int foo ();
+
+__attribute__((target_clones("cpu=power6x", "cpu=power6", "default")))
+int foo (int);
+
+/* { dg-final { scan-assembler-times "\n_Z3foov\.default:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.cpu_power6:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3foov\.cpu_power6x:\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\tlis \[\\d\]+,_Z3foov\.default@ha\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3foov\.cpu_power6@ha\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3foov\.cpu_power6x@ha\n" 0 } } */
+
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.default:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.cpu_power6:\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n_Z3fooi\.cpu_power6x:\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\tlis \[\\d\]+,_Z3fooi\.default@ha\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3fooi\.cpu_power6@ha\n" 0 } } */
+/* { dg-final { scan-assembler-times "\n\tlis \[\\d\]+,_Z3fooi\.cpu_power6x@ha\n" 0 } } */

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 2/5] tree: Extend DECL_FUNCTION_VERSIONED to an enum
  2024-01-15 11:26 [PATCH 0/5] Fix fmv mangling for AArch64 Andrew Carlotti
  2024-01-15 11:26 ` [PATCH 1/5] testsuite: Add tests for fmv symbol presence and mangling Andrew Carlotti
@ 2024-01-15 11:27 ` Andrew Carlotti
  2024-01-15 12:28   ` Richard Biener
  2024-01-15 11:27 ` [PATCH 3/5] Change create_version_clone_with_body parameter name Andrew Carlotti
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Andrew Carlotti @ 2024-01-15 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener

This allows code to determine why a particular function is
multiversioned.  For now, this will primarily be used to preserve
existing name mangling quirks when subsequent commits change all
function multiversioning name mangling to use explicit target hooks.
However, this can also be used in future to allow more of the
multiversioning logic to be moved out of target hooks, and to allow
targets to simultaneously enable multiversioning with both 'target' and
'target_version' attributes.

gcc/ChangeLog:

	* multiple_target.cc (expand_target_clones): Use new enum value.
	* tree-core.h (enum function_version_source): New enum.
	(struct tree_function_decl): Extend versioned_function to two
	bits.

gcc/cp/ChangeLog:

	* decl.cc (maybe_mark_function_versioned): Use new enum value.
	(duplicate_decls): Preserve DECL_FUNCTION_VERSIONED enum value.
	* module.cc (trees_out::core_bools): Use two bits for
	function_decl.versioned_function.
	(trees_in::core_bools): Ditto.


diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
index b10a72a87bf0a1cabab52c1e4b657bc8a379b91e..527931cd90a0a779a508a096b2623351fd65a2e8 100644
--- a/gcc/cp/decl.cc
+++ b/gcc/cp/decl.cc
@@ -1254,7 +1254,10 @@ maybe_mark_function_versioned (tree decl)
 {
   if (!DECL_FUNCTION_VERSIONED (decl))
     {
-      DECL_FUNCTION_VERSIONED (decl) = 1;
+      if (TARGET_HAS_FMV_TARGET_ATTRIBUTE)
+	DECL_FUNCTION_VERSIONED (decl) = FUNCTION_VERSION_TARGET;
+      else
+	DECL_FUNCTION_VERSIONED (decl) = FUNCTION_VERSION_TARGET_VERSION;
       /* If DECL_ASSEMBLER_NAME has already been set, re-mangle
 	 to include the version marker.  */
       if (DECL_ASSEMBLER_NAME_SET_P (decl))
@@ -3159,7 +3162,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
       && DECL_FUNCTION_VERSIONED (olddecl))
     {
       /* Set the flag for newdecl so that it gets copied to olddecl.  */
-      DECL_FUNCTION_VERSIONED (newdecl) = 1;
+      DECL_FUNCTION_VERSIONED (newdecl) = DECL_FUNCTION_VERSIONED (olddecl);
       /* newdecl will be purged after copying to olddecl and is no longer
          a version.  */
       cgraph_node::delete_function_version_by_decl (newdecl);
diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
index aa75e2809d8fdca14443c6b911bf725f6d286d20..ba60d0753f91ef91d45fb5d62f26118be4e34840 100644
--- a/gcc/cp/module.cc
+++ b/gcc/cp/module.cc
@@ -5473,7 +5473,11 @@ trees_out::core_bools (tree t)
       WB (t->function_decl.looping_const_or_pure_flag);
 
       WB (t->function_decl.has_debug_args_flag);
-      WB (t->function_decl.versioned_function);
+
+      /* versioned_function is a 2 bit enum.  */
+      unsigned vf = t->function_decl.versioned_function;
+      WB ((vf >> 0) & 1);
+      WB ((vf >> 1) & 1);
 
       /* decl_type is a (misnamed) 2 bit discriminator.	 */
       unsigned kind = t->function_decl.decl_type;
@@ -5618,7 +5622,12 @@ trees_in::core_bools (tree t)
       RB (t->function_decl.looping_const_or_pure_flag);
       
       RB (t->function_decl.has_debug_args_flag);
-      RB (t->function_decl.versioned_function);
+
+      /* versioned_function is a 2 bit enum.  */
+      unsigned vf = 0;
+      vf |= unsigned (b ()) << 0;
+      vf |= unsigned (b ()) << 1;
+      t->function_decl.versioned_function = function_version_source (vf);
 
       /* decl_type is a (misnamed) 2 bit discriminator.	 */
       unsigned kind = 0;
diff --git a/gcc/multiple_target.cc b/gcc/multiple_target.cc
index 1fdd279da04a7acc5e8c50f528139f19cadcd5ff..56a1934fe820e91b2fa451dcf6989382c906b98c 100644
--- a/gcc/multiple_target.cc
+++ b/gcc/multiple_target.cc
@@ -383,7 +383,7 @@ expand_target_clones (struct cgraph_node *node, bool definition)
   if (decl1_v == NULL)
     decl1_v = node->insert_new_function_version ();
   before = decl1_v;
-  DECL_FUNCTION_VERSIONED (node->decl) = 1;
+  DECL_FUNCTION_VERSIONED (node->decl) = FUNCTION_VERSION_TARGET_CLONES;
 
   for (i = 0; i < attrnum; i++)
     {
@@ -421,7 +421,8 @@ expand_target_clones (struct cgraph_node *node, bool definition)
 
       before->next = after;
       after->prev = before;
-      DECL_FUNCTION_VERSIONED (new_node->decl) = 1;
+      DECL_FUNCTION_VERSIONED (new_node->decl)
+	= FUNCTION_VERSION_TARGET_CLONES;
     }
 
   XDELETEVEC (attrs);
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 8a89462bd7ecac52fcdc11c0b57ccf7c190572b3..e159d53f9d11ba848c49499aa963daa2fbcbc648 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1955,6 +1955,19 @@ enum function_decl_type
   /* 0 values left */
 };
 
+/* Enumerate function multiversioning attributes.  This is used to record which
+   attribute enabled multiversioning on a function, and allows targets to
+   adjust their behaviour accordingly.  */
+
+enum function_version_source
+{
+  FUNCTION_VERSION_NONE = 0,
+  FUNCTION_VERSION_TARGET = 1,
+  FUNCTION_VERSION_TARGET_CLONES = 2,
+  FUNCTION_VERSION_TARGET_VERSION = 3
+};
+
+
 /* FUNCTION_DECL inherits from DECL_NON_COMMON because of the use of the
    arguments/result/saved_tree fields by front ends.   It was either inherit
    FUNCTION_DECL from non_common, or inherit non_common from FUNCTION_DECL,
@@ -2002,10 +2015,10 @@ struct GTY(()) tree_function_decl {
   /* Align the bitfield to boundary of a byte.  */
   ENUM_BITFIELD(function_decl_type) decl_type: 2;
   unsigned has_debug_args_flag : 1;
-  unsigned versioned_function : 1;
+  ENUM_BITFIELD(function_version_source) versioned_function : 2;
   unsigned replaceable_operator : 1;
 
-  /* 11 bits left for future expansion.  */
+  /* 10 bits left for future expansion.  */
   /* 32 bits on 64-bit HW.  */
 };
 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 3/5] Change create_version_clone_with_body parameter name
  2024-01-15 11:26 [PATCH 0/5] Fix fmv mangling for AArch64 Andrew Carlotti
  2024-01-15 11:26 ` [PATCH 1/5] testsuite: Add tests for fmv symbol presence and mangling Andrew Carlotti
  2024-01-15 11:27 ` [PATCH 2/5] tree: Extend DECL_FUNCTION_VERSIONED to an enum Andrew Carlotti
@ 2024-01-15 11:27 ` Andrew Carlotti
  2024-01-15 11:28 ` [PATCH 4/5] cp: Use get_mangled_id in more places in mangle_decl Andrew Carlotti
  2024-01-15 11:28 ` [PATCH 5/5] Add target hook for function version name mangling Andrew Carlotti
  4 siblings, 0 replies; 11+ messages in thread
From: Andrew Carlotti @ 2024-01-15 11:27 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener

The new name better describes where it is used, and will be more
suitable when subsequent commits make further changes to this function.

gcc/ChangeLog:

	* cgraph.h (create_version_clone_with_body): Rename parameter
	and change default value.
	* cgraphclones.cc: Rename parameter.
	* multiple_target.cc (create_target_clone): Update for inverted
	boolean parameter.


diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index b4f028b3f3034056de1050ea1ab93a682197d0e1..16e2b2d045767206d5ccf12ee226f92ee10511d9 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 VERSION_DECL is set true, use clone_function_name_numbered for the
-     function clone.  Otherwise, use clone_function_name.
+     If TARGET_VERSION is set true, use clone_function_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
@@ -1024,7 +1024,7 @@ struct GTY((tag ("SYMTAB_FUNCTION"))) cgraph_node : public symtab_node
      vec<ipa_replace_map *, va_gc> *tree_map,
      ipa_param_adjustments *param_adjustments,
      bitmap bbs_to_copy, basic_block new_entry_block, const char *clone_name,
-     tree target_attributes = NULL_TREE, bool version_decl = true);
+     tree target_attributes = NULL_TREE, bool target_version = false);
 
   /* Insert a new cgraph_function_version_info node into cgraph_fnver_htab
      corresponding to cgraph_node.  */
diff --git a/gcc/cgraphclones.cc b/gcc/cgraphclones.cc
index 6d7bc402a29161f473aaa34fb11b24264a7e8b7c..ab9a0fe7ccc5fcf9a0a03363c66016466d39427e 100644
--- a/gcc/cgraphclones.cc
+++ b/gcc/cgraphclones.cc
@@ -1013,7 +1013,7 @@ cgraph_node::create_version_clone_with_body
    vec<ipa_replace_map *, va_gc> *tree_map,
    ipa_param_adjustments *param_adjustments,
    bitmap bbs_to_copy, basic_block new_entry_block, const char *suffix,
-   tree target_attributes, bool version_decl)
+   tree target_attributes, bool target_version)
 {
   tree old_decl = decl;
   cgraph_node *new_version_node = NULL;
@@ -1034,8 +1034,8 @@ cgraph_node::create_version_clone_with_body
     new_decl = copy_node (old_decl);
 
   /* Generate a new name for the new version. */
-  tree fnname = (version_decl ? clone_function_name_numbered (old_decl, suffix)
-		: clone_function_name (old_decl, suffix));
+  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);
diff --git a/gcc/multiple_target.cc b/gcc/multiple_target.cc
index 56a1934fe820e91b2fa451dcf6989382c906b98c..5fa13ee78035924e5dbd2aec1dd05192342c1a59 100644
--- a/gcc/multiple_target.cc
+++ b/gcc/multiple_target.cc
@@ -281,7 +281,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, false);
+						name, attributes, true);
       if (new_node == NULL)
 	return NULL;
       new_node->force_output = true;

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 4/5] cp: Use get_mangled_id in more places in mangle_decl
  2024-01-15 11:26 [PATCH 0/5] Fix fmv mangling for AArch64 Andrew Carlotti
                   ` (2 preceding siblings ...)
  2024-01-15 11:27 ` [PATCH 3/5] Change create_version_clone_with_body parameter name Andrew Carlotti
@ 2024-01-15 11:28 ` Andrew Carlotti
  2024-01-16 20:24   ` Jason Merrill
  2024-01-15 11:28 ` [PATCH 5/5] Add target hook for function version name mangling Andrew Carlotti
  4 siblings, 1 reply; 11+ messages in thread
From: Andrew Carlotti @ 2024-01-15 11:28 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener

There's no functional change here, but it makes it clearer that all
three locations should be doing the same thing (aside from changes to
flag_abi_version).

gcc/cp/ChangeLog:

	* mangle.cc (mangle_decl): Consistently use get_mangled_id.


diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
index a04bc584586f28cb80d21b5c6d647416aa8843df..9bd684608b9e3378292cdb042184ba603b3d69aa 100644
--- a/gcc/cp/mangle.cc
+++ b/gcc/cp/mangle.cc
@@ -4503,8 +4503,7 @@ mangle_decl (const tree decl)
 	    return;
 
 	  flag_abi_version = flag_abi_compat_version;
-	  id2 = mangle_decl_string (decl);
-	  id2 = targetm.mangle_decl_assembler_name (decl, id2);
+	  id2 = get_mangled_id (decl);
 	  flag_abi_version = save_ver;
 
 	  if (id2 != id)
@@ -4519,8 +4518,7 @@ mangle_decl (const tree decl)
 	      || id2 == NULL_TREE)
 	    {
 	      flag_abi_version = warn_abi_version;
-	      id2 = mangle_decl_string (decl);
-	      id2 = targetm.mangle_decl_assembler_name (decl, id2);
+	      id2 = get_mangled_id (decl);
 	    }
 	  flag_abi_version = save_ver;
 

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 5/5] Add target hook for function version name mangling
  2024-01-15 11:26 [PATCH 0/5] Fix fmv mangling for AArch64 Andrew Carlotti
                   ` (3 preceding siblings ...)
  2024-01-15 11:28 ` [PATCH 4/5] cp: Use get_mangled_id in more places in mangle_decl Andrew Carlotti
@ 2024-01-15 11:28 ` Andrew Carlotti
  4 siblings, 0 replies; 11+ messages in thread
From: Andrew Carlotti @ 2024-01-15 11:28 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener

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.


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 } } */

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/5] tree: Extend DECL_FUNCTION_VERSIONED to an enum
  2024-01-15 11:27 ` [PATCH 2/5] tree: Extend DECL_FUNCTION_VERSIONED to an enum Andrew Carlotti
@ 2024-01-15 12:28   ` Richard Biener
  2024-01-16  8:21     ` Andrew Carlotti
  0 siblings, 1 reply; 11+ messages in thread
From: Richard Biener @ 2024-01-15 12:28 UTC (permalink / raw)
  To: Andrew Carlotti; +Cc: gcc-patches

On Mon, Jan 15, 2024 at 12:27 PM Andrew Carlotti
<andrew.carlotti@arm.com> wrote:
>
> This allows code to determine why a particular function is
> multiversioned.  For now, this will primarily be used to preserve
> existing name mangling quirks when subsequent commits change all
> function multiversioning name mangling to use explicit target hooks.
> However, this can also be used in future to allow more of the
> multiversioning logic to be moved out of target hooks, and to allow
> targets to simultaneously enable multiversioning with both 'target' and
> 'target_version' attributes.

Why does module.cc need to stream the bits?  target_clone runs long
after the FE finished.  Instead I wonder why LTO doesn't stream the bits
(tree-streamer-{in,out}.cc)?

You have four states but only mention 'target' and 'target_version', what's the
states actually?  Can you amend the function_version_source enum
comment accordingly?

This looks like stage1 material to me.

Thanks,
Richard.

> gcc/ChangeLog:
>
>         * multiple_target.cc (expand_target_clones): Use new enum value.
>         * tree-core.h (enum function_version_source): New enum.
>         (struct tree_function_decl): Extend versioned_function to two
>         bits.
>
> gcc/cp/ChangeLog:
>
>         * decl.cc (maybe_mark_function_versioned): Use new enum value.
>         (duplicate_decls): Preserve DECL_FUNCTION_VERSIONED enum value.
>         * module.cc (trees_out::core_bools): Use two bits for
>         function_decl.versioned_function.
>         (trees_in::core_bools): Ditto.
>
>
> diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> index b10a72a87bf0a1cabab52c1e4b657bc8a379b91e..527931cd90a0a779a508a096b2623351fd65a2e8 100644
> --- a/gcc/cp/decl.cc
> +++ b/gcc/cp/decl.cc
> @@ -1254,7 +1254,10 @@ maybe_mark_function_versioned (tree decl)
>  {
>    if (!DECL_FUNCTION_VERSIONED (decl))
>      {
> -      DECL_FUNCTION_VERSIONED (decl) = 1;
> +      if (TARGET_HAS_FMV_TARGET_ATTRIBUTE)
> +       DECL_FUNCTION_VERSIONED (decl) = FUNCTION_VERSION_TARGET;
> +      else
> +       DECL_FUNCTION_VERSIONED (decl) = FUNCTION_VERSION_TARGET_VERSION;
>        /* If DECL_ASSEMBLER_NAME has already been set, re-mangle
>          to include the version marker.  */
>        if (DECL_ASSEMBLER_NAME_SET_P (decl))
> @@ -3159,7 +3162,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
>        && DECL_FUNCTION_VERSIONED (olddecl))
>      {
>        /* Set the flag for newdecl so that it gets copied to olddecl.  */
> -      DECL_FUNCTION_VERSIONED (newdecl) = 1;
> +      DECL_FUNCTION_VERSIONED (newdecl) = DECL_FUNCTION_VERSIONED (olddecl);
>        /* newdecl will be purged after copying to olddecl and is no longer
>           a version.  */
>        cgraph_node::delete_function_version_by_decl (newdecl);
> diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> index aa75e2809d8fdca14443c6b911bf725f6d286d20..ba60d0753f91ef91d45fb5d62f26118be4e34840 100644
> --- a/gcc/cp/module.cc
> +++ b/gcc/cp/module.cc
> @@ -5473,7 +5473,11 @@ trees_out::core_bools (tree t)
>        WB (t->function_decl.looping_const_or_pure_flag);
>
>        WB (t->function_decl.has_debug_args_flag);
> -      WB (t->function_decl.versioned_function);
> +
> +      /* versioned_function is a 2 bit enum.  */
> +      unsigned vf = t->function_decl.versioned_function;
> +      WB ((vf >> 0) & 1);
> +      WB ((vf >> 1) & 1);
>
>        /* decl_type is a (misnamed) 2 bit discriminator.         */
>        unsigned kind = t->function_decl.decl_type;
> @@ -5618,7 +5622,12 @@ trees_in::core_bools (tree t)
>        RB (t->function_decl.looping_const_or_pure_flag);
>
>        RB (t->function_decl.has_debug_args_flag);
> -      RB (t->function_decl.versioned_function);
> +
> +      /* versioned_function is a 2 bit enum.  */
> +      unsigned vf = 0;
> +      vf |= unsigned (b ()) << 0;
> +      vf |= unsigned (b ()) << 1;
> +      t->function_decl.versioned_function = function_version_source (vf);
>
>        /* decl_type is a (misnamed) 2 bit discriminator.         */
>        unsigned kind = 0;
> diff --git a/gcc/multiple_target.cc b/gcc/multiple_target.cc
> index 1fdd279da04a7acc5e8c50f528139f19cadcd5ff..56a1934fe820e91b2fa451dcf6989382c906b98c 100644
> --- a/gcc/multiple_target.cc
> +++ b/gcc/multiple_target.cc
> @@ -383,7 +383,7 @@ expand_target_clones (struct cgraph_node *node, bool definition)
>    if (decl1_v == NULL)
>      decl1_v = node->insert_new_function_version ();
>    before = decl1_v;
> -  DECL_FUNCTION_VERSIONED (node->decl) = 1;
> +  DECL_FUNCTION_VERSIONED (node->decl) = FUNCTION_VERSION_TARGET_CLONES;
>
>    for (i = 0; i < attrnum; i++)
>      {
> @@ -421,7 +421,8 @@ expand_target_clones (struct cgraph_node *node, bool definition)
>
>        before->next = after;
>        after->prev = before;
> -      DECL_FUNCTION_VERSIONED (new_node->decl) = 1;
> +      DECL_FUNCTION_VERSIONED (new_node->decl)
> +       = FUNCTION_VERSION_TARGET_CLONES;
>      }
>
>    XDELETEVEC (attrs);
> diff --git a/gcc/tree-core.h b/gcc/tree-core.h
> index 8a89462bd7ecac52fcdc11c0b57ccf7c190572b3..e159d53f9d11ba848c49499aa963daa2fbcbc648 100644
> --- a/gcc/tree-core.h
> +++ b/gcc/tree-core.h
> @@ -1955,6 +1955,19 @@ enum function_decl_type
>    /* 0 values left */
>  };
>
> +/* Enumerate function multiversioning attributes.  This is used to record which
> +   attribute enabled multiversioning on a function, and allows targets to
> +   adjust their behaviour accordingly.  */
> +
> +enum function_version_source
> +{
> +  FUNCTION_VERSION_NONE = 0,
> +  FUNCTION_VERSION_TARGET = 1,
> +  FUNCTION_VERSION_TARGET_CLONES = 2,
> +  FUNCTION_VERSION_TARGET_VERSION = 3
> +};
> +
> +
>  /* FUNCTION_DECL inherits from DECL_NON_COMMON because of the use of the
>     arguments/result/saved_tree fields by front ends.   It was either inherit
>     FUNCTION_DECL from non_common, or inherit non_common from FUNCTION_DECL,
> @@ -2002,10 +2015,10 @@ struct GTY(()) tree_function_decl {
>    /* Align the bitfield to boundary of a byte.  */
>    ENUM_BITFIELD(function_decl_type) decl_type: 2;
>    unsigned has_debug_args_flag : 1;
> -  unsigned versioned_function : 1;
> +  ENUM_BITFIELD(function_version_source) versioned_function : 2;
>    unsigned replaceable_operator : 1;
>
> -  /* 11 bits left for future expansion.  */
> +  /* 10 bits left for future expansion.  */
>    /* 32 bits on 64-bit HW.  */
>  };
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 2/5] tree: Extend DECL_FUNCTION_VERSIONED to an enum
  2024-01-15 12:28   ` Richard Biener
@ 2024-01-16  8:21     ` Andrew Carlotti
  2024-01-16 10:42       ` [PATCH] aarch64: Fix function multiversioning mangling Andrew Carlotti
  0 siblings, 1 reply; 11+ messages in thread
From: Andrew Carlotti @ 2024-01-16  8:21 UTC (permalink / raw)
  To: Richard Biener; +Cc: gcc-patches

On Mon, Jan 15, 2024 at 01:28:04PM +0100, Richard Biener wrote:
> On Mon, Jan 15, 2024 at 12:27 PM Andrew Carlotti
> <andrew.carlotti@arm.com> wrote:
> >
> > This allows code to determine why a particular function is
> > multiversioned.  For now, this will primarily be used to preserve
> > existing name mangling quirks when subsequent commits change all
> > function multiversioning name mangling to use explicit target hooks.
> > However, this can also be used in future to allow more of the
> > multiversioning logic to be moved out of target hooks, and to allow
> > targets to simultaneously enable multiversioning with both 'target' and
> > 'target_version' attributes.
> 
> Why does module.cc need to stream the bits?  target_clone runs long
> after the FE finished.  Instead I wonder why LTO doesn't stream the bits
> (tree-streamer-{in,out}.cc)?
>
> You have four states but only mention 'target' and 'target_version', what's the
> states actually?  Can you amend the function_version_source enum
> comment accordingly?

All four states are used, although currently not all within a single target,
and in many places you could also work out whether you're in the
"target_clones" case or the "target"/"target_version" case based upon whether
you're in the frontend code or the target_clone pass.  So perhaps the second
bit can be made redundant in most places, but it's useful in some parts of the
code.

The main benefits of this design are:
- that it allows backend target hooks to distinguish between the different
  causes of function multiversioning without having to create separate hooks,
  or pass an extra argument down the call stack;
- that it allows a backend to choose to support mutltiversioning with both
  "target" and "target_version" attributes (I remember Martin Liška suggested
  supporting "target_version" on x86 as well, and it could provide a way to
  improve how multiversioning works without running into backwards
  compatibility issues for the "target" attribute).

> This looks like stage1 material to me.

I considered it as stage 3 material, because it fixes a bug on aarch64 (where
the existing code didn't comply with the ACLE spec, and would have cause
problems when applied to public symbols).  Admittedly, I did miss the end of
stage 3 by a couple of days; I hadn't realised how early stage 4 began, and
spent the last couple of weeks focussing on Binutils work instead.

However, I've now realised that I can fix this bug entirely within the aarch64
backend (by overwriting the incorrect mangling applied in target-agnostic
code).  I'll send out that patch later today, which should hopefully be more
acceptable at this stage.

Thanks,
Andrew

> Thanks,
> Richard.
> 
> > gcc/ChangeLog:
> >
> >         * multiple_target.cc (expand_target_clones): Use new enum value.
> >         * tree-core.h (enum function_version_source): New enum.
> >         (struct tree_function_decl): Extend versioned_function to two
> >         bits.
> >
> > gcc/cp/ChangeLog:
> >
> >         * decl.cc (maybe_mark_function_versioned): Use new enum value.
> >         (duplicate_decls): Preserve DECL_FUNCTION_VERSIONED enum value.
> >         * module.cc (trees_out::core_bools): Use two bits for
> >         function_decl.versioned_function.
> >         (trees_in::core_bools): Ditto.
> >
> >
> > diff --git a/gcc/cp/decl.cc b/gcc/cp/decl.cc
> > index b10a72a87bf0a1cabab52c1e4b657bc8a379b91e..527931cd90a0a779a508a096b2623351fd65a2e8 100644
> > --- a/gcc/cp/decl.cc
> > +++ b/gcc/cp/decl.cc
> > @@ -1254,7 +1254,10 @@ maybe_mark_function_versioned (tree decl)
> >  {
> >    if (!DECL_FUNCTION_VERSIONED (decl))
> >      {
> > -      DECL_FUNCTION_VERSIONED (decl) = 1;
> > +      if (TARGET_HAS_FMV_TARGET_ATTRIBUTE)
> > +       DECL_FUNCTION_VERSIONED (decl) = FUNCTION_VERSION_TARGET;
> > +      else
> > +       DECL_FUNCTION_VERSIONED (decl) = FUNCTION_VERSION_TARGET_VERSION;
> >        /* If DECL_ASSEMBLER_NAME has already been set, re-mangle
> >          to include the version marker.  */
> >        if (DECL_ASSEMBLER_NAME_SET_P (decl))
> > @@ -3159,7 +3162,7 @@ duplicate_decls (tree newdecl, tree olddecl, bool hiding, bool was_hidden)
> >        && DECL_FUNCTION_VERSIONED (olddecl))
> >      {
> >        /* Set the flag for newdecl so that it gets copied to olddecl.  */
> > -      DECL_FUNCTION_VERSIONED (newdecl) = 1;
> > +      DECL_FUNCTION_VERSIONED (newdecl) = DECL_FUNCTION_VERSIONED (olddecl);
> >        /* newdecl will be purged after copying to olddecl and is no longer
> >           a version.  */
> >        cgraph_node::delete_function_version_by_decl (newdecl);
> > diff --git a/gcc/cp/module.cc b/gcc/cp/module.cc
> > index aa75e2809d8fdca14443c6b911bf725f6d286d20..ba60d0753f91ef91d45fb5d62f26118be4e34840 100644
> > --- a/gcc/cp/module.cc
> > +++ b/gcc/cp/module.cc
> > @@ -5473,7 +5473,11 @@ trees_out::core_bools (tree t)
> >        WB (t->function_decl.looping_const_or_pure_flag);
> >
> >        WB (t->function_decl.has_debug_args_flag);
> > -      WB (t->function_decl.versioned_function);
> > +
> > +      /* versioned_function is a 2 bit enum.  */
> > +      unsigned vf = t->function_decl.versioned_function;
> > +      WB ((vf >> 0) & 1);
> > +      WB ((vf >> 1) & 1);
> >
> >        /* decl_type is a (misnamed) 2 bit discriminator.         */
> >        unsigned kind = t->function_decl.decl_type;
> > @@ -5618,7 +5622,12 @@ trees_in::core_bools (tree t)
> >        RB (t->function_decl.looping_const_or_pure_flag);
> >
> >        RB (t->function_decl.has_debug_args_flag);
> > -      RB (t->function_decl.versioned_function);
> > +
> > +      /* versioned_function is a 2 bit enum.  */
> > +      unsigned vf = 0;
> > +      vf |= unsigned (b ()) << 0;
> > +      vf |= unsigned (b ()) << 1;
> > +      t->function_decl.versioned_function = function_version_source (vf);
> >
> >        /* decl_type is a (misnamed) 2 bit discriminator.         */
> >        unsigned kind = 0;
> > diff --git a/gcc/multiple_target.cc b/gcc/multiple_target.cc
> > index 1fdd279da04a7acc5e8c50f528139f19cadcd5ff..56a1934fe820e91b2fa451dcf6989382c906b98c 100644
> > --- a/gcc/multiple_target.cc
> > +++ b/gcc/multiple_target.cc
> > @@ -383,7 +383,7 @@ expand_target_clones (struct cgraph_node *node, bool definition)
> >    if (decl1_v == NULL)
> >      decl1_v = node->insert_new_function_version ();
> >    before = decl1_v;
> > -  DECL_FUNCTION_VERSIONED (node->decl) = 1;
> > +  DECL_FUNCTION_VERSIONED (node->decl) = FUNCTION_VERSION_TARGET_CLONES;
> >
> >    for (i = 0; i < attrnum; i++)
> >      {
> > @@ -421,7 +421,8 @@ expand_target_clones (struct cgraph_node *node, bool definition)
> >
> >        before->next = after;
> >        after->prev = before;
> > -      DECL_FUNCTION_VERSIONED (new_node->decl) = 1;
> > +      DECL_FUNCTION_VERSIONED (new_node->decl)
> > +       = FUNCTION_VERSION_TARGET_CLONES;
> >      }
> >
> >    XDELETEVEC (attrs);
> > diff --git a/gcc/tree-core.h b/gcc/tree-core.h
> > index 8a89462bd7ecac52fcdc11c0b57ccf7c190572b3..e159d53f9d11ba848c49499aa963daa2fbcbc648 100644
> > --- a/gcc/tree-core.h
> > +++ b/gcc/tree-core.h
> > @@ -1955,6 +1955,19 @@ enum function_decl_type
> >    /* 0 values left */
> >  };
> >
> > +/* Enumerate function multiversioning attributes.  This is used to record which
> > +   attribute enabled multiversioning on a function, and allows targets to
> > +   adjust their behaviour accordingly.  */
> > +
> > +enum function_version_source
> > +{
> > +  FUNCTION_VERSION_NONE = 0,
> > +  FUNCTION_VERSION_TARGET = 1,
> > +  FUNCTION_VERSION_TARGET_CLONES = 2,
> > +  FUNCTION_VERSION_TARGET_VERSION = 3
> > +};
> > +
> > +
> >  /* FUNCTION_DECL inherits from DECL_NON_COMMON because of the use of the
> >     arguments/result/saved_tree fields by front ends.   It was either inherit
> >     FUNCTION_DECL from non_common, or inherit non_common from FUNCTION_DECL,
> > @@ -2002,10 +2015,10 @@ struct GTY(()) tree_function_decl {
> >    /* Align the bitfield to boundary of a byte.  */
> >    ENUM_BITFIELD(function_decl_type) decl_type: 2;
> >    unsigned has_debug_args_flag : 1;
> > -  unsigned versioned_function : 1;
> > +  ENUM_BITFIELD(function_version_source) versioned_function : 2;
> >    unsigned replaceable_operator : 1;
> >
> > -  /* 11 bits left for future expansion.  */
> > +  /* 10 bits left for future expansion.  */
> >    /* 32 bits on 64-bit HW.  */
> >  };
> >

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH] aarch64: Fix function multiversioning mangling
  2024-01-16  8:21     ` Andrew Carlotti
@ 2024-01-16 10:42       ` Andrew Carlotti
  2024-01-25 16:49         ` Richard Sandiford
  0 siblings, 1 reply; 11+ messages in thread
From: Andrew Carlotti @ 2024-01-16 10:42 UTC (permalink / raw)
  To: gcc-patches; +Cc: Richard Biener, Richard Sandiford

It would be neater if the middle end for target_clones used a target
hook for version name mangling, so we only do version name mangling
once.  However, that would require more intrusive refactoring that will
have to wait till Stage 1.


This patch builds upon the testsuite additions in patch 1/5 of the
previous series. I could commit just the aarch64 tests for now if that's
preferred. Is this version of the fix ok for master?

gcc/ChangeLog:

	* config/aarch64/aarch64.cc
	(get_suffixed_assembler_name): New.
	(make_resolver_func): Use get_suffixed_assembler_name.
	(aarch64_mangle_decl_assembler_name): Add ".default" suffix.
	(aarch64_generate_version_dispatcher_body): Redo name mangling.

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.


diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
index 7d1f8c65ce41044d6850262300cf08a23d606617..bf698a2c3bb105375a2be37ca032397161bf4334 100644
--- a/gcc/config/aarch64/aarch64.cc
+++ b/gcc/config/aarch64/aarch64.cc
@@ -19832,6 +19832,21 @@ build_ifunc_arg_type ()
   return pointer_type;
 }
 
+/* Return an identifier for the base assembler name of a versioned function.
+   This is computed by taking the default version's assembler name, and
+   stripping off the ".default" suffix if it's already been appended.  */
+
+tree get_suffixed_assembler_name (tree default_decl, const char *suffix)
+{
+  std::string name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (default_decl));
+
+  auto size = name.size ();
+  if (size >= 8 && name.compare (size - 8, 8, ".default") == 0)
+    name.resize (size - 8);
+  name += suffix;
+  return get_identifier (name.c_str());
+}
+
 /* Make the resolver function decl to dispatch the versions of
    a multi-versioned function,  DEFAULT_DECL.  IFUNC_ALIAS_DECL is
    ifunc alias that will point to the created resolver.  Create an
@@ -19845,8 +19860,9 @@ 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");
+  /* Create resolver function name based on default_decl.  We need to remove an
+     existing ".default" suffix if this has already been appended.  */
+  tree decl_name = get_suffixed_assembler_name (default_decl, ".resolver");
   const char *resolver_name = IDENTIFIER_POINTER (decl_name);
 
   /* The resolver function should have signature
@@ -20137,6 +20153,8 @@ dispatch_function_versions (tree dispatch_decl,
   return 0;
 }
 
+tree aarch64_mangle_decl_assembler_name (tree, tree);
+
 /* Implement TARGET_GENERATE_VERSION_DISPATCHER_BODY.  */
 
 tree
@@ -20193,6 +20211,28 @@ aarch64_generate_version_dispatcher_body (void *node_p)
   dispatch_function_versions (resolver_decl, &fn_ver_vec, &empty_bb);
   cgraph_edge::rebuild_edges ();
   pop_cfun ();
+
+  /* Fix up symbol names.  First we need to obtain the base name, which may
+     have already been mangled.  */
+  tree base_name = get_suffixed_assembler_name (default_ver_decl, "");
+
+  /* We need to redo the version mangling on the non-default versions for the
+     target_clones case.  Redoing the mangling for the target_version case is
+     redundant but does no harm.  We need to skip the default version, because
+     expand_clones will append ".default" later; fortunately that suffix is the
+     one we want anyway.  */
+  for (versn_info = node_version_info->next->next; versn_info;
+       versn_info = versn_info->next)
+    {
+      tree version_decl = versn_info->this_node->decl;
+      tree name = aarch64_mangle_decl_assembler_name (version_decl,
+						      base_name);
+      symtab->change_decl_assembler_name (version_decl, name);
+    }
+
+  /* We also need to use the base name for the ifunc declaration.  */
+  symtab->change_decl_assembler_name (node->decl, base_name);
+
   return resolver_decl;
 }
 
@@ -20317,11 +20357,15 @@ aarch64_mangle_decl_assembler_name (tree decl, tree id)
     {
       aarch64_fmv_feature_mask feature_mask = get_feature_mask_for_version (decl);
 
-      /* No suffix for the default version.  */
+      std::string name = IDENTIFIER_POINTER (id);
+
+      /* For the default version, append ".default".  */
       if (feature_mask == 0ULL)
-	return id;
+	{
+	  name += ".default";
+	  return get_identifier (name.c_str());
+	}
 
-      std::string name = IDENTIFIER_POINTER (id);
       name += "._";
 
       for (int i = 0; i < FEAT_MAX; i++)
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 } } */

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 4/5] cp: Use get_mangled_id in more places in mangle_decl
  2024-01-15 11:28 ` [PATCH 4/5] cp: Use get_mangled_id in more places in mangle_decl Andrew Carlotti
@ 2024-01-16 20:24   ` Jason Merrill
  0 siblings, 0 replies; 11+ messages in thread
From: Jason Merrill @ 2024-01-16 20:24 UTC (permalink / raw)
  To: Andrew Carlotti, gcc-patches; +Cc: Richard Biener

On 1/15/24 06:28, Andrew Carlotti wrote:
> There's no functional change here, but it makes it clearer that all
> three locations should be doing the same thing (aside from changes to
> flag_abi_version).

OK.

> gcc/cp/ChangeLog:
> 
> 	* mangle.cc (mangle_decl): Consistently use get_mangled_id.
> 
> 
> diff --git a/gcc/cp/mangle.cc b/gcc/cp/mangle.cc
> index a04bc584586f28cb80d21b5c6d647416aa8843df..9bd684608b9e3378292cdb042184ba603b3d69aa 100644
> --- a/gcc/cp/mangle.cc
> +++ b/gcc/cp/mangle.cc
> @@ -4503,8 +4503,7 @@ mangle_decl (const tree decl)
>   	    return;
>   
>   	  flag_abi_version = flag_abi_compat_version;
> -	  id2 = mangle_decl_string (decl);
> -	  id2 = targetm.mangle_decl_assembler_name (decl, id2);
> +	  id2 = get_mangled_id (decl);
>   	  flag_abi_version = save_ver;
>   
>   	  if (id2 != id)
> @@ -4519,8 +4518,7 @@ mangle_decl (const tree decl)
>   	      || id2 == NULL_TREE)
>   	    {
>   	      flag_abi_version = warn_abi_version;
> -	      id2 = mangle_decl_string (decl);
> -	      id2 = targetm.mangle_decl_assembler_name (decl, id2);
> +	      id2 = get_mangled_id (decl);
>   	    }
>   	  flag_abi_version = save_ver;
>   
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH] aarch64: Fix function multiversioning mangling
  2024-01-16 10:42       ` [PATCH] aarch64: Fix function multiversioning mangling Andrew Carlotti
@ 2024-01-25 16:49         ` Richard Sandiford
  0 siblings, 0 replies; 11+ messages in thread
From: Richard Sandiford @ 2024-01-25 16:49 UTC (permalink / raw)
  To: Andrew Carlotti; +Cc: gcc-patches, Richard Biener

Andrew Carlotti <andrew.carlotti@arm.com> writes:
> It would be neater if the middle end for target_clones used a target
> hook for version name mangling, so we only do version name mangling
> once.  However, that would require more intrusive refactoring that will
> have to wait till Stage 1.
>
>
> This patch builds upon the testsuite additions in patch 1/5 of the
> previous series. I could commit just the aarch64 tests for now if that's
> preferred. Is this version of the fix ok for master?
>
> gcc/ChangeLog:
>
> 	* config/aarch64/aarch64.cc
> 	(get_suffixed_assembler_name): New.
> 	(make_resolver_func): Use get_suffixed_assembler_name.
> 	(aarch64_mangle_decl_assembler_name): Add ".default" suffix.
> 	(aarch64_generate_version_dispatcher_body): Redo name mangling.
>
> 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.

I found this a bit difficult to review (not your fault).  In the
abstract, it seems a bit dangerous to change the names of the clones
while emitting the dispatcher.  But I agree that it looks like it
should work in practice, and that it's probably the least invasive
fix for GCC 14.  The dispatcher is created by the same IPA pass
that creates the clones, so there should be little risk of the
old assembler name's being used before it's changed.  And
symbol_table::change_decl_assembler_name does have some code
to detect when a name is changed after use, in case things are
restructured later.

So this patch and the aarch64 parts of 1/5 are OK from my POV
with some trivial changes below.

> diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc
> index 7d1f8c65ce41044d6850262300cf08a23d606617..bf698a2c3bb105375a2be37ca032397161bf4334 100644
> --- a/gcc/config/aarch64/aarch64.cc
> +++ b/gcc/config/aarch64/aarch64.cc
> @@ -19832,6 +19832,21 @@ build_ifunc_arg_type ()
>    return pointer_type;
>  }
>  
> +/* Return an identifier for the base assembler name of a versioned function.
> +   This is computed by taking the default version's assembler name, and
> +   stripping off the ".default" suffix if it's already been appended.  */
> +
> +tree get_suffixed_assembler_name (tree default_decl, const char *suffix)

Probably best to make this static, given that it isn't in the aarch64_
"namespace".

Formatting nit, but: there should be a new line before the function name.

> +{
> +  std::string name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (default_decl));
> +
> +  auto size = name.size ();
> +  if (size >= 8 && name.compare (size - 8, 8, ".default") == 0)
> +    name.resize (size - 8);
> +  name += suffix;
> +  return get_identifier (name.c_str());
> +}
> +
>  /* Make the resolver function decl to dispatch the versions of
>     a multi-versioned function,  DEFAULT_DECL.  IFUNC_ALIAS_DECL is
>     ifunc alias that will point to the created resolver.  Create an
> @@ -19845,8 +19860,9 @@ 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");
> +  /* Create resolver function name based on default_decl.  We need to remove an
> +     existing ".default" suffix if this has already been appended.  */
> +  tree decl_name = get_suffixed_assembler_name (default_decl, ".resolver");
>    const char *resolver_name = IDENTIFIER_POINTER (decl_name);
>  
>    /* The resolver function should have signature
> @@ -20137,6 +20153,8 @@ dispatch_function_versions (tree dispatch_decl,
>    return 0;
>  }
>  
> +tree aarch64_mangle_decl_assembler_name (tree, tree);
> +

Please reorder the functions instead of adding the forward declaration.
It'll create a bit of git churn, but that's OK.

>  /* Implement TARGET_GENERATE_VERSION_DISPATCHER_BODY.  */
>  
>  tree
> @@ -20193,6 +20211,28 @@ aarch64_generate_version_dispatcher_body (void *node_p)
>    dispatch_function_versions (resolver_decl, &fn_ver_vec, &empty_bb);
>    cgraph_edge::rebuild_edges ();
>    pop_cfun ();
> +
> +  /* Fix up symbol names.  First we need to obtain the base name, which may
> +     have already been mangled.  */
> +  tree base_name = get_suffixed_assembler_name (default_ver_decl, "");
> +
> +  /* We need to redo the version mangling on the non-default versions for the
> +     target_clones case.  Redoing the mangling for the target_version case is
> +     redundant but does no harm.  We need to skip the default version, because
> +     expand_clones will append ".default" later; fortunately that suffix is the
> +     one we want anyway.  */
> +  for (versn_info = node_version_info->next->next; versn_info;
> +       versn_info = versn_info->next)
> +    {
> +      tree version_decl = versn_info->this_node->decl;
> +      tree name = aarch64_mangle_decl_assembler_name (version_decl,
> +						      base_name);
> +      symtab->change_decl_assembler_name (version_decl, name);
> +    }
> +
> +  /* We also need to use the base name for the ifunc declaration.  */
> +  symtab->change_decl_assembler_name (node->decl, base_name);
> +
>    return resolver_decl;
>  }
>  
> @@ -20317,11 +20357,15 @@ aarch64_mangle_decl_assembler_name (tree decl, tree id)
>      {
>        aarch64_fmv_feature_mask feature_mask = get_feature_mask_for_version (decl);
>  
> -      /* No suffix for the default version.  */
> +      std::string name = IDENTIFIER_POINTER (id);
> +
> +      /* For the default version, append ".default".  */
>        if (feature_mask == 0ULL)
> -	return id;
> +	{
> +	  name += ".default";
> +	  return get_identifier (name.c_str());
> +	}
>  
> -      std::string name = IDENTIFIER_POINTER (id);
>        name += "._";
>  
>        for (int i = 0; i < FEAT_MAX; i++)
> 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 } } */

I was wondering whether it would also be worth having
scan-assembler-nots such as:

/* { dg-final { scan-assembler-not "\n_Z3foov:\n" } } */

to make extra sure that we don't emit the cloned function as an
ordinary symbol.  But it's your call -- the %gnu_indirect_function
test is probably enough.  The patch is OK either way.

Thanks,
Richard

>  /* { 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 } } */

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2024-01-25 16:49 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2024-01-15 11:26 [PATCH 0/5] Fix fmv mangling for AArch64 Andrew Carlotti
2024-01-15 11:26 ` [PATCH 1/5] testsuite: Add tests for fmv symbol presence and mangling Andrew Carlotti
2024-01-15 11:27 ` [PATCH 2/5] tree: Extend DECL_FUNCTION_VERSIONED to an enum Andrew Carlotti
2024-01-15 12:28   ` Richard Biener
2024-01-16  8:21     ` Andrew Carlotti
2024-01-16 10:42       ` [PATCH] aarch64: Fix function multiversioning mangling Andrew Carlotti
2024-01-25 16:49         ` Richard Sandiford
2024-01-15 11:27 ` [PATCH 3/5] Change create_version_clone_with_body parameter name Andrew Carlotti
2024-01-15 11:28 ` [PATCH 4/5] cp: Use get_mangled_id in more places in mangle_decl Andrew Carlotti
2024-01-16 20:24   ` Jason Merrill
2024-01-15 11:28 ` [PATCH 5/5] Add target hook for function version name mangling Andrew Carlotti

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).