diff options
author | CoprDistGit <infra@openeuler.org> | 2025-02-28 10:03:49 +0000 |
---|---|---|
committer | CoprDistGit <infra@openeuler.org> | 2025-02-28 10:03:49 +0000 |
commit | 73127104a245052cd5cf29cdaaca3e5c32c70348 (patch) | |
tree | 8e28b63e478c43c252f18b49836dff7313affe54 /0174-Backport-SME-aarch64-Add-arm_streaming-_compatible-a.patch | |
parent | 49d3feaf4665cdb07576fc1a2382a4d82a612d35 (diff) |
automatic import of gccopeneuler24.03_LTS_SP1
Diffstat (limited to '0174-Backport-SME-aarch64-Add-arm_streaming-_compatible-a.patch')
-rw-r--r-- | 0174-Backport-SME-aarch64-Add-arm_streaming-_compatible-a.patch | 1178 |
1 files changed, 1178 insertions, 0 deletions
diff --git a/0174-Backport-SME-aarch64-Add-arm_streaming-_compatible-a.patch b/0174-Backport-SME-aarch64-Add-arm_streaming-_compatible-a.patch new file mode 100644 index 0000000..381f4ce --- /dev/null +++ b/0174-Backport-SME-aarch64-Add-arm_streaming-_compatible-a.patch @@ -0,0 +1,1178 @@ +From 70b732b4518dd0e44b9e6bfaaad78492b8db8f29 Mon Sep 17 00:00:00 2001 +From: Richard Sandiford <richard.sandiford@arm.com> +Date: Tue, 5 Dec 2023 10:11:23 +0000 +Subject: [PATCH 075/157] [Backport][SME] aarch64: Add + arm_streaming(_compatible) attributes + +Reference: https://gcc.gnu.org/git/?p=gcc.git;a=commit;h=2c9a54b4238308b127c3b60b01a591363131e7db + +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_<mode>): 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 4085ad840..397745fbd 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 000000000..5915c98a8 +--- /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 ++ <http://www.gnu.org/licenses/>. */ ++ ++/* 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 14a568140..9b03410dc 100644 +--- a/gcc/config/aarch64/aarch64-protos.h ++++ b/gcc/config/aarch64/aarch64-protos.h +@@ -772,6 +772,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 (rtx *); + bool aarch64_expand_setmem (rtx *); +@@ -851,7 +852,7 @@ bool aarch64_is_mov_xn_imm (unsigned HOST_WIDE_INT); + bool aarch64_use_return_insn_p (void); + const char *aarch64_output_casesi (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 114252a3c..904166b21 100644 +--- a/gcc/config/aarch64/aarch64.cc ++++ b/gcc/config/aarch64/aarch64.cc +@@ -2985,8 +2985,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 } */ +@@ -2998,7 +3008,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 ++}; + + /* An ISA extension in the co-processor and main instruction set space. */ + struct aarch64_option_extension +@@ -4301,6 +4335,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 +@@ -4363,17 +4439,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 +@@ -8117,7 +8222,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; +@@ -8138,9 +8243,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; +@@ -10627,7 +10738,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; + +@@ -18618,6 +18731,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 +@@ -18630,25 +18744,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; +@@ -18821,6 +18935,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 +@@ -18830,25 +18959,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; + +@@ -18856,7 +18984,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. +@@ -18906,7 +19055,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; + } + +@@ -18947,7 +19096,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; + } + +@@ -19047,7 +19196,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; + } + +@@ -19552,7 +19701,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]; +@@ -19566,7 +19715,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. */ +@@ -27270,22 +27419,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 19b82b4f3..84215c8c3 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) +@@ -904,6 +925,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 c0977a3da..29a665e45 100644 +--- a/gcc/config/aarch64/aarch64.md ++++ b/gcc/config/aarch64/aarch64.md +@@ -7017,7 +7017,8 @@ + { + 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_<mode> (operands[0], abi)); + RTL_CONST_CALL_P (call) = 1; +diff --git a/gcc/config/aarch64/t-aarch64 b/gcc/config/aarch64/t-aarch64 +index 6a21a248f..10cd8f093 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 000000000..72fcd0bd9 +--- /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 ++# <http://www.gnu.org/licenses/>. */ ++ ++# 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 000000000..032485adf +--- /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 000000000..c3de726e7 +--- /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 000000000..f2dd2db9b +--- /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 0fa470880..45bb02561 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 000000000..c990e5924 +--- /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 ++# <http://www.gnu.org/licenses/>. */ ++ ++# 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 000000000..8f1b83676 +--- /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 000000000..8874b05b8 +--- /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 000000000..e8be0f821 +--- /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; ++} +-- +2.33.0 + |