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