From patchwork Tue Dec 5 10:13:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Richard Sandiford X-Patchwork-Id: 1872037 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org (client-ip=8.43.85.97; helo=server2.sourceware.org; envelope-from=gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=patchwork.ozlabs.org) Received: from server2.sourceware.org (server2.sourceware.org [8.43.85.97]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature ECDSA (secp384r1) server-digest SHA384) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4SkxJd1D9pz1ySd for ; Tue, 5 Dec 2023 21:16:17 +1100 (AEDT) Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id E1E3E3875DFB for ; Tue, 5 Dec 2023 10:15:53 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by sourceware.org (Postfix) with ESMTP id 813ED385C322 for ; Tue, 5 Dec 2023 10:13:41 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 813ED385C322 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=arm.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 813ED385C322 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701771227; cv=none; b=pUR1eImkdqEuQjco9TCmr8udQQFpCCWmu5VViAAuoXvIH7U1r82Zn7DJ658PaqPkNWegM72gNVmxMDvvIEqzn/WdKfiw9rzz6pttusM+LoJg870hZLMEnXZYw+vg83Tbpda20R5ryLPV8Qau7pS5jxaZqb1d+lbZyl0xRmT9Ymo= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1701771227; c=relaxed/simple; bh=ldzIIh4rS+EIqzsdVZSy94rsSrvWFFjoB/BGru1r4P0=; h=From:To:Subject:Date:Message-Id:MIME-Version; b=uMCHsnhuTtDgGpR3czd8GbynVtFccVJAdsQdy9Mf1coH64FN60zCfHPpEY9zbMt4HitFpT/hVyl2Ahu3p4I3cyhOhS8uNnOQKC3sQFu+aPhaI94gayM8F3pFEkBCWg0KZ0KGWMAvDsySFOuARJPp+WhHIe1ZiDXgmkN7dL8HdGE= ARC-Authentication-Results: i=1; server2.sourceware.org Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id BD2711570; Tue, 5 Dec 2023 02:14:27 -0800 (PST) Received: from e121540-lin.manchester.arm.com (e121540-lin.manchester.arm.com [10.32.110.72]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id AE9403F5A1; Tue, 5 Dec 2023 02:13:40 -0800 (PST) From: Richard Sandiford To: gcc-patches@gcc.gnu.org Cc: Richard Sandiford Subject: [pushed v2 11/25] aarch64: Add arm_streaming(_compatible) attributes Date: Tue, 5 Dec 2023 10:13:09 +0000 Message-Id: <20231205101323.1914247-12-richard.sandiford@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20231205101323.1914247-1-richard.sandiford@arm.com> References: <20231205101323.1914247-1-richard.sandiford@arm.com> MIME-Version: 1.0 X-Spam-Status: No, score=-21.2 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_ASCII_DIVIDERS, KAM_DMARC_NONE, KAM_DMARC_STATUS, KAM_LAZY_DOMAIN_SECURITY, KAM_SHORT, KAM_STOCKGEN, SPF_HELO_NONE, SPF_NONE, TXREP, T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+incoming=patchwork.ozlabs.org@gcc.gnu.org This patch adds support for recognising the SME arm::streaming and arm::streaming_compatible attributes. These attributes respectively describe whether the processor is definitely in "streaming mode" (PSTATE.SM==1), whether the processor is definitely not in streaming mode (PSTATE.SM==0), or whether we don't know at compile time either way. As far as the compiler is concerned, this effectively creates three ISA submodes: streaming mode enables things that are not available in non-streaming mode, non-streaming mode enables things that not available in streaming mode, and streaming-compatible mode has to stick to the common subset. This means that some instructions are conditional on PSTATE.SM==1 and some are conditional on PSTATE.SM==0. I wondered about recording the streaming state in a new variable. However, the set of available instructions is also influenced by PSTATE.ZA (added later), so I think it makes sense to view this as an instance of a more general mechanism. Also, keeping the PSTATE.SM state in the same flag variable as the other ISA features makes it possible to sum up the requirements of an ACLE function in a single value. The patch therefore adds a new set of feature flags called "ISA modes". Unlike the other two sets of flags (optional features and architecture- level features), these ISA modes are not controlled directly by command-line parameters or "target" attributes. arm::streaming and arm::streaming_compatible are function type attributes rather than function declaration attributes. This means that we need to find somewhere to copy the type information across to a function's target options. The patch does this in aarch64_set_current_function. We also need to record which ISA mode a callee expects/requires to be active on entry. (The same mode is then active on return.) The patch extends the current UNSPEC_CALLEE_ABI cookie to include this information, as well as the PCS variant that it recorded previously. The attributes can also be written __arm_streaming and __arm_streaming_compatible. This has two advantages: it triggers an error on compilers that don't understand the attributes, and it eases use on C, where [[...]] attributes were only added in C23. gcc/ * config/aarch64/aarch64-isa-modes.def: New file. * config/aarch64/aarch64.h: Include it in the feature enumerations. (AARCH64_FL_SM_STATE, AARCH64_FL_ISA_MODES): New constants. (AARCH64_FL_DEFAULT_ISA_MODE): Likewise. (AARCH64_ISA_MODE): New macro. (CUMULATIVE_ARGS): Add an isa_mode field. * config/aarch64/aarch64-protos.h (aarch64_gen_callee_cookie): Declare. (aarch64_tlsdesc_abi_id): Return an arm_pcs. * config/aarch64/aarch64.cc (attr_streaming_exclusions) (aarch64_gnu_attributes, aarch64_gnu_attribute_table) (aarch64_arm_attributes, aarch64_arm_attribute_table): New tables. (aarch64_attribute_table): Redefine to include the gnu and arm attributes. (aarch64_fntype_pstate_sm, aarch64_fntype_isa_mode): New functions. (aarch64_fndecl_pstate_sm, aarch64_fndecl_isa_mode): Likewise. (aarch64_gen_callee_cookie, aarch64_callee_abi): Likewise. (aarch64_insn_callee_cookie, aarch64_insn_callee_abi): Use them. (aarch64_function_arg, aarch64_output_mi_thunk): Likewise. (aarch64_init_cumulative_args): Initialize the isa_mode field. (aarch64_output_mi_thunk): Use aarch64_gen_callee_cookie to get the ABI cookie. (aarch64_override_options): Add the ISA mode to the feature set. (aarch64_temporary_target::copy_from_fndecl): Likewise. (aarch64_fndecl_options, aarch64_handle_attr_arch): Likewise. (aarch64_set_current_function): Maintain the correct ISA mode. (aarch64_tlsdesc_abi_id): Return an arm_pcs. (aarch64_comp_type_attributes): Handle arm::streaming and arm::streaming_compatible. * config/aarch64/aarch64-c.cc (aarch64_define_unconditional_macros): Define __arm_streaming and __arm_streaming_compatible. * config/aarch64/aarch64.md (tlsdesc_small_): Use aarch64_gen_callee_cookie to get the ABI cookie. * config/aarch64/t-aarch64 (TM_H): Add all feature-related .def files. gcc/testsuite/ * gcc.target/aarch64/sme/aarch64-sme.exp: New harness. * gcc.target/aarch64/sme/streaming_mode_1.c: New test. * gcc.target/aarch64/sme/streaming_mode_2.c: Likewise. * gcc.target/aarch64/sme/keyword_macros_1.c: Likewise. * g++.target/aarch64/sme/aarch64-sme.exp: New harness. * g++.target/aarch64/sme/streaming_mode_1.C: New test. * g++.target/aarch64/sme/streaming_mode_2.C: Likewise. * g++.target/aarch64/sme/keyword_macros_1.C: Likewise. * gcc.target/aarch64/auto-init-1.c: Only expect the call insn to contain 1 (const_int 0), not 2. --- gcc/config/aarch64/aarch64-c.cc | 14 ++ gcc/config/aarch64/aarch64-isa-modes.def | 35 +++ gcc/config/aarch64/aarch64-protos.h | 3 +- gcc/config/aarch64/aarch64.cc | 233 +++++++++++++++--- gcc/config/aarch64/aarch64.h | 24 +- gcc/config/aarch64/aarch64.md | 3 +- gcc/config/aarch64/t-aarch64 | 5 +- .../g++.target/aarch64/sme/aarch64-sme.exp | 40 +++ .../g++.target/aarch64/sme/keyword_macros_1.C | 4 + .../g++.target/aarch64/sme/streaming_mode_1.C | 142 +++++++++++ .../g++.target/aarch64/sme/streaming_mode_2.C | 25 ++ .../gcc.target/aarch64/auto-init-1.c | 3 +- .../gcc.target/aarch64/sme/aarch64-sme.exp | 40 +++ .../gcc.target/aarch64/sme/keyword_macros_1.c | 4 + .../gcc.target/aarch64/sme/streaming_mode_1.c | 130 ++++++++++ .../gcc.target/aarch64/sme/streaming_mode_2.c | 25 ++ 16 files changed, 685 insertions(+), 45 deletions(-) create mode 100644 gcc/config/aarch64/aarch64-isa-modes.def create mode 100644 gcc/testsuite/g++.target/aarch64/sme/aarch64-sme.exp create mode 100644 gcc/testsuite/g++.target/aarch64/sme/keyword_macros_1.C create mode 100644 gcc/testsuite/g++.target/aarch64/sme/streaming_mode_1.C create mode 100644 gcc/testsuite/g++.target/aarch64/sme/streaming_mode_2.C create mode 100644 gcc/testsuite/gcc.target/aarch64/sme/aarch64-sme.exp create mode 100644 gcc/testsuite/gcc.target/aarch64/sme/keyword_macros_1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sme/streaming_mode_1.c create mode 100644 gcc/testsuite/gcc.target/aarch64/sme/streaming_mode_2.c diff --git a/gcc/config/aarch64/aarch64-c.cc b/gcc/config/aarch64/aarch64-c.cc index ab8844f6049..1603621b30d 100644 --- a/gcc/config/aarch64/aarch64-c.cc +++ b/gcc/config/aarch64/aarch64-c.cc @@ -72,6 +72,20 @@ aarch64_define_unconditional_macros (cpp_reader *pfile) builtin_define_with_int_value ("__ARM_SIZEOF_WCHAR_T", WCHAR_TYPE_SIZE / 8); builtin_define ("__GCC_ASM_FLAG_OUTPUTS__"); + + /* Define keyword attributes like __arm_streaming as macros that expand + to the associated [[...]] attribute. Use __extension__ in the attribute + for C, since the [[...]] syntax was only added in C23. */ +#define DEFINE_ARM_KEYWORD_MACRO(NAME) \ + builtin_define_with_value ("__arm_" NAME, \ + lang_GNU_CXX () \ + ? "[[arm::" NAME "]]" \ + : "[[__extension__ arm::" NAME "]]", 0); + + DEFINE_ARM_KEYWORD_MACRO ("streaming"); + DEFINE_ARM_KEYWORD_MACRO ("streaming_compatible"); + +#undef DEFINE_ARM_KEYWORD_MACRO } /* Undefine/redefine macros that depend on the current backend state and may diff --git a/gcc/config/aarch64/aarch64-isa-modes.def b/gcc/config/aarch64/aarch64-isa-modes.def new file mode 100644 index 00000000000..5915c98a896 --- /dev/null +++ b/gcc/config/aarch64/aarch64-isa-modes.def @@ -0,0 +1,35 @@ +/* Copyright (C) 2023 Free Software Foundation, Inc. + + This file is part of GCC. + + GCC is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published + by the Free Software Foundation; either version 3, or (at your + option) any later version. + + GCC is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with GCC; see the file COPYING3. If not see + . */ + +/* This file defines a set of "ISA modes"; in other words, it defines + various bits of runtime state that control the set of available + instructions or that affect the semantics of instructions in some way. + + Before using #include to read this file, define a macro: + + DEF_AARCH64_ISA_MODE(NAME) + + where NAME is the name of the mode. */ + +/* Indicates that PSTATE.SM is known to be 1 or 0 respectively. These + modes are mutually exclusive. If neither mode is active then the state + of PSTATE.SM is not known at compile time. */ +DEF_AARCH64_ISA_MODE(SM_ON) +DEF_AARCH64_ISA_MODE(SM_OFF) + +#undef DEF_AARCH64_ISA_MODE diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h index 765c42916f6..f629c1c383e 100644 --- a/gcc/config/aarch64/aarch64-protos.h +++ b/gcc/config/aarch64/aarch64-protos.h @@ -767,6 +767,7 @@ bool aarch64_constant_address_p (rtx); bool aarch64_emit_approx_div (rtx, rtx, rtx); bool aarch64_emit_approx_sqrt (rtx, rtx, bool); tree aarch64_vector_load_decl (tree); +rtx aarch64_gen_callee_cookie (aarch64_feature_flags, arm_pcs); void aarch64_expand_call (rtx, rtx, rtx, bool); bool aarch64_expand_cpymem_mops (rtx *, bool); bool aarch64_expand_cpymem (rtx *); @@ -852,7 +853,7 @@ bool aarch64_use_return_insn_p (void); const char *aarch64_output_casesi (rtx *); const char *aarch64_output_load_tp (rtx); -unsigned int aarch64_tlsdesc_abi_id (); +arm_pcs aarch64_tlsdesc_abi_id (); enum aarch64_symbol_type aarch64_classify_symbol (rtx, HOST_WIDE_INT); enum aarch64_symbol_type aarch64_classify_tls_symbol (rtx); enum reg_class aarch64_regno_regclass (unsigned); diff --git a/gcc/config/aarch64/aarch64.cc b/gcc/config/aarch64/aarch64.cc index 7a5d0d325e9..b60728b3b5d 100644 --- a/gcc/config/aarch64/aarch64.cc +++ b/gcc/config/aarch64/aarch64.cc @@ -464,8 +464,18 @@ handle_aarch64_vector_pcs_attribute (tree *node, tree name, tree, gcc_unreachable (); } +/* Mutually-exclusive function type attributes for controlling PSTATE.SM. */ +static const struct attribute_spec::exclusions attr_streaming_exclusions[] = +{ + /* Attribute name exclusion applies to: + function, type, variable */ + { "streaming", false, true, false }, + { "streaming_compatible", false, true, false }, + { NULL, false, false, false } +}; + /* Table of machine attributes. */ -TARGET_GNU_ATTRIBUTES (aarch64_attribute_table, +static const attribute_spec aarch64_gnu_attributes[] = { /* { name, min_len, max_len, decl_req, type_req, fn_type_req, affects_type_identity, handler, exclude } */ @@ -477,7 +487,31 @@ TARGET_GNU_ATTRIBUTES (aarch64_attribute_table, { "Advanced SIMD type", 1, 1, false, true, false, true, NULL, NULL }, { "SVE type", 3, 3, false, true, false, true, NULL, NULL }, { "SVE sizeless type", 0, 0, false, true, false, true, NULL, NULL } -}); +}; + +static const scoped_attribute_specs aarch64_gnu_attribute_table = +{ + "gnu", aarch64_gnu_attributes +}; + +static const attribute_spec aarch64_arm_attributes[] = +{ + { "streaming", 0, 0, false, true, true, true, + NULL, attr_streaming_exclusions }, + { "streaming_compatible", 0, 0, false, true, true, true, + NULL, attr_streaming_exclusions }, +}; + +static const scoped_attribute_specs aarch64_arm_attribute_table = +{ + "arm", aarch64_arm_attributes +}; + +static const scoped_attribute_specs *const aarch64_attribute_table[] = +{ + &aarch64_gnu_attribute_table, + &aarch64_arm_attribute_table +}; typedef enum aarch64_cond_code { @@ -1715,6 +1749,48 @@ aarch64_fntype_abi (const_tree fntype) return default_function_abi; } +/* Return the state of PSTATE.SM on entry to functions of type FNTYPE. */ + +static aarch64_feature_flags +aarch64_fntype_pstate_sm (const_tree fntype) +{ + if (lookup_attribute ("arm", "streaming", TYPE_ATTRIBUTES (fntype))) + return AARCH64_FL_SM_ON; + + if (lookup_attribute ("arm", "streaming_compatible", + TYPE_ATTRIBUTES (fntype))) + return 0; + + return AARCH64_FL_SM_OFF; +} + +/* Return the ISA mode on entry to functions of type FNTYPE. */ + +static aarch64_feature_flags +aarch64_fntype_isa_mode (const_tree fntype) +{ + return aarch64_fntype_pstate_sm (fntype); +} + +/* Return the state of PSTATE.SM when compiling the body of + function FNDECL. This might be different from the state of + PSTATE.SM on entry. */ + +static aarch64_feature_flags +aarch64_fndecl_pstate_sm (const_tree fndecl) +{ + return aarch64_fntype_pstate_sm (TREE_TYPE (fndecl)); +} + +/* Return the ISA mode that should be used to compile the body of + function FNDECL. */ + +static aarch64_feature_flags +aarch64_fndecl_isa_mode (const_tree fndecl) +{ + return aarch64_fndecl_pstate_sm (fndecl); +} + /* Implement TARGET_COMPATIBLE_VECTOR_TYPES_P. */ static bool @@ -1777,17 +1853,46 @@ aarch64_reg_save_mode (unsigned int regno) gcc_unreachable (); } -/* Implement TARGET_INSN_CALLEE_ABI. */ +/* Given the ISA mode on entry to a callee and the ABI of the callee, + return the CONST_INT that should be placed in an UNSPEC_CALLEE_ABI rtx. */ -const predefined_function_abi & -aarch64_insn_callee_abi (const rtx_insn *insn) +rtx +aarch64_gen_callee_cookie (aarch64_feature_flags isa_mode, arm_pcs pcs_variant) +{ + return gen_int_mode ((unsigned int) isa_mode + | (unsigned int) pcs_variant << AARCH64_NUM_ISA_MODES, + DImode); +} + +/* COOKIE is a CONST_INT from an UNSPEC_CALLEE_ABI rtx. Return the + callee's ABI. */ + +static const predefined_function_abi & +aarch64_callee_abi (rtx cookie) +{ + return function_abis[UINTVAL (cookie) >> AARCH64_NUM_ISA_MODES]; +} + +/* INSN is a call instruction. Return the CONST_INT stored in its + UNSPEC_CALLEE_ABI rtx. */ + +static rtx +aarch64_insn_callee_cookie (const rtx_insn *insn) { rtx pat = PATTERN (insn); gcc_assert (GET_CODE (pat) == PARALLEL); rtx unspec = XVECEXP (pat, 0, 1); gcc_assert (GET_CODE (unspec) == UNSPEC && XINT (unspec, 1) == UNSPEC_CALLEE_ABI); - return function_abis[INTVAL (XVECEXP (unspec, 0, 0))]; + return XVECEXP (unspec, 0, 0); +} + +/* Implement TARGET_INSN_CALLEE_ABI. */ + +const predefined_function_abi & +aarch64_insn_callee_abi (const rtx_insn *insn) +{ + return aarch64_callee_abi (aarch64_insn_callee_cookie (insn)); } /* Implement TARGET_HARD_REGNO_CALL_PART_CLOBBERED. The callee only saves @@ -5712,7 +5817,7 @@ aarch64_function_arg (cumulative_args_t pcum_v, const function_arg_info &arg) || pcum->pcs_variant == ARM_PCS_SVE); if (arg.end_marker_p ()) - return gen_int_mode (pcum->pcs_variant, DImode); + return aarch64_gen_callee_cookie (pcum->isa_mode, pcum->pcs_variant); aarch64_layout_arg (pcum_v, arg); return pcum->aapcs_reg; @@ -5733,9 +5838,15 @@ aarch64_init_cumulative_args (CUMULATIVE_ARGS *pcum, pcum->aapcs_nextnvrn = 0; pcum->aapcs_nextnprn = 0; if (fntype) - pcum->pcs_variant = (arm_pcs) fntype_abi (fntype).id (); + { + pcum->pcs_variant = (arm_pcs) fntype_abi (fntype).id (); + pcum->isa_mode = aarch64_fntype_isa_mode (fntype); + } else - pcum->pcs_variant = ARM_PCS_AAPCS64; + { + pcum->pcs_variant = ARM_PCS_AAPCS64; + pcum->isa_mode = AARCH64_FL_DEFAULT_ISA_MODE; + } pcum->aapcs_reg = NULL_RTX; pcum->aapcs_arg_processed = false; pcum->aapcs_stack_words = 0; @@ -8306,7 +8417,9 @@ aarch64_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED, } funexp = XEXP (DECL_RTL (function), 0); funexp = gen_rtx_MEM (FUNCTION_MODE, funexp); - rtx callee_abi = gen_int_mode (fndecl_abi (function).id (), DImode); + auto isa_mode = aarch64_fntype_isa_mode (TREE_TYPE (function)); + auto pcs_variant = arm_pcs (fndecl_abi (function).id ()); + rtx callee_abi = aarch64_gen_callee_cookie (isa_mode, pcs_variant); insn = emit_call_insn (gen_sibcall (funexp, const0_rtx, callee_abi)); SIBLING_CALL_P (insn) = 1; @@ -16485,6 +16598,7 @@ aarch64_override_options (void) SUBTARGET_OVERRIDE_OPTIONS; #endif + auto isa_mode = AARCH64_FL_DEFAULT_ISA_MODE; if (cpu && arch) { /* If both -mcpu and -march are specified, warn if they are not @@ -16507,25 +16621,25 @@ aarch64_override_options (void) } selected_arch = arch->arch; - aarch64_set_asm_isa_flags (arch_isa); + aarch64_set_asm_isa_flags (arch_isa | isa_mode); } else if (cpu) { selected_arch = cpu->arch; - aarch64_set_asm_isa_flags (cpu_isa); + aarch64_set_asm_isa_flags (cpu_isa | isa_mode); } else if (arch) { cpu = &all_cores[arch->ident]; selected_arch = arch->arch; - aarch64_set_asm_isa_flags (arch_isa); + aarch64_set_asm_isa_flags (arch_isa | isa_mode); } else { /* No -mcpu or -march specified, so use the default CPU. */ cpu = &all_cores[TARGET_CPU_DEFAULT]; selected_arch = cpu->arch; - aarch64_set_asm_isa_flags (cpu->flags); + aarch64_set_asm_isa_flags (cpu->flags | isa_mode); } selected_tune = tune ? tune->ident : cpu->ident; @@ -16698,6 +16812,21 @@ aarch64_save_restore_target_globals (tree new_tree) TREE_TARGET_GLOBALS (new_tree) = save_target_globals_default_opts (); } +/* Return the target_option_node for FNDECL, or the current options + if FNDECL is null. */ + +static tree +aarch64_fndecl_options (tree fndecl) +{ + if (!fndecl) + return target_option_current_node; + + if (tree options = DECL_FUNCTION_SPECIFIC_TARGET (fndecl)) + return options; + + return target_option_default_node; +} + /* Implement TARGET_SET_CURRENT_FUNCTION. Unpack the codegen decisions like tuning and ISA features from the DECL_FUNCTION_SPECIFIC_TARGET of the function, if such exists. This function may be called multiple @@ -16707,25 +16836,24 @@ aarch64_save_restore_target_globals (tree new_tree) static void aarch64_set_current_function (tree fndecl) { - if (!fndecl || fndecl == aarch64_previous_fndecl) - return; - - tree old_tree = (aarch64_previous_fndecl - ? DECL_FUNCTION_SPECIFIC_TARGET (aarch64_previous_fndecl) - : NULL_TREE); - - tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET (fndecl); + tree old_tree = aarch64_fndecl_options (aarch64_previous_fndecl); + tree new_tree = aarch64_fndecl_options (fndecl); - /* If current function has no attributes but the previous one did, - use the default node. */ - if (!new_tree && old_tree) - new_tree = target_option_default_node; + auto new_isa_mode = (fndecl + ? aarch64_fndecl_isa_mode (fndecl) + : AARCH64_FL_DEFAULT_ISA_MODE); + auto isa_flags = TREE_TARGET_OPTION (new_tree)->x_aarch64_isa_flags; /* If nothing to do, return. #pragma GCC reset or #pragma GCC pop to the default have been handled by aarch64_save_restore_target_globals from aarch64_pragma_target_parse. */ - if (old_tree == new_tree) - return; + if (old_tree == new_tree + && (!fndecl || aarch64_previous_fndecl) + && (isa_flags & AARCH64_FL_ISA_MODES) == new_isa_mode) + { + gcc_assert (AARCH64_ISA_MODE == new_isa_mode); + return; + } aarch64_previous_fndecl = fndecl; @@ -16733,7 +16861,28 @@ aarch64_set_current_function (tree fndecl) cl_target_option_restore (&global_options, &global_options_set, TREE_TARGET_OPTION (new_tree)); + /* The ISA mode can vary based on function type attributes and + function declaration attributes. Make sure that the target + options correctly reflect these attributes. */ + if ((isa_flags & AARCH64_FL_ISA_MODES) != new_isa_mode) + { + auto base_flags = (aarch64_asm_isa_flags & ~AARCH64_FL_ISA_MODES); + aarch64_set_asm_isa_flags (base_flags | new_isa_mode); + + aarch64_override_options_internal (&global_options); + new_tree = build_target_option_node (&global_options, + &global_options_set); + DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_tree; + + tree new_optimize = build_optimization_node (&global_options, + &global_options_set); + if (new_optimize != optimization_default_node) + DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize; + } + aarch64_save_restore_target_globals (new_tree); + + gcc_assert (AARCH64_ISA_MODE == new_isa_mode); } /* Enum describing the various ways we can handle attributes. @@ -16783,7 +16932,7 @@ aarch64_handle_attr_arch (const char *str) { gcc_assert (tmp_arch); selected_arch = tmp_arch->arch; - aarch64_set_asm_isa_flags (tmp_flags); + aarch64_set_asm_isa_flags (tmp_flags | AARCH64_ISA_MODE); return true; } @@ -16824,7 +16973,7 @@ aarch64_handle_attr_cpu (const char *str) gcc_assert (tmp_cpu); selected_tune = tmp_cpu->ident; selected_arch = tmp_cpu->arch; - aarch64_set_asm_isa_flags (tmp_flags); + aarch64_set_asm_isa_flags (tmp_flags | AARCH64_ISA_MODE); return true; } @@ -16924,7 +17073,7 @@ aarch64_handle_attr_isa_flags (char *str) features if the user wants to handpick specific features. */ if (strncmp ("+nothing", str, 8) == 0) { - isa_flags = 0; + isa_flags = AARCH64_ISA_MODE; str += 8; } @@ -17417,7 +17566,7 @@ aarch64_can_inline_p (tree caller, tree callee) /* Return the ID of the TLDESC ABI, initializing the descriptor if hasn't been already. */ -unsigned int +arm_pcs aarch64_tlsdesc_abi_id () { predefined_function_abi &tlsdesc_abi = function_abis[ARM_PCS_TLSDESC]; @@ -17431,7 +17580,7 @@ aarch64_tlsdesc_abi_id () SET_HARD_REG_BIT (full_reg_clobbers, regno); tlsdesc_abi.initialize (ARM_PCS_TLSDESC, full_reg_clobbers); } - return tlsdesc_abi.id (); + return ARM_PCS_TLSDESC; } /* Return true if SYMBOL_REF X binds locally. */ @@ -25386,22 +25535,26 @@ aarch64_simd_clone_usable (struct cgraph_node *node) static int aarch64_comp_type_attributes (const_tree type1, const_tree type2) { - auto check_attr = [&](const char *name) { - tree attr1 = lookup_attribute (name, TYPE_ATTRIBUTES (type1)); - tree attr2 = lookup_attribute (name, TYPE_ATTRIBUTES (type2)); + auto check_attr = [&](const char *ns, const char *name) { + tree attr1 = lookup_attribute (ns, name, TYPE_ATTRIBUTES (type1)); + tree attr2 = lookup_attribute (ns, name, TYPE_ATTRIBUTES (type2)); if (!attr1 && !attr2) return true; return attr1 && attr2 && attribute_value_equal (attr1, attr2); }; - if (!check_attr ("aarch64_vector_pcs")) + if (!check_attr ("gnu", "aarch64_vector_pcs")) + return 0; + if (!check_attr ("gnu", "Advanced SIMD type")) + return 0; + if (!check_attr ("gnu", "SVE type")) return 0; - if (!check_attr ("Advanced SIMD type")) + if (!check_attr ("gnu", "SVE sizeless type")) return 0; - if (!check_attr ("SVE type")) + if (!check_attr ("arm", "streaming")) return 0; - if (!check_attr ("SVE sizeless type")) + if (!check_attr ("arm", "streaming_compatible")) return 0; return 1; } diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h index 43b56748b36..08d135d9a74 100644 --- a/gcc/config/aarch64/aarch64.h +++ b/gcc/config/aarch64/aarch64.h @@ -157,10 +157,13 @@ #ifndef USED_FOR_TARGET -/* Define an enum of all features (architectures and extensions). */ +/* Define an enum of all features (ISA modes, architectures and extensions). + The ISA modes must come first. */ enum class aarch64_feature : unsigned char { +#define DEF_AARCH64_ISA_MODE(IDENT) IDENT, #define AARCH64_OPT_EXTENSION(A, IDENT, C, D, E, F) IDENT, #define AARCH64_ARCH(A, B, IDENT, D, E) IDENT, +#include "aarch64-isa-modes.def" #include "aarch64-option-extensions.def" #include "aarch64-arches.def" }; @@ -169,16 +172,34 @@ enum class aarch64_feature : unsigned char { #define HANDLE(IDENT) \ constexpr auto AARCH64_FL_##IDENT \ = aarch64_feature_flags (1) << int (aarch64_feature::IDENT); +#define DEF_AARCH64_ISA_MODE(IDENT) HANDLE (IDENT) #define AARCH64_OPT_EXTENSION(A, IDENT, C, D, E, F) HANDLE (IDENT) #define AARCH64_ARCH(A, B, IDENT, D, E) HANDLE (IDENT) +#include "aarch64-isa-modes.def" #include "aarch64-option-extensions.def" #include "aarch64-arches.def" #undef HANDLE +constexpr auto AARCH64_FL_SM_STATE = AARCH64_FL_SM_ON | AARCH64_FL_SM_OFF; + +constexpr unsigned int AARCH64_NUM_ISA_MODES = (0 +#define DEF_AARCH64_ISA_MODE(IDENT) + 1 +#include "aarch64-isa-modes.def" +); + +/* The mask of all ISA modes. */ +constexpr auto AARCH64_FL_ISA_MODES + = (aarch64_feature_flags (1) << AARCH64_NUM_ISA_MODES) - 1; + +/* The default ISA mode, for functions with no attributes that specify + something to the contrary. */ +constexpr auto AARCH64_FL_DEFAULT_ISA_MODE = AARCH64_FL_SM_OFF; + #endif /* Macros to test ISA flags. */ +#define AARCH64_ISA_MODE (aarch64_isa_flags & AARCH64_FL_ISA_MODES) #define AARCH64_ISA_CRC (aarch64_isa_flags & AARCH64_FL_CRC) #define AARCH64_ISA_CRYPTO (aarch64_isa_flags & AARCH64_FL_CRYPTO) #define AARCH64_ISA_FP (aarch64_isa_flags & AARCH64_FL_FP) @@ -935,6 +956,7 @@ enum arm_pcs typedef struct { enum arm_pcs pcs_variant; + aarch64_feature_flags isa_mode; int aapcs_arg_processed; /* No need to lay out this argument again. */ int aapcs_ncrn; /* Next Core register number. */ int aapcs_nextncrn; /* Next next core register number. */ diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md index d843f472dc2..e6b19b962b1 100644 --- a/gcc/config/aarch64/aarch64.md +++ b/gcc/config/aarch64/aarch64.md @@ -7335,7 +7335,8 @@ (define_expand "tlsdesc_small_" { if (TARGET_SVE) { - rtx abi = gen_int_mode (aarch64_tlsdesc_abi_id (), DImode); + rtx abi = aarch64_gen_callee_cookie (AARCH64_ISA_MODE, + aarch64_tlsdesc_abi_id ()); rtx_insn *call = emit_call_insn (gen_tlsdesc_small_sve_ (operands[0], abi)); RTL_CONST_CALL_P (call) = 1; diff --git a/gcc/config/aarch64/t-aarch64 b/gcc/config/aarch64/t-aarch64 index a9a244ab6d6..a4e0aa03274 100644 --- a/gcc/config/aarch64/t-aarch64 +++ b/gcc/config/aarch64/t-aarch64 @@ -20,7 +20,10 @@ TM_H += $(srcdir)/config/aarch64/aarch64-fusion-pairs.def \ $(srcdir)/config/aarch64/aarch64-tuning-flags.def \ - $(srcdir)/config/aarch64/aarch64-option-extensions.def + $(srcdir)/config/aarch64/aarch64-option-extensions.def \ + $(srcdir)/config/aarch64/aarch64-cores.def \ + $(srcdir)/config/aarch64/aarch64-isa-modes.def \ + $(srcdir)/config/aarch64/aarch64-arches.def OPTIONS_H_EXTRA += $(srcdir)/config/aarch64/aarch64-cores.def \ $(srcdir)/config/aarch64/aarch64-arches.def diff --git a/gcc/testsuite/g++.target/aarch64/sme/aarch64-sme.exp b/gcc/testsuite/g++.target/aarch64/sme/aarch64-sme.exp new file mode 100644 index 00000000000..72fcd0bd982 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sme/aarch64-sme.exp @@ -0,0 +1,40 @@ +# Specific regression driver for AArch64 SME. +# Copyright (C) 2009-2023 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . */ + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't an AArch64 target. +if {![istarget aarch64*-*-*] } { + return +} + +# Load support procs. +load_lib g++-dg.exp + +# Initialize `dg'. +dg-init + +aarch64-with-arch-dg-options "" { + # Main loop. + dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \ + "" "" +} + +# All done. +dg-finish diff --git a/gcc/testsuite/g++.target/aarch64/sme/keyword_macros_1.C b/gcc/testsuite/g++.target/aarch64/sme/keyword_macros_1.C new file mode 100644 index 00000000000..032485adf95 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sme/keyword_macros_1.C @@ -0,0 +1,4 @@ +/* { dg-options "-std=c++11 -pedantic-errors" } */ + +void f1 () __arm_streaming; +void f2 () __arm_streaming_compatible; diff --git a/gcc/testsuite/g++.target/aarch64/sme/streaming_mode_1.C b/gcc/testsuite/g++.target/aarch64/sme/streaming_mode_1.C new file mode 100644 index 00000000000..c3de726e726 --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sme/streaming_mode_1.C @@ -0,0 +1,142 @@ +// { dg-options "" } + +void sc_a () [[arm::streaming_compatible]]; +void sc_a (); // { dg-error "ambiguating new declaration" "" { xfail *-*-* } } + +void sc_b (); +void sc_b () [[arm::streaming_compatible]]; // { dg-error "ambiguating new declaration" } + +void sc_c () [[arm::streaming_compatible]]; +void sc_c () {} // Inherits attribute from declaration (confusingly). + +void sc_d (); +void sc_d () [[arm::streaming_compatible]] {} // { dg-error "ambiguating new declaration" } + +void sc_e () [[arm::streaming_compatible]] {} +void sc_e (); // { dg-error "ambiguating new declaration" "" { xfail *-*-* } } + +void sc_f () {} +void sc_f () [[arm::streaming_compatible]]; // { dg-error "ambiguating new declaration" } + +extern void (*sc_g) (); +extern void (*sc_g) () [[arm::streaming_compatible]]; // { dg-error "conflicting declaration" } + +extern void (*sc_h) () [[arm::streaming_compatible]]; +extern void (*sc_h) (); // { dg-error "conflicting declaration" } + +//---------------------------------------------------------------------------- + +void s_a () [[arm::streaming]]; +void s_a (); // { dg-error "ambiguating new declaration" "" { xfail *-*-* } } + +void s_b (); +void s_b () [[arm::streaming]]; // { dg-error "ambiguating new declaration" } + +void s_c () [[arm::streaming]]; +void s_c () {} // Inherits attribute from declaration (confusingly). + +void s_d (); +void s_d () [[arm::streaming]] {} // { dg-error "ambiguating new declaration" } + +void s_e () [[arm::streaming]] {} +void s_e (); // { dg-error "ambiguating new declaration" "" { xfail *-*-* } } + +void s_f () {} +void s_f () [[arm::streaming]]; // { dg-error "ambiguating new declaration" } + +extern void (*s_g) (); +extern void (*s_g) () [[arm::streaming]]; // { dg-error "conflicting declaration" } + +extern void (*s_h) () [[arm::streaming]]; +extern void (*s_h) (); // { dg-error "conflicting declaration" } + +//---------------------------------------------------------------------------- + +void mixed_a () [[arm::streaming]]; +void mixed_a () [[arm::streaming_compatible]]; // { dg-error "ambiguating new declaration" } + +void mixed_b () [[arm::streaming_compatible]]; +void mixed_b () [[arm::streaming]]; // { dg-error "ambiguating new declaration" } + +void mixed_c () [[arm::streaming]]; +void mixed_c () [[arm::streaming_compatible]] {} // { dg-error "ambiguating new declaration" } + +void mixed_d () [[arm::streaming_compatible]]; +void mixed_d () [[arm::streaming]] {} // { dg-error "ambiguating new declaration" } + +void mixed_e () [[arm::streaming]] {} +void mixed_e () [[arm::streaming_compatible]]; // { dg-error "ambiguating new declaration" } + +void mixed_f () [[arm::streaming_compatible]] {} +void mixed_f () [[arm::streaming]]; // { dg-error "ambiguating new declaration" } + +extern void (*mixed_g) () [[arm::streaming_compatible]]; +extern void (*mixed_g) () [[arm::streaming]]; // { dg-error "conflicting declaration" } + +extern void (*mixed_h) () [[arm::streaming]]; +extern void (*mixed_h) () [[arm::streaming_compatible]]; // { dg-error "conflicting declaration" } + +//---------------------------------------------------------------------------- + +void contradiction_1 () [[arm::streaming, arm::streaming_compatible]]; // { dg-warning "conflicts with attribute" } +void contradiction_2 () [[arm::streaming_compatible, arm::streaming]]; // { dg-warning "conflicts with attribute" } + +int [[arm::streaming_compatible]] int_attr; // { dg-warning "attribute ignored" } +void [[arm::streaming_compatible]] ret_attr (); // { dg-warning "attribute ignored" } +void *[[arm::streaming]] ptr_attr; // { dg-warning "only applies to function types" } + +typedef void s_callback () [[arm::streaming]]; +typedef void sc_callback () [[arm::streaming_compatible]]; + +typedef void contradiction_callback_1 () [[arm::streaming, arm::streaming_compatible]]; // { dg-warning "conflicts with attribute" } +typedef void contradiction_callback_2 () [[arm::streaming_compatible, arm::streaming]]; // { dg-warning "conflicts with attribute" } + +void (*contradiction_callback_ptr_1) () [[arm::streaming, arm::streaming_compatible]]; // { dg-warning "conflicts with attribute" } +void (*contradiction_callback_ptr_2) () [[arm::streaming_compatible, arm::streaming]]; // { dg-warning "conflicts with attribute" } + +struct s { + void (*contradiction_callback_ptr_1) () [[arm::streaming, arm::streaming_compatible]]; // { dg-warning "conflicts with attribute" } + void (*contradiction_callback_ptr_2) () [[arm::streaming_compatible, arm::streaming]]; // { dg-warning "conflicts with attribute" } +}; + +//---------------------------------------------------------------------------- + +void keyword_ok_1 () __arm_streaming; +void keyword_ok_1 () __arm_streaming; + +void keyword_ok_2 () __arm_streaming; +void keyword_ok_2 () [[arm::streaming]]; + +void keyword_ok_3 () [[arm::streaming]]; +void keyword_ok_3 () __arm_streaming; + +void keyword_ok_4 () __arm_streaming [[arm::streaming]]; + +void keyword_ok_5 () __arm_streaming_compatible; +void keyword_ok_5 () [[arm::streaming_compatible]]; + +//---------------------------------------------------------------------------- + +void keyword_contradiction_1 () __arm_streaming; +void keyword_contradiction_1 (); // { dg-error "ambiguating new declaration" "" { xfail *-*-* } } + +void keyword_contradiction_2 (); +void keyword_contradiction_2 () __arm_streaming; // { dg-error "ambiguating new declaration" } + +void keyword_contradiction_3 () __arm_streaming; +void keyword_contradiction_3 () [[arm::streaming_compatible]]; // { dg-error "ambiguating new declaration" } + +void keyword_contradiction_4 () [[arm::streaming_compatible]]; +void keyword_contradiction_4 () __arm_streaming; // { dg-error "ambiguating new declaration" } + +//---------------------------------------------------------------------------- + +struct s1 +{ + virtual void f () [[arm::streaming]]; +}; + +struct s2 : public s1 +{ + void f () override; // { dg-error "conflicting type attributes" } +}; diff --git a/gcc/testsuite/g++.target/aarch64/sme/streaming_mode_2.C b/gcc/testsuite/g++.target/aarch64/sme/streaming_mode_2.C new file mode 100644 index 00000000000..f2dd2db9b6f --- /dev/null +++ b/gcc/testsuite/g++.target/aarch64/sme/streaming_mode_2.C @@ -0,0 +1,25 @@ +// { dg-options "" } + +void sc_fn () [[arm::streaming_compatible]]; +void s_fn () [[arm::streaming]]; +void ns_fn (); + +void (*sc_fn_ptr) () [[arm::streaming_compatible]]; +void (*s_fn_ptr) () [[arm::streaming]]; +void (*ns_fn_ptr) (); + +void +f () +{ + sc_fn_ptr = sc_fn; + sc_fn_ptr = s_fn; // { dg-error "invalid conversion" } + sc_fn_ptr = ns_fn; // { dg-error "invalid conversion" } + + s_fn_ptr = sc_fn; // { dg-error "invalid conversion" } + s_fn_ptr = s_fn; + s_fn_ptr = ns_fn; // { dg-error "invalid conversion" } + + ns_fn_ptr = sc_fn; // { dg-error "invalid conversion" } + ns_fn_ptr = s_fn; // { dg-error "invalid conversion" } + ns_fn_ptr = ns_fn; +} diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-1.c b/gcc/testsuite/gcc.target/aarch64/auto-init-1.c index 0fa470880bf..45bb02561ed 100644 --- a/gcc/testsuite/gcc.target/aarch64/auto-init-1.c +++ b/gcc/testsuite/gcc.target/aarch64/auto-init-1.c @@ -29,4 +29,5 @@ void foo() return; } -/* { dg-final { scan-rtl-dump-times "const_int 0" 11 "expand" } } */ +/* Includes 1 for the call instruction and 1 for a nop. */ +/* { dg-final { scan-rtl-dump-times "const_int 0" 10 "expand" } } */ diff --git a/gcc/testsuite/gcc.target/aarch64/sme/aarch64-sme.exp b/gcc/testsuite/gcc.target/aarch64/sme/aarch64-sme.exp new file mode 100644 index 00000000000..c990e59247a --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sme/aarch64-sme.exp @@ -0,0 +1,40 @@ +# Specific regression driver for AArch64 SME. +# Copyright (C) 2009-2023 Free Software Foundation, Inc. +# +# This file is part of GCC. +# +# GCC is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GCC is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GCC; see the file COPYING3. If not see +# . */ + +# GCC testsuite that uses the `dg.exp' driver. + +# Exit immediately if this isn't an AArch64 target. +if {![istarget aarch64*-*-*] } { + return +} + +# Load support procs. +load_lib gcc-dg.exp + +# Initialize `dg'. +dg-init + +aarch64-with-arch-dg-options "" { + # Main loop. + dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.\[cCS\]]] \ + "" "" +} + +# All done. +dg-finish diff --git a/gcc/testsuite/gcc.target/aarch64/sme/keyword_macros_1.c b/gcc/testsuite/gcc.target/aarch64/sme/keyword_macros_1.c new file mode 100644 index 00000000000..8f1b836764e --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sme/keyword_macros_1.c @@ -0,0 +1,4 @@ +/* { dg-options "-std=c90 -pedantic-errors" } */ + +void f1 () __arm_streaming; +void f2 () __arm_streaming_compatible; diff --git a/gcc/testsuite/gcc.target/aarch64/sme/streaming_mode_1.c b/gcc/testsuite/gcc.target/aarch64/sme/streaming_mode_1.c new file mode 100644 index 00000000000..8874b05b882 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sme/streaming_mode_1.c @@ -0,0 +1,130 @@ +// { dg-options "" } + +void sc_a () [[arm::streaming_compatible]]; +void sc_a (); // { dg-error "conflicting types" } + +void sc_b (); +void sc_b () [[arm::streaming_compatible]]; // { dg-error "conflicting types" } + +void sc_c () [[arm::streaming_compatible]]; +void sc_c () {} // Inherits attribute from declaration (confusingly). + +void sc_d (); +void sc_d () [[arm::streaming_compatible]] {} // { dg-error "conflicting types" } + +void sc_e () [[arm::streaming_compatible]] {} +void sc_e (); // { dg-error "conflicting types" } + +void sc_f () {} +void sc_f () [[arm::streaming_compatible]]; // { dg-error "conflicting types" } + +extern void (*sc_g) (); +extern void (*sc_g) () [[arm::streaming_compatible]]; // { dg-error "conflicting types" } + +extern void (*sc_h) () [[arm::streaming_compatible]]; +extern void (*sc_h) (); // { dg-error "conflicting types" } + +//---------------------------------------------------------------------------- + +void s_a () [[arm::streaming]]; +void s_a (); // { dg-error "conflicting types" } + +void s_b (); +void s_b () [[arm::streaming]]; // { dg-error "conflicting types" } + +void s_c () [[arm::streaming]]; +void s_c () {} // Inherits attribute from declaration (confusingly). + +void s_d (); +void s_d () [[arm::streaming]] {} // { dg-error "conflicting types" } + +void s_e () [[arm::streaming]] {} +void s_e (); // { dg-error "conflicting types" } + +void s_f () {} +void s_f () [[arm::streaming]]; // { dg-error "conflicting types" } + +extern void (*s_g) (); +extern void (*s_g) () [[arm::streaming]]; // { dg-error "conflicting types" } + +extern void (*s_h) () [[arm::streaming]]; +extern void (*s_h) (); // { dg-error "conflicting types" } + +//---------------------------------------------------------------------------- + +void mixed_a () [[arm::streaming]]; +void mixed_a () [[arm::streaming_compatible]]; // { dg-error "conflicting types" } + +void mixed_b () [[arm::streaming_compatible]]; +void mixed_b () [[arm::streaming]]; // { dg-error "conflicting types" } + +void mixed_c () [[arm::streaming]]; +void mixed_c () [[arm::streaming_compatible]] {} // { dg-error "conflicting types" } + +void mixed_d () [[arm::streaming_compatible]]; +void mixed_d () [[arm::streaming]] {} // { dg-error "conflicting types" } + +void mixed_e () [[arm::streaming]] {} +void mixed_e () [[arm::streaming_compatible]]; // { dg-error "conflicting types" } + +void mixed_f () [[arm::streaming_compatible]] {} +void mixed_f () [[arm::streaming]]; // { dg-error "conflicting types" } + +extern void (*mixed_g) () [[arm::streaming_compatible]]; +extern void (*mixed_g) () [[arm::streaming]]; // { dg-error "conflicting types" } + +extern void (*mixed_h) () [[arm::streaming]]; +extern void (*mixed_h) () [[arm::streaming_compatible]]; // { dg-error "conflicting types" } + +//---------------------------------------------------------------------------- + +void contradiction_1 () [[arm::streaming, arm::streaming_compatible]]; // { dg-warning "conflicts with attribute" } +void contradiction_2 () [[arm::streaming_compatible, arm::streaming]]; // { dg-warning "conflicts with attribute" } + +int [[arm::streaming_compatible]] int_attr; // { dg-warning "only applies to function types" } +void [[arm::streaming_compatible]] ret_attr (); // { dg-warning "only applies to function types" } +void *[[arm::streaming]] ptr_attr; // { dg-warning "only applies to function types" } + +typedef void s_callback () [[arm::streaming]]; +typedef void sc_callback () [[arm::streaming_compatible]]; + +typedef void contradiction_callback_1 () [[arm::streaming, arm::streaming_compatible]]; // { dg-warning "conflicts with attribute" } +typedef void contradiction_callback_2 () [[arm::streaming_compatible, arm::streaming]]; // { dg-warning "conflicts with attribute" } + +void (*contradiction_callback_ptr_1) () [[arm::streaming, arm::streaming_compatible]]; // { dg-warning "conflicts with attribute" } +void (*contradiction_callback_ptr_2) () [[arm::streaming_compatible, arm::streaming]]; // { dg-warning "conflicts with attribute" } + +struct s { + void (*contradiction_callback_ptr_1) () [[arm::streaming, arm::streaming_compatible]]; // { dg-warning "conflicts with attribute" } + void (*contradiction_callback_ptr_2) () [[arm::streaming_compatible, arm::streaming]]; // { dg-warning "conflicts with attribute" } +}; + +//---------------------------------------------------------------------------- + +void keyword_ok_1 () __arm_streaming; +void keyword_ok_1 () __arm_streaming; + +void keyword_ok_2 () __arm_streaming; +void keyword_ok_2 () [[arm::streaming]]; + +void keyword_ok_3 () [[arm::streaming]]; +void keyword_ok_3 () __arm_streaming; + +void keyword_ok_4 () __arm_streaming [[arm::streaming]]; + +void keyword_ok_5 () __arm_streaming_compatible; +void keyword_ok_5 () [[arm::streaming_compatible]]; + +//---------------------------------------------------------------------------- + +void keyword_contradiction_1 () __arm_streaming; +void keyword_contradiction_1 (); // { dg-error "conflicting types" } + +void keyword_contradiction_2 (); +void keyword_contradiction_2 () __arm_streaming; // { dg-error "conflicting types" } + +void keyword_contradiction_3 () __arm_streaming; +void keyword_contradiction_3 () [[arm::streaming_compatible]]; // { dg-error "conflicting types" } + +void keyword_contradiction_4 () [[arm::streaming_compatible]]; +void keyword_contradiction_4 () __arm_streaming; // { dg-error "conflicting types" } diff --git a/gcc/testsuite/gcc.target/aarch64/sme/streaming_mode_2.c b/gcc/testsuite/gcc.target/aarch64/sme/streaming_mode_2.c new file mode 100644 index 00000000000..e8be0f82176 --- /dev/null +++ b/gcc/testsuite/gcc.target/aarch64/sme/streaming_mode_2.c @@ -0,0 +1,25 @@ +// { dg-options "" } + +void sc_fn () [[arm::streaming_compatible]]; +void s_fn () [[arm::streaming]]; +void ns_fn (); + +void (*sc_fn_ptr) () [[arm::streaming_compatible]]; +void (*s_fn_ptr) () [[arm::streaming]]; +void (*ns_fn_ptr) (); + +void +f () +{ + sc_fn_ptr = sc_fn; + sc_fn_ptr = s_fn; // { dg-error "incompatible pointer type" } + sc_fn_ptr = ns_fn; // { dg-error "incompatible pointer type" } + + s_fn_ptr = sc_fn; // { dg-error "incompatible pointer type" } + s_fn_ptr = s_fn; + s_fn_ptr = ns_fn; // { dg-error "incompatible pointer type" } + + ns_fn_ptr = sc_fn; // { dg-error "incompatible pointer type" } + ns_fn_ptr = s_fn; // { dg-error "incompatible pointer type" } + ns_fn_ptr = ns_fn; +}