]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
LoongArch: Implement target attribute.
authorLulu Cheng <chenglulu@loongson.cn>
Tue, 7 Jan 2025 03:42:25 +0000 (11:42 +0800)
committerLulu Cheng <chenglulu@loongson.cn>
Tue, 21 Jan 2025 09:36:28 +0000 (17:36 +0800)
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.

17 files changed:
gcc/attr-urls.def
gcc/config.gcc
gcc/config/loongarch/loongarch-protos.h
gcc/config/loongarch/loongarch-target-attr.cc [new file with mode: 0644]
gcc/config/loongarch/loongarch.cc
gcc/config/loongarch/t-loongarch
gcc/doc/extend.texi
gcc/testsuite/gcc.target/loongarch/arch-func-attr-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/attr-check-error-message.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/cmodel-func-attr-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/lasx-func-attr-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/lasx-func-attr-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/lsx-func-attr-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/lsx-func-attr-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/strict_align-func-attr-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/strict_align-func-attr-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/loongarch/vector-func-attr-1.c [new file with mode: 0644]

index e8417cff43c3637dde4613f94a6fe13f4d0bb254..0d27400d218a1c8864e50969411f3978ef508438 100644 (file)
@@ -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},
index 82227e86521c4a264bb0a7331ec6db98e7cf0b5d..c0e66a26f953c525127ea0e2390adb530edf2427 100644 (file)
@@ -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"
        ;;
index 33fcb5ee87f39f3eb267276effa8224746b34874..dba52beac00afafe52bc9ed921f52934550067a6 100644 (file)
@@ -214,4 +214,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 (file)
index 0000000..6bb1e6b
--- /dev/null
@@ -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_LASX || 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;
+}
index 51f7239025693b6bb613e380af5c7c41f24c2857..ee44d9dd7fa0e1b09d621beaf7cf3d796e9671e6 100644 (file)
@@ -7718,7 +7718,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)
@@ -7744,9 +7744,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 ();
 }
 
@@ -7785,10 +7782,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
@@ -7798,6 +7800,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;
 
@@ -7806,9 +7811,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);
@@ -7829,6 +7839,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.  */
@@ -11398,6 +11413,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"
index 8f2f57f27baa8a056810dcda839b47fefa05246f..b7dbb4befc53204b0d024e9114d36c073a3a877f 100644 (file)
@@ -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 \
index b0bb0d47230e0c49c83f7ef961b1e201d21d1992..c711f017df5cc4d64fc06448d3681b969cbe8853 100644 (file)
@@ -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,80 @@ 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 slightly different from the
+command-line option @option{-mno-lasx}.
+Example:
+
+@smallexample
+test.c:
+typedef int v4i32 __attribute__ ((vector_size(16), aligned(16)));
+
+v4i32 a, b, c;
+#ifdef WITH_ATTR
+__attribute__ ((target("no-lasx"))) void
+#else
+void
+#endif
+test ()
+@{
+  c = a + b;
+@}
+@end smallexample
+@smallexample
+$ gcc test.c -o test.s -O2 -mlasx -DWITH_ATTR
+@end smallexample
+Compiled as above, 128-bit vectorization is possible.
+But the following method cannot perform 128-bit vectorization.
+@smallexample
+$ gcc test.c -o test.s -O2 -mlasx -mno-lasx
+@end smallexample
+
+@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 (file)
index 0000000..98cc7e5
--- /dev/null
@@ -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 (file)
index 0000000..82dcd17
--- /dev/null
@@ -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 (file)
index 0000000..119cd0e
--- /dev/null
@@ -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 (file)
index 0000000..5dad982
--- /dev/null
@@ -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 (file)
index 0000000..33cc924
--- /dev/null
@@ -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 (file)
index 0000000..3e2c1dc
--- /dev/null
@@ -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 (file)
index 0000000..97475ff
--- /dev/null
@@ -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 (file)
index 0000000..0489374
--- /dev/null
@@ -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 (file)
index 0000000..0e81486
--- /dev/null
@@ -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 (file)
index 0000000..655ca23
--- /dev/null
@@ -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" } } */