Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2226691/?format=api
{ "id": 2226691, "url": "http://patchwork.ozlabs.org/api/patches/2226691/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/bmm.hhuodmon6a.gcc.gcc-TEST.alfie.richards.49.1.11@forge-stage.sourceware.org/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<bmm.hhuodmon6a.gcc.gcc-TEST.alfie.richards.49.1.11@forge-stage.sourceware.org>", "list_archive_url": null, "date": "2026-04-22T18:21:59", "name": "[v1,11/13] c: Add target_version attribute support.", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "73446de189ace03dbf80f18aa27a23e84552a786", "submitter": { "id": 93228, "url": "http://patchwork.ozlabs.org/api/people/93228/?format=api", "name": "\\\"alfie.richards via Sourceware Forge\\\"", "email": "forge-bot+alfie.richards@forge-stage.sourceware.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/bmm.hhuodmon6a.gcc.gcc-TEST.alfie.richards.49.1.11@forge-stage.sourceware.org/mbox/", "series": [ { "id": 501072, "url": "http://patchwork.ozlabs.org/api/series/501072/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=501072", "date": "2026-04-22T18:21:54", "name": "FMV refactor and ACLE compliance for C++", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/501072/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2226691/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2226691/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Delivered-To": [ "patchwork-incoming@legolas.ozlabs.org", "gcc-patches@gcc.gnu.org" ], "Authentication-Results": [ "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)", "sourceware.org; dmarc=none (p=none dis=none)\n header.from=forge-stage.sourceware.org", "sourceware.org;\n spf=pass smtp.mailfrom=forge-stage.sourceware.org", "server2.sourceware.org;\n arc=none smtp.remote-ip=38.145.34.39" ], "Received": [ "from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4g17B41Mx1z1yD5\n\tfor <incoming@patchwork.ozlabs.org>; Thu, 23 Apr 2026 04:32:28 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 573BE4C31825\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 22 Apr 2026 18:32:26 +0000 (GMT)", "from forge-stage.sourceware.org (vm08.sourceware.org [38.145.34.39])\n by sourceware.org (Postfix) with ESMTPS id 68CA04422A92\n for <gcc-patches@gcc.gnu.org>; Wed, 22 Apr 2026 18:23:34 +0000 (GMT)", "from forge-stage.sourceware.org (localhost [IPv6:::1])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256)\n (No client certificate requested)\n by forge-stage.sourceware.org (Postfix) with ESMTPS id BB7594345E\n for <gcc-patches@gcc.gnu.org>; Wed, 22 Apr 2026 18:23:30 +0000 (UTC)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 573BE4C31825", "OpenDKIM Filter v2.11.0 sourceware.org 68CA04422A92" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 68CA04422A92", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 68CA04422A92", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776882214; cv=none;\n b=GHpxKr0N4jFCYOVeK5mQvZwllf5GD9HD9dGfomHkydDEVrYJ8Vo9VLXJnkdyQGgk0qjg2YAn68tD//ruEguLBGEdijBr6zAf3c6k26PT0GINfOxmudOooOsHeNeibG9b+idkCpjy3zn/5MkR3uJ7XyOH7PqWop/0xcCGv1TQ9D4=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776882214; c=relaxed/simple;\n bh=GjFkGc4RPly+cBi7Zcv9FkEI10Lm7Xbc4NLXZqwQrXA=;\n h=From:Date:Subject:To:Message-ID;\n b=Ooo3yey776PSthNXi0q+mddkOjzIbW5i19wZdeRwKCqBs3r7wGZOaN6RKhXcDZ/HUT3U/Tsuf9lmtwBdFVHwMOChMnJ47eUDrzo9YMUo4JPbWfp0LJhoWXKRRR8sOYZL0YSQoil5Us6Vudd4dgmnXdSSllrHc6fqmtepen592C4=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "From": "\"\\\"alfie.richards via Sourceware Forge\\\"\"\n <forge-bot+alfie.richards@forge-stage.sourceware.org>", "Date": "Wed, 22 Apr 2026 18:21:59 +0000", "Subject": "[PATCH v1 11/13] c: Add target_version attribute support.", "To": "gcc-patches mailing list <gcc-patches@gcc.gnu.org>", "Message-ID": "\n <bmm.hhuodmon6a.gcc.gcc-TEST.alfie.richards.49.1.11@forge-stage.sourceware.org>", "X-Mailer": "batrachomyomachia", "X-Requested-Reviewer": [ "rsandifo", "rearnsha" ], "X-Pull-Request-Organization": "gcc", "X-Pull-Request-Repository": "gcc-TEST", "X-Pull-Request": "https://forge.sourceware.org/gcc/gcc-TEST/pulls/49", "References": "\n <bmm.hhuodmon6a.gcc.gcc-TEST.alfie.richards.49.1.0@forge-stage.sourceware.org>", "In-Reply-To": "\n <bmm.hhuodmon6a.gcc.gcc-TEST.alfie.richards.49.1.0@forge-stage.sourceware.org>", "X-Patch-URL": "\n https://forge.sourceware.org/alfie.richards/gcc-TEST/commit/d21158abe9bb538b2ca07e5629251c683a37f81c", "X-BeenThere": "gcc-patches@gcc.gnu.org", "X-Mailman-Version": "2.1.30", "Precedence": "list", "List-Id": "Gcc-patches mailing list <gcc-patches.gcc.gnu.org>", "List-Unsubscribe": "<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>", "List-Archive": "<https://gcc.gnu.org/pipermail/gcc-patches/>", "List-Post": "<mailto:gcc-patches@gcc.gnu.org>", "List-Help": "<mailto:gcc-patches-request@gcc.gnu.org?subject=help>", "List-Subscribe": "<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>", "Reply-To": "gcc-patches mailing list <gcc-patches@gcc.gnu.org>,\n alfierichards@sourceware.org", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "From: Alfie Richards <alfie.richards@arm.com>\n\nThis commit introduces support for the target_version attribute in the c\nfrontend, following the behavior defined in the Arm C Language Extension.\n\nKey changes include:\n\n- During pushdecl, the compiler now checks whether the current symbol is\n part of a multiversioned set.\n - New versions are added to the function multiversioning (FMV) set, and the\n symbol binding is updated to include the default version (if present).\n This means the binding for a multiversioned symbol will always reference\n the default version (if present), as it defines the scope and signature\n for the entire set.\n - Pre-existing versions are merged with their previous version (or diagnosed).\n- Lookup logic is adjusted to prevent resolving non-default versions.\n- start_decl and start_function are updated to handle marking and mangling of\n versioned functions.\n- c_parse_final_cleanups now includes a call to process_same_body_aliases.\n This has no functional impact other than setting cpp_implicit_aliases_done\n on all nodes, which is necessary for certain shared FMV logic.\n\ngcc/c/ChangeLog:\n\n\t* c-decl.cc (maybe_mark_function_versioned): New function.\n\t(merge_decls): Preserve DECL_FUNCTION_VERSIONED in merging.\n\t(duplicate_decls): Add check and diagnostic for unmergable version decls.\n\t(pushdecl): Add FMV target_version logic.\n\t(lookup_name): Don't resolve non-default versions.\n\t(start_decl): Mark and mangle versioned functions.\n\t(start_function): Mark and mangle versioned functions.\n\t(c_parse_final_cleanups): Add call to process_same_body_aliases.\n\ngcc/testsuite/ChangeLog:\n\n\t* gcc.target/aarch64/mv-1.c: New test.\n\t* gcc.target/aarch64/mv-and-mvc1.c: New test.\n\t* gcc.target/aarch64/mv-and-mvc2.c: New test.\n\t* gcc.target/aarch64/mv-and-mvc3.c: New test.\n\t* gcc.target/aarch64/mv-and-mvc4.c: New test.\n\t* gcc.target/aarch64/mv-symbols1.c: New test.\n\t* gcc.target/aarch64/mv-symbols10.c: New test.\n\t* gcc.target/aarch64/mv-symbols11.c: New test.\n\t* gcc.target/aarch64/mv-symbols12.c: New test.\n\t* gcc.target/aarch64/mv-symbols13.c: New test.\n\t* gcc.target/aarch64/mv-symbols14.c: New test.\n\t* gcc.target/aarch64/mv-symbols2.c: New test.\n\t* gcc.target/aarch64/mv-symbols3.c: New test.\n\t* gcc.target/aarch64/mv-symbols4.c: New test.\n\t* gcc.target/aarch64/mv-symbols5.c: New test.\n\t* gcc.target/aarch64/mv-symbols6.c: New test.\n\t* gcc.target/aarch64/mv-symbols7.c: New test.\n\t* gcc.target/aarch64/mv-symbols8.c: New test.\n\t* gcc.target/aarch64/mv-symbols9.c: New test.\n\t* gcc.target/aarch64/mvc-symbols1.c: New test.\n\t* gcc.target/aarch64/mvc-symbols2.c: New test.\n\t* gcc.target/aarch64/mvc-symbols3.c: New test.\n\t* gcc.target/aarch64/mvc-symbols4.c: New test.\n---\n gcc/c/c-decl.cc | 115 ++++++++++++++++++\n gcc/testsuite/gcc.target/aarch64/mv-1.c | 43 +++++++\n .../gcc.target/aarch64/mv-and-mvc1.c | 37 ++++++\n .../gcc.target/aarch64/mv-and-mvc2.c | 28 +++++\n .../gcc.target/aarch64/mv-and-mvc3.c | 40 ++++++\n .../gcc.target/aarch64/mv-and-mvc4.c | 37 ++++++\n .../gcc.target/aarch64/mv-symbols1.c | 38 ++++++\n .../gcc.target/aarch64/mv-symbols10.c | 42 +++++++\n .../gcc.target/aarch64/mv-symbols11.c | 16 +++\n .../gcc.target/aarch64/mv-symbols12.c | 27 ++++\n .../gcc.target/aarch64/mv-symbols13.c | 28 +++++\n .../gcc.target/aarch64/mv-symbols14.c | 34 ++++++\n .../gcc.target/aarch64/mv-symbols2.c | 28 +++++\n .../gcc.target/aarch64/mv-symbols3.c | 27 ++++\n .../gcc.target/aarch64/mv-symbols4.c | 31 +++++\n .../gcc.target/aarch64/mv-symbols5.c | 36 ++++++\n .../gcc.target/aarch64/mv-symbols6.c | 20 +++\n .../gcc.target/aarch64/mv-symbols7.c | 47 +++++++\n .../gcc.target/aarch64/mv-symbols8.c | 47 +++++++\n .../gcc.target/aarch64/mv-symbols9.c | 44 +++++++\n .../gcc.target/aarch64/mvc-symbols1.c | 25 ++++\n .../gcc.target/aarch64/mvc-symbols2.c | 15 +++\n .../gcc.target/aarch64/mvc-symbols3.c | 19 +++\n .../gcc.target/aarch64/mvc-symbols4.c | 12 ++\n 24 files changed, 836 insertions(+)\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-1.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-and-mvc1.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-and-mvc2.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-and-mvc3.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-and-mvc4.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-symbols1.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-symbols10.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-symbols11.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-symbols12.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-symbols13.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-symbols14.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-symbols2.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-symbols3.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-symbols4.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-symbols5.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-symbols6.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-symbols7.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-symbols8.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mv-symbols9.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mvc-symbols1.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mvc-symbols2.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mvc-symbols3.c\n create mode 100644 gcc/testsuite/gcc.target/aarch64/mvc-symbols4.c", "diff": "diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc\nindex 8e8bac6c32b9..b1b586253b82 100644\n--- a/gcc/c/c-decl.cc\n+++ b/gcc/c/c-decl.cc\n@@ -2088,6 +2088,29 @@ previous_tag (tree type)\n return NULL_TREE;\n }\n \n+/* Subroutine to mark functions as versioned when using the attribute\n+ 'target_version'. */\n+\n+static void\n+maybe_mark_function_versioned (tree decl)\n+{\n+ if (!DECL_FUNCTION_VERSIONED (decl))\n+ {\n+ /* We need to insert function version now to make sure the correct\n+\t pre-mangled assembler name is recorded. */\n+ cgraph_node *node = cgraph_node::get_create (decl);\n+\n+ if (!node->function_version ())\n+\tnode->insert_new_function_version ();\n+\n+ DECL_FUNCTION_VERSIONED (decl) = 1;\n+\n+ tree mangled_name\n+\t= targetm.mangle_decl_assembler_name (decl, DECL_NAME (decl));\n+ SET_DECL_ASSEMBLER_NAME (decl, mangled_name);\n+ }\n+ }\n+\n /* Subroutine of duplicate_decls. Compare NEWDECL to OLDDECL.\n Returns true if the caller should proceed to merge the two, false\n if OLDDECL should simply be discarded. As a side effect, issues\n@@ -2507,6 +2530,10 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,\n \t\t\t\"but not here\");\n \t }\n \t}\n+ /* Check if these are unmergable overlapping FMV declarations. */\n+ if (!TARGET_HAS_FMV_TARGET_ATTRIBUTE\n+\t && !diagnose_versioned_decls (olddecl, newdecl))\n+\treturn false;\n }\n else if (VAR_P (newdecl))\n {\n@@ -2974,6 +3001,12 @@ merge_decls (tree newdecl, tree olddecl, tree newtype, tree oldtype)\n \n if (TREE_CODE (newdecl) == FUNCTION_DECL)\n {\n+ if (DECL_FUNCTION_VERSIONED (olddecl)\n+\t || DECL_FUNCTION_VERSIONED (newdecl))\n+\t{\n+\t maybe_mark_function_versioned (olddecl);\n+\t maybe_mark_function_versioned (newdecl);\n+\t}\n /* If we're redefining a function previously defined as extern\n \t inline, make sure we emit debug info for the inline before we\n \t throw it away, in case it was inlined into a function that\n@@ -3373,6 +3406,56 @@ pushdecl (tree x)\n \t\tTREE_TYPE (b_use->decl) = b_use->u.type;\n \t }\n \t}\n+\n+ /* Check if x is part of a FMV set with b_use. */\n+ if (b_use && TREE_CODE (b_use->decl) == FUNCTION_DECL\n+\t && TREE_CODE (x) == FUNCTION_DECL && DECL_FILE_SCOPE_P (b_use->decl)\n+\t && DECL_FILE_SCOPE_P (x)\n+\t && distinct_version_decls (x, b_use->decl)\n+\t && comptypes (vistype, type) != 0)\n+\t{\n+\t if (current_scope->depth != b->depth)\n+\t error (\"FMV versions must all be declared at the same scope level\");\n+\n+\t maybe_mark_function_versioned (b_use->decl);\n+\t maybe_mark_function_versioned (b->decl);\n+\t maybe_mark_function_versioned (x);\n+\n+\t cgraph_node *b_node = cgraph_node::get_create (b_use->decl);\n+\t cgraph_function_version_info *b_v = b_node->function_version ();\n+\t if (!b_v)\n+\t b_v = b_node->insert_new_function_version ();\n+\n+\t /* Check if this new node conflicts with any previous functions\n+\t in the set. */\n+\t cgraph_function_version_info *version = b_v;\n+\t for (; version; version = version->next)\n+\t if (!distinct_version_decls (version->this_node->decl, x))\n+\t {\n+\t\t/* The decls define overlapping version, so attempt to merge\n+\t\t or diagnose the conflict. */\n+\t\tif (duplicate_decls (x, version->this_node->decl))\n+\t\t return version->this_node->decl;\n+\t\telse\n+\t\t return error_mark_node;\n+\t }\n+\n+\t /* This is a new version to be added to FMV structure. */\n+\t cgraph_node::add_function_version (b_v, x);\n+\n+\t /* Get the first node from the structure. */\n+\t cgraph_function_version_info *default_v = b_v;\n+\t while (default_v->prev)\n+\t default_v = default_v->prev;\n+\t /* Always use the default node for the bindings. */\n+\t b_use->decl = default_v->this_node->decl;\n+\t b->decl = default_v->this_node->decl;\n+\n+\t /* Node is not a duplicate, so no need to do the rest of the\n+\t checks. */\n+\t return x;\n+\t}\n+\n if (duplicate_decls (x, b_use->decl))\n \t{\n \t if (b_use != b)\n@@ -4497,6 +4580,12 @@ tree\n lookup_name (tree name)\n {\n struct c_binding *b = I_SYMBOL_BINDING (name);\n+ /* Do not resolve non-default function versions. */\n+ if (b\n+ && TREE_CODE (b->decl) == FUNCTION_DECL\n+ && DECL_FUNCTION_VERSIONED (b->decl)\n+ && !is_function_default_version (b->decl))\n+ return NULL_TREE;\n if (b && !b->invisible)\n {\n maybe_record_typedef_use (b->decl);\n@@ -5771,6 +5860,17 @@ start_decl (struct c_declarator *declarator, struct c_declspecs *declspecs,\n && VAR_OR_FUNCTION_DECL_P (decl))\n objc_check_global_decl (decl);\n \n+ /* To enable versions to be created across TU's we mark and mangle all\n+ non-default versioned functions. */\n+ if (TREE_CODE (decl) == FUNCTION_DECL\n+ && !TARGET_HAS_FMV_TARGET_ATTRIBUTE\n+ && get_target_version (decl).is_valid ())\n+ {\n+ maybe_mark_function_versioned (decl);\n+ if (current_scope != file_scope)\n+\terror (\"versioned declarations are only allowed at file scope\");\n+ }\n+\n /* Add this decl to the current scope.\n TEM may equal DECL or it may be a previous decl of the same name. */\n if (do_push)\n@@ -10732,6 +10832,17 @@ start_function (struct c_declspecs *declspecs, struct c_declarator *declarator,\n warn_parm_array_mismatch (origloc, old_decl, parms);\n }\n \n+ /* To enable versions to be created across TU's we mark and mangle all\n+ non-default versioned functions. */\n+ if (TREE_CODE (decl1) == FUNCTION_DECL\n+ && !TARGET_HAS_FMV_TARGET_ATTRIBUTE\n+ && get_target_version (decl1).is_valid ())\n+ {\n+ maybe_mark_function_versioned (decl1);\n+ if (current_scope != file_scope)\n+\terror (\"versioned definitions are only allowed at file scope\");\n+ }\n+\n /* Record the decl so that the function name is defined.\n If we already have a decl for this name, and it is a FUNCTION_DECL,\n use the old decl. */\n@@ -13578,6 +13689,10 @@ c_parse_final_cleanups (void)\n c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t)));\n c_write_global_declarations_1 (BLOCK_VARS (ext_block));\n \n+ /* Call this to set cpp_implicit_aliases_done on all nodes. This is\n+ important for function multiversioning aliases to get resolved. */\n+ symtab->process_same_body_aliases ();\n+\n if (!in_lto_p)\n free_attr_access_data ();\n \ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-1.c b/gcc/testsuite/gcc.target/aarch64/mv-1.c\nnew file mode 100644\nindex 000000000000..6f095ecd7a73\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-1.c\n@@ -0,0 +1,43 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__ ((target_version (\"default\"))) int\n+foo ()\n+{\n+ return 1;\n+}\n+\n+__attribute__ ((target_version (\"rng\"))) int\n+foo ()\n+{\n+ return 2;\n+}\n+\n+__attribute__ ((target_version (\"flagm\"))) int\n+foo ()\n+{\n+ return 3;\n+}\n+\n+__attribute__ ((target_version (\"rng+flagm\"))) int\n+foo ()\n+{\n+ return 4;\n+}\n+\n+int\n+bar ()\n+{\n+ return foo ();\n+}\n+\n+/* Check usage of the first two FMV features, in case of off-by-one errors. */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mrng:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MrngMflagm:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mflagm:\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-and-mvc1.c b/gcc/testsuite/gcc.target/aarch64/mv-and-mvc1.c\nnew file mode 100644\nindex 000000000000..39ed306eec25\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-and-mvc1.c\n@@ -0,0 +1,37 @@\n+/* { dg-do compile } */\n+/* { dg-require-ifunc \"\" } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__((target_version(\"default\")))\n+int foo ()\n+{\n+ return 0;\n+}\n+\n+__attribute__((target_clones(\"dotprod\", \"sve+sve2\")))\n+int foo ()\n+{\n+ return 1;\n+}\n+\n+__attribute__((target_clones(\"sve\", \"sve2\")))\n+int foo ()\n+{\n+ return 2;\n+}\n+\n+int bar()\n+{\n+ return foo ();\n+}\n+\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Msve:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Msve2:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-and-mvc2.c b/gcc/testsuite/gcc.target/aarch64/mv-and-mvc2.c\nnew file mode 100644\nindex 000000000000..17c7cbdd02da\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-and-mvc2.c\n@@ -0,0 +1,28 @@\n+/* { dg-do compile } */\n+/* { dg-require-ifunc \"\" } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__((target_version(\"default\")))\n+int foo ();\n+\n+__attribute__((target_clones(\"dotprod\", \"sve+sve2\")))\n+int foo ()\n+{\n+ return 1;\n+}\n+\n+__attribute__((target_clones(\"sve\", \"sve2\")))\n+int foo ()\n+{\n+ return 2;\n+}\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Msve:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Msve2:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 0 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-and-mvc3.c b/gcc/testsuite/gcc.target/aarch64/mv-and-mvc3.c\nnew file mode 100644\nindex 000000000000..8325c8e06999\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-and-mvc3.c\n@@ -0,0 +1,40 @@\n+/* { dg-do compile } */\n+/* { dg-require-ifunc \"\" } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__((target_clones(\"dotprod\", \"sve+sve2\")))\n+int foo ();\n+\n+__attribute__((target_version(\"default\")))\n+int foo ()\n+{\n+ return 0;\n+}\n+\n+__attribute__((target_clones(\"sve\", \"sve2\")))\n+int foo ()\n+{\n+ return 2;\n+}\n+\n+int bar()\n+{\n+ return foo ();\n+}\n+\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Msve:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Msve2:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\n+// { dg-final { scan-assembler-times \"\\n\\tadrp\\tx\\[0-9\\]+, foo\\.default\\n\" 1 } }\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx\\[0-9\\]+, foo\\._Mdotprod\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx\\[0-9\\]+, foo\\._MsveMsve2\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx\\[0-9\\]+, foo\\._Msve\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx\\[0-9\\]+, foo\\._Msve2\\n\" 1 } } */\n+\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-and-mvc4.c b/gcc/testsuite/gcc.target/aarch64/mv-and-mvc4.c\nnew file mode 100644\nindex 000000000000..951c9500d747\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-and-mvc4.c\n@@ -0,0 +1,37 @@\n+/* { dg-do compile } */\n+/* { dg-require-ifunc \"\" } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__((target_version(\"dotprod\")))\n+int foo ()\n+{\n+ return 0;\n+}\n+\n+__attribute__((target_clones(\"default\", \"sve+sve2\")))\n+int foo ()\n+{\n+ return 1;\n+}\n+\n+__attribute__((target_clones(\"sve\", \"sve2\")))\n+int foo ()\n+{\n+ return 2;\n+}\n+\n+int bar()\n+{\n+ return foo ();\n+}\n+\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Msve:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Msve2:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-symbols1.c b/gcc/testsuite/gcc.target/aarch64/mv-symbols1.c\nnew file mode 100644\nindex 000000000000..798227826e50\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-symbols1.c\n@@ -0,0 +1,38 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+// Basic case of fmv correctness with all functions and use in one TU.\n+\n+__attribute__ ((target_version (\"default\"))) int\n+foo ()\n+{\n+ return 1;\n+}\n+\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo ()\n+{\n+ return 3;\n+}\n+__attribute__ ((target_version (\"sve+sve2\"))) int\n+foo ()\n+{\n+ return 5;\n+}\n+\n+int\n+bar ()\n+{\n+ return foo ();\n+}\n+\n+/* When updating any of the symbol names in these tests, make sure to also\n+ update any tests for their absence in mv-symbolsN.C */\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-symbols10.c b/gcc/testsuite/gcc.target/aarch64/mv-symbols10.c\nnew file mode 100644\nindex 000000000000..d5256389d7bb\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-symbols10.c\n@@ -0,0 +1,42 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+int\n+foo ();\n+\n+int\n+foo ()\n+{\n+ return 1;\n+}\n+\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo ()\n+{\n+ return 3;\n+}\n+__attribute__ ((target_version (\"sve+sve2\"))) int\n+foo ()\n+{\n+ return 5;\n+}\n+\n+int\n+bar ()\n+{\n+ return foo ();\n+}\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx., foo\\._MsveMsve2\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx., foo\\._Mdotprod\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx., foo\\.default\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-symbols11.c b/gcc/testsuite/gcc.target/aarch64/mv-symbols11.c\nnew file mode 100644\nindex 000000000000..fd3dc345a599\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-symbols11.c\n@@ -0,0 +1,16 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+// Check that types can be combined\n+\n+__attribute__ ((target_version (\"default\"))) int\n+foo (int a, int (*b)[4]) { return 1; }\n+\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo (int a, int (*b)[]) { return 3; }\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-symbols12.c b/gcc/testsuite/gcc.target/aarch64/mv-symbols12.c\nnew file mode 100644\nindex 000000000000..1a0b667eb5f1\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-symbols12.c\n@@ -0,0 +1,27 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__ ((target_version (\"default\"))) int\n+foo () { return 1; }\n+\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo () { return 3; }\n+\n+int bar ()\n+{\n+ int (*test)() = foo;\n+\n+ test();\n+}\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx\\[0-9\\], foo\\._Mdotprod\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx\\[0-9\\], foo\\.default\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx\\[0-9\\]+, foo\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-symbols13.c b/gcc/testsuite/gcc.target/aarch64/mv-symbols13.c\nnew file mode 100644\nindex 000000000000..308dace64a78\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-symbols13.c\n@@ -0,0 +1,28 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__ ((target_version (\"default\"))) int\n+foo ();\n+\n+int bar ()\n+{\n+ int (*test)() = foo;\n+\n+ test();\n+}\n+\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo () { return 3; }\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx\\[0-9\\], foo\\._Mdotprod\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx\\[0-9\\], foo\\.default\\n\" 0 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx\\[0-9\\]+, foo\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 0 } } */\n+\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-symbols14.c b/gcc/testsuite/gcc.target/aarch64/mv-symbols14.c\nnew file mode 100644\nindex 000000000000..d1af69fe31d9\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-symbols14.c\n@@ -0,0 +1,34 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+int foo ();\n+\n+__attribute__ ((target_version (\"default\"))) int\n+foo ()\n+{\n+ return 1;\n+}\n+\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo ()\n+{\n+ return 3;\n+}\n+\n+int\n+bar ()\n+{\n+ return foo ();\n+}\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx., foo\\._Mdotprod\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx., foo\\.default\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-symbols2.c b/gcc/testsuite/gcc.target/aarch64/mv-symbols2.c\nnew file mode 100644\nindex 000000000000..a8732caf2140\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-symbols2.c\n@@ -0,0 +1,28 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+// FMV correctness with definitions but no call\n+\n+__attribute__ ((target_version (\"default\"))) int\n+foo ()\n+{\n+ return 1;\n+}\n+\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo ()\n+{\n+ return 3;\n+}\n+__attribute__ ((target_version (\"sve+sve2\"))) int\n+foo ()\n+{\n+ return 5;\n+}\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-symbols3.c b/gcc/testsuite/gcc.target/aarch64/mv-symbols3.c\nnew file mode 100644\nindex 000000000000..962bae935773\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-symbols3.c\n@@ -0,0 +1,27 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+// FMV correctness with declarations but no implementation\n+\n+__attribute__ ((target_version (\"default\"))) int\n+foo ();\n+\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo ();\n+\n+__attribute__ ((target_version (\"sve+sve2\"))) int\n+foo ();\n+\n+int\n+bar ()\n+{\n+ return foo ();\n+}\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 0 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-symbols4.c b/gcc/testsuite/gcc.target/aarch64/mv-symbols4.c\nnew file mode 100644\nindex 000000000000..a476800b2c53\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-symbols4.c\n@@ -0,0 +1,31 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+// FMV correctness with a default implementation and declarations of other\n+// versions\n+\n+__attribute__ ((target_version (\"default\"))) int\n+foo ()\n+{\n+ return 1;\n+}\n+\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo ();\n+\n+__attribute__ ((target_version (\"sve+sve2\"))) int\n+foo ();\n+\n+int\n+bar ()\n+{\n+ return foo ();\n+}\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-symbols5.c b/gcc/testsuite/gcc.target/aarch64/mv-symbols5.c\nnew file mode 100644\nindex 000000000000..4df20009f795\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-symbols5.c\n@@ -0,0 +1,36 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+// FMV correctness with default declaration, and implementations of other\n+// versions.\n+\n+__attribute__ ((target_version (\"default\"))) int\n+foo ();\n+\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo ()\n+{\n+ return 3;\n+}\n+__attribute__ ((target_version (\"sve+sve2\"))) int\n+foo ()\n+{\n+ return 5;\n+}\n+\n+int\n+bar ()\n+{\n+ return foo ();\n+}\n+\n+/* When updating any of the symbol names in these tests, make sure to also\n+ update any tests for their absence in mvc-symbolsN.C */\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 0 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-symbols6.c b/gcc/testsuite/gcc.target/aarch64/mv-symbols6.c\nnew file mode 100644\nindex 000000000000..cbf8bcaf8e16\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-symbols6.c\n@@ -0,0 +1,20 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__ ((target_version (\"default\"))) int\n+foo ()\n+{\n+ return 1;\n+}\n+\n+int bar()\n+{\n+ return foo();\n+}\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"bl\\tfoo.default\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \".global\\tfoo\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \".set\\tfoo,foo.default\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-symbols7.c b/gcc/testsuite/gcc.target/aarch64/mv-symbols7.c\nnew file mode 100644\nindex 000000000000..2ea4d2ebf0fb\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-symbols7.c\n@@ -0,0 +1,47 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo ();\n+\n+__attribute__ ((target_version (\"sve+sve2\"))) int\n+foo ();\n+\n+__attribute__ ((target_version (\"default\"))) int\n+foo ();\n+\n+int\n+bar ()\n+{\n+ return foo ();\n+}\n+\n+__attribute__ ((target_version (\"sve+sve2\"))) int\n+foo ()\n+{\n+ return 5;\n+}\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo ()\n+{\n+ return 3;\n+}\n+__attribute__ ((target_version (\"default\"))) int\n+foo ()\n+{\n+ return 1;\n+}\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx., foo\\._MsveMsve2\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx., foo\\._Mdotprod\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx., foo\\.default\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-symbols8.c b/gcc/testsuite/gcc.target/aarch64/mv-symbols8.c\nnew file mode 100644\nindex 000000000000..3e3eaf21aa9e\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-symbols8.c\n@@ -0,0 +1,47 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo ();\n+\n+__attribute__ ((target_version (\"sve+sve2\"))) int\n+foo ();\n+\n+__attribute__ ((target_version (\"default\"))) int\n+foo ();\n+\n+__attribute__ ((target_version (\"sve+sve2\"))) int\n+foo ()\n+{\n+ return 5;\n+}\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo ()\n+{\n+ return 3;\n+}\n+__attribute__ ((target_version (\"default\"))) int\n+foo ()\n+{\n+ return 1;\n+}\n+\n+int\n+bar ()\n+{\n+ return foo ();\n+}\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx., foo\\._MsveMsve2\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx., foo\\._Mdotprod\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx., foo\\.default\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mv-symbols9.c b/gcc/testsuite/gcc.target/aarch64/mv-symbols9.c\nnew file mode 100644\nindex 000000000000..8e0864f1663f\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mv-symbols9.c\n@@ -0,0 +1,44 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo ();\n+__attribute__ ((target_version (\"sve+sve2\"))) int\n+foo ();\n+\n+int\n+foo ()\n+{\n+ return 1;\n+}\n+\n+__attribute__ ((target_version (\"dotprod\"))) int\n+foo ()\n+{\n+ return 3;\n+}\n+__attribute__ ((target_version (\"sve+sve2\"))) int\n+foo ()\n+{\n+ return 5;\n+}\n+\n+int\n+bar ()\n+{\n+ return foo ();\n+}\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx., foo\\._MsveMsve2\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx., foo\\._Mdotprod\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tadrp\\tx., foo\\.default\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mvc-symbols1.c b/gcc/testsuite/gcc.target/aarch64/mvc-symbols1.c\nnew file mode 100644\nindex 000000000000..3ad15e5bb73d\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mvc-symbols1.c\n@@ -0,0 +1,25 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__ ((target_clones (\"default\", \"dotprod\", \"sve+sve2\"))) int\n+foo ()\n+{\n+ return 1;\n+}\n+\n+int\n+bar ()\n+{\n+ return foo ();\n+}\n+\n+/* When updating any of the symbol names in these tests, make sure to also\n+ update any tests for their absence in mvc-symbolsN.C */\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mvc-symbols2.c b/gcc/testsuite/gcc.target/aarch64/mvc-symbols2.c\nnew file mode 100644\nindex 000000000000..78385ed904bb\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mvc-symbols2.c\n@@ -0,0 +1,15 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__ ((target_clones (\"default\", \"dotprod\", \"sve+sve2\"))) int\n+foo ()\n+{\n+ return 1;\n+}\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 1 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mvc-symbols3.c b/gcc/testsuite/gcc.target/aarch64/mvc-symbols3.c\nnew file mode 100644\nindex 000000000000..1cbe3fd08509\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mvc-symbols3.c\n@@ -0,0 +1,19 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__ ((target_clones (\"default\", \"dotprod\", \"sve+sve2\"))) int\n+foo ();\n+\n+int\n+bar ()\n+{\n+ return foo ();\n+}\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\tbl\\tfoo\\n\" 1 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 0 } } */\ndiff --git a/gcc/testsuite/gcc.target/aarch64/mvc-symbols4.c b/gcc/testsuite/gcc.target/aarch64/mvc-symbols4.c\nnew file mode 100644\nindex 000000000000..abaf60f91c3e\n--- /dev/null\n+++ b/gcc/testsuite/gcc.target/aarch64/mvc-symbols4.c\n@@ -0,0 +1,12 @@\n+/* { dg-do compile } */\n+/* { dg-options \"-O0\" } */\n+\n+__attribute__ ((target_clones (\"default\", \"dotprod\", \"sve+sve2\"))) int\n+foo ();\n+\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.default:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._Mdotprod:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\._MsveMsve2:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\nfoo\\.resolver:\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.type\\tfoo, %gnu_indirect_function\\n\" 0 } } */\n+/* { dg-final { scan-assembler-times \"\\n\\t\\.set\\tfoo,foo\\.resolver\\n\" 0 } } */\n", "prefixes": [ "v1", "11/13" ] }