Add function attributes support for LoongArch. Currently, the following items are supported:
__attribute__ ((target ("{no-}strict-align"))) __attribute__ ((target ("cmodel="))) __attribute__ ((target ("arch="))) __attribute__ ((target ("tune="))) __attribute__ ((target ("{no-}lsx"))) __attribute__ ((target ("{no-}lasx"))) This implementation is derived from AArch64. gcc/ChangeLog: * attr-urls.def: Regenerate. * config.gcc: Add loongarch-target-attr.o to extra_objs. * config/loongarch/loongarch-protos.h (loongarch_option_valid_attribute_p): Function declaration. (loongarch_option_override_internal): Likewise. * config/loongarch/loongarch.cc (loongarch_option_override_internal): Delete the modifications to target_option_default_node and target_option_current_node. (loongarch_set_current_function): Add annotation information. (loongarch_option_override): add assignment operations to target_option_default_node and target_option_current_node. (TARGET_OPTION_VALID_ATTRIBUTE_P): Define. * config/loongarch/t-loongarch: Add compilation of target file loongarch-target-attr.o. * doc/extend.texi: Add description information of LoongArch Function Attributes. * config/loongarch/loongarch-target-attr.cc: New file. gcc/testsuite/ChangeLog: * gcc.target/loongarch/arch-func-attr-1.c: New test. * gcc.target/loongarch/cmodel-func-attr-1.c: New test. * gcc.target/loongarch/lasx-func-attr-1.c: New test. * gcc.target/loongarch/lasx-func-attr-2.c: New test. * gcc.target/loongarch/lsx-func-attr-1.c: New test. * gcc.target/loongarch/lsx-func-attr-2.c: New test. * gcc.target/loongarch/strict_align-func-attr-1.c: New test. * gcc.target/loongarch/strict_align-func-attr-2.c: New test. * gcc.target/loongarch/vector-func-attr-1.c: New test. * gcc.target/loongarch/attr-check-error-message.c: New test. --- gcc/attr-urls.def | 6 + gcc/config.gcc | 2 +- gcc/config/loongarch/loongarch-protos.h | 2 + gcc/config/loongarch/loongarch-target-attr.cc | 413 ++++++++++++++++++ gcc/config/loongarch/loongarch.cc | 26 +- gcc/config/loongarch/t-loongarch | 6 + gcc/doc/extend.texi | 49 +++ .../gcc.target/loongarch/arch-func-attr-1.c | 16 + .../loongarch/attr-check-error-message.c | 30 ++ .../gcc.target/loongarch/cmodel-func-attr-1.c | 17 + .../gcc.target/loongarch/lasx-func-attr-1.c | 15 + .../gcc.target/loongarch/lasx-func-attr-2.c | 12 + .../gcc.target/loongarch/lsx-func-attr-1.c | 15 + .../gcc.target/loongarch/lsx-func-attr-2.c | 12 + .../loongarch/strict_align-func-attr-1.c | 17 + .../loongarch/strict_align-func-attr-2.c | 17 + .../gcc.target/loongarch/vector-func-attr-1.c | 15 + 17 files changed, 665 insertions(+), 5 deletions(-) create mode 100644 gcc/config/loongarch/loongarch-target-attr.cc create mode 100644 gcc/testsuite/gcc.target/loongarch/arch-func-attr-1.c create mode 100644 gcc/testsuite/gcc.target/loongarch/attr-check-error-message.c create mode 100644 gcc/testsuite/gcc.target/loongarch/cmodel-func-attr-1.c create mode 100644 gcc/testsuite/gcc.target/loongarch/lasx-func-attr-1.c create mode 100644 gcc/testsuite/gcc.target/loongarch/lasx-func-attr-2.c create mode 100644 gcc/testsuite/gcc.target/loongarch/lsx-func-attr-1.c create mode 100644 gcc/testsuite/gcc.target/loongarch/lsx-func-attr-2.c create mode 100644 gcc/testsuite/gcc.target/loongarch/strict_align-func-attr-1.c create mode 100644 gcc/testsuite/gcc.target/loongarch/strict_align-func-attr-2.c create mode 100644 gcc/testsuite/gcc.target/loongarch/vector-func-attr-1.c diff --git a/gcc/attr-urls.def b/gcc/attr-urls.def index e8417cff43c..0d27400d218 100644 --- a/gcc/attr-urls.def +++ b/gcc/attr-urls.def @@ -18,6 +18,7 @@ const attr_url_entry function_attrs[] = { { "amdgpu_hsa_kernel", "gcc/AMD-GCN-Function-Attributes.html#index-amdgpu_005fhsa_005fkernel-function-attribute_002c-AMD-GCN", "AMD GCN", 17}, { "arch=", "gcc/AArch64-Function-Attributes.html#index-arch_003d-function-attribute_002c-AArch64", "AArch64", 5}, { "arch=", "gcc/ARM-Function-Attributes.html#index-arch_003d-function-attribute_002c-ARM", "ARM", 5}, + { "arch=", "gcc/LoongArch-Function-Attributes.html#index-arch_003d-function-attribute_002c-LoongArch", "LoongArch", 5}, { "arch=", "gcc/RISC-V-Function-Attributes.html#index-arch_003d-function-attribute_002c-RISC-V", "RISC-V", 5}, { "artificial", "gcc/Common-Function-Attributes.html#index-artificial-function-attribute", "", 10}, { "assume_aligned", "gcc/Common-Function-Attributes.html#index-assume_005faligned-function-attribute", "", 14}, @@ -29,6 +30,7 @@ const attr_url_entry function_attrs[] = { { "cdecl", "gcc/x86-Function-Attributes.html#index-cdecl-function-attribute_002c-x86-32", "x86-32", 5}, { "cf_check", "gcc/x86-Function-Attributes.html#index-cf_005fcheck-function-attribute_002c-x86", "x86", 8}, { "cmodel=", "gcc/AArch64-Function-Attributes.html#index-cmodel_003d-function-attribute_002c-AArch64", "AArch64", 7}, + { "cmodel=", "gcc/LoongArch-Function-Attributes.html#index-cmodel_003d-function-attribute_002c-LoongArch", "LoongArch", 7}, { "code_readable", "gcc/MIPS-Function-Attributes.html#index-code_005freadable-function-attribute_002c-MIPS", "MIPS", 13}, { "cold", "gcc/Common-Function-Attributes.html#index-cold-function-attribute", "", 4}, { "const", "gcc/Common-Function-Attributes.html#index-const-function-attribute", "", 5}, @@ -113,6 +115,7 @@ const attr_url_entry function_attrs[] = { { "kspisusp", "gcc/Blackfin-Function-Attributes.html#index-kspisusp-function-attribute_002c-Blackfin", "Blackfin", 8}, { "l1_text", "gcc/Blackfin-Function-Attributes.html#index-l1_005ftext-function-attribute_002c-Blackfin", "Blackfin", 7}, { "l2", "gcc/Blackfin-Function-Attributes.html#index-l2-function-attribute_002c-Blackfin", "Blackfin", 2}, + { "lasx", "gcc/LoongArch-Function-Attributes.html#index-lasx-function-attribute_002c-LoongArch", "LoongArch", 4}, { "leaf", "gcc/Common-Function-Attributes.html#index-leaf-function-attribute", "", 4}, { "long_call", "gcc/ARC-Function-Attributes.html#index-long_005fcall-function-attribute_002c-ARC", "ARC", 9}, { "long_call", "gcc/ARM-Function-Attributes.html#index-long_005fcall-function-attribute_002c-ARM", "ARM", 9}, @@ -121,6 +124,7 @@ const attr_url_entry function_attrs[] = { { "longcall", "gcc/Blackfin-Function-Attributes.html#index-longcall-function-attribute_002c-Blackfin", "Blackfin", 8}, { "longcall", "gcc/PowerPC-Function-Attributes.html#index-longcall-function-attribute_002c-PowerPC", "PowerPC", 8}, { "lower", "gcc/MSP430-Function-Attributes.html#index-lower-function-attribute_002c-MSP430", "MSP430", 5}, + { "lsx", "gcc/LoongArch-Function-Attributes.html#index-lsx-function-attribute_002c-LoongArch", "LoongArch", 3}, { "malloc", "gcc/Common-Function-Attributes.html#index-malloc-function-attribute", "", 6}, { "medium_call", "gcc/ARC-Function-Attributes.html#index-medium_005fcall-function-attribute_002c-ARC", "ARC", 11}, { "micromips", "gcc/MIPS-Function-Attributes.html#index-micromips-function-attribute", "", 9}, @@ -217,6 +221,7 @@ const attr_url_entry function_attrs[] = { { "stack_protect", "gcc/Common-Function-Attributes.html#index-stack_005fprotect-function-attribute", "", 13}, { "stdcall", "gcc/x86-Function-Attributes.html#index-stdcall-function-attribute_002c-x86-32", "x86-32", 7}, { "strict-align", "gcc/AArch64-Function-Attributes.html#index-strict-align-function-attribute_002c-AArch64", "AArch64", 12}, + { "strict-align", "gcc/LoongArch-Function-Attributes.html#index-strict-align-function-attribute_002c-LoongArch", "LoongArch", 12}, { "symver", "gcc/Common-Function-Attributes.html#index-symver-function-attribute", "", 6}, { "syscall_linkage", "gcc/IA-64-Function-Attributes.html#index-syscall_005flinkage-function-attribute_002c-IA-64", "IA-64", 15}, { "sysv_abi", "gcc/x86-Function-Attributes.html#index-sysv_005fabi-function-attribute_002c-x86", "x86", 8}, @@ -232,6 +237,7 @@ const attr_url_entry function_attrs[] = { { "trap_exit", "gcc/SH-Function-Attributes.html#index-trap_005fexit-function-attribute_002c-SH", "SH", 9}, { "trapa_handler", "gcc/SH-Function-Attributes.html#index-trapa_005fhandler-function-attribute_002c-SH", "SH", 13}, { "tune=", "gcc/AArch64-Function-Attributes.html#index-tune_003d-function-attribute_002c-AArch64", "AArch64", 5}, + { "tune=", "gcc/LoongArch-Function-Attributes.html#index-tune_003d-function-attribute_002c-LoongArch", "LoongArch", 5}, { "tune=", "gcc/RISC-V-Function-Attributes.html#index-tune_003d-function-attribute_002c-RISC-V", "RISC-V", 5}, { "unavailable", "gcc/Common-Function-Attributes.html#index-unavailable-function-attribute", "", 11}, { "unused", "gcc/Common-Function-Attributes.html#index-unused-function-attribute", "", 6}, diff --git a/gcc/config.gcc b/gcc/config.gcc index 55e37146ee0..89740e08bbc 100644 --- a/gcc/config.gcc +++ b/gcc/config.gcc @@ -494,7 +494,7 @@ loongarch*-*-*) cpu_type=loongarch d_target_objs="loongarch-d.o" extra_headers="larchintrin.h lsxintrin.h lasxintrin.h" - extra_objs="loongarch-c.o loongarch-builtins.o loongarch-cpu.o loongarch-opts.o loongarch-def.o loongarch-evolution.o" + extra_objs="loongarch-c.o loongarch-builtins.o loongarch-cpu.o loongarch-opts.o loongarch-def.o loongarch-evolution.o loongarch-target-attr.o" extra_gcc_objs="loongarch-driver.o loongarch-cpu.o loongarch-opts.o loongarch-def.o" extra_options="${extra_options} g.opt fused-madd.opt" ;; diff --git a/gcc/config/loongarch/loongarch-protos.h b/gcc/config/loongarch/loongarch-protos.h index fb544ad75ca..531b0bcb636 100644 --- a/gcc/config/loongarch/loongarch-protos.h +++ b/gcc/config/loongarch/loongarch-protos.h @@ -212,4 +212,6 @@ extern void loongarch_emit_swrsqrtsf (rtx, rtx, machine_mode, bool); extern void loongarch_emit_swdivsf (rtx, rtx, rtx, machine_mode); extern bool loongarch_explicit_relocs_p (enum loongarch_symbol_type); extern bool loongarch_symbol_extreme_p (enum loongarch_symbol_type); +extern bool loongarch_option_valid_attribute_p (tree, tree, tree, int); +extern void loongarch_option_override_internal (struct loongarch_target *, struct gcc_options *, struct gcc_options *); #endif /* ! GCC_LOONGARCH_PROTOS_H */ diff --git a/gcc/config/loongarch/loongarch-target-attr.cc b/gcc/config/loongarch/loongarch-target-attr.cc new file mode 100644 index 00000000000..1fafd4c4466 --- /dev/null +++ b/gcc/config/loongarch/loongarch-target-attr.cc @@ -0,0 +1,413 @@ +/* Subroutines used for LoongArch code generation. + Copyright (C) 2025 Free Software Foundation, Inc. + Contributed by Loongson Ltd. + Based on AArch64 target for GNU compiler. + +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/>. */ + +#define IN_TARGET_CODE 1 + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "target.h" +#include "tree.h" +#include "tm_p.h" +#include "diagnostic.h" +#include "opts.h" + +/* Enum describing the various ways we can handle attributes. + In many cases we can reuse the generic option handling machinery. */ + +enum loongarch_attr_opt_type +{ + loongarch_attr_mask, /* Attribute should set a bit in target_flags. */ + loongarch_attr_enum, /* Attribute sets an enum variable. */ + loongarch_attr_bool /* Attribute sets or unsets a boolean variable. */ +}; + +/* All the information needed to handle a target attribute. + NAME is the name of the attribute. + ATTR_TYPE specifies the type of behavior of the attribute as described + in the definition of enum loongarch_attr_opt_type. + ALLOW_NEG is true if the attribute supports a "no-" form. + OPT_NUM is the enum specifying the option that the attribute modifies. + This is needed for attributes that mirror the behavior of a command-line + option, that is it has ATTR_TYPE loongarch_attr_mask. */ + +struct loongarch_attribute_info +{ + const char *name; + enum loongarch_attr_opt_type attr_type; + bool allow_neg; + enum opt_code opt_num; +}; +/* The target attributes that we support. */ + +static const struct loongarch_attribute_info loongarch_attributes[] = +{ + { "strict-align", loongarch_attr_mask, true, OPT_mstrict_align }, + { "cmodel", loongarch_attr_enum, false, OPT_mcmodel_ }, + { "arch", loongarch_attr_enum, false, OPT_march_ }, + { "tune", loongarch_attr_enum, false, OPT_mtune_ }, + { "lsx", loongarch_attr_bool, true, OPT_mlsx }, + { "lasx", loongarch_attr_bool, true, OPT_mlasx }, + { NULL, loongarch_attr_bool, false, OPT____ } +}; + +bool +loongarch_handle_option (struct gcc_options *opts, + struct gcc_options *opts_set ATTRIBUTE_UNUSED, + const struct cl_decoded_option *decoded, + location_t loc ATTRIBUTE_UNUSED) +{ + size_t code = decoded->opt_index; + int val = decoded->value; + + switch (code) + { + case OPT_mstrict_align: + if (val) + opts->x_target_flags |= MASK_STRICT_ALIGN; + else + opts->x_target_flags &= ~MASK_STRICT_ALIGN; + return true; + + case OPT_mcmodel_: + opts->x_la_opt_cmodel = val; + return true; + + case OPT_march_: + opts->x_la_opt_cpu_arch = val; + + /* Set these variables to the initial values so that they can be reset + in the loongarch_config_target function according to the ARCH + settings. */ + opts->x_la_opt_simd = M_OPT_UNSET; + opts->x_la_opt_fpu = M_OPT_UNSET; + opts->x_la_isa_evolution = 0; + return true; + + case OPT_mtune_: + opts->x_la_opt_cpu_tune = val; + + /* Set these variables to the initial values so that they can be reset + in the loongarch_target_option_override function according to the TUNE + settings. */ + opts->x_str_align_functions = NULL; + opts->x_str_align_loops = NULL; + opts->x_str_align_jumps = NULL; + return true; + + case OPT_mlsx: + opts->x_la_opt_simd = val ? (la_opt_simd == ISA_EXT_SIMD_LASX + ? ISA_EXT_SIMD_LASX : ISA_EXT_SIMD_LSX) : ISA_EXT_NONE; + return true; + + case OPT_mlasx: + opts->x_la_opt_simd = val ? ISA_EXT_SIMD_LASX + : (la_opt_simd == ISA_EXT_SIMD_LSX || la_opt_simd == ISA_EXT_SIMD_LSX + ? ISA_EXT_SIMD_LSX : ISA_EXT_NONE); + return true; + + default: + return true; + } +} + +/* Parse ARG_STR which contains the definition of one target attribute. + Show appropriate errors if any or return true if the attribute is valid. */ + +static bool +loongarch_process_one_target_attr (char *arg_str, location_t loc) +{ + bool invert = false; + + size_t len = strlen (arg_str); + + if (len == 0) + { + error_at (loc, "malformed %<target()%> pragma or attribute"); + return false; + } + + char *str_to_check = (char *) alloca (len + 1); + strcpy (str_to_check, arg_str); + + if (len > 3 && startswith (str_to_check, "no-")) + { + invert = true; + str_to_check += 3; + } + char *arg = strchr (str_to_check, '='); + + /* If we found opt=foo then terminate STR_TO_CHECK at the '=' + and point ARG to "foo". */ + if (arg) + { + *arg = '\0'; + arg++; + } + const struct loongarch_attribute_info *p_attr; + bool found = false; + for (p_attr = loongarch_attributes; p_attr->name; p_attr++) + { + /* If the names don't match up, or the user has given an argument + to an attribute that doesn't accept one, or didn't give an argument + to an attribute that expects one, fail to match. */ + if (strcmp (str_to_check, p_attr->name) != 0) + continue; + + found = true; + + /* If the name matches but the attribute does not allow "no-" versions + then we can't match. */ + if (invert && !p_attr->allow_neg) + { + error_at (loc, "pragma or attribute %<target(\"%s\")%> does not " + "allow a negated form", str_to_check); + return false; + } + + switch (p_attr->attr_type) + { + /* Either set or unset a boolean option. */ + case loongarch_attr_mask: + { + struct cl_decoded_option decoded; + + /* We only need to specify the option number. + loongarch_handle_option will know which mask to apply. */ + decoded.opt_index = p_attr->opt_num; + decoded.value = !invert; + + loongarch_handle_option (&global_options, &global_options_set, + &decoded, input_location); + break; + } + + /* Use the option setting machinery to set an option to an enum. */ + case loongarch_attr_enum: + { + gcc_assert (arg); + bool valid; + int value; + struct cl_decoded_option decoded; + valid = opt_enum_arg_to_value (p_attr->opt_num, arg, + &value, CL_TARGET); + + decoded.opt_index = p_attr->opt_num; + decoded.value = value; + + if (valid) + loongarch_handle_option (&global_options, + &global_options_set, + &decoded, input_location); + else + error_at (loc, "pragma or attribute %<target(\"%s=%s\")%> is " + "not valid", str_to_check, arg); + break; + } + + /* Either set or unset a boolean option. */ + case loongarch_attr_bool: + { + struct cl_decoded_option decoded; + + generate_option (p_attr->opt_num, NULL, !invert, + CL_TARGET, &decoded); + loongarch_handle_option (&global_options, &global_options_set, + &decoded, input_location); + break; + } + default: + gcc_unreachable (); + } + } + + /* If we reached here we either have found an attribute and validated + it or didn't match any. If we matched an attribute but its arguments + were malformed we will have returned false already. */ + if (!found) + error_at (loc, "attribute %<target%> argument %qs is unknown", + str_to_check); + + return found; +} + +/* Count how many times the character C appears in + NULL-terminated string STR. */ + +static unsigned int +num_occurences_in_str (char c, char *str) +{ + unsigned int res = 0; + while (*str != '\0') + { + if (*str == c) + res++; + + str++; + } + + return res; +} + +/* Parse the tree in ARGS that contains the target attribute information + and update the global target options space. */ + +bool +loongarch_process_target_attr (tree args, tree fndecl) +{ + location_t loc + = fndecl == NULL ? UNKNOWN_LOCATION : DECL_SOURCE_LOCATION (fndecl); + + if (TREE_CODE (args) == TREE_LIST) + { + do + { + tree head = TREE_VALUE (args); + if (head) + { + if (!loongarch_process_target_attr (head, fndecl)) + return false; + } + args = TREE_CHAIN (args); + } while (args); + + return true; + } + + if (TREE_CODE (args) != STRING_CST) + { + error_at (loc, "attribute %<target%> argument not a string"); + return false; + } + + size_t len = strlen (TREE_STRING_POINTER (args)); + auto_vec<char, 32> buffer; + buffer.safe_grow (len + 1); + char *str_to_check = buffer.address (); + memcpy (str_to_check, TREE_STRING_POINTER (args), len + 1); + + if (len == 0) + { + error_at (loc, "malformed %<target()%> pragma or attribute"); + return false; + } + + /* Used to catch empty spaces between commas i.e. + attribute ((target ("attr1,,attr2"))). */ + unsigned int num_commas = num_occurences_in_str (',', str_to_check); + + /* Handle multiple target attributes separated by ','. */ + char *token = strtok_r (str_to_check, ",", &str_to_check); + + unsigned int num_attrs = 0; + while (token) + { + num_attrs++; + if (!loongarch_process_one_target_attr (token, loc)) + return false; + + token = strtok_r (NULL, ",", &str_to_check); + } + + if (num_attrs != num_commas + 1) + { + error_at (loc, "malformed %<target(\"%s\")%> pragma or attribute", + TREE_STRING_POINTER (args)); + return false; + } + + return true; +} + +/* Implement TARGET_OPTION_VALID_ATTRIBUTE_P. This is used to + process attribute ((target ("..."))). */ + +bool +loongarch_option_valid_attribute_p (tree fndecl, tree, tree args, int) +{ + struct cl_target_option cur_target; + bool ret; + tree old_optimize; + tree new_target, new_optimize; + tree existing_target = DECL_FUNCTION_SPECIFIC_TARGET (fndecl); + + tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl); + + old_optimize + = build_optimization_node (&global_options, &global_options_set); + + /* If the function changed the optimization levels as well as setting + target options, start with the optimizations specified. */ + if (func_optimize && func_optimize != old_optimize) + cl_optimization_restore (&global_options, &global_options_set, + TREE_OPTIMIZATION (func_optimize)); + + /* Save the current target options to restore at the end. */ + cl_target_option_save (&cur_target, &global_options, &global_options_set); + + /* If fndecl already has some target attributes applied to it, unpack + them so that we add this attribute on top of them, rather than + overwriting them. */ + if (existing_target) + { + struct cl_target_option *existing_options + = TREE_TARGET_OPTION (existing_target); + + if (existing_options) + cl_target_option_restore (&global_options, &global_options_set, + existing_options); + } + else + cl_target_option_restore (&global_options, &global_options_set, + TREE_TARGET_OPTION (target_option_current_node)); + + ret = loongarch_process_target_attr (args, fndecl); + + /* Set up any additional state. */ + if (ret) + { + loongarch_option_override_internal (&la_target, + &global_options, + &global_options_set); + new_target = build_target_option_node (&global_options, + &global_options_set); + } + else + new_target = NULL; + + new_optimize = build_optimization_node (&global_options, + &global_options_set); + + if (fndecl && ret) + { + DECL_FUNCTION_SPECIFIC_TARGET (fndecl) = new_target; + + if (old_optimize != new_optimize) + DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl) = new_optimize; + } + + cl_target_option_restore (&global_options, &global_options_set, &cur_target); + + if (old_optimize != new_optimize) + cl_optimization_restore (&global_options, &global_options_set, + TREE_OPTIMIZATION (old_optimize)); + return ret; +} diff --git a/gcc/config/loongarch/loongarch.cc b/gcc/config/loongarch/loongarch.cc index d5e90bfd1e1..f3514073cea 100644 --- a/gcc/config/loongarch/loongarch.cc +++ b/gcc/config/loongarch/loongarch.cc @@ -7644,7 +7644,7 @@ loongarch_reg_init (void) = loongarch_hard_regno_mode_ok_uncached (regno, (machine_mode) mode); } -static void +void loongarch_option_override_internal (struct loongarch_target *target, struct gcc_options *opts, struct gcc_options *opts_set) @@ -7670,9 +7670,6 @@ loongarch_option_override_internal (struct loongarch_target *target, /* Override some options according to the resolved target. */ loongarch_target_option_override (target, opts, opts_set); - target_option_default_node = target_option_current_node - = build_target_option_node (opts, opts_set); - loongarch_reg_init (); } @@ -7711,10 +7708,15 @@ loongarch_set_current_function (tree fndecl) else old_tree = target_option_default_node; + /* When the function is optimized, the pop_cfun will be called, and + the fndecl will be NULL. */ if (fndecl == NULL_TREE) { if (old_tree != target_option_current_node) { + /* When this function is set with special options, we need to + restore the original global optimization options at the end + of function optimization. */ loongarch_previous_fndecl = NULL_TREE; cl_target_option_restore (&global_options, &global_options_set, TREE_TARGET_OPTION @@ -7724,6 +7726,9 @@ loongarch_set_current_function (tree fndecl) } tree new_tree = DECL_FUNCTION_SPECIFIC_TARGET (fndecl); + + /* When no separate compilation parameters are set for the function, + new_tree is NULL. */ if (new_tree == NULL_TREE) new_tree = target_option_default_node; @@ -7732,9 +7737,14 @@ loongarch_set_current_function (tree fndecl) if (new_tree == old_tree) return; + /* According to the settings of the functions attribute and pragma, + the options is corrected. */ cl_target_option_restore (&global_options, &global_options_set, TREE_TARGET_OPTION (new_tree)); + /* After correcting the value of options, we need to update the + rules for using the hardware registers to ensure that the + rules correspond to the options. */ loongarch_reg_init (); loongarch_save_restore_target_globals (new_tree); @@ -7755,6 +7765,11 @@ loongarch_option_override (void) &global_options, &global_options_set); + /* Save the initial options so that we can restore the initial option + settings later when processing attributes and pragmas. */ + target_option_default_node = target_option_current_node + = build_target_option_node (&global_options, &global_options_set); + } /* Implement TARGET_OPTION_SAVE. */ @@ -11324,6 +11339,9 @@ loongarch_asm_code_end (void) #undef TARGET_C_MODE_FOR_FLOATING_TYPE #define TARGET_C_MODE_FOR_FLOATING_TYPE loongarch_c_mode_for_floating_type +#undef TARGET_OPTION_VALID_ATTRIBUTE_P +#define TARGET_OPTION_VALID_ATTRIBUTE_P loongarch_option_valid_attribute_p + struct gcc_target targetm = TARGET_INITIALIZER; #include "gt-loongarch.h" diff --git a/gcc/config/loongarch/t-loongarch b/gcc/config/loongarch/t-loongarch index 8f2f57f27ba..b7dbb4befc5 100644 --- a/gcc/config/loongarch/t-loongarch +++ b/gcc/config/loongarch/t-loongarch @@ -47,6 +47,12 @@ loongarch-c.o: $(srcdir)/config/loongarch/loongarch-c.cc $(CONFIG_H) $(SYSTEM_H) $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ $(srcdir)/config/loongarch/loongarch-c.cc +loongarch-target-attr.o: $(srcdir)/config/loongarch/loongarch-target-attr.cc \ + $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TARGET_H) $(TREE_H) $(TM_H) \ + $(DIAGNOSTIC_CORE_H) + $(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \ + $(srcdir)/config/loongarch/loongarch-target-attr.cc + loongarch-builtins.o: $(srcdir)/config/loongarch/loongarch-builtins.cc $(CONFIG_H) \ $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(TREE_H) $(RECOG_H) langhooks.h \ $(DIAGNOSTIC_CORE_H) $(OPTABS_H) $(srcdir)/config/loongarch/loongarch-ftypes.def \ diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi index 1e1b4cc837d..d896677fd3a 100644 --- a/gcc/doc/extend.texi +++ b/gcc/doc/extend.texi @@ -2642,6 +2642,7 @@ GCC plugins may provide their own attributes. * Epiphany Function Attributes:: * H8/300 Function Attributes:: * IA-64 Function Attributes:: +* LoongArch Function Attributes:: * M32C Function Attributes:: * M32R/D Function Attributes:: * m68k Function Attributes:: @@ -5642,6 +5643,54 @@ extern int foo () __attribute__((version_id ("20040821"))); Calls to @code{foo} are mapped to calls to @code{foo@{20040821@}}. @end table +@node LoongArch Function Attributes +@subsection LoongArch Function Attributes + +These function attributes are supported by the LoongArch end: + +@table @code +@cindex @code{strict-align} function attribute, LoongArch +@item strict-align +@itemx no-strict-align +@code{strict-align} indicates that the compiler should not assume that unaligned +memory references are handled by the system. To allow the compiler to assume +that aligned memory references are handled by the system, the inverse attribute +@code{no-strict-align} can be specified. The behavior is same as for the +command-line option @option{-mstrict-align} and @option{-mno-strict-align}. + +@cindex @code{cmodel=} function attribute, LoongArch +@item cmodel= +Indicates that code should be generated for a particular code model for +this function. The behavior and permissible arguments are the same as +for the command-line option @option{-mcmodel=}. + +@cindex @code{arch=} function attribute, LoongArch +@item arch= +Specifies the architecture version and architectural extensions to use +for this function. The behavior and permissible arguments are the same as +for the @option{-march=} command-line option. + +@cindex @code{tune=} function attribute, LoongArch +@item tune= +Specifies the core for which to tune the performance of this function. +The behavior and permissible arguments are the same as for the @option{-mtune=} +command-line option. + +@cindex @code{lsx} function attribute, LoongArch +@item lsx +@itemx no-lsx +@code{lsx} indicates that vector instruction generation is allowed (not allowed) +when compiling the function. The behavior is same as for the command-line option +@option{-mlsx} and @option{-mno-lsx}. + +@cindex @code{lasx} function attribute, LoongArch +@item lasx +@itemx no-lasx +@code{lasx} indicates that lasx instruction generation is allowed (not allowed) +when compiling the function. The behavior is same as for the command-line option +@option{-mlasx} and @option{-mno-lasx}. +@end table + @node M32C Function Attributes @subsection M32C Function Attributes diff --git a/gcc/testsuite/gcc.target/loongarch/arch-func-attr-1.c b/gcc/testsuite/gcc.target/loongarch/arch-func-attr-1.c new file mode 100644 index 00000000000..98cc7e577e3 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/arch-func-attr-1.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -march=loongarch64 -mno-lsx" } */ + +extern char a[64]; +extern char b[64]; + +__attribute__ ((target ("arch=la64v1.1"))) +void +test (void) +{ + for (int i = 0; i < 64; i++) + a[i] = b[i]; +} + + +/* { dg-final { scan-assembler "vld" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/attr-check-error-message.c b/gcc/testsuite/gcc.target/loongarch/attr-check-error-message.c new file mode 100644 index 00000000000..82dcd172555 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/attr-check-error-message.c @@ -0,0 +1,30 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -Wno-attributes" } */ + +__attribute__ ((target ("mno-lsx"))) void +test1 (void) /* { dg-error "attribute \\\'target\\\' argument \\\'mno-lsx\\\' is unknown" } */ +{} + +__attribute__ ((target (""))) void +test2 (void) /* { dg-error "malformed \\\'target\\\(\\\)\\\' pragma or attribute" } */ +{} + +__attribute__ ((target ("no-cmodel="))) void +test3 (void) /* { dg-error "pragma or attribute \\\'target\\\(\\\"cmodel\\\"\\\)\\\' does not allow a negated form" } */ +{} + +__attribute__ ((target ("cmodel=test"))) void +test4 (void) /* { dg-error "pragma or attribute \\\'target\\\(\\\"cmodel=test\\\"\\\)\\\' is not valid" } */ +{} + +__attribute__ ((target ("test"))) void +test5 (void) /* { dg-error "attribute \\\'target\\\' argument \\\'test\\\' is unknown" } */ +{} + +__attribute__ ((target (lsx))) void /* { dg-error "\\\'lsx\\\' undeclared here" } */ +test6 (void) /* { dg-error "attribute \\\'target\\\' argument not a string" } */ +{} + +__attribute__ ((target ("lsx,"))) void +test7 (void) /* { dg-error "malformed \\\'target\\\(\\\"lsx,\\\"\\\)\\\' pragma or attribute" } */ +{} diff --git a/gcc/testsuite/gcc.target/loongarch/cmodel-func-attr-1.c b/gcc/testsuite/gcc.target/loongarch/cmodel-func-attr-1.c new file mode 100644 index 00000000000..119cd0e1646 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/cmodel-func-attr-1.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mcmodel=normal -mexplicit-relocs=none" } */ + +extern char a[8]; +extern char b[8]; + +__attribute__ ((target ("cmodel=extreme"))) +void +test (void) +{ + a[0] = b[1]; + a[1] = b[2]; + a[2] = b[3]; + a[3] = b[4]; +} + +/* { dg-final { scan-assembler "la.global\t\\\$r\[0-9\]+,\\\$r\[0-9\]+,a" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/lasx-func-attr-1.c b/gcc/testsuite/gcc.target/loongarch/lasx-func-attr-1.c new file mode 100644 index 00000000000..5dad9821f03 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/lasx-func-attr-1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-lsx" } */ + +typedef int v8i32 __attribute__ ((vector_size(32), aligned(32))); +extern v8i32 a, b, c; + +__attribute__ ((target ("lasx"))) +void +test (void) +{ + a = b + c; +} + + +/* { dg-final { scan-assembler "xvadd.w" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/lasx-func-attr-2.c b/gcc/testsuite/gcc.target/loongarch/lasx-func-attr-2.c new file mode 100644 index 00000000000..33cc924d0e4 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/lasx-func-attr-2.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mlasx" } */ + +typedef int v8i32 __attribute__ ((vector_size(32), aligned(32))); +extern v8i32 a, b, c; + +__attribute__ ((target ("no-lasx"))) +void +test (void) +{ + a = __builtin_lasx_xvadd_w (b, c); /* { dg-error "built-in function '__builtin_lasx_xvadd_w' is not enabled" } */ +} diff --git a/gcc/testsuite/gcc.target/loongarch/lsx-func-attr-1.c b/gcc/testsuite/gcc.target/loongarch/lsx-func-attr-1.c new file mode 100644 index 00000000000..3e2c1dc3359 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/lsx-func-attr-1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-lsx" } */ + +typedef int v4i32 __attribute__ ((vector_size(16), aligned(16))); +extern v4i32 a, b, c; + +__attribute__ ((target ("lsx"))) +void +test (void) +{ + a = b + c; +} + + +/* { dg-final { scan-assembler "vadd.w" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/lsx-func-attr-2.c b/gcc/testsuite/gcc.target/loongarch/lsx-func-attr-2.c new file mode 100644 index 00000000000..97475fff579 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/lsx-func-attr-2.c @@ -0,0 +1,12 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mlsx" } */ + +typedef int v4i32 __attribute__ ((vector_size(16), aligned(16))); +extern v4i32 a, b, c; + +__attribute__ ((target ("no-lsx"))) +void +test (void) +{ + a = __builtin_lsx_vadd_w (b, c); /* { dg-error "built-in function '__builtin_lsx_vadd_w' is not enabled" } */ +} diff --git a/gcc/testsuite/gcc.target/loongarch/strict_align-func-attr-1.c b/gcc/testsuite/gcc.target/loongarch/strict_align-func-attr-1.c new file mode 100644 index 00000000000..04893746de8 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/strict_align-func-attr-1.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mstrict-align" } */ +extern char a[8]; +extern char b[8]; + +__attribute__ ((target ("no-strict-align"))) +void +test (void) +{ + a[0] = b[1]; + a[1] = b[2]; + a[2] = b[3]; + a[3] = b[4]; +} + + +/* { dg-final { scan-assembler-not "ld.bu" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/strict_align-func-attr-2.c b/gcc/testsuite/gcc.target/loongarch/strict_align-func-attr-2.c new file mode 100644 index 00000000000..0e81486cd53 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/strict_align-func-attr-2.c @@ -0,0 +1,17 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mno-strict-align" } */ +extern char a[8]; +extern char b[8]; + +__attribute__ ((target ("strict-align"))) +void +test (void) +{ + a[0] = b[1]; + a[1] = b[2]; + a[2] = b[3]; + a[3] = b[4]; +} + + +/* { dg-final { scan-assembler-not "ld.w" } } */ diff --git a/gcc/testsuite/gcc.target/loongarch/vector-func-attr-1.c b/gcc/testsuite/gcc.target/loongarch/vector-func-attr-1.c new file mode 100644 index 00000000000..655ca234be0 --- /dev/null +++ b/gcc/testsuite/gcc.target/loongarch/vector-func-attr-1.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -mlsx" } */ + +typedef int v4i32 __attribute__ ((vector_size(16), aligned(16))); +extern v4i32 a, b, c; + +__attribute__ ((target ("no-lasx"))) +void +test (void) +{ + a = b + c; +} + + +/* { dg-final { scan-assembler "vadd.w" } } */ -- 2.34.1